ian@0
|
1 // Copyright 2007-2010 Baptiste Lepilleur
|
ian@0
|
2 // Distributed under MIT license, or public domain if desired and
|
ian@0
|
3 // recognized in your jurisdiction.
|
ian@0
|
4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
ian@0
|
5
|
ian@0
|
6 // included by json_value.cpp
|
ian@0
|
7
|
ian@0
|
8 namespace Json {
|
ian@0
|
9
|
ian@0
|
10 // //////////////////////////////////////////////////////////////////
|
ian@0
|
11 // //////////////////////////////////////////////////////////////////
|
ian@0
|
12 // //////////////////////////////////////////////////////////////////
|
ian@0
|
13 // class ValueInternalMap
|
ian@0
|
14 // //////////////////////////////////////////////////////////////////
|
ian@0
|
15 // //////////////////////////////////////////////////////////////////
|
ian@0
|
16 // //////////////////////////////////////////////////////////////////
|
ian@0
|
17
|
ian@0
|
18 /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
ian@0
|
19 * This optimization is used by the fast allocator.
|
ian@0
|
20 */
|
ian@0
|
21 ValueInternalLink::ValueInternalLink()
|
ian@0
|
22 : previous_( 0 )
|
ian@0
|
23 , next_( 0 )
|
ian@0
|
24 {
|
ian@0
|
25 }
|
ian@0
|
26
|
ian@0
|
27 ValueInternalLink::~ValueInternalLink()
|
ian@0
|
28 {
|
ian@0
|
29 for ( int index =0; index < itemPerLink; ++index )
|
ian@0
|
30 {
|
ian@0
|
31 if ( !items_[index].isItemAvailable() )
|
ian@0
|
32 {
|
ian@0
|
33 if ( !items_[index].isMemberNameStatic() )
|
ian@0
|
34 free( keys_[index] );
|
ian@0
|
35 }
|
ian@0
|
36 else
|
ian@0
|
37 break;
|
ian@0
|
38 }
|
ian@0
|
39 }
|
ian@0
|
40
|
ian@0
|
41
|
ian@0
|
42
|
ian@0
|
43 ValueMapAllocator::~ValueMapAllocator()
|
ian@0
|
44 {
|
ian@0
|
45 }
|
ian@0
|
46
|
ian@0
|
47 #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
ian@0
|
48 class DefaultValueMapAllocator : public ValueMapAllocator
|
ian@0
|
49 {
|
ian@0
|
50 public: // overridden from ValueMapAllocator
|
ian@0
|
51 virtual ValueInternalMap *newMap()
|
ian@0
|
52 {
|
ian@0
|
53 return new ValueInternalMap();
|
ian@0
|
54 }
|
ian@0
|
55
|
ian@0
|
56 virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
ian@0
|
57 {
|
ian@0
|
58 return new ValueInternalMap( other );
|
ian@0
|
59 }
|
ian@0
|
60
|
ian@0
|
61 virtual void destructMap( ValueInternalMap *map )
|
ian@0
|
62 {
|
ian@0
|
63 delete map;
|
ian@0
|
64 }
|
ian@0
|
65
|
ian@0
|
66 virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
ian@0
|
67 {
|
ian@0
|
68 return new ValueInternalLink[size];
|
ian@0
|
69 }
|
ian@0
|
70
|
ian@0
|
71 virtual void releaseMapBuckets( ValueInternalLink *links )
|
ian@0
|
72 {
|
ian@0
|
73 delete [] links;
|
ian@0
|
74 }
|
ian@0
|
75
|
ian@0
|
76 virtual ValueInternalLink *allocateMapLink()
|
ian@0
|
77 {
|
ian@0
|
78 return new ValueInternalLink();
|
ian@0
|
79 }
|
ian@0
|
80
|
ian@0
|
81 virtual void releaseMapLink( ValueInternalLink *link )
|
ian@0
|
82 {
|
ian@0
|
83 delete link;
|
ian@0
|
84 }
|
ian@0
|
85 };
|
ian@0
|
86 #else
|
ian@0
|
87 /// @todo make this thread-safe (lock when accessign batch allocator)
|
ian@0
|
88 class DefaultValueMapAllocator : public ValueMapAllocator
|
ian@0
|
89 {
|
ian@0
|
90 public: // overridden from ValueMapAllocator
|
ian@0
|
91 virtual ValueInternalMap *newMap()
|
ian@0
|
92 {
|
ian@0
|
93 ValueInternalMap *map = mapsAllocator_.allocate();
|
ian@0
|
94 new (map) ValueInternalMap(); // placement new
|
ian@0
|
95 return map;
|
ian@0
|
96 }
|
ian@0
|
97
|
ian@0
|
98 virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
ian@0
|
99 {
|
ian@0
|
100 ValueInternalMap *map = mapsAllocator_.allocate();
|
ian@0
|
101 new (map) ValueInternalMap( other ); // placement new
|
ian@0
|
102 return map;
|
ian@0
|
103 }
|
ian@0
|
104
|
ian@0
|
105 virtual void destructMap( ValueInternalMap *map )
|
ian@0
|
106 {
|
ian@0
|
107 if ( map )
|
ian@0
|
108 {
|
ian@0
|
109 map->~ValueInternalMap();
|
ian@0
|
110 mapsAllocator_.release( map );
|
ian@0
|
111 }
|
ian@0
|
112 }
|
ian@0
|
113
|
ian@0
|
114 virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
ian@0
|
115 {
|
ian@0
|
116 return new ValueInternalLink[size];
|
ian@0
|
117 }
|
ian@0
|
118
|
ian@0
|
119 virtual void releaseMapBuckets( ValueInternalLink *links )
|
ian@0
|
120 {
|
ian@0
|
121 delete [] links;
|
ian@0
|
122 }
|
ian@0
|
123
|
ian@0
|
124 virtual ValueInternalLink *allocateMapLink()
|
ian@0
|
125 {
|
ian@0
|
126 ValueInternalLink *link = linksAllocator_.allocate();
|
ian@0
|
127 memset( link, 0, sizeof(ValueInternalLink) );
|
ian@0
|
128 return link;
|
ian@0
|
129 }
|
ian@0
|
130
|
ian@0
|
131 virtual void releaseMapLink( ValueInternalLink *link )
|
ian@0
|
132 {
|
ian@0
|
133 link->~ValueInternalLink();
|
ian@0
|
134 linksAllocator_.release( link );
|
ian@0
|
135 }
|
ian@0
|
136 private:
|
ian@0
|
137 BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
ian@0
|
138 BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
ian@0
|
139 };
|
ian@0
|
140 #endif
|
ian@0
|
141
|
ian@0
|
142 static ValueMapAllocator *&mapAllocator()
|
ian@0
|
143 {
|
ian@0
|
144 static DefaultValueMapAllocator defaultAllocator;
|
ian@0
|
145 static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
ian@0
|
146 return mapAllocator;
|
ian@0
|
147 }
|
ian@0
|
148
|
ian@0
|
149 static struct DummyMapAllocatorInitializer {
|
ian@0
|
150 DummyMapAllocatorInitializer()
|
ian@0
|
151 {
|
ian@0
|
152 mapAllocator(); // ensure mapAllocator() statics are initialized before main().
|
ian@0
|
153 }
|
ian@0
|
154 } dummyMapAllocatorInitializer;
|
ian@0
|
155
|
ian@0
|
156
|
ian@0
|
157
|
ian@0
|
158 // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
ian@0
|
159
|
ian@0
|
160 /*
|
ian@0
|
161 use linked list hash map.
|
ian@0
|
162 buckets array is a container.
|
ian@0
|
163 linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
ian@0
|
164 value have extra state: valid, available, deleted
|
ian@0
|
165 */
|
ian@0
|
166
|
ian@0
|
167
|
ian@0
|
168 ValueInternalMap::ValueInternalMap()
|
ian@0
|
169 : buckets_( 0 )
|
ian@0
|
170 , tailLink_( 0 )
|
ian@0
|
171 , bucketsSize_( 0 )
|
ian@0
|
172 , itemCount_( 0 )
|
ian@0
|
173 {
|
ian@0
|
174 }
|
ian@0
|
175
|
ian@0
|
176
|
ian@0
|
177 ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
|
ian@0
|
178 : buckets_( 0 )
|
ian@0
|
179 , tailLink_( 0 )
|
ian@0
|
180 , bucketsSize_( 0 )
|
ian@0
|
181 , itemCount_( 0 )
|
ian@0
|
182 {
|
ian@0
|
183 reserve( other.itemCount_ );
|
ian@0
|
184 IteratorState it;
|
ian@0
|
185 IteratorState itEnd;
|
ian@0
|
186 other.makeBeginIterator( it );
|
ian@0
|
187 other.makeEndIterator( itEnd );
|
ian@0
|
188 for ( ; !equals(it,itEnd); increment(it) )
|
ian@0
|
189 {
|
ian@0
|
190 bool isStatic;
|
ian@0
|
191 const char *memberName = key( it, isStatic );
|
ian@0
|
192 const Value &aValue = value( it );
|
ian@0
|
193 resolveReference(memberName, isStatic) = aValue;
|
ian@0
|
194 }
|
ian@0
|
195 }
|
ian@0
|
196
|
ian@0
|
197
|
ian@0
|
198 ValueInternalMap &
|
ian@0
|
199 ValueInternalMap::operator =( const ValueInternalMap &other )
|
ian@0
|
200 {
|
ian@0
|
201 ValueInternalMap dummy( other );
|
ian@0
|
202 swap( dummy );
|
ian@0
|
203 return *this;
|
ian@0
|
204 }
|
ian@0
|
205
|
ian@0
|
206
|
ian@0
|
207 ValueInternalMap::~ValueInternalMap()
|
ian@0
|
208 {
|
ian@0
|
209 if ( buckets_ )
|
ian@0
|
210 {
|
ian@0
|
211 for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
|
ian@0
|
212 {
|
ian@0
|
213 ValueInternalLink *link = buckets_[bucketIndex].next_;
|
ian@0
|
214 while ( link )
|
ian@0
|
215 {
|
ian@0
|
216 ValueInternalLink *linkToRelease = link;
|
ian@0
|
217 link = link->next_;
|
ian@0
|
218 mapAllocator()->releaseMapLink( linkToRelease );
|
ian@0
|
219 }
|
ian@0
|
220 }
|
ian@0
|
221 mapAllocator()->releaseMapBuckets( buckets_ );
|
ian@0
|
222 }
|
ian@0
|
223 }
|
ian@0
|
224
|
ian@0
|
225
|
ian@0
|
226 void
|
ian@0
|
227 ValueInternalMap::swap( ValueInternalMap &other )
|
ian@0
|
228 {
|
ian@0
|
229 ValueInternalLink *tempBuckets = buckets_;
|
ian@0
|
230 buckets_ = other.buckets_;
|
ian@0
|
231 other.buckets_ = tempBuckets;
|
ian@0
|
232 ValueInternalLink *tempTailLink = tailLink_;
|
ian@0
|
233 tailLink_ = other.tailLink_;
|
ian@0
|
234 other.tailLink_ = tempTailLink;
|
ian@0
|
235 BucketIndex tempBucketsSize = bucketsSize_;
|
ian@0
|
236 bucketsSize_ = other.bucketsSize_;
|
ian@0
|
237 other.bucketsSize_ = tempBucketsSize;
|
ian@0
|
238 BucketIndex tempItemCount = itemCount_;
|
ian@0
|
239 itemCount_ = other.itemCount_;
|
ian@0
|
240 other.itemCount_ = tempItemCount;
|
ian@0
|
241 }
|
ian@0
|
242
|
ian@0
|
243
|
ian@0
|
244 void
|
ian@0
|
245 ValueInternalMap::clear()
|
ian@0
|
246 {
|
ian@0
|
247 ValueInternalMap dummy;
|
ian@0
|
248 swap( dummy );
|
ian@0
|
249 }
|
ian@0
|
250
|
ian@0
|
251
|
ian@0
|
252 ValueInternalMap::BucketIndex
|
ian@0
|
253 ValueInternalMap::size() const
|
ian@0
|
254 {
|
ian@0
|
255 return itemCount_;
|
ian@0
|
256 }
|
ian@0
|
257
|
ian@0
|
258 bool
|
ian@0
|
259 ValueInternalMap::reserveDelta( BucketIndex growth )
|
ian@0
|
260 {
|
ian@0
|
261 return reserve( itemCount_ + growth );
|
ian@0
|
262 }
|
ian@0
|
263
|
ian@0
|
264 bool
|
ian@0
|
265 ValueInternalMap::reserve( BucketIndex newItemCount )
|
ian@0
|
266 {
|
ian@0
|
267 if ( !buckets_ && newItemCount > 0 )
|
ian@0
|
268 {
|
ian@0
|
269 buckets_ = mapAllocator()->allocateMapBuckets( 1 );
|
ian@0
|
270 bucketsSize_ = 1;
|
ian@0
|
271 tailLink_ = &buckets_[0];
|
ian@0
|
272 }
|
ian@0
|
273 // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
ian@0
|
274 return true;
|
ian@0
|
275 }
|
ian@0
|
276
|
ian@0
|
277
|
ian@0
|
278 const Value *
|
ian@0
|
279 ValueInternalMap::find( const char *key ) const
|
ian@0
|
280 {
|
ian@0
|
281 if ( !bucketsSize_ )
|
ian@0
|
282 return 0;
|
ian@0
|
283 HashKey hashedKey = hash( key );
|
ian@0
|
284 BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
ian@0
|
285 for ( const ValueInternalLink *current = &buckets_[bucketIndex];
|
ian@0
|
286 current != 0;
|
ian@0
|
287 current = current->next_ )
|
ian@0
|
288 {
|
ian@0
|
289 for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
|
ian@0
|
290 {
|
ian@0
|
291 if ( current->items_[index].isItemAvailable() )
|
ian@0
|
292 return 0;
|
ian@0
|
293 if ( strcmp( key, current->keys_[index] ) == 0 )
|
ian@0
|
294 return ¤t->items_[index];
|
ian@0
|
295 }
|
ian@0
|
296 }
|
ian@0
|
297 return 0;
|
ian@0
|
298 }
|
ian@0
|
299
|
ian@0
|
300
|
ian@0
|
301 Value *
|
ian@0
|
302 ValueInternalMap::find( const char *key )
|
ian@0
|
303 {
|
ian@0
|
304 const ValueInternalMap *constThis = this;
|
ian@0
|
305 return const_cast<Value *>( constThis->find( key ) );
|
ian@0
|
306 }
|
ian@0
|
307
|
ian@0
|
308
|
ian@0
|
309 Value &
|
ian@0
|
310 ValueInternalMap::resolveReference( const char *key,
|
ian@0
|
311 bool isStatic )
|
ian@0
|
312 {
|
ian@0
|
313 HashKey hashedKey = hash( key );
|
ian@0
|
314 if ( bucketsSize_ )
|
ian@0
|
315 {
|
ian@0
|
316 BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
ian@0
|
317 ValueInternalLink **previous = 0;
|
ian@0
|
318 BucketIndex index;
|
ian@0
|
319 for ( ValueInternalLink *current = &buckets_[bucketIndex];
|
ian@0
|
320 current != 0;
|
ian@0
|
321 previous = ¤t->next_, current = current->next_ )
|
ian@0
|
322 {
|
ian@0
|
323 for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
|
ian@0
|
324 {
|
ian@0
|
325 if ( current->items_[index].isItemAvailable() )
|
ian@0
|
326 return setNewItem( key, isStatic, current, index );
|
ian@0
|
327 if ( strcmp( key, current->keys_[index] ) == 0 )
|
ian@0
|
328 return current->items_[index];
|
ian@0
|
329 }
|
ian@0
|
330 }
|
ian@0
|
331 }
|
ian@0
|
332
|
ian@0
|
333 reserveDelta( 1 );
|
ian@0
|
334 return unsafeAdd( key, isStatic, hashedKey );
|
ian@0
|
335 }
|
ian@0
|
336
|
ian@0
|
337
|
ian@0
|
338 void
|
ian@0
|
339 ValueInternalMap::remove( const char *key )
|
ian@0
|
340 {
|
ian@0
|
341 HashKey hashedKey = hash( key );
|
ian@0
|
342 if ( !bucketsSize_ )
|
ian@0
|
343 return;
|
ian@0
|
344 BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
ian@0
|
345 for ( ValueInternalLink *link = &buckets_[bucketIndex];
|
ian@0
|
346 link != 0;
|
ian@0
|
347 link = link->next_ )
|
ian@0
|
348 {
|
ian@0
|
349 BucketIndex index;
|
ian@0
|
350 for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
ian@0
|
351 {
|
ian@0
|
352 if ( link->items_[index].isItemAvailable() )
|
ian@0
|
353 return;
|
ian@0
|
354 if ( strcmp( key, link->keys_[index] ) == 0 )
|
ian@0
|
355 {
|
ian@0
|
356 doActualRemove( link, index, bucketIndex );
|
ian@0
|
357 return;
|
ian@0
|
358 }
|
ian@0
|
359 }
|
ian@0
|
360 }
|
ian@0
|
361 }
|
ian@0
|
362
|
ian@0
|
363 void
|
ian@0
|
364 ValueInternalMap::doActualRemove( ValueInternalLink *link,
|
ian@0
|
365 BucketIndex index,
|
ian@0
|
366 BucketIndex bucketIndex )
|
ian@0
|
367 {
|
ian@0
|
368 // find last item of the bucket and swap it with the 'removed' one.
|
ian@0
|
369 // set removed items flags to 'available'.
|
ian@0
|
370 // if last page only contains 'available' items, then desallocate it (it's empty)
|
ian@0
|
371 ValueInternalLink *&lastLink = getLastLinkInBucket( index );
|
ian@0
|
372 BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
ian@0
|
373 for ( ;
|
ian@0
|
374 lastItemIndex < ValueInternalLink::itemPerLink;
|
ian@0
|
375 ++lastItemIndex ) // may be optimized with dicotomic search
|
ian@0
|
376 {
|
ian@0
|
377 if ( lastLink->items_[lastItemIndex].isItemAvailable() )
|
ian@0
|
378 break;
|
ian@0
|
379 }
|
ian@0
|
380
|
ian@0
|
381 BucketIndex lastUsedIndex = lastItemIndex - 1;
|
ian@0
|
382 Value *valueToDelete = &link->items_[index];
|
ian@0
|
383 Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
|
ian@0
|
384 if ( valueToDelete != valueToPreserve )
|
ian@0
|
385 valueToDelete->swap( *valueToPreserve );
|
ian@0
|
386 if ( lastUsedIndex == 0 ) // page is now empty
|
ian@0
|
387 { // remove it from bucket linked list and delete it.
|
ian@0
|
388 ValueInternalLink *linkPreviousToLast = lastLink->previous_;
|
ian@0
|
389 if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
|
ian@0
|
390 {
|
ian@0
|
391 mapAllocator()->releaseMapLink( lastLink );
|
ian@0
|
392 linkPreviousToLast->next_ = 0;
|
ian@0
|
393 lastLink = linkPreviousToLast;
|
ian@0
|
394 }
|
ian@0
|
395 }
|
ian@0
|
396 else
|
ian@0
|
397 {
|
ian@0
|
398 Value dummy;
|
ian@0
|
399 valueToPreserve->swap( dummy ); // restore deleted to default Value.
|
ian@0
|
400 valueToPreserve->setItemUsed( false );
|
ian@0
|
401 }
|
ian@0
|
402 --itemCount_;
|
ian@0
|
403 }
|
ian@0
|
404
|
ian@0
|
405
|
ian@0
|
406 ValueInternalLink *&
|
ian@0
|
407 ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
|
ian@0
|
408 {
|
ian@0
|
409 if ( bucketIndex == bucketsSize_ - 1 )
|
ian@0
|
410 return tailLink_;
|
ian@0
|
411 ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
|
ian@0
|
412 if ( !previous )
|
ian@0
|
413 previous = &buckets_[bucketIndex];
|
ian@0
|
414 return previous;
|
ian@0
|
415 }
|
ian@0
|
416
|
ian@0
|
417
|
ian@0
|
418 Value &
|
ian@0
|
419 ValueInternalMap::setNewItem( const char *key,
|
ian@0
|
420 bool isStatic,
|
ian@0
|
421 ValueInternalLink *link,
|
ian@0
|
422 BucketIndex index )
|
ian@0
|
423 {
|
ian@0
|
424 char *duplicatedKey = makeMemberName( key );
|
ian@0
|
425 ++itemCount_;
|
ian@0
|
426 link->keys_[index] = duplicatedKey;
|
ian@0
|
427 link->items_[index].setItemUsed();
|
ian@0
|
428 link->items_[index].setMemberNameIsStatic( isStatic );
|
ian@0
|
429 return link->items_[index]; // items already default constructed.
|
ian@0
|
430 }
|
ian@0
|
431
|
ian@0
|
432
|
ian@0
|
433 Value &
|
ian@0
|
434 ValueInternalMap::unsafeAdd( const char *key,
|
ian@0
|
435 bool isStatic,
|
ian@0
|
436 HashKey hashedKey )
|
ian@0
|
437 {
|
ian@0
|
438 JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
|
ian@0
|
439 BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
ian@0
|
440 ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
|
ian@0
|
441 ValueInternalLink *link = previousLink;
|
ian@0
|
442 BucketIndex index;
|
ian@0
|
443 for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
ian@0
|
444 {
|
ian@0
|
445 if ( link->items_[index].isItemAvailable() )
|
ian@0
|
446 break;
|
ian@0
|
447 }
|
ian@0
|
448 if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
|
ian@0
|
449 {
|
ian@0
|
450 ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
|
ian@0
|
451 index = 0;
|
ian@0
|
452 link->next_ = newLink;
|
ian@0
|
453 previousLink = newLink;
|
ian@0
|
454 link = newLink;
|
ian@0
|
455 }
|
ian@0
|
456 return setNewItem( key, isStatic, link, index );
|
ian@0
|
457 }
|
ian@0
|
458
|
ian@0
|
459
|
ian@0
|
460 ValueInternalMap::HashKey
|
ian@0
|
461 ValueInternalMap::hash( const char *key ) const
|
ian@0
|
462 {
|
ian@0
|
463 HashKey hash = 0;
|
ian@0
|
464 while ( *key )
|
ian@0
|
465 hash += *key++ * 37;
|
ian@0
|
466 return hash;
|
ian@0
|
467 }
|
ian@0
|
468
|
ian@0
|
469
|
ian@0
|
470 int
|
ian@0
|
471 ValueInternalMap::compare( const ValueInternalMap &other ) const
|
ian@0
|
472 {
|
ian@0
|
473 int sizeDiff( itemCount_ - other.itemCount_ );
|
ian@0
|
474 if ( sizeDiff != 0 )
|
ian@0
|
475 return sizeDiff;
|
ian@0
|
476 // Strict order guaranty is required. Compare all keys FIRST, then compare values.
|
ian@0
|
477 IteratorState it;
|
ian@0
|
478 IteratorState itEnd;
|
ian@0
|
479 makeBeginIterator( it );
|
ian@0
|
480 makeEndIterator( itEnd );
|
ian@0
|
481 for ( ; !equals(it,itEnd); increment(it) )
|
ian@0
|
482 {
|
ian@0
|
483 if ( !other.find( key( it ) ) )
|
ian@0
|
484 return 1;
|
ian@0
|
485 }
|
ian@0
|
486
|
ian@0
|
487 // All keys are equals, let's compare values
|
ian@0
|
488 makeBeginIterator( it );
|
ian@0
|
489 for ( ; !equals(it,itEnd); increment(it) )
|
ian@0
|
490 {
|
ian@0
|
491 const Value *otherValue = other.find( key( it ) );
|
ian@0
|
492 int valueDiff = value(it).compare( *otherValue );
|
ian@0
|
493 if ( valueDiff != 0 )
|
ian@0
|
494 return valueDiff;
|
ian@0
|
495 }
|
ian@0
|
496 return 0;
|
ian@0
|
497 }
|
ian@0
|
498
|
ian@0
|
499
|
ian@0
|
500 void
|
ian@0
|
501 ValueInternalMap::makeBeginIterator( IteratorState &it ) const
|
ian@0
|
502 {
|
ian@0
|
503 it.map_ = const_cast<ValueInternalMap *>( this );
|
ian@0
|
504 it.bucketIndex_ = 0;
|
ian@0
|
505 it.itemIndex_ = 0;
|
ian@0
|
506 it.link_ = buckets_;
|
ian@0
|
507 }
|
ian@0
|
508
|
ian@0
|
509
|
ian@0
|
510 void
|
ian@0
|
511 ValueInternalMap::makeEndIterator( IteratorState &it ) const
|
ian@0
|
512 {
|
ian@0
|
513 it.map_ = const_cast<ValueInternalMap *>( this );
|
ian@0
|
514 it.bucketIndex_ = bucketsSize_;
|
ian@0
|
515 it.itemIndex_ = 0;
|
ian@0
|
516 it.link_ = 0;
|
ian@0
|
517 }
|
ian@0
|
518
|
ian@0
|
519
|
ian@0
|
520 bool
|
ian@0
|
521 ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
|
ian@0
|
522 {
|
ian@0
|
523 return x.map_ == other.map_
|
ian@0
|
524 && x.bucketIndex_ == other.bucketIndex_
|
ian@0
|
525 && x.link_ == other.link_
|
ian@0
|
526 && x.itemIndex_ == other.itemIndex_;
|
ian@0
|
527 }
|
ian@0
|
528
|
ian@0
|
529
|
ian@0
|
530 void
|
ian@0
|
531 ValueInternalMap::incrementBucket( IteratorState &iterator )
|
ian@0
|
532 {
|
ian@0
|
533 ++iterator.bucketIndex_;
|
ian@0
|
534 JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
ian@0
|
535 "ValueInternalMap::increment(): attempting to iterate beyond end." );
|
ian@0
|
536 if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
|
ian@0
|
537 iterator.link_ = 0;
|
ian@0
|
538 else
|
ian@0
|
539 iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
ian@0
|
540 iterator.itemIndex_ = 0;
|
ian@0
|
541 }
|
ian@0
|
542
|
ian@0
|
543
|
ian@0
|
544 void
|
ian@0
|
545 ValueInternalMap::increment( IteratorState &iterator )
|
ian@0
|
546 {
|
ian@0
|
547 JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
|
ian@0
|
548 ++iterator.itemIndex_;
|
ian@0
|
549 if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
|
ian@0
|
550 {
|
ian@0
|
551 JSON_ASSERT_MESSAGE( iterator.link_ != 0,
|
ian@0
|
552 "ValueInternalMap::increment(): attempting to iterate beyond end." );
|
ian@0
|
553 iterator.link_ = iterator.link_->next_;
|
ian@0
|
554 if ( iterator.link_ == 0 )
|
ian@0
|
555 incrementBucket( iterator );
|
ian@0
|
556 }
|
ian@0
|
557 else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
|
ian@0
|
558 {
|
ian@0
|
559 incrementBucket( iterator );
|
ian@0
|
560 }
|
ian@0
|
561 }
|
ian@0
|
562
|
ian@0
|
563
|
ian@0
|
564 void
|
ian@0
|
565 ValueInternalMap::decrement( IteratorState &iterator )
|
ian@0
|
566 {
|
ian@0
|
567 if ( iterator.itemIndex_ == 0 )
|
ian@0
|
568 {
|
ian@0
|
569 JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
|
ian@0
|
570 if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
|
ian@0
|
571 {
|
ian@0
|
572 JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
|
ian@0
|
573 --(iterator.bucketIndex_);
|
ian@0
|
574 }
|
ian@0
|
575 iterator.link_ = iterator.link_->previous_;
|
ian@0
|
576 iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
ian@0
|
577 }
|
ian@0
|
578 }
|
ian@0
|
579
|
ian@0
|
580
|
ian@0
|
581 const char *
|
ian@0
|
582 ValueInternalMap::key( const IteratorState &iterator )
|
ian@0
|
583 {
|
ian@0
|
584 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
ian@0
|
585 return iterator.link_->keys_[iterator.itemIndex_];
|
ian@0
|
586 }
|
ian@0
|
587
|
ian@0
|
588 const char *
|
ian@0
|
589 ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
|
ian@0
|
590 {
|
ian@0
|
591 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
ian@0
|
592 isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
ian@0
|
593 return iterator.link_->keys_[iterator.itemIndex_];
|
ian@0
|
594 }
|
ian@0
|
595
|
ian@0
|
596
|
ian@0
|
597 Value &
|
ian@0
|
598 ValueInternalMap::value( const IteratorState &iterator )
|
ian@0
|
599 {
|
ian@0
|
600 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
ian@0
|
601 return iterator.link_->items_[iterator.itemIndex_];
|
ian@0
|
602 }
|
ian@0
|
603
|
ian@0
|
604
|
ian@0
|
605 int
|
ian@0
|
606 ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
|
ian@0
|
607 {
|
ian@0
|
608 int offset = 0;
|
ian@0
|
609 IteratorState it = x;
|
ian@0
|
610 while ( !equals( it, y ) )
|
ian@0
|
611 increment( it );
|
ian@0
|
612 return offset;
|
ian@0
|
613 }
|
ian@0
|
614
|
ian@0
|
615 } // namespace Json
|