[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - 2 commits - include/tools tools/qa tools/source

Noel Grandin (via logerrit) logerrit at kemper.freedesktop.org
Mon Aug 10 21:07:53 UTC 2020


 include/tools/json_writer.hxx         |   66 +++++++++++++++++---
 tools/qa/cppunit/test_json_writer.cxx |   38 ++++++++++-
 tools/source/misc/json_writer.cxx     |  112 ++++++++++++++++++++++++++++++----
 3 files changed, 190 insertions(+), 26 deletions(-)

New commits:
commit f271eca1eb24ed28658afe4c73d71cbf77a78dec
Author:     Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Wed Jun 24 18:24:37 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Aug 10 23:07:32 2020 +0200

    fix JsonWriter::reallocBuffer
    
    was not updating mSpaceAllocated
    
    Change-Id: Ie5404e58c6520d32b72c19ddfa58b2ab2b895199
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97049
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
    (cherry picked from commit 3fb5c11ac69e6687e579d4129cb892c5ae746a5e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100445
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/tools/source/misc/json_writer.cxx b/tools/source/misc/json_writer.cxx
index 251c44c0246f..f2b008ea6fd2 100644
--- a/tools/source/misc/json_writer.cxx
+++ b/tools/source/misc/json_writer.cxx
@@ -320,6 +320,7 @@ void JsonWriter::reallocBuffer(int noMoreBytesRequired)
     free(mpBuffer);
     mpBuffer = pNew;
     mPos = mpBuffer + currentUsed;
+    mSpaceAllocated = newSize;
 }
 
 /** Hands ownership of the underlying storage buffer to the caller,
commit 29954dbeb16ef206940a8fe7ed94e487f842d17a
Author:     Noel Grandin <noelgrandin at gmail.com>
AuthorDate: Thu Jun 18 21:39:30 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Mon Aug 10 23:07:20 2020 +0200

    improvements to JSON Writer
    
    part of the master commit cb95276e6e6bf12a1c06d5c252551e55c788fcb2
    
    Change-Id: Icf18fb4b3ebced375196a8cdbd2a543acf4e43c5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100444
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/include/tools/json_writer.hxx b/include/tools/json_writer.hxx
index 588577d41303..bf07aa0aaa35 100644
--- a/include/tools/json_writer.hxx
+++ b/include/tools/json_writer.hxx
@@ -13,6 +13,11 @@
 #include <memory>
 #include <algorithm>
 
+namespace rtl
+{
+class OStringBuffer;
+}
+
 /** Simple JSON encoder designed specifically for LibreOfficeKit purposes.
  *
  * (1) Minimal allocations/re-allocations/copying
@@ -22,10 +27,14 @@
 namespace tools
 {
 class ScopedJsonWriterNode;
+class ScopedJsonWriterArray;
+class ScopedJsonWriterStruct;
 
 class TOOLS_DLLPUBLIC JsonWriter
 {
     friend class ScopedJsonWriterNode;
+    friend class ScopedJsonWriterArray;
+    friend class ScopedJsonWriterStruct;
 
     int mSpaceAllocated;
     char* mpBuffer;
@@ -38,33 +47,36 @@ public:
     ~JsonWriter();
 
     [[nodiscard]] ScopedJsonWriterNode startNode(const char*);
+    [[nodiscard]] ScopedJsonWriterArray startArray(const char*);
+    [[nodiscard]] ScopedJsonWriterStruct startStruct();
 
     void put(const char* pPropName, const OUString& rPropValue);
     void put(const char* pPropName, const OString& rPropValue);
     void put(const char* pPropName, const char* pPropVal);
     void put(const char*, int);
 
-    /** Hands ownership of the the underlying storage buffer to the caller,
+    /// This assumes that this data belongs at this point in the stream, and is valid, and properly encoded
+    void putRaw(const rtl::OStringBuffer&);
+
+    /** Hands ownership of the underlying storage buffer to the caller,
      * after this no more document modifications may be written. */
     char* extractData();
     OString extractAsOString();
 
 private:
     void endNode();
+    void endArray();
+    void endStruct();
     void addCommaBeforeField();
+    void reallocBuffer(int noMoreBytesRequired);
 
+    // this part inline to speed up the fast path
     inline void ensureSpace(int noMoreBytesRequired)
     {
+        assert(mpBuffer && "already extracted data");
         int currentUsed = mPos - mpBuffer;
         if (currentUsed + noMoreBytesRequired >= mSpaceAllocated)
-        {
-            auto newSize = std::max(mSpaceAllocated * 2, (currentUsed + noMoreBytesRequired) * 2);
-            char* pNew = static_cast<char*>(malloc(newSize));
-            memcpy(pNew, mpBuffer, currentUsed);
-            free(mpBuffer);
-            mpBuffer = pNew;
-            mPos = mpBuffer;
-        }
+            reallocBuffer(noMoreBytesRequired);
     }
 };
 
