libjson and QString

Anonymous
2012-03-05
2013-06-12
  • Anonymous - 2012-03-05

    Hello all,

    I've been doing some server project in Qt and needed a JSon library. With Google help I chose Your library to use. I was using Qt QString::toStdString() method to get standard json_string.  I didn't care about performance (this method creates additional string), yet. But the worst thing happend is there was a problem converting QString (in UTF-8) to std::string. Some wierd (I mean Polish letters), were encoded wrong and now I wish I could stick to QString for good. As documentation states, it shouldn't be a problem to use QString, by changing JSONOption.h file. But, unfortunately, it's not that good. There are some differences between QString API and std::string. Thus, I tried to write my own KString class deriving from QString, and the following code is what I got. If someone feels like, please have a look and check if this port is fine. Code compiles fine, but I have some problems with linking library. Hope will overcome this soon. If so, I will surely post it here.

    #ifndef QSTRING_JSON_H
    #define QSTRING_JSON_H
    #include <QtCore/qstring.h>
    #include <QtCore/QChar>
    #include <QtCore/QRegExp>
    #include <string>
    class KString;
    typedef KString json_string;
    class KString:
        public QString
    {
    public:
        KString ():
            QString() {}
        KString (const QChar* unicode, int size):
            QString(unicode, size) {}
        KString (const QChar* unicode):
            QString(unicode) {}
        KString (QChar ch):
            QString(ch) {}
        KString (int size, QChar ch):
            QString(size, ch) {}
        KString (const QLatin1String &str):
            QString(str) {}
        KString (const KString &other):
            QString(other) {}
        KString (const char *str):
            QString(str) {}
        KString (const QByteArray &ba):
            QString(ba) {}
            KString (const QString &other):
                QString(other) {}
        KString (QString::const_iterator begin, QString::const_iterator end):
            QString(begin, end - begin + 1) {}
    
        inline const char* c_str ( ) const {
            return toUtf8().data();
        }
        inline bool find_first_not_of(const QString &chars, size_t pos = 0) const
        {
            //return true if text not contains any of char in chars
            QString::const_iterator it = constBegin() + pos;
            QString::const_iterator end = constEnd();
                    while (it != end) {
                if (chars.contains(*it) == false)
                    return it - constBegin();
                ++it;
            }
    
            return npos;
        }
        static const size_t npos = -1;
        inline const char operator[] (size_t pos) const 
        {
            QChar c = QString::operator[](pos);
            return c.toAscii();
        }
        inline bool empty() const 
        {
            return isEmpty();
        }
        inline size_t find_first_of(const QString& str, size_t pos = 0) const
        {
            QRegExp regExp("[" + str + "]");
            return indexOf(regExp, pos);
        }
    
        inline KString substr(size_t pos = 0, size_t n = npos) const
        {
                    return KString(mid(pos, npos));
        }
        inline QString::iterator erase(QString::iterator first, QString::iterator last) 
        {   
            KString::iterator b = begin();
            int pos = first - b;
            int size = last - first + 1;
            remove (pos, size);
            if (count() > pos)
                return (b + pos);
            else 
                return end();       
        }
    
            inline KString &assign(QString::const_iterator begin, QString::const_iterator end)
            {
                this->clear();
                this->resize(end-begin);
                for (; begin != end; ++begin)
                    this->QString::append(*begin);
                return *this;
            }
            inline KString &append(QString::const_iterator begin, QString::const_iterator end)
            {
                this->resize(size() + (end - begin));
                for (; begin != end; ++begin)
                    this->QString::append(*begin);
                return *this;
            }
            inline size_t find(char c, size_t pos = 0) const
            {
                return indexOf(c, pos);
            }
    };
    #endif //QSTRING_JSON_H
    
     
  • Jonathan Wallace

    Hello,
    I have Qt installed on one of my machines, I will run the test suite against this class sometime in the next week.  I may integrate this into libjson as well as a compile option.

     
  • Anonymous - 2012-03-05

    Thanks for posting so fast. One of the issues I have already spot is constructor:

        KString (QString::const_iterator begin, QString::const_iterator end):
                    QString(begin, end - begin) {}
    

    There was '1' and shouldn't be. I am still working on it to make it running fine.

     
  • Anonymous - 2012-03-05

    Ok, now it works better, at all. I suppose there is a lot to do to improve performance, but still - this is the beginning. I would really like to see someone telling me what's wrong or right :)

    #ifndef QSTRING_JSON_H
    #define QSTRING_JSON_H
    #include <QtCore/qstring.h>
    #include <QtCore/QChar>
    #include <QtCore/QRegExp>
    #include <QtCore/QDebug>
    #include <string>
    class KString;
    typedef KString json_string;
    class KString:
        public QString
    {
    public:
        KString ():
            QString() {}
        KString (const QChar* unicode, int size):
            QString(unicode, size) {}
        KString (const QChar* unicode):
            QString(unicode) {}
        KString (QChar ch):
            QString(ch) {}
        KString (int size, QChar ch):
            QString(size, ch) {}
        KString (const QLatin1String &str):
            QString(str) {}
        KString (const KString &other):
            QString(other) {}
        KString (const char *str):
            QString(str) {}
        KString (const QByteArray &ba):
            QString(ba) {}
            KString (const QString &other):
                QString(other) {}
        KString (QString::const_iterator begin, QString::const_iterator end):
                    QString(begin, end - begin) {}
    
        inline const char* c_str ( ) const {
            return toUtf8().data();
        }
            inline size_t find_first_not_of(const QString &chars, size_t pos = 0) const
        {
            //return true if text not contains any of char in chars
            QString::const_iterator it = constBegin() + pos;
            QString::const_iterator end = constEnd();
                    while (it != end) {
                if (chars.contains(*it) == false)
                    return it - constBegin();
                ++it;
            }
    
            return npos;
        }
        static const size_t npos = -1;
        inline const char operator[] (size_t pos) const 
        {
            QChar c = QString::operator[](pos);
            return c.toAscii();
        }
        inline bool empty() const 
        {
            return isEmpty();
        }
        inline size_t find_first_of(const QString& str, size_t pos = 0) const
        {
            QRegExp regExp("[" + str + "]");
            return indexOf(regExp, pos);
        }
    
        inline KString substr(size_t pos = 0, size_t n = npos) const
        {
                return KString(mid(pos, npos));
        }
        inline QString::iterator erase(QString::iterator first, QString::iterator last) 
        {   
            KString::iterator b = begin();
            int pos = first - b;
            int size = last - first + 1;
            remove (pos, size);
            if (count() > pos)
                return (b + pos);
            else 
                return end();       
        }
    
            inline KString &assign(QString::const_iterator begin, QString::const_iterator end)
            {
                size_t size = end - begin;
                setUnicode(begin, size);
                return *this;
            }
            inline KString &append(QString::const_iterator begin, QString::const_iterator end)
            {
                QString::append(QString::fromRawData(begin, (end - begin)));
                return *this;
            }
            inline size_t find(char c, size_t pos = 0) const
            {
                return indexOf(c, pos);
            }
    };
    #endif //QSTRING_JSON_H
    
     
  • Jonathan Wallace

    inline const char* c_str ( ) const {
    return toUtf8().data();
    }

    I did notice that, I'm not sure that data() for QString will null terminate and the c_str() function is required to. 

    Hopefully I will be able to run a test sometime before the weekend, though I'm still chasing another bug in the new code.

     
  • Anonymous - 2012-03-06

    I think this will work. However qt does a conversion here, so could be a performance bottleneck. On the other side, documentation says that for all the functions that take char*:
    "you can pass a QString to a function that takes a const char * argument using the qPrintable() macro which returns the given QString as a const char *. This is equivalent to calling <QString>.toLocal8Bit().constData()."
    so toLocal8Bit().constData() or toLocal8Bit().data() would probably be better. 

     
  • Anonymous - 2012-03-06

    Hi again. Dwelled on the issue for some time and realized my previous sollution could even cause segfaults. For instance have a look at  method KString::c_str(). It creates temporal object, namely QByteArray by calling toUtf8(), which char* is extracted from to be returned. And this char* is used later, but the QByteArray object is not valid anymore - it got destroyed, when c_str() scope was finished. That's bad, or at least I think so.
    I decided, that to make this library more Qt friendly (to be able to use it with the minimum number of conversions), I should use QByteArray. And this works fine, so far. Of course, I haven't conducted any tests yet. When I have time, I will try to do it at least.

    This is my code:

    #ifndef JSON_QSTRING_H
    #define JSON_QSTRING_H
    #include <QtCore/QByteArray>
    #include <QtCore/QChar>
    #include <QtCore/QRegExp>
    #include <QtCore/QDebug>
    #include <string>
    class JSonQString;
    typedef JSonQString json_string;
    class JSonQString:
            public QByteArray
    {
    public:
        JSonQString():
            QByteArray() {}
        JSonQString(const char *data):
            QByteArray(data) {}
        JSonQString(const char *data, int size):
            QByteArray(data, size) {}
        JSonQString(int size, char c):
            QByteArray(size, c) {}
        JSonQString(int size, Qt::Initialization init):
            QByteArray(size, init) {}
        JSonQString (QByteArray::const_iterator begin, QByteArray::const_iterator end):
            QByteArray(begin, end - begin) {}
        inline const char* c_str ( ) const {
            return constData();
        }
        inline size_t find_first_not_of(const QByteArray &chars, size_t pos = 0) const
        {
            //return true if text not contains any of char in chars
            for (QByteArray::const_iterator it = this->begin() + pos; it != this->end(); ++it, ++pos) {
                if (!chars.contains(*it))
                    return pos;
            }
            return npos;
        }
        static const size_t npos = std::string::npos;
        //this would have better performance than QByteArray::operator[] (since at() is faster), but gives warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
    //    inline char operator[] (size_t pos) const
    //    {
    //        //return QByteArray::operator[](pos);
    //        //at() can be faster than operator[](), because it never causes a deep copy to occur
    //        return at(pos);
    //    }
        inline bool empty() const
        {
            return isEmpty();
        }
        inline size_t find_first_of(const QByteArray& set, size_t pos = 0) const
        {
            for (QByteArray::const_iterator it = this->begin() + pos; it != this->end(); ++it, ++pos) {
                if (set.contains(*it))
                    return pos;
            }
            return npos;
        }
        inline JSonQString substr(size_t pos = 0, size_t n = npos) const
        {
            return JSonQString(mid(pos, n));
        }
        inline QByteArray::iterator erase(QByteArray::iterator first, QByteArray::iterator last)
        {
            JSonQString::iterator b = begin();
            int pos = first - b;
            int size = last - first + 1;
            remove (pos, size);
            if (count() > pos)
                return (b + pos);
            else
                return end();
        }
        inline JSonQString &assign(QByteArray::const_iterator begin, QByteArray::const_iterator end)
        {
            size_t size = end - begin;
            clear();
            QByteArray::append(begin, size);
    //        QByteArray::append('\0');
            return *this;
        }
        inline JSonQString &append(QByteArray::const_iterator begin, QByteArray::const_iterator end)
        {
            QByteArray::append(begin, (end - begin));
    //        QByteArray::append('\0');
            return *this;
        }
        inline size_t find(char c, size_t pos = 0) const
        {
            return indexOf(c, pos);
        }
        JSonQString &operator+=(JSonQString &other)
        {
            return *((JSonQString*)&(this->QByteArray::append(other)));
        }
        JSonQString &operator+=(const JSonQString &other)
        {
            return *((JSonQString*)&(this->QByteArray::append(other)));
        }
        JSonQString &operator+=(char c)
        {
            return *((JSonQString*)&(this->QByteArray::append(c)));
        }
    };
    inline const JSonQString operator+(const JSonQString &a1, const JSonQString &a2)
    { return JSonQString(a1) += a2; }
    inline const JSonQString operator+(const JSonQString &a1, const char *a2)
    { return JSonQString(a1) += a2; }
    inline const JSonQString operator+(const JSonQString &a1, char a2)
    { return JSonQString(a1) += a2; }
    inline const JSonQString operator+(const char *a1, const JSonQString &a2)
    { return JSonQString(a1) += a2; }
    inline const JSonQString operator+(char a1, const JSonQString &a2)
    { return JSonQString(&a1, 1) += a2; }
    #endif //JSON_QSTRING_H
    
     
  • Jonathan Wallace

    Cool thanks, I will try to integrate this into libjson as an option.

     
  • Anonymous - 2012-03-10

    To compile what I did, minor modification to makefile is needed. Here is a diff ouput:
    139,142c139,141
    < stringinclude = /usr/include/qt4/
    < cxxflags_small   = -c -Os -ffast-math -DJSON_LESS_MEMORY -DNDEBUG -I${stringinclude}
    < cxxflags_debug   = -c -g -DJSON_SAFE -DJSON_DEBUG -I${stringinclude}
    < cxxflags_shared  = -f$(PIC) -I${stringinclude}
    --
    > cxxflags_small   = -c -Os -ffast-math -DJSON_LESS_MEMORY -DNDEBUG
    > cxxflags_debug   = -c -g -DJSON_SAFE -DJSON_DEBUG
    > cxxflags_shared  = -f$(PIC)
    163c162
    And by the way, I am making a *.so library to use it in my project. I came accross some problems in makefile while compiling and below is what I had to change to make it working:
    163c162
    < SHARED          ?= 1
    --
    > SHARED          ?= "1"
    189c188
    < ifeq ($(SHARED),1)
    --
    > ifeq ($(SHARED), 1)
    Hope this helps. Greetings!

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks