1
// included by json_value.cpp
2
// everything is within Json namespace
4
// //////////////////////////////////////////////////////////////////
5
// //////////////////////////////////////////////////////////////////
6
// //////////////////////////////////////////////////////////////////
7
// class ValueInternalMap
8
// //////////////////////////////////////////////////////////////////
9
// //////////////////////////////////////////////////////////////////
10
// //////////////////////////////////////////////////////////////////
12
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
13
* This optimization is used by the fast allocator.
15
ValueInternalLink::ValueInternalLink()
21
ValueInternalLink::~ValueInternalLink()
23
for ( int index =0; index < itemPerLink; ++index )
25
if ( !items_[index].isItemAvailable() )
27
if ( !items_[index].isMemberNameStatic() )
37
ValueMapAllocator::~ValueMapAllocator()
41
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
42
class DefaultValueMapAllocator : public ValueMapAllocator
44
public: // overridden from ValueMapAllocator
45
virtual ValueInternalMap *newMap()
47
return new ValueInternalMap();
50
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
52
return new ValueInternalMap( other );
55
virtual void destructMap( ValueInternalMap *map )
60
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
62
return new ValueInternalLink[size];
65
virtual void releaseMapBuckets( ValueInternalLink *links )
70
virtual ValueInternalLink *allocateMapLink()
72
return new ValueInternalLink();
75
virtual void releaseMapLink( ValueInternalLink *link )
81
/// @todo make this thread-safe (lock when accessign batch allocator)
82
class DefaultValueMapAllocator : public ValueMapAllocator
84
public: // overridden from ValueMapAllocator
85
virtual ValueInternalMap *newMap()
87
ValueInternalMap *map = mapsAllocator_.allocate();
88
new (map) ValueInternalMap(); // placement new
92
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
94
ValueInternalMap *map = mapsAllocator_.allocate();
95
new (map) ValueInternalMap( other ); // placement new
99
virtual void destructMap( ValueInternalMap *map )
103
map->~ValueInternalMap();
104
mapsAllocator_.release( map );
108
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
110
return new ValueInternalLink[size];
113
virtual void releaseMapBuckets( ValueInternalLink *links )
118
virtual ValueInternalLink *allocateMapLink()
120
ValueInternalLink *link = linksAllocator_.allocate();
121
memset( link, 0, sizeof(ValueInternalLink) );
125
virtual void releaseMapLink( ValueInternalLink *link )
127
link->~ValueInternalLink();
128
linksAllocator_.release( link );
131
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
132
BatchAllocator<ValueInternalLink,1> linksAllocator_;
136
static ValueMapAllocator *&mapAllocator()
138
static DefaultValueMapAllocator defaultAllocator;
139
static ValueMapAllocator *mapAllocator = &defaultAllocator;
143
static struct DummyMapAllocatorInitializer {
144
DummyMapAllocatorInitializer()
146
mapAllocator(); // ensure mapAllocator() statics are initialized before main().
148
} dummyMapAllocatorInitializer;
152
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
155
use linked list hash map.
156
buckets array is a container.
157
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
158
value have extra state: valid, available, deleted
162
ValueInternalMap::ValueInternalMap()
171
ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
177
reserve( other.itemCount_ );
180
other.makeBeginIterator( it );
181
other.makeEndIterator( itEnd );
182
for ( ; !equals(it,itEnd); increment(it) )
185
const char *memberName = key( it, isStatic );
186
const Value &aValue = value( it );
187
resolveReference(memberName, isStatic) = aValue;
193
ValueInternalMap::operator =( const ValueInternalMap &other )
195
ValueInternalMap dummy( other );
201
ValueInternalMap::~ValueInternalMap()
205
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
207
ValueInternalLink *link = buckets_[bucketIndex].next_;
210
ValueInternalLink *linkToRelease = link;
212
mapAllocator()->releaseMapLink( linkToRelease );
215
mapAllocator()->releaseMapBuckets( buckets_ );
221
ValueInternalMap::swap( ValueInternalMap &other )
223
ValueInternalLink *tempBuckets = buckets_;
224
buckets_ = other.buckets_;
225
other.buckets_ = tempBuckets;
226
ValueInternalLink *tempTailLink = tailLink_;
227
tailLink_ = other.tailLink_;
228
other.tailLink_ = tempTailLink;
229
BucketIndex tempBucketsSize = bucketsSize_;
230
bucketsSize_ = other.bucketsSize_;
231
other.bucketsSize_ = tempBucketsSize;
232
BucketIndex tempItemCount = itemCount_;
233
itemCount_ = other.itemCount_;
234
other.itemCount_ = tempItemCount;
239
ValueInternalMap::clear()
241
ValueInternalMap dummy;
246
ValueInternalMap::BucketIndex
247
ValueInternalMap::size() const
253
ValueInternalMap::reserveDelta( BucketIndex growth )
255
return reserve( itemCount_ + growth );
259
ValueInternalMap::reserve( BucketIndex newItemCount )
261
if ( !buckets_ && newItemCount > 0 )
263
buckets_ = mapAllocator()->allocateMapBuckets( 1 );
265
tailLink_ = &buckets_[0];
267
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
273
ValueInternalMap::find( const char *key ) const
277
HashKey hashedKey = hash( key );
278
BucketIndex bucketIndex = hashedKey % bucketsSize_;
279
for ( const ValueInternalLink *current = &buckets_[bucketIndex];
281
current = current->next_ )
283
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
285
if ( current->items_[index].isItemAvailable() )
287
if ( strcmp( key, current->keys_[index] ) == 0 )
288
return ¤t->items_[index];
296
ValueInternalMap::find( const char *key )
298
const ValueInternalMap *constThis = this;
299
return const_cast<Value *>( constThis->find( key ) );
304
ValueInternalMap::resolveReference( const char *key,
307
HashKey hashedKey = hash( key );
310
BucketIndex bucketIndex = hashedKey % bucketsSize_;
311
ValueInternalLink **previous = 0;
313
for ( ValueInternalLink *current = &buckets_[bucketIndex];
315
previous = ¤t->next_, current = current->next_ )
317
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
319
if ( current->items_[index].isItemAvailable() )
320
return setNewItem( key, isStatic, current, index );
321
if ( strcmp( key, current->keys_[index] ) == 0 )
322
return current->items_[index];
328
return unsafeAdd( key, isStatic, hashedKey );
333
ValueInternalMap::remove( const char *key )
335
HashKey hashedKey = hash( key );
338
BucketIndex bucketIndex = hashedKey % bucketsSize_;
339
for ( ValueInternalLink *link = &buckets_[bucketIndex];
344
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
346
if ( link->items_[index].isItemAvailable() )
348
if ( strcmp( key, link->keys_[index] ) == 0 )
350
doActualRemove( link, index, bucketIndex );
358
ValueInternalMap::doActualRemove( ValueInternalLink *link,
360
BucketIndex bucketIndex )
362
// find last item of the bucket and swap it with the 'removed' one.
363
// set removed items flags to 'available'.
364
// if last page only contains 'available' items, then desallocate it (it's empty)
365
ValueInternalLink *&lastLink = getLastLinkInBucket( index );
366
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
368
lastItemIndex < ValueInternalLink::itemPerLink;
369
++lastItemIndex ) // may be optimized with dicotomic search
371
if ( lastLink->items_[lastItemIndex].isItemAvailable() )
375
BucketIndex lastUsedIndex = lastItemIndex - 1;
376
Value *valueToDelete = &link->items_[index];
377
Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
378
if ( valueToDelete != valueToPreserve )
379
valueToDelete->swap( *valueToPreserve );
380
if ( lastUsedIndex == 0 ) // page is now empty
381
{ // remove it from bucket linked list and delete it.
382
ValueInternalLink *linkPreviousToLast = lastLink->previous_;
383
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
385
mapAllocator()->releaseMapLink( lastLink );
386
linkPreviousToLast->next_ = 0;
387
lastLink = linkPreviousToLast;
393
valueToPreserve->swap( dummy ); // restore deleted to default Value.
394
valueToPreserve->setItemUsed( false );
401
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
403
if ( bucketIndex == bucketsSize_ - 1 )
405
ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
407
previous = &buckets_[bucketIndex];
413
ValueInternalMap::setNewItem( const char *key,
415
ValueInternalLink *link,
418
char *duplicatedKey = valueAllocator()->makeMemberName( key );
420
link->keys_[index] = duplicatedKey;
421
link->items_[index].setItemUsed();
422
link->items_[index].setMemberNameIsStatic( isStatic );
423
return link->items_[index]; // items already default constructed.
428
ValueInternalMap::unsafeAdd( const char *key,
432
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
433
BucketIndex bucketIndex = hashedKey % bucketsSize_;
434
ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
435
ValueInternalLink *link = previousLink;
437
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
439
if ( link->items_[index].isItemAvailable() )
442
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
444
ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
446
link->next_ = newLink;
447
previousLink = newLink;
450
return setNewItem( key, isStatic, link, index );
454
ValueInternalMap::HashKey
455
ValueInternalMap::hash( const char *key ) const
465
ValueInternalMap::compare( const ValueInternalMap &other ) const
467
int sizeDiff( itemCount_ - other.itemCount_ );
470
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
473
makeBeginIterator( it );
474
makeEndIterator( itEnd );
475
for ( ; !equals(it,itEnd); increment(it) )
477
if ( !other.find( key( it ) ) )
481
// All keys are equals, let's compare values
482
makeBeginIterator( it );
483
for ( ; !equals(it,itEnd); increment(it) )
485
const Value *otherValue = other.find( key( it ) );
486
int valueDiff = value(it).compare( *otherValue );
487
if ( valueDiff != 0 )
495
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
497
it.map_ = const_cast<ValueInternalMap *>( this );
505
ValueInternalMap::makeEndIterator( IteratorState &it ) const
507
it.map_ = const_cast<ValueInternalMap *>( this );
508
it.bucketIndex_ = bucketsSize_;
515
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
517
return x.map_ == other.map_
518
&& x.bucketIndex_ == other.bucketIndex_
519
&& x.link_ == other.link_
520
&& x.itemIndex_ == other.itemIndex_;
525
ValueInternalMap::incrementBucket( IteratorState &iterator )
527
++iterator.bucketIndex_;
528
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
529
"ValueInternalMap::increment(): attempting to iterate beyond end." );
530
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
533
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
534
iterator.itemIndex_ = 0;
539
ValueInternalMap::increment( IteratorState &iterator )
541
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
542
++iterator.itemIndex_;
543
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
545
JSON_ASSERT_MESSAGE( iterator.link_ != 0,
546
"ValueInternalMap::increment(): attempting to iterate beyond end." );
547
iterator.link_ = iterator.link_->next_;
548
if ( iterator.link_ == 0 )
549
incrementBucket( iterator );
551
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
553
incrementBucket( iterator );
559
ValueInternalMap::decrement( IteratorState &iterator )
561
if ( iterator.itemIndex_ == 0 )
563
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
564
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
566
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
567
--(iterator.bucketIndex_);
569
iterator.link_ = iterator.link_->previous_;
570
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
576
ValueInternalMap::key( const IteratorState &iterator )
578
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
579
return iterator.link_->keys_[iterator.itemIndex_];
583
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
585
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
586
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
587
return iterator.link_->keys_[iterator.itemIndex_];
592
ValueInternalMap::value( const IteratorState &iterator )
594
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
595
return iterator.link_->items_[iterator.itemIndex_];
600
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
603
IteratorState it = x;
604
while ( !equals( it, y ) )