@@ -85,5 +97,41 @@ class ScopedJsonWriterNode
 public:
     ~ScopedJsonWriterNode() { mrWriter.endNode(); }
 };
+
+/**
+ * Auto-closes the node.
+ */
+class ScopedJsonWriterArray
+{
+    friend class JsonWriter;
+
+    JsonWriter& mrWriter;
+
+    ScopedJsonWriterArray(JsonWriter& rWriter)
+        : mrWriter(rWriter)
+    {
+    }
+
+public:
+    ~ScopedJsonWriterArray() { mrWriter.endArray(); }
+};
+
+/**
+ * Auto-closes the node.
+ */
+class ScopedJsonWriterStruct
+{
+    friend class JsonWriter;
+
+    JsonWriter& mrWriter;
+
+    ScopedJsonWriterStruct(JsonWriter& rWriter)
+        : mrWriter(rWriter)
+    {
+    }
+
+public:
+    ~ScopedJsonWriterStruct() { mrWriter.endStruct(); }
+};
 };
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/tools/qa/cppunit/test_json_writer.cxx b/tools/qa/cppunit/test_json_writer.cxx
index e27afc95f712..6a2cc7813574 100644
--- a/tools/qa/cppunit/test_json_writer.cxx
+++ b/tools/qa/cppunit/test_json_writer.cxx
@@ -30,12 +30,19 @@ public:
     virtual void setUp() override {}
 
     void test1();
+    void test2();
 
     CPPUNIT_TEST_SUITE(JsonWriterTest);
     CPPUNIT_TEST(test1);
+    CPPUNIT_TEST(test2);
     CPPUNIT_TEST_SUITE_END();
 };
 
+struct Free
+{
+    void operator()(void* p) const { std::free(p); }
+};
+
 void JsonWriterTest::test1()
 {
     tools::JsonWriter aJson;
@@ -48,10 +55,6 @@ void JsonWriterTest::test1()
         aJson.put("int", 12);
     }
 
-    struct Free
-    {
-        void operator()(void* p) const { std::free(p); }
-    };
     std::unique_ptr<char, Free> result(aJson.extractData());
 
     CPPUNIT_ASSERT_EQUAL(std::string("{ \"node\": { \"oustring\": \"val1\", \"ostring\": \"val2\", "
@@ -59,6 +62,33 @@ void JsonWriterTest::test1()
                          std::string(result.get()));
 }
 
+void JsonWriterTest::test2()
+{
+    tools::JsonWriter aJson;
+
+    {
+        auto testNode = aJson.startNode("node");
+        aJson.put("field1", OUString("val1"));
+        aJson.put("field2", OUString("val2"));
+        {
+            auto testNode2 = aJson.startNode("node");
+            aJson.put("field3", OUString("val3"));
+            {
+                auto testNode3 = aJson.startNode("node");
+                aJson.put("field4", OUString("val4"));
+                aJson.put("field5", OUString("val5"));
+            }
+        }
+    }
+
+    std::unique_ptr<char, Free> result(aJson.extractData());
+
+    CPPUNIT_ASSERT_EQUAL(std::string("{ \"node\": { \"field1\": \"val1\", \"field2\": \"val2\", "
+                                     "\"node\": { \"field3\": \"val3\", \"node\": { \"field4\": "
+                                     "\"val4\", \"field5\": \"val5\"}}}}"),
+                         std::string(result.get()));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(JsonWriterTest);
 }
 
