Kaynağa Gözat

[add] optional type
[add] Cursor management (expirimental)

isundil 9 yıl önce
ebeveyn
işleme
d24fcf1026

+ 7 - 0
include/curseOutput.hh

@@ -1,6 +1,7 @@
 #pragma once
 
 class JSonElement;
+template<class T> class Optional;
 
 class CurseOutput
 {
@@ -10,6 +11,9 @@ class CurseOutput
 
         void run();
 
+    private:
+        typedef Optional<std::pair<Optional<const std::string>, const JSonElement *> > t_nextKey;
+
     protected:
         void init();
         void shutdown();
@@ -17,13 +21,16 @@ class CurseOutput
         void redraw(std::pair<int, int> &, const std::pair<int, int>&, const JSonElement *);
         bool readInput();
         void getScreenSize(std::pair<int, int> &);
+        static CurseOutput::t_nextKey findNext(const JSonElement *);
         void write(const int &x, const int &y, JSonElement *item);
         void write(const int &x, const int &y, const std::string &item);
+        void writeKey(const std::string &key, std::pair<int, int> &cursor);
 
         unsigned int offset_x;
         unsigned int offset_y;
 
         const JSonElement *data;
+        std::pair<std::pair<unsigned int, unsigned int>, const JSonElement *> topleft;
         const unsigned int indentLevel;
 };
 

+ 1 - 0
include/jsonArray.hh

@@ -6,6 +6,7 @@
 class JSonArray: public JSonContainer, public std::list<JSonElement *>
 {
     public:
+        JSonArray(JSonContainer *parent);
         virtual ~JSonArray();
         virtual unsigned int size() const;
 };

+ 1 - 0
include/jsonContainer.hh

