//------------------------------------------------------------------------------ /* Copyright (c) 2011-2013, OpenCoin, Inc. */ //============================================================================== // included by json_value.cpp // everything is within Json namespace // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueInternalArray // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueArrayAllocator::~ValueArrayAllocator () { } // ////////////////////////////////////////////////////////////////// // class DefaultValueArrayAllocator // ////////////////////////////////////////////////////////////////// #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR class DefaultValueArrayAllocator : public ValueArrayAllocator { public: // overridden from ValueArrayAllocator virtual ~DefaultValueArrayAllocator () { } virtual ValueInternalArray* newArray () { return new ValueInternalArray (); } virtual ValueInternalArray* newArrayCopy ( const ValueInternalArray& other ) { return new ValueInternalArray ( other ); } virtual void destructArray ( ValueInternalArray* array ) { delete array; } virtual void reallocateArrayPageIndex ( Value**& indexes, ValueInternalArray::PageIndex& indexCount, ValueInternalArray::PageIndex minNewIndexCount ) { ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1; if ( minNewIndexCount > newIndexCount ) newIndexCount = minNewIndexCount; void* newIndexes = realloc ( indexes, sizeof (Value*) * newIndexCount ); if ( !newIndexes ) throw std::bad_alloc (); indexCount = newIndexCount; indexes = static_cast ( newIndexes ); } virtual void releaseArrayPageIndex ( Value** indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free ( indexes ); } virtual Value* allocateArrayPage () { return static_cast ( malloc ( sizeof (Value) * ValueInternalArray::itemsPerPage ) ); } virtual void releaseArrayPage ( Value* value ) { if ( value ) free ( value ); } }; #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR /// @todo make this thread-safe (lock when accessign batch allocator) class DefaultValueArrayAllocator : public ValueArrayAllocator { public: // overridden from ValueArrayAllocator virtual ~DefaultValueArrayAllocator () { } virtual ValueInternalArray* newArray () { ValueInternalArray* array = arraysAllocator_.allocate (); new (array) ValueInternalArray (); // placement new return array; } virtual ValueInternalArray* newArrayCopy ( const ValueInternalArray& other ) { ValueInternalArray* array = arraysAllocator_.allocate (); new (array) ValueInternalArray ( other ); // placement new return array; } virtual void destructArray ( ValueInternalArray* array ) { if ( array ) { array->~ValueInternalArray (); arraysAllocator_.release ( array ); } } virtual void reallocateArrayPageIndex ( Value**& indexes, ValueInternalArray::PageIndex& indexCount, ValueInternalArray::PageIndex minNewIndexCount ) { ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1; if ( minNewIndexCount > newIndexCount ) newIndexCount = minNewIndexCount; void* newIndexes = realloc ( indexes, sizeof (Value*) * newIndexCount ); if ( !newIndexes ) throw std::bad_alloc (); indexCount = newIndexCount; indexes = static_cast ( newIndexes ); } virtual void releaseArrayPageIndex ( Value** indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free ( indexes ); } virtual Value* allocateArrayPage () { return static_cast ( pagesAllocator_.allocate () ); } virtual void releaseArrayPage ( Value* value ) { if ( value ) pagesAllocator_.release ( value ); } private: BatchAllocator arraysAllocator_; BatchAllocator pagesAllocator_; }; #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR static ValueArrayAllocator*& arrayAllocator () { static DefaultValueArrayAllocator defaultAllocator; static ValueArrayAllocator* arrayAllocator = &defaultAllocator; return arrayAllocator; } static struct DummyArrayAllocatorInitializer { DummyArrayAllocatorInitializer () { arrayAllocator (); // ensure arrayAllocator() statics are initialized before main(). } } dummyArrayAllocatorInitializer; // ////////////////////////////////////////////////////////////////// // class ValueInternalArray // ////////////////////////////////////////////////////////////////// bool ValueInternalArray::equals ( const IteratorState& x, const IteratorState& other ) { return x.array_ == other.array_ && x.currentItemIndex_ == other.currentItemIndex_ && x.currentPageIndex_ == other.currentPageIndex_; } void ValueInternalArray::increment ( IteratorState& it ) { JSON_ASSERT_MESSAGE ( it.array_ && (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ != it.array_->size_, "ValueInternalArray::increment(): moving iterator beyond end" ); ++ (it.currentItemIndex_); if ( it.currentItemIndex_ == itemsPerPage ) { it.currentItemIndex_ = 0; ++ (it.currentPageIndex_); } } void ValueInternalArray::decrement ( IteratorState& it ) { JSON_ASSERT_MESSAGE ( it.array_ && it.currentPageIndex_ == it.array_->pages_ && it.currentItemIndex_ == 0, "ValueInternalArray::decrement(): moving iterator beyond end" ); if ( it.currentItemIndex_ == 0 ) { it.currentItemIndex_ = itemsPerPage - 1; -- (it.currentPageIndex_); } else { -- (it.currentItemIndex_); } } Value& ValueInternalArray::unsafeDereference ( const IteratorState& it ) { return (* (it.currentPageIndex_))[it.currentItemIndex_]; } Value& ValueInternalArray::dereference ( const IteratorState& it ) { JSON_ASSERT_MESSAGE ( it.array_ && (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ < it.array_->size_, "ValueInternalArray::dereference(): dereferencing invalid iterator" ); return unsafeDereference ( it ); } void ValueInternalArray::makeBeginIterator ( IteratorState& it ) const { it.array_ = const_cast ( this ); it.currentItemIndex_ = 0; it.currentPageIndex_ = pages_; } void ValueInternalArray::makeIterator ( IteratorState& it, ArrayIndex index ) const { it.array_ = const_cast ( this ); it.currentItemIndex_ = index % itemsPerPage; it.currentPageIndex_ = pages_ + index / itemsPerPage; } void ValueInternalArray::makeEndIterator ( IteratorState& it ) const { makeIterator ( it, size_ ); } ValueInternalArray::ValueInternalArray () : pages_ ( 0 ) , size_ ( 0 ) , pageCount_ ( 0 ) { } ValueInternalArray::ValueInternalArray ( const ValueInternalArray& other ) : pages_ ( 0 ) , pageCount_ ( 0 ) , size_ ( other.size_ ) { PageIndex minNewPages = other.size_ / itemsPerPage; arrayAllocator ()->reallocateArrayPageIndex ( pages_, pageCount_, minNewPages ); JSON_ASSERT_MESSAGE ( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); IteratorState itOther; other.makeBeginIterator ( itOther ); Value* value; for ( ArrayIndex index = 0; index < size_; ++index, increment (itOther) ) { if ( index % itemsPerPage == 0 ) { PageIndex pageIndex = index / itemsPerPage; value = arrayAllocator ()->allocateArrayPage (); pages_[pageIndex] = value; } new (value) Value ( dereference ( itOther ) ); } } ValueInternalArray& ValueInternalArray::operator = ( const ValueInternalArray& other ) { ValueInternalArray temp ( other ); swap ( temp ); return *this; } ValueInternalArray::~ValueInternalArray () { // destroy all constructed items IteratorState it; IteratorState itEnd; makeBeginIterator ( it); makeEndIterator ( itEnd ); for ( ; !equals (it, itEnd); increment (it) ) { Value* value = &dereference (it); value->~Value (); } // release all pages PageIndex lastPageIndex = size_ / itemsPerPage; for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) arrayAllocator ()->releaseArrayPage ( pages_[pageIndex] ); // release pages index arrayAllocator ()->releaseArrayPageIndex ( pages_, pageCount_ ); } void ValueInternalArray::swap ( ValueInternalArray& other ) { Value** tempPages = pages_; pages_ = other.pages_; other.pages_ = tempPages; ArrayIndex tempSize = size_; size_ = other.size_; other.size_ = tempSize; PageIndex tempPageCount = pageCount_; pageCount_ = other.pageCount_; other.pageCount_ = tempPageCount; } void ValueInternalArray::clear () { ValueInternalArray dummy; swap ( dummy ); } void ValueInternalArray::resize ( ArrayIndex newSize ) { if ( newSize == 0 ) clear (); else if ( newSize < size_ ) { IteratorState it; IteratorState itEnd; makeIterator ( it, newSize ); makeIterator ( itEnd, size_ ); for ( ; !equals (it, itEnd); increment (it) ) { Value* value = &dereference (it); value->~Value (); } PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; PageIndex lastPageIndex = size_ / itemsPerPage; for ( ; pageIndex < lastPageIndex; ++pageIndex ) arrayAllocator ()->releaseArrayPage ( pages_[pageIndex] ); size_ = newSize; } else if ( newSize > size_ ) resolveReference ( newSize ); } void ValueInternalArray::makeIndexValid ( ArrayIndex index ) { // Need to enlarge page index ? if ( index >= pageCount_ * itemsPerPage ) { PageIndex minNewPages = (index + 1) / itemsPerPage; arrayAllocator ()->reallocateArrayPageIndex ( pages_, pageCount_, minNewPages ); JSON_ASSERT_MESSAGE ( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); } // Need to allocate new pages ? ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0 ? size_ - (size_ % itemsPerPage) + itemsPerPage : size_; if ( nextPageIndex <= index ) { PageIndex pageIndex = nextPageIndex / itemsPerPage; PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; for ( ; pageToAllocate-- > 0; ++pageIndex ) pages_[pageIndex] = arrayAllocator ()->allocateArrayPage (); } // Initialize all new entries IteratorState it; IteratorState itEnd; makeIterator ( it, size_ ); size_ = index + 1; makeIterator ( itEnd, size_ ); for ( ; !equals (it, itEnd); increment (it) ) { Value* value = &dereference (it); new (value) Value (); // Construct a default value using placement new } } Value& ValueInternalArray::resolveReference ( ArrayIndex index ) { if ( index >= size_ ) makeIndexValid ( index ); return pages_[index / itemsPerPage][index % itemsPerPage]; } Value* ValueInternalArray::find ( ArrayIndex index ) const { if ( index >= size_ ) return 0; return & (pages_[index / itemsPerPage][index % itemsPerPage]); } ValueInternalArray::ArrayIndex ValueInternalArray::size () const { return size_; } int ValueInternalArray::distance ( const IteratorState& x, const IteratorState& y ) { return indexOf (y) - indexOf (x); } ValueInternalArray::ArrayIndex ValueInternalArray::indexOf ( const IteratorState& iterator ) { if ( !iterator.array_ ) return ArrayIndex (-1); return ArrayIndex ( (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage + iterator.currentItemIndex_ ); } int ValueInternalArray::compare ( const ValueInternalArray& other ) const { int sizeDiff ( size_ - other.size_ ); if ( sizeDiff != 0 ) return sizeDiff; for ( ArrayIndex index = 0; index < size_; ++index ) { int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare ( other.pages_[index / itemsPerPage][index % itemsPerPage] ); if ( diff != 0 ) return diff; } return 0; }