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