forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			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;
 | 
						|
}
 |