@@ -29,7 +29,6 @@ public class BsonTrie<TValue>
29
29
30
30
// private fields
31
31
private readonly BsonTrieNode < TValue > _root ;
32
- private bool _isFrozen ;
33
32
34
33
// constructors
35
34
/// <summary>
@@ -60,7 +59,6 @@ public BsonTrieNode<TValue> Root
60
59
/// <param name="value">The value to add. The value can be null for reference types.</param>
61
60
public void Add ( string elementName , TValue value )
62
61
{
63
- if ( _isFrozen ) { throw new InvalidOperationException ( "BsonTrie is frozen." ) ; }
64
62
var keyBytes = __utf8Encoding . GetBytes ( elementName ) ;
65
63
66
64
var node = _root ;
@@ -78,18 +76,6 @@ public void Add(string elementName, TValue value)
78
76
node . SetValue ( elementName , value ) ;
79
77
}
80
78
81
- /// <summary>
82
- /// Freezes the BsonTrie and optimizes the nodes included so far for faster retrieval.
83
- /// </summary>
84
- public void Freeze ( )
85
- {
86
- if ( ! _isFrozen )
87
- {
88
- _root . Freeze ( ) ;
89
- _isFrozen = true ;
90
- }
91
- }
92
-
93
79
/// <summary>
94
80
/// Gets the value associated with the specified element name.
95
81
/// </summary>
@@ -136,11 +122,8 @@ public sealed class BsonTrieNode<TValue>
136
122
private TValue _value ;
137
123
private BsonTrieNode < TValue > _onlyChild ; // used when there is only one child
138
124
private BsonTrieNode < TValue > [ ] _children ; // used when there are two or more children
139
-
140
- // private fields set when node is frozen
141
- private bool _isFrozen ;
142
- private byte _minKeyByte ;
143
- private byte [ ] _keyByteIndexes ; // maps key bytes into indexes into the _children list
125
+ private byte [ ] _childrenIndexes ; // maps key bytes into indexes into the _children array
126
+ private byte _minChildKeyByte ; // key byte value of first element in _childrenIndexes
144
127
145
128
// constructors
146
129
internal BsonTrieNode ( byte keyByte )
@@ -209,12 +192,12 @@ public BsonTrieNode<TValue> GetChild(byte keyByte)
209
192
}
210
193
else if ( _children != null )
211
194
{
212
- var index = ( uint ) ( ( int ) keyByte - _minKeyByte ) ;
195
+ var index = ( uint ) ( ( int ) keyByte - _minChildKeyByte ) ;
213
196
// enable the .Net CLR to eliminate an array bounds check on _keyByteIndexes
214
- var keyByteIndexes = _keyByteIndexes ;
215
- if ( index < keyByteIndexes . Length )
197
+ var childrenIndexes = _childrenIndexes ;
198
+ if ( index < childrenIndexes . Length )
216
199
{
217
- index = keyByteIndexes [ index ] ;
200
+ index = childrenIndexes [ index ] ;
218
201
// enable the .Net CLR to eliminate an array bounds check on _children
219
202
var children = _children ;
220
203
if ( index < children . Length )
@@ -229,100 +212,87 @@ public BsonTrieNode<TValue> GetChild(byte keyByte)
229
212
// internal methods
230
213
internal void AddChild ( BsonTrieNode < TValue > child )
231
214
{
232
- if ( _isFrozen ) { throw new InvalidOperationException ( "BsonTrieNode is frozen." ) ; }
215
+ if ( GetChild ( child . _keyByte ) != null )
216
+ {
217
+ throw new ArgumentException ( "BsonTrieNode already contains a child with the same keyByte." ) ;
218
+ }
219
+
233
220
if ( _children != null )
234
221
{
235
- if ( _children [ child . _keyByte ] != null )
222
+ // add a new child to the existing _children
223
+ var children = new BsonTrieNode < TValue > [ _children . Length + 1 ] ;
224
+ Array . Copy ( _children , children , _children . Length ) ;
225
+ children [ children . Length - 1 ] = child ;
226
+
227
+ var childrenIndexes = _childrenIndexes ;
228
+ var minChildKeyByte = _minChildKeyByte ;
229
+ var maxChildKeyByte = _minChildKeyByte + _childrenIndexes . Length - 1 ;
230
+
231
+ // if new keyByte doesn't fall within existing min/max range expand the range
232
+ if ( child . _keyByte < minChildKeyByte )
236
233
{
237
- throw new ArgumentException ( "BsonTrieNode already contains a child with the same keyByte." ) ;
234
+ // grow the indexes on the min side
235
+ minChildKeyByte = child . _keyByte ;
236
+ childrenIndexes = new byte [ maxChildKeyByte - minChildKeyByte + 1 ] ;
237
+ var sizeDelta = childrenIndexes . Length - _childrenIndexes . Length ;
238
+ for ( var i = 0 ; i < sizeDelta ; i ++ )
239
+ {
240
+ childrenIndexes [ i ] = 255 ;
241
+ }
242
+ Array . Copy ( _childrenIndexes , 0 , childrenIndexes , sizeDelta , _childrenIndexes . Length ) ;
238
243
}
244
+ else if ( child . _keyByte > maxChildKeyByte )
245
+ {
246
+ // grow the indexes on the max side
247
+ maxChildKeyByte = child . _keyByte ;
248
+ childrenIndexes = new byte [ maxChildKeyByte - minChildKeyByte + 1 ] ;
249
+ var sizeDelta = childrenIndexes . Length - _childrenIndexes . Length ;
250
+ Array . Copy ( _childrenIndexes , 0 , childrenIndexes , 0 , _childrenIndexes . Length ) ;
251
+ for ( var i = _childrenIndexes . Length ; i < childrenIndexes . Length ; i ++ )
252
+ {
253
+ childrenIndexes [ i ] = 255 ;
254
+ }
255
+ }
256
+ childrenIndexes [ child . _keyByte - minChildKeyByte ] = ( byte ) ( children . Length - 1 ) ;
239
257
240
- _children [ child . _keyByte ] = child ;
258
+ _children = children ;
259
+ _childrenIndexes = childrenIndexes ;
260
+ _minChildKeyByte = minChildKeyByte ;
241
261
}
242
262
else if ( _onlyChild != null )
243
263
{
244
- if ( _onlyChild . _keyByte == child . _keyByte )
264
+ // switch from having an _onlyChild to having two _children
265
+ var children = new BsonTrieNode < TValue > [ 2 ] ;
266
+ children [ 0 ] = _onlyChild ;
267
+ children [ 1 ] = child ;
268
+
269
+ var minChildKeyByte = _onlyChild . _keyByte ;
270
+ var maxChildKeyByte = child . _keyByte ;
271
+ if ( minChildKeyByte > maxChildKeyByte )
245
272
{
246
- throw new ArgumentException ( "BsonTrieNode already contains a child with the same keyByte." ) ;
273
+ minChildKeyByte = child . _keyByte ;
274
+ maxChildKeyByte = _onlyChild . _keyByte ;
247
275
}
248
276
249
- var children = new BsonTrieNode < TValue > [ 256 ] ;
250
- children [ _onlyChild . _keyByte ] = _onlyChild ;
251
- children [ child . _keyByte ] = child ;
252
-
253
- var keyByteIndexes = new byte [ 256 ] ;
254
- for ( var i = 0 ; i < keyByteIndexes . Length ; i ++ )
277
+ var childrenIndexes = new byte [ maxChildKeyByte - minChildKeyByte + 1 ] ;
278
+ for ( var i = 0 ; i < childrenIndexes . Length ; i ++ )
255
279
{
256
- keyByteIndexes [ i ] = ( byte ) i ;
280
+ childrenIndexes [ i ] = 255 ;
257
281
}
282
+ childrenIndexes [ _onlyChild . _keyByte - minChildKeyByte ] = 0 ;
283
+ childrenIndexes [ child . _keyByte - minChildKeyByte ] = 1 ;
258
284
259
- _keyByteIndexes = keyByteIndexes ;
260
285
_onlyChild = null ;
261
286
_children = children ;
287
+ _childrenIndexes = childrenIndexes ;
288
+ _minChildKeyByte = minChildKeyByte ;
262
289
}
263
290
else
264
291
{
265
292
_onlyChild = child ;
266
293
}
267
294
}
268
295
269
- internal void Freeze ( )
270
- {
271
- if ( ! _isFrozen )
272
- {
273
- if ( _onlyChild != null )
274
- {
275
- _onlyChild . Freeze ( ) ;
276
- }
277
- else if ( _children != null )
278
- {
279
- var i = 0 ;
280
-
281
- // _children is guaranteed to have at least one element that isn't null
282
- for ( ; _children [ i ] == null ; i ++ ) ;
283
-
284
- var minKeyByte = ( byte ) i ;
285
- var maxKeyByte = minKeyByte ;
286
-
287
- byte childIndex = 0 ;
288
-
289
- for ( i ++ ; i < _children . Length ; i ++ )
290
- {
291
- if ( _children [ i ] != null )
292
- {
293
- maxKeyByte = ( byte ) i ;
294
- childIndex ++ ;
295
- }
296
- }
297
-
298
- var keyByteIndexes = new byte [ ( int ) maxKeyByte - minKeyByte + 1 ] ;
299
- for ( i = 0 ; i < keyByteIndexes . Length ; i ++ )
300
- {
301
- keyByteIndexes [ i ] = 255 ; // make sure unused entries can be identified
302
- }
303
-
304
- var children = new BsonTrieNode < TValue > [ ( int ) childIndex + 1 ] ;
305
- childIndex = 0 ;
306
- for ( i = 0 ; i < _children . Length ; i ++ )
307
- {
308
- var child = _children [ i ] ;
309
- if ( child != null )
310
- {
311
- keyByteIndexes [ child . _keyByte - minKeyByte ] = childIndex ;
312
- children [ childIndex ] = child ;
313
- child . Freeze ( ) ;
314
- childIndex ++ ;
315
- }
316
- }
317
-
318
- _minKeyByte = minKeyByte ;
319
- _keyByteIndexes = keyByteIndexes ;
320
- _children = children ;
321
- }
322
- _isFrozen = true ;
323
- }
324
- }
325
-
326
296
internal void SetValue ( string elementName , TValue value )
327
297
{
328
298
if ( elementName == null )
@@ -333,7 +303,6 @@ internal void SetValue(string elementName, TValue value)
333
303
{
334
304
throw new InvalidOperationException ( "BsonTrieNode already has a value." ) ;
335
305
}
336
- if ( _isFrozen ) { throw new InvalidOperationException ( "BsonTrieNode is frozen." ) ; }
337
306
338
307
_elementName = elementName ;
339
308
_value = value ;
0 commit comments