erlang-terms 1.1.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.editorconfig +20 -0
  4. data/.gitignore +10 -18
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +15 -3
  8. data/.yardopts +6 -0
  9. data/CHANGELOG.md +9 -0
  10. data/Gemfile +21 -1
  11. data/LICENSE.txt +1 -1
  12. data/README.md +95 -17
  13. data/Rakefile +8 -3
  14. data/erlang-terms.gemspec +14 -11
  15. data/lib/erlang-terms.rb +1 -0
  16. data/lib/erlang/associable.rb +98 -0
  17. data/lib/erlang/atom.rb +257 -0
  18. data/lib/erlang/binary.rb +425 -0
  19. data/lib/erlang/bitstring.rb +464 -0
  20. data/lib/erlang/cons.rb +122 -0
  21. data/lib/erlang/enumerable.rb +160 -0
  22. data/lib/erlang/error.rb +4 -0
  23. data/lib/erlang/export.rb +110 -12
  24. data/lib/erlang/float.rb +201 -0
  25. data/lib/erlang/function.rb +259 -0
  26. data/lib/erlang/immutable.rb +101 -0
  27. data/lib/erlang/list.rb +1685 -24
  28. data/lib/erlang/map.rb +935 -21
  29. data/lib/erlang/nil.rb +73 -10
  30. data/lib/erlang/pid.rb +120 -18
  31. data/lib/erlang/port.rb +123 -0
  32. data/lib/erlang/reference.rb +161 -0
  33. data/lib/erlang/string.rb +175 -3
  34. data/lib/erlang/term.rb +24 -0
  35. data/lib/erlang/terms.rb +324 -8
  36. data/lib/erlang/terms/version.rb +1 -1
  37. data/lib/erlang/trie.rb +364 -0
  38. data/lib/erlang/tuple.rb +1582 -14
  39. data/lib/erlang/undefined.rb +32 -0
  40. metadata +49 -71
  41. data/spec/erlang/export_spec.rb +0 -17
  42. data/spec/erlang/list_spec.rb +0 -39
  43. data/spec/erlang/map_spec.rb +0 -24
  44. data/spec/erlang/nil_spec.rb +0 -18
  45. data/spec/erlang/pid_spec.rb +0 -21
  46. data/spec/erlang/string_spec.rb +0 -11
  47. data/spec/erlang/terms_spec.rb +0 -7
  48. data/spec/erlang/tuple_spec.rb +0 -20
  49. data/spec/spec_helper.rb +0 -7
@@ -1,5 +1,5 @@
1
1
  module Erlang
2
2
  module Terms
3
- VERSION = "1.1.0"
3
+ VERSION = "2.0.1"
4
4
  end
5
5
  end
@@ -0,0 +1,364 @@
1
+ module Erlang
2
+ # Licensing
3
+ # =========
4
+ #
5
+ # Portions taken and modified from https://github.com/hamstergem/hamster
6
+ #
7
+ # Copyright (c) 2009-2014 Simon Harris
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining
10
+ # a copy of this software and associated documentation files (the
11
+ # "Software"), to deal in the Software without restriction, including
12
+ # without limitation the rights to use, copy, modify, merge, publish,
13
+ # distribute, sublicense, and/or sell copies of the Software, and to
14
+ # permit persons to whom the Software is furnished to do so, subject to
15
+ # the following conditions:
16
+ #
17
+ # The above copyright notice and this permission notice shall be
18
+ # included in all copies or substantial portions of the Software.
19
+ #
20
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ #
28
+ # @private
29
+ class Trie
30
+ def self.[](pairs)
31
+ result = self.new(0)
32
+ pairs.each { |key, val| result.put!(key, val) }
33
+ result
34
+ end
35
+
36
+ # Returns the number of key-value pairs in the trie.
37
+ attr_reader :size
38
+
39
+ def initialize(significant_bits, size = 0, entries = [], children = [])
40
+ @significant_bits = significant_bits
41
+ @entries = entries
42
+ @children = children
43
+ @size = size
44
+ end
45
+
46
+ # Returns <tt>true</tt> if the trie contains no key-value pairs.
47
+ def empty?
48
+ size == 0
49
+ end
50
+
51
+ # Returns <tt>true</tt> if the given key is present in the trie.
52
+ def key?(key)
53
+ !!get(key)
54
+ end
55
+
56
+ # Calls <tt>block</tt> once for each entry in the trie, passing the key-value pair as parameters.
57
+ def each(&block)
58
+ # TODO: Using block.call here is slower than using yield by 5-10%, but
59
+ # the latter segfaults on ruby 2.2 and above. Once that is fixed and
60
+ # broken versions are sufficiently old, we should revert back to yield
61
+ # with a warning that the broken versions are unsupported.
62
+ #
63
+ # For more context:
64
+ # * https://bugs.ruby-lang.org/issues/11451
65
+ # * https://github.com/hamstergem/hamster/issues/189
66
+ @entries.each { |entry| block.call(entry) if entry }
67
+ @children.each do |child|
68
+ child.each(&block) if child
69
+ end
70
+ nil
71
+ end
72
+
73
+ def reverse_each(&block)
74
+ @children.reverse_each do |child|
75
+ child.reverse_each(&block) if child
76
+ end
77
+ @entries.reverse_each { |entry| yield(entry) if entry }
78
+ nil
79
+ end
80
+
81
+ def reduce(memo)
82
+ each { |entry| memo = yield(memo, entry) }
83
+ memo
84
+ end
85
+
86
+ def select
87
+ keys_to_delete = []
88
+ each { |entry| keys_to_delete << entry[0] unless yield(entry) }
89
+ bulk_delete(keys_to_delete)
90
+ end
91
+
92
+ # @return [Trie] A copy of `self` with the given value associated with the
93
+ # key (or `self` if no modification was needed because an identical
94
+ # key-value pair wes already stored
95
+ def put(key, value)
96
+ index = index_for(key)
97
+ entry = @entries[index]
98
+
99
+ if !entry
100
+ entries = @entries.dup
101
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
102
+ entries[index] = [key, value].freeze
103
+ Trie.new(@significant_bits, @size + 1, entries, @children)
104
+ elsif entry[0].eql?(key)
105
+ if entry[1].equal?(value)
106
+ self
107
+ else
108
+ entries = @entries.dup
109
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
110
+ entries[index] = [key, value].freeze
111
+ Trie.new(@significant_bits, @size, entries, @children)
112
+ end
113
+ else
114
+ child = @children[index]
115
+ if child
116
+ new_child = child.put(key, value)
117
+ if new_child.equal?(child)
118
+ self
119
+ else
120
+ children = @children.dup
121
+ children[index] = new_child
122
+ new_self_size = @size + (new_child.size - child.size)
123
+ Trie.new(@significant_bits, new_self_size, @entries, children)
124
+ end
125
+ else
126
+ children = @children.dup
127
+ children[index] = Trie.new(@significant_bits + 5).put!(key, value)
128
+ Trie.new(@significant_bits, @size + 1, @entries, children)
129
+ end
130
+ end
131
+ end
132
+
133
+ # Put multiple elements into a Trie. This is more efficient than several
134
+ # calls to `#put`.
135
+ #
136
+ # @param key_value_pairs Enumerable of pairs (`[key, value]`)
137
+ # @return [Trie] A copy of `self` after associated the given keys and
138
+ # values (or `self` if no modifications where needed).
139
+ def bulk_put(key_value_pairs)
140
+ new_entries = nil
141
+ new_children = nil
142
+ new_size = @size
143
+
144
+ key_value_pairs.each do |key, value|
145
+ index = index_for(key)
146
+ entry = (new_entries || @entries)[index]
147
+
148
+ if !entry
149
+ new_entries ||= @entries.dup
150
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
151
+ new_entries[index] = [key, value].freeze
152
+ new_size += 1
153
+ elsif entry[0].eql?(key)
154
+ if !entry[1].equal?(value)
155
+ new_entries ||= @entries.dup
156
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
157
+ new_entries[index] = [key, value].freeze
158
+ end
159
+ else
160
+ child = (new_children || @children)[index]
161
+ if child
162
+ new_child = child.put(key, value)
163
+ if !new_child.equal?(child)
164
+ new_children ||= @children.dup
165
+ new_children[index] = new_child
166
+ new_size += new_child.size - child.size
167
+ end
168
+ else
169
+ new_children ||= @children.dup
170
+ new_children[index] = Trie.new(@significant_bits + 5).put!(key, value)
171
+ new_size += 1
172
+ end
173
+ end
174
+ end
175
+
176
+ if new_entries || new_children
177
+ Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
178
+ else
179
+ self
180
+ end
181
+ end
182
+
183
+ # Returns <tt>self</tt> after overwriting the element associated with the specified key.
184
+ def put!(key, value)
185
+ index = index_for(key)
186
+ entry = @entries[index]
187
+ if !entry
188
+ @size += 1
189
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
190
+ @entries[index] = [key, value].freeze
191
+ elsif entry[0].eql?(key)
192
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
193
+ @entries[index] = [key, value].freeze
194
+ else
195
+ child = @children[index]
196
+ if child
197
+ old_child_size = child.size
198
+ @children[index] = child.put!(key, value)
199
+ @size += child.size - old_child_size
200
+ else
201
+ @children[index] = Trie.new(@significant_bits + 5).put!(key, value)
202
+ @size += 1
203
+ end
204
+ end
205
+ self
206
+ end
207
+
208
+ # Retrieves the entry corresponding to the given key. If not found, returns <tt>nil</tt>.
209
+ def get(key)
210
+ index = index_for(key)
211
+ entry = @entries[index]
212
+ if entry && entry[0].eql?(key)
213
+ entry
214
+ else
215
+ child = @children[index]
216
+ child.get(key) if child
217
+ end
218
+ end
219
+
220
+ # Returns a copy of <tt>self</tt> with the given key (and associated value) deleted. If not found, returns <tt>self</tt>.
221
+ def delete(key)
222
+ find_and_delete(key) || Trie.new(@significant_bits)
223
+ end
224
+
225
+ # Delete multiple elements from a Trie. This is more efficient than
226
+ # several calls to `#delete`.
227
+ #
228
+ # @param keys [Enumerable] The keys to delete
229
+ # @return [Trie]
230
+ def bulk_delete(keys)
231
+ new_entries = nil
232
+ new_children = nil
233
+ new_size = @size
234
+
235
+ keys.each do |key|
236
+ index = index_for(key)
237
+ entry = (new_entries || @entries)[index]
238
+ if !entry
239
+ next
240
+ elsif entry[0].eql?(key)
241
+ new_entries ||= @entries.dup
242
+ child = (new_children || @children)[index]
243
+ if child
244
+ # Bring up the first entry from the child into entries
245
+ new_children ||= @children.dup
246
+ new_children[index] = child.delete_at do |child_entry|
247
+ new_entries[index] = child_entry
248
+ end
249
+ else
250
+ new_entries[index] = nil
251
+ end
252
+ new_size -= 1
253
+ else
254
+ child = (new_children || @children)[index]
255
+ if child
256
+ copy = child.find_and_delete(key)
257
+ unless copy.equal?(child)
258
+ new_children ||= @children.dup
259
+ new_children[index] = copy
260
+ new_size -= (child.size - copy_size(copy))
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ if new_entries || new_children
267
+ Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
268
+ else
269
+ self
270
+ end
271
+ end
272
+
273
+ def include?(key, value)
274
+ entry = get(key)
275
+ entry && value.eql?(entry[1])
276
+ end
277
+
278
+ def at(index)
279
+ @entries.each do |entry|
280
+ if entry
281
+ return entry if index == 0
282
+ index -= 1
283
+ end
284
+ end
285
+ @children.each do |child|
286
+ if child
287
+ if child.size >= index+1
288
+ return child.at(index)
289
+ else
290
+ index -= child.size
291
+ end
292
+ end
293
+ end
294
+ nil
295
+ end
296
+
297
+ # Returns <tt>true</tt> if . <tt>eql?</tt> is synonymous with <tt>==</tt>
298
+ def eql?(other)
299
+ return true if equal?(other)
300
+ return false unless instance_of?(other.class) && size == other.size
301
+ each do |entry|
302
+ return false unless other.include?(entry[0], entry[1])
303
+ end
304
+ true
305
+ end
306
+ alias :== :eql?
307
+
308
+ protected
309
+
310
+ # Returns a replacement instance after removing the specified key.
311
+ # If not found, returns <tt>self</tt>.
312
+ # If empty, returns <tt>nil</tt>.
313
+ def find_and_delete(key)
314
+ index = index_for(key)
315
+ entry = @entries[index]
316
+ if entry && entry[0].eql?(key)
317
+ return delete_at(index)
318
+ else
319
+ child = @children[index]
320
+ if child
321
+ copy = child.find_and_delete(key)
322
+ unless copy.equal?(child)
323
+ children = @children.dup
324
+ children[index] = copy
325
+ new_size = @size - (child.size - copy_size(copy))
326
+ return Trie.new(@significant_bits, new_size, @entries, children)
327
+ end
328
+ end
329
+ end
330
+ self
331
+ end
332
+
333
+ # Returns a replacement instance after removing the specified entry. If empty, returns <tt>nil</tt>
334
+ def delete_at(index = @entries.index { |e| e })
335
+ yield(@entries[index]) if block_given?
336
+ if size > 1
337
+ entries = @entries.dup
338
+ child = @children[index]
339
+ if child
340
+ children = @children.dup
341
+ children[index] = child.delete_at do |entry|
342
+ entries[index] = entry
343
+ end
344
+ else
345
+ entries[index] = nil
346
+ end
347
+ Trie.new(@significant_bits, @size - 1, entries, children || @children)
348
+ end
349
+ end
350
+
351
+ private
352
+
353
+ def index_for(key)
354
+ (key.hash.abs >> @significant_bits) & 31
355
+ end
356
+
357
+ def copy_size(copy)
358
+ copy ? copy.size : 0
359
+ end
360
+ end
361
+
362
+ # @private
363
+ EmptyTrie = Erlang::Trie.new(0)
364
+ end
@@ -1,23 +1,1591 @@
1
1
  module Erlang
