[Cppunit-cvs] cppunit2/src/cpptl deque.cpp, NONE, 1.1 json_batchallocator.h, NONE, 1.1 json_interna
Brought to you by:
blep
From: Baptiste L. <bl...@us...> - 2006-09-01 19:59:52
|
Update of /cvsroot/cppunit/cppunit2/src/cpptl In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv27173/src/cpptl Added Files: deque.cpp json_batchallocator.h json_internalarray.inl json_internalmap.inl json_valueiterator.inl Log Message: - synchronized with lastest jsoncpp. --- NEW FILE: json_batchallocator.h --- #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED # define JSONCPP_BATCHALLOCATOR_H_INCLUDED # include <stdlib.h> # include <assert.h> # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION namespace Json { /* Fast memory allocator. * * This memory allocator allocates memory for a batch of object (specified by * the page size, the number of object in each page). * * It does not allow the destruction of a single object. All the allocated objects * can be destroyed at once. The memory can be either released or reused for future * allocation. * * The in-place new operator must be used to construct the object using the pointer * returned by allocate. */ template<typename AllocatedType ,const unsigned int objectPerAllocation> class BatchAllocator { public: typedef AllocatedType Type; BatchAllocator( unsigned int objectsPerPage = 255 ) : freeHead_( 0 ) , objectsPerPage_( objectsPerPage ) { // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. assert( objectsPerPage >= 16 ); batches_ = allocateBatch( 0 ); // allocated a dummy page currentBatch_ = batches_; } ~BatchAllocator() { for ( BatchInfo *batch = batches_; batch; ) { BatchInfo *nextBatch = batch->next_; free( batch ); batch = nextBatch; } } /// allocate space for an array of objectPerAllocation object. /// @warning it is the responsability of the caller to call objects constructors. AllocatedType *allocate() { if ( freeHead_ ) // returns node from free list. { AllocatedType *object = freeHead_; freeHead_ = *(AllocatedType **)object; return object; } if ( currentBatch_->used_ == currentBatch_->end_ ) { currentBatch_ = currentBatch_->next_; while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) currentBatch_ = currentBatch_->next_; if ( !currentBatch_ ) // no free batch found, allocate a new one { currentBatch_ = allocateBatch( objectsPerPage_ ); currentBatch_->next_ = batches_; // insert at the head of the list batches_ = currentBatch_; } } AllocatedType *allocated = currentBatch_->used_; currentBatch_->used_ += objectPerAllocation; return allocated; } /// Release the object. /// @warning it is the responsability of the caller to actually destruct the object. void release( AllocatedType *object ) { assert( object != 0 ); *(AllocatedType **)object = freeHead_; freeHead_ = object; } private: struct BatchInfo { BatchInfo *next_; AllocatedType *used_; AllocatedType *end_; AllocatedType buffer_[objectPerAllocation]; }; // disabled copy constructor and assignement operator. BatchAllocator( const BatchAllocator & ); void operator =( const BatchAllocator &); static BatchInfo *allocateBatch( unsigned int objectsPerPage ) { const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); batch->next_ = 0; batch->used_ = batch->buffer_; batch->end_ = batch->buffer_ + objectsPerPage; return batch; } BatchInfo *batches_; BatchInfo *currentBatch_; /// Head of a single linked list within the allocated space of freeed object AllocatedType *freeHead_; unsigned int objectsPerPage_; }; } // namespace Json # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED --- NEW FILE: json_internalarray.inl --- // 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<Value **>( newIndexes ); } virtual void releaseArrayPageIndex( Value **indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free( indexes ); } virtual Value *allocateArrayPage() { return static_cast<Value *>( 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<Value **>( newIndexes ); } virtual void releaseArrayPageIndex( Value **indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free( indexes ); } virtual Value *allocateArrayPage() { return static_cast<Value *>( pagesAllocator_.allocate() ); } virtual void releaseArrayPage( Value *value ) { if ( value ) pagesAllocator_.release( value ); } private: BatchAllocator<ValueInternalArray,1> arraysAllocator_; BatchAllocator<Value,ValueInternalArray::itemsPerPage> 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<ValueInternalArray *>( this ); it.currentItemIndex_ = 0; it.currentPageIndex_ = pages_; } void ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const { it.array_ = const_cast<ValueInternalArray *>( 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; } --- NEW FILE: deque.cpp --- #include <cpptl/deque.h> namespace CppTL { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class DequeBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// DequeBase::DequeBase() { initialize(); } DequeBase::~DequeBase() { delete [] pageMapBuffer_; } void DequeBase::initialize() { pageMapBuffer_ = 0; pageMap_ = 0; pageMapBufferSize_ = 0; usedPages_ = 0; firstPageStartIndex_ = 0; lastPageEndIndex_ = 0; } void DequeBase::swap( DequeBase &other ) { CppTL::swap( pageMapBuffer_, other.pageMapBuffer_ ); CppTL::swap( pageMap_, other.pageMap_ ); CppTL::swap( pageMapBufferSize_, other.pageMapBufferSize_ ); CppTL::swap( usedPages_, other.usedPages_ ); CppTL::swap( firstPageStartIndex_, other.firstPageStartIndex_ ); CppTL::swap( lastPageEndIndex_, other.lastPageEndIndex_ ); } void DequeBase::prependPage( void *newPage ) { growPageMap( 1, 0 ); CPPTL_ASSERT_MESSAGE( pageMap_ > pageMapBuffer_, "DequeBase::growPageMap(): logic bug" ); *--pageMap_ = newPage; ++usedPages_; } void DequeBase::appendPage( void *newPage ) { growPageMap( 0, 1 ); CPPTL_ASSERT_MESSAGE( usedPages_ < pageMapBufferSize_, "DequeBase::growPageMap(): logic bug" ); pageMap_[ usedPages_++ ] = newPage; } void DequeBase::growPageMap( size_t pagesToPrepend, size_t pagesToAppend ) { size_t minNewSize = usedPages_ + pagesToPrepend + pagesToAppend; size_t maxAvailableFront = pageMap_ - pageMapBuffer_; size_t maxAvailableBack = pageMapBufferSize_ - usedPages_; if ( minNewSize > pageMapBufferSize_ || maxAvailableFront < pagesToPrepend || maxAvailableBack < pagesToAppend ) // not enough space, need to realloc { const size_t minGrowth = 32; size_t baseSize = CPPTL_MAX( minNewSize, pageMapBufferSize_ + minGrowth ); size_t newSize = baseSize/2 + baseSize; void **oldBuffer = pageMapBuffer_; typedef void *VoidPtr; pageMapBuffer_ = new VoidPtr[pageMapBufferSize_]; // may throw if not enough memory delete [] oldBuffer; pageMapBufferSize_ = newSize; size_t zeroIndex = (pageMapBufferSize_ - minNewSize) / 2; pageMap_ = pageMapBuffer_ + sizeof(void*) * zeroIndex; memmove( pageMap_, pageMapBuffer_ + sizeof(void*) * maxAvailableFront, sizeof(void*) * usedPages_ ); } } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class DequeIteratorCommonBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// DequeIteratorCommonBase::DequeIteratorCommonBase() : pageMapBegin_( 0 ) , pageMapEnd_( 0 ) , pageMapCurrent_( 0 ) , indexInCurrentPage_( 0 ) , firstPageStartIndex_( 0 ) , lastPageStartIndex_( 0 ) { } DequeIteratorCommonBase::DequeIteratorCommonBase( void **pageMapBegin, void **pageMapEnd, void **pageMapCurrent, size_t indexInCurrentPage, size_t firstPageStartIndex, size_t lastPageStartIndex ) : pageMapBegin_( pageMapBegin ) , pageMapEnd_( pageMapEnd ) , pageMapCurrent_( pageMapCurrent ) , indexInCurrentPage_( indexInCurrentPage ) , firstPageStartIndex_( firstPageStartIndex ) , lastPageStartIndex_( lastPageStartIndex ) { } void DequeIteratorCommonBase::increment() { CPPTL_ASSERT_MESSAGE( pageMapCurrent_ != pageMapEnd_ || indexInCurrentPage_ != lastPageStartIndex_, "DequeIterator: incrementing beyond end" ); ++indexInCurrentPage_; if ( indexInCurrentPage_ == elementPerPage ) { ++pageMapCurrent_; indexInCurrentPage_ = 0; } } void DequeIteratorCommonBase::decrement() { CPPTL_ASSERT_MESSAGE( pageMapCurrent_ != pageMapBegin_ || indexInCurrentPage_ != firstPageStartIndex_, "DequeIterator: decrementing beyond beginning" ); if ( indexInCurrentPage_ == 0 ) { --pageMapCurrent_; indexInCurrentPage_ = elementPerPage - 1; } else { --indexInCurrentPage_; } } void DequeIteratorCommonBase::advance( difference_type n ) { if ( n > 0 ) { n += indexInCurrentPage_; size_t inPageAdvance = n % elementPerPage; size_t fullPageAdvance = n / elementPerPage; CPPTL_ASSERT_MESSAGE( pageMapEnd_-pageMapCurrent_ < fullPageAdvance, "DequeIterator: advancing beyond end" ); CPPTL_ASSERT_MESSAGE( pageMapCurrent_ + fullPageAdvance + 1 != pageMapEnd_ || inPageAdvance < lastPageStartIndex_, "DequeIterator: advancing beyond end" ); pageMapCurrent_ += fullPageAdvance; indexInCurrentPage_ = inPageAdvance; } else if ( n < 0 ) { n = indexInCurrentPage_ - n; if ( n >= 0 ) { indexInCurrentPage_ = n; } else { size_t inPageAdvance = -n % elementPerPage; size_t fullPageAdvance = -n / elementPerPage; CPPTL_ASSERT_MESSAGE( pageMapCurrent_-pageMapBegin_ < fullPageAdvance, "DequeIterator: advancing beyond beginning" ); CPPTL_ASSERT_MESSAGE( pageMapCurrent_ - fullPageAdvance == pageMapBegin_ || inPageAdvance >= firstPageStartIndex_, "DequeIterator: advancing beyond beginning" ); pageMapCurrent_ -= fullPageAdvance; indexInCurrentPage_ = inPageAdvance; } } } DequeIteratorCommonBase::difference_type DequeIteratorCommonBase::computeDistance( const DequeIteratorCommonBase &other ) const { difference_type pageDistance = difference_type(pageMapCurrent_ - pageMapBegin_) - difference_type(other.pageMapCurrent_ - other.pageMapBegin_); difference_type indexDistance( indexInCurrentPage_ - other.indexInCurrentPage_ ); return pageDistance * elementPerPage + indexDistance; } DequeIteratorCommonBase::size_t DequeIteratorCommonBase::index() const { return (pageMapCurrent_ - pageMapBegin_) * elementPerPage + indexInCurrentPage_ - firstPageStartIndex_; } } // namespace CppTL --- NEW FILE: json_valueiterator.inl --- // included by json_value.cpp // everything is within Json namespace // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIteratorBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIteratorBase::ValueIteratorBase() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) : current_( current ) { } #else ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) : isArray_( true ) { iterator_.array_ = state; } ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) : isArray_( false ) { iterator_.map_ = state; } #endif Value & ValueIteratorBase::deref() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP return current_->second; #else if ( isArray_ ) return ValueInternalArray::dereference( iterator_.array_ ); return ValueInternalMap::value( iterator_.map_ ); #endif } void ValueIteratorBase::increment() { #ifndef JSON_VALUE_USE_INTERNAL_MAP ++current_; #else if ( isArray_ ) ValueInternalArray::increment( iterator_.array_ ); ValueInternalMap::increment( iterator_.map_ ); #endif } void ValueIteratorBase::decrement() { #ifndef JSON_VALUE_USE_INTERNAL_MAP --current_; #else if ( isArray_ ) ValueInternalArray::decrement( iterator_.array_ ); ValueInternalMap::decrement( iterator_.map_ ); #endif } ValueIteratorBase::difference_type ValueIteratorBase::computeDistance( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP # ifdef JSON_USE_CPPTL_SMALLMAP return current_ - other.current_; # else return difference_type( std::distance( current_, other.current_ ) ); # endif #else if ( isArray_ ) return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); #endif } bool ValueIteratorBase::isEqual( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP return current_ == other.current_; #else if ( isArray_ ) return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); #endif } void ValueIteratorBase::copy( const SelfType &other ) { #ifndef JSON_VALUE_USE_INTERNAL_MAP current_ = other.current_; #else if ( isArray_ ) iterator_.array_ = other.iterator_.array_; iterator_.map_ = other.iterator_.map_; #endif } Value ValueIteratorBase::key() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( czstring.c_str() ) { if ( czstring.isStaticString() ) return Value( StaticString( czstring.c_str() ) ); return Value( czstring.c_str() ); } return Value( czstring.index() ); #else if ( isArray_ ) return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); bool isStatic; const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); if ( isStatic ) return Value( StaticString( memberName ) ); return Value( memberName ); #endif } Value::UInt ValueIteratorBase::index() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( !czstring.c_str() ) return czstring.index(); return Value::UInt( -1 ); #else if ( isArray_ ) return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); return Value::UInt( -1 ); #endif } const char * ValueIteratorBase::memberName() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const char *name = (*current_).first.c_str(); return name ? name : ""; #else if ( !isArray_ ) return ValueInternalMap::key( iterator_.map_ ); return ""; #endif } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueConstIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueConstIterator::ValueConstIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueConstIterator & ValueConstIterator::operator =( const ValueIteratorBase &other ) { copy( other ); return *this; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIterator::ValueIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueIterator::ValueIterator( const ValueConstIterator &other ) : ValueIteratorBase( other ) { } ValueIterator::ValueIterator( const ValueIterator &other ) : ValueIteratorBase( other ) { } ValueIterator & ValueIterator::operator =( const SelfType &other ) { copy( other ); return *this; } --- NEW FILE: json_internalmap.inl --- // included by json_value.cpp // everything is within Json namespace // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueInternalMap // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); * This optimization is used by the fast allocator. */ ValueInternalLink::ValueInternalLink() : previous_( 0 ) , next_( 0 ) { } ValueInternalLink::~ValueInternalLink() { for ( int index =0; index < itemPerLink; ++index ) { if ( !items_[index].isItemAvailable() ) { if ( !items_[index].isMemberNameStatic() ) free( keys_[index] ); } else break; } } ValueMapAllocator::~ValueMapAllocator() { } #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR class DefaultValueMapAllocator : public ValueMapAllocator { public: // overridden from ValueMapAllocator virtual ValueInternalMap *newMap() { return new ValueInternalMap(); } virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) { return new ValueInternalMap( other ); } virtual void destructMap( ValueInternalMap *map ) { delete map; } virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) { return new ValueInternalLink[size]; } virtual void releaseMapBuckets( ValueInternalLink *links ) { delete [] links; } virtual ValueInternalLink *allocateMapLink() { return new ValueInternalLink(); } virtual void releaseMapLink( ValueInternalLink *link ) { delete link; } }; #else /// @todo make this thread-safe (lock when accessign batch allocator) class DefaultValueMapAllocator : public ValueMapAllocator { public: // overridden from ValueMapAllocator virtual ValueInternalMap *newMap() { ValueInternalMap *map = mapsAllocator_.allocate(); new (map) ValueInternalMap(); // placement new return map; } virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) { ValueInternalMap *map = mapsAllocator_.allocate(); new (map) ValueInternalMap( other ); // placement new return map; } virtual void destructMap( ValueInternalMap *map ) { if ( map ) { map->~ValueInternalMap(); mapsAllocator_.release( map ); } } virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) { return new ValueInternalLink[size]; } virtual void releaseMapBuckets( ValueInternalLink *links ) { delete [] links; } virtual ValueInternalLink *allocateMapLink() { ValueInternalLink *link = linksAllocator_.allocate(); memset( link, 0, sizeof(ValueInternalLink) ); return link; } virtual void releaseMapLink( ValueInternalLink *link ) { link->~ValueInternalLink(); linksAllocator_.release( link ); } private: BatchAllocator<ValueInternalMap,1> mapsAllocator_; BatchAllocator<ValueInternalLink,1> linksAllocator_; }; #endif static ValueMapAllocator *&mapAllocator() { static DefaultValueMapAllocator defaultAllocator; static ValueMapAllocator *mapAllocator = &defaultAllocator; return mapAllocator; } static struct DummyMapAllocatorInitializer { DummyMapAllocatorInitializer() { mapAllocator(); // ensure mapAllocator() statics are initialized before main(). } } dummyMapAllocatorInitializer; // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. /* use linked list hash map. buckets array is a container. linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) value have extra state: valid, available, deleted */ ValueInternalMap::ValueInternalMap() : buckets_( 0 ) , tailLink_( 0 ) , bucketsSize_( 0 ) , itemCount_( 0 ) { } ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) : buckets_( 0 ) , tailLink_( 0 ) , bucketsSize_( 0 ) , itemCount_( 0 ) { reserve( other.itemCount_ ); IteratorState it; IteratorState itEnd; other.makeBeginIterator( it ); other.makeEndIterator( itEnd ); for ( ; !equals(it,itEnd); increment(it) ) { bool isStatic; const char *memberName = key( it, isStatic ); const Value &aValue = value( it ); resolveReference(memberName, isStatic) = aValue; } } ValueInternalMap & ValueInternalMap::operator =( const ValueInternalMap &other ) { ValueInternalMap dummy( other ); swap( dummy ); return *this; } ValueInternalMap::~ValueInternalMap() { if ( buckets_ ) { for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) { ValueInternalLink *link = buckets_[bucketIndex].next_; while ( link ) { ValueInternalLink *linkToRelease = link; link = link->next_; mapAllocator()->releaseMapLink( linkToRelease ); } } mapAllocator()->releaseMapBuckets( buckets_ ); } } void ValueInternalMap::swap( ValueInternalMap &other ) { ValueInternalLink *tempBuckets = buckets_; buckets_ = other.buckets_; other.buckets_ = tempBuckets; ValueInternalLink *tempTailLink = tailLink_; tailLink_ = other.tailLink_; other.tailLink_ = tempTailLink; BucketIndex tempBucketsSize = bucketsSize_; bucketsSize_ = other.bucketsSize_; other.bucketsSize_ = tempBucketsSize; BucketIndex tempItemCount = itemCount_; itemCount_ = other.itemCount_; other.itemCount_ = tempItemCount; } void ValueInternalMap::clear() { ValueInternalMap dummy; swap( dummy ); } ValueInternalMap::BucketIndex ValueInternalMap::size() const { return itemCount_; } bool ValueInternalMap::reserveDelta( BucketIndex growth ) { return reserve( itemCount_ + growth ); } bool ValueInternalMap::reserve( BucketIndex newItemCount ) { if ( !buckets_ && newItemCount > 0 ) { buckets_ = mapAllocator()->allocateMapBuckets( 1 ); bucketsSize_ = 1; tailLink_ = &buckets_[0]; } // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; return true; } const Value * ValueInternalMap::find( const char *key ) const { if ( !bucketsSize_ ) return 0; HashKey hashedKey = hash( key ); BucketIndex bucketIndex = hashedKey % bucketsSize_; for ( const ValueInternalLink *current = &buckets_[bucketIndex]; current != 0; current = current->next_ ) { for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) { if ( current->items_[index].isItemAvailable() ) return 0; if ( strcmp( key, current->keys_[index] ) == 0 ) return ¤t->items_[index]; } } return 0; } Value * ValueInternalMap::find( const char *key ) { const ValueInternalMap *constThis = this; return const_cast<Value *>( constThis->find( key ) ); } Value & ValueInternalMap::resolveReference( const char *key, bool isStatic ) { HashKey hashedKey = hash( key ); if ( bucketsSize_ ) { BucketIndex bucketIndex = hashedKey % bucketsSize_; ValueInternalLink **previous = 0; BucketIndex index; for ( ValueInternalLink *current = &buckets_[bucketIndex]; current != 0; previous = ¤t->next_, current = current->next_ ) { for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) { if ( current->items_[index].isItemAvailable() ) return setNewItem( key, isStatic, current, index ); if ( strcmp( key, current->keys_[index] ) == 0 ) return current->items_[index]; } } } reserveDelta( 1 ); return unsafeAdd( key, isStatic, hashedKey ); } void ValueInternalMap::remove( const char *key ) { HashKey hashedKey = hash( key ); if ( !bucketsSize_ ) return; BucketIndex bucketIndex = hashedKey % bucketsSize_; for ( ValueInternalLink *link = &buckets_[bucketIndex]; link != 0; link = link->next_ ) { BucketIndex index; for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) { if ( link->items_[index].isItemAvailable() ) return; if ( strcmp( key, link->keys_[index] ) == 0 ) { doActualRemove( link, index, bucketIndex ); return; } } } } void ValueInternalMap::doActualRemove( ValueInternalLink *link, BucketIndex index, BucketIndex bucketIndex ) { // find last item of the bucket and swap it with the 'removed' one. // set removed items flags to 'available'. // if last page only contains 'available' items, then desallocate it (it's empty) ValueInternalLink *&lastLink = getLastLinkInBucket( index ); BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 for ( ; lastItemIndex < ValueInternalLink::itemPerLink; ++lastItemIndex ) // may be optimized with dicotomic search { if ( lastLink->items_[lastItemIndex].isItemAvailable() ) break; } BucketIndex lastUsedIndex = lastItemIndex - 1; Value *valueToDelete = &link->items_[index]; Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; if ( valueToDelete != valueToPreserve ) valueToDelete->swap( *valueToPreserve ); if ( lastUsedIndex == 0 ) // page is now empty { // remove it from bucket linked list and delete it. ValueInternalLink *linkPreviousToLast = lastLink->previous_; if ( linkPreviousToLast != 0 ) // can not deleted bucket link. { mapAllocator()->releaseMapLink( lastLink ); linkPreviousToLast->next_ = 0; lastLink = linkPreviousToLast; } } else { Value dummy; valueToPreserve->swap( dummy ); // restore deleted to default Value. valueToPreserve->setItemUsed( false ); } --itemCount_; } ValueInternalLink *& ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) { if ( bucketIndex == bucketsSize_ - 1 ) return tailLink_; ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; if ( !previous ) previous = &buckets_[bucketIndex]; return previous; } Value & ValueInternalMap::setNewItem( const char *key, bool isStatic, ValueInternalLink *link, BucketIndex index ) { char *duplicatedKey = valueAllocator()->makeMemberName( key ); ++itemCount_; link->keys_[index] = duplicatedKey; link->items_[index].setItemUsed(); link->items_[index].setMemberNameIsStatic( isStatic ); return link->items_[index]; // items already default constructed. } Value & ValueInternalMap::unsafeAdd( const char *key, bool isStatic, HashKey hashedKey ) { JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); BucketIndex bucketIndex = hashedKey % bucketsSize_; ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); ValueInternalLink *link = previousLink; BucketIndex index; for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) { if ( link->items_[index].isItemAvailable() ) break; } if ( index == ValueInternalLink::itemPerLink ) // need to add a new page { ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); index = 0; link->next_ = newLink; previousLink = newLink; link = newLink; } return setNewItem( key, isStatic, link, index ); } ValueInternalMap::HashKey ValueInternalMap::hash( const char *key ) const { HashKey hash = 0; while ( *key ) hash += *key++ * 37; return hash; } int ValueInternalMap::compare( const ValueInternalMap &other ) const { int sizeDiff( itemCount_ - other.itemCount_ ); if ( sizeDiff != 0 ) return sizeDiff; // Strict order guaranty is required. Compare all keys FIRST, then compare values. IteratorState it; IteratorState itEnd; makeBeginIterator( it ); makeEndIterator( itEnd ); for ( ; !equals(it,itEnd); increment(it) ) { if ( !other.find( key( it ) ) ) return 1; } // All keys are equals, let's compare values makeBeginIterator( it ); for ( ; !equals(it,itEnd); increment(it) ) { const Value *otherValue = other.find( key( it ) ); int valueDiff = value(it).compare( *otherValue ); if ( valueDiff != 0 ) return valueDiff; } return 0; } void ValueInternalMap::makeBeginIterator( IteratorState &it ) const { it.map_ = const_cast<ValueInternalMap *>( this ); it.bucketIndex_ = 0; it.itemIndex_ = 0; it.link_ = buckets_; } void ValueInternalMap::makeEndIterator( IteratorState &it ) const { it.map_ = const_cast<ValueInternalMap *>( this ); it.bucketIndex_ = bucketsSize_; it.itemIndex_ = 0; it.link_ = 0; } bool ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) { return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ && x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_; } void ValueInternalMap::incrementBucket( IteratorState &iterator ) { ++iterator.bucketIndex_; JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, "ValueInternalMap::increment(): attempting to iterate beyond end." ); if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) iterator.link_ = 0; else iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); iterator.itemIndex_ = 0; } void ValueInternalMap::increment( IteratorState &iterator ) { JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); ++iterator.itemIndex_; if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) { JSON_ASSERT_MESSAGE( iterator.link_ != 0, "ValueInternalMap::increment(): attempting to iterate beyond end." ); iterator.link_ = iterator.link_->next_; if ( iterator.link_ == 0 ) incrementBucket( iterator ); } else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) { incrementBucket( iterator ); } } void ValueInternalMap::decrement( IteratorState &iterator ) { if ( iterator.itemIndex_ == 0 ) { JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) { JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); --(iterator.bucketIndex_); } iterator.link_ = iterator.link_->previous_; iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; } } const char * ValueInternalMap::key( const IteratorState &iterator ) { JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); return iterator.link_->keys_[iterator.itemIndex_]; } const char * ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) { JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); return iterator.link_->keys_[iterator.itemIndex_]; } Value & ValueInternalMap::value( const IteratorState &iterator ) { JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); return iterator.link_->items_[iterator.itemIndex_]; } int ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) { int offset = 0; IteratorState it = x; while ( !equals( it, y ) ) increment( it ); return offset; } |