123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- // included by json_value.cpp
- // everything is within Json namespace
- // //////////////////////////////////////////////////////////////////
- // //////////////////////////////////////////////////////////////////
- // //////////////////////////////////////////////////////////////////
- // class ValueInternalMap
- // //////////////////////////////////////////////////////////////////
- // //////////////////////////////////////////////////////////////////
- // //////////////////////////////////////////////////////////////////
- /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
- * This optimization is used by the fast allocator.
- */
- ValueInternalLink::ValueInternalLink()
- : previous_( 0 )
- , next_( 0 )
- {
- }
- ValueInternalLink::~ValueInternalLink()
- {
- for ( int index =0; index < itemPerLink; ++index )
- {
- if ( !items_[index].isItemAvailable() )
- {
- if ( !items_[index].isMemberNameStatic() )
- free( keys_[index] );
- }
- else
- break;
- }
- }
- ValueMapAllocator::~ValueMapAllocator()
- {
- }
- #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
- class DefaultValueMapAllocator : public ValueMapAllocator
- {
- public: // overridden from ValueMapAllocator
- virtual ValueInternalMap *newMap()
- {
- return new ValueInternalMap();
- }
- virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
- {
- return new ValueInternalMap( other );
- }
- virtual void destructMap( ValueInternalMap *map )
- {
- delete map;
- }
- virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
- {
- return new ValueInternalLink[size];
- }
- virtual void releaseMapBuckets( ValueInternalLink *links )
- {
- delete [] links;
- }
- virtual ValueInternalLink *allocateMapLink()
- {
- return new ValueInternalLink();
- }
- virtual void releaseMapLink( ValueInternalLink *link )
- {
- delete link;
- }
- };
- #else
- /// @todo make this thread-safe (lock when accessign batch allocator)
- class DefaultValueMapAllocator : public ValueMapAllocator
- {
- public: // overridden from ValueMapAllocator
- virtual ValueInternalMap *newMap()
- {
- ValueInternalMap *map = mapsAllocator_.allocate();
- new (map) ValueInternalMap(); // placement new
- return map;
- }
- virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
- {
- ValueInternalMap *map = mapsAllocator_.allocate();
- new (map) ValueInternalMap( other ); // placement new
- return map;
- }
- virtual void destructMap( ValueInternalMap *map )
- {
- if ( map )
- {
- map->~ValueInternalMap();
- mapsAllocator_.release( map );
- }
- }
- virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
- {
- return new ValueInternalLink[size];
- }
- virtual void releaseMapBuckets( ValueInternalLink *links )
- {
- delete [] links;
- }
- virtual ValueInternalLink *allocateMapLink()
- {
- ValueInternalLink *link = linksAllocator_.allocate();
- memset( link, 0, sizeof(ValueInternalLink) );
- return link;
- }
- virtual void releaseMapLink( ValueInternalLink *link )
- {
- link->~ValueInternalLink();
- linksAllocator_.release( link );
- }
- private:
- BatchAllocator<ValueInternalMap,1> mapsAllocator_;
- BatchAllocator<ValueInternalLink,1> linksAllocator_;
- };
- #endif
- static ValueMapAllocator *&mapAllocator()
- {
- static DefaultValueMapAllocator defaultAllocator;
- static ValueMapAllocator *mapAllocator = &defaultAllocator;
- return mapAllocator;
- }
- static struct DummyMapAllocatorInitializer {
- DummyMapAllocatorInitializer()
- {
- mapAllocator(); // ensure mapAllocator() statics are initialized before main().
- }
- } dummyMapAllocatorInitializer;
- // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
- /*
- use linked list hash map.
- buckets array is a container.
- linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
- value have extra state: valid, available, deleted
- */
- ValueInternalMap::ValueInternalMap()
- : buckets_( 0 )
- , tailLink_( 0 )
- , bucketsSize_( 0 )
- , itemCount_( 0 )
- {
- }
- ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
- : buckets_( 0 )
- , tailLink_( 0 )
- , bucketsSize_( 0 )
- , itemCount_( 0 )
- {
- reserve( other.itemCount_ );
- IteratorState it;
- IteratorState itEnd;
- other.makeBeginIterator( it );
- other.makeEndIterator( itEnd );
- for ( ; !equals(it,itEnd); increment(it) )
- {
- bool isStatic;
- const char *memberName = key( it, isStatic );
- const Value &aValue = value( it );
- resolveReference(memberName, isStatic) = aValue;
- }
- }
- ValueInternalMap &
- ValueInternalMap::operator =( const ValueInternalMap &other )
- {
- ValueInternalMap dummy( other );
- swap( dummy );
- return *this;
- }
- ValueInternalMap::~ValueInternalMap()
- {
- if ( buckets_ )
- {
- for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
- {
- ValueInternalLink *link = buckets_[bucketIndex].next_;
- while ( link )
- {
- ValueInternalLink *linkToRelease = link;
- link = link->next_;
- mapAllocator()->releaseMapLink( linkToRelease );
- }
- }
- mapAllocator()->releaseMapBuckets( buckets_ );
- }
- }
- void
- ValueInternalMap::swap( ValueInternalMap &other )
- {
- ValueInternalLink *tempBuckets = buckets_;
- buckets_ = other.buckets_;
- other.buckets_ = tempBuckets;
- ValueInternalLink *tempTailLink = tailLink_;
- tailLink_ = other.tailLink_;
- other.tailLink_ = tempTailLink;
- BucketIndex tempBucketsSize = bucketsSize_;
- bucketsSize_ = other.bucketsSize_;
- other.bucketsSize_ = tempBucketsSize;
- BucketIndex tempItemCount = itemCount_;
- itemCount_ = other.itemCount_;
- other.itemCount_ = tempItemCount;
- }
- void
- ValueInternalMap::clear()
- {
- ValueInternalMap dummy;
- swap( dummy );
- }
- ValueInternalMap::BucketIndex
- ValueInternalMap::size() const
- {
- return itemCount_;
- }
- bool
- ValueInternalMap::reserveDelta( BucketIndex growth )
- {
- return reserve( itemCount_ + growth );
- }
- bool
- ValueInternalMap::reserve( BucketIndex newItemCount )
- {
- if ( !buckets_ && newItemCount > 0 )
- {
- buckets_ = mapAllocator()->allocateMapBuckets( 1 );
- bucketsSize_ = 1;
- tailLink_ = &buckets_[0];
- }
- // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
- return true;
- }
- const Value *
- ValueInternalMap::find( const char *key ) const
- {
- if ( !bucketsSize_ )
- return 0;
- HashKey hashedKey = hash( key );
- BucketIndex bucketIndex = hashedKey % bucketsSize_;
- for ( const ValueInternalLink *current = &buckets_[bucketIndex];
- current != 0;
- current = current->next_ )
- {
- for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
- {
- if ( current->items_[index].isItemAvailable() )
- return 0;
- if ( strcmp( key, current->keys_[index] ) == 0 )
- return ¤t->items_[index];
- }
- }
- return 0;
- }
- Value *
- ValueInternalMap::find( const char *key )
- {
- const ValueInternalMap *constThis = this;
- return const_cast<Value *>( constThis->find( key ) );
- }
- Value &
- ValueInternalMap::resolveReference( const char *key,
- bool isStatic )
- {
- HashKey hashedKey = hash( key );
- if ( bucketsSize_ )
- {
- BucketIndex bucketIndex = hashedKey % bucketsSize_;
- ValueInternalLink **previous = 0;
- BucketIndex index;
- for ( ValueInternalLink *current = &buckets_[bucketIndex];
- current != 0;
- previous = ¤t->next_, current = current->next_ )
- {
- for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
- {
- if ( current->items_[index].isItemAvailable() )
- return setNewItem( key, isStatic, current, index );
- if ( strcmp( key, current->keys_[index] ) == 0 )
- return current->items_[index];
- }
- }
- }
- reserveDelta( 1 );
- return unsafeAdd( key, isStatic, hashedKey );
- }
- void
- ValueInternalMap::remove( const char *key )
- {
- HashKey hashedKey = hash( key );
- if ( !bucketsSize_ )
- return;
- BucketIndex bucketIndex = hashedKey % bucketsSize_;
- for ( ValueInternalLink *link = &buckets_[bucketIndex];
- link != 0;
- link = link->next_ )
- {
- BucketIndex index;
- for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
- {
- if ( link->items_[index].isItemAvailable() )
- return;
- if ( strcmp( key, link->keys_[index] ) == 0 )
- {
- doActualRemove( link, index, bucketIndex );
- return;
- }
- }
- }
- }
- void
- ValueInternalMap::doActualRemove( ValueInternalLink *link,
- BucketIndex index,
- BucketIndex bucketIndex )
- {
- // find last item of the bucket and swap it with the 'removed' one.
- // set removed items flags to 'available'.
- // if last page only contains 'available' items, then desallocate it (it's empty)
- ValueInternalLink *&lastLink = getLastLinkInBucket( index );
- BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
- for ( ;
- lastItemIndex < ValueInternalLink::itemPerLink;
- ++lastItemIndex ) // may be optimized with dicotomic search
- {
- if ( lastLink->items_[lastItemIndex].isItemAvailable() )
- break;
- }
-
- BucketIndex lastUsedIndex = lastItemIndex - 1;
- Value *valueToDelete = &link->items_[index];
- Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
- if ( valueToDelete != valueToPreserve )
- valueToDelete->swap( *valueToPreserve );
- if ( lastUsedIndex == 0 ) // page is now empty
- { // remove it from bucket linked list and delete it.
- ValueInternalLink *linkPreviousToLast = lastLink->previous_;
- if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
- {
- mapAllocator()->releaseMapLink( lastLink );
- linkPreviousToLast->next_ = 0;
- lastLink = linkPreviousToLast;
- }
- }
- else
- {
- Value dummy;
- valueToPreserve->swap( dummy ); // restore deleted to default Value.
- valueToPreserve->setItemUsed( false );
- }
- --itemCount_;
- }
- ValueInternalLink *&
- ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
- {
- if ( bucketIndex == bucketsSize_ - 1 )
- return tailLink_;
- ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
- if ( !previous )
- previous = &buckets_[bucketIndex];
- return previous;
- }
- Value &
- ValueInternalMap::setNewItem( const char *key,
- bool isStatic,
- ValueInternalLink *link,
- BucketIndex index )
- {
- char *duplicatedKey = valueAllocator()->makeMemberName( key );
- ++itemCount_;
- link->keys_[index] = duplicatedKey;
- link->items_[index].setItemUsed();
- link->items_[index].setMemberNameIsStatic( isStatic );
- return link->items_[index]; // items already default constructed.
- }
- Value &
- ValueInternalMap::unsafeAdd( const char *key,
- bool isStatic,
- HashKey hashedKey )
- {
- JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
- BucketIndex bucketIndex = hashedKey % bucketsSize_;
- ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
- ValueInternalLink *link = previousLink;
- BucketIndex index;
- for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
- {
- if ( link->items_[index].isItemAvailable() )
- break;
- }
- if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
- {
- ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
- index = 0;
- link->next_ = newLink;
- previousLink = newLink;
- link = newLink;
- }
- return setNewItem( key, isStatic, link, index );
- }
- ValueInternalMap::HashKey
- ValueInternalMap::hash( const char *key ) const
- {
- HashKey hash = 0;
- while ( *key )
- hash += *key++ * 37;
- return hash;
- }
- int
- ValueInternalMap::compare( const ValueInternalMap &other ) const
- {
- int sizeDiff( itemCount_ - other.itemCount_ );
- if ( sizeDiff != 0 )
- return sizeDiff;
- // Strict order guaranty is required. Compare all keys FIRST, then compare values.
- IteratorState it;
- IteratorState itEnd;
- makeBeginIterator( it );
- makeEndIterator( itEnd );
- for ( ; !equals(it,itEnd); increment(it) )
- {
- if ( !other.find( key( it ) ) )
- return 1;
- }
- // All keys are equals, let's compare values
- makeBeginIterator( it );
- for ( ; !equals(it,itEnd); increment(it) )
- {
- const Value *otherValue = other.find( key( it ) );
- int valueDiff = value(it).compare( *otherValue );
- if ( valueDiff != 0 )
- return valueDiff;
- }
- return 0;
- }
- void
- ValueInternalMap::makeBeginIterator( IteratorState &it ) const
- {
- it.map_ = const_cast<ValueInternalMap *>( this );
- it.bucketIndex_ = 0;
- it.itemIndex_ = 0;
- it.link_ = buckets_;
- }
- void
- ValueInternalMap::makeEndIterator( IteratorState &it ) const
- {
- it.map_ = const_cast<ValueInternalMap *>( this );
- it.bucketIndex_ = bucketsSize_;
- it.itemIndex_ = 0;
- it.link_ = 0;
- }
- bool
- ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
- {
- return x.map_ == other.map_
- && x.bucketIndex_ == other.bucketIndex_
- && x.link_ == other.link_
- && x.itemIndex_ == other.itemIndex_;
- }
- void
- ValueInternalMap::incrementBucket( IteratorState &iterator )
- {
- ++iterator.bucketIndex_;
- JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
- "ValueInternalMap::increment(): attempting to iterate beyond end." );
- if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
- iterator.link_ = 0;
- else
- iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
- iterator.itemIndex_ = 0;
- }
- void
- ValueInternalMap::increment( IteratorState &iterator )
- {
- JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
- ++iterator.itemIndex_;
- if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
- {
- JSON_ASSERT_MESSAGE( iterator.link_ != 0,
- "ValueInternalMap::increment(): attempting to iterate beyond end." );
- iterator.link_ = iterator.link_->next_;
- if ( iterator.link_ == 0 )
- incrementBucket( iterator );
- }
- else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
- {
- incrementBucket( iterator );
- }
- }
- void
- ValueInternalMap::decrement( IteratorState &iterator )
- {
- if ( iterator.itemIndex_ == 0 )
- {
- JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
- if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
- {
- JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
- --(iterator.bucketIndex_);
- }
- iterator.link_ = iterator.link_->previous_;
- iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
- }
- }
- const char *
- ValueInternalMap::key( const IteratorState &iterator )
- {
- JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
- return iterator.link_->keys_[iterator.itemIndex_];
- }
- const char *
- ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
- {
- JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
- isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
- return iterator.link_->keys_[iterator.itemIndex_];
- }
- Value &
- ValueInternalMap::value( const IteratorState &iterator )
- {
- JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
- return iterator.link_->items_[iterator.itemIndex_];
- }
- int
- ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
- {
- int offset = 0;
- IteratorState it = x;
- while ( !equals( it, y ) )
- increment( it );
- return offset;
- }
|