erlang-terms 1.1.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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