Jelajahi Sumber

Add Pointer default/copy constructor, assignment operator. Test constructor with tokens

Milo Yip 10 tahun lalu
induk
melakukan
cf0ff19cac
2 mengubah file dengan 130 tambahan dan 6 penghapusan
  1. 54 6
      include/rapidjson/pointer.h
  2. 76 0
      test/unittest/pointertest.cpp

+ 54 - 6
include/rapidjson/pointer.h

@@ -33,6 +33,16 @@ public:
 
     static const SizeType kInvalidIndex = ~SizeType(0);
 
+    GenericPointer()
+        : allocator_(),
+        ownAllocator_(),
+        nameBuffer_(),
+        tokens_(),
+        tokenCount_(),
+        valid_(true)
+    {
+    }
+
     GenericPointer(const Ch* source, Allocator* allocator = 0) 
         : allocator_(allocator),
           ownAllocator_(),
@@ -55,16 +65,27 @@ public:
         Parse(source, length);
     }
 
-    GenericPointer(const Token* tokens, size_t tokenCount) : 
+    GenericPointer(const Token* tokens, size_t tokenCount)
         : allocator_(),
           ownAllocator_(),
           nameBuffer_(),
-          tokens_(tokens),
+          tokens_(const_cast<Token*>(tokens)),
           tokenCount_(tokenCount),
           valid_(true)
     {
     }
 
+    GenericPointer(const GenericPointer& rhs)
+        : allocator_(),
+          ownAllocator_(),
+          nameBuffer_(),
+          tokens_(),
+          tokenCount_(),
+          valid_()
+    {
+        *this = rhs;
+    }
+
     ~GenericPointer() {
         if (nameBuffer_) {
             Allocator::Free(nameBuffer_);
@@ -73,6 +94,36 @@ public:
         RAPIDJSON_DELETE(ownAllocator_);
     }
 
+    GenericPointer& operator=(const GenericPointer& rhs) {
+        this->~GenericPointer();
+
+        tokenCount_ = rhs.tokenCount_;
+        valid_ = rhs.valid_;
+
+        if (rhs.nameBuffer_) {
+            if (!allocator_)
+                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+            size_t nameBufferSize = tokenCount_; // null terminators
+            for (Token *t = rhs.tokens_; t != rhs.tokens_ + tokenCount_; ++t)
+                nameBufferSize += t->length;
+            nameBuffer_ = (Ch*)allocator_->Malloc(nameBufferSize * sizeof(Ch));
+            std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize);
+
+            tokens_ = (Token*)allocator_->Malloc(tokenCount_ * sizeof(Token));
+            std::memcpy(tokens_, rhs.tokens_, tokenCount_ * sizeof(Token));
+
+            // Adjust pointers to name buffer
+            std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
+            for (Token *t = rhs.tokens_; t != rhs.tokens_ + tokenCount_; ++t)
+                t->name += diff;
+        }
+        else
+            tokens_ = rhs.tokens_;
+
+        return *this;
+    }
+
     bool IsValid() const { return valid_; }
 
     const Token* GetTokens() const { return tokens_; }
@@ -192,7 +243,7 @@ private:
 
         // Create a buffer as same size of source
         RAPIDJSON_ASSERT(nameBuffer_ == 0);
-        nameBuffer_ = (Ch*)allocator_->Malloc(length);
+        nameBuffer_ = (Ch*)allocator_->Malloc(length * sizeof(Ch));
 
         RAPIDJSON_ASSERT(tokens_ == 0);
         tokens_ = (Token*)allocator_->Malloc(length * sizeof(Token)); // Maximum possible tokens in the source
@@ -266,9 +317,6 @@ private:
         return;
     }
 
-    GenericPointer(const GenericPointer& rhs);
-    GenericPointer& operator=(const GenericPointer& rhs);
-
     Allocator* allocator_;
     Allocator* ownAllocator_;
     Ch* nameBuffer_;

+ 76 - 0
test/unittest/pointertest.cpp

@@ -166,6 +166,82 @@ TEST(Pointer, Stringify) {
     }
 }
 
+// Construct a Pointer with static tokens, no dynamic allocation involved.
+#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, Pointer::kInvalidIndex }
+#define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0"
+
+#undef NAME
+#undef INDEX
+
+TEST(Pointer, ConstructorWithToken) {
+    Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+    EXPECT_TRUE(p.IsValid());
+    EXPECT_EQ(2, p.GetTokenCount());
+    EXPECT_EQ(3, p.GetTokens()[0].length);
+    EXPECT_STREQ("foo", p.GetTokens()[0].name);
+    EXPECT_EQ(1, p.GetTokens()[1].length);
+    EXPECT_STREQ("0", p.GetTokens()[1].name);
+    EXPECT_EQ(0, p.GetTokens()[1].index);
+}
+
+TEST(Pointer, CopyConstructor) {
+    {
+        Pointer p("/foo/0");
+        Pointer q(p);
+        EXPECT_TRUE(q.IsValid());
+        EXPECT_EQ(2, q.GetTokenCount());
+        EXPECT_EQ(3, q.GetTokens()[0].length);
+        EXPECT_STREQ("foo", q.GetTokens()[0].name);
+        EXPECT_EQ(1, q.GetTokens()[1].length);
+        EXPECT_STREQ("0", q.GetTokens()[1].name);
+        EXPECT_EQ(0, q.GetTokens()[1].index);
+    }
+
+    // Static tokens
+    {
+        Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+        Pointer q(p);
+        EXPECT_TRUE(q.IsValid());
+        EXPECT_EQ(2, q.GetTokenCount());
+        EXPECT_EQ(3, q.GetTokens()[0].length);
+        EXPECT_STREQ("foo", q.GetTokens()[0].name);
+        EXPECT_EQ(1, q.GetTokens()[1].length);
+        EXPECT_STREQ("0", q.GetTokens()[1].name);
+        EXPECT_EQ(0, q.GetTokens()[1].index);
+    }
+}
+
+TEST(Pointer, Assignment) {
+    {
+        Pointer p("/foo/0");
+        Pointer q;
+        q = p;
+        EXPECT_TRUE(q.IsValid());
+        EXPECT_EQ(2, q.GetTokenCount());
+        EXPECT_EQ(3, q.GetTokens()[0].length);
+        EXPECT_STREQ("foo", q.GetTokens()[0].name);
+        EXPECT_EQ(1, q.GetTokens()[1].length);
+        EXPECT_STREQ("0", q.GetTokens()[1].name);
+        EXPECT_EQ(0, q.GetTokens()[1].index);
+    }
+
+    // Static tokens
+    {
+        Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+        Pointer q;
+        q = p;
+        EXPECT_TRUE(q.IsValid());
+        EXPECT_EQ(2, q.GetTokenCount());
+        EXPECT_EQ(3, q.GetTokens()[0].length);
+        EXPECT_STREQ("foo", q.GetTokens()[0].name);
+        EXPECT_EQ(1, q.GetTokens()[1].length);
+        EXPECT_STREQ("0", q.GetTokens()[1].name);
+        EXPECT_EQ(0, q.GetTokens()[1].index);
+    }
+}
+
 TEST(Pointer, Create) {
     Document d;
     EXPECT_EQ(&d, &Pointer("").Create(d, d.GetAllocator()));