mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Clean up JSON code:
* Remove obsolete files * Remove obsolete preprocessor configuration tags and decorations * Remove arcane functionality (YAML compatibility, comment support) * Enforce strict mode (single root) * Improve parsing of numerical types * Misc. cleanups
This commit is contained in:
committed by
Tom Ritchford
parent
6d91d02c62
commit
558c6b621b
@@ -2012,12 +2012,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_assert.h">
|
<ClInclude Include="..\..\src\ripple\json\impl\json_assert.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_batchallocator.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_internalarray.inl">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_internalmap.inl">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\json\impl\json_reader.cpp">
|
<ClCompile Include="..\..\src\ripple\json\impl\json_reader.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -2034,10 +2028,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\json\JsonPropertyStream.h">
|
<ClInclude Include="..\..\src\ripple\json\JsonPropertyStream.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_config.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_features.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_forwards.h">
|
<ClInclude Include="..\..\src\ripple\json\json_forwards.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_reader.h">
|
<ClInclude Include="..\..\src\ripple\json\json_reader.h">
|
||||||
|
|||||||
@@ -2952,15 +2952,6 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_assert.h">
|
<ClInclude Include="..\..\src\ripple\json\impl\json_assert.h">
|
||||||
<Filter>ripple\json\impl</Filter>
|
<Filter>ripple\json\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_batchallocator.h">
|
|
||||||
<Filter>ripple\json\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_internalarray.inl">
|
|
||||||
<Filter>ripple\json\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\impl\json_internalmap.inl">
|
|
||||||
<Filter>ripple\json\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\json\impl\json_reader.cpp">
|
<ClCompile Include="..\..\src\ripple\json\impl\json_reader.cpp">
|
||||||
<Filter>ripple\json\impl</Filter>
|
<Filter>ripple\json\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -2979,12 +2970,6 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\json\JsonPropertyStream.h">
|
<ClInclude Include="..\..\src\ripple\json\JsonPropertyStream.h">
|
||||||
<Filter>ripple\json</Filter>
|
<Filter>ripple\json</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_config.h">
|
|
||||||
<Filter>ripple\json</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_features.h">
|
|
||||||
<Filter>ripple\json</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\json\json_forwards.h">
|
<ClInclude Include="..\..\src\ripple\json\json_forwards.h">
|
||||||
<Filter>ripple\json</Filter>
|
<Filter>ripple\json</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -1074,7 +1074,7 @@ bool ApplicationImp::loadOldLedger (
|
|||||||
{
|
{
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
Json::Value jLedger;
|
Json::Value jLedger;
|
||||||
if (!reader.parse (ledgerFile, jLedger, false))
|
if (!reader.parse (ledgerFile, jLedger))
|
||||||
m_journal.fatal << "Unable to parse ledger JSON";
|
m_journal.fatal << "Unable to parse ledger JSON";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#ifndef RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED
|
#ifndef RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED
|
||||||
#define RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED
|
#define RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
#include <beast/utility/PropertyStream.h>
|
#include <beast/utility/PropertyStream.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_JSON_JSON_AUTOLINK_H_INCLUDED
|
|
||||||
#define RIPPLE_JSON_JSON_AUTOLINK_H_INCLUDED
|
|
||||||
|
|
||||||
// VFALCO TODO remove this file
|
|
||||||
#error This file is deprecated!
|
|
||||||
|
|
||||||
# include "config.h"
|
|
||||||
|
|
||||||
# ifdef JSON_IN_CPPTL
|
|
||||||
# include <cpptl/cpptl_autolink.h>
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
|
||||||
# define CPPTL_AUTOLINK_NAME "json"
|
|
||||||
# undef CPPTL_AUTOLINK_DLL
|
|
||||||
# ifdef JSON_DLL
|
|
||||||
# define CPPTL_AUTOLINK_DLL
|
|
||||||
# endif
|
|
||||||
# include "autolink.h"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // JSON_AUTOLINK_H_INCLUDED
|
|
||||||
@@ -20,8 +20,6 @@
|
|||||||
#ifndef RIPPLE_JSON_JSON_BATCHALLOCATOR_H_INCLUDED
|
#ifndef RIPPLE_JSON_JSON_BATCHALLOCATOR_H_INCLUDED
|
||||||
#define RIPPLE_JSON_JSON_BATCHALLOCATOR_H_INCLUDED
|
#define RIPPLE_JSON_JSON_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
namespace Json
|
namespace Json
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -139,7 +137,5 @@ private:
|
|||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
|||||||
@@ -1,497 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,671 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
// 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 ) noexcept
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -20,65 +20,16 @@
|
|||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/json/json_reader.h>
|
#include <ripple/json/json_reader.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
namespace Json
|
namespace Json
|
||||||
{
|
{
|
||||||
|
|
||||||
// Implementation of class Features
|
|
||||||
// ////////////////////////////////
|
|
||||||
|
|
||||||
Features::Features ()
|
|
||||||
: allowComments_ ( true )
|
|
||||||
, strictRoot_ ( false )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
|
||||||
Features::all ()
|
|
||||||
{
|
|
||||||
return Features ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
|
||||||
Features::strictMode ()
|
|
||||||
{
|
|
||||||
Features features;
|
|
||||||
features.allowComments_ = false;
|
|
||||||
features.strictRoot_ = true;
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of class Reader
|
// Implementation of class Reader
|
||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
static
|
||||||
static inline bool
|
std::string
|
||||||
in ( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
codePointToUTF8 (unsigned int cp)
|
||||||
{
|
|
||||||
return c == c1 || c == c2 || c == c3 || c == c4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
in ( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
|
||||||
{
|
|
||||||
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
containsNewLine ( Reader::Location begin,
|
|
||||||
Reader::Location end )
|
|
||||||
{
|
|
||||||
for ( ; begin < end; ++begin )
|
|
||||||
if ( *begin == '\n' || *begin == '\r' )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string codePointToUTF8 (unsigned int cp)
|
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
@@ -119,33 +70,24 @@ static std::string codePointToUTF8 (unsigned int cp)
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Reader::Reader ()
|
Reader::Reader ()
|
||||||
: features_ ( Features::all () )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Reader::Reader ( const Features& features )
|
|
||||||
: features_ ( features )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::parse ( std::string const& document,
|
Reader::parse ( std::string const& document,
|
||||||
Value& root,
|
Value& root)
|
||||||
bool collectComments )
|
|
||||||
{
|
{
|
||||||
document_ = document;
|
document_ = document;
|
||||||
const char* begin = document_.c_str ();
|
const char* begin = document_.c_str ();
|
||||||
const char* end = begin + document_.length ();
|
const char* end = begin + document_.length ();
|
||||||
return parse ( begin, end, root, collectComments );
|
return parse ( begin, end, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::parse ( std::istream& sin,
|
Reader::parse ( std::istream& sin,
|
||||||
Value& root,
|
Value& root)
|
||||||
bool collectComments )
|
|
||||||
{
|
{
|
||||||
//std::istream_iterator<char> begin(sin);
|
//std::istream_iterator<char> begin(sin);
|
||||||
//std::istream_iterator<char> end;
|
//std::istream_iterator<char> end;
|
||||||
@@ -156,26 +98,18 @@ Reader::parse ( std::istream& sin,
|
|||||||
// create an extra copy.
|
// create an extra copy.
|
||||||
std::string doc;
|
std::string doc;
|
||||||
std::getline (sin, doc, (char)EOF);
|
std::getline (sin, doc, (char)EOF);
|
||||||
return parse ( doc, root, collectComments );
|
return parse ( doc, root );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::parse ( const char* beginDoc, const char* endDoc,
|
Reader::parse ( const char* beginDoc, const char* endDoc,
|
||||||
Value& root,
|
Value& root)
|
||||||
bool collectComments )
|
|
||||||
{
|
{
|
||||||
if ( !features_.allowComments_ )
|
|
||||||
{
|
|
||||||
collectComments = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
begin_ = beginDoc;
|
begin_ = beginDoc;
|
||||||
end_ = endDoc;
|
end_ = endDoc;
|
||||||
collectComments_ = collectComments;
|
|
||||||
current_ = begin_;
|
current_ = begin_;
|
||||||
lastValueEnd_ = 0;
|
lastValueEnd_ = 0;
|
||||||
lastValue_ = 0;
|
lastValue_ = 0;
|
||||||
commentsBefore_ = "";
|
|
||||||
errors_.clear ();
|
errors_.clear ();
|
||||||
|
|
||||||
while ( !nodes_.empty () )
|
while ( !nodes_.empty () )
|
||||||
@@ -187,11 +121,6 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
|
|||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens ( token );
|
skipCommentTokens ( token );
|
||||||
|
|
||||||
if ( collectComments_ && !commentsBefore_.empty () )
|
|
||||||
root.setComment ( commentsBefore_, commentAfter );
|
|
||||||
|
|
||||||
if ( features_.strictRoot_ )
|
|
||||||
{
|
|
||||||
if ( !root.isArray () && !root.isObject () )
|
if ( !root.isArray () && !root.isObject () )
|
||||||
{
|
{
|
||||||
// Set error location to start of doc, ideally should be first token found in doc
|
// Set error location to start of doc, ideally should be first token found in doc
|
||||||
@@ -202,12 +131,10 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
|
|||||||
token );
|
token );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readValue ()
|
Reader::readValue ()
|
||||||
{
|
{
|
||||||
@@ -215,13 +142,6 @@ Reader::readValue ()
|
|||||||
skipCommentTokens ( token );
|
skipCommentTokens ( token );
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
if ( collectComments_ && !commentsBefore_.empty () )
|
|
||||||
{
|
|
||||||
currentValue ().setComment ( commentsBefore_, commentBefore );
|
|
||||||
commentsBefore_ = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch ( token.type_ )
|
switch ( token.type_ )
|
||||||
{
|
{
|
||||||
case tokenObjectBegin:
|
case tokenObjectBegin:
|
||||||
@@ -232,10 +152,14 @@ Reader::readValue ()
|
|||||||
successful = readArray ( token );
|
successful = readArray ( token );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tokenNumber:
|
case tokenInteger:
|
||||||
successful = decodeNumber ( token );
|
successful = decodeNumber ( token );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case tokenDouble:
|
||||||
|
successful = decodeDouble ( token );
|
||||||
|
break;
|
||||||
|
|
||||||
case tokenString:
|
case tokenString:
|
||||||
successful = decodeString ( token );
|
successful = decodeString ( token );
|
||||||
break;
|
break;
|
||||||
@@ -256,12 +180,6 @@ Reader::readValue ()
|
|||||||
return addError ( "Syntax error: value, object or array expected.", token );
|
return addError ( "Syntax error: value, object or array expected.", token );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( collectComments_ )
|
|
||||||
{
|
|
||||||
lastValueEnd_ = current_;
|
|
||||||
lastValue_ = ¤tValue ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,18 +187,11 @@ Reader::readValue ()
|
|||||||
void
|
void
|
||||||
Reader::skipCommentTokens ( Token& token )
|
Reader::skipCommentTokens ( Token& token )
|
||||||
{
|
{
|
||||||
if ( features_.allowComments_ )
|
|
||||||
{
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
readToken ( token );
|
readToken ( token );
|
||||||
}
|
}
|
||||||
while ( token.type_ == tokenComment );
|
while ( token.type_ == tokenComment );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
readToken ( token );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -343,8 +254,7 @@ Reader::readToken ( Token& token )
|
|||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
case '-':
|
case '-':
|
||||||
token.type_ = tokenNumber;
|
token.type_ = readNumber ();
|
||||||
readNumber ();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
@@ -423,57 +333,17 @@ Reader::match ( Location pattern,
|
|||||||
bool
|
bool
|
||||||
Reader::readComment ()
|
Reader::readComment ()
|
||||||
{
|
{
|
||||||
Location commentBegin = current_ - 1;
|
|
||||||
Char c = getNextChar ();
|
Char c = getNextChar ();
|
||||||
bool successful = false;
|
|
||||||
|
|
||||||
if ( c == '*' )
|
if ( c == '*' )
|
||||||
successful = readCStyleComment ();
|
return readCStyleComment ();
|
||||||
else if ( c == '/' )
|
|
||||||
successful = readCppStyleComment ();
|
if ( c == '/' )
|
||||||
|
return readCppStyleComment ();
|
||||||
|
|
||||||
if ( !successful )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( collectComments_ )
|
|
||||||
{
|
|
||||||
CommentPlacement placement = commentBefore;
|
|
||||||
|
|
||||||
if ( lastValueEnd_ && !containsNewLine ( lastValueEnd_, commentBegin ) )
|
|
||||||
{
|
|
||||||
if ( c != '*' || !containsNewLine ( commentBegin, current_ ) )
|
|
||||||
placement = commentAfterOnSameLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
addComment ( commentBegin, current_, placement );
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Reader::addComment ( Location begin,
|
|
||||||
Location end,
|
|
||||||
CommentPlacement placement )
|
|
||||||
{
|
|
||||||
assert ( collectComments_ );
|
|
||||||
|
|
||||||
if ( placement == commentAfterOnSameLine )
|
|
||||||
{
|
|
||||||
assert ( lastValue_ != 0 );
|
|
||||||
lastValue_->setComment ( std::string ( begin, end ), placement );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( !commentsBefore_.empty () )
|
|
||||||
commentsBefore_ += "\n";
|
|
||||||
|
|
||||||
commentsBefore_ += std::string ( begin, end );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readCStyleComment ()
|
Reader::readCStyleComment ()
|
||||||
{
|
{
|
||||||
@@ -503,18 +373,36 @@ Reader::readCppStyleComment ()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reader::TokenType
|
||||||
void
|
|
||||||
Reader::readNumber ()
|
Reader::readNumber ()
|
||||||
{
|
{
|
||||||
|
static char const extended_tokens[] = { '.', 'e', 'E', '+', '-' };
|
||||||
|
|
||||||
|
TokenType type = tokenInteger;
|
||||||
|
|
||||||
|
if ( current_ != end_ )
|
||||||
|
{
|
||||||
|
if (*current_ == '-')
|
||||||
|
++current_;
|
||||||
|
|
||||||
while ( current_ != end_ )
|
while ( current_ != end_ )
|
||||||
{
|
{
|
||||||
if ( ! (*current_ >= '0' && *current_ <= '9') &&
|
if (!std::isdigit (*current_))
|
||||||
!in ( *current_, '.', 'e', 'E', '+', '-' ) )
|
{
|
||||||
|
auto ret = std::find (std::begin (extended_tokens),
|
||||||
|
std::end (extended_tokens), *current_);
|
||||||
|
|
||||||
|
if (ret == std::end (extended_tokens))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
type = tokenDouble;
|
||||||
|
}
|
||||||
|
|
||||||
++current_;
|
++current_;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -664,28 +552,29 @@ Reader::readArray ( Token& tokenStart )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
in ( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||||
|
{
|
||||||
|
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::decodeNumber ( Token& token )
|
Reader::decodeNumber ( Token& token )
|
||||||
{
|
{
|
||||||
bool isDouble = false;
|
|
||||||
|
|
||||||
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
|
||||||
{
|
|
||||||
isDouble = isDouble
|
|
||||||
|| in ( *inspect, '.', 'e', 'E', '+' )
|
|
||||||
|| ( *inspect == '-' && inspect != token.start_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isDouble )
|
|
||||||
return decodeDouble ( token );
|
|
||||||
|
|
||||||
Location current = token.start_;
|
Location current = token.start_;
|
||||||
bool isNegative = *current == '-';
|
bool isNegative = *current == '-';
|
||||||
|
|
||||||
if ( isNegative )
|
if ( isNegative )
|
||||||
++current;
|
++current;
|
||||||
|
|
||||||
|
if (current == token.end_)
|
||||||
|
{
|
||||||
|
return addError ( "'" + std::string ( token.start_, token.end_ ) +
|
||||||
|
"' is not a valid number.", token );
|
||||||
|
}
|
||||||
|
|
||||||
|
// The existing Json integers are 32-bit so using a 64-bit value here avoids
|
||||||
|
// overflows in the conversion code below.
|
||||||
std::int64_t value = 0;
|
std::int64_t value = 0;
|
||||||
|
|
||||||
static_assert(sizeof(value) > sizeof(Value::maxUInt),
|
static_assert(sizeof(value) > sizeof(Value::maxUInt),
|
||||||
@@ -1063,7 +952,7 @@ Reader::getFormatedErrorMessages () const
|
|||||||
std::istream& operator>> ( std::istream& sin, Value& root )
|
std::istream& operator>> ( std::istream& sin, Value& root )
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
bool ok = reader.parse (sin, root, true);
|
bool ok = reader.parse (sin, root);
|
||||||
|
|
||||||
//JSON_ASSERT( ok );
|
//JSON_ASSERT( ok );
|
||||||
if (!ok) throw std::runtime_error (reader.getFormatedErrorMessages ());
|
if (!ok) throw std::runtime_error (reader.getFormatedErrorMessages ());
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,95 +30,41 @@
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase ()
|
ValueIteratorBase::ValueIteratorBase ()
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
: current_ ()
|
: current_ ()
|
||||||
, isNull_ ( true )
|
, isNull_ ( true )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
:
|
|
||||||
isArray_ ( true )
|
|
||||||
, isNull_ ( true )
|
|
||||||
{
|
|
||||||
iterator_.array_ = ValueInternalArray::IteratorState ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueIteratorBase::ValueIteratorBase ( const Value::ObjectValues::iterator& current )
|
ValueIteratorBase::ValueIteratorBase ( const Value::ObjectValues::iterator& current )
|
||||||
: current_ ( current )
|
: current_ ( current )
|
||||||
, isNull_ ( false )
|
, isNull_ ( false )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#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&
|
Value&
|
||||||
ValueIteratorBase::deref () const
|
ValueIteratorBase::deref () const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
return current_->second;
|
return current_->second;
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
return ValueInternalArray::dereference ( iterator_.array_ );
|
|
||||||
|
|
||||||
return ValueInternalMap::value ( iterator_.map_ );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ValueIteratorBase::increment ()
|
ValueIteratorBase::increment ()
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
++current_;
|
++current_;
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
ValueInternalArray::increment ( iterator_.array_ );
|
|
||||||
|
|
||||||
ValueInternalMap::increment ( iterator_.map_ );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ValueIteratorBase::decrement ()
|
ValueIteratorBase::decrement ()
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
--current_;
|
--current_;
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
ValueInternalArray::decrement ( iterator_.array_ );
|
|
||||||
|
|
||||||
ValueInternalMap::decrement ( iterator_.map_ );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ValueIteratorBase::difference_type
|
ValueIteratorBase::difference_type
|
||||||
ValueIteratorBase::computeDistance ( const SelfType& other ) const
|
ValueIteratorBase::computeDistance ( const SelfType& other ) const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
# ifdef JSON_USE_CPPTL_SMALLMAP
|
|
||||||
return current_ - other.current_;
|
|
||||||
# else
|
|
||||||
|
|
||||||
// Iterator for null value are initialized using the default
|
// Iterator for null value are initialized using the default
|
||||||
// constructor, which initialize current_ to the default
|
// constructor, which initialize current_ to the default
|
||||||
// std::map::iterator. As begin() and end() are two instance
|
// std::map::iterator. As begin() and end() are two instance
|
||||||
@@ -142,57 +88,31 @@ ValueIteratorBase::computeDistance ( const SelfType& other ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
return myDistance;
|
return myDistance;
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
return ValueInternalArray::distance ( iterator_.array_, other.iterator_.array_ );
|
|
||||||
|
|
||||||
return ValueInternalMap::distance ( iterator_.map_, other.iterator_.map_ );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ValueIteratorBase::isEqual ( const SelfType& other ) const
|
ValueIteratorBase::isEqual ( const SelfType& other ) const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
if ( isNull_ )
|
if ( isNull_ )
|
||||||
{
|
{
|
||||||
return other.isNull_;
|
return other.isNull_;
|
||||||
}
|
}
|
||||||
|
|
||||||
return current_ == other.current_;
|
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
|
void
|
||||||
ValueIteratorBase::copy ( const SelfType& other )
|
ValueIteratorBase::copy ( const SelfType& other )
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
current_ = other.current_;
|
current_ = other.current_;
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
iterator_.array_ = other.iterator_.array_;
|
|
||||||
|
|
||||||
iterator_.map_ = other.iterator_.map_;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value
|
Value
|
||||||
ValueIteratorBase::key () const
|
ValueIteratorBase::key () const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
|
||||||
if ( czstring.c_str () )
|
if ( czstring.c_str () )
|
||||||
@@ -204,55 +124,26 @@ ValueIteratorBase::key () const
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Value ( czstring.index () );
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UInt
|
UInt
|
||||||
ValueIteratorBase::index () const
|
ValueIteratorBase::index () const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
|
||||||
if ( !czstring.c_str () )
|
if ( !czstring.c_str () )
|
||||||
return czstring.index ();
|
return czstring.index ();
|
||||||
|
|
||||||
return Value::UInt ( -1 );
|
return Value::UInt ( -1 );
|
||||||
#else
|
|
||||||
|
|
||||||
if ( isArray_ )
|
|
||||||
return Value::UInt ( ValueInternalArray::indexOf ( iterator_.array_ ) );
|
|
||||||
|
|
||||||
return Value::UInt ( -1 );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
ValueIteratorBase::memberName () const
|
ValueIteratorBase::memberName () const
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const char* name = (*current_).first.c_str ();
|
const char* name = (*current_).first.c_str ();
|
||||||
return name ? name : "";
|
return name ? name : "";
|
||||||
#else
|
|
||||||
|
|
||||||
if ( !isArray_ )
|
|
||||||
return ValueInternalMap::key ( iterator_.map_ );
|
|
||||||
|
|
||||||
return "";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -268,23 +159,10 @@ ValueConstIterator::ValueConstIterator ()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueConstIterator::ValueConstIterator ( const Value::ObjectValues::iterator& current )
|
ValueConstIterator::ValueConstIterator ( const Value::ObjectValues::iterator& current )
|
||||||
: ValueIteratorBase ( current )
|
: ValueIteratorBase ( current )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
ValueConstIterator::ValueConstIterator ( const ValueInternalArray::IteratorState& state )
|
|
||||||
: ValueIteratorBase ( state )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueConstIterator::ValueConstIterator ( const ValueInternalMap::IteratorState& state )
|
|
||||||
: ValueIteratorBase ( state )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ValueConstIterator&
|
ValueConstIterator&
|
||||||
ValueConstIterator::operator = ( const ValueIteratorBase& other )
|
ValueConstIterator::operator = ( const ValueIteratorBase& other )
|
||||||
@@ -307,22 +185,10 @@ ValueIterator::ValueIterator ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueIterator::ValueIterator ( const Value::ObjectValues::iterator& current )
|
ValueIterator::ValueIterator ( const Value::ObjectValues::iterator& current )
|
||||||
: ValueIteratorBase ( current )
|
: 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 )
|
ValueIterator::ValueIterator ( const ValueConstIterator& other )
|
||||||
: ValueIteratorBase ( other )
|
: ValueIteratorBase ( other )
|
||||||
|
|||||||
@@ -189,18 +189,9 @@ Writer::~Writer ()
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
FastWriter::FastWriter ()
|
FastWriter::FastWriter ()
|
||||||
: yamlCompatiblityEnabled_ ( false )
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FastWriter::enableYAMLCompatibility ()
|
|
||||||
{
|
|
||||||
yamlCompatiblityEnabled_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
FastWriter::write ( const Value& root )
|
FastWriter::write ( const Value& root )
|
||||||
{
|
{
|
||||||
@@ -272,8 +263,7 @@ FastWriter::writeValue ( const Value& value )
|
|||||||
document_ += ",";
|
document_ += ",";
|
||||||
|
|
||||||
document_ += valueToQuotedString ( name.c_str () );
|
document_ += valueToQuotedString ( name.c_str () );
|
||||||
document_ += yamlCompatiblityEnabled_ ? ": "
|
document_ += ":";
|
||||||
: ":";
|
|
||||||
writeValue ( value[name] );
|
writeValue ( value[name] );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,9 +290,7 @@ StyledWriter::write ( const Value& root )
|
|||||||
document_ = "";
|
document_ = "";
|
||||||
addChildValues_ = false;
|
addChildValues_ = false;
|
||||||
indentString_ = "";
|
indentString_ = "";
|
||||||
writeCommentBeforeValue ( root );
|
|
||||||
writeValue ( root );
|
writeValue ( root );
|
||||||
writeCommentAfterValueOnSameLine ( root );
|
|
||||||
document_ += "\n";
|
document_ += "\n";
|
||||||
return document_;
|
return document_;
|
||||||
}
|
}
|
||||||
@@ -357,19 +345,14 @@ StyledWriter::writeValue ( const Value& value )
|
|||||||
{
|
{
|
||||||
std::string const& name = *it;
|
std::string const& name = *it;
|
||||||
const Value& childValue = value[name];
|
const Value& childValue = value[name];
|
||||||
writeCommentBeforeValue ( childValue );
|
|
||||||
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
|
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
|
||||||
document_ += " : ";
|
document_ += " : ";
|
||||||
writeValue ( childValue );
|
writeValue ( childValue );
|
||||||
|
|
||||||
if ( ++it == members.end () )
|
if ( ++it == members.end () )
|
||||||
{
|
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
document_ += ",";
|
document_ += ",";
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unindent ();
|
unindent ();
|
||||||
@@ -402,7 +385,6 @@ StyledWriter::writeArrayValue ( const Value& value )
|
|||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
const Value& childValue = value[index];
|
const Value& childValue = value[index];
|
||||||
writeCommentBeforeValue ( childValue );
|
|
||||||
|
|
||||||
if ( hasChildValue )
|
if ( hasChildValue )
|
||||||
writeWithIndent ( childValues_[index] );
|
writeWithIndent ( childValues_[index] );
|
||||||
@@ -413,13 +395,9 @@ StyledWriter::writeArrayValue ( const Value& value )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( ++index == size )
|
if ( ++index == size )
|
||||||
{
|
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
document_ += ",";
|
document_ += ",";
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unindent ();
|
unindent ();
|
||||||
@@ -465,11 +443,10 @@ StyledWriter::isMultineArray ( const Value& value )
|
|||||||
addChildValues_ = true;
|
addChildValues_ = true;
|
||||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||||
|
|
||||||
for ( int index = 0; index < size && !isMultiLine; ++index )
|
for ( int index = 0; index < size; ++index )
|
||||||
{
|
{
|
||||||
writeValue ( value[index] );
|
writeValue ( value[index] );
|
||||||
lineLength += int ( childValues_[index].length () );
|
lineLength += int ( childValues_[index].length () );
|
||||||
isMultiLine = isMultiLine && hasCommentForValue ( value[index] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addChildValues_ = false;
|
addChildValues_ = false;
|
||||||
@@ -530,70 +507,6 @@ StyledWriter::unindent ()
|
|||||||
indentString_.resize ( indentString_.size () - indentSize_ );
|
indentString_.resize ( indentString_.size () - indentSize_ );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
StyledWriter::writeCommentBeforeValue ( const Value& root )
|
|
||||||
{
|
|
||||||
if ( !root.hasComment ( commentBefore ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
document_ += normalizeEOL ( root.getComment ( commentBefore ) );
|
|
||||||
document_ += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
StyledWriter::writeCommentAfterValueOnSameLine ( const Value& root )
|
|
||||||
{
|
|
||||||
if ( root.hasComment ( commentAfterOnSameLine ) )
|
|
||||||
document_ += " " + normalizeEOL ( root.getComment ( commentAfterOnSameLine ) );
|
|
||||||
|
|
||||||
if ( root.hasComment ( commentAfter ) )
|
|
||||||
{
|
|
||||||
document_ += "\n";
|
|
||||||
document_ += normalizeEOL ( root.getComment ( commentAfter ) );
|
|
||||||
document_ += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
StyledWriter::hasCommentForValue ( const Value& value )
|
|
||||||
{
|
|
||||||
return value.hasComment ( commentBefore )
|
|
||||||
|| value.hasComment ( commentAfterOnSameLine )
|
|
||||||
|| value.hasComment ( commentAfter );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string
|
|
||||||
StyledWriter::normalizeEOL ( std::string const& text )
|
|
||||||
{
|
|
||||||
std::string normalized;
|
|
||||||
normalized.reserve ( text.length () );
|
|
||||||
const char* begin = text.c_str ();
|
|
||||||
const char* end = begin + text.length ();
|
|
||||||
const char* current = begin;
|
|
||||||
|
|
||||||
while ( current != end )
|
|
||||||
{
|
|
||||||
char c = *current++;
|
|
||||||
|
|
||||||
if ( c == '\r' ) // mac or dos EOL
|
|
||||||
{
|
|
||||||
if ( *current == '\n' ) // convert dos EOL
|
|
||||||
++current;
|
|
||||||
|
|
||||||
normalized += '\n';
|
|
||||||
}
|
|
||||||
else // handle unix EOL & other char
|
|
||||||
normalized += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Class StyledStreamWriter
|
// Class StyledStreamWriter
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -611,9 +524,7 @@ StyledStreamWriter::write ( std::ostream& out, const Value& root )
|
|||||||
document_ = &out;
|
document_ = &out;
|
||||||
addChildValues_ = false;
|
addChildValues_ = false;
|
||||||
indentString_ = "";
|
indentString_ = "";
|
||||||
writeCommentBeforeValue ( root );
|
|
||||||
writeValue ( root );
|
writeValue ( root );
|
||||||
writeCommentAfterValueOnSameLine ( root );
|
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
document_ = nullptr; // Forget the stream, for safety.
|
document_ = nullptr; // Forget the stream, for safety.
|
||||||
}
|
}
|
||||||
@@ -668,19 +579,14 @@ StyledStreamWriter::writeValue ( const Value& value )
|
|||||||
{
|
{
|
||||||
std::string const& name = *it;
|
std::string const& name = *it;
|
||||||
const Value& childValue = value[name];
|
const Value& childValue = value[name];
|
||||||
writeCommentBeforeValue ( childValue );
|
|
||||||
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
|
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
|
||||||
*document_ << " : ";
|
*document_ << " : ";
|
||||||
writeValue ( childValue );
|
writeValue ( childValue );
|
||||||
|
|
||||||
if ( ++it == members.end () )
|
if ( ++it == members.end () )
|
||||||
{
|
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
*document_ << ",";
|
*document_ << ",";
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unindent ();
|
unindent ();
|
||||||
@@ -713,7 +619,6 @@ StyledStreamWriter::writeArrayValue ( const Value& value )
|
|||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
const Value& childValue = value[index];
|
const Value& childValue = value[index];
|
||||||
writeCommentBeforeValue ( childValue );
|
|
||||||
|
|
||||||
if ( hasChildValue )
|
if ( hasChildValue )
|
||||||
writeWithIndent ( childValues_[index] );
|
writeWithIndent ( childValues_[index] );
|
||||||
@@ -724,13 +629,9 @@ StyledStreamWriter::writeArrayValue ( const Value& value )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( ++index == size )
|
if ( ++index == size )
|
||||||
{
|
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
*document_ << ",";
|
*document_ << ",";
|
||||||
writeCommentAfterValueOnSameLine ( childValue );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unindent ();
|
unindent ();
|
||||||
@@ -776,11 +677,10 @@ StyledStreamWriter::isMultineArray ( const Value& value )
|
|||||||
addChildValues_ = true;
|
addChildValues_ = true;
|
||||||
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
|
||||||
|
|
||||||
for ( int index = 0; index < size && !isMultiLine; ++index )
|
for ( int index = 0; index < size; ++index )
|
||||||
{
|
{
|
||||||
writeValue ( value[index] );
|
writeValue ( value[index] );
|
||||||
lineLength += int ( childValues_[index].length () );
|
lineLength += int ( childValues_[index].length () );
|
||||||
isMultiLine = isMultiLine && hasCommentForValue ( value[index] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addChildValues_ = false;
|
addChildValues_ = false;
|
||||||
@@ -843,69 +743,6 @@ StyledStreamWriter::unindent ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
StyledStreamWriter::writeCommentBeforeValue ( const Value& root )
|
|
||||||
{
|
|
||||||
if ( !root.hasComment ( commentBefore ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
*document_ << normalizeEOL ( root.getComment ( commentBefore ) );
|
|
||||||
*document_ << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
StyledStreamWriter::writeCommentAfterValueOnSameLine ( const Value& root )
|
|
||||||
{
|
|
||||||
if ( root.hasComment ( commentAfterOnSameLine ) )
|
|
||||||
*document_ << " " + normalizeEOL ( root.getComment ( commentAfterOnSameLine ) );
|
|
||||||
|
|
||||||
if ( root.hasComment ( commentAfter ) )
|
|
||||||
{
|
|
||||||
*document_ << "\n";
|
|
||||||
*document_ << normalizeEOL ( root.getComment ( commentAfter ) );
|
|
||||||
*document_ << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
StyledStreamWriter::hasCommentForValue ( const Value& value )
|
|
||||||
{
|
|
||||||
return value.hasComment ( commentBefore )
|
|
||||||
|| value.hasComment ( commentAfterOnSameLine )
|
|
||||||
|| value.hasComment ( commentAfter );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string
|
|
||||||
StyledStreamWriter::normalizeEOL ( std::string const& text )
|
|
||||||
{
|
|
||||||
std::string normalized;
|
|
||||||
normalized.reserve ( text.length () );
|
|
||||||
const char* begin = text.c_str ();
|
|
||||||
const char* end = begin + text.length ();
|
|
||||||
const char* current = begin;
|
|
||||||
|
|
||||||
while ( current != end )
|
|
||||||
{
|
|
||||||
char c = *current++;
|
|
||||||
|
|
||||||
if ( c == '\r' ) // mac or dos EOL
|
|
||||||
{
|
|
||||||
if ( *current == '\n' ) // convert dos EOL
|
|
||||||
++current;
|
|
||||||
|
|
||||||
normalized += '\n';
|
|
||||||
}
|
|
||||||
else // handle unix EOL & other char
|
|
||||||
normalized += c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<< ( std::ostream& sout, const Value& root )
|
std::ostream& operator<< ( std::ostream& sout, const Value& root )
|
||||||
{
|
{
|
||||||
Json::StyledStreamWriter writer;
|
Json::StyledStreamWriter writer;
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_JSON_JSON_CONFIG_H_INCLUDED
|
|
||||||
#define RIPPLE_JSON_JSON_CONFIG_H_INCLUDED
|
|
||||||
|
|
||||||
/// If defined, indicates that json library is embedded in CppTL library.
|
|
||||||
//# define JSON_IN_CPPTL 1
|
|
||||||
|
|
||||||
/// If defined, indicates that json may leverage CppTL library
|
|
||||||
//# define JSON_USE_CPPTL 1
|
|
||||||
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
|
||||||
/// as Value container.
|
|
||||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
|
||||||
/// If defined, indicates that Json specific container should be used
|
|
||||||
/// (hash table & simple deque container with customizable allocator).
|
|
||||||
/// THIS FEATURE IS STILL EXPERIMENTAL!
|
|
||||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
|
||||||
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
|
||||||
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
|
||||||
/// as if it was a POD) that may cause some validation tool to report errors.
|
|
||||||
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
|
||||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
|
||||||
|
|
||||||
/// If defined, indicates that Json use exception to report invalid type manipulation
|
|
||||||
/// instead of C assert macro.
|
|
||||||
# define JSON_USE_EXCEPTION 1
|
|
||||||
|
|
||||||
# ifdef JSON_IN_CPPTL
|
|
||||||
# include <cpptl/config.h>
|
|
||||||
# ifndef JSON_USE_CPPTL
|
|
||||||
# define JSON_USE_CPPTL 1
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef JSON_IN_CPPTL
|
|
||||||
# define JSON_API CPPTL_API
|
|
||||||
# elif defined(JSON_DLL_BUILD)
|
|
||||||
# define JSON_API __declspec(dllexport)
|
|
||||||
# elif defined(JSON_DLL)
|
|
||||||
# define JSON_API __declspec(dllimport)
|
|
||||||
# else
|
|
||||||
# define JSON_API
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // JSON_CONFIG_H_INCLUDED
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_JSON_JSON_FEATURES_H_INCLUDED
|
|
||||||
#define RIPPLE_JSON_JSON_FEATURES_H_INCLUDED
|
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
|
|
||||||
namespace Json
|
|
||||||
{
|
|
||||||
|
|
||||||
/** \brief Configuration passed to reader and writer.
|
|
||||||
* This configuration object can be used to force the Reader or Writer
|
|
||||||
* to behave in a standard conforming way.
|
|
||||||
*/
|
|
||||||
class JSON_API Features
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
|
||||||
* - C & C++ comments are allowed
|
|
||||||
* - Root object can be any JSON value
|
|
||||||
* - Assumes Value strings are encoded in UTF-8
|
|
||||||
*/
|
|
||||||
static Features all ();
|
|
||||||
|
|
||||||
/** \brief A configuration that is strictly compatible with the JSON specification.
|
|
||||||
* - Comments are forbidden.
|
|
||||||
* - Root object must be either an array or an object value.
|
|
||||||
* - Assumes Value strings are encoded in UTF-8
|
|
||||||
*/
|
|
||||||
static Features strictMode ();
|
|
||||||
|
|
||||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
|
||||||
*/
|
|
||||||
Features ();
|
|
||||||
|
|
||||||
/// \c true if comments are allowed. Default: \c true.
|
|
||||||
bool allowComments_;
|
|
||||||
|
|
||||||
/// \c true if root must be either an array or an object value. Default: \c false.
|
|
||||||
bool strictRoot_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Json
|
|
||||||
|
|
||||||
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
|
||||||
@@ -20,38 +20,17 @@
|
|||||||
#ifndef RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED
|
#ifndef RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED
|
||||||
#define RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED
|
#define RIPPLE_JSON_JSON_FORWARDS_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
|
|
||||||
namespace Json
|
namespace Json
|
||||||
{
|
{
|
||||||
|
|
||||||
// writer.h
|
|
||||||
class FastWriter;
|
|
||||||
class StyledWriter;
|
|
||||||
|
|
||||||
// reader.h
|
|
||||||
class Reader;
|
|
||||||
|
|
||||||
// features.h
|
|
||||||
class Features;
|
|
||||||
|
|
||||||
// value.h
|
// value.h
|
||||||
typedef int Int;
|
typedef int Int;
|
||||||
typedef unsigned int UInt;
|
typedef unsigned int UInt;
|
||||||
class StaticString;
|
class StaticString;
|
||||||
class Path;
|
|
||||||
class PathArgument;
|
|
||||||
class Value;
|
class Value;
|
||||||
class ValueIteratorBase;
|
class ValueIteratorBase;
|
||||||
class ValueIterator;
|
class ValueIterator;
|
||||||
class ValueConstIterator;
|
class ValueConstIterator;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
class ValueAllocator;
|
|
||||||
class ValueMapAllocator;
|
|
||||||
class ValueInternalLink;
|
|
||||||
class ValueInternalArray;
|
|
||||||
class ValueInternalMap;
|
|
||||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
# define CPPTL_JSON_READER_H_INCLUDED
|
# define CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
#include <ripple/json/json_features.h>
|
|
||||||
#include <ripple/json/json_forwards.h>
|
#include <ripple/json/json_forwards.h>
|
||||||
#include <ripple/json/json_value.h>
|
#include <ripple/json/json_value.h>
|
||||||
|
|
||||||
@@ -35,7 +33,7 @@ namespace Json
|
|||||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class JSON_API Reader
|
class Reader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef char Char;
|
typedef char Char;
|
||||||
@@ -46,44 +44,25 @@ public:
|
|||||||
*/
|
*/
|
||||||
Reader ();
|
Reader ();
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing the specified feature set
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
* for parsing.
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
*/
|
*/
|
||||||
Reader ( const Features& features );
|
bool parse ( std::string const& document, Value& root);
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
* \param document UTF-8 encoded string containing the document to read.
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them back during
|
|
||||||
* serialization, \c false to discard comments.
|
|
||||||
* This parameter is ignored if Features::allowComments_
|
|
||||||
* is \c false.
|
|
||||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
*/
|
*/
|
||||||
bool parse ( std::string const& document,
|
bool parse ( const char* beginDoc, const char* endDoc, Value& root);
|
||||||
Value& root,
|
|
||||||
bool collectComments = true );
|
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
|
||||||
* \param document UTF-8 encoded string containing the document to read.
|
|
||||||
* \param root [out] Contains the root value of the document if it was
|
|
||||||
* successfully parsed.
|
|
||||||
* \param collectComments \c true to collect comment and allow writing them back during
|
|
||||||
* serialization, \c false to discard comments.
|
|
||||||
* This parameter is ignored if Features::allowComments_
|
|
||||||
* is \c false.
|
|
||||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
|
||||||
*/
|
|
||||||
bool parse ( const char* beginDoc, const char* endDoc,
|
|
||||||
Value& root,
|
|
||||||
bool collectComments = true );
|
|
||||||
|
|
||||||
/// \brief Parse from input stream.
|
/// \brief Parse from input stream.
|
||||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||||
bool parse ( std::istream& is,
|
bool parse ( std::istream& is, Value& root);
|
||||||
Value& root,
|
|
||||||
bool collectComments = true );
|
|
||||||
|
|
||||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||||
* \return Formatted error message with the list of errors with their location in
|
* \return Formatted error message with the list of errors with their location in
|
||||||
@@ -101,7 +80,8 @@ private:
|
|||||||
tokenArrayBegin,
|
tokenArrayBegin,
|
||||||
tokenArrayEnd,
|
tokenArrayEnd,
|
||||||
tokenString,
|
tokenString,
|
||||||
tokenNumber,
|
tokenInteger,
|
||||||
|
tokenDouble,
|
||||||
tokenTrue,
|
tokenTrue,
|
||||||
tokenFalse,
|
tokenFalse,
|
||||||
tokenNull,
|
tokenNull,
|
||||||
@@ -138,7 +118,7 @@ private:
|
|||||||
bool readCStyleComment ();
|
bool readCStyleComment ();
|
||||||
bool readCppStyleComment ();
|
bool readCppStyleComment ();
|
||||||
bool readString ();
|
bool readString ();
|
||||||
void readNumber ();
|
Reader::TokenType readNumber ();
|
||||||
bool readValue ();
|
bool readValue ();
|
||||||
bool readObject ( Token& token );
|
bool readObject ( Token& token );
|
||||||
bool readArray ( Token& token );
|
bool readArray ( Token& token );
|
||||||
@@ -168,9 +148,6 @@ private:
|
|||||||
int& line,
|
int& line,
|
||||||
int& column ) const;
|
int& column ) const;
|
||||||
std::string getLocationLineAndColumn ( Location location ) const;
|
std::string getLocationLineAndColumn ( Location location ) const;
|
||||||
void addComment ( Location begin,
|
|
||||||
Location end,
|
|
||||||
CommentPlacement placement );
|
|
||||||
void skipCommentTokens ( Token& token );
|
void skipCommentTokens ( Token& token );
|
||||||
|
|
||||||
typedef std::stack<Value*> Nodes;
|
typedef std::stack<Value*> Nodes;
|
||||||
@@ -182,9 +159,6 @@ private:
|
|||||||
Location current_;
|
Location current_;
|
||||||
Location lastValueEnd_;
|
Location lastValueEnd_;
|
||||||
Value* lastValue_;
|
Value* lastValue_;
|
||||||
std::string commentsBefore_;
|
|
||||||
Features features_;
|
|
||||||
bool collectComments_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Read from 'sin' into 'root'.
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED
|
#ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED
|
||||||
#define RIPPLE_JSON_JSON_VALUE_H_INCLUDED
|
#define RIPPLE_JSON_JSON_VALUE_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
#include <ripple/json/json_forwards.h>
|
#include <ripple/json/json_forwards.h>
|
||||||
#include <beast/strings/String.h>
|
#include <beast/strings/String.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -54,11 +53,6 @@ enum CommentPlacement
|
|||||||
numberOfCommentPlacement
|
numberOfCommentPlacement
|
||||||
};
|
};
|
||||||
|
|
||||||
//# ifdef JSON_USE_CPPTL
|
|
||||||
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
|
|
||||||
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
|
|
||||||
//# endif
|
|
||||||
|
|
||||||
/** \brief Lightweight wrapper to tag static string.
|
/** \brief Lightweight wrapper to tag static string.
|
||||||
*
|
*
|
||||||
* Value constructor and objectValue member assignement takes advantage of the
|
* Value constructor and objectValue member assignement takes advantage of the
|
||||||
@@ -73,7 +67,7 @@ enum CommentPlacement
|
|||||||
* object[code] = 1234;
|
* object[code] = 1234;
|
||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
class JSON_API StaticString
|
class StaticString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit StaticString ( const char* czstring )
|
explicit StaticString ( const char* czstring )
|
||||||
@@ -122,13 +116,10 @@ private:
|
|||||||
* It is possible to iterate over the list of a #objectValue values using
|
* It is possible to iterate over the list of a #objectValue values using
|
||||||
* the getMemberNames() method.
|
* the getMemberNames() method.
|
||||||
*/
|
*/
|
||||||
class JSON_API Value
|
class Value
|
||||||
{
|
{
|
||||||
friend class ValueIteratorBase;
|
friend class ValueIteratorBase;
|
||||||
# ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
friend class ValueInternalLink;
|
|
||||||
friend class ValueInternalMap;
|
|
||||||
# endif
|
|
||||||
public:
|
public:
|
||||||
typedef std::vector<std::string> Members;
|
typedef std::vector<std::string> Members;
|
||||||
typedef ValueIterator iterator;
|
typedef ValueIterator iterator;
|
||||||
@@ -143,8 +134,6 @@ public:
|
|||||||
static const UInt maxUInt;
|
static const UInt maxUInt;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
# ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
class CZString
|
class CZString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -171,13 +160,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
# ifndef JSON_USE_CPPTL_SMALLMAP
|
|
||||||
typedef std::map<CZString, Value> ObjectValues;
|
typedef std::map<CZString, Value> ObjectValues;
|
||||||
# else
|
|
||||||
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
|
||||||
# endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
|
||||||
# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** \brief Create a default Value of the given type.
|
/** \brief Create a default Value of the given type.
|
||||||
@@ -215,9 +198,6 @@ public:
|
|||||||
Value ( std::string const& value );
|
Value ( std::string const& value );
|
||||||
// VFALCO DEPRECATED Avoid this conversion
|
// VFALCO DEPRECATED Avoid this conversion
|
||||||
Value (beast::String const& beastString);
|
Value (beast::String const& beastString);
|
||||||
# ifdef JSON_USE_CPPTL
|
|
||||||
Value ( const CppTL::ConstString& value );
|
|
||||||
# endif
|
|
||||||
Value ( bool value );
|
Value ( bool value );
|
||||||
Value ( const Value& other );
|
Value ( const Value& other );
|
||||||
~Value ();
|
~Value ();
|
||||||
@@ -246,9 +226,6 @@ public:
|
|||||||
|
|
||||||
const char* asCString () const;
|
const char* asCString () const;
|
||||||
std::string asString () const;
|
std::string asString () const;
|
||||||
# ifdef JSON_USE_CPPTL
|
|
||||||
CppTL::ConstString asConstString () const;
|
|
||||||
# endif
|
|
||||||
Int asInt () const;
|
Int asInt () const;
|
||||||
UInt asUInt () const;
|
UInt asUInt () const;
|
||||||
double asDouble () const;
|
double asDouble () const;
|
||||||
@@ -330,23 +307,14 @@ public:
|
|||||||
* \endcode
|
* \endcode
|
||||||
*/
|
*/
|
||||||
Value& operator[] ( const StaticString& key );
|
Value& operator[] ( const StaticString& key );
|
||||||
# ifdef JSON_USE_CPPTL
|
|
||||||
/// Access an object value by name, create a null member if it does not exist.
|
|
||||||
Value& operator[] ( const CppTL::ConstString& key );
|
|
||||||
/// Access an object value by name, returns null if there is no member with that name.
|
|
||||||
const Value& operator[] ( const CppTL::ConstString& key ) const;
|
|
||||||
# endif
|
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
Value get ( const char* key,
|
Value get ( const char* key,
|
||||||
const Value& defaultValue ) const;
|
const Value& defaultValue ) const;
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
Value get ( std::string const& key,
|
Value get ( std::string const& key,
|
||||||
const Value& defaultValue ) const;
|
const Value& defaultValue ) const;
|
||||||
# ifdef JSON_USE_CPPTL
|
|
||||||
/// Return the member named key if it exist, defaultValue otherwise.
|
|
||||||
Value get ( const CppTL::ConstString& key,
|
|
||||||
const Value& defaultValue ) const;
|
|
||||||
# endif
|
|
||||||
/// \brief Remove and return the named member.
|
/// \brief Remove and return the named member.
|
||||||
///
|
///
|
||||||
/// Do nothing if it did not exist.
|
/// Do nothing if it did not exist.
|
||||||
@@ -361,10 +329,6 @@ public:
|
|||||||
bool isMember ( const char* key ) const;
|
bool isMember ( const char* key ) const;
|
||||||
/// Return true if the object has a member named key.
|
/// Return true if the object has a member named key.
|
||||||
bool isMember ( std::string const& key ) const;
|
bool isMember ( std::string const& key ) const;
|
||||||
# ifdef JSON_USE_CPPTL
|
|
||||||
/// Return true if the object has a member named key.
|
|
||||||
bool isMember ( const CppTL::ConstString& key ) const;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/// \brief Return a list of the member names.
|
/// \brief Return a list of the member names.
|
||||||
///
|
///
|
||||||
@@ -373,17 +337,6 @@ public:
|
|||||||
/// \post if type() was nullValue, it remains nullValue
|
/// \post if type() was nullValue, it remains nullValue
|
||||||
Members getMemberNames () const;
|
Members getMemberNames () const;
|
||||||
|
|
||||||
//# ifdef JSON_USE_CPPTL
|
|
||||||
// EnumMemberNames enumMemberNames() const;
|
|
||||||
// EnumValues enumValues() const;
|
|
||||||
//# endif
|
|
||||||
|
|
||||||
/// Comments must be //... or /* ... */
|
|
||||||
void setComment ( const char* comment,
|
|
||||||
CommentPlacement placement );
|
|
||||||
/// Comments must be //... or /* ... */
|
|
||||||
void setComment ( std::string const& comment,
|
|
||||||
CommentPlacement placement );
|
|
||||||
bool hasComment ( CommentPlacement placement ) const;
|
bool hasComment ( CommentPlacement placement ) const;
|
||||||
/// Include delimiters and embedded newlines.
|
/// Include delimiters and embedded newlines.
|
||||||
std::string getComment ( CommentPlacement placement ) const;
|
std::string getComment ( CommentPlacement placement ) const;
|
||||||
@@ -400,48 +353,7 @@ private:
|
|||||||
Value& resolveReference ( const char* key,
|
Value& resolveReference ( const char* key,
|
||||||
bool isStatic );
|
bool isStatic );
|
||||||
|
|
||||||
# ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
inline bool isItemAvailable () const
|
|
||||||
{
|
|
||||||
return itemIsUsed_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setItemUsed ( bool isUsed = true )
|
|
||||||
{
|
|
||||||
itemIsUsed_ = isUsed ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isMemberNameStatic () const
|
|
||||||
{
|
|
||||||
return memberNameIsStatic_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setMemberNameIsStatic ( bool isStatic )
|
|
||||||
{
|
|
||||||
memberNameIsStatic_ = isStatic ? 1 : 0;
|
|
||||||
}
|
|
||||||
# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CommentInfo
|
|
||||||
{
|
|
||||||
CommentInfo ();
|
|
||||||
~CommentInfo ();
|
|
||||||
|
|
||||||
void setComment ( const char* text );
|
|
||||||
|
|
||||||
char* comment_;
|
|
||||||
};
|
|
||||||
|
|
||||||
//struct MemberNamesTransform
|
|
||||||
//{
|
|
||||||
// typedef const char *result_type;
|
|
||||||
// const char *operator()( const CZString &name ) const
|
|
||||||
// {
|
|
||||||
// return name.c_str();
|
|
||||||
// }
|
|
||||||
//};
|
|
||||||
|
|
||||||
union ValueHolder
|
union ValueHolder
|
||||||
{
|
{
|
||||||
Int int_;
|
Int int_;
|
||||||
@@ -449,88 +361,10 @@ private:
|
|||||||
double real_;
|
double real_;
|
||||||
bool bool_;
|
bool bool_;
|
||||||
char* string_;
|
char* string_;
|
||||||
# ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueInternalArray* array_;
|
|
||||||
ValueInternalMap* map_;
|
|
||||||
#else
|
|
||||||
ObjectValues* map_;
|
ObjectValues* map_;
|
||||||
# endif
|
|
||||||
} value_;
|
} value_;
|
||||||
ValueType type_ : 8;
|
ValueType type_ : 8;
|
||||||
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
# ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
|
|
||||||
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
|
||||||
# endif
|
|
||||||
CommentInfo* comments_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Experimental and untested: represents an element of the "path" to access a node.
|
|
||||||
*/
|
|
||||||
class PathArgument
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class Path;
|
|
||||||
|
|
||||||
PathArgument ();
|
|
||||||
PathArgument ( UInt index );
|
|
||||||
PathArgument ( const char* key );
|
|
||||||
PathArgument ( std::string const& key );
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum Kind
|
|
||||||
{
|
|
||||||
kindNone = 0,
|
|
||||||
kindIndex,
|
|
||||||
kindKey
|
|
||||||
};
|
|
||||||
std::string key_;
|
|
||||||
UInt index_;
|
|
||||||
Kind kind_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Experimental and untested: represents a "path" to access a node.
|
|
||||||
*
|
|
||||||
* Syntax:
|
|
||||||
* - "." => root node
|
|
||||||
* - ".[n]" => elements at index 'n' of root node (an array value)
|
|
||||||
* - ".name" => member named 'name' of root node (an object value)
|
|
||||||
* - ".name1.name2.name3"
|
|
||||||
* - ".[0][1][2].name1[3]"
|
|
||||||
* - ".%" => member name is provided as parameter
|
|
||||||
* - ".[%]" => index is provied as parameter
|
|
||||||
*/
|
|
||||||
class Path
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Path ( std::string const& path,
|
|
||||||
const PathArgument& a1 = PathArgument (),
|
|
||||||
const PathArgument& a2 = PathArgument (),
|
|
||||||
const PathArgument& a3 = PathArgument (),
|
|
||||||
const PathArgument& a4 = PathArgument (),
|
|
||||||
const PathArgument& a5 = PathArgument () );
|
|
||||||
|
|
||||||
const Value& resolve ( const Value& root ) const;
|
|
||||||
Value resolve ( const Value& root,
|
|
||||||
const Value& defaultValue ) const;
|
|
||||||
/// Creates the "path" to access the specified node and returns a reference on the node.
|
|
||||||
Value& make ( Value& root ) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::vector<const PathArgument*> InArgs;
|
|
||||||
typedef std::vector<PathArgument> Args;
|
|
||||||
|
|
||||||
void makePath ( std::string const& path,
|
|
||||||
const InArgs& in );
|
|
||||||
void addPathInArg ( std::string const& path,
|
|
||||||
const InArgs& in,
|
|
||||||
InArgs::const_iterator& itInArg,
|
|
||||||
PathArgument::Kind kind );
|
|
||||||
void invalidPath ( std::string const& path,
|
|
||||||
int location );
|
|
||||||
|
|
||||||
Args args_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.
|
/** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.
|
||||||
@@ -554,346 +388,6 @@ public:
|
|||||||
virtual void releaseStringValue ( char* value ) = 0;
|
virtual void releaseStringValue ( char* value ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
/** \brief Allocator to customize Value internal map.
|
|
||||||
* Below is an example of a simple implementation (default implementation actually
|
|
||||||
* use memory pool for speed).
|
|
||||||
* \code
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
class JSON_API ValueMapAllocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ValueMapAllocator ();
|
|
||||||
virtual ValueInternalMap* newMap () = 0;
|
|
||||||
virtual ValueInternalMap* newMapCopy ( const ValueInternalMap& other ) = 0;
|
|
||||||
virtual void destructMap ( ValueInternalMap* map ) = 0;
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets ( unsigned int size ) = 0;
|
|
||||||
virtual void releaseMapBuckets ( ValueInternalLink* links ) = 0;
|
|
||||||
virtual ValueInternalLink* allocateMapLink () = 0;
|
|
||||||
virtual void releaseMapLink ( ValueInternalLink* link ) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
|
|
||||||
* \internal previous_ & next_ allows for bidirectional traversal.
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalLink
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
|
|
||||||
enum InternalFlags
|
|
||||||
{
|
|
||||||
flagAvailable = 0,
|
|
||||||
flagUsed = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
ValueInternalLink ();
|
|
||||||
|
|
||||||
~ValueInternalLink ();
|
|
||||||
|
|
||||||
Value items_[itemPerLink];
|
|
||||||
char* keys_[itemPerLink];
|
|
||||||
ValueInternalLink* previous_;
|
|
||||||
ValueInternalLink* next_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief A linked page based hash-table implementation used internally by Value.
|
|
||||||
* \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
|
|
||||||
* list in each bucket to handle collision. There is an addional twist in that
|
|
||||||
* each node of the collision linked list is a page containing a fixed amount of
|
|
||||||
* value. This provides a better compromise between memory usage and speed.
|
|
||||||
*
|
|
||||||
* Each bucket is made up of a chained list of ValueInternalLink. The last
|
|
||||||
* link of a given bucket can be found in the 'previous_' field of the following bucket.
|
|
||||||
* The last link of the last bucket is stored in tailLink_ as it has no following bucket.
|
|
||||||
* Only the last link of a bucket may contains 'available' item. The last link always
|
|
||||||
* contains at least one element unless is it the bucket one very first link.
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalMap
|
|
||||||
{
|
|
||||||
friend class ValueIteratorBase;
|
|
||||||
friend class Value;
|
|
||||||
public:
|
|
||||||
typedef unsigned int HashKey;
|
|
||||||
typedef unsigned int BucketIndex;
|
|
||||||
|
|
||||||
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
struct IteratorState
|
|
||||||
{
|
|
||||||
IteratorState ()
|
|
||||||
: map_ (0)
|
|
||||||
, link_ (0)
|
|
||||||
, itemIndex_ (0)
|
|
||||||
, bucketIndex_ (0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ValueInternalMap* map_;
|
|
||||||
ValueInternalLink* link_;
|
|
||||||
BucketIndex itemIndex_;
|
|
||||||
BucketIndex bucketIndex_;
|
|
||||||
};
|
|
||||||
# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
ValueInternalMap ();
|
|
||||||
ValueInternalMap ( const ValueInternalMap& other );
|
|
||||||
ValueInternalMap& operator = ( const ValueInternalMap& other );
|
|
||||||
~ValueInternalMap ();
|
|
||||||
|
|
||||||
void swap ( ValueInternalMap& other ) noexcept;
|
|
||||||
|
|
||||||
BucketIndex size () const;
|
|
||||||
|
|
||||||
void clear ();
|
|
||||||
|
|
||||||
bool reserveDelta ( BucketIndex growth );
|
|
||||||
|
|
||||||
bool reserve ( BucketIndex newItemCount );
|
|
||||||
|
|
||||||
const Value* find ( const char* key ) const;
|
|
||||||
|
|
||||||
Value* find ( const char* key );
|
|
||||||
|
|
||||||
Value& resolveReference ( const char* key,
|
|
||||||
bool isStatic );
|
|
||||||
|
|
||||||
void remove ( const char* key );
|
|
||||||
|
|
||||||
void doActualRemove ( ValueInternalLink* link,
|
|
||||||
BucketIndex index,
|
|
||||||
BucketIndex bucketIndex );
|
|
||||||
|
|
||||||
ValueInternalLink*& getLastLinkInBucket ( BucketIndex bucketIndex );
|
|
||||||
|
|
||||||
Value& setNewItem ( const char* key,
|
|
||||||
bool isStatic,
|
|
||||||
ValueInternalLink* link,
|
|
||||||
BucketIndex index );
|
|
||||||
|
|
||||||
Value& unsafeAdd ( const char* key,
|
|
||||||
bool isStatic,
|
|
||||||
HashKey hashedKey );
|
|
||||||
|
|
||||||
HashKey hash ( const char* key ) const;
|
|
||||||
|
|
||||||
int compare ( const ValueInternalMap& other ) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void makeBeginIterator ( IteratorState& it ) const;
|
|
||||||
void makeEndIterator ( IteratorState& it ) const;
|
|
||||||
static bool equals ( const IteratorState& x, const IteratorState& other );
|
|
||||||
static void increment ( IteratorState& iterator );
|
|
||||||
static void incrementBucket ( IteratorState& iterator );
|
|
||||||
static void decrement ( IteratorState& iterator );
|
|
||||||
static const char* key ( const IteratorState& iterator );
|
|
||||||
static const char* key ( const IteratorState& iterator, bool& isStatic );
|
|
||||||
static Value& value ( const IteratorState& iterator );
|
|
||||||
static int distance ( const IteratorState& x, const IteratorState& y );
|
|
||||||
|
|
||||||
private:
|
|
||||||
ValueInternalLink* buckets_;
|
|
||||||
ValueInternalLink* tailLink_;
|
|
||||||
BucketIndex bucketsSize_;
|
|
||||||
BucketIndex itemCount_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief A simplified deque implementation used internally by Value.
|
|
||||||
* \internal
|
|
||||||
* It is based on a list of fixed "page", each page contains a fixed number of items.
|
|
||||||
* Instead of using a linked-list, a array of pointer is used for fast item look-up.
|
|
||||||
* Look-up for an element is as follow:
|
|
||||||
* - compute page index: pageIndex = itemIndex / itemsPerPage
|
|
||||||
* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
|
|
||||||
*
|
|
||||||
* Insertion is amortized constant time (only the array containing the index of pointers
|
|
||||||
* need to be reallocated when items are appended).
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalArray
|
|
||||||
{
|
|
||||||
friend class Value;
|
|
||||||
friend class ValueIteratorBase;
|
|
||||||
public:
|
|
||||||
enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo.
|
|
||||||
typedef Value::ArrayIndex ArrayIndex;
|
|
||||||
typedef unsigned int PageIndex;
|
|
||||||
|
|
||||||
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
struct IteratorState // Must be a POD
|
|
||||||
{
|
|
||||||
IteratorState ()
|
|
||||||
: array_ (0)
|
|
||||||
, currentPageIndex_ (0)
|
|
||||||
, currentItemIndex_ (0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ValueInternalArray* array_;
|
|
||||||
Value** currentPageIndex_;
|
|
||||||
unsigned int currentItemIndex_;
|
|
||||||
};
|
|
||||||
# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
ValueInternalArray ();
|
|
||||||
ValueInternalArray ( const ValueInternalArray& other );
|
|
||||||
ValueInternalArray& operator = ( const ValueInternalArray& other );
|
|
||||||
~ValueInternalArray ();
|
|
||||||
void swap ( ValueInternalArray& other ) noexcept;
|
|
||||||
|
|
||||||
void clear ();
|
|
||||||
void resize ( ArrayIndex newSize );
|
|
||||||
|
|
||||||
Value& resolveReference ( ArrayIndex index );
|
|
||||||
|
|
||||||
Value* find ( ArrayIndex index ) const;
|
|
||||||
|
|
||||||
ArrayIndex size () const;
|
|
||||||
|
|
||||||
int compare ( const ValueInternalArray& other ) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool equals ( const IteratorState& x, const IteratorState& other );
|
|
||||||
static void increment ( IteratorState& iterator );
|
|
||||||
static void decrement ( IteratorState& iterator );
|
|
||||||
static Value& dereference ( const IteratorState& iterator );
|
|
||||||
static Value& unsafeDereference ( const IteratorState& iterator );
|
|
||||||
static int distance ( const IteratorState& x, const IteratorState& y );
|
|
||||||
static ArrayIndex indexOf ( const IteratorState& iterator );
|
|
||||||
void makeBeginIterator ( IteratorState& it ) const;
|
|
||||||
void makeEndIterator ( IteratorState& it ) const;
|
|
||||||
void makeIterator ( IteratorState& it, ArrayIndex index ) const;
|
|
||||||
|
|
||||||
void makeIndexValid ( ArrayIndex index );
|
|
||||||
|
|
||||||
Value** pages_;
|
|
||||||
ArrayIndex size_;
|
|
||||||
PageIndex pageCount_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Experimental: do not use. Allocator to customize Value internal array.
|
|
||||||
* Below is an example of a simple implementation (actual implementation use
|
|
||||||
* memory pool).
|
|
||||||
\code
|
|
||||||
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 destruct( 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 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
class JSON_API ValueArrayAllocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ValueArrayAllocator ();
|
|
||||||
virtual ValueInternalArray* newArray () = 0;
|
|
||||||
virtual ValueInternalArray* newArrayCopy ( const ValueInternalArray& other ) = 0;
|
|
||||||
virtual void destructArray ( ValueInternalArray* array ) = 0;
|
|
||||||
/** \brief Reallocate array page index.
|
|
||||||
* Reallocates an array of pointer on each page.
|
|
||||||
* \param indexes [input] pointer on the current index. May be \c NULL.
|
|
||||||
* [output] pointer on the new index of at least
|
|
||||||
* \a minNewIndexCount pages.
|
|
||||||
* \param indexCount [input] current number of pages in the index.
|
|
||||||
* [output] number of page the reallocated index can handle.
|
|
||||||
* \b MUST be >= \a minNewIndexCount.
|
|
||||||
* \param minNewIndexCount Minimum number of page the new index must be able to
|
|
||||||
* handle.
|
|
||||||
*/
|
|
||||||
virtual void reallocateArrayPageIndex ( Value**& indexes,
|
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
|
||||||
ValueInternalArray::PageIndex minNewIndexCount ) = 0;
|
|
||||||
virtual void releaseArrayPageIndex ( Value** indexes,
|
|
||||||
ValueInternalArray::PageIndex indexCount ) = 0;
|
|
||||||
virtual Value* allocateArrayPage () = 0;
|
|
||||||
virtual void releaseArrayPage ( Value* value ) = 0;
|
|
||||||
};
|
|
||||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief base class for Value iterators.
|
/** \brief base class for Value iterators.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -905,12 +399,8 @@ public:
|
|||||||
typedef ValueIteratorBase SelfType;
|
typedef ValueIteratorBase SelfType;
|
||||||
|
|
||||||
ValueIteratorBase ();
|
ValueIteratorBase ();
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueIteratorBase ( const Value::ObjectValues::iterator& current );
|
explicit ValueIteratorBase ( const Value::ObjectValues::iterator& current );
|
||||||
#else
|
|
||||||
ValueIteratorBase ( const ValueInternalArray::IteratorState& state );
|
|
||||||
ValueIteratorBase ( const ValueInternalMap::IteratorState& state );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool operator == ( const SelfType& other ) const
|
bool operator == ( const SelfType& other ) const
|
||||||
{
|
{
|
||||||
@@ -950,18 +440,9 @@ protected:
|
|||||||
void copy ( const SelfType& other );
|
void copy ( const SelfType& other );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
Value::ObjectValues::iterator current_;
|
Value::ObjectValues::iterator current_;
|
||||||
// Indicates that iterator is for a null value.
|
// Indicates that iterator is for a null value.
|
||||||
bool isNull_;
|
bool isNull_;
|
||||||
#else
|
|
||||||
union
|
|
||||||
{
|
|
||||||
ValueInternalArray::IteratorState array_;
|
|
||||||
ValueInternalMap::IteratorState map_;
|
|
||||||
} iterator_;
|
|
||||||
bool isArray_;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief const iterator for object and array value.
|
/** \brief const iterator for object and array value.
|
||||||
@@ -981,12 +462,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueConstIterator ( const Value::ObjectValues::iterator& current );
|
explicit ValueConstIterator ( const Value::ObjectValues::iterator& current );
|
||||||
#else
|
|
||||||
ValueConstIterator ( const ValueInternalArray::IteratorState& state );
|
|
||||||
ValueConstIterator ( const ValueInternalMap::IteratorState& state );
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
SelfType& operator = ( const ValueIteratorBase& other );
|
SelfType& operator = ( const ValueIteratorBase& other );
|
||||||
|
|
||||||
@@ -1041,12 +517,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueIterator ( const Value::ObjectValues::iterator& current );
|
explicit ValueIterator ( const Value::ObjectValues::iterator& current );
|
||||||
#else
|
|
||||||
ValueIterator ( const ValueInternalArray::IteratorState& state );
|
|
||||||
ValueIterator ( const ValueInternalMap::IteratorState& state );
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SelfType& operator = ( const SelfType& other );
|
SelfType& operator = ( const SelfType& other );
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#ifndef RIPPLE_JSON_JSON_WRITER_H_INCLUDED
|
#ifndef RIPPLE_JSON_JSON_WRITER_H_INCLUDED
|
||||||
#define RIPPLE_JSON_JSON_WRITER_H_INCLUDED
|
#define RIPPLE_JSON_JSON_WRITER_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
#include <ripple/json/json_forwards.h>
|
#include <ripple/json/json_forwards.h>
|
||||||
#include <ripple/json/json_value.h>
|
#include <ripple/json/json_value.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -32,7 +31,7 @@ class Value;
|
|||||||
|
|
||||||
/** \brief Abstract class for writers.
|
/** \brief Abstract class for writers.
|
||||||
*/
|
*/
|
||||||
class JSON_API Writer
|
class Writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Writer ();
|
virtual ~Writer ();
|
||||||
@@ -46,14 +45,12 @@ public:
|
|||||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||||
* \sa Reader, Value
|
* \sa Reader, Value
|
||||||
*/
|
*/
|
||||||
class JSON_API FastWriter : public Writer
|
class FastWriter : public Writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FastWriter ();
|
FastWriter ();
|
||||||
virtual ~FastWriter () {}
|
virtual ~FastWriter () {}
|
||||||
|
|
||||||
void enableYAMLCompatibility ();
|
|
||||||
|
|
||||||
public: // overridden from Writer
|
public: // overridden from Writer
|
||||||
virtual std::string write ( const Value& root );
|
virtual std::string write ( const Value& root );
|
||||||
|
|
||||||
@@ -61,7 +58,6 @@ private:
|
|||||||
void writeValue ( const Value& value );
|
void writeValue ( const Value& value );
|
||||||
|
|
||||||
std::string document_;
|
std::string document_;
|
||||||
bool yamlCompatiblityEnabled_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||||
@@ -82,7 +78,7 @@ private:
|
|||||||
*
|
*
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledWriter: public Writer
|
class StyledWriter: public Writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StyledWriter ();
|
StyledWriter ();
|
||||||
@@ -104,10 +100,6 @@ private:
|
|||||||
void writeWithIndent ( std::string const& value );
|
void writeWithIndent ( std::string const& value );
|
||||||
void indent ();
|
void indent ();
|
||||||
void unindent ();
|
void unindent ();
|
||||||
void writeCommentBeforeValue ( const Value& root );
|
|
||||||
void writeCommentAfterValueOnSameLine ( const Value& root );
|
|
||||||
bool hasCommentForValue ( const Value& value );
|
|
||||||
static std::string normalizeEOL ( std::string const& text );
|
|
||||||
|
|
||||||
typedef std::vector<std::string> ChildValues;
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
@@ -139,7 +131,7 @@ private:
|
|||||||
* \param indentation Each level will be indented by this amount extra.
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
* \sa Reader, Value, Value::setComment()
|
* \sa Reader, Value, Value::setComment()
|
||||||
*/
|
*/
|
||||||
class JSON_API StyledStreamWriter
|
class StyledStreamWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StyledStreamWriter ( std::string indentation = "\t" );
|
StyledStreamWriter ( std::string indentation = "\t" );
|
||||||
@@ -162,10 +154,6 @@ private:
|
|||||||
void writeWithIndent ( std::string const& value );
|
void writeWithIndent ( std::string const& value );
|
||||||
void indent ();
|
void indent ();
|
||||||
void unindent ();
|
void unindent ();
|
||||||
void writeCommentBeforeValue ( const Value& root );
|
|
||||||
void writeCommentAfterValueOnSameLine ( const Value& root );
|
|
||||||
bool hasCommentForValue ( const Value& value );
|
|
||||||
static std::string normalizeEOL ( std::string const& text );
|
|
||||||
|
|
||||||
typedef std::vector<std::string> ChildValues;
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
@@ -177,11 +165,11 @@ private:
|
|||||||
bool addChildValues_;
|
bool addChildValues_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string JSON_API valueToString ( Int value );
|
std::string valueToString ( Int value );
|
||||||
std::string JSON_API valueToString ( UInt value );
|
std::string valueToString ( UInt value );
|
||||||
std::string JSON_API valueToString ( double value );
|
std::string valueToString ( double value );
|
||||||
std::string JSON_API valueToString ( bool value );
|
std::string valueToString ( bool value );
|
||||||
std::string JSON_API valueToQuotedString ( const char* value );
|
std::string valueToQuotedString ( const char* value );
|
||||||
|
|
||||||
/// \brief Output using the StyledStreamWriter.
|
/// \brief Output using the StyledStreamWriter.
|
||||||
/// \see Json::operator>>()
|
/// \see Json::operator>>()
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#ifndef RIPPLE_JSON_TO_STRING_H_INCLUDED
|
#ifndef RIPPLE_JSON_TO_STRING_H_INCLUDED
|
||||||
#define RIPPLE_JSON_TO_STRING_H_INCLUDED
|
#define RIPPLE_JSON_TO_STRING_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/json/json_config.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ struct WriteJson_test : TestOutputSuite
|
|||||||
|
|
||||||
void run () override
|
void run () override
|
||||||
{
|
{
|
||||||
runTest ("null");
|
|
||||||
runTest ("true");
|
|
||||||
runTest ("0");
|
|
||||||
runTest ("23.5");
|
|
||||||
runTest ("string", "\"a string\"");
|
|
||||||
runTest ("empty dict", "{}");
|
runTest ("empty dict", "{}");
|
||||||
runTest ("empty array", "[]");
|
runTest ("empty array", "[]");
|
||||||
runTest ("array", "[23,4.25,true,null,\"string\"]");
|
runTest ("array", "[23,4.25,true,null,\"string\"]");
|
||||||
|
|||||||
@@ -27,12 +27,6 @@
|
|||||||
|
|
||||||
// For json/
|
// For json/
|
||||||
//
|
//
|
||||||
#ifdef JSON_USE_CPPTL
|
|
||||||
#include <cpptl/conststring.h>
|
|
||||||
#endif
|
|
||||||
#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
|
||||||
#include <ripple/json/impl/json_batchallocator.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JSON_ASSERT_UNREACHABLE assert( false )
|
#define JSON_ASSERT_UNREACHABLE assert( false )
|
||||||
#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
|
#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
|
||||||
|
|||||||
Reference in New Issue
Block a user