| Class | LazyArray |
| In: |
lib/extlib/lazy_array.rb
|
| Parent: | Object |
| head | [R] | |
| tail | [R] |
# File lib/extlib/lazy_array.rb, line 394
394: def initialize
395: @load_with_proc = lambda { |v| v }
396: @head = []
397: @tail = []
398: @array = []
399: end
# File lib/extlib/lazy_array.rb, line 181
181: def <<(entry)
182: if loaded?
183: lazy_load
184: @array << entry
185: else
186: @tail << entry
187: end
188: self
189: end
# File lib/extlib/lazy_array.rb, line 356
356: def ==(other)
357: return true if equal?(other)
358: return false unless other.respond_to?(:to_ary)
359:
360: # if necessary, convert to something that can be compared
361: other = other.to_ary unless other.respond_to?(:[])
362:
363: unless loaded?
364: # compare the head against the beginning of other. start at index
365: # 0 and incrementally compare each entry. if other is a LazyArray
366: # this has a lesser likelyhood of triggering a lazy load
367: 0.upto(@head.size - 1) do |i|
368: return false unless @head[i] == other[i]
369: end
370:
371: # compare the tail against the end of other. start at index
372: # -1 and decrementally compare each entry. if other is a LazyArray
373: # this has a lesser likelyhood of triggering a lazy load
374: -1.downto(@tail.size * -1) do |i|
375: return false unless @tail[i] == other[i]
376: end
377:
378: lazy_load
379: end
380:
381: @array == other
382: end
# File lib/extlib/lazy_array.rb, line 106
106: def [](*args)
107: index, length = extract_slice_arguments(*args)
108:
109: if length.nil?
110: return at(index)
111: end
112:
113: length ||= 1
114:
115: if index >= 0 && lazy_possible?(@head, index + length)
116: @head[*args]
117: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
118: @tail[*args]
119: else
120: lazy_load
121: @array[*args]
122: end
123: end
# File lib/extlib/lazy_array.rb, line 142
142: def []=(*args)
143: index, length = extract_slice_arguments(*args[0..-2])
144:
145: length ||= 1
146:
147: if index >= 0 && lazy_possible?(@head, index + length)
148: @head.[]=(*args)
149: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
150: @tail.[]=(*args)
151: else
152: lazy_load
153: @array.[]=(*args)
154: end
155: end
# File lib/extlib/lazy_array.rb, line 98
98: def any?(&block)
99: (lazy_possible?(@tail) && @tail.any?(&block)) ||
100: (lazy_possible?(@head) && @head.any?(&block)) || begin
101: lazy_load
102: @array.any?(&block)
103: end
104: end
# File lib/extlib/lazy_array.rb, line 34
34: def at(index)
35: if index >= 0 && lazy_possible?(@head, index + 1)
36: @head.at(index)
37: elsif index < 0 && lazy_possible?(@tail, index.abs)
38: @tail.at(index)
39: else
40: lazy_load
41: @array.at(index)
42: end
43: end
# File lib/extlib/lazy_array.rb, line 283
283: def clear
284: mark_loaded
285: @array.clear
286: self
287: end
# File lib/extlib/lazy_array.rb, line 193
193: def concat(other)
194: if loaded?
195: lazy_load
196: @array.concat(other)
197: else
198: @tail.concat(other)
199: end
200: self
201: end
# File lib/extlib/lazy_array.rb, line 253
253: def delete_at(index)
254: if index >= 0 && lazy_possible?(@head, index + 1)
255: @head.delete_at(index)
256: elsif index < 0 && lazy_possible?(@tail, index.abs)
257: @tail.delete_at(index)
258: else
259: lazy_load
260: @array.delete_at(index)
261: end
262: end
# File lib/extlib/lazy_array.rb, line 264
264: def delete_if(&block)
265: if loaded?
266: lazy_load
267: @array.delete_if(&block)
268: else
269: @reapers ||= []
270: @reapers << block
271: @head.delete_if(&block)
272: @tail.delete_if(&block)
273: end
274: self
275: end
# File lib/extlib/lazy_array.rb, line 330
330: def eql?(other)
331: return true if equal?(other)
332: return false unless other.class.equal?(self.class)
333:
334: unless loaded?
335: # compare the head against the beginning of other. start at index
336: # 0 and incrementally compare each entry. if other is a LazyArray
337: # this has a lesser likelyhood of triggering a lazy load
338: 0.upto(@head.size - 1) do |i|
339: return false unless @head[i].eql?(other[i])
340: end
341:
342: # compare the tail against the end of other. start at index
343: # -1 and decrementally compare each entry. if other is a LazyArray
344: # this has a lesser likelyhood of triggering a lazy load
345: -1.downto(@tail.size * -1) do |i|
346: return false unless @tail[i].eql?(other[i])
347: end
348:
349: lazy_load
350: end
351:
352: # convert other to an Array before checking equality
353: @array.eql?(other.to_ary)
354: end
# File lib/extlib/lazy_array.rb, line 45
45: def fetch(*args, &block)
46: index = args.first
47:
48: if index >= 0 && lazy_possible?(@head, index + 1)
49: @head.fetch(*args, &block)
50: elsif index < 0 && lazy_possible?(@tail, index.abs)
51: @tail.fetch(*args, &block)
52: else
53: lazy_load
54: @array.fetch(*args, &block)
55: end
56: end
# File lib/extlib/lazy_array.rb, line 16
16: def first(*args)
17: if lazy_possible?(@head, *args)
18: @head.first(*args)
19: else
20: lazy_load
21: @array.first(*args)
22: end
23: end
# File lib/extlib/lazy_array.rb, line 315
315: def freeze
316: if loaded?
317: @array.freeze
318: else
319: @head.freeze
320: @tail.freeze
321: end
322: @frozen = true
323: self
324: end
# File lib/extlib/lazy_array.rb, line 86
86: def include?(entry)
87: (lazy_possible?(@tail) && @tail.include?(entry)) ||
88: (lazy_possible?(@head) && @head.include?(entry)) || begin
89: lazy_load
90: @array.include?(entry)
91: end
92: end
# File lib/extlib/lazy_array.rb, line 79
79: def index(entry)
80: (lazy_possible?(@head) && @head.index(entry)) || begin
81: lazy_load
82: @array.index(entry)
83: end
84: end
# File lib/extlib/lazy_array.rb, line 223
223: def insert(index, *entries)
224: if index >= 0 && lazy_possible?(@head, index)
225: @head.insert(index, *entries)
226: elsif index < 0 && lazy_possible?(@tail, index.abs - 1)
227: @tail.insert(index, *entries)
228: else
229: lazy_load
230: @array.insert(index, *entries)
231: end
232: self
233: end
# File lib/extlib/lazy_array.rb, line 305
305: def kind_of?(klass)
306: super || @array.kind_of?(klass)
307: end
# File lib/extlib/lazy_array.rb, line 25
25: def last(*args)
26: if lazy_possible?(@tail, *args)
27: @tail.last(*args)
28: else
29: lazy_load
30: @array.last(*args)
31: end
32: end
# File lib/extlib/lazy_array.rb, line 296
296: def load_with(&block)
297: @load_with_proc = block
298: self
299: end
# File lib/extlib/lazy_array.rb, line 235
235: def pop
236: if lazy_possible?(@tail)
237: @tail.pop
238: else
239: lazy_load
240: @array.pop
241: end
242: end
# File lib/extlib/lazy_array.rb, line 203
203: def push(*entries)
204: if loaded?
205: lazy_load
206: @array.push(*entries)
207: else
208: @tail.push(*entries)
209: end
210: self
211: end
# File lib/extlib/lazy_array.rb, line 277
277: def replace(other)
278: mark_loaded
279: @array.replace(other)
280: self
281: end
# File lib/extlib/lazy_array.rb, line 311
311: def respond_to?(method, include_private = false)
312: super || @array.respond_to?(method)
313: end
# File lib/extlib/lazy_array.rb, line 163
163: def reverse!
164: # reverse without kicking if possible
165: if loaded?
166: @array = @array.reverse
167: else
168: @head, @tail = @tail.reverse, @head.reverse
169:
170: proc = @load_with_proc
171:
172: @load_with_proc = lambda do |v|
173: proc.call(v)
174: v.instance_variable_get(:@array).reverse!
175: end
176: end
177:
178: self
179: end
# File lib/extlib/lazy_array.rb, line 244
244: def shift
245: if lazy_possible?(@head)
246: @head.shift
247: else
248: lazy_load
249: @array.shift
250: end
251: end
# File lib/extlib/lazy_array.rb, line 127
127: def slice!(*args)
128: index, length = extract_slice_arguments(*args)
129:
130: length ||= 1
131:
132: if index >= 0 && lazy_possible?(@head, index + length)
133: @head.slice!(*args)
134: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
135: @tail.slice!(*args)
136: else
137: lazy_load
138: @array.slice!(*args)
139: end
140: end
# File lib/extlib/lazy_array.rb, line 213
213: def unshift(*entries)
214: if loaded?
215: lazy_load
216: @array.unshift(*entries)
217: else
218: @head.unshift(*entries)
219: end
220: self
221: end
# File lib/extlib/lazy_array.rb, line 58
58: def values_at(*args)
59: accumulator = []
60:
61: lazy_possible = args.all? do |arg|
62: index, length = extract_slice_arguments(arg)
63:
64: if index >= 0 && lazy_possible?(@head, index + (length || 1))
65: accumulator.concat(head.values_at(*arg))
66: elsif index < 0 && lazy_possible?(@tail, index.abs)
67: accumulator.concat(tail.values_at(*arg))
68: end
69: end
70:
71: if lazy_possible
72: accumulator
73: else
74: lazy_load
75: @array.values_at(*args)
76: end
77: end
# File lib/extlib/lazy_array.rb, line 388
388: def lazy_possible?(list, need_length = 1)
389: !loaded? && need_length <= list.size
390: end
Extract arguments for slice an slice! and return index and length
@param [Integer, Array(Integer), Range] *args the index,
index and length, or range indicating first and last position
@return [Integer] the index @return [Integer,NilClass] the length, if any
@api private
# File lib/extlib/lazy_array.rb, line 438
438: def extract_slice_arguments(*args)
439: first_arg, second_arg = args
440:
441: if args.size == 2 && first_arg.kind_of?(Integer) && second_arg.kind_of?(Integer)
442: return first_arg, second_arg
443: elsif args.size == 1
444: if first_arg.kind_of?(Integer)
445: return first_arg
446: elsif first_arg.kind_of?(Range)
447: index = first_arg.first
448: length = first_arg.last - index
449: length += 1 unless first_arg.exclude_end?
450: return index, length
451: end
452: end
453:
454: raise ArgumentError, "arguments may be 1 or 2 Integers, or 1 Range object, was: #{args.inspect}", caller(1)
455: end
# File lib/extlib/lazy_array.rb, line 401
401: def initialize_copy(original)
402: if original.loaded?
403: mark_loaded
404: @array = @array.dup
405: @head = @tail = nil
406: else
407: @head = @head.dup
408: @tail = @tail.dup
409: @array = @array.dup
410: end
411: end
# File lib/extlib/lazy_array.rb, line 413
413: def lazy_load
414: return if loaded?
415: mark_loaded
416: @load_with_proc[self]
417: @array.unshift(*@head)
418: @array.concat(@tail)
419: @head = @tail = nil
420: @reapers.each { |r| @array.delete_if(&r) } if @reapers
421: @array.freeze if frozen?
422: end
delegate any not-explicitly-handled methods to @array, if possible. this is handy for handling methods mixed-into Array like group_by
# File lib/extlib/lazy_array.rb, line 459
459: def method_missing(method, *args, &block)
460: if @array.respond_to?(method)
461: lazy_load
462: results = @array.send(method, *args, &block)
463: results.equal?(@array) ? self : results
464: else
465: super
466: end
467: end