2
- class Tuple < ::Array
3
- def arity
4
- length
2
+ # A `Tuple` is an ordered, integer-indexed collection of objects. Like
3
+ # Ruby's `Array`, `Tuple` indexing starts at zero and negative indexes count
4
+ # back from the end.
5
+ #
6
+ # `Tuple` has a similar interface to `Array`. The main difference is methods
7
+ # that would destructively update an `Array` (such as {#insert} or
8
+ # {#delete_at}) instead return new `Tuple`s and leave the existing one
9
+ # unchanged.
10
+ #
11
+ # ### Creating New Tuples
12
+ #
13
+ # Erlang::Tuple.new([:first, :second, :third])
14
+ # Erlang::Tuple[1, 2, 3, 4, 5]
15
+ #
16
+ # ### Retrieving Elements from Tuples
17
+ #
18
+ # tuple = Erlang::Tuple[1, 2, 3, 4, 5]
19
+ #
20
+ # tuple[0] # => 1
21
+ # tuple[-1] # => 5
22
+ # tuple[0,3] # => Erlang::Tuple[1, 2, 3]
23
+ # tuple[1..-1] # => Erlang::Tuple[2, 3, 4, 5]
24
+ # tuple.first # => 1
25
+ # tuple.last # => 5
26
+ #
27
+ # ### Creating Modified Tuples
28
+ #
29
+ # tuple.add(6) # => Erlang::Tuple[1, 2, 3, 4, 5, 6]
30
+ # tuple.insert(1, :a, :b) # => Erlang::Tuple[1, :a, :b, 2, 3, 4, 5]
31
+ # tuple.delete_at(2) # => Erlang::Tuple[1, 2, 4, 5]
32
+ # tuple + [6, 7] # => Erlang::Tuple[1, 2, 3, 4, 5, 6, 7]
33
+ #
34
+ # Licensing
35
+ # =========
36
+ #
37
+ # Portions taken and modified from https://github.com/hamstergem/hamster
38
+ #
39
+ # Copyright (c) 2009-2014 Simon Harris
40
+ #
41
+ # Permission is hereby granted, free of charge, to any person obtaining
42
+ # a copy of this software and associated documentation files (the
43
+ # "Software"), to deal in the Software without restriction, including
44
+ # without limitation the rights to use, copy, modify, merge, publish,
45
+ # distribute, sublicense, and/or sell copies of the Software, and to
46
+ # permit persons to whom the Software is furnished to do so, subject to
47
+ # the following conditions:
48
+ #
49
+ # The above copyright notice and this permission notice shall be
50
+ # included in all copies or substantial portions of the Software.
51
+ #
52
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
53
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
55
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
56
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
57
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
58
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59
+ #
60
+ class Tuple
61
+ include Erlang::Term
62
+ include Erlang::Immutable
63
+ include Erlang::Enumerable
64
+ include Erlang::Associable
65
+
66
+ # @private
67
+ BLOCK_SIZE = 32
68
+ # @private
69
+ INDEX_MASK = BLOCK_SIZE - 1
70
+ # @private
71
+ BITS_PER_LEVEL = 5
72
+
73
+ # Return the number of elements in this `Tuple`
74
+ # @return [Integer]
75
+ attr_reader :size
76
+ alias :arity :size
77
+ alias :length :size
78
+
79
+ class << self
80
+ # Create a new `Tuple` populated with the given elements.
81
+ # @return [Tuple]
82
+ def [](*elements)
83
+ return new(elements.freeze)
84
+ end
85
+
86
+ # Return an empty `Tuple`. If used on a subclass, returns an empty instance
87
+ # of that class.
88
+ #
89
+ # @return [Tuple]
90
+ def empty
91
+ return @empty ||= self.new
92
+ end
93
+
94
+ # "Raw" allocation of a new `Tuple`. Used internally to create a new
95
+ # instance quickly after building a modified trie.
96
+ #
97
+ # @return [Tuple]
98
+ # @private
99
+ def alloc(root, size, levels)
100
+ obj = allocate
101
+ obj.instance_variable_set(:@root, root)
102
+ obj.instance_variable_set(:@size, size)
103
+ obj.instance_variable_set(:@levels, levels)
104
+ return obj
105
+ end
106
+
107
+ def compare(a, b)
108
+ raise ArgumentError, "'a' must be of Erlang::Tuple type" if not a.kind_of?(Erlang::Tuple)
109
+ raise ArgumentError, "'b' must be of Erlang::Tuple type" if not b.kind_of?(Erlang::Tuple)
110
+ c = a.size <=> b.size
111
+ i = 0
112
+ while c == 0 and i < a.size and i < b.size
113
+ c = Erlang.compare(a[i], b[i])
114
+ i += 1
115
+ end
116
+ return c
117
+ end
118
+ end
119
+
120
+ def initialize(elements=[].freeze)
121
+ elements = elements.to_a.map { |element| Erlang.from(element) }
122
+ if elements.size <= 32
123
+ elements = elements.dup.freeze if !elements.frozen?
124
+ @root, @size, @levels = elements, elements.size, 0
125
+ else
126
+ root, size, levels = elements, elements.size, 0
127
+ while root.size > 32
128
+ root = root.each_slice(32).to_a
129
+ levels += 1
130
+ end
131
+ @root, @size, @levels = root.freeze, size, levels
132
+ end
133
+ end
134
+
135
+ # Return `true` if this `Tuple` contains no elements.
136
+ #
137
+ # @return [Boolean]
138
+ def empty?
139
+ return @size == 0
140
+ end
141
+
142
+ # Return the first element in the `Tuple`. If the tuple is empty, return `nil`.
143
+ #
144
+ # @example
145
+ # Erlang::Tuple["A", "B", "C"].first # => "A"
146
+ #
147
+ # @return [Object]
148
+ def first
149
+ return get(0)
150
+ end
151
+
152
+ # Return the last element in the `Tuple`. If the tuple is empty, return `nil`.
153
+ #
154
+ # @example
155
+ # Erlang::Tuple["A", "B", "C"].last # => "C"
156
+ #
157
+ # @return [Object]
158
+ def last
159
+ return get(-1)
160
+ end
161
+
162
+ # Return a new `Tuple` with `element` added after the last occupied position.
163
+ #
164
+ # @example
165
+ # Erlang::Tuple[1, 2].add(99) # => Erlang::Tuple[1, 2, 99]
166
+ #
167
+ # @param element [Object] The object to insert at the end of the tuple
168
+ # @return [Tuple]
169
+ def add(element)
170
+ return update_root(@size, Erlang.from(element))
171
+ end
172
+ alias :<< :add
173
+ alias :push :add
174
+
175
+ # Return a new `Tuple` with a new value at the given `index`. If `index`
176
+ # is greater than the length of the tuple, the returned tuple will be
177
+ # padded with `nil`s to the correct size.
178
+ #
179
+ # @overload put(index, element)
180
+ # Return a new `Tuple` with the element at `index` replaced by `element`.
181
+ #
182
+ # @param element [Object] The object to insert into that position
183
+ # @example
184
+ # Erlang::Tuple[1, 2, 3, 4].put(2, 99)
185
+ # # => Erlang::Tuple[1, 2, 99, 4]
186
+ # Erlang::Tuple[1, 2, 3, 4].put(-1, 99)
187
+ # # => Erlang::Tuple[1, 2, 3, 99]
188
+ # Erlang::Tuple[].put(2, 99)
189
+ # # => Erlang::Tuple[nil, nil, 99]
190
+ #
191
+ # @overload put(index)
192
+ # Return a new `Tuple` with the element at `index` replaced by the return
193
+ # value of the block.
194
+ #
195
+ # @yield (existing) Once with the existing value at the given `index`.
196
+ # @example
197
+ # Erlang::Tuple[1, 2, 3, 4].put(2) { |v| v * 10 }
198
+ # # => Erlang::Tuple[1, 2, 30, 4]
199
+ #
200
+ # @param index [Integer] The index to update. May be negative.
201
+ # @return [Tuple]
202
+ def put(index, element = yield(get(index)))
203
+ raise IndexError, "index #{index} outside of tuple bounds" if index < -@size
204
+ element = Erlang.from(element)
205
+ index += @size if index < 0
206
+ if index > @size
207
+ suffix = Array.new(index - @size, nil)
208
+ suffix << element
209
+ return replace_suffix(@size, suffix)
210
+ else
211
+ return update_root(index, element)
212
+ end
213
+ end
214
+ alias :set :put
215
+
216
+ # @!method update_in(*key_path, &block)
217
+ # Return a new `Tuple` with a deeply nested value modified to the result
218
+ # of the given code block. When traversing the nested `Tuple`s and
219
+ # `Hash`es, non-existing keys are created with empty `Hash` values.
220
+ #
221
+ # The code block receives the existing value of the deeply nested key (or
222
+ # `nil` if it doesn't exist). This is useful for "transforming" the value
223
+ # associated with a certain key.
224
+ #
225
+ # Note that the original `Tuple` and sub-`Tuple`s and sub-`Hash`es are
226
+ # left unmodified; new data structure copies are created along the path
227
+ # wherever needed.
228
+ #
229
+ # @example
230
+ # t = Erlang::Tuple[123, 456, 789, Erlang::Map["a" => Erlang::Tuple[5, 6, 7]]]
231
+ # t.update_in(3, "a", 1) { |value| value + 9 }
232
+ # # => Erlang::Tuple[123, 456, 789, Erlang::Map["a" => Erlang::Tuple[5, 15, 7]]]
233
+ #
234
+ # @param key_path [Object(s)] List of keys which form the path to the key to be modified
235
+ # @yield [value] The previously stored value
236
+ # @yieldreturn [Object] The new value to store
237
+ # @return [Tuple]
238
+ # @see Associable#update_in
239
+
240
+ # Retrieve the element at `index`. If there is none (either the provided index
241
+ # is too high or too low), return `nil`.
242
+ #
243
+ # @example
244
+ # t = Erlang::Tuple["A", "B", "C", "D"]
245
+ # t.get(2) # => "C"
246
+ # t.get(-1) # => "D"
247
+ # t.get(4) # => nil
248
+ #
249
+ # @param index [Integer] The index to retrieve
250
+ # @return [Object]
251
+ def get(index)
252
+ return nil if @size == 0
253
+ index += @size if index < 0
254
+ return nil if index >= @size || index < 0
255
+ return leaf_node_for(@root, @levels * BITS_PER_LEVEL, index)[index & INDEX_MASK]
256
+ end
257
+ alias :at :get
258
+
259
+ # Retrieve the value at `index` with optional default.
260
+ #
261
+ # @overload fetch(index)
262
+ # Retrieve the value at the given index, or raise an `IndexError` if not
263
+ # found.
264
+ #
265
+ # @param index [Integer] The index to look up
266
+ # @raise [IndexError] if index does not exist
267
+ # @example
268
+ # t = Erlang::Tuple["A", "B", "C", "D"]
269
+ # t.fetch(2) # => "C"
270
+ # t.fetch(-1) # => "D"
271
+ # t.fetch(4) # => IndexError: index 4 outside of tuple bounds
272
+ #
273
+ # @overload fetch(index) { |index| ... }
274
+ # Retrieve the value at the given index, or return the result of yielding
275
+ # the block if not found.
276
+ #
277
+ # @yield Once if the index is not found.
278
+ # @yieldparam [Integer] index The index which does not exist
279
+ # @yieldreturn [Object] Default value to return
280
+ # @param index [Integer] The index to look up
281
+ # @example
282
+ # t = Erlang::Tuple["A", "B", "C", "D"]
283
+ # t.fetch(2) { |i| i * i } # => "C"
284
+ # t.fetch(4) { |i| i * i } # => 16
285
+ #
286
+ # @overload fetch(index, default)
287
+ # Retrieve the value at the given index, or return the provided `default`
288
+ # value if not found.
289
+ #
290
+ # @param index [Integer] The index to look up
291
+ # @param default [Object] Object to return if the key is not found
292
+ # @example
293
+ # t = Erlang::Tuple["A", "B", "C", "D"]
294
+ # t.fetch(2, "Z") # => "C"
295
+ # t.fetch(4, "Z") # => "Z"
296
+ #
297
+ # @return [Object]
298
+ def fetch(index, default = (missing_default = true))
299
+ if index >= -@size && index < @size
300
+ return get(index)
301
+ elsif block_given?
302
+ return Erlang.from(yield(index))
303
+ elsif !missing_default
304
+ return Erlang.from(default)
305
+ else
306
+ raise IndexError, "index #{index} outside of tuple bounds"
307
+ end
308
+ end
309
+
310
+ # Return specific objects from the `Tuple`. All overloads return `nil` if
311
+ # the starting index is out of range.
312
+ #
313
+ # @overload tuple.slice(index)
314
+ # Returns a single object at the given `index`. If `index` is negative,
315
+ # count backwards from the end.
316
+ #
317
+ # @param index [Integer] The index to retrieve. May be negative.
318
+ # @return [Object]
319
+ # @example
320
+ # t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
321
+ # t[2] # => "C"
322
+ # t[-1] # => "F"
323
+ # t[6] # => nil
324
+ #
325
+ # @overload tuple.slice(index, length)
326
+ # Return a subtuple starting at `index` and continuing for `length`
327
+ # elements or until the end of the `Tuple`, whichever occurs first.
328
+ #
329
+ # @param start [Integer] The index to start retrieving elements from. May be
330
+ # negative.
331
+ # @param length [Integer] The number of elements to retrieve.
332
+ # @return [Tuple]
333
+ # @example
334
+ # t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
335
+ # t[2, 3] # => Erlang::Tuple["C", "D", "E"]
336
+ # t[-2, 3] # => Erlang::Tuple["E", "F"]
337
+ # t[20, 1] # => nil
338
+ #
339
+ # @overload tuple.slice(index..end)
340
+ # Return a subtuple starting at `index` and continuing to index
341
+ # `end` or the end of the `Tuple`, whichever occurs first.
342
+ #
343
+ # @param range [Range] The range of indices to retrieve.
344
+ # @return [Tuple]
345
+ # @example
346
+ # t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
347
+ # t[2..3] # => Erlang::Tuple["C", "D"]
348
+ # t[-2..100] # => Erlang::Tuple["E", "F"]
349
+ # t[20..21] # => nil
350
+ def slice(arg, length = (missing_length = true))
351
+ if missing_length
352
+ if arg.is_a?(Range)
353
+ from, to = arg.begin, arg.end
354
+ from += @size if from < 0
355
+ to += @size if to < 0
356
+ to += 1 if !arg.exclude_end?
357
+ length = to - from
358
+ length = 0 if length < 0
359
+ return subsequence(from, length)
360
+ else
361
+ return get(arg)
362
+ end
363
+ else
364
+ arg += @size if arg < 0
365
+ return subsequence(arg, length)
366
+ end
367
+ end
368
+ alias :[] :slice
369
+
370
+ # Return a new `Tuple` with the given values inserted before the element
371
+ # at `index`. If `index` is greater than the current length, `nil` values
372
+ # are added to pad the `Tuple` to the required size.
373
+ #
374
+ # @example
375
+ # Erlang::Tuple["A", "B", "C", "D"].insert(2, "X", "Y", "Z")
376
+ # # => Erlang::Tuple["A", "B", "X", "Y", "Z", "C", "D"]
377
+ # Erlang::Tuple[].insert(2, "X", "Y", "Z")
378
+ # # => Erlang::Tuple[nil, nil, "X", "Y", "Z"]
379
+ #
380
+ # @param index [Integer] The index where the new elements should go
381
+ # @param elements [Array] The elements to add
382
+ # @return [Tuple]
383
+ # @raise [IndexError] if index exceeds negative range.
384
+ def insert(index, *elements)
385
+ raise IndexError if index < -@size
386
+ index += @size if index < 0
387
+
388
+ elements = elements.map { |element| Erlang.from(element) }
389
+
390
+ if index < @size
391
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
392
+ suffix.unshift(*elements)
393
+ elsif index == @size
394
+ suffix = elements
395
+ else
396
+ suffix = Array.new(index - @size, nil).concat(elements)
397
+ index = @size
398
+ end
399
+
400
+ return replace_suffix(index, suffix)
401
+ end
402
+
403
+ # Return a new `Tuple` with the element at `index` removed. If the given `index`
404
+ # does not exist, return `self`.
405
+ #
406
+ # @example
407
+ # Erlang::Tuple["A", "B", "C", "D"].delete_at(2)
408
+ # # => Erlang::Tuple["A", "B", "D"]
409
+ #
410
+ # @param index [Integer] The index to remove
411
+ # @return [Tuple]
412
+ def delete_at(index)
413
+ return self if index >= @size || index < -@size
414
+ index += @size if index < 0
415
+
416
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
417
+ return replace_suffix(index, suffix.tap { |a| a.shift })
418
+ end
419
+
420
+ # Return a new `Tuple` with the last element removed. Return `self` if
421
+ # empty.
422
+ #
423
+ # @example
424
+ # Erlang::Tuple["A", "B", "C"].pop # => Erlang::Tuple["A", "B"]
425
+ #
426
+ # @return [Tuple]
427
+ def pop
428
+ return self if @size == 0
429
+ return replace_suffix(@size-1, [])
430
+ end
431
+
432
+ # Return a new `Tuple` with `object` inserted before the first element,
433
+ # moving the other elements upwards.
434
+ #
435
+ # @example
436
+ # Erlang::Tuple["A", "B"].unshift("Z")
437
+ # # => Erlang::Tuple["Z", "A", "B"]
438
+ #
439
+ # @param object [Object] The value to prepend
440
+ # @return [Tuple]
441
+ def unshift(object)
442
+ return insert(0, Erlang.from(object))
443
+ end
444
+
445
+ # Return a new `Tuple` with the first element removed. If empty, return
446
+ # `self`.
447
+ #
448
+ # @example
449
+ # Erlang::Tuple["A", "B", "C"].shift # => Erlang::Tuple["B", "C"]
450
+ #
451
+ # @return [Tuple]
452
+ def shift
453
+ return delete_at(0)
454
+ end
455
+
456
+ # Call the given block once for each element in the tuple, passing each
457
+ # element from first to last successively to the block. If no block is given,
458
+ # an `Enumerator` is returned instead.
459
+ #
460
+ # @example
461
+ # Erlang::Tuple["A", "B", "C"].each { |e| puts "Element: #{e}" }
462
+ #
463
+ # Element: A
464
+ # Element: B
465
+ # Element: C
466
+ # # => Erlang::Tuple["A", "B", "C"]
467
+ #
468
+ # @return [self, Enumerator]
469
+ def each(&block)
470
+ return to_enum unless block_given?
471
+ traverse_depth_first(@root, @levels, &block)
472
+ return self
473
+ end
474
+
475
+ # Call the given block once for each element in the tuple, from last to
476
+ # first.
477
+ #
478
+ # @example
479
+ # Erlang::Tuple["A", "B", "C"].reverse_each { |e| puts "Element: #{e}" }
480
+ #
481
+ # Element: C
482
+ # Element: B
483
+ # Element: A
484
+ #
485
+ # @return [self]
486
+ def reverse_each(&block)
487
+ return enum_for(:reverse_each) unless block_given?
488
+ reverse_traverse_depth_first(@root, @levels, &block)
489
+ return self
490
+ end
491
+
492
+ # Return a new `Tuple` containing all elements for which the given block returns
493
+ # true.
494
+ #
495
+ # @example
496
+ # Erlang::Tuple["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
497
+ # # => Erlang::Tuple["Bird", "Elephant"]
498
+ #
499
+ # @return [Tuple]
500
+ # @yield [element] Once for each element.
501
+ def select
502
+ return enum_for(:select) unless block_given?
503
+ return reduce(self.class.empty) { |tuple, element| yield(element) ? tuple.add(element) : tuple }
504
+ end
505
+ alias :find_all :select
506
+ alias :keep_if :select
507
+
508
+ # Return a new `Tuple` with all elements which are equal to `obj` removed.
509
+ # `#==` is used for checking equality.
510
+ #
511
+ # @example
512
+ # Erlang::Tuple["C", "B", "A", "B"].delete("B") # => Erlang::Tuple["C", "A"]
513
+ #
514
+ # @param obj [Object] The object to remove (every occurrence)
515
+ # @return [Tuple]
516
+ def delete(obj)
517
+ obj = Erlang.from(obj)
518
+ return select { |element| element != obj }
519
+ end
520
+
521
+ # Invoke the given block once for each element in the tuple, and return a new
522
+ # `Tuple` containing the values returned by the block. If no block is
523
+ # provided, return an enumerator.
524
+ #
525
+ # @example
526
+ # Erlang::Tuple[3, 2, 1].map { |e| e * e } # => Erlang::Tuple[9, 4, 1]
527
+ #
528
+ # @return [Tuple, Enumerator]
529
+ def map
530
+ return enum_for(:map) if not block_given?
531
+ return self if empty?
532
+ return self.class.new(super)
533
+ end
534
+ alias :collect :map
535
+
536
+ # Return a new `Tuple` with the concatenated results of running the block once
537
+ # for every element in this `Tuple`.
538
+ #
539
+ # @example
540
+ # Erlang::Tuple[1, 2, 3].flat_map { |x| [x, -x] }
541
+ # # => Erlang::Tuple[1, -1, 2, -2, 3, -3]
542
+ #
543
+ # @return [Tuple]
544
+ def flat_map
545
+ return enum_for(:flat_map) if not block_given?
546
+ return self if empty?
547
+ return self.class.new(super)
548
+ end
549
+
550
+ # Return a new `Tuple` with the same elements as this one, but randomly permuted.
551
+ #
552
+ # @example
553
+ # Erlang::Tuple[1, 2, 3, 4].shuffle # => Erlang::Tuple[4, 1, 3, 2]
554
+ #
555
+ # @return [Tuple]
556
+ def shuffle
557
+ return self.class.new(((array = to_a).frozen? ? array.shuffle : array.shuffle!).freeze)
558
+ end
559
+
560
+ # Return a new `Tuple` with no duplicate elements, as determined by `#hash` and
561
+ # `#eql?`. For each group of equivalent elements, only the first will be retained.
562
+ #
563
+ # @example
564
+ # Erlang::Tuple["A", "B", "C", "B"].uniq # => Erlang::Tuple["A", "B", "C"]
565
+ # Erlang::Tuple["a", "A", "b"].uniq(&:upcase) # => Erlang::Tuple["a", "b"]
566
+ #
567
+ # @return [Tuple]
568
+ def uniq(&block)
569
+ array = self.to_a
570
+ if block_given?
571
+ if array.frozen?
572
+ return self.class.new(array.uniq(&block).freeze)
573
+ elsif array.uniq!(&block) # returns nil if no changes were made
574
+ return self.class.new(array.freeze)
575
+ else
576
+ return self
577
+ end
578
+ elsif array.frozen?
579
+ return self.class.new(array.uniq.freeze)
580
+ elsif array.uniq! # returns nil if no changes were made
581
+ return self.class.new(array.freeze)
582
+ else
583
+ return self
584
+ end
585
+ end
586
+
587
+ # Return a new `Tuple` with the same elements as this one, but in reverse order.
588
+ #
589
+ # @example
590
+ # Erlang::Tuple["A", "B", "C"].reverse # => Erlang::Tuple["C", "B", "A"]
591
+ #
592
+ # @return [Tuple]
593
+ def reverse
594
+ return self.class.new(((array = to_a).frozen? ? array.reverse : array.reverse!).freeze)
595
+ end
596
+
597
+ # Return a new `Tuple` with the same elements, but rotated so that the one at
598
+ # index `count` is the first element of the new tuple. If `count` is positive,
599
+ # the elements will be shifted left, and those shifted past the lowest position
600
+ # will be moved to the end. If `count` is negative, the elements will be shifted
601
+ # right, and those shifted past the last position will be moved to the beginning.
602
+ #
603
+ # @example
604
+ # t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
605
+ # t.rotate(2) # => Erlang::Tuple["C", "D", "E", "F", "A", "B"]
606
+ # t.rotate(-1) # => Erlang::Tuple["F", "A", "B", "C", "D", "E"]
607
+ #
608
+ # @param count [Integer] The number of positions to shift elements by
609
+ # @return [Tuple]
610
+ def rotate(count = 1)
611
+ return self if (count % @size) == 0
612
+ return self.class.new(((array = to_a).frozen? ? array.rotate(count) : array.rotate!(count)).freeze)
613
+ end
614
+
615
+ # Return a new `Tuple` with all nested tuples and arrays recursively "flattened
616
+ # out". That is, their elements inserted into the new `Tuple` in the place where
617
+ # the nested array/tuple originally was. If an optional `level` argument is
618
+ # provided, the flattening will only be done recursively that number of times.
619
+ # A `level` of 0 means not to flatten at all, 1 means to only flatten nested
620
+ # arrays/tuples which are directly contained within this `Tuple`.
621
+ #
622
+ # @example
623
+ # t = Erlang::Tuple["A", Erlang::Tuple["B", "C", Erlang::Tuple["D"]]]
624
+ # t.flatten(1)
625
+ # # => Erlang::Tuple["A", "B", "C", Erlang::Tuple["D"]]
626
+ # t.flatten
627
+ # # => Erlang::Tuple["A", "B", "C", "D"]
628
+ #
629
+ # @param level [Integer] The depth to which flattening should be applied
630
+ # @return [Tuple]
631
+ def flatten(level = -1)
632
+ return self if level == 0
633
+ array = self.to_a
634
+ if array.frozen?
635
+ return self.class.new(array.flatten(level).freeze)
636
+ elsif array.flatten!(level) # returns nil if no changes were made
637
+ return self.class.new(array.freeze)
638
+ else
639
+ return self
640
+ end
641
+ end
642
+
643
+ # Return a new `Tuple` built by concatenating this one with `other`. `other`
644
+ # can be any object which is convertible to an `Array` using `#to_a`.
645
+ #
646
+ # @example
647
+ # Erlang::Tuple["A", "B", "C"] + ["D", "E"]
648
+ # # => Erlang::Tuple["A", "B", "C", "D", "E"]
649
+ #
650
+ # @param other [Enumerable] The collection to concatenate onto this tuple
651
+ # @return [Tuple]
652
+ def +(other)
653
+ other = Erlang.from(other)
654
+ other = other.to_a
655
+ other = other.dup if other.frozen?
656
+ return replace_suffix(@size, other)
657
+ end
658
+ alias :concat :+
659
+
660
+ # Combine two tuples by "zipping" them together. `others` should be arrays
661
+ # and/or tuples. The corresponding elements from this `Tuple` and each of
662
+ # `others` (that is, the elements with the same indices) will be gathered
663
+ # into arrays.
664
+ #
665
+ # If `others` contains fewer elements than this tuple, `nil` will be used
666
+ # for padding.
667
+ #
668
+ # @overload zip(*others)
669
+ # Return a new tuple containing the new arrays.
670
+ #
671
+ # @return [Tuple]
672
+ #
673
+ # @overload zip(*others)
674
+ # @yield [pair] once for each array
675
+ # @return [nil]
676
+ #
677
+ # @example
678
+ # t1 = Erlang::Tuple["A", "B", "C"]
679
+ # t2 = Erlang::Tuple[1, 2]
680
+ # t1.zip(t2)
681
+ # # => Erlang::Tuple[["A", 1], ["B", 2], ["C", nil]]
682
+ #
683
+ # @param others [Array] The arrays/tuples to zip together with this one
684
+ # @return [Tuple]
685
+ def zip(*others)
686
+ others = others.map { |other| Erlang.from(other) }
687
+ if block_given?
688
+ return super(*others)
689
+ else
690
+ return self.class.new(super(*others))
691
+ end
692
+ end
693
+
694
+ # Return a new `Tuple` with the same elements, but sorted.
695
+ #
696
+ # @overload sort
697
+ # Compare elements with their natural sort key (`#<=>`).
698
+ #
699
+ # @example
700
+ # Erlang::Tuple["Elephant", "Dog", "Lion"].sort
701
+ # # => Erlang::Tuple["Dog", "Elephant", "Lion"]
702
+ #
703
+ # @overload sort
704
+ # Uses the block as a comparator to determine sorted order.
705
+ #
706
+ # @yield [a, b] Any number of times with different pairs of elements.
707
+ # @yieldreturn [Integer] Negative if the first element should be sorted
708
+ # lower, positive if the latter element, or 0 if
709
+ # equal.
710
+ # @example
711
+ # Erlang::Tuple["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
712
+ # # => Erlang::Tuple["Dog", "Lion", "Elephant"]
713
+ #
714
+ # @return [Tuple]
715
+ def sort(&comparator)
716
+ comparator = Erlang.method(:compare) unless block_given?
717
+ array = super(&comparator)
718
+ return self.class.new(array)
719
+ end
720
+
721
+ # Return a new `Tuple` with the same elements, but sorted. The sort order is
722
+ # determined by mapping the elements through the given block to obtain sort
723
+ # keys, and then sorting the keys according to their natural sort order
724
+ # (`#<=>`).
725
+ #
726
+ # @yield [element] Once for each element.
727
+ # @yieldreturn a sort key object for the yielded element.
728
+ # @example
729
+ # Erlang::Tuple["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
730
+ # # => Erlang::Tuple["Dog", "Lion", "Elephant"]
731
+ #
732
+ # @return [Tuple]
733
+ def sort_by
734
+ return sort unless block_given?
735
+ block = ->(x) { Erlang.from(transformer.call(x)) }
736
+ array = super(&block)
737
+ return self.class.new(array)
738
+ end
739
+
740
+ # Drop the first `n` elements and return the rest in a new `Tuple`.
741
+ #
742
+ # @example
743
+ # Erlang::Tuple["A", "B", "C", "D", "E", "F"].drop(2)
744
+ # # => Erlang::Tuple["C", "D", "E", "F"]
745
+ #
746
+ # @param n [Integer] The number of elements to remove
747
+ # @return [Tuple]
748
+ # @raise ArgumentError if `n` is negative.
749
+ def drop(n)
750
+ return self if n == 0
751
+ return self.class.empty if n >= @size
752
+ raise ArgumentError, "attempt to drop negative size" if n < 0
753
+ return self.class.new(flatten_suffix(@root, @levels * BITS_PER_LEVEL, n, []))
754
+ end
755
+
756
+ # Return only the first `n` elements in a new `Tuple`.
757
+ #
758
+ # @example
759
+ # Erlang::Tuple["A", "B", "C", "D", "E", "F"].take(4)
760
+ # # => Erlang::Tuple["A", "B", "C", "D"]
761
+ #
762
+ # @param n [Integer] The number of elements to retain
763
+ # @return [Tuple]
764
+ def take(n)
765
+ return self if n >= @size
766
+ return self.class.new(super)
767
+ end
768
+
769
+ # Drop elements up to, but not including, the first element for which the
770
+ # block returns `nil` or `false`. Gather the remaining elements into a new
771
+ # `Tuple`. If no block is given, an `Enumerator` is returned instead.
772
+ #
773
+ # @example
774
+ # Erlang::Tuple[1, 3, 5, 7, 6, 4, 2].drop_while { |e| e < 5 }
775
+ # # => Erlang::Tuple[5, 7, 6, 4, 2]
776
+ #
777
+ # @return [Tuple, Enumerator]
778
+ def drop_while
779
+ return enum_for(:drop_while) if not block_given?
780
+ return self.class.new(super)
781
+ end
782
+
783
+ # Gather elements up to, but not including, the first element for which the
784
+ # block returns `nil` or `false`, and return them in a new `Tuple`. If no block
785
+ # is given, an `Enumerator` is returned instead.
786
+ #
787
+ # @example
788
+ # Erlang::Tuple[1, 3, 5, 7, 6, 4, 2].take_while { |e| e < 5 }
789
+ # # => Erlang::Tuple[1, 3]
790
+ #
791
+ # @return [Tuple, Enumerator]
792
+ def take_while
793
+ return enum_for(:take_while) if not block_given?
794
+ return self.class.new(super)
795
+ end
796
+
797
+ # Repetition. Return a new `Tuple` built by concatenating `times` copies
798
+ # of this one together.
799
+ #
800
+ # @example
801
+ # Erlang::Tuple["A", "B"] * 3
802
+ # # => Erlang::Tuple["A", "B", "A", "B", "A", "B"]
803
+ #
804
+ # @param times [Integer] The number of times to repeat the elements in this tuple
805
+ # @return [Tuple]
806
+ def *(times)
807
+ return self.class.empty if times == 0
808
+ return self if times == 1
809
+ result = (to_a * times)
810
+ return result.is_a?(Array) ? self.class.new(result) : result
5
811
  end
