Files
rippled/modules/ripple_basics/json/json_internalarray.inl
2013-09-01 12:21:58 -07:00

485 lines
13 KiB
C++

//------------------------------------------------------------------------------
/*
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<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;
}