@@ -5,6 +5,7 @@
 class JSonContainer: public JSonElement
 {
     public:
+        JSonContainer(JSonContainer *parent);
         virtual ~JSonContainer();
         virtual unsigned int size() const =0;
 

+ 10 - 0
include/jsonElement.hh

@@ -2,11 +2,21 @@
 
 #include <string>
 
+class JSonContainer;
+
 class JSonElement
 {
     public:
+        JSonElement(JSonContainer *parent);
         virtual ~JSonElement();
 
         virtual std::string stringify() const =0;
+        unsigned int getLevel() const;
+        JSonContainer *getParent();
+        const JSonContainer *getParent() const;
+
+    private:
+        JSonElement();
+        JSonContainer *parent;
 };
 

+ 1 - 0
include/jsonObject.hh

@@ -8,6 +8,7 @@ template<typename T> class JSonPrimitive;
 class JSonObject: public JSonContainer, public std::map<std::string, JSonElement*>
 {
     public:
+        JSonObject(JSonContainer *parent);
         virtual ~JSonObject();
 
         void push(const std::string &key, JSonElement *child);

+ 2 - 2
include/jsonPrimitive.hh

@@ -6,7 +6,7 @@ template <typename T>
 class JSonPrimitive: public JSonElement
 {
     public:
-        JSonPrimitive(T const &v);
+        JSonPrimitive(JSonContainer *parent, T const &v);
         virtual ~JSonPrimitive();
 
         T getValue() const;
@@ -20,7 +20,7 @@ class JSonPrimitive: public JSonElement
 };
 
 template<typename T>
-JSonPrimitive<T>::JSonPrimitive(T const &v): value(v)
+JSonPrimitive<T>::JSonPrimitive(JSonContainer *parent, T const &v): JSonElement(parent), value(v)
 { }
 
 template<typename T>

+ 29 - 0
include/optional.hpp

@@ -0,0 +1,29 @@
+#pragma once
+
+template<class T>
+class Optional
+{
+    public:
+        Optional(): _empty(true)
+        { };
+
+        Optional(T v): _empty(false), _value(v)
+        { }
+
+        T value() const
+        { return _value; }
+
+        bool isPresent() const
+        { return !_empty; }
+
+        bool isAbsent() const
+        { return _empty; }
+
+    static Optional<T> empty()
+        { return Optional<T>(); }
+
+    private:
+        bool _empty;
+        T _value;
+};
+

+ 4 - 4
include/streamConsumer.hh

@@ -18,11 +18,11 @@ class StreamConsumer
         /**
          * @return true on success
         **/
-        JSonElement *consumeToken(std::string &buf);
-        JSonElement *readNext();
+        JSonElement *consumeToken(JSonContainer *parent, std::string &buf);
+        JSonElement *readNext(JSonContainer *parent);
 
-        JSonObject *readObject();
-        JSonArray *readArray();
+        JSonObject *readObject(JSonContainer *parent);
+        JSonArray *readArray(JSonContainer *parent);
         bool ignoreChar(char c) const noexcept;
 
         std::istream &stream;

+ 93 - 17
src/curseOutput.cpp

@@ -7,6 +7,7 @@
 #include "jsonObject.hh"
 #include "jsonArray.hh"
 #include "jsonPrimitive.hh"
+#include "optional.hpp"
 
 CurseOutput::CurseOutput(JSonElement *root): data(root), indentLevel(4)
 { }
@@ -29,34 +30,107 @@ void CurseOutput::run()
 void CurseOutput::redraw()
 {
     std::pair<int, int> screenSize;
-    std::pair<int, int> cursor(0, 0);
+    std::pair<int, int> cursor(topleft.second->getLevel() * indentLevel, 0);
 
-    redraw(cursor, screenSize, data);
+    redraw(cursor, screenSize, topleft.second);
 }
 
-void CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<int, int> &maxSize, const JSonElement *item)
+CurseOutput::t_nextKey CurseOutput::findNext(const JSonElement *item)
 {
-    if (dynamic_cast<const JSonObject*>(item) != nullptr)
+    const JSonContainer *parent = item->getParent();
+    if (parent == nullptr)
+        return t_nextKey::empty(); // Root node, can't have brothers
+    if (dynamic_cast<const JSonObject *>(parent) != nullptr)
     {
-        for (JSonObject::const_iterator i = ((JSonObject *)item)->cbegin(); i != ((JSonObject *)item)->cend(); ++i)
+        const JSonObject *oParent = (const JSonObject *) parent;
+        JSonObject::const_iterator it = oParent->cbegin();
+        while (it != oParent->cend())
         {
-            const std::pair<std::string, JSonElement *> ipair = *i;
-            std::string key = ipair.first;
-            write(cursor.first, cursor.second, key +": ");
-            cursor.first += indentLevel;
-            cursor.second++;
-            redraw(cursor, maxSize, ipair.second);
-            cursor.first -= indentLevel;
+            if ((*it).second == item)
+            {
+                it++;
+                if (it == oParent->cend())
+                    return t_nextKey::empty(); // Last item
+                return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>((*it).first, (*it).second));
+            }
+            it++;
         }
+        return t_nextKey::empty();
     }
-    else if (dynamic_cast<const JSonArray*>(item) != nullptr)
+    if (dynamic_cast<const JSonArray *>(parent) != nullptr)
     {
+        const JSonArray *aParent = (const JSonArray *) parent;
+        JSonArray::const_iterator it = aParent->cbegin();
+        while (it != aParent->cend())
+        {
+            if (*it == item)
+            {
+                it++;
+                if (it == aParent->cend())
+                    return t_nextKey::empty(); // Last item
+                return t_nextKey(std::pair<Optional<const std::string>, const JSonElement *>(Optional<const std::string>::empty(), *it));
+            }
+            it++;
+        }
+        return t_nextKey::empty();
     }
-    else
+    return t_nextKey::empty(); // Primitive, can't have child (impossible)
+}
+
+void CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<int, int> &maxSize, const JSonElement *item)
+{
+    do
     {
-        write(cursor.first, cursor.second, item->stringify());
-        cursor.second++;
-    }
+        if (dynamic_cast<const JSonObject*>(item) != nullptr)
+        {
+            cursor.first += indentLevel /2;
+            write(cursor.first, cursor.second, "{");
+            cursor.first += indentLevel /2;
+            cursor.second++;
+            for (JSonObject::const_iterator i = ((JSonObject *)item)->cbegin(); i != ((JSonObject *)item)->cend(); ++i)
+            {
+                const std::pair<std::string, JSonElement *> ipair = *i;
+                writeKey(ipair.first, cursor);
+                redraw(cursor, maxSize, ipair.second);
+                cursor.first -= indentLevel;
+            }
+            cursor.first -= indentLevel /2;
+            write(cursor.first, cursor.second, "}");
+            cursor.first -= indentLevel /2;
+            cursor.second++;
+        }
+        else if (dynamic_cast<const JSonArray*>(item) != nullptr)
+        {
+            cursor.first += indentLevel /2;
+            write(cursor.first, cursor.second, "[");
+            cursor.first += indentLevel /2;
+            cursor.second++;
+            for (JSonArray::const_iterator i = ((JSonArray *)item)->cbegin(); i != ((JSonArray *)item)->cend(); ++i)
+                redraw(cursor, maxSize, *i);
+            cursor.first -= indentLevel /2;
+            write(cursor.first, cursor.second, "]");
+            cursor.first -= indentLevel /2;
+            cursor.second++;
+        }
+        else
+        {
+            write(cursor.first, cursor.second, item->stringify());
+            cursor.second++;
+        }
+        t_nextKey next = findNext(item);
+        if (next.isAbsent())
+            break;
+        if (next.value().first.isPresent())
+            writeKey(next.value().first.value(), cursor);
+        item = next.value().second;
+    } while (true);
+}
+
+void CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor)
+{
+    write(cursor.first, cursor.second, key +": ");
+    cursor.first += indentLevel;
+    cursor.second++;
 }
 
 void CurseOutput::write(const int &x, const int &y, JSonElement *item)
