Class: Rod::CollectionProxy
- Inherits:
-
Object
- Object
- Rod::CollectionProxy
- Includes:
- Enumerable
- Defined in:
- lib/rod/collection_proxy.rb
Overview
This class allows for lazy fetching the elements from a collection of Rod objects.
Instance Attribute Summary collapse
-
#offset ⇒ Object
readonly
Returns the value of attribute offset.
-
#size ⇒ Object
(also: #count)
readonly
Returns the value of attribute size.
Instance Method Summary collapse
-
#&(other) ⇒ Object
Computes an intersection with the
other
collection proxy. -
#<<(element) ⇒ Object
Appends element to the end of the collection.
-
#[](index) ⇒ Object
Returns an object with given
index
. -
#added ⇒ Object
Returns a collection of added items.
-
#clear ⇒ Object
Clears the contents of the collection proxy.
-
#delete(element) ⇒ Object
Removes the
element
from the collection. -
#delete_at(index) ⇒ Object
Removes the element at
index
from the colelction. -
#deleted ⇒ Object
Returns a collection of deleted items.
-
#each ⇒ Object
Iterator implementation.
-
#empty? ⇒ Boolean
Returns true if the collection is empty.
-
#initialize(size, database, offset, klass) ⇒ CollectionProxy
constructor
Intializes the proxy with its
size
,database
it is connected to, theoffset
of join elements and theklass
of stored objects. -
#insert(index, element) ⇒ Object
Inserts the
element
at givenindex
. -
#intersection_size(other) ⇒ Object
Returns the size of intersection with the other collection proxy.
-
#save ⇒ Object
Saves to collection proxy into disk and returns the collection proxy’s
offset
. -
#to_s ⇒ Object
String representation of the collection proxy.
-
#|(other) ⇒ Object
Computes a union with the
other
collection proxy.
Constructor Details
#initialize(size, database, offset, klass) ⇒ CollectionProxy
Intializes the proxy with its size
, database
it is connected to, the offset
of join elements and the klass
of stored objects. If the klass is nil, the collection holds polymorphic objects.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/rod/collection_proxy.rb', line 16 def initialize(size,database,offset,klass) raise InvalidArgument.new("collection size",nil) if size.nil? @size = size @original_size = size raise InvalidArgument.new("collection database",nil) if database.nil? @database = database raise InvalidArgument.new("collection offset",nil) if offset.nil? @offset = offset @klass = klass #@commands = [] @added = [] @deleted = [] @map = {} end |
Instance Attribute Details
#offset ⇒ Object (readonly)
Returns the value of attribute offset.
9 10 11 |
# File 'lib/rod/collection_proxy.rb', line 9 def offset @offset end |
#size ⇒ Object (readonly) Also known as: count
Returns the value of attribute size.
9 10 11 |
# File 'lib/rod/collection_proxy.rb', line 9 def size @size end |
Instance Method Details
#&(other) ⇒ Object
Computes an intersection with the other
collection proxy.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/rod/collection_proxy.rb', line 86 def &(other) # So far this optimization works only for monomorphic # collection proxies without added elements. if @klass && @added.empty? my_ids = self.size.times.map do |index| id_for(index) end.sort other_ids = other.size.times.map do |index| other.id_for(index) end.sort ids = [] last_id = nil while(!my_ids.empty?) do if my_ids.first == other_ids.first id = my_ids.shift other_ids.shift ids << id unless last_id == id last_id = id elsif my_ids.first < other_ids.first my_ids.shift else other_ids.shift end end result = CollectionProxy.new(0,@database,0,@klass) ids.each{|id| result << [id,@klass]} else result = self.to_a & other.to_a end result end |
#<<(element) ⇒ Object
Appends element to the end of the collection.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/rod/collection_proxy.rb', line 119 def <<(element) if element.nil? pair = [0,NilClass] elsif element.is_a?(Model) if element.new? pair = [element,element.class] else pair = [element.rod_id,element.class] end else # Assume we have an array with direct values of rod_id and class. pair = element end index = @size @map[index] = @added.size @added << pair #@commands << [:append, pair] @size += 1 end |
#[](index) ⇒ Object
Returns an object with given index
. The index
have to be positive and smaller from the collection size. Otherwise nil
is returned.
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/rod/collection_proxy.rb', line 34 def [](index) return nil if index >= @size || index < 0 rod_id = id_for(index) if rod_id.is_a?(Model) rod_id elsif rod_id == 0 nil else class_for(index).find_by_rod_id(rod_id) end end |
#added ⇒ Object
Returns a collection of added items.
242 243 244 245 246 247 248 249 250 |
# File 'lib/rod/collection_proxy.rb', line 242 def added @added.map do |id_or_object,klass| if id_or_object.is_a?(Model) id_or_object else id_or_object == 0 ? nil : klass.find_by_rod_id(id_or_object) end end end |
#clear ⇒ Object
Clears the contents of the collection proxy.
216 217 218 219 220 221 |
# File 'lib/rod/collection_proxy.rb', line 216 def clear @deleted = @original_size.times.to_a @added.clear @map.clear @size = 0 end |
#delete(element) ⇒ Object
Removes the element
from the collection.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/rod/collection_proxy.rb', line 164 def delete(element) indices = [] self.each.with_index{|e,i| indices << i if e == element} if indices.empty? if block_given? return yield else return nil end end #@commands << [:delete,indices] indices.each.with_index do |index,offset| self.delete_at(index-offset) end element end |
#delete_at(index) ⇒ Object
Removes the element at index
from the colelction. So far the index
has to be positive.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/rod/collection_proxy.rb', line 183 def delete_at(index) return nil if index >= @size || index < 0 element = self[index] if direct_index = @map[index] @added.delete_at(direct_index) @map.delete(index) @map.keys.sort.each do |key| if key > index value = @map.delete(key) value -= 1 if value > direct_index @map[key-1] = value else if (value = @map[key]) > direct_index @map[key] -= 1 end end end else lazy_index = lazy_index(index) position = @deleted.bsearch_upper_boundary{|e| e <=> lazy_index } @deleted.insert(position,lazy_index) @map.keys.sort.each do |key| if key > index @map[key-1] = @map.delete(key) end end end #@commands << [:delete,[index]] @size -= 1 element end |
#deleted ⇒ Object
Returns a collection of deleted items.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/rod/collection_proxy.rb', line 253 def deleted @deleted.map do |index| if polymorphic? rod_id = @database.polymorphic_join_index(@offset,index) if rod_id != 0 klass = Model.get_class(@database.polymorphic_join_class(@offset,index)) end else klass = @klass rod_id = @database.join_index(@offset,index) end rod_id == 0 ? nil : klass.find_by_rod_id(rod_id) end end |
#each ⇒ Object
Iterator implementation. It raises an exception when the collection is modified during iteration. WARNING: This is not compliant with an Array class!
226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/rod/collection_proxy.rb', line 226 def each if block_given? @size.times do |index| added_size = @added.size deleted_size = @deleted.size yield self[index] if added_size != @added.size || deleted_size != @deleted.size raise "Can't modify collection during iteration!" end end else enum_for(:each) end end |
#empty? ⇒ Boolean
Returns true if the collection is empty.
275 276 277 |
# File 'lib/rod/collection_proxy.rb', line 275 def empty? self.count == 0 end |
#insert(index, element) ⇒ Object
Inserts the element
at given index
. So far the index
has to be positive, smaller or equal to size and only one pair of values is accepted. If these assumptions are not met, nil is returned.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/rod/collection_proxy.rb', line 143 def insert(index,element) return nil if index < 0 || index > @size if element.new? pair = [element,element.class] else pair = [element.rod_id,element.class] end @map.keys.sort.reverse.each do |key| if key >= index value = @map.delete(key) @map[key+1] = value end end @map[index] = @added.size @added << pair #@commands << [:insert,pair] @size += 1 self end |
#intersection_size(other) ⇒ Object
Returns the size of intersection with the other collection proxy. XXX this method assumes that the elements are sorted according to rod_id, the collection is not polymorphic and no elements were added nor deleted.
49 50 51 |
# File 'lib/rod/collection_proxy.rb', line 49 def intersection_size(other) @database.fast_intersection_size(self.offset,self.size,other.offset,other.size) end |
#save ⇒ Object
Saves to collection proxy into disk and returns the collection proxy’s offset
. If no element was added nor deleted, nothing happes.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/rod/collection_proxy.rb', line 282 def save unless @added.empty? && @deleted.empty? # We cannot reuse the allocated space, since the data # that is copied would be destroyed. if polymorphic? offset = @database.allocate_polymorphic_join_elements(@size) else offset = @database.allocate_join_elements(@size) end pairs = @size.times.map do |index| rod_id = id_for(index) if rod_id.is_a?(Model) object = rod_id if object.new? if polymorphic? object.reference_updaters << ReferenceUpdater.for_plural(self,index,@database) else object.reference_updaters << ReferenceUpdater.for_plural(self,index,@database) end next else rod_id = object.rod_id end end [rod_id,index] end.compact if polymorphic? pairs.each do |rod_id,index| class_id = (rod_id == 0 ? 0 : class_for(index).name_hash) @database.set_polymorphic_join_element_id(offset,index,rod_id,class_id) end else pairs.each do |rod_id,index| @database.set_join_element_id(offset,index,rod_id) end end @offset = offset @added.clear @deleted.clear @map.clear @original_size = @size end @offset end |
#to_s ⇒ Object
String representation of the collection proxy. Displays only the actual and the original size.
270 271 272 |
# File 'lib/rod/collection_proxy.rb', line 270 def to_s "Collection:[#{@size}][#{@original_size}]" end |
#|(other) ⇒ Object
Computes a union with the other
collection proxy.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/rod/collection_proxy.rb', line 54 def |(other) # So far this optimization works only for monomorphic # collection proxies without added elements. if @klass && @added.empty? my_ids = self.size.times.map do |index| id_for(index) end.sort other_ids = other.size.times.map do |index| other.id_for(index) end.sort ids = [] last_id = nil while(!my_ids.empty?) do id = my_ids.shift other_ids.shift if other_ids.first == id ids << id unless last_id == id last_id = id end while(!other_ids.empty?) do id = other_ids.shift ids << id unless last_id == id last_id = id end result = CollectionProxy.new(0,@database,0,@klass) ids.each{|id| result << [id,@klass]} else result = self.to_a | other.to_a end result end |