diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 880b040..a44c0ea 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1259,7 +1259,7 @@ int z = a[0u].GetInt(); // This works too. } private: - template + template friend class GenericDocument; enum { @@ -1406,11 +1406,12 @@ typedef GenericValue > 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 > +template , typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue { 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(1))->~ValueType(); else stack_.Clear(); + stack_.ShrinkToFit(); } static const size_t kDefaultStackCapacity = 1024; - internal::Stack stack_; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; ParseResult parseResult_; }; diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 0606ccf..2fb5cf2 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -28,48 +28,58 @@ using namespace rapidjson; -TEST(Document, Parse) { - Document doc; +template +void ParseTest() { + typedef GenericDocument, 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, CrtAllocator>(); + ParseTest, MemoryPoolAllocator<> >(); + ParseTest >(); + ParseTest(); +} + static FILE* OpenEncodedFile(const char* filename) { char buffer[1024]; sprintf(buffer, "encodings/%s", filename);