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