annotate third_party/json/json_internalmap.inl @ 0:add35537fdbb tip

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