array-compositing 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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