json_internalarray.inl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008 namespace Json {
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 ValueArrayAllocator::~ValueArrayAllocator()
00019 {
00020 }
00021
00022
00023
00024
00025 #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
00026 class DefaultValueArrayAllocator : public ValueArrayAllocator
00027 {
00028 public:
00029 virtual ~DefaultValueArrayAllocator()
00030 {
00031 }
00032
00033 virtual ValueInternalArray *newArray()
00034 {
00035 return new ValueInternalArray();
00036 }
00037
00038 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
00039 {
00040 return new ValueInternalArray( other );
00041 }
00042
00043 virtual void destructArray( ValueInternalArray *array )
00044 {
00045 delete array;
00046 }
00047
00048 virtual void reallocateArrayPageIndex( Value **&indexes,
00049 ValueInternalArray::PageIndex &indexCount,
00050 ValueInternalArray::PageIndex minNewIndexCount )
00051 {
00052 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
00053 if ( minNewIndexCount > newIndexCount )
00054 newIndexCount = minNewIndexCount;
00055 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
00056 if ( !newIndexes )
00057 throw std::bad_alloc();
00058 indexCount = newIndexCount;
00059 indexes = static_cast<Value **>( newIndexes );
00060 }
00061 virtual void releaseArrayPageIndex( Value **indexes,
00062 ValueInternalArray::PageIndex indexCount )
00063 {
00064 if ( indexes )
00065 free( indexes );
00066 }
00067
00068 virtual Value *allocateArrayPage()
00069 {
00070 return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
00071 }
00072
00073 virtual void releaseArrayPage( Value *value )
00074 {
00075 if ( value )
00076 free( value );
00077 }
00078 };
00079
00080 #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
00082 class DefaultValueArrayAllocator : public ValueArrayAllocator
00083 {
00084 public:
00085 virtual ~DefaultValueArrayAllocator()
00086 {
00087 }
00088
00089 virtual ValueInternalArray *newArray()
00090 {
00091 ValueInternalArray *array = arraysAllocator_.allocate();
00092 new (array) ValueInternalArray();
00093 return array;
00094 }
00095
00096 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
00097 {
00098 ValueInternalArray *array = arraysAllocator_.allocate();
00099 new (array) ValueInternalArray( other );
00100 return array;
00101 }
00102
00103 virtual void destructArray( ValueInternalArray *array )
00104 {
00105 if ( array )
00106 {
00107 array->~ValueInternalArray();
00108 arraysAllocator_.release( array );
00109 }
00110 }
00111
00112 virtual void reallocateArrayPageIndex( Value **&indexes,
00113 ValueInternalArray::PageIndex &indexCount,
00114 ValueInternalArray::PageIndex minNewIndexCount )
00115 {
00116 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
00117 if ( minNewIndexCount > newIndexCount )
00118 newIndexCount = minNewIndexCount;
00119 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
00120 if ( !newIndexes )
00121 throw std::bad_alloc();
00122 indexCount = newIndexCount;
00123 indexes = static_cast<Value **>( newIndexes );
00124 }
00125 virtual void releaseArrayPageIndex( Value **indexes,
00126 ValueInternalArray::PageIndex indexCount )
00127 {
00128 if ( indexes )
00129 free( indexes );
00130 }
00131
00132 virtual Value *allocateArrayPage()
00133 {
00134 return static_cast<Value *>( pagesAllocator_.allocate() );
00135 }
00136
00137 virtual void releaseArrayPage( Value *value )
00138 {
00139 if ( value )
00140 pagesAllocator_.release( value );
00141 }
00142 private:
00143 BatchAllocator<ValueInternalArray,1> arraysAllocator_;
00144 BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
00145 };
00146 #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
00147
00148 static ValueArrayAllocator *&arrayAllocator()
00149 {
00150 static DefaultValueArrayAllocator defaultAllocator;
00151 static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
00152 return arrayAllocator;
00153 }
00154
00155 static struct DummyArrayAllocatorInitializer {
00156 DummyArrayAllocatorInitializer()
00157 {
00158 arrayAllocator();
00159 }
00160 } dummyArrayAllocatorInitializer;
00161
00162
00163
00164
00165 bool
00166 ValueInternalArray::equals( const IteratorState &x,
00167 const IteratorState &other )
00168 {
00169 return x.array_ == other.array_
00170 && x.currentItemIndex_ == other.currentItemIndex_
00171 && x.currentPageIndex_ == other.currentPageIndex_;
00172 }
00173
00174
00175 void
00176 ValueInternalArray::increment( IteratorState &it )
00177 {
00178 JSON_ASSERT_MESSAGE( it.array_ &&
00179 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
00180 != it.array_->size_,
00181 "ValueInternalArray::increment(): moving iterator beyond end" );
00182 ++(it.currentItemIndex_);
00183 if ( it.currentItemIndex_ == itemsPerPage )
00184 {
00185 it.currentItemIndex_ = 0;
00186 ++(it.currentPageIndex_);
00187 }
00188 }
00189
00190
00191 void
00192 ValueInternalArray::decrement( IteratorState &it )
00193 {
00194 JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
00195 && it.currentItemIndex_ == 0,
00196 "ValueInternalArray::decrement(): moving iterator beyond end" );
00197 if ( it.currentItemIndex_ == 0 )
00198 {
00199 it.currentItemIndex_ = itemsPerPage-1;
00200 --(it.currentPageIndex_);
00201 }
00202 else
00203 {
00204 --(it.currentItemIndex_);
00205 }
00206 }
00207
00208
00209 Value &
00210 ValueInternalArray::unsafeDereference( const IteratorState &it )
00211 {
00212 return (*(it.currentPageIndex_))[it.currentItemIndex_];
00213 }
00214
00215
00216 Value &
00217 ValueInternalArray::dereference( const IteratorState &it )
00218 {
00219 JSON_ASSERT_MESSAGE( it.array_ &&
00220 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
00221 < it.array_->size_,
00222 "ValueInternalArray::dereference(): dereferencing invalid iterator" );
00223 return unsafeDereference( it );
00224 }
00225
00226 void
00227 ValueInternalArray::makeBeginIterator( IteratorState &it ) const
00228 {
00229 it.array_ = const_cast<ValueInternalArray *>( this );
00230 it.currentItemIndex_ = 0;
00231 it.currentPageIndex_ = pages_;
00232 }
00233
00234
00235 void
00236 ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
00237 {
00238 it.array_ = const_cast<ValueInternalArray *>( this );
00239 it.currentItemIndex_ = index % itemsPerPage;
00240 it.currentPageIndex_ = pages_ + index / itemsPerPage;
00241 }
00242
00243
00244 void
00245 ValueInternalArray::makeEndIterator( IteratorState &it ) const
00246 {
00247 makeIterator( it, size_ );
00248 }
00249
00250
00251 ValueInternalArray::ValueInternalArray()
00252 : pages_( 0 )
00253 , size_( 0 )
00254 , pageCount_( 0 )
00255 {
00256 }
00257
00258
00259 ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
00260 : pages_( 0 )
00261 , pageCount_( 0 )
00262 , size_( other.size_ )
00263 {
00264 PageIndex minNewPages = other.size_ / itemsPerPage;
00265 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
00266 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
00267 "ValueInternalArray::reserve(): bad reallocation" );
00268 IteratorState itOther;
00269 other.makeBeginIterator( itOther );
00270 Value *value;
00271 for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
00272 {
00273 if ( index % itemsPerPage == 0 )
00274 {
00275 PageIndex pageIndex = index / itemsPerPage;
00276 value = arrayAllocator()->allocateArrayPage();
00277 pages_[pageIndex] = value;
00278 }
00279 new (value) Value( dereference( itOther ) );
00280 }
00281 }
00282
00283
00284 ValueInternalArray &
00285 ValueInternalArray::operator =( const ValueInternalArray &other )
00286 {
00287 ValueInternalArray temp( other );
00288 swap( temp );
00289 return *this;
00290 }
00291
00292
00293 ValueInternalArray::~ValueInternalArray()
00294 {
00295
00296 IteratorState it;
00297 IteratorState itEnd;
00298 makeBeginIterator( it);
00299 makeEndIterator( itEnd );
00300 for ( ; !equals(it,itEnd); increment(it) )
00301 {
00302 Value *value = &dereference(it);
00303 value->~Value();
00304 }
00305
00306 PageIndex lastPageIndex = size_ / itemsPerPage;
00307 for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
00308 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
00309
00310 arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
00311 }
00312
00313
00314 void
00315 ValueInternalArray::swap( ValueInternalArray &other )
00316 {
00317 Value **tempPages = pages_;
00318 pages_ = other.pages_;
00319 other.pages_ = tempPages;
00320 ArrayIndex tempSize = size_;
00321 size_ = other.size_;
00322 other.size_ = tempSize;
00323 PageIndex tempPageCount = pageCount_;
00324 pageCount_ = other.pageCount_;
00325 other.pageCount_ = tempPageCount;
00326 }
00327
00328 void
00329 ValueInternalArray::clear()
00330 {
00331 ValueInternalArray dummy;
00332 swap( dummy );
00333 }
00334
00335
00336 void
00337 ValueInternalArray::resize( ArrayIndex newSize )
00338 {
00339 if ( newSize == 0 )
00340 clear();
00341 else if ( newSize < size_ )
00342 {
00343 IteratorState it;
00344 IteratorState itEnd;
00345 makeIterator( it, newSize );
00346 makeIterator( itEnd, size_ );
00347 for ( ; !equals(it,itEnd); increment(it) )
00348 {
00349 Value *value = &dereference(it);
00350 value->~Value();
00351 }
00352 PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
00353 PageIndex lastPageIndex = size_ / itemsPerPage;
00354 for ( ; pageIndex < lastPageIndex; ++pageIndex )
00355 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
00356 size_ = newSize;
00357 }
00358 else if ( newSize > size_ )
00359 resolveReference( newSize );
00360 }
00361
00362
00363 void
00364 ValueInternalArray::makeIndexValid( ArrayIndex index )
00365 {
00366
00367 if ( index >= pageCount_ * itemsPerPage )
00368 {
00369 PageIndex minNewPages = (index + 1) / itemsPerPage;
00370 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
00371 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
00372 }
00373
00374
00375 ArrayIndex nextPageIndex =
00376 (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
00377 : size_;
00378 if ( nextPageIndex <= index )
00379 {
00380 PageIndex pageIndex = nextPageIndex / itemsPerPage;
00381 PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
00382 for ( ; pageToAllocate-- > 0; ++pageIndex )
00383 pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
00384 }
00385
00386
00387 IteratorState it;
00388 IteratorState itEnd;
00389 makeIterator( it, size_ );
00390 size_ = index + 1;
00391 makeIterator( itEnd, size_ );
00392 for ( ; !equals(it,itEnd); increment(it) )
00393 {
00394 Value *value = &dereference(it);
00395 new (value) Value();
00396 }
00397 }
00398
00399 Value &
00400 ValueInternalArray::resolveReference( ArrayIndex index )
00401 {
00402 if ( index >= size_ )
00403 makeIndexValid( index );
00404 return pages_[index/itemsPerPage][index%itemsPerPage];
00405 }
00406
00407 Value *
00408 ValueInternalArray::find( ArrayIndex index ) const
00409 {
00410 if ( index >= size_ )
00411 return 0;
00412 return &(pages_[index/itemsPerPage][index%itemsPerPage]);
00413 }
00414
00415 ValueInternalArray::ArrayIndex
00416 ValueInternalArray::size() const
00417 {
00418 return size_;
00419 }
00420
00421 int
00422 ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
00423 {
00424 return indexOf(y) - indexOf(x);
00425 }
00426
00427
00428 ValueInternalArray::ArrayIndex
00429 ValueInternalArray::indexOf( const IteratorState &iterator )
00430 {
00431 if ( !iterator.array_ )
00432 return ArrayIndex(-1);
00433 return ArrayIndex(
00434 (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
00435 + iterator.currentItemIndex_ );
00436 }
00437
00438
00439 int
00440 ValueInternalArray::compare( const ValueInternalArray &other ) const
00441 {
00442 int sizeDiff( size_ - other.size_ );
00443 if ( sizeDiff != 0 )
00444 return sizeDiff;
00445
00446 for ( ArrayIndex index =0; index < size_; ++index )
00447 {
00448 int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
00449 other.pages_[index/itemsPerPage][index%itemsPerPage] );
00450 if ( diff != 0 )
00451 return diff;
00452 }
00453 return 0;
00454 }
00455
00456 }