Commit 941aa93f authored by Milo Yip's avatar Milo Yip

Separate Document's value and stack allocator.

Use CrtAllocator for stack.
ShrinkToFit stack after parsing.
parent 37140198
...@@ -1259,7 +1259,7 @@ int z = a[0u].GetInt(); // This works too. ...@@ -1259,7 +1259,7 @@ int z = a[0u].GetInt(); // This works too.
} }
private: private:
template <typename, typename> template <typename, typename, typename>
friend class GenericDocument; friend class GenericDocument;
enum { enum {
...@@ -1406,11 +1406,12 @@ typedef GenericValue<UTF8<> > Value; ...@@ -1406,11 +1406,12 @@ typedef GenericValue<UTF8<> > Value;
//! A document for parsing JSON text as DOM. //! A document for parsing JSON text as DOM.
/*! /*!
\note implements Handler concept \note implements Handler concept
\tparam Encoding encoding for both parsing and string storage. \tparam Encoding Encoding for both parsing and string storage.
\tparam Allocator allocator for allocating memory for the DOM, and the stack during parsing. \tparam Allocator Allocator for allocating memory for the DOM
\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 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> { class GenericDocument : public GenericValue<Encoding, Allocator> {
public: public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
...@@ -1418,10 +1419,20 @@ public: ...@@ -1418,10 +1419,20 @@ public:
typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! Constructor //! Constructor
/*! \param allocator Optional allocator for allocating stack memory. /*! \param allocator Optional allocator for allocating memory.
\param stackCapacity Initial capacity of stack in bytes. \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 //!@name Parse from stream
//!@{ //!@{
...@@ -1549,7 +1560,7 @@ public: ...@@ -1549,7 +1560,7 @@ public:
//!@} //!@}
//! Get the allocator of this document. //! Get the allocator of this document.
Allocator& GetAllocator() { return stack_.GetAllocator(); } Allocator& GetAllocator() { return *allocator_; }
//! Get the capacity of stack in bytes. //! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); } size_t GetStackCapacity() const { return stack_.GetCapacity(); }
...@@ -1612,10 +1623,13 @@ private: ...@@ -1612,10 +1623,13 @@ private:
(stack_.template Pop<ValueType>(1))->~ValueType(); (stack_.template Pop<ValueType>(1))->~ValueType();
else else
stack_.Clear(); stack_.Clear();
stack_.ShrinkToFit();
} }
static const size_t kDefaultStackCapacity = 1024; static const size_t kDefaultStackCapacity = 1024;
internal::Stack<Allocator> stack_; Allocator* allocator_;
Allocator* ownAllocator_;
internal::Stack<StackAllocator> stack_;
ParseResult parseResult_; ParseResult parseResult_;
}; };
......
...@@ -28,48 +28,58 @@ ...@@ -28,48 +28,58 @@
using namespace rapidjson; using namespace rapidjson;
TEST(Document, Parse) { template <typename Allocator, typename StackAllocator>
Document doc; 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] } "); 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.IsObject());
EXPECT_TRUE(doc.HasMember("hello")); EXPECT_TRUE(doc.HasMember("hello"));
Value& hello = doc["hello"]; const ValueType& hello = doc["hello"];
EXPECT_TRUE(hello.IsString()); EXPECT_TRUE(hello.IsString());
EXPECT_STREQ("world", hello.GetString()); EXPECT_STREQ("world", hello.GetString());
EXPECT_TRUE(doc.HasMember("t")); EXPECT_TRUE(doc.HasMember("t"));
Value& t = doc["t"]; const ValueType& t = doc["t"];
EXPECT_TRUE(t.IsTrue()); EXPECT_TRUE(t.IsTrue());
EXPECT_TRUE(doc.HasMember("f")); EXPECT_TRUE(doc.HasMember("f"));
Value& f = doc["f"]; const ValueType& f = doc["f"];
EXPECT_TRUE(f.IsFalse()); EXPECT_TRUE(f.IsFalse());
EXPECT_TRUE(doc.HasMember("n")); EXPECT_TRUE(doc.HasMember("n"));
Value& n = doc["n"]; const ValueType& n = doc["n"];
EXPECT_TRUE(n.IsNull()); EXPECT_TRUE(n.IsNull());
EXPECT_TRUE(doc.HasMember("i")); EXPECT_TRUE(doc.HasMember("i"));
Value& i = doc["i"]; const ValueType& i = doc["i"];
EXPECT_TRUE(i.IsNumber()); EXPECT_TRUE(i.IsNumber());
EXPECT_EQ(123, i.GetInt()); EXPECT_EQ(123, i.GetInt());
EXPECT_TRUE(doc.HasMember("pi")); EXPECT_TRUE(doc.HasMember("pi"));
Value& pi = doc["pi"]; const ValueType& pi = doc["pi"];
EXPECT_TRUE(pi.IsNumber()); EXPECT_TRUE(pi.IsNumber());
EXPECT_EQ(3.1416, pi.GetDouble()); EXPECT_EQ(3.1416, pi.GetDouble());
EXPECT_TRUE(doc.HasMember("a")); EXPECT_TRUE(doc.HasMember("a"));
Value& a = doc["a"]; const ValueType& a = doc["a"];
EXPECT_TRUE(a.IsArray()); EXPECT_TRUE(a.IsArray());
EXPECT_EQ(4u, a.Size()); EXPECT_EQ(4u, a.Size());
for (SizeType i = 0; i < 4; i++) for (SizeType i = 0; i < 4; i++)
EXPECT_EQ(i + 1, a[i].GetUint()); 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) { static FILE* OpenEncodedFile(const char* filename) {
char buffer[1024]; char buffer[1024];
sprintf(buffer, "encodings/%s", filename); sprintf(buffer, "encodings/%s", filename);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment