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