summaryrefslogtreecommitdiffstats
path: root/lib/jsoncpp/src/lib_json/json_internalarray.inl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/jsoncpp/src/lib_json/json_internalarray.inl')
-rw-r--r--lib/jsoncpp/src/lib_json/json_internalarray.inl448
1 files changed, 448 insertions, 0 deletions
diff --git a/lib/jsoncpp/src/lib_json/json_internalarray.inl b/lib/jsoncpp/src/lib_json/json_internalarray.inl
new file mode 100644
index 000000000..9b985d258
--- /dev/null
+++ b/lib/jsoncpp/src/lib_json/json_internalarray.inl
@@ -0,0 +1,448 @@
+// 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;
+}