array-compositing 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,385 @@
1
+
2
+ class ::Array::Compositing::ParentIndexMap
3
+
4
+ ################
5
+ # initialize #
6
+ ################
7
+
8
+ def initialize
9
+
10
+ @parent_local_map = [ ]
11
+ @local_parent_map = [ ]
12
+
13
+ @parent_lazy_lookup = [ ]
14
+
15
+ @parent_and_interpolated_object_count = 0
16
+
17
+ end
18
+
19
+ ######################
20
+ # index_for_offset #
21
+ ######################
22
+
23
+ def index_for_offset( index_offset )
24
+
25
+ index = nil
26
+
27
+ if index_offset >= 0
28
+ index = index_offset
29
+ else
30
+ index = @local_parent_map.count + index_offset
31
+ end
32
+
33
+ if index < 0
34
+ index = 0
35
+ end
36
+
37
+ return index
38
+
39
+ end
40
+
41
+ #############################
42
+ # inside_parent_elements? #
43
+ #############################
44
+
45
+ def inside_parent_elements?( local_index )
46
+
47
+ local_index = index_for_offset( local_index )
48
+
49
+ return local_index < @parent_and_interpolated_object_count
50
+
51
+ end
52
+
53
+ ################################################
54
+ # replaced_parent_element_with_parent_index? #
55
+ ################################################
56
+
57
+ def replaced_parent_element_with_parent_index?( parent_index )
58
+
59
+ replaced = false
60
+
61
+ parent_index = index_for_offset( parent_index )
62
+
63
+ # if parent index is greater than interpolated count we have a new parent, so not replaced
64
+ if @parent_and_interpolated_object_count == 0
65
+
66
+ if @local_parent_map.count > 0
67
+ replaced = true
68
+ end
69
+
70
+ elsif parent_index < @parent_and_interpolated_object_count
71
+
72
+ if local_index_for_parent = @parent_local_map[ parent_index ] and local_index_for_parent >= 0
73
+ replaced = replaced_parent_element_with_local_index?( local_index_for_parent )
74
+ else
75
+ replaced = true
76
+ end
77
+
78
+ elsif parent_index == @parent_and_interpolated_object_count
79
+
80
+ if local_index_for_parent = @parent_local_map[ parent_index ] and local_index_for_parent >= 0
81
+ replaced = replaced_parent_element_with_local_index?( local_index_for_parent )
82
+ end
83
+
84
+ end
85
+
86
+ return replaced
87
+
88
+ end
89
+
90
+ ###############################################
91
+ # replaced_parent_element_with_local_index? #
92
+ ###############################################
93
+
94
+ def replaced_parent_element_with_local_index?( local_index )
95
+
96
+ local_index = index_for_offset( local_index )
97
+
98
+ return parent_index( local_index ).nil?
99
+
100
+ end
101
+
102
+ ######################
103
+ # requires_lookup? #
104
+ ######################
105
+
106
+ def requires_lookup?( local_index )
107
+
108
+ local_index = index_for_offset( local_index )
109
+
110
+ return @parent_lazy_lookup[ local_index ]
111
+
112
+ end
113
+
114
+ ##############################
115
+ # indexes_requiring_lookup #
116
+ ##############################
117
+
118
+ def indexes_requiring_lookup
119
+
120
+ indexes = [ ]
121
+
122
+ @parent_lazy_lookup.each_with_index do |true_or_false, this_index|
123
+ if true_or_false
124
+ indexes.push( this_index )
125
+ end
126
+ end
127
+
128
+ return indexes
129
+
130
+ end
131
+
132
+ ################
133
+ # looked_up! #
134
+ ################
135
+
136
+ def looked_up!( local_index )
137
+
138
+ local_index = index_for_offset( local_index )
139
+
140
+ @parent_lazy_lookup[ local_index ] = false
141
+
142
+ end
143
+
144
+ ##################
145
+ # parent_index #
146
+ ##################
147
+
148
+ def parent_index( local_index )
149
+
150
+ local_index = index_for_offset( local_index )
151
+
152
+ return @local_parent_map[ local_index ]
153
+
154
+ end
155
+
156
+ #################
157
+ # local_index #
158
+ #################
159
+
160
+ def local_index( parent_index )
161
+
162
+ parent_index = index_for_offset( parent_index )
163
+
164
+ if local_index = @parent_local_map[ parent_index ] and
165
+ local_index < 0
166
+ local_index = 0
167
+ end
168
+
169
+ return local_index
170
+
171
+ end
172
+
173
+ ###################
174
+ # parent_insert #
175
+ ###################
176
+
177
+ def parent_insert( parent_insert_index, object_count )
178
+
179
+ parent_insert_index = index_for_offset( parent_insert_index )
180
+
181
+ local_insert_index = nil
182
+
183
+ # It's possible we have no parent map yet (if the first insert is from an already-initialized parent
184
+ # that did not previously have any members).
185
+ case parent_insert_index
186
+ when 0
187
+ local_insert_index = @parent_local_map[ parent_insert_index ] || 0
188
+ else
189
+ unless local_insert_index = @parent_local_map[ parent_insert_index ]
190
+ local_insert_index = @parent_and_interpolated_object_count
191
+ end
192
+ end
193
+
194
+ # Insert new parent index correspondences.
195
+ object_count.times do |this_time|
196
+ this_parent_index = parent_insert_index + this_time
197
+ this_local_index = local_insert_index + this_time
198
+ @parent_local_map.insert( this_parent_index, this_local_index )
199
+ @local_parent_map.insert( this_local_index, this_parent_index )
200
+ @parent_lazy_lookup.insert( this_local_index, true )
201
+ end
202
+
203
+ # Update any correspondences whose parent indexes are above the insert.
204
+ parent_index_at_end_of_insert = parent_insert_index + object_count
205
+ remaining_count = @parent_local_map.count - parent_index_at_end_of_insert
206
+ remaining_count.times do |this_time|
207
+ this_parent_index = parent_index_at_end_of_insert + this_time
208
+ @parent_local_map[ this_parent_index ] += object_count
209
+ end
210
+
211
+ local_index_at_end_of_insert = local_insert_index + object_count
212
+
213
+ remaining_count = @local_parent_map.count - local_index_at_end_of_insert
214
+ remaining_count.times do |this_time|
215
+ this_local_index = local_index_at_end_of_insert + this_time
216
+ if existing_parent_index = @local_parent_map[ this_local_index ]
217
+ existing_parent_index += object_count
218
+ @local_parent_map[ this_local_index ] += object_count
219
+ end
220
+ end
221
+
222
+ # Update count of parent + interpolated objects since we inserted inside the collection.
223
+ @parent_and_interpolated_object_count += object_count
224
+
225
+ return local_insert_index
226
+
227
+ end
228
+
229
+ ##################
230
+ # local_insert #
231
+ ##################
232
+
233
+ def local_insert( local_index, object_count )
234
+
235
+ local_index = index_for_offset( local_index )
236
+
237
+ # account for insert in parent-local
238
+ # if we're inside the set of parent elements then we need to tell the parent map to adjust
239
+ if inside_parent_elements?( local_index )
240
+
241
+ unless parent_insert_index = @local_parent_map[ local_index ]
242
+ next_local_index = local_index
243
+ begin
244
+ parent_insert_index = @local_parent_map[ next_local_index ]
245
+ next_local_index += 1
246
+ end while parent_insert_index.nil? and next_local_index < @local_parent_map.count
247
+ end
248
+
249
+ if parent_insert_index
250
+ remaining_count = @parent_local_map.count - parent_insert_index
251
+ remaining_count.times do |this_time|
252
+ this_parent_index = parent_insert_index + this_time
253
+ @parent_local_map[ this_parent_index ] += object_count
254
+ end
255
+ end
256
+
257
+ end
258
+
259
+ # account for insert in local-parent
260
+ object_count.times do |this_time|
261
+ this_local_insert_index = local_index + this_time
262
+ @local_parent_map.insert( this_local_insert_index, nil )
263
+ @parent_lazy_lookup.insert( this_local_insert_index, false )
264
+ end
265
+
266
+ end
267
+
268
+ ################
269
+ # parent_set #
270
+ ################
271
+
272
+ def parent_set( parent_index )
273
+
274
+ parent_index = index_for_offset( parent_index )
275
+
276
+ # if we are setting an index that already exists then we have a parent to local map - we never delete those
277
+ # except when we delete the parent
278
+ if local_index = @parent_local_map[ parent_index ]
279
+ unless replaced_parent_element_with_local_index?( local_index )
280
+ @parent_lazy_lookup[ local_index ] = true
281
+ end
282
+ else
283
+ local_index = @parent_and_interpolated_object_count
284
+ parent_insert( local_index, 1 )
285
+ end
286
+
287
+ return local_index
288
+
289
+ end
290
+
291
+ ###############
292
+ # local_set #
293
+ ###############
294
+
295
+ def local_set( local_index )
296
+
297
+ local_index = index_for_offset( local_index )
298
+
299
+ if parent_index = @local_parent_map[ local_index ]
300
+ @local_parent_map[ local_index ] = nil
301
+ end
302
+
303
+ @parent_lazy_lookup[ local_index ] = false
304
+
305
+ end
306
+
307
+ ######################
308
+ # parent_delete_at #
309
+ ######################
310
+
311
+ def parent_delete_at( parent_delete_at_index )
312
+
313
+ parent_delete_at_index = index_for_offset( parent_delete_at_index )
314
+
315
+ # get local index for parent index where delete is occuring
316
+ local_delete_at_index = @parent_local_map.delete_at( parent_delete_at_index )
317
+
318
+ # update any correspondences whose parent indexes are below the delete
319
+ remaining_count = @parent_local_map.count - parent_delete_at_index
320
+ remaining_count.times do |this_time|
321
+ this_parent_index = parent_delete_at_index + this_time
322
+ @parent_local_map[ this_parent_index ] -= 1
323
+ end
324
+
325
+ remaining_count = @local_parent_map.count - local_delete_at_index
326
+ remaining_count.times do |this_time|
327
+ this_local_index = local_delete_at_index + this_time
328
+ if parent_index = @local_parent_map[ this_local_index ]
329
+ @local_parent_map[ this_local_index ] = parent_index - 1
330
+ end
331
+ end
332
+
333
+ if @parent_and_interpolated_object_count > 0
334
+ @parent_and_interpolated_object_count -= 1
335
+ end
336
+
337
+ # if local => parent is already nil then we've overridden the corresponding index already
338
+ # (we used to call this "replaced_parents")
339
+ unless @local_parent_map[ local_delete_at_index ].nil?
340
+ @local_parent_map.delete_at( local_delete_at_index )
341
+ @parent_lazy_lookup.delete_at( local_delete_at_index )
342
+ end
343
+
344
+ return local_delete_at_index
345
+
346
+ end
347
+
348
+ #####################
349
+ # local_delete_at #
350
+ #####################
351
+
352
+ def local_delete_at( local_index )
353
+
354
+ local_index = index_for_offset( local_index )
355
+
356
+ parent_index = @local_parent_map.delete_at( local_index )
357
+ @parent_lazy_lookup.delete_at( local_index )
358
+
359
+ if inside_parent_elements?( local_index )
360
+
361
+ # if we don't have a parent index corresponding to this index, find the next one that corresponds
362
+ unless parent_index
363
+ next_local_index = local_index
364
+ begin
365
+ parent_index = @local_parent_map[ next_local_index ]
366
+ next_local_index += 1
367
+ end while parent_index.nil? and next_local_index < @local_parent_map.count
368
+ end
369
+
370
+ if parent_index
371
+ remaining_count = @parent_local_map.count - parent_index
372
+ remaining_count.times do |this_time|
373
+ this_parent_index = parent_index + this_time
374
+ @parent_local_map[ this_parent_index ] -= 1
375
+ end
376
+ if @parent_and_interpolated_object_count > 0
377
+ @parent_and_interpolated_object_count -= 1
378
+ end
379
+ end
380
+
381
+ end
382
+
383
+ end
384
+
385
+ end
@@ -0,0 +1,2 @@
1
+
2
+ require_relative '../compositing.rb'
@@ -0,0 +1,3 @@
1
+
2
+ class ::Array::Compositing < ::Array::Hooked
3
+ end
@@ -0,0 +1,3 @@
1
+
2
+ require_relative 'compositing/parent_index_map.rb'
3
+ require_relative 'compositing/array_interface.rb'
@@ -0,0 +1,442 @@
1
+
2
+ require_relative '../../../lib/array-compositing.rb'
3
+
4
+ describe ::Array::Compositing::ParentIndexMap do
5
+
6
+ ######################
7
+ # index_for_offset #
8
+ ######################
9
+
10
+ it 'can translate an offset (positive or negative) into an index' do
11
+ module ::Array::Compositing::ParentIndexMap::IndexForOffsetMock
12
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
13
+ index_for_offset( 0 ).should == 0
14
+ index_for_offset( 1 ).should == 1
15
+ index_for_offset( -1 ).should == 0
16
+ index_for_offset( -2 ).should == 0
17
+ local_insert( 0, 6 )
18
+ index_for_offset( 0 ).should == 0
19
+ index_for_offset( 1 ).should == 1
20
+ index_for_offset( 3 ).should == 3
21
+ index_for_offset( 5 ).should == 5
22
+ index_for_offset( -1 ).should == 5
23
+ index_for_offset( -3 ).should == 3
24
+ index_for_offset( -5 ).should == 1
25
+ index_for_offset( -7 ).should == 0
26
+ end
27
+ end
28
+ end
29
+
30
+ #############################
31
+ # inside_parent_elements? #
32
+ #############################
33
+
34
+ it 'can report whether a local index is inside the range of parent elements' do
35
+ module ::Array::Compositing::ParentIndexMap::InsideParentElementsMock
36
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
37
+ # mock the count
38
+ @parent_and_interpolated_object_count = 4
39
+ inside_parent_elements?( 3 ).should == true
40
+ inside_parent_elements?( 0 ).should == true
41
+ inside_parent_elements?( 4 ).should == false
42
+ inside_parent_elements?( 6 ).should == false
43
+ end
44
+ end
45
+ end
46
+
47
+ ##################
48
+ # parent_index #
49
+ # local_index #
50
+ ##################
51
+
52
+ it 'can return a parent index for a local index or local index for a parent index given two sets of maps that it tracks internally' do
53
+ module ::Array::Compositing::ParentIndexMap::ParentIndexMock
54
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
55
+ # mock the parent-local arrays
56
+ @parent_local_map = [ 0, 1, 2, 3, 4 ]
57
+ @local_parent_map = [ 0, 1, 2, 3, 4 ]
58
+ parent_index( 0 ).should == 0
59
+ local_index( 4 ).should == 4
60
+ end
61
+ end
62
+ end
63
+
64
+ ################################################
65
+ # replaced_parent_element_with_parent_index? #
66
+ ################################################
67
+
68
+ it 'can report if it has replaced a parent index referenced by parent index' do
69
+ module ::Array::Compositing::ParentIndexMap::ReplacedParentElementWithParentIndexMock
70
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
71
+ parent_insert( 0, 2 )
72
+ replaced_parent_element_with_parent_index?( 0 ).should == false
73
+ replaced_parent_element_with_parent_index?( 1 ).should == false
74
+ local_set( 1 )
75
+ local_delete_at( 0 )
76
+ replaced_parent_element_with_parent_index?( 0 ).should == true
77
+ replaced_parent_element_with_parent_index?( 1 ).should == true
78
+ end
79
+ end
80
+ end
81
+
82
+ ###############################################
83
+ # replaced_parent_element_with_local_index? #
84
+ ###############################################
85
+
86
+ it 'can report if it has replaced a parent index referenced by local index' do
87
+ module ::Array::Compositing::ParentIndexMap::ReplacedParentElementWithLocalIndexMock
88
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
89
+ parent_insert( 0, 2 )
90
+ replaced_parent_element_with_local_index?( 0 ).should == false
91
+ replaced_parent_element_with_local_index?( 1 ).should == false
92
+ local_set( 1 )
93
+ replaced_parent_element_with_local_index?( 0 ).should == false
94
+ replaced_parent_element_with_local_index?( 1 ).should == true
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ ###################
101
+ # parent_insert #
102
+ ###################
103
+
104
+ it 'can update its internal parent-local maps for a parent insert with no children' do
105
+ module ::Array::Compositing::ParentIndexMap::ParentInsertMock
106
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
107
+ parent_insert( 0, 2 )
108
+ parent_index( 0 ).should == 0
109
+ local_index( 0 ).should == 0
110
+ requires_lookup?( 0 ).should == true
111
+ requires_lookup?( 1 ).should == true
112
+ looked_up!( 0 )
113
+ looked_up!( 1 )
114
+ requires_lookup?( 0 ).should == false
115
+ requires_lookup?( 1 ).should == false
116
+ end
117
+ end
118
+ end
119
+
120
+ it 'can update its internal parent-local maps for a parent insert with children' do
121
+ module ::Array::Compositing::ParentIndexMap::ParentInsertMock
122
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
123
+ local_insert( 0, 2 )
124
+ parent_index( 0 ).should == nil
125
+ local_index( 0 ).should == nil
126
+ parent_insert( 0, 2 )
127
+ parent_index( 0 ).should == 0
128
+ parent_index( 1 ).should == 1
129
+ local_index( 0 ).should == 0
130
+ local_index( 1 ).should == 1
131
+ local_index( 2 ).should == nil
132
+ local_index( 3 ).should == nil
133
+ requires_lookup?( 0 ).should == true
134
+ requires_lookup?( 1 ).should == true
135
+ looked_up!( 0 )
136
+ looked_up!( 1 )
137
+ requires_lookup?( 0 ).should == false
138
+ requires_lookup?( 1 ).should == false
139
+ end
140
+ end
141
+ end
142
+
143
+ ##################
144
+ # local_insert #
145
+ ##################
146
+
147
+ it 'can update its internal parent-local maps for a local insert when there are no parent elements' do
148
+ module ::Array::Compositing::ParentIndexMap::LocalInsertMock
149
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
150
+ local_insert( 0, 2 )
151
+ parent_index( 0 ).should == nil
152
+ local_index( 0 ).should == nil
153
+ requires_lookup?( 0 ).should == false
154
+ requires_lookup?( 1 ).should == false
155
+ end
156
+ end
157
+ end
158
+
159
+ it 'can update its internal parent-local maps for a local insert inside the range of parent elements' do
160
+ module ::Array::Compositing::ParentIndexMap::LocalInsertMock
161
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
162
+ parent_insert( 0, 2 )
163
+ local_insert( 0, 2 )
164
+ parent_index( 0 ).should == nil
165
+ parent_index( 1 ).should == nil
166
+ parent_index( 2 ).should == 0
167
+ parent_index( 3 ).should == 1
168
+ local_index( 0 ).should == 2
169
+ local_index( 1 ).should == 3
170
+ local_index( 2 ).should == nil
171
+ local_index( 3 ).should == nil
172
+ requires_lookup?( 0 ).should == false
173
+ requires_lookup?( 1 ).should == false
174
+ requires_lookup?( 2 ).should == true
175
+ requires_lookup?( 3 ).should == true
176
+ looked_up!( 2 )
177
+ looked_up!( 3 )
178
+ requires_lookup?( 2 ).should == false
179
+ requires_lookup?( 3 ).should == false
180
+ end
181
+ end
182
+ end
183
+
184
+ it 'can update its internal parent-local maps for a local insert not inside parent element range' do
185
+ module ::Array::Compositing::ParentIndexMap::LocalInsertMock
186
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
187
+ parent_insert( 0, 2 )
188
+ local_insert( 2, 2 )
189
+ parent_index( 0 ).should == 0
190
+ parent_index( 1 ).should == 1
191
+ parent_index( 2 ).should == nil
192
+ parent_index( 3 ).should == nil
193
+ local_index( 0 ).should == 0
194
+ local_index( 1 ).should == 1
195
+ local_index( 2 ).should == nil
196
+ local_index( 3 ).should == nil
197
+ requires_lookup?( 0 ).should == true
198
+ requires_lookup?( 1 ).should == true
199
+ requires_lookup?( 2 ).should == false
200
+ requires_lookup?( 3 ).should == false
201
+ looked_up!( 0 )
202
+ looked_up!( 1 )
203
+ requires_lookup?( 0 ).should == false
204
+ requires_lookup?( 1 ).should == false
205
+ end
206
+ end
207
+ end
208
+
209
+ ################
210
+ # parent_set #
211
+ ################
212
+
213
+ it 'can update its internal parent-local maps for a parent set not inside existing parent elements' do
214
+ module ::Array::Compositing::ParentIndexMap::ParentSetMock
215
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
216
+ parent_insert( 0, 2 )
217
+ local_insert( 2, 2 )
218
+ parent_set( 2 )
219
+ parent_index( 0 ).should == 0
220
+ parent_index( 1 ).should == 1
221
+ parent_index( 2 ).should == 2
222
+ local_index( 0 ).should == 0
223
+ local_index( 1 ).should == 1
224
+ local_index( 2 ).should == 2
225
+ local_index( 3 ).should == nil
226
+ local_index( 4 ).should == nil
227
+ requires_lookup?( 0 ).should == true
228
+ requires_lookup?( 1 ).should == true
229
+ requires_lookup?( 2 ).should == true
230
+ requires_lookup?( 3 ).should == false
231
+ looked_up!( 0 )
232
+ looked_up!( 1 )
233
+ requires_lookup?( 0 ).should == false
234
+ requires_lookup?( 1 ).should == false
235
+ end
236
+ end
237
+ end
238
+
239
+ it 'can update its internal parent-local maps for a parent set inside existing parent elements' do
240
+ module ::Array::Compositing::ParentIndexMap::ParentSetMock
241
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
242
+ parent_insert( 0, 2 )
243
+ local_insert( 2, 2 )
244
+ parent_set( 1 )
245
+ parent_index( 0 ).should == 0
246
+ parent_index( 1 ).should == 1
247
+ local_index( 0 ).should == 0
248
+ local_index( 1 ).should == 1
249
+ local_index( 2 ).should == nil
250
+ local_index( 3 ).should == nil
251
+ requires_lookup?( 0 ).should == true
252
+ requires_lookup?( 1 ).should == true
253
+ requires_lookup?( 2 ).should == false
254
+ requires_lookup?( 3 ).should == false
255
+ looked_up!( 0 )
256
+ looked_up!( 1 )
257
+ requires_lookup?( 0 ).should == false
258
+ requires_lookup?( 1 ).should == false
259
+ end
260
+ end
261
+ end
262
+
263
+ it 'can update its internal parent-local maps for a parent set inside existing parent elements when parent element has been replaced' do
264
+ module ::Array::Compositing::ParentIndexMap::ParentSetMock
265
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
266
+ parent_insert( 0, 2 )
267
+ local_insert( 2, 2 )
268
+ local_set( 1 )
269
+ parent_set( 1 )
270
+ parent_index( 0 ).should == 0
271
+ parent_index( 1 ).should == nil
272
+ local_index( 0 ).should == 0
273
+ local_index( 1 ).should == 1
274
+ local_index( 2 ).should == nil
275
+ local_index( 3 ).should == nil
276
+ requires_lookup?( 0 ).should == true
277
+ requires_lookup?( 1 ).should == false
278
+ requires_lookup?( 2 ).should == false
279
+ requires_lookup?( 3 ).should == false
280
+ looked_up!( 0 )
281
+ looked_up!( 1 )
282
+ requires_lookup?( 0 ).should == false
283
+ requires_lookup?( 1 ).should == false
284
+ end
285
+ end
286
+ end
287
+
288
+ ###############
289
+ # local_set #
290
+ ###############
291
+
292
+ it 'can update its internal parent-local maps for a local set with no parent elements' do
293
+ module ::Array::Compositing::ParentIndexMap::LocalSetMock
294
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
295
+ local_set( 0 )
296
+ parent_index( 0 ).should == nil
297
+ local_index( 0 ).should == nil
298
+ requires_lookup?( 0 ).should == false
299
+ end
300
+ end
301
+ end
302
+
303
+ it 'can update its internal parent-local maps for a local set over a parent element' do
304
+ module ::Array::Compositing::ParentIndexMap::LocalSetMock
305
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
306
+ parent_insert( 0, 2 )
307
+ local_set( 0 )
308
+ parent_index( 0 ).should == nil
309
+ parent_index( 1 ).should == 1
310
+ local_index( 0 ).should == 0
311
+ local_index( 1 ).should == 1
312
+ requires_lookup?( 0 ).should == false
313
+ requires_lookup?( 1 ).should == true
314
+ looked_up!( 1 )
315
+ requires_lookup?( 1 ).should == false
316
+ end
317
+ end
318
+ end
319
+
320
+ it 'can update its internal parent-local maps for a local set outside parent elements' do
321
+ module ::Array::Compositing::ParentIndexMap::LocalSetMock
322
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
323
+ parent_insert( 0, 2 )
324
+ local_set( 2 )
325
+ parent_index( 0 ).should == 0
326
+ parent_index( 1 ).should == 1
327
+ local_index( 0 ).should == 0
328
+ local_index( 1 ).should == 1
329
+ local_index( 2 ).should == nil
330
+ requires_lookup?( 0 ).should == true
331
+ requires_lookup?( 1 ).should == true
332
+ requires_lookup?( 2 ).should == false
333
+ looked_up!( 0 )
334
+ looked_up!( 1 )
335
+ requires_lookup?( 0 ).should == false
336
+ requires_lookup?( 1 ).should == false
337
+ end
338
+ end
339
+ end
340
+
341
+ ######################
342
+ # parent_delete_at #
343
+ ######################
344
+
345
+ it 'can update its internal parent-local maps for a parent delete with no child elements' do
346
+ module ::Array::Compositing::ParentIndexMap::ParentNoChildDeleteAtMock
347
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
348
+ parent_insert( 0, 2 )
349
+ parent_delete_at( 1 )
350
+ parent_index( 0 ).should == 0
351
+ parent_index( 1 ).should == nil
352
+ local_index( 0 ).should == 0
353
+ local_index( 1 ).should == nil
354
+ requires_lookup?( 0 ).should == true
355
+ requires_lookup?( 1 ).should == nil
356
+ end
357
+ end
358
+ end
359
+
360
+ it 'can update its internal parent-local maps for a parent delete with replaced child elements' do
361
+ module ::Array::Compositing::ParentIndexMap::ParentReplacedChildDeleteAtMock
362
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
363
+ parent_insert( 0, 2 )
364
+ local_set( 1 )
365
+ parent_delete_at( 1 )
366
+ parent_index( 0 ).should == 0
367
+ parent_index( 1 ).should == nil
368
+ local_index( 0 ).should == 0
369
+ local_index( 1 ).should == nil
370
+ @local_parent_map.count.should == 2
371
+ requires_lookup?( 0 ).should == true
372
+ requires_lookup?( 1 ).should == false
373
+ looked_up!( 0 )
374
+ requires_lookup?( 0 ).should == false
375
+ end
376
+ end
377
+ end
378
+
379
+ #####################
380
+ # local_delete_at #
381
+ #####################
382
+
383
+ it 'can update its internal parent-local maps for a local delete of parent elements' do
384
+ module ::Array::Compositing::ParentIndexMap::LocalDeleteAtMock
385
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
386
+ parent_insert( 0, 2 )
387
+ local_delete_at( 1 )
388
+ parent_index( 0 ).should == 0
389
+ parent_index( 1 ).should == nil
390
+ local_index( 0 ).should == 0
391
+ local_index( 1 ).should == 0
392
+ requires_lookup?( 0 ).should == true
393
+ requires_lookup?( 1 ).should == nil
394
+ looked_up!( 0 )
395
+ requires_lookup?( 0 ).should == false
396
+ end
397
+ end
398
+ end
399
+
400
+ it 'can update its internal parent-local maps for a local delete inside parents of a non-parent element' do
401
+ module ::Array::Compositing::ParentIndexMap::LocalDeleteAtMock
402
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
403
+ parent_insert( 0, 2 )
404
+ local_insert( 1, 1 )
405
+ local_delete_at( 1 )
406
+ parent_index( 0 ).should == 0
407
+ parent_index( 1 ).should == 1
408
+ local_index( 0 ).should == 0
409
+ local_index( 1 ).should == 1
410
+ requires_lookup?( 0 ).should == true
411
+ requires_lookup?( 1 ).should == true
412
+ looked_up!( 0 )
413
+ looked_up!( 1 )
414
+ requires_lookup?( 0 ).should == false
415
+ requires_lookup?( 1 ).should == false
416
+ end
417
+ end
418
+ end
419
+
420
+ it 'can update its internal parent-local maps for a local delete outside parents' do
421
+ module ::Array::Compositing::ParentIndexMap::LocalDeleteAtMock
422
+ ::Array::Compositing::ParentIndexMap.new.instance_eval do
423
+ parent_insert( 0, 2 )
424
+ local_insert( 2, 2 )
425
+ local_delete_at( 3 )
426
+ parent_index( 0 ).should == 0
427
+ parent_index( 1 ).should == 1
428
+ local_index( 0 ).should == 0
429
+ local_index( 1 ).should == 1
430
+ requires_lookup?( 0 ).should == true
431
+ requires_lookup?( 1 ).should == true
432
+ requires_lookup?( 2 ).should == false
433
+ requires_lookup?( 3 ).should == nil
434
+ looked_up!( 0 )
435
+ looked_up!( 1 )
436
+ requires_lookup?( 0 ).should == false
437
+ requires_lookup?( 1 ).should == false
438
+ end
439
+ end
440
+ end
441
+
442
+ end