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.
- data/CHANGELOG.rdoc +43 -0
- data/README.md +65 -0
- data/README.rdoc +0 -0
- data/lib/array-compositing.rb +2 -0
- data/lib/array/compositing.rb +15 -0
- data/lib/array/compositing/array_interface.rb +486 -0
- data/lib/array/compositing/parent_index_map.rb +385 -0
- data/lib/array/hooked/compositing.rb +2 -0
- data/lib/array/namespaces.rb +3 -0
- data/lib/array/requires.rb +3 -0
- data/spec/array/compositing/parent_index_map_spec.rb +442 -0
- data/spec/array/compositing_spec.rb +1098 -0
- metadata +74 -0
@@ -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,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
|