Browse Source

[Fix #22] lazy compute string size to get accurate row costs
[add] inline values' col costs
[Fix] unicode stops string reading

isundil 9 years ago
parent
commit
0af7c48cec
5 changed files with 82 additions and 38 deletions
  1. 9 8
      include/curseOutput.hh
  2. 9 0
      include/jsonElement.hh
  3. 38 28
      src/curseOutput.cpp
  4. 25 1
      src/jsonElement.cpp
  5. 1 1
      src/streamConsumer.cpp

+ 9 - 8
include/curseOutput.hh

@@ -65,7 +65,7 @@ class CurseOutput
         /**
          * redraw item and children
         **/
-        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, const JSonElement *item);
+        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, JSonElement *item);
 
         /**
          * Wait for input
@@ -89,7 +89,7 @@ class CurseOutput
          * @param @maxWidth screen width
          * @return the number of line written
         **/
-        static unsigned int getNbLines(float nbChar, unsigned int maxWidth);
+        static unsigned int getNbLines(const size_t nbChar, unsigned int maxWidth);
 
         /**
          * get flags to be passed to write.
@@ -104,13 +104,14 @@ class CurseOutput
          * Warning: this one does not check line height, because he's not aware of cursor position
         **/
         void write(const std::string &str, const OutputFlag flags) const;
-        unsigned int write(const int &x, const int &y, const JSonElement *item, unsigned int maxWidth, const OutputFlag);
-        unsigned int write(const int &x, const int &y, const std::string &item, unsigned int maxWidth, const OutputFlag);
+        unsigned int write(const int &x, const int &y, JSonElement *item, unsigned int maxWidth, const OutputFlag);
+        unsigned int write(const int &x, const int &y, const std::string &item, const size_t len, unsigned int maxWidth, const OutputFlag);
         unsigned int write(const int &x, const int &y, const char item, unsigned int maxWidth, const OutputFlag);
-        bool writeKey(const std::string &key, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag, unsigned int extraLen =0);
-        bool writeKey(const std::string &key, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
+        bool writeKey(const std::string &key, const size_t keylen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag, unsigned int extraLen =0);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
         bool writeContainer(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxSize, const JSonContainer *);
-        bool writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const std::list<JSonElement *> * obj);
+        bool writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, std::list<JSonElement *> * obj);
 
         /**
          * find next search occurence and select it (wich cause viewport to move, eventually)
@@ -151,7 +152,7 @@ class CurseOutput
         /**
          * Root item
         **/
-        const JSonElement *data;
+        JSonElement * const data;
 
         /**
          * selected item

+ 9 - 0
include/jsonElement.hh

@@ -21,6 +21,13 @@ class JSonElement
          * return string-representative of this JSonElement
         **/
         virtual std::string stringify() const =0;
+
+        /**
+         * get the number of col string will output
+        **/
+        virtual size_t strlen() const;
+        virtual size_t lazystrlen();
+
         /**
          * return number of parents this item has
         **/
@@ -56,5 +63,7 @@ class JSonElement
          * Not a JSonContainer because JSonObjectEntry can be a parent and isn't a JSonContainer either
         **/
         JSonElement *parent;
+
+        size_t _strlen;
 };
 

+ 38 - 28
src/curseOutput.cpp

@@ -130,7 +130,7 @@ bool CurseOutput::redraw(const std::string &errorMsg)
     return result;
 }
 
-bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const JSonElement *item)
+bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, JSonElement *item)
 {
     checkSelection(item, cursor);
     if (dynamic_cast<const JSonContainer*>(item))
@@ -160,24 +160,24 @@ bool CurseOutput::writeContainer(std::pair<int, int> &cursor, const std::pair<un
     {
         std::string ss;
         ss.append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
-        cursor.second += write(cursor.first, cursor.second, ss, maxSize.first, getFlag(item));
+        cursor.second += write(cursor.first, cursor.second, ss, 7, maxSize.first, getFlag(item));
     }
     else
     {
         cursor.second += write(cursor.first, cursor.second, childDelimiter[0], maxSize.first, getFlag(item));
         if (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1)
                 return false;
-        if (!writeContent(cursor, maxSize, (const std::list<JSonElement *> *)item))
+        if (!writeContent(cursor, maxSize, (std::list<JSonElement *> *)item))
             return false;
         cursor.second += write(cursor.first, cursor.second, childDelimiter[1], maxSize.first, getFlag(item));
     }
     return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second -1);
 }
 
-bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const std::list<JSonElement*> *_item)
+bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, std::list<JSonElement*> *_item)
 {
-    const JSonContainer *item = (const JSonContainer *)_item;
-    bool containerIsObject = (dynamic_cast<const JSonObject *>(item) != nullptr);
+    JSonContainer *item = (JSonContainer *)_item;
+    bool containerIsObject = (dynamic_cast<JSonObject *>(item) != nullptr);
     bool result = true;
     cursor.first += INDENT_LEVEL;
 
@@ -187,37 +187,38 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
         if (containerIsObject)
         {
             JSonObjectEntry *ent = (JSonObjectEntry*) i;
-            bool isContainer = (dynamic_cast<const JSonContainer *>(**ent) != nullptr);
+            bool isContainer = (dynamic_cast<JSonContainer *>(**ent) != nullptr);
             std::string key = ent->stringify();
             checkSelection(ent, cursor);
-            if (isContainer && collapsed.find((const JSonContainer*)(**ent)) != collapsed.cend())
+            if (isContainer && collapsed.find((JSonContainer*)(**ent)) != collapsed.cend())
             {
-                if (dynamic_cast<const JSonObject *>(**ent))
+                if (dynamic_cast<JSonObject *>(**ent))
                 {
-                    if (!writeKey(key, "{ ... }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ ... }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                         break;
                 }
-                else if (!writeKey(key, "[ ... ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ... ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else if (!isContainer)
             {
-                if (!writeKey(key, ((**ent)->stringify()), cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                JSonElement *eContent = **ent;
+                if (!writeKey(key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else if (((JSonContainer*)(**ent))->size() == 0)
             {
                 if (dynamic_cast<const JSonObject *>(**ent) )
                 {
-                    if (!writeKey(key, "{ }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                         break;
                 }
-                else if (!writeKey(key, "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else
             {
-                if (!writeKey(key, cursor, maxSize, getFlag(ent)))
+                if (!writeKey(key, ent->lazystrlen(), cursor, maxSize, getFlag(ent)))
                     break;
                 const JSonElement *saveSelection = selection;
                 if (selection == ent)
@@ -245,21 +246,30 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
     return result;
 }
 
-bool CurseOutput::writeKey(const std::string &key, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
 {
     if (cursor.second - scrollTop < 0)
     {
         cursor.second++;
         return true;
     }
-    if (!writeKey(key, cursor, maxSize, flags, after.size()))
-        return false;
+    char oldType = flags.type();
+    flags.type(OutputFlag::TYPE_OBJKEY);
+    write(cursor.first, cursor.second, key, 0, 1, flags);
+    flags.type(OutputFlag::TYPE_OBJ);
+    write(": ", flags);
+    flags.type(oldType);
     write(after.c_str(), flags);
-    //TODO check result if write goes to new line
-    return true;
+    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, maxSize.first);
+    return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second);
+}
+
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
+{
+    return writeKey(key, keylen, after, after.size(), cursor, maxSize, flags);
 }
 
-bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags, unsigned int extraLen)
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags, unsigned int extraLen)
 {
     if (cursor.second - scrollTop < 0)
     {
@@ -268,16 +278,16 @@ bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor,
     }
     char oldType = flags.type();
     flags.type(OutputFlag::TYPE_OBJKEY);
-    cursor.second += write(cursor.first, cursor.second, key, maxSize.first -extraLen -2, flags);
+    cursor.second += write(cursor.first, cursor.second, key, keylen, maxSize.first -extraLen -2, flags);
     flags.type(OutputFlag::TYPE_OBJ);
     write(": ", flags);
     flags.type(oldType);
     return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second);
 }
 
-unsigned int CurseOutput::write(const int &x, const int &y, const JSonElement *item, unsigned int maxWidth, OutputFlag flags)
+unsigned int CurseOutput::write(const int &x, const int &y, JSonElement *item, unsigned int maxWidth, OutputFlag flags)
 {
-    return write(x, y, item->stringify(), maxWidth, flags);
+    return write(x, y, item->stringify(), item->lazystrlen(), maxWidth, flags);
 }
 
 unsigned int CurseOutput::write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags)
@@ -322,19 +332,19 @@ void CurseOutput::write(const std::string &str, const OutputFlag flags) const
         attroff(COLOR_PAIR(color));
 }
 
-unsigned int CurseOutput::write(const int &x, const int &y, const std::string &str, unsigned int maxWidth, const OutputFlag flags)
+unsigned int CurseOutput::write(const int &x, const int &y, const std::string &str, const size_t strlen, unsigned int maxWidth, const OutputFlag flags)
 {
     int offsetY = y - scrollTop;
     if (offsetY < 0)
         return 1;
     move(offsetY, x);
     write(str, flags);
-    return getNbLines(str.size() +x, maxWidth);
+    return getNbLines(strlen +x, maxWidth);
 }
 
-unsigned int CurseOutput::getNbLines(float nbChar, unsigned int maxWidth)
+unsigned int CurseOutput::getNbLines(const size_t nbChar, unsigned int maxWidth)
 {
-    float nLine = nbChar / maxWidth;
+    double nLine = (double) nbChar / maxWidth;
     if (nLine == (unsigned int) nLine)
         return nLine;
     return nLine +1;

+ 25 - 1
src/jsonElement.cpp

@@ -9,7 +9,7 @@
 #include "jsonObjectEntry.hh"
 #include "searchPattern.hh"
 
-JSonElement::JSonElement(JSonElement *p): parent(p)
+JSonElement::JSonElement(JSonElement *p): parent(p), _strlen(0)
 { }
 
 JSonElement::~JSonElement()
@@ -20,6 +20,30 @@ void JSonElement::setParent(JSonElement *p)
     parent = p;
 }
 
+size_t JSonElement::lazystrlen()
+{
+    if (_strlen)
+        return _strlen;
+    const std::string buf = stringify();
+    if (!buf.size())
+        return _strlen;
+    wchar_t wbuf[buf.size()];
+    mbstowcs(wbuf, buf.c_str(), buf.size() * sizeof(wchar_t));
+    return _strlen = wcslen(wbuf);
+}
+
+size_t JSonElement::strlen() const
+{
+    if (_strlen)
+        return _strlen;
+    const std::string buf = stringify();
+    if (!buf.size())
+        return _strlen;
+    wchar_t wbuf[buf.size()];
+    mbtowc(wbuf, buf.c_str(), buf.size());
+    return wcslen(wbuf);
+}
+
 unsigned int JSonElement::getLevel() const
 {
     unsigned int level = 0;

+ 1 - 1
src/streamConsumer.cpp

@@ -361,7 +361,7 @@ void StreamConsumer::appendUnicode(const char unicode[4], std::stringstream &buf
     char test[5];
     bzero(test, sizeof(*test) *5);
     snprintf(test, 4, "%lc", uni);
-    buf.write(test, 4);
+    buf.write(test, 3);
 }
 
 std::string StreamConsumer::extractUnicode(const char *buf)