| Class | LazyArray |
| In: |
lib/extlib/lazy_array.rb
|
| Parent: | Object |
| head | [R] | |
| tail | [R] |
# File lib/extlib/lazy_array.rb, line 344
344: def initialize
345: @frozen = false
346: @loaded = false
347: @load_with_proc = lambda { |v| v }
348: @head = []
349: @tail = []
350: @array = []
351: @reapers = []
352: end
# File lib/extlib/lazy_array.rb, line 165
165: def <<(entry)
166: if loaded?
167: lazy_load
168: @array << entry
169: else
170: @tail << entry
171: end
172: self
173: end
# File lib/extlib/lazy_array.rb, line 311
311: def ==(other)
312: if equal?(other)
313: return true
314: end
315:
316: unless other.respond_to?(:to_ary)
317: return false
318: end
319:
320: # if necessary, convert to something that can be compared
321: other = other.to_ary unless other.respond_to?(:[])
322:
323: cmp?(other, :==)
324: end
# File lib/extlib/lazy_array.rb, line 96
96: def [](*args)
97: index, length = extract_slice_arguments(*args)
98:
99: if length == 1 && args.size == 1 && args.first.kind_of?(Integer)
100: return at(index)
101: end
102:
103: if index >= 0 && lazy_possible?(@head, index + length)
104: @head[*args]
105: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
106: @tail[*args]
107: else
108: lazy_load
109: @array[*args]
110: end
111: end
# File lib/extlib/lazy_array.rb, line 128
128: def []=(*args)
129: index, length = extract_slice_arguments(*args[0..-2])
130:
131: if index >= 0 && lazy_possible?(@head, index + length)
132: @head.[]=(*args)
133: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
134: @tail.[]=(*args)
135: else
136: lazy_load
137: @array.[]=(*args)
138: end
139: end
# File lib/extlib/lazy_array.rb, line 88
88: def any?(&block)
89: (lazy_possible?(@tail) && @tail.any?(&block)) ||
90: (lazy_possible?(@head) && @head.any?(&block)) || begin
91: lazy_load
92: @array.any?(&block)
93: end
94: end
# File lib/extlib/lazy_array.rb, line 24
24: def at(index)
25: if index >= 0 && lazy_possible?(@head, index + 1)
26: @head.at(index)
27: elsif index < 0 && lazy_possible?(@tail, index.abs)
28: @tail.at(index)
29: else
30: lazy_load
31: @array.at(index)
32: end
33: end
# File lib/extlib/lazy_array.rb, line 264
264: def clear
265: mark_loaded
266: @array.clear
267: self
268: end
# File lib/extlib/lazy_array.rb, line 175
175: def concat(other)
176: if loaded?
177: lazy_load
178: @array.concat(other)
179: else
180: @tail.concat(other)
181: end
182: self
183: end
# File lib/extlib/lazy_array.rb, line 235
235: def delete_at(index)
236: if index >= 0 && lazy_possible?(@head, index + 1)
237: @head.delete_at(index)
238: elsif index < 0 && lazy_possible?(@tail, index.abs)
239: @tail.delete_at(index)
240: else
241: lazy_load
242: @array.delete_at(index)
243: end
244: end
# File lib/extlib/lazy_array.rb, line 246
246: def delete_if(&block)
247: if loaded?
248: lazy_load
249: @array.delete_if(&block)
250: else
251: @reapers << block
252: @head.delete_if(&block)
253: @tail.delete_if(&block)
254: end
255: self
256: end
# File lib/extlib/lazy_array.rb, line 326
326: def eql?(other)
327: if equal?(other)
328: return true
329: end
330:
331: unless other.class.equal?(self.class)
332: return false
333: end
334:
335: cmp?(other, :eql?)
336: end
# File lib/extlib/lazy_array.rb, line 35
35: def fetch(*args, &block)
36: index = args.first
37:
38: if index >= 0 && lazy_possible?(@head, index + 1)
39: @head.fetch(*args, &block)
40: elsif index < 0 && lazy_possible?(@tail, index.abs)
41: @tail.fetch(*args, &block)
42: else
43: lazy_load
44: @array.fetch(*args, &block)
45: end
46: end
# File lib/extlib/lazy_array.rb, line 6
6: def first(*args)
7: if lazy_possible?(@head, *args)
8: @head.first(*args)
9: else
10: lazy_load
11: @array.first(*args)
12: end
13: end
# File lib/extlib/lazy_array.rb, line 296
296: def freeze
297: if loaded?
298: @array.freeze
299: else
300: @head.freeze
301: @tail.freeze
302: end
303: @frozen = true
304: self
305: end
# File lib/extlib/lazy_array.rb, line 76
76: def include?(entry)
77: (lazy_possible?(@tail) && @tail.include?(entry)) ||
78: (lazy_possible?(@head) && @head.include?(entry)) || begin
79: lazy_load
80: @array.include?(entry)
81: end
82: end
# File lib/extlib/lazy_array.rb, line 69
69: def index(entry)
70: (lazy_possible?(@head) && @head.index(entry)) || begin
71: lazy_load
72: @array.index(entry)
73: end
74: end
# File lib/extlib/lazy_array.rb, line 205
205: def insert(index, *entries)
206: if index >= 0 && lazy_possible?(@head, index)
207: @head.insert(index, *entries)
208: elsif index < 0 && lazy_possible?(@tail, index.abs - 1)
209: @tail.insert(index, *entries)
210: else
211: lazy_load
212: @array.insert(index, *entries)
213: end
214: self
215: end
# File lib/extlib/lazy_array.rb, line 286
286: def kind_of?(klass)
287: super || @array.kind_of?(klass)
288: end
# File lib/extlib/lazy_array.rb, line 15
15: def last(*args)
16: if lazy_possible?(@tail, *args)
17: @tail.last(*args)
18: else
19: lazy_load
20: @array.last(*args)
21: end
22: end
# File lib/extlib/lazy_array.rb, line 338
338: def lazy_possible?(list, need_length = 1)
339: !loaded? && need_length <= list.size
340: end
# File lib/extlib/lazy_array.rb, line 277
277: def load_with(&block)
278: @load_with_proc = block
279: self
280: end
# File lib/extlib/lazy_array.rb, line 217
217: def pop
218: if lazy_possible?(@tail)
219: @tail.pop
220: else
221: lazy_load
222: @array.pop
223: end
224: end
# File lib/extlib/lazy_array.rb, line 185
185: def push(*entries)
186: if loaded?
187: lazy_load
188: @array.push(*entries)
189: else
190: @tail.push(*entries)
191: end
192: self
193: end
# File lib/extlib/lazy_array.rb, line 258
258: def replace(other)
259: mark_loaded
260: @array.replace(other)
261: self
262: end
# File lib/extlib/lazy_array.rb, line 292
292: def respond_to?(method, include_private = false)
293: super || @array.respond_to?(method)
294: end
# File lib/extlib/lazy_array.rb, line 147
147: def reverse!
148: # reverse without kicking if possible
149: if loaded?
150: @array = @array.reverse
151: else
152: @head, @tail = @tail.reverse, @head.reverse
153:
154: proc = @load_with_proc
155:
156: @load_with_proc = lambda do |v|
157: proc.call(v)
158: v.instance_variable_get(:@array).reverse!
159: end
160: end
161:
162: self
163: end
# File lib/extlib/lazy_array.rb, line 226
226: def shift
227: if lazy_possible?(@head)
228: @head.shift
229: else
230: lazy_load
231: @array.shift
232: end
233: end
# File lib/extlib/lazy_array.rb, line 115
115: def slice!(*args)
116: index, length = extract_slice_arguments(*args)
117:
118: if index >= 0 && lazy_possible?(@head, index + length)
119: @head.slice!(*args)
120: elsif index < 0 && lazy_possible?(@tail, index.abs - 1 + length)
121: @tail.slice!(*args)
122: else
123: lazy_load
124: @array.slice!(*args)
125: end
126: end
# File lib/extlib/lazy_array.rb, line 195
195: def unshift(*entries)
196: if loaded?
197: lazy_load
198: @array.unshift(*entries)
199: else
200: @head.unshift(*entries)
201: end
202: self
203: end
# File lib/extlib/lazy_array.rb, line 48
48: def values_at(*args)
49: accumulator = []
50:
51: lazy_possible = args.all? do |arg|
52: index, length = extract_slice_arguments(arg)
53:
54: if index >= 0 && lazy_possible?(@head, index + length)
55: accumulator.concat(head.values_at(*arg))
56: elsif index < 0 && lazy_possible?(@tail, index.abs)
57: accumulator.concat(tail.values_at(*arg))
58: end
59: end
60:
61: if lazy_possible
62: accumulator
63: else
64: lazy_load
65: @array.values_at(*args)
66: end
67: end
# File lib/extlib/lazy_array.rb, line 416
416: def cmp?(other, operator)
417: unless loaded?
418: # compare the head against the beginning of other. start at index
419: # 0 and incrementally compare each entry. if other is a LazyArray
420: # this has a lesser likelyhood of triggering a lazy load
421: 0.upto(@head.size - 1) do |i|
422: return false unless @head[i].send(operator, other[i])
423: end
424:
425: # compare the tail against the end of other. start at index
426: # -1 and decrementally compare each entry. if other is a LazyArray
427: # this has a lesser likelyhood of triggering a lazy load
428: -1.downto(@tail.size * -1) do |i|
429: return false unless @tail[i].send(operator, other[i])
430: end
431:
432: lazy_load
433: end
434:
435: @array.send(operator, other.to_ary)
436: 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 385
385: def extract_slice_arguments(*args)
386: first_arg, second_arg = args
387:
388: if args.size == 2 && first_arg.kind_of?(Integer) && second_arg.kind_of?(Integer)
389: return first_arg, second_arg
390: elsif args.size == 1
391: if first_arg.kind_of?(Integer)
392: return first_arg, 1
393: elsif first_arg.kind_of?(Range)
394: index = first_arg.first
395: length = first_arg.last - index
396: length += 1 unless first_arg.exclude_end?
397: return index, length
398: end
399: end
400:
401: raise ArgumentError, "arguments may be 1 or 2 Integers, or 1 Range object, was: #{args.inspect}", caller(1)
402: end
# File lib/extlib/lazy_array.rb, line 354
354: def initialize_copy(original)
355: @head = @head.try_dup
356: @tail = @tail.try_dup
357: @array = @array.try_dup
358: end
# File lib/extlib/lazy_array.rb, line 360
360: def lazy_load
361: return if loaded?
362: mark_loaded
363: @load_with_proc[self]
364: @array.unshift(*@head)
365: @array.concat(@tail)
366: @head = @tail = nil
367: @reapers.each { |r| @array.delete_if(&r) } if @reapers
368: @array.freeze if frozen?
369: 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 406
406: def method_missing(method, *args, &block)
407: if @array.respond_to?(method)
408: lazy_load
409: results = @array.send(method, *args, &block)
410: results.equal?(@array) ? self : results
411: else
412: super
413: end
414: end