Separate Document's value and stack allocator.

Use CrtAllocator for stack.
ShrinkToFit stack after parsing.
This commit is contained in:
Milo Yip 2014-08-17 18:33:47 +08:00
parent 3714019819
commit 941aa93f45
2 changed files with 43 additions and 19 deletions

View File

@ -1259,7 +1259,7 @@ int z = a[0u].GetInt(); // This works too.
}
private:
template <typename, typename>
template <typename, typename, typename>
friend class GenericDocument;
enum {
@ -1406,11 +1406,12 @@ typedef GenericValue<UTF8<> > Value;
//! A document for parsing JSON text as DOM.
/*!
\note implements Handler concept
\tparam Encoding encoding for both parsing and string storage.
\tparam Allocator allocator for allocating memory for the DOM, and the stack during parsing.
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructors. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
\tparam Encoding Encoding for both parsing and string storage.
\tparam Allocator Allocator for allocating memory for the DOM
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
*/
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
class GenericDocument : public GenericValue<Encoding, Allocator> {
public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
@ -1418,10 +1419,20 @@ public:
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! Constructor
/*! \param allocator Optional allocator for allocating stack memory.
\param stackCapacity Initial capacity of stack in bytes.
/*! \param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack.
*/
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {}
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
ownAllocator_ = allocator_ = new Allocator();
}
~GenericDocument() {
delete ownAllocator_;
}
//!@name Parse from stream
//!@{
@ -1549,7 +1560,7 @@ public:
//!@}
//! Get the allocator of this document.
Allocator& GetAllocator() { return stack_.GetAllocator(); }
Allocator& GetAllocator() { return *allocator_; }
//! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
@ -1612,10 +1623,13 @@ private:
(stack_.template Pop<ValueType>(1))->~ValueType();
else
stack_.Clear();
stack_.ShrinkToFit();
}
static const size_t kDefaultStackCapacity = 1024;
internal::Stack<Allocator> stack_;
Allocator* allocator_;
Allocator* ownAllocator_;
internal::Stack<StackAllocator> stack_;
ParseResult parseResult_;
};

View File

@ -28,48 +28,58 @@
using namespace rapidjson;
TEST(Document, Parse) {
Document doc;
template <typename Allocator, typename StackAllocator>
void ParseTest() {
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
typedef DocumentType::ValueType ValueType;
DocumentType doc;
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
EXPECT_TRUE(doc.IsObject());
EXPECT_TRUE(doc.HasMember("hello"));
Value& hello = doc["hello"];
const ValueType& hello = doc["hello"];
EXPECT_TRUE(hello.IsString());
EXPECT_STREQ("world", hello.GetString());
EXPECT_TRUE(doc.HasMember("t"));
Value& t = doc["t"];
const ValueType& t = doc["t"];
EXPECT_TRUE(t.IsTrue());
EXPECT_TRUE(doc.HasMember("f"));
Value& f = doc["f"];
const ValueType& f = doc["f"];
EXPECT_TRUE(f.IsFalse());
EXPECT_TRUE(doc.HasMember("n"));
Value& n = doc["n"];
const ValueType& n = doc["n"];
EXPECT_TRUE(n.IsNull());
EXPECT_TRUE(doc.HasMember("i"));
Value& i = doc["i"];
const ValueType& i = doc["i"];
EXPECT_TRUE(i.IsNumber());
EXPECT_EQ(123, i.GetInt());
EXPECT_TRUE(doc.HasMember("pi"));
Value& pi = doc["pi"];
const ValueType& pi = doc["pi"];
EXPECT_TRUE(pi.IsNumber());
EXPECT_EQ(3.1416, pi.GetDouble());
EXPECT_TRUE(doc.HasMember("a"));
Value& a = doc["a"];
const ValueType& a = doc["a"];
EXPECT_TRUE(a.IsArray());
EXPECT_EQ(4u, a.Size());
for (SizeType i = 0; i < 4; i++)
EXPECT_EQ(i + 1, a[i].GetUint());
}
TEST(Document, Parse) {
ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
ParseTest<CrtAllocator, CrtAllocator>();
}
static FILE* OpenEncodedFile(const char* filename) {
char buffer[1024];
sprintf(buffer, "encodings/%s", filename);