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, 19 * sizeof(ValueInternalLink) ); 20 * This optimization is used by the fast allocator. 21 */ 22ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {} 23 24ValueInternalLink::~ValueInternalLink() { 25 for (int index = 0; index < itemPerLink; ++index) { 26 if (!items_[index].isItemAvailable()) { 27 if (!items_[index].isMemberNameStatic()) 28 free(keys_[index]); 29 } else 30 break; 31 } 32} 33 34ValueMapAllocator::~ValueMapAllocator() {} 35 36#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 37class DefaultValueMapAllocator : public ValueMapAllocator { 38public: // overridden from ValueMapAllocator 39 virtual ValueInternalMap* newMap() { return new ValueInternalMap(); } 40 41 virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) { 42 return new ValueInternalMap(other); 43 } 44 45 virtual void destructMap(ValueInternalMap* map) { delete map; } 46 47 virtual ValueInternalLink* allocateMapBuckets(unsigned int size) { 48 return new ValueInternalLink[size]; 49 } 50 51 virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; } 52 53 virtual ValueInternalLink* allocateMapLink() { 54 return new ValueInternalLink(); 55 } 56 57 virtual void releaseMapLink(ValueInternalLink* link) { delete link; } 58}; 59#else 60/// @todo make this thread-safe (lock when accessign batch allocator) 61class DefaultValueMapAllocator : public ValueMapAllocator { 62public: // overridden from ValueMapAllocator 63 virtual ValueInternalMap* newMap() { 64 ValueInternalMap* map = mapsAllocator_.allocate(); 65 new (map) ValueInternalMap(); // placement new 66 return map; 67 } 68 69 virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) { 70 ValueInternalMap* map = mapsAllocator_.allocate(); 71 new (map) ValueInternalMap(other); // placement new 72 return map; 73 } 74 75 virtual void destructMap(ValueInternalMap* map) { 76 if (map) { 77 map->~ValueInternalMap(); 78 mapsAllocator_.release(map); 79 } 80 } 81 82 virtual ValueInternalLink* allocateMapBuckets(unsigned int size) { 83 return new ValueInternalLink[size]; 84 } 85 86 virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; } 87 88 virtual ValueInternalLink* allocateMapLink() { 89 ValueInternalLink* link = linksAllocator_.allocate(); 90 memset(link, 0, sizeof(ValueInternalLink)); 91 return link; 92 } 93 94 virtual void releaseMapLink(ValueInternalLink* link) { 95 link->~ValueInternalLink(); 96 linksAllocator_.release(link); 97 } 98 99private: 100 BatchAllocator<ValueInternalMap, 1> mapsAllocator_; 101 BatchAllocator<ValueInternalLink, 1> linksAllocator_; 102}; 103#endif 104 105static ValueMapAllocator*& mapAllocator() { 106 static DefaultValueMapAllocator defaultAllocator; 107 static ValueMapAllocator* mapAllocator = &defaultAllocator; 108 return mapAllocator; 109} 110 111static struct DummyMapAllocatorInitializer { 112 DummyMapAllocatorInitializer() { 113 mapAllocator(); // ensure mapAllocator() statics are initialized before 114 // main(). 115 } 116} dummyMapAllocatorInitializer; 117 118// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. 119 120/* 121use linked list hash map. 122buckets array is a container. 123linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) 124value have extra state: valid, available, deleted 125*/ 126 127ValueInternalMap::ValueInternalMap() 128 : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {} 129 130ValueInternalMap::ValueInternalMap(const ValueInternalMap& other) 131 : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) { 132 reserve(other.itemCount_); 133 IteratorState it; 134 IteratorState itEnd; 135 other.makeBeginIterator(it); 136 other.makeEndIterator(itEnd); 137 for (; !equals(it, itEnd); increment(it)) { 138 bool isStatic; 139 const char* memberName = key(it, isStatic); 140 const Value& aValue = value(it); 141 resolveReference(memberName, isStatic) = aValue; 142 } 143} 144 145ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) { 146 swap(other); 147 return *this; 148} 149 150ValueInternalMap::~ValueInternalMap() { 151 if (buckets_) { 152 for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_; 153 ++bucketIndex) { 154 ValueInternalLink* link = buckets_[bucketIndex].next_; 155 while (link) { 156 ValueInternalLink* linkToRelease = link; 157 link = link->next_; 158 mapAllocator()->releaseMapLink(linkToRelease); 159 } 160 } 161 mapAllocator()->releaseMapBuckets(buckets_); 162 } 163} 164 165void ValueInternalMap::swap(ValueInternalMap& other) { 166 ValueInternalLink* tempBuckets = buckets_; 167 buckets_ = other.buckets_; 168 other.buckets_ = tempBuckets; 169 ValueInternalLink* tempTailLink = tailLink_; 170 tailLink_ = other.tailLink_; 171 other.tailLink_ = tempTailLink; 172 BucketIndex tempBucketsSize = bucketsSize_; 173 bucketsSize_ = other.bucketsSize_; 174 other.bucketsSize_ = tempBucketsSize; 175 BucketIndex tempItemCount = itemCount_; 176 itemCount_ = other.itemCount_; 177 other.itemCount_ = tempItemCount; 178} 179 180void ValueInternalMap::clear() { 181 ValueInternalMap dummy; 182 swap(dummy); 183} 184 185ValueInternalMap::BucketIndex ValueInternalMap::size() const { 186 return itemCount_; 187} 188 189bool ValueInternalMap::reserveDelta(BucketIndex growth) { 190 return reserve(itemCount_ + growth); 191} 192 193bool ValueInternalMap::reserve(BucketIndex newItemCount) { 194 if (!buckets_ && newItemCount > 0) { 195 buckets_ = mapAllocator()->allocateMapBuckets(1); 196 bucketsSize_ = 1; 197 tailLink_ = &buckets_[0]; 198 } 199 // BucketIndex idealBucketCount = (newItemCount + 200 // ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; 201 return true; 202} 203 204const Value* ValueInternalMap::find(const char* key) const { 205 if (!bucketsSize_) 206 return 0; 207 HashKey hashedKey = hash(key); 208 BucketIndex bucketIndex = hashedKey % bucketsSize_; 209 for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0; 210 current = current->next_) { 211 for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink; 212 ++index) { 213 if (current->items_[index].isItemAvailable()) 214 return 0; 215 if (strcmp(key, current->keys_[index]) == 0) 216 return ¤t->items_[index]; 217 } 218 } 219 return 0; 220} 221 222Value* ValueInternalMap::find(const char* key) { 223 const ValueInternalMap* constThis = this; 224 return const_cast<Value*>(constThis->find(key)); 225} 226 227Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) { 228 HashKey hashedKey = hash(key); 229 if (bucketsSize_) { 230 BucketIndex bucketIndex = hashedKey % bucketsSize_; 231 ValueInternalLink** previous = 0; 232 BucketIndex index; 233 for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0; 234 previous = ¤t->next_, current = current->next_) { 235 for (index = 0; index < ValueInternalLink::itemPerLink; ++index) { 236 if (current->items_[index].isItemAvailable()) 237 return setNewItem(key, isStatic, current, index); 238 if (strcmp(key, current->keys_[index]) == 0) 239 return current->items_[index]; 240 } 241 } 242 } 243 244 reserveDelta(1); 245 return unsafeAdd(key, isStatic, hashedKey); 246} 247 248void ValueInternalMap::remove(const char* key) { 249 HashKey hashedKey = hash(key); 250 if (!bucketsSize_) 251 return; 252 BucketIndex bucketIndex = hashedKey % bucketsSize_; 253 for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0; 254 link = link->next_) { 255 BucketIndex index; 256 for (index = 0; index < ValueInternalLink::itemPerLink; ++index) { 257 if (link->items_[index].isItemAvailable()) 258 return; 259 if (strcmp(key, link->keys_[index]) == 0) { 260 doActualRemove(link, index, bucketIndex); 261 return; 262 } 263 } 264 } 265} 266 267void ValueInternalMap::doActualRemove(ValueInternalLink* link, 268 BucketIndex index, 269 BucketIndex bucketIndex) { 270 // find last item of the bucket and swap it with the 'removed' one. 271 // set removed items flags to 'available'. 272 // if last page only contains 'available' items, then desallocate it (it's 273 // empty) 274 ValueInternalLink*& lastLink = getLastLinkInBucket(index); 275 BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 276 for (; lastItemIndex < ValueInternalLink::itemPerLink; 277 ++lastItemIndex) // may be optimized with dicotomic search 278 { 279 if (lastLink->items_[lastItemIndex].isItemAvailable()) 280 break; 281 } 282 283 BucketIndex lastUsedIndex = lastItemIndex - 1; 284 Value* valueToDelete = &link->items_[index]; 285 Value* valueToPreserve = &lastLink->items_[lastUsedIndex]; 286 if (valueToDelete != valueToPreserve) 287 valueToDelete->swap(*valueToPreserve); 288 if (lastUsedIndex == 0) // page is now empty 289 { // remove it from bucket linked list and delete it. 290 ValueInternalLink* linkPreviousToLast = lastLink->previous_; 291 if (linkPreviousToLast != 0) // can not deleted bucket link. 292 { 293 mapAllocator()->releaseMapLink(lastLink); 294 linkPreviousToLast->next_ = 0; 295 lastLink = linkPreviousToLast; 296 } 297 } else { 298 Value dummy; 299 valueToPreserve->swap(dummy); // restore deleted to default Value. 300 valueToPreserve->setItemUsed(false); 301 } 302 --itemCount_; 303} 304 305ValueInternalLink*& 306ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) { 307 if (bucketIndex == bucketsSize_ - 1) 308 return tailLink_; 309 ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_; 310 if (!previous) 311 previous = &buckets_[bucketIndex]; 312 return previous; 313} 314 315Value& ValueInternalMap::setNewItem(const char* key, 316 bool isStatic, 317 ValueInternalLink* link, 318 BucketIndex index) { 319 char* duplicatedKey = makeMemberName(key); 320 ++itemCount_; 321 link->keys_[index] = duplicatedKey; 322 link->items_[index].setItemUsed(); 323 link->items_[index].setMemberNameIsStatic(isStatic); 324 return link->items_[index]; // items already default constructed. 325} 326 327Value& 328ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) { 329 JSON_ASSERT_MESSAGE(bucketsSize_ > 0, 330 "ValueInternalMap::unsafeAdd(): internal logic error."); 331 BucketIndex bucketIndex = hashedKey % bucketsSize_; 332 ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex); 333 ValueInternalLink* link = previousLink; 334 BucketIndex index; 335 for (index = 0; index < ValueInternalLink::itemPerLink; ++index) { 336 if (link->items_[index].isItemAvailable()) 337 break; 338 } 339 if (index == ValueInternalLink::itemPerLink) // need to add a new page 340 { 341 ValueInternalLink* newLink = mapAllocator()->allocateMapLink(); 342 index = 0; 343 link->next_ = newLink; 344 previousLink = newLink; 345 link = newLink; 346 } 347 return setNewItem(key, isStatic, link, index); 348} 349 350ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const { 351 HashKey hash = 0; 352 while (*key) 353 hash += *key++ * 37; 354 return hash; 355} 356 357int ValueInternalMap::compare(const ValueInternalMap& other) const { 358 int sizeDiff(itemCount_ - other.itemCount_); 359 if (sizeDiff != 0) 360 return sizeDiff; 361 // Strict order guaranty is required. Compare all keys FIRST, then compare 362 // values. 363 IteratorState it; 364 IteratorState itEnd; 365 makeBeginIterator(it); 366 makeEndIterator(itEnd); 367 for (; !equals(it, itEnd); increment(it)) { 368 if (!other.find(key(it))) 369 return 1; 370 } 371 372 // All keys are equals, let's compare values 373 makeBeginIterator(it); 374 for (; !equals(it, itEnd); increment(it)) { 375 const Value* otherValue = other.find(key(it)); 376 int valueDiff = value(it).compare(*otherValue); 377 if (valueDiff != 0) 378 return valueDiff; 379 } 380 return 0; 381} 382 383void ValueInternalMap::makeBeginIterator(IteratorState& it) const { 384 it.map_ = const_cast<ValueInternalMap*>(this); 385 it.bucketIndex_ = 0; 386 it.itemIndex_ = 0; 387 it.link_ = buckets_; 388} 389 390void ValueInternalMap::makeEndIterator(IteratorState& it) const { 391 it.map_ = const_cast<ValueInternalMap*>(this); 392 it.bucketIndex_ = bucketsSize_; 393 it.itemIndex_ = 0; 394 it.link_ = 0; 395} 396 397bool ValueInternalMap::equals(const IteratorState& x, 398 const IteratorState& other) { 399 return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ && 400 x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_; 401} 402 403void ValueInternalMap::incrementBucket(IteratorState& iterator) { 404 ++iterator.bucketIndex_; 405 JSON_ASSERT_MESSAGE( 406 iterator.bucketIndex_ <= iterator.map_->bucketsSize_, 407 "ValueInternalMap::increment(): attempting to iterate beyond end."); 408 if (iterator.bucketIndex_ == iterator.map_->bucketsSize_) 409 iterator.link_ = 0; 410 else 411 iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); 412 iterator.itemIndex_ = 0; 413} 414 415void ValueInternalMap::increment(IteratorState& iterator) { 416 JSON_ASSERT_MESSAGE(iterator.map_, 417 "Attempting to iterator using invalid iterator."); 418 ++iterator.itemIndex_; 419 if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) { 420 JSON_ASSERT_MESSAGE( 421 iterator.link_ != 0, 422 "ValueInternalMap::increment(): attempting to iterate beyond end."); 423 iterator.link_ = iterator.link_->next_; 424 if (iterator.link_ == 0) 425 incrementBucket(iterator); 426 } else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) { 427 incrementBucket(iterator); 428 } 429} 430 431void ValueInternalMap::decrement(IteratorState& iterator) { 432 if (iterator.itemIndex_ == 0) { 433 JSON_ASSERT_MESSAGE(iterator.map_, 434 "Attempting to iterate using invalid iterator."); 435 if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) { 436 JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0, 437 "Attempting to iterate beyond beginning."); 438 --(iterator.bucketIndex_); 439 } 440 iterator.link_ = iterator.link_->previous_; 441 iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; 442 } 443} 444 445const char* ValueInternalMap::key(const IteratorState& iterator) { 446 JSON_ASSERT_MESSAGE(iterator.link_, 447 "Attempting to iterate using invalid iterator."); 448 return iterator.link_->keys_[iterator.itemIndex_]; 449} 450 451const char* ValueInternalMap::key(const IteratorState& iterator, 452 bool& isStatic) { 453 JSON_ASSERT_MESSAGE(iterator.link_, 454 "Attempting to iterate using invalid iterator."); 455 isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); 456 return iterator.link_->keys_[iterator.itemIndex_]; 457} 458 459Value& ValueInternalMap::value(const IteratorState& iterator) { 460 JSON_ASSERT_MESSAGE(iterator.link_, 461 "Attempting to iterate using invalid iterator."); 462 return iterator.link_->items_[iterator.itemIndex_]; 463} 464 465int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) { 466 int offset = 0; 467 IteratorState it = x; 468 while (!equals(it, y)) 469 increment(it); 470 return offset; 471} 472 473} // namespace Json 474