449 lines
12 KiB
C++
449 lines
12 KiB
C++
// 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;
|
|
}
|