annotate third_party/json/json_internalarray.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 ValueInternalArray
ian@0 14 // //////////////////////////////////////////////////////////////////
ian@0 15 // //////////////////////////////////////////////////////////////////
ian@0 16 // //////////////////////////////////////////////////////////////////
ian@0 17
ian@0 18 ValueArrayAllocator::~ValueArrayAllocator()
ian@0 19 {
ian@0 20 }
ian@0 21
ian@0 22 // //////////////////////////////////////////////////////////////////
ian@0 23 // class DefaultValueArrayAllocator
ian@0 24 // //////////////////////////////////////////////////////////////////
ian@0 25 #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
ian@0 26 class DefaultValueArrayAllocator : public ValueArrayAllocator
ian@0 27 {
ian@0 28 public: // overridden from ValueArrayAllocator
ian@0 29 virtual ~DefaultValueArrayAllocator()
ian@0 30 {
ian@0 31 }
ian@0 32
ian@0 33 virtual ValueInternalArray *newArray()
ian@0 34 {
ian@0 35 return new ValueInternalArray();
ian@0 36 }
ian@0 37
ian@0 38 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
ian@0 39 {
ian@0 40 return new ValueInternalArray( other );
ian@0 41 }
ian@0 42
ian@0 43 virtual void destructArray( ValueInternalArray *array )
ian@0 44 {
ian@0 45 delete array;
ian@0 46 }
ian@0 47
ian@0 48 virtual void reallocateArrayPageIndex( Value **&indexes,
ian@0 49 ValueInternalArray::PageIndex &indexCount,
ian@0 50 ValueInternalArray::PageIndex minNewIndexCount )
ian@0 51 {
ian@0 52 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
ian@0 53 if ( minNewIndexCount > newIndexCount )
ian@0 54 newIndexCount = minNewIndexCount;
ian@0 55 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
ian@0 56 JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
ian@0 57 indexCount = newIndexCount;
ian@0 58 indexes = static_cast<Value **>( newIndexes );
ian@0 59 }
ian@0 60 virtual void releaseArrayPageIndex( Value **indexes,
ian@0 61 ValueInternalArray::PageIndex indexCount )
ian@0 62 {
ian@0 63 if ( indexes )
ian@0 64 free( indexes );
ian@0 65 }
ian@0 66
ian@0 67 virtual Value *allocateArrayPage()
ian@0 68 {
ian@0 69 return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
ian@0 70 }
ian@0 71
ian@0 72 virtual void releaseArrayPage( Value *value )
ian@0 73 {
ian@0 74 if ( value )
ian@0 75 free( value );
ian@0 76 }
ian@0 77 };
ian@0 78
ian@0 79 #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
ian@0 80 /// @todo make this thread-safe (lock when accessign batch allocator)
ian@0 81 class DefaultValueArrayAllocator : public ValueArrayAllocator
ian@0 82 {
ian@0 83 public: // overridden from ValueArrayAllocator
ian@0 84 virtual ~DefaultValueArrayAllocator()
ian@0 85 {
ian@0 86 }
ian@0 87
ian@0 88 virtual ValueInternalArray *newArray()
ian@0 89 {
ian@0 90 ValueInternalArray *array = arraysAllocator_.allocate();
ian@0 91 new (array) ValueInternalArray(); // placement new
ian@0 92 return array;
ian@0 93 }
ian@0 94
ian@0 95 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
ian@0 96 {
ian@0 97 ValueInternalArray *array = arraysAllocator_.allocate();
ian@0 98 new (array) ValueInternalArray( other ); // placement new
ian@0 99 return array;
ian@0 100 }
ian@0 101
ian@0 102 virtual void destructArray( ValueInternalArray *array )
ian@0 103 {
ian@0 104 if ( array )
ian@0 105 {
ian@0 106 array->~ValueInternalArray();
ian@0 107 arraysAllocator_.release( array );
ian@0 108 }
ian@0 109 }
ian@0 110
ian@0 111 virtual void reallocateArrayPageIndex( Value **&indexes,
ian@0 112 ValueInternalArray::PageIndex &indexCount,
ian@0 113 ValueInternalArray::PageIndex minNewIndexCount )
ian@0 114 {
ian@0 115 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
ian@0 116 if ( minNewIndexCount > newIndexCount )
ian@0 117 newIndexCount = minNewIndexCount;
ian@0 118 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
ian@0 119 JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
ian@0 120 indexCount = newIndexCount;
ian@0 121 indexes = static_cast<Value **>( newIndexes );
ian@0 122 }
ian@0 123 virtual void releaseArrayPageIndex( Value **indexes,
ian@0 124 ValueInternalArray::PageIndex indexCount )
ian@0 125 {
ian@0 126 if ( indexes )
ian@0 127 free( indexes );
ian@0 128 }
ian@0 129
ian@0 130 virtual Value *allocateArrayPage()
ian@0 131 {
ian@0 132 return static_cast<Value *>( pagesAllocator_.allocate() );
ian@0 133 }
ian@0 134
ian@0 135 virtual void releaseArrayPage( Value *value )
ian@0 136 {
ian@0 137 if ( value )
ian@0 138 pagesAllocator_.release( value );
ian@0 139 }
ian@0 140 private:
ian@0 141 BatchAllocator<ValueInternalArray,1> arraysAllocator_;
ian@0 142 BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
ian@0 143 };
ian@0 144 #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
ian@0 145
ian@0 146 static ValueArrayAllocator *&arrayAllocator()
ian@0 147 {
ian@0 148 static DefaultValueArrayAllocator defaultAllocator;
ian@0 149 static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
ian@0 150 return arrayAllocator;
ian@0 151 }
ian@0 152
ian@0 153 static struct DummyArrayAllocatorInitializer {
ian@0 154 DummyArrayAllocatorInitializer()
ian@0 155 {
ian@0 156 arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
ian@0 157 }
ian@0 158 } dummyArrayAllocatorInitializer;
ian@0 159
ian@0 160 // //////////////////////////////////////////////////////////////////
ian@0 161 // class ValueInternalArray
ian@0 162 // //////////////////////////////////////////////////////////////////
ian@0 163 bool
ian@0 164 ValueInternalArray::equals( const IteratorState &x,
ian@0 165 const IteratorState &other )
ian@0 166 {
ian@0 167 return x.array_ == other.array_
ian@0 168 && x.currentItemIndex_ == other.currentItemIndex_
ian@0 169 && x.currentPageIndex_ == other.currentPageIndex_;
ian@0 170 }
ian@0 171
ian@0 172
ian@0 173 void
ian@0 174 ValueInternalArray::increment( IteratorState &it )
ian@0 175 {
ian@0 176 JSON_ASSERT_MESSAGE( it.array_ &&
ian@0 177 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
ian@0 178 != it.array_->size_,
ian@0 179 "ValueInternalArray::increment(): moving iterator beyond end" );
ian@0 180 ++(it.currentItemIndex_);
ian@0 181 if ( it.currentItemIndex_ == itemsPerPage )
ian@0 182 {
ian@0 183 it.currentItemIndex_ = 0;
ian@0 184 ++(it.currentPageIndex_);
ian@0 185 }
ian@0 186 }
ian@0 187
ian@0 188
ian@0 189 void
ian@0 190 ValueInternalArray::decrement( IteratorState &it )
ian@0 191 {
ian@0 192 JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
ian@0 193 && it.currentItemIndex_ == 0,
ian@0 194 "ValueInternalArray::decrement(): moving iterator beyond end" );
ian@0 195 if ( it.currentItemIndex_ == 0 )
ian@0 196 {
ian@0 197 it.currentItemIndex_ = itemsPerPage-1;
ian@0 198 --(it.currentPageIndex_);
ian@0 199 }
ian@0 200 else
ian@0 201 {
ian@0 202 --(it.currentItemIndex_);
ian@0 203 }
ian@0 204 }
ian@0 205
ian@0 206
ian@0 207 Value &
ian@0 208 ValueInternalArray::unsafeDereference( const IteratorState &it )
ian@0 209 {
ian@0 210 return (*(it.currentPageIndex_))[it.currentItemIndex_];
ian@0 211 }
ian@0 212
ian@0 213
ian@0 214 Value &
ian@0 215 ValueInternalArray::dereference( const IteratorState &it )
ian@0 216 {
ian@0 217 JSON_ASSERT_MESSAGE( it.array_ &&
ian@0 218 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
ian@0 219 < it.array_->size_,
ian@0 220 "ValueInternalArray::dereference(): dereferencing invalid iterator" );
ian@0 221 return unsafeDereference( it );
ian@0 222 }
ian@0 223
ian@0 224 void
ian@0 225 ValueInternalArray::makeBeginIterator( IteratorState &it ) const
ian@0 226 {
ian@0 227 it.array_ = const_cast<ValueInternalArray *>( this );
ian@0 228 it.currentItemIndex_ = 0;
ian@0 229 it.currentPageIndex_ = pages_;
ian@0 230 }
ian@0 231
ian@0 232
ian@0 233 void
ian@0 234 ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
ian@0 235 {
ian@0 236 it.array_ = const_cast<ValueInternalArray *>( this );
ian@0 237 it.currentItemIndex_ = index % itemsPerPage;
ian@0 238 it.currentPageIndex_ = pages_ + index / itemsPerPage;
ian@0 239 }
ian@0 240
ian@0 241
ian@0 242 void
ian@0 243 ValueInternalArray::makeEndIterator( IteratorState &it ) const
ian@0 244 {
ian@0 245 makeIterator( it, size_ );
ian@0 246 }
ian@0 247
ian@0 248
ian@0 249 ValueInternalArray::ValueInternalArray()
ian@0 250 : pages_( 0 )
ian@0 251 , size_( 0 )
ian@0 252 , pageCount_( 0 )
ian@0 253 {
ian@0 254 }
ian@0 255
ian@0 256
ian@0 257 ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
ian@0 258 : pages_( 0 )
ian@0 259 , size_( other.size_ )
ian@0 260 , pageCount_( 0 )
ian@0 261 {
ian@0 262 PageIndex minNewPages = other.size_ / itemsPerPage;
ian@0 263 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
ian@0 264 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
ian@0 265 "ValueInternalArray::reserve(): bad reallocation" );
ian@0 266 IteratorState itOther;
ian@0 267 other.makeBeginIterator( itOther );
ian@0 268 Value *value;
ian@0 269 for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
ian@0 270 {
ian@0 271 if ( index % itemsPerPage == 0 )
ian@0 272 {
ian@0 273 PageIndex pageIndex = index / itemsPerPage;
ian@0 274 value = arrayAllocator()->allocateArrayPage();
ian@0 275 pages_[pageIndex] = value;
ian@0 276 }
ian@0 277 new (value) Value( dereference( itOther ) );
ian@0 278 }
ian@0 279 }
ian@0 280
ian@0 281
ian@0 282 ValueInternalArray &
ian@0 283 ValueInternalArray::operator =( const ValueInternalArray &other )
ian@0 284 {
ian@0 285 ValueInternalArray temp( other );
ian@0 286 swap( temp );
ian@0 287 return *this;
ian@0 288 }
ian@0 289
ian@0 290
ian@0 291 ValueInternalArray::~ValueInternalArray()
ian@0 292 {
ian@0 293 // destroy all constructed items
ian@0 294 IteratorState it;
ian@0 295 IteratorState itEnd;
ian@0 296 makeBeginIterator( it);
ian@0 297 makeEndIterator( itEnd );
ian@0 298 for ( ; !equals(it,itEnd); increment(it) )
ian@0 299 {
ian@0 300 Value *value = &dereference(it);
ian@0 301 value->~Value();
ian@0 302 }
ian@0 303 // release all pages
ian@0 304 PageIndex lastPageIndex = size_ / itemsPerPage;
ian@0 305 for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
ian@0 306 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
ian@0 307 // release pages index
ian@0 308 arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
ian@0 309 }
ian@0 310
ian@0 311
ian@0 312 void
ian@0 313 ValueInternalArray::swap( ValueInternalArray &other )
ian@0 314 {
ian@0 315 Value **tempPages = pages_;
ian@0 316 pages_ = other.pages_;
ian@0 317 other.pages_ = tempPages;
ian@0 318 ArrayIndex tempSize = size_;
ian@0 319 size_ = other.size_;
ian@0 320 other.size_ = tempSize;
ian@0 321 PageIndex tempPageCount = pageCount_;
ian@0 322 pageCount_ = other.pageCount_;
ian@0 323 other.pageCount_ = tempPageCount;
ian@0 324 }
ian@0 325
ian@0 326 void
ian@0 327 ValueInternalArray::clear()
ian@0 328 {
ian@0 329 ValueInternalArray dummy;
ian@0 330 swap( dummy );
ian@0 331 }
ian@0 332
ian@0 333
ian@0 334 void
ian@0 335 ValueInternalArray::resize( ArrayIndex newSize )
ian@0 336 {
ian@0 337 if ( newSize == 0 )
ian@0 338 clear();
ian@0 339 else if ( newSize < size_ )
ian@0 340 {
ian@0 341 IteratorState it;
ian@0 342 IteratorState itEnd;
ian@0 343 makeIterator( it, newSize );
ian@0 344 makeIterator( itEnd, size_ );
ian@0 345 for ( ; !equals(it,itEnd); increment(it) )
ian@0 346 {
ian@0 347 Value *value = &dereference(it);
ian@0 348 value->~Value();
ian@0 349 }
ian@0 350 PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
ian@0 351 PageIndex lastPageIndex = size_ / itemsPerPage;
ian@0 352 for ( ; pageIndex < lastPageIndex; ++pageIndex )
ian@0 353 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
ian@0 354 size_ = newSize;
ian@0 355 }
ian@0 356 else if ( newSize > size_ )
ian@0 357 resolveReference( newSize );
ian@0 358 }
ian@0 359
ian@0 360
ian@0 361 void
ian@0 362 ValueInternalArray::makeIndexValid( ArrayIndex index )
ian@0 363 {
ian@0 364 // Need to enlarge page index ?
ian@0 365 if ( index >= pageCount_ * itemsPerPage )
ian@0 366 {
ian@0 367 PageIndex minNewPages = (index + 1) / itemsPerPage;
ian@0 368 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
ian@0 369 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
ian@0 370 }
ian@0 371
ian@0 372 // Need to allocate new pages ?
ian@0 373 ArrayIndex nextPageIndex =
ian@0 374 (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
ian@0 375 : size_;
ian@0 376 if ( nextPageIndex <= index )
ian@0 377 {
ian@0 378 PageIndex pageIndex = nextPageIndex / itemsPerPage;
ian@0 379 PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
ian@0 380 for ( ; pageToAllocate-- > 0; ++pageIndex )
ian@0 381 pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
ian@0 382 }
ian@0 383
ian@0 384 // Initialize all new entries
ian@0 385 IteratorState it;
ian@0 386 IteratorState itEnd;
ian@0 387 makeIterator( it, size_ );
ian@0 388 size_ = index + 1;
ian@0 389 makeIterator( itEnd, size_ );
ian@0 390 for ( ; !equals(it,itEnd); increment(it) )
ian@0 391 {
ian@0 392 Value *value = &dereference(it);
ian@0 393 new (value) Value(); // Construct a default value using placement new
ian@0 394 }
ian@0 395 }
ian@0 396
ian@0 397 Value &
ian@0 398 ValueInternalArray::resolveReference( ArrayIndex index )
ian@0 399 {
ian@0 400 if ( index >= size_ )
ian@0 401 makeIndexValid( index );
ian@0 402 return pages_[index/itemsPerPage][index%itemsPerPage];
ian@0 403 }
ian@0 404
ian@0 405 Value *
ian@0 406 ValueInternalArray::find( ArrayIndex index ) const
ian@0 407 {
ian@0 408 if ( index >= size_ )
ian@0 409 return 0;
ian@0 410 return &(pages_[index/itemsPerPage][index%itemsPerPage]);
ian@0 411 }
ian@0 412
ian@0 413 ValueInternalArray::ArrayIndex
ian@0 414 ValueInternalArray::size() const
ian@0 415 {
ian@0 416 return size_;
ian@0 417 }
ian@0 418
ian@0 419 int
ian@0 420 ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
ian@0 421 {
ian@0 422 return indexOf(y) - indexOf(x);
ian@0 423 }
ian@0 424
ian@0 425
ian@0 426 ValueInternalArray::ArrayIndex
ian@0 427 ValueInternalArray::indexOf( const IteratorState &iterator )
ian@0 428 {
ian@0 429 if ( !iterator.array_ )
ian@0 430 return ArrayIndex(-1);
ian@0 431 return ArrayIndex(
ian@0 432 (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
ian@0 433 + iterator.currentItemIndex_ );
ian@0 434 }
ian@0 435
ian@0 436
ian@0 437 int
ian@0 438 ValueInternalArray::compare( const ValueInternalArray &other ) const
ian@0 439 {
ian@0 440 int sizeDiff( size_ - other.size_ );
ian@0 441 if ( sizeDiff != 0 )
ian@0 442 return sizeDiff;
ian@0 443
ian@0 444 for ( ArrayIndex index =0; index < size_; ++index )
ian@0 445 {
ian@0 446 int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
ian@0 447 other.pages_[index/itemsPerPage][index%itemsPerPage] );
ian@0 448 if ( diff != 0 )
ian@0 449 return diff;
ian@0 450 }
ian@0 451 return 0;
ian@0 452 }
ian@0 453
ian@0 454 } // namespace Json