@@ -89,6 +163,8 @@ void CurseOutput::init()
     initscr();
     noecho();
     curs_set(false);
+    topleft.first = std::pair<unsigned int, unsigned int>(0, 0);
+    topleft.second = data;
 }
 
 void CurseOutput::shutdown()

+ 3 - 0
src/jsonArray.cpp

@@ -1,5 +1,8 @@
 #include "jsonArray.hh"
 
+JSonArray::JSonArray(JSonContainer *p): JSonContainer(p)
+{ }
+
 JSonArray::~JSonArray()
 {
     for (iterator i = begin(); i != end(); ++i)

+ 3 - 0
src/jsonContainer.cpp

@@ -1,5 +1,8 @@
 #include "jsonContainer.hh"
 
+JSonContainer::JSonContainer(JSonContainer *p):JSonElement(p)
+{ }
+
 JSonContainer::~JSonContainer()
 { }
 

+ 22 - 0
src/jsonElement.cpp

@@ -1,5 +1,27 @@
 #include "jsonElement.hh"
+#include "jsonContainer.hh"
+
+JSonElement::JSonElement(JSonContainer *p): parent(p)
+{ }
 
 JSonElement::~JSonElement()
 { }
 
+unsigned int JSonElement::getLevel() const
+{
+    unsigned int level = 0;
+    for (const JSonElement *parent = this; parent; parent = parent->parent)
+        level++;
+    return level;
+}
+
+JSonContainer *JSonElement::getParent()
+{
+    return parent;
+}
+
+const JSonContainer *JSonElement::getParent() const
+{
+    return parent;
+}
+

+ 3 - 0
src/jsonObject.cpp

@@ -1,6 +1,9 @@
 #include "jsonObject.hh"
 #include "jsonPrimitive.hh"
 
+JSonObject::JSonObject(JSonContainer *p): JSonContainer(p)
+{ }
+
 JSonObject::~JSonObject()
 {
     for (iterator i = begin(); i != end(); ++i)

+ 34 - 34
src/streamConsumer.cpp

@@ -15,24 +15,24 @@ StreamConsumer::~StreamConsumer()
 StreamConsumer *StreamConsumer::read(std::istream &stream)
 {
     StreamConsumer *inst = new StreamConsumer(stream);
-    inst->root = inst->readNext();
+    inst->root = inst->readNext(nullptr);
     return inst;
 }
 
-JSonElement *StreamConsumer::readNext()
+JSonElement *StreamConsumer::readNext(JSonContainer *parent)
 {
     std::string buf;
-    JSonElement *root = consumeToken(buf);
+    JSonElement *root = consumeToken(parent, buf);
 
     if (root == nullptr)
     {
         if (buf == "{")
         {
-            return readObject();
+            return readObject(parent);
         }
         else if (buf == "[")
         {
-            return readArray();
+            return readArray(parent);
         }
         else
             return nullptr;
@@ -45,7 +45,7 @@ JSonElement * const StreamConsumer::getRoot() const
     return root;
 }
 
-JSonObject *StreamConsumer::readObject()
+JSonObject *StreamConsumer::readObject(JSonContainer *parent)
 {
     JSonElement *keyObj;
     JSonObject *result = nullptr;
@@ -53,54 +53,54 @@ JSonObject *StreamConsumer::readObject()
 
     do
     {
-        keyObj = consumeToken(buf);
+        keyObj = consumeToken(parent, buf);
         if (result == nullptr && keyObj == nullptr && buf == "}")
-            return new JSonObject();
+            return new JSonObject(parent);
         JSonPrimitive<std::string> *key = dynamic_cast<JSonPrimitive<std::string> *>(keyObj);
         if (key == nullptr)
-            throw new JsonException(stream.tellg());
-        if (consumeToken(buf) != nullptr || buf != ":")
-            throw new JsonException(stream.tellg());
-        JSonElement *child = readNext();
+            throw JsonException(stream.tellg());
+        if (consumeToken(parent, buf) != nullptr || buf != ":")
+            throw JsonException(stream.tellg());
+        JSonElement *child = readNext(parent);
         if (result == nullptr)
-            result = new JSonObject();
+            result = new JSonObject(parent);
         else if (result->contains(key->getValue()))
-            throw new JsonException(stream.tellg()); //Double key
+            throw JsonException(stream.tellg()); //Double key
         result->push(key->getValue(), child);
         delete keyObj;
-        keyObj = consumeToken(buf);
+        keyObj = consumeToken(parent, buf);
     } while (!keyObj && buf != "}");
     return result;
 }
 
-JSonArray *StreamConsumer::readArray()
+JSonArray *StreamConsumer::readArray(JSonContainer *parent)
 {
     JSonArray *result = nullptr;
-    JSonElement *child = readNext();
+    JSonElement *child = readNext(parent);
     std::string buf;
 
     if (child == nullptr && buf == "]")
-        return new JSonArray(); //Empty object
+        return new JSonArray(parent); //Empty object
     do
     {
         if (child == nullptr)
-            throw new JsonException(stream.tellg());
+            throw JsonException(stream.tellg());
         if (result == nullptr)
-            result = new JSonArray();
+            result = new JSonArray(parent);
         result->push_back(child);
-        child = consumeToken(buf);
+        child = consumeToken(parent, buf);
         if (child != nullptr)
-            throw new JsonException(stream.tellg());
+            throw JsonException(stream.tellg());
         else if (buf == "]")
             break;
         else if (buf != ",")
-            throw new JsonException(stream.tellg());
-        child = consumeToken(buf);
+            throw JsonException(stream.tellg());
+        child = consumeToken(parent, buf);
     } while (true);
     return result;
 }
 
-JSonElement *StreamConsumer::consumeToken(std::string &buf)
+JSonElement *StreamConsumer::consumeToken(JSonContainer *parent, std::string &buf)
 {
     bool escaped = false;
     bool inString = false;
@@ -117,7 +117,7 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
             if (!escaped)
             {
                 if (c == '"')
-                    return new JSonPrimitive<std::string>(buf);
+                    return new JSonPrimitive<std::string>(parent, buf);
                 else if (c == '\\')
                     escaped = true;
                 else
@@ -128,7 +128,7 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
                 if (c == '\\' || c == '"')
                     buf += c;
                 else
-                    throw new JsonEscapedException(c, stream.tellg());
+                    throw JsonEscapedException(c, stream.tellg());
             }
         }
         else if (inBool)
@@ -138,17 +138,17 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
             else if (buf == "true")
             {
                 stream.unget();
-                return new JSonPrimitive<bool>(true);
+                return new JSonPrimitive<bool>(parent, true);
             }
             else if (buf == "false")
             {
                 stream.unget();
-                return new JSonPrimitive<bool>(false);
+                return new JSonPrimitive<bool>(parent, false);
             }
             else if (ignoreChar(c))
                 ;
             else
-                throw new JsonFormatException(c, stream.tellg());
+                throw JsonFormatException(c, stream.tellg());
         }
         else if (inNumber)
         {
@@ -163,14 +163,14 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
             {
                 stream.unget();
                 if (numberIsFloat)
-                    return new JSonPrimitive<float>(std::stof(buf));
+                    return new JSonPrimitive<float>(parent, std::stof(buf));
                 try
                 {
-                    return new JSonPrimitive<int>(std::stoi(buf));
+                    return new JSonPrimitive<int>(parent, std::stoi(buf));
                 }
                 catch(std::out_of_range e)
                 {
-                    return new JSonPrimitive<long long>(std::stol(buf));
+                    return new JSonPrimitive<long long>(parent, std::stol(buf));
                 }
             }
         }
@@ -198,7 +198,7 @@ JSonElement *StreamConsumer::consumeToken(std::string &buf)
                 inNumber = true;
             }
             else if (!ignoreChar(c))
-                throw new JsonFormatException(c, stream.tellg());
+                throw JsonFormatException(c, stream.tellg());
         }
     }
     buf = "";