diff --git a/tools/source/misc/json_writer.cxx b/tools/source/misc/json_writer.cxx
index ab109dae669c..251c44c0246f 100644
--- a/tools/source/misc/json_writer.cxx
+++ b/tools/source/misc/json_writer.cxx
@@ -10,6 +10,7 @@
 #include <tools/json_writer.hxx>
 #include <stdio.h>
 #include <cstring>
+#include <rtl/strbuf.hxx>
 
 namespace tools
 {
@@ -22,6 +23,7 @@ JsonWriter::JsonWriter()
     , mpBuffer(static_cast<char*>(malloc(mSpaceAllocated)))
     , mStartNodeCount(0)
     , mPos(mpBuffer)
+    , mbFirstFieldInNode(true)
 {
     *mPos = '{';
     ++mPos;
@@ -38,7 +40,10 @@ JsonWriter::~JsonWriter()
 ScopedJsonWriterNode JsonWriter::startNode(const char* pNodeName)
 {
     auto len = strlen(pNodeName);
-    ensureSpace(len + 4);
+    ensureSpace(len + 6);
+
+    addCommaBeforeField();
+
     *mPos = '"';
     ++mPos;
     memcpy(mPos, pNodeName, len);
@@ -57,15 +62,70 @@ void JsonWriter::endNode()
     ensureSpace(1);
     *mPos = '}';
     ++mPos;
+    mbFirstFieldInNode = false;
 }
 
-void JsonWriter::put(const char* pPropName, const OUString& rPropVal)
+ScopedJsonWriterArray JsonWriter::startArray(const char* pNodeName)
+{
+    auto len = strlen(pNodeName);
+    ensureSpace(len + 6);
+
+    addCommaBeforeField();
+
+    *mPos = '"';
+    ++mPos;
+    memcpy(mPos, pNodeName, len);
+    mPos += len;
+    strncpy(mPos, "\": [ ", 5);
+    mPos += 5;
+    mStartNodeCount++;
+    mbFirstFieldInNode = true;
+    return ScopedJsonWriterArray(*this);
+}
+
+void JsonWriter::endArray()
 {
+    assert(mStartNodeCount && "mismatched StartNode/EndNode somewhere");
+    --mStartNodeCount;
+    ensureSpace(1);
+    *mPos = ']';
+    ++mPos;
+    mbFirstFieldInNode = false;
+}
+
+ScopedJsonWriterStruct JsonWriter::startStruct()
+{
+    ensureSpace(6);
+
     addCommaBeforeField();
 
+    *mPos = '{';
+    ++mPos;
+    *mPos = ' ';
+    ++mPos;
+    mStartNodeCount++;
+    mbFirstFieldInNode = true;
+    return ScopedJsonWriterStruct(*this);
+}
+
+void JsonWriter::endStruct()
+{
+    assert(mStartNodeCount && "mismatched StartNode/EndNode somewhere");
+    --mStartNodeCount;
+    ensureSpace(1);
+    *mPos = '}';
+    ++mPos;
+    mbFirstFieldInNode = false;
+}
+
+void JsonWriter::put(const char* pPropName, const OUString& rPropVal)
+{
     auto nPropNameLength = strlen(pPropName);
     auto nWorstCasePropValLength = rPropVal.getLength() * 2;
-    ensureSpace(nPropNameLength + nWorstCasePropValLength + 6);
+    ensureSpace(nPropNameLength + nWorstCasePropValLength + 8);
+
+    addCommaBeforeField();
+
     *mPos = '"';
     ++mPos;
     memcpy(mPos, pPropName, nPropNameLength);
@@ -120,11 +180,12 @@ void JsonWriter::put(const char* pPropName, const OUString& rPropVal)
 
 void JsonWriter::put(const char* pPropName, const OString& rPropVal)
 {
-    addCommaBeforeField();
-
     auto nPropNameLength = strlen(pPropName);
     auto nWorstCasePropValLength = rPropVal.getLength();
-    ensureSpace(nPropNameLength + nWorstCasePropValLength + 6);
+    ensureSpace(nPropNameLength + nWorstCasePropValLength + 8);
+
+    addCommaBeforeField();
+
     *mPos = '"';
     ++mPos;
     memcpy(mPos, pPropName, nPropNameLength);
@@ -163,12 +224,13 @@ void JsonWriter::put(const char* pPropName, const OString& rPropVal)
 
 void JsonWriter::put(const char* pPropName, const char* pPropVal)
 {
-    addCommaBeforeField();
-
     auto nPropNameLength = strlen(pPropName);
     auto nPropValLength = strlen(pPropVal);
     auto nWorstCasePropValLength = nPropValLength * 2;
-    ensureSpace(nPropNameLength + nWorstCasePropValLength + 6);
+    ensureSpace(nPropNameLength + nWorstCasePropValLength + 8);
+
+    addCommaBeforeField();
+
     *mPos = '"';
     ++mPos;
     memcpy(mPos, pPropName, nPropNameLength);
@@ -210,11 +272,12 @@ void JsonWriter::put(const char* pPropName, const char* pPropVal)
 
 void JsonWriter::put(const char* pPropName, int nPropVal)
 {
-    addCommaBeforeField();
-
     auto nPropNameLength = strlen(pPropName);
     auto nWorstCasePropValLength = 32;
-    ensureSpace(nPropNameLength + nWorstCasePropValLength + 6);
+    ensureSpace(nPropNameLength + nWorstCasePropValLength + 8);
+
+    addCommaBeforeField();
+
     *mPos = '"';
     ++mPos;
     memcpy(mPos, pPropName, nPropNameLength);
@@ -225,6 +288,16 @@ void JsonWriter::put(const char* pPropName, int nPropVal)
     mPos += sprintf(mPos, "%d", nPropVal);
 }
 
+void JsonWriter::putRaw(const rtl::OStringBuffer& rRawBuf)
+{
+    ensureSpace(rRawBuf.getLength() + 2);
+
+    addCommaBeforeField();
+
+    memcpy(mPos, rRawBuf.getStr(), rRawBuf.getLength());
+    mPos += rRawBuf.getLength();
+}
+
 void JsonWriter::addCommaBeforeField()
 {
     if (mbFirstFieldInNode)
@@ -238,12 +311,24 @@ void JsonWriter::addCommaBeforeField()
     }
 }
 
-/** Hands ownership of the the underlying storage buffer to the caller,
+void JsonWriter::reallocBuffer(int noMoreBytesRequired)
+{
+    int currentUsed = mPos - mpBuffer;
+    auto newSize = std::max<int>(mSpaceAllocated * 2, (currentUsed + noMoreBytesRequired) * 2);
+    char* pNew = static_cast<char*>(malloc(newSize));
+    memcpy(pNew, mpBuffer, currentUsed);
+    free(mpBuffer);
+    mpBuffer = pNew;
+    mPos = mpBuffer + currentUsed;
+}
+
+/** Hands ownership of the underlying storage buffer to the caller,
   * after this no more document modifications may be written. */
 char* JsonWriter::extractData()
 {
     assert(mStartNodeCount == 0 && "did not close all nodes");
     assert(mpBuffer && "data already extracted");
+    ensureSpace(2);
     // add closing brace
     *mPos = '}';
     ++mPos;


More information about the Libreoffice-commits mailing list