JsonCpp project page JsonCpp home page

json_internalmap.inl

Go to the documentation of this file.
00001 // Copyright 2007-2010 Baptiste Lepilleur
00002 // Distributed under MIT license, or public domain if desired and
00003 // recognized in your jurisdiction.
00004 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
00005 
00006 // included by json_value.cpp
00007 
00008 namespace Json {
00009 
00010 // //////////////////////////////////////////////////////////////////
00011 // //////////////////////////////////////////////////////////////////
00012 // //////////////////////////////////////////////////////////////////
00013 // class ValueInternalMap
00014 // //////////////////////////////////////////////////////////////////
00015 // //////////////////////////////////////////////////////////////////
00016 // //////////////////////////////////////////////////////////////////
00017 
00021 ValueInternalLink::ValueInternalLink()
00022    : previous_( 0 )
00023    , next_( 0 )
00024 {
00025 }
00026 
00027 ValueInternalLink::~ValueInternalLink()
00028 { 
00029    for ( int index =0; index < itemPerLink; ++index )
00030    {
00031       if ( !items_[index].isItemAvailable() )
00032       {
00033          if ( !items_[index].isMemberNameStatic() )
00034             free( keys_[index] );
00035       }
00036       else
00037          break;
00038    }
00039 }
00040 
00041 
00042 
00043 ValueMapAllocator::~ValueMapAllocator()
00044 {
00045 }
00046 
00047 #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
00048 class DefaultValueMapAllocator : public ValueMapAllocator
00049 {
00050 public: // overridden from ValueMapAllocator
00051    virtual ValueInternalMap *newMap()
00052    {
00053       return new ValueInternalMap();
00054    }
00055 
00056    virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
00057    {
00058       return new ValueInternalMap( other );
00059    }
00060 
00061    virtual void destructMap( ValueInternalMap *map )
00062    {
00063       delete map;
00064    }
00065 
00066    virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
00067    {
00068       return new ValueInternalLink[size];
00069    }
00070 
00071    virtual void releaseMapBuckets( ValueInternalLink *links )
00072    {
00073       delete [] links;
00074    }
00075 
00076    virtual ValueInternalLink *allocateMapLink()
00077    {
00078       return new ValueInternalLink();
00079    }
00080 
00081    virtual void releaseMapLink( ValueInternalLink *link )
00082    {
00083       delete link;
00084    }
00085 };
00086 #else
00088 class DefaultValueMapAllocator : public ValueMapAllocator
00089 {
00090 public: // overridden from ValueMapAllocator
00091    virtual ValueInternalMap *newMap()
00092    {
00093       ValueInternalMap *map = mapsAllocator_.allocate();
00094       new (map) ValueInternalMap(); // placement new
00095       return map;
00096    }
00097 
00098    virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
00099    {
00100       ValueInternalMap *map = mapsAllocator_.allocate();
00101       new (map) ValueInternalMap( other ); // placement new
00102       return map;
00103    }
00104 
00105    virtual void destructMap( ValueInternalMap *map )
00106    {
00107       if ( map )
00108       {
00109          map->~ValueInternalMap();
00110          mapsAllocator_.release( map );
00111       }
00112    }
00113 
00114    virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
00115    {
00116       return new ValueInternalLink[size];
00117    }
00118 
00119    virtual void releaseMapBuckets( ValueInternalLink *links )
00120    {
00121       delete [] links;
00122    }
00123 
00124    virtual ValueInternalLink *allocateMapLink()
00125    {
00126       ValueInternalLink *link = linksAllocator_.allocate();
00127       memset( link, 0, sizeof(ValueInternalLink) );
00128       return link;
00129    }
00130 
00131    virtual void releaseMapLink( ValueInternalLink *link )
00132    {
00133       link->~ValueInternalLink();
00134       linksAllocator_.release( link );
00135    }
00136 private:
00137    BatchAllocator<ValueInternalMap,1> mapsAllocator_;
00138    BatchAllocator<ValueInternalLink,1> linksAllocator_;
00139 };
00140 #endif
00141 
00142 static ValueMapAllocator *&mapAllocator()
00143 {
00144    static DefaultValueMapAllocator defaultAllocator;
00145    static ValueMapAllocator *mapAllocator = &defaultAllocator;
00146    return mapAllocator;
00147 }
00148 
00149 static struct DummyMapAllocatorInitializer {
00150    DummyMapAllocatorInitializer() 
00151    {
00152       mapAllocator();      // ensure mapAllocator() statics are initialized before main().
00153    }
00154 } dummyMapAllocatorInitializer;
00155 
00156 
00157 
00158 // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
00159 
00160 /*
00161 use linked list hash map. 
00162 buckets array is a container.
00163 linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
00164 value have extra state: valid, available, deleted
00165 */
00166 
00167 
00168 ValueInternalMap::ValueInternalMap()
00169    : buckets_( 0 )
00170    , tailLink_( 0 )
00171    , bucketsSize_( 0 )
00172    , itemCount_( 0 )
00173 {
00174 }
00175 
00176 
00177 ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
00178    : buckets_( 0 )
00179    , tailLink_( 0 )
00180    , bucketsSize_( 0 )
00181    , itemCount_( 0 )
00182 {
00183    reserve( other.itemCount_ );
00184    IteratorState it;
00185    IteratorState itEnd;
00186    other.makeBeginIterator( it );
00187    other.makeEndIterator( itEnd );
00188    for ( ; !equals(it,itEnd); increment(it) )
00189    {
00190       bool isStatic;
00191       const char *memberName = key( it, isStatic );
00192       const Value &aValue = value( it );
00193       resolveReference(memberName, isStatic) = aValue;
00194    }
00195 }
00196 
00197 
00198 ValueInternalMap &
00199 ValueInternalMap::operator =( const ValueInternalMap &other )
00200 {
00201    ValueInternalMap dummy( other );
00202    swap( dummy );
00203    return *this;
00204 }
00205 
00206 
00207 ValueInternalMap::~ValueInternalMap()
00208 {
00209    if ( buckets_ )
00210    {
00211       for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
00212       {
00213          ValueInternalLink *link = buckets_[bucketIndex].next_;
00214          while ( link )
00215          {
00216             ValueInternalLink *linkToRelease = link;
00217             link = link->next_;
00218             mapAllocator()->releaseMapLink( linkToRelease );
00219          }
00220       }
00221       mapAllocator()->releaseMapBuckets( buckets_ );
00222    }
00223 }
00224 
00225 
00226 void 
00227 ValueInternalMap::swap( ValueInternalMap &other )
00228 {
00229    ValueInternalLink *tempBuckets = buckets_;
00230    buckets_ = other.buckets_;
00231    other.buckets_ = tempBuckets;
00232    ValueInternalLink *tempTailLink = tailLink_;
00233    tailLink_ = other.tailLink_;
00234    other.tailLink_ = tempTailLink;
00235    BucketIndex tempBucketsSize = bucketsSize_;
00236    bucketsSize_ = other.bucketsSize_;
00237    other.bucketsSize_ = tempBucketsSize;
00238    BucketIndex tempItemCount = itemCount_;
00239    itemCount_ = other.itemCount_;
00240    other.itemCount_ = tempItemCount;
00241 }
00242 
00243 
00244 void 
00245 ValueInternalMap::clear()
00246 {
00247    ValueInternalMap dummy;
00248    swap( dummy );
00249 }
00250 
00251 
00252 ValueInternalMap::BucketIndex 
00253 ValueInternalMap::size() const
00254 {
00255    return itemCount_;
00256 }
00257 
00258 bool 
00259 ValueInternalMap::reserveDelta( BucketIndex growth )
00260 {
00261    return reserve( itemCount_ + growth );
00262 }
00263 
00264 bool 
00265 ValueInternalMap::reserve( BucketIndex newItemCount )
00266 {
00267    if ( !buckets_  &&  newItemCount > 0 )
00268    {
00269       buckets_ = mapAllocator()->allocateMapBuckets( 1 );
00270       bucketsSize_ = 1;
00271       tailLink_ = &buckets_[0];
00272    }
00273 //   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
00274    return true;
00275 }
00276 
00277 
00278 const Value *
00279 ValueInternalMap::find( const char *key ) const
00280 {
00281    if ( !bucketsSize_ )
00282       return 0;
00283    HashKey hashedKey = hash( key );
00284    BucketIndex bucketIndex = hashedKey % bucketsSize_;
00285    for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 
00286          current != 0; 
00287          current = current->next_ )
00288    {
00289       for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
00290       {
00291          if ( current->items_[index].isItemAvailable() )
00292             return 0;
00293          if ( strcmp( key, current->keys_[index] ) == 0 )
00294             return &current->items_[index];
00295       }
00296    }
00297    return 0;
00298 }
00299 
00300 
00301 Value *
00302 ValueInternalMap::find( const char *key )
00303 {
00304    const ValueInternalMap *constThis = this;
00305    return const_cast<Value *>( constThis->find( key ) );
00306 }
00307 
00308 
00309 Value &
00310 ValueInternalMap::resolveReference( const char *key,
00311                                     bool isStatic )
00312 {
00313    HashKey hashedKey = hash( key );
00314    if ( bucketsSize_ )
00315    {
00316       BucketIndex bucketIndex = hashedKey % bucketsSize_;
00317       ValueInternalLink **previous = 0;
00318       BucketIndex index;
00319       for ( ValueInternalLink *current = &buckets_[bucketIndex]; 
00320             current != 0; 
00321             previous = &current->next_, current = current->next_ )
00322       {
00323          for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
00324          {
00325             if ( current->items_[index].isItemAvailable() )
00326                return setNewItem( key, isStatic, current, index );
00327             if ( strcmp( key, current->keys_[index] ) == 0 )
00328                return current->items_[index];
00329          }
00330       }
00331    }
00332 
00333    reserveDelta( 1 );
00334    return unsafeAdd( key, isStatic, hashedKey );
00335 }
00336 
00337 
00338 void 
00339 ValueInternalMap::remove( const char *key )
00340 {
00341    HashKey hashedKey = hash( key );
00342    if ( !bucketsSize_ )
00343       return;
00344    BucketIndex bucketIndex = hashedKey % bucketsSize_;
00345    for ( ValueInternalLink *link = &buckets_[bucketIndex]; 
00346          link != 0; 
00347          link = link->next_ )
00348    {
00349       BucketIndex index;
00350       for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
00351       {
00352          if ( link->items_[index].isItemAvailable() )
00353             return;
00354          if ( strcmp( key, link->keys_[index] ) == 0 )
00355          {
00356             doActualRemove( link, index, bucketIndex );
00357             return;
00358          }
00359       }
00360    }
00361 }
00362 
00363 void 
00364 ValueInternalMap::doActualRemove( ValueInternalLink *link, 
00365                                   BucketIndex index,
00366                                   BucketIndex bucketIndex )
00367 {
00368    // find last item of the bucket and swap it with the 'removed' one.
00369    // set removed items flags to 'available'.
00370    // if last page only contains 'available' items, then desallocate it (it's empty)
00371    ValueInternalLink *&lastLink = getLastLinkInBucket( index );
00372    BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
00373    for ( ;   
00374          lastItemIndex < ValueInternalLink::itemPerLink; 
00375          ++lastItemIndex ) // may be optimized with dicotomic search
00376    {
00377       if ( lastLink->items_[lastItemIndex].isItemAvailable() )
00378          break;
00379    }
00380    
00381    BucketIndex lastUsedIndex = lastItemIndex - 1;
00382    Value *valueToDelete = &link->items_[index];
00383    Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
00384    if ( valueToDelete != valueToPreserve )
00385       valueToDelete->swap( *valueToPreserve );
00386    if ( lastUsedIndex == 0 )  // page is now empty
00387    {  // remove it from bucket linked list and delete it.
00388       ValueInternalLink *linkPreviousToLast = lastLink->previous_;
00389       if ( linkPreviousToLast != 0 )   // can not deleted bucket link.
00390       {
00391          mapAllocator()->releaseMapLink( lastLink );
00392          linkPreviousToLast->next_ = 0;
00393          lastLink = linkPreviousToLast;
00394       }
00395    }
00396    else
00397    {
00398       Value dummy;
00399       valueToPreserve->swap( dummy ); // restore deleted to default Value.
00400       valueToPreserve->setItemUsed( false );
00401    }
00402    --itemCount_;
00403 }
00404 
00405 
00406 ValueInternalLink *&
00407 ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
00408 {
00409    if ( bucketIndex == bucketsSize_ - 1 )
00410       return tailLink_;
00411    ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
00412    if ( !previous )
00413       previous = &buckets_[bucketIndex];
00414    return previous;
00415 }
00416 
00417 
00418 Value &
00419 ValueInternalMap::setNewItem( const char *key, 
00420                               bool isStatic,
00421                               ValueInternalLink *link, 
00422                               BucketIndex index )
00423 {
00424    char *duplicatedKey = makeMemberName( key );
00425    ++itemCount_;
00426    link->keys_[index] = duplicatedKey;
00427    link->items_[index].setItemUsed();
00428    link->items_[index].setMemberNameIsStatic( isStatic );
00429    return link->items_[index]; // items already default constructed.
00430 }
00431 
00432 
00433 Value &
00434 ValueInternalMap::unsafeAdd( const char *key, 
00435                              bool isStatic, 
00436                              HashKey hashedKey )
00437 {
00438    JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
00439    BucketIndex bucketIndex = hashedKey % bucketsSize_;
00440    ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
00441    ValueInternalLink *link = previousLink;
00442    BucketIndex index;
00443    for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
00444    {
00445       if ( link->items_[index].isItemAvailable() )
00446          break;
00447    }
00448    if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
00449    {
00450       ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
00451       index = 0;
00452       link->next_ = newLink;
00453       previousLink = newLink;
00454       link = newLink;
00455    }
00456    return setNewItem( key, isStatic, link, index );
00457 }
00458 
00459 
00460 ValueInternalMap::HashKey 
00461 ValueInternalMap::hash( const char *key ) const
00462 {
00463    HashKey hash = 0;
00464    while ( *key )
00465       hash += *key++ * 37;
00466    return hash;
00467 }
00468 
00469 
00470 int 
00471 ValueInternalMap::compare( const ValueInternalMap &other ) const
00472 {
00473    int sizeDiff( itemCount_ - other.itemCount_ );
00474    if ( sizeDiff != 0 )
00475       return sizeDiff;
00476    // Strict order guaranty is required. Compare all keys FIRST, then compare values.
00477    IteratorState it;
00478    IteratorState itEnd;
00479    makeBeginIterator( it );
00480    makeEndIterator( itEnd );
00481    for ( ; !equals(it,itEnd); increment(it) )
00482    {
00483       if ( !other.find( key( it ) ) )
00484          return 1;
00485    }
00486 
00487    // All keys are equals, let's compare values
00488    makeBeginIterator( it );
00489    for ( ; !equals(it,itEnd); increment(it) )
00490    {
00491       const Value *otherValue = other.find( key( it ) );
00492       int valueDiff = value(it).compare( *otherValue );
00493       if ( valueDiff != 0 )
00494          return valueDiff;
00495    }
00496    return 0;
00497 }
00498 
00499 
00500 void 
00501 ValueInternalMap::makeBeginIterator( IteratorState &it ) const
00502 {
00503    it.map_ = const_cast<ValueInternalMap *>( this );
00504    it.bucketIndex_ = 0;
00505    it.itemIndex_ = 0;
00506    it.link_ = buckets_;
00507 }
00508 
00509 
00510 void 
00511 ValueInternalMap::makeEndIterator( IteratorState &it ) const
00512 {
00513    it.map_ = const_cast<ValueInternalMap *>( this );
00514    it.bucketIndex_ = bucketsSize_;
00515    it.itemIndex_ = 0;
00516    it.link_ = 0;
00517 }
00518 
00519 
00520 bool 
00521 ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
00522 {
00523    return x.map_ == other.map_  
00524           &&  x.bucketIndex_ == other.bucketIndex_  
00525           &&  x.link_ == other.link_
00526           &&  x.itemIndex_ == other.itemIndex_;
00527 }
00528 
00529 
00530 void 
00531 ValueInternalMap::incrementBucket( IteratorState &iterator )
00532 {
00533    ++iterator.bucketIndex_;
00534    JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
00535       "ValueInternalMap::increment(): attempting to iterate beyond end." );
00536    if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
00537       iterator.link_ = 0;
00538    else
00539       iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
00540    iterator.itemIndex_ = 0;
00541 }
00542 
00543 
00544 void 
00545 ValueInternalMap::increment( IteratorState &iterator )
00546 {
00547    JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
00548    ++iterator.itemIndex_;
00549    if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
00550    {
00551       JSON_ASSERT_MESSAGE( iterator.link_ != 0,
00552          "ValueInternalMap::increment(): attempting to iterate beyond end." );
00553       iterator.link_ = iterator.link_->next_;
00554       if ( iterator.link_ == 0 )
00555          incrementBucket( iterator );
00556    }
00557    else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
00558    {
00559       incrementBucket( iterator );
00560    }
00561 }
00562 
00563 
00564 void 
00565 ValueInternalMap::decrement( IteratorState &iterator )
00566 {
00567    if ( iterator.itemIndex_ == 0 )
00568    {
00569       JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
00570       if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
00571       {
00572          JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
00573          --(iterator.bucketIndex_);
00574       }
00575       iterator.link_ = iterator.link_->previous_;
00576       iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
00577    }
00578 }
00579 
00580 
00581 const char *
00582 ValueInternalMap::key( const IteratorState &iterator )
00583 {
00584    JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
00585    return iterator.link_->keys_[iterator.itemIndex_];
00586 }
00587 
00588 const char *
00589 ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
00590 {
00591    JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
00592    isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
00593    return iterator.link_->keys_[iterator.itemIndex_];
00594 }
00595 
00596 
00597 Value &
00598 ValueInternalMap::value( const IteratorState &iterator )
00599 {
00600    JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
00601    return iterator.link_->items_[iterator.itemIndex_];
00602 }
00603 
00604 
00605 int 
00606 ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
00607 {
00608    int offset = 0;
00609    IteratorState it = x;
00610    while ( !equals( it, y ) )
00611       increment( it );
00612    return offset;
00613 }
00614 
00615 } // namespace Json

SourceForge Logo hosts this site. Send comments to:
Json-cpp Developers