6
812
 
7
- def inspect
8
- "#<#{self.class.name} {#{super[1..-2]}}>"
813
+ # Replace a range of indexes with the given object.
814
+ #
815
+ # @overload fill(object)
816
+ # Return a new `Tuple` of the same size, with every index set to
817
+ # `object`.
818
+ #
819
+ # @param [Object] object Fill value.
820
+ # @example
821
+ # Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z")
822
+ # # => Erlang::Tuple["Z", "Z", "Z", "Z", "Z", "Z"]
823
+ #
824
+ # @overload fill(object, index)
825
+ # Return a new `Tuple` with all indexes from `index` to the end of the
826
+ # tuple set to `object`.
827
+ #
828
+ # @param [Object] object Fill value.
829
+ # @param [Integer] index Starting index. May be negative.
830
+ # @example
831
+ # Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z", 3)
832
+ # # => Erlang::Tuple["A", "B", "C", "Z", "Z", "Z"]
833
+ #
834
+ # @overload fill(object, index, length)
835
+ # Return a new `Tuple` with `length` indexes, beginning from `index`,
836
+ # set to `object`. Expands the `Tuple` if `length` would extend beyond
837
+ # the current length.
838
+ #
839
+ # @param [Object] object Fill value.
840
+ # @param [Integer] index Starting index. May be negative.
841
+ # @param [Integer] length
842
+ # @example
843
+ # Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z", 3, 2)
844
+ # # => Erlang::Tuple["A", "B", "C", "Z", "Z", "F"]
845
+ # Erlang::Tuple["A", "B"].fill("Z", 1, 5)
846
+ # # => Erlang::Tuple["A", "Z", "Z", "Z", "Z", "Z"]
847
+ #
848
+ # @return [Tuple]
849
+ # @raise [IndexError] if index is out of negative range.
850
+ def fill(object, index = 0, length = nil)
851
+ raise IndexError if index < -@size
852
+ object = Erlang.from(object)
853
+ index += @size if index < 0
854
+ length ||= @size - index # to the end of the array, if no length given
855
+
856
+ if index < @size
857
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
858
+ suffix.fill(object, 0, length)
859
+ elsif index == @size
860
+ suffix = Array.new(length, object)
861
+ else
862
+ suffix = Array.new(index - @size, nil).concat(Array.new(length, object))
863
+ index = @size
864
+ end
865
+
866
+ return replace_suffix(index, suffix)
867
+ end
868
+
869
+ # When invoked with a block, yields all combinations of length `n` of elements
870
+ # from the `Tuple`, and then returns `self`. There is no guarantee about
871
+ # which order the combinations will be yielded.
872
+ #
873
+ # If no block is given, an `Enumerator` is returned instead.
874
+ #
875
+ # @example
876
+ # t = Erlang::Tuple[5, 6, 7, 8]
877
+ # t.combination(3) { |c| puts "Combination: #{c}" }
878
+ #
879
+ # Combination: [5, 6, 7]
880
+ # Combination: [5, 6, 8]
881
+ # Combination: [5, 7, 8]
882
+ # Combination: [6, 7, 8]
883
+ # #=> Erlang::Tuple[5, 6, 7, 8]
884
+ #
885
+ # @return [self, Enumerator]
886
+ def combination(n)
887
+ return enum_for(:combination, n) if not block_given?
888
+ return self if n < 0 || @size < n
889
+ if n == 0
890
+ yield []
891
+ elsif n == 1
892
+ each { |element| yield [element] }
893
+ elsif n == @size
894
+ yield self.to_a
895
+ else
896
+ combos = lambda do |result,index,remaining|
897
+ while @size - index > remaining
898
+ if remaining == 1
899
+ yield result.dup << get(index)
900
+ else
901
+ combos[result.dup << get(index), index+1, remaining-1]
902
+ end
903
+ index += 1
904
+ end
905
+ index.upto(@size-1) { |i| result << get(i) }
906
+ yield result
907
+ end
908
+ combos[[], 0, n]
909
+ end
910
+ return self
911
+ end
912
+
913
+ # When invoked with a block, yields all repeated combinations of length `n` of
914
+ # tuples from the `Tuple`, and then returns `self`. A "repeated combination" is
915
+ # one in which any tuple from the `Tuple` can appear consecutively any number of
916
+ # times.
917
+ #
918
+ # There is no guarantee about which order the combinations will be yielded in.
919
+ #
920
+ # If no block is given, an `Enumerator` is returned instead.
921
+ #
922
+ # @example
923
+ # t = Erlang::Tuple[5, 6, 7, 8]
924
+ # t.repeated_combination(2) { |c| puts "Combination: #{c}" }
925
+ #
926
+ # Combination: [5, 5]
927
+ # Combination: [5, 6]
928
+ # Combination: [5, 7]
929
+ # Combination: [5, 8]
930
+ # Combination: [6, 6]
931
+ # Combination: [6, 7]
932
+ # Combination: [6, 8]
933
+ # Combination: [7, 7]
934
+ # Combination: [7, 8]
935
+ # Combination: [8, 8]
936
+ # # => Erlang::Tuple[5, 6, 7, 8]
937
+ #
938
+ # @return [self, Enumerator]
939
+ def repeated_combination(n)
940
+ return enum_for(:repeated_combination, n) if not block_given?
941
+ if n < 0
942
+ # yield nothing
943
+ elsif n == 0
944
+ yield []
945
+ elsif n == 1
946
+ each { |element| yield [element] }
947
+ elsif @size == 0
948
+ # yield nothing
949
+ else
950
+ combos = lambda do |result,index,remaining|
951
+ while index < @size-1
952
+ if remaining == 1
953
+ yield result.dup << get(index)
954
+ else
955
+ combos[result.dup << get(index), index, remaining-1]
956
+ end
957
+ index += 1
958
+ end
959
+ element = get(index)
960
+ remaining.times { result << element }
961
+ yield result
962
+ end
963
+ combos[[], 0, n]
964
+ end
965
+ return self
966
+ end
967
+
968
+ # Yields all permutations of length `n` of elements from the `Tuple`, and then
969
+ # returns `self`. If no length `n` is specified, permutations of all elements
970
+ # will be yielded.
971
+ #
972
+ # There is no guarantee about which order the permutations will be yielded in.
973
+ #
974
+ # If no block is given, an `Enumerator` is returned instead.
975
+ #
976
+ # @example
977
+ # t = Erlang::Tuple[5, 6, 7]
978
+ # t.permutation(2) { |p| puts "Permutation: #{p}" }
979
+ #
980
+ # Permutation: [5, 6]
981
+ # Permutation: [5, 7]
982
+ # Permutation: [6, 5]
983
+ # Permutation: [6, 7]
984
+ # Permutation: [7, 5]
985
+ # Permutation: [7, 6]
986
+ # # => Erlang::Tuple[5, 6, 7]
987
+ #
988
+ # @return [self, Enumerator]
989
+ def permutation(n = @size)
990
+ return enum_for(:permutation, n) if not block_given?
991
+ if n < 0 || @size < n
992
+ # yield nothing
993
+ elsif n == 0
994
+ yield []
995
+ elsif n == 1
996
+ each { |element| yield [element] }
997
+ else
998
+ used, result = [], []
999
+ perms = lambda do |index|
1000
+ 0.upto(@size-1) do |i|
1001
+ if !used[i]
1002
+ result[index] = get(i)
1003
+ if index < n-1
1004
+ used[i] = true
1005
+ perms[index+1]
1006
+ used[i] = false
1007
+ else
1008
+ yield result.dup
1009
+ end
1010
+ end
1011
+ end
1012
+ end
1013
+ perms[0]
1014
+ end
1015
+ return self
1016
+ end
1017
+
1018
+ # When invoked with a block, yields all repeated permutations of length `n` of
1019
+ # elements from the `Tuple`, and then returns `self`. A "repeated permutation" is
1020
+ # one where any element from the `Tuple` can appear any number of times, and in
1021
+ # any position (not just consecutively)
1022
+ #
1023
+ # If no length `n` is specified, permutations of all elements will be yielded.
1024
+ # There is no guarantee about which order the permutations will be yielded in.
1025
+ #
1026
+ # If no block is given, an `Enumerator` is returned instead.
1027
+ #
1028
+ # @example
1029
+ # t = Erlang::Tuple[5, 6, 7]
1030
+ # t.repeated_permutation(2) { |p| puts "Permutation: #{p}" }
1031
+ #
1032
+ # Permutation: [5, 5]
1033
+ # Permutation: [5, 6]
1034
+ # Permutation: [5, 7]
1035
+ # Permutation: [6, 5]
1036
+ # Permutation: [6, 6]
1037
+ # Permutation: [6, 7]
1038
+ # Permutation: [7, 5]
1039
+ # Permutation: [7, 6]
1040
+ # Permutation: [7, 7]
1041
+ # # => Erlang::Tuple[5, 6, 7]
1042
+ #
1043
+ # @return [self, Enumerator]
1044
+ def repeated_permutation(n = @size)
1045
+ return enum_for(:repeated_permutation, n) if not block_given?
1046
+ if n < 0
1047
+ # yield nothing
1048
+ elsif n == 0
1049
+ yield []
1050
+ elsif n == 1
1051
+ each { |element| yield [element] }
1052
+ else
1053
+ result = []
1054
+ perms = lambda do |index|
1055
+ 0.upto(@size-1) do |i|
1056
+ result[index] = get(i)
1057
+ if index < n-1
1058
+ perms[index+1]
1059
+ else
1060
+ yield result.dup
1061
+ end
1062
+ end
1063
+ end
1064
+ perms[0]
1065
+ end
1066
+ return self
1067
+ end
1068
+
1069
+ # Cartesian product or multiplication.
1070
+ #
1071
+ # @overload product(*tuples)
1072
+ # Return a `Tuple` of all combinations of elements from this `Tuple` and each
1073
+ # of the given tuples or arrays. The length of the returned `Tuple` is the product
1074
+ # of `self.size` and the size of each argument tuple or array.
1075
+ # @example
1076
+ # t1 = Erlang::Tuple[1, 2, 3]
1077
+ # t2 = Erlang::Tuple["A", "B"]
1078
+ # t1.product(t2)
1079
+ # # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"], [3, "B"]]
1080
+ # @overload product
1081
+ # Return the result of multiplying all the elements in this `Tuple` together.
1082
+ #
1083
+ # @example
1084
+ # Erlang::Tuple[1, 2, 3, 4, 5].product # => 120
1085
+ #
1086
+ # @return [Tuple]
1087
+ def product(*tuples)
1088
+ tuples = tuples.map { |tuple| Erlang.from(tuple) }
1089
+ # if no tuples passed, return "product" as in result of multiplying all elements
1090
+ return super if tuples.empty?
1091
+
1092
+ tuples.unshift(self)
1093
+
1094
+ if tuples.any?(&:empty?)
1095
+ return block_given? ? self : []
1096
+ end
1097
+
1098
+ counters = Array.new(tuples.size, 0)
1099
+
1100
+ bump_counters = lambda do
1101
+ i = tuples.size-1
1102
+ counters[i] += 1
1103
+ while counters[i] == tuples[i].size
1104
+ counters[i] = 0
1105
+ i -= 1
1106
+ return true if i == -1 # we are done
1107
+ counters[i] += 1
1108
+ end
1109
+ false # not done yet
1110
+ end
1111
+ build_array = lambda do
1112
+ array = []
1113
+ counters.each_with_index { |index,i| array << tuples[i][index] }
1114
+ array
1115
+ end
1116
+
1117
+ if block_given?
1118
+ while true
1119
+ yield build_array[]
1120
+ return self if bump_counters[]
1121
+ end
1122
+ else
1123
+ result = []
1124
+ while true
1125
+ result << build_array[]
1126
+ return result if bump_counters[]
1127
+ end
1128
+ end
1129
+ end
1130
+
1131
+ # Assume all elements are tuples or arrays and transpose the rows and columns.
1132
+ # In other words, take the first element of each nested tuple/array and gather
1133
+ # them together into a new `Tuple`. Do likewise for the second, third, and so on
1134
+ # down to the end of each nested Tuple/array. Gather all the resulting `Tuple`s
1135
+ # into a new `Tuple` and return it.
1136
+ #
1137
+ # This operation is closely related to {#zip}. The result is almost the same as
1138
+ # calling {#zip} on the first nested Tuple/array with the others supplied as
1139
+ # arguments.
1140
+ #
1141
+ # @example
1142
+ # Erlang::Tuple[["A", 10], ["B", 20], ["C", 30]].transpose
1143
+ # # => Erlang::Tuple[Erlang::Tuple["A", "B", "C"], Erlang::Tuple[10, 20, 30]]
1144
+ #
1145
+ # @return [Tuple]
1146
+ # @raise [IndexError] if elements are not of the same size.
1147
+ # @raise [TypeError] if an element can not be implicitly converted to an array (using `#to_ary`)
1148
+ def transpose
1149
+ return self.class.empty if empty?
1150
+ result = Array.new(first.size) { [] }
1151
+
1152
+ 0.upto(@size-1) do |i|
1153
+ source = get(i)
1154
+ if source.size != result.size
1155
+ raise IndexError, "element size differs (#{source.size} should be #{result.size})"
1156
+ end
1157
+
1158
+ 0.upto(result.size-1) do |j|
1159
+ result[j].push(source[j])
1160
+ end
1161
+ end
1162
+
1163
+ result.map! { |a| self.class.new(a) }
1164
+ return self.class.new(result)
1165
+ end
1166
+
1167
+ # Finds a value from this `Tuple` which meets the condition defined by the
1168
+ # provided block, using a binary search. The tuple must already be sorted
1169
+ # with respect to the block. See Ruby's `Array#bsearch` for details,
1170
+ # behaviour is equivalent.
1171
+ #
1172
+ # @example
1173
+ # t = Erlang::Tuple[1, 3, 5, 7, 9, 11, 13]
1174
+ # # Block returns true/false for exact element match:
1175
+ # t.bsearch { |e| e > 4 } # => 5
1176
+ # # Block returns number to match an element in 4 <= e <= 7:
1177
+ # t.bsearch { |e| 1 - e / 4 } # => 7
1178
+ #
1179
+ # @yield Once for at most `log n` elements, where `n` is the size of the
1180
+ # tuple. The exact elements and ordering are undefined.
1181
+ # @yieldreturn [Boolean] `true` if this element matches the criteria, `false` otherwise.
1182
+ # @yieldreturn [Integer] See `Array#bsearch` for details.
1183
+ # @yieldparam [Object] element element to be evaluated
1184
+ # @return [Object] The matched element, or `nil` if none found.
1185
+ # @raise TypeError if the block returns a non-numeric, non-boolean, non-nil
1186
+ # value.
1187
+ def bsearch
1188
+ return enum_for(:bsearch) if not block_given?
1189
+ low, high, result = 0, @size, nil
1190
+ while low < high
1191
+ mid = (low + ((high - low) >> 1))
1192
+ val = get(mid)
1193
+ v = yield val
1194
+ if v.is_a? Numeric
1195
+ if v == 0
1196
+ return val
1197
+ elsif v > 0
1198
+ high = mid
1199
+ else
1200
+ low = mid + 1
1201
+ end
1202
+ elsif v == true
1203
+ result = val
1204
+ high = mid
1205
+ elsif !v
1206
+ low = mid + 1
1207
+ else
1208
+ raise TypeError, "wrong argument type #{v.class} (must be numeric, true, false, or nil)"
1209
+ end
1210
+ end
1211
+ return result
1212
+ end
1213
+
1214
+ # Return an empty `Tuple` instance, of the same class as this one. Useful if you
1215
+ # have multiple subclasses of `Tuple` and want to treat them polymorphically.
1216
+ #
1217
+ # @return [Tuple]
1218
+ def clear
1219
+ return self.class.empty
1220
+ end
1221
+
1222
+ # Return a randomly chosen element from this `Tuple`. If the tuple is empty, return `nil`.
1223
+ #
1224
+ # @example
1225
+ # Erlang::Tuple[1, 2, 3, 4, 5].sample # => 2
1226
+ #
1227
+ # @return [Object]
1228
+ def sample
1229
+ return get(rand(@size))
1230
+ end
1231
+
1232
+ # Return a new `Tuple` with only the elements at the given `indices`, in the
1233
+ # order specified by `indices`. If any of the `indices` do not exist, `nil`s will
1234
+ # appear in their places.
1235
+ #
1236
+ # @example
1237
+ # t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
1238
+ # t.values_at(2, 4, 5) # => Erlang::Tuple["C", "E", "F"]
1239
+ #
1240
+ # @param indices [Array] The indices to retrieve and gather into a new `Tuple`
1241
+ # @return [Tuple]
1242
+ def values_at(*indices)
1243
+ return self.class.new(indices.map { |i| get(i) }.freeze)
1244
+ end
1245
+
1246
+ # Find the index of an element, starting from the end of the tuple.
1247
+ # Returns `nil` if no element is found.
1248
+ #
1249
+ # @overload rindex(obj)
1250
+ # Return the index of the last element which is `#==` to `obj`.
1251
+ #
1252
+ # @example
1253
+ # t = Erlang::Tuple[7, 8, 9, 7, 8, 9]
1254
+ # t.rindex(8) # => 4
1255
+ #
1256
+ # @overload rindex
1257
+ # Return the index of the last element for which the block returns true.
1258
+ #
1259
+ # @yield [element] Once for each element, last to first, until the block
1260
+ # returns true.
1261
+ # @example
1262
+ # t = Erlang::Tuple[7, 8, 9, 7, 8, 9]
1263
+ # t.rindex { |e| e.even? } # => 4
1264
+ #
1265
+ # @return [Integer]
1266
+ def rindex(obj = (missing_arg = true))
1267
+ obj = Erlang.from(obj)
1268
+ i = @size - 1
1269
+ if missing_arg
1270
+ if block_given?
1271
+ reverse_each { |element| return i if yield element; i -= 1 }
1272
+ return nil
1273
+ else
1274
+ return enum_for(:rindex)
1275
+ end
1276
+ else
1277
+ reverse_each { |element| return i if element == obj; i -= 1 }
1278
+ return nil
1279
+ end
1280
+ end
1281
+
1282
+ # Assumes all elements are nested, indexable collections, and searches through them,
1283
+ # comparing `obj` with the first element of each nested collection. Return the
1284
+ # first nested collection which matches, or `nil` if none is found.
1285
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
1286
+ # not indexable collections).
1287
+ #
1288
+ # @example
1289
+ # t = Erlang::Tuple[Erlang::Tuple["A", 10], Erlang::Tuple["B", 20], Erlang::Tuple["C", 30]]
1290
+ # t.assoc("B") # => Erlang::Tuple["B", 20]
1291
+ #
1292
+ # @param obj [Object] The object to search for
1293
+ # @return [Object]
1294
+ def assoc(obj)
1295
+ obj = Erlang.from(obj)
1296
+ each do |array|
1297
+ next if !array.respond_to?(:[])
1298
+ return array if obj == array[0]
1299
+ end
1300
+ return nil
1301
+ end
1302
+
1303
+ # Assumes all elements are nested, indexable collections, and searches through them,
1304
+ # comparing `obj` with the second element of each nested collection. Return
1305
+ # the first nested collection which matches, or `nil` if none is found.
1306
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
1307
+ # not indexable collections).
1308
+ #
1309
+ # @example
1310
+ # t = Erlang::Tuple[Erlang::Tuple["A", 10], Erlang::Tuple["B", 20], Erlang::Tuple["C", 30]]
1311
+ # t.rassoc(20) # => Erlang::Tuple["B", 20]
1312
+ #
1313
+ # @param obj [Object] The object to search for
1314
+ # @return [Object]
1315
+ def rassoc(obj)
1316
+ obj = Erlang.from(obj)
1317
+ each do |array|
1318
+ next if !array.respond_to?(:[])
1319
+ return array if obj == array[1]
1320
+ end
1321
+ return nil
1322
+ end
1323
+
1324
+ # Return an `Array` with the same elements, in the same order. The returned
1325
+ # `Array` may or may not be frozen.
1326
+ #
1327
+ # @return [Array]
1328
+ def to_a
1329
+ if @levels == 0
1330
+ # When initializing a Tuple with 32 or less elements, we always make
1331
+ # sure @root is frozen, so we can return it directly here
1332
+ return @root
1333
+ else
1334
+ return flatten_node(@root, @levels * BITS_PER_LEVEL, [])
1335
+ end
1336
+ end
1337
+ alias :to_ary :to_a
1338
+
1339
+ # Return true if `other` has the same type and contents as this `Tuple`.
1340
+ #
1341
+ # @param other [Object] The collection to compare with
1342
+ # @return [Boolean]
1343
+ def eql?(other)
1344
+ return true if other.equal?(self)
1345
+ if instance_of?(other.class)
1346
+ return false if @size != other.size
1347
+ return @root.eql?(other.instance_variable_get(:@root))
1348
+ else
1349
+ return !!(Erlang.compare(other, self) == 0)
1350
+ end
9
1351
  end
1352
+ alias :== :eql?
10
1353
 
11
- def pretty_inspect
12
- "#<#{self.class.name} #{super[0..-2]}>\n"
1354
+ # See `Object#hash`.
1355
+ # @return [Integer]
1356
+ def hash
1357
+ return reduce(Erlang::Tuple.hash) { |hash, item| (hash << 5) - hash + item.hash }
13
1358
  end
14
1359
 
15
- def pretty_print(q)
16
- q.group(1, '{', '}') {
17
- q.seplist(self) { |v|
18
- q.pp v
19
- }
20
- }
1360
+ # @return [::Array]
1361
+ # @private
1362
+ def marshal_dump
1363
+ return to_a
1364
+ end
1365
+
1366
+ # @private
1367
+ def marshal_load(array)
1368
+ initialize(array.freeze)
1369
+ __send__(:immutable!)
1370
+ return self
1371
+ end
1372
+
1373
+ # Allows this `Tuple` to be printed using `Erlang.inspect()`.
1374
+ #
1375
+ # @return [String]
1376
+ def erlang_inspect(raw = false)
1377
+ result = '{'
1378
+ each_with_index { |obj, i| result << ',' if i > 0; result << Erlang.inspect(obj, raw: raw) }
1379
+ result << '}'
1380
+ return result
1381
+ end
1382
+
1383
+ private
1384
+
1385
+ def traverse_depth_first(node, level, &block)
1386
+ return node.each(&block) if level == 0
1387
+ return node.each { |child| traverse_depth_first(child, level - 1, &block) }
1388
+ end
1389
+
1390
+ def reverse_traverse_depth_first(node, level, &block)
1391
+ return node.reverse_each(&block) if level == 0
1392
+ return node.reverse_each { |child| reverse_traverse_depth_first(child, level - 1, &block) }
1393
+ end
1394
+
1395
+ def leaf_node_for(node, bitshift, index)
1396
+ while bitshift > 0
1397
+ node = node[(index >> bitshift) & INDEX_MASK]
1398
+ bitshift -= BITS_PER_LEVEL
1399
+ end
1400
+ return node
1401
+ end
1402
+
1403
+ def update_root(index, item)
1404
+ root, levels = @root, @levels
1405
+ while index >= (1 << (BITS_PER_LEVEL * (levels + 1)))
1406
+ root = [root].freeze
1407
+ levels += 1
1408
+ end
1409
+ new_root = update_leaf_node(root, levels * BITS_PER_LEVEL, index, item)
1410
+ if new_root.equal?(root)
1411
+ return self
1412
+ else
1413
+ return self.class.alloc(new_root, @size > index ? @size : index + 1, levels)
1414
+ end
1415
+ end
1416
+
1417
+ def update_leaf_node(node, bitshift, index, item)
1418
+ slot_index = (index >> bitshift) & INDEX_MASK
1419
+ if bitshift > 0
1420
+ old_child = node[slot_index] || []
1421
+ item = update_leaf_node(old_child, bitshift - BITS_PER_LEVEL, index, item)
1422
+ end
1423
+ existing_item = node[slot_index]
1424
+ if existing_item.equal?(item)
1425
+ return node
1426
+ else
1427
+ return node.dup.tap { |n| n[slot_index] = item }.freeze
1428
+ end
1429
+ end
1430
+
1431
+ def flatten_range(node, bitshift, from, to)
1432
+ from_slot = (from >> bitshift) & INDEX_MASK
1433
+ to_slot = (to >> bitshift) & INDEX_MASK
1434
+
1435
+ if bitshift == 0 # are we at the bottom?
1436
+ return node.slice(from_slot, to_slot-from_slot+1)
1437
+ elsif from_slot == to_slot
1438
+ return flatten_range(node[from_slot], bitshift - BITS_PER_LEVEL, from, to)
1439
+ else
1440
+ # the following bitmask can be used to pick out the part of the from/to indices
1441
+ # which will be used to direct path BELOW this node
1442
+ mask = ((1 << bitshift) - 1)
1443
+ result = []
1444
+
1445
+ if from & mask == 0
1446
+ flatten_node(node[from_slot], bitshift - BITS_PER_LEVEL, result)
1447
+ else
1448
+ result.concat(flatten_range(node[from_slot], bitshift - BITS_PER_LEVEL, from, from | mask))
1449
+ end
1450
+
1451
+ (from_slot+1).upto(to_slot-1) do |slot_index|
1452
+ flatten_node(node[slot_index], bitshift - BITS_PER_LEVEL, result)
1453
+ end
1454
+
1455
+ if to & mask == mask
1456
+ flatten_node(node[to_slot], bitshift - BITS_PER_LEVEL, result)
1457
+ else
1458
+ result.concat(flatten_range(node[to_slot], bitshift - BITS_PER_LEVEL, to & ~mask, to))
1459
+ end
1460
+
1461
+ return result
1462
+ end
1463
+ end
1464
+
1465
+ def flatten_node(node, bitshift, result)
1466
+ if bitshift == 0
1467
+ result.concat(node)
1468
+ elsif bitshift == BITS_PER_LEVEL
1469
+ node.each { |a| result.concat(a) }
1470
+ else
1471
+ bitshift -= BITS_PER_LEVEL
1472
+ node.each { |a| flatten_node(a, bitshift, result) }
1473
+ end
1474
+ return result
1475
+ end
1476
+
1477
+ def subsequence(from, length)
1478
+ return nil if from > @size || from < 0 || length < 0
1479
+ length = @size - from if @size < from + length
1480
+ return self.class.empty if length == 0
1481
+ return self.class.new(flatten_range(@root, @levels * BITS_PER_LEVEL, from, from + length - 1))
1482
+ end
1483
+
1484
+ def flatten_suffix(node, bitshift, from, result)
1485
+ from_slot = (from >> bitshift) & INDEX_MASK
1486
+
1487
+ if bitshift == 0
1488
+ if from_slot == 0
1489
+ return result.concat(node)
1490
+ else
1491
+ return result.concat(node.slice(from_slot, 32)) # entire suffix of node. excess length is ignored by #slice
1492
+ end
1493
+ else
1494
+ mask = ((1 << bitshift) - 1)
1495
+ if from & mask == 0
1496
+ from_slot.upto(node.size-1) do |i|
1497
+ flatten_node(node[i], bitshift - BITS_PER_LEVEL, result)
1498
+ end
1499
+ elsif child = node[from_slot]
1500
+ flatten_suffix(child, bitshift - BITS_PER_LEVEL, from, result)
1501
+ (from_slot+1).upto(node.size-1) do |i|
1502
+ flatten_node(node[i], bitshift - BITS_PER_LEVEL, result)
1503
+ end
1504
+ end
1505
+ return result
1506
+ end
1507
+ end
1508
+
1509
+ def replace_suffix(from, suffix)
1510
+ # new suffix can go directly after existing elements
1511
+ raise IndexError if from > @size
1512
+ root, levels = @root, @levels
1513
+
1514
+ if (from >> (BITS_PER_LEVEL * (@levels + 1))) != 0
1515
+ # index where new suffix goes doesn't fall within current tree
1516
+ # we will need to deepen tree
1517
+ root = [root].freeze
1518
+ levels += 1
1519
+ end
1520
+
1521
+ new_size = from + suffix.size
1522
+ root = replace_node_suffix(root, levels * BITS_PER_LEVEL, from, suffix)
1523
+
1524
+ if !suffix.empty?
1525
+ levels.times { suffix = suffix.each_slice(32).to_a }
1526
+ root.concat(suffix)
1527
+ while root.size > 32
1528
+ root = root.each_slice(32).to_a
1529
+ levels += 1
1530
+ end
1531
+ else
1532
+ while root.size == 1 && levels > 0
1533
+ root = root[0]
1534
+ levels -= 1
1535
+ end
1536
+ end
1537
+
1538
+ return self.class.alloc(root.freeze, new_size, levels)
1539
+ end
1540
+
1541
+ def replace_node_suffix(node, bitshift, from, suffix)
1542
+ from_slot = (from >> bitshift) & INDEX_MASK
1543
+
1544
+ if bitshift == 0
1545
+ if from_slot == 0
1546
+ return suffix.shift(32)
1547
+ else
1548
+ return node.take(from_slot).concat(suffix.shift(32 - from_slot))
1549
+ end
1550
+ else
1551
+ mask = ((1 << bitshift) - 1)
1552
+ if from & mask == 0
1553
+ if from_slot == 0
1554
+ new_node = suffix.shift(32 * (1 << bitshift))
1555
+ while bitshift != 0
1556
+ new_node = new_node.each_slice(32).to_a
1557
+ bitshift -= BITS_PER_LEVEL
1558
+ end
1559
+ return new_node
1560
+ else
1561
+ result = node.take(from_slot)
1562
+ remainder = suffix.shift((32 - from_slot) * (1 << bitshift))
1563
+ while bitshift != 0
1564
+ remainder = remainder.each_slice(32).to_a
1565
+ bitshift -= BITS_PER_LEVEL
1566
+ end
1567
+ return result.concat(remainder)
1568
+ end
1569
+ elsif child = node[from_slot]
1570
+ result = node.take(from_slot)
1571
+ result.push(replace_node_suffix(child, bitshift - BITS_PER_LEVEL, from, suffix))
1572
+ remainder = suffix.shift((31 - from_slot) * (1 << bitshift))
1573
+ while bitshift != 0
1574
+ remainder = remainder.each_slice(32).to_a
1575
+ bitshift -= BITS_PER_LEVEL
1576
+ end
1577
+ return result.concat(remainder)
1578
+ else
1579
+ raise "Shouldn't happen"
1580
+ end
1581
+ end
21
1582
  end
22
1583
  end
23
- end
1584
+
1585
+ # The canonical empty `Tuple`. Returned by `Tuple[]` when
1586
+ # invoked with no arguments; also returned by `Tuple.empty`. Prefer using this
1587
+ # one rather than creating many empty tuples using `Tuple.new`.
1588
+ #
1589
+ # @private
1590
+ EmptyTuple = Erlang::Tuple.empty
1591
+ end