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