diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2011-12-07 21:19:07 +0100 |
---|---|---|
committer | Hicks James <jamey.hicks@nokia.com> | 2011-12-08 15:15:43 +0100 |
commit | 01ad456e4477a36a12162ef9866bd28b7202bfee (patch) | |
tree | c9b1c850a97af13bce78413cdf70c06dd69c8514 | |
parent | d02f9658c47599c4f07c269d18fbc503cafdffc2 (diff) |
Refactored the way Values are stored
Values now require 4 to 8 bytes less
storage than before.
Change-Id: I15477cf3e9b509f9e9a34f03ed9d1db60333adbb
Reviewed-by: Hicks James <jamey.hicks@nokia.com>
-rw-r--r-- | src/qjson_p.h | 288 | ||||
-rw-r--r-- | src/qjsonarray.cpp | 29 | ||||
-rw-r--r-- | src/qjsonglobal.h | 15 | ||||
-rw-r--r-- | src/qjsonobject.cpp | 26 | ||||
-rw-r--r-- | src/qjsonvalue.cpp | 266 | ||||
-rw-r--r-- | src/qjsonvalue.h | 19 | ||||
-rw-r--r-- | src/qjsonwriter.cpp | 19 | ||||
-rw-r--r-- | tests/auto/tst_qtjson.cpp | 5 |
8 files changed, 370 insertions, 297 deletions
diff --git a/src/qjson_p.h b/src/qjson_p.h index e016493..2ef94c7 100644 --- a/src/qjson_p.h +++ b/src/qjson_p.h @@ -18,40 +18,40 @@ String: 16 bytes header + 2*(string.length()) - Values: 8 bytes + size of data + Values: 4 bytes + size of data (size can be 0 for some data) bool: 0 bytes number: 8 bytes - string: size of String + string: 4 + 2*length of string array: size of array object: size of object - Array: 16 bytes + 4*length + size of Values - Object: 16 bytes + 12*length + size of Key Strings + size of Values + Array: 16 bytes + 4*length + size of Value data + Object: 16 bytes + 12*length + size of Key Strings + size of Value data For an example such as { // object: 16 + 5*12 = 72 - "firstName": "John", // key 16+18, value 8+16+8 = 66 - "lastName" : "Smith", // key 16+16, value 8+16+10 = 66 - "age" : 25, // key 16+6, value 8+8 = 38 - "address" : // key 16+14 value 8 + object below = 422 + "firstName": "John", // key 4+18, value 4+4+8 = 38 + "lastName" : "Smith", // key 4+16, value 4+4+10 = 38 + "age" : 25, // key 4+6, value 4+8 = 22 + "address" : // key 4+14 value 4 + object below = 288 { // object: 16 + 4*12 - "streetAddress": "21 2nd Street", // key 16+26, value 8+16+26 - "city" : "New York", // key 16+8, value 8+16+16 - "state" : "NY", // key 16+10, value 8+16+4 - "postalCode" : "10021" // key 16+20, value 8+16+10 - }, // object total: 384 - "phoneNumber": // key: 16+22, value 8 + array below = 430 + "streetAddress": "21 2nd Street", // key 4+26, value 4+4+26 + "city" : "New York", // key 4+8, value 4+4+16 + "state" : "NY", // key 4+10, value 4+4+4 + "postalCode" : "10021" // key 4+20, value 4+4+10 + }, // object total: 266 + "phoneNumber": // key: 4+22, value 4 + array below = 278 [ // array: 16 + 2*4 + values below - { // value 8 + object 16 + 2*12 - "type" : "home", // key 16+8, value 8+16+8 - "number": "212 555-1234" // key 16+12, value 8+16+26 - }, // object total: 174 - { // value 8 + object 16 + 2*12 - "type" : "fax", // key 16+6, value 8+16+6 - "number": "646 555-4567" // key 16+12, value 8+16+26 - } // object total: 170 - ] // array total: 384 - } // great total: 1094 bytes + { // value 4 + object 16 + 2*12 + "type" : "home", // key 4+8, value 4+4+8 + "number": "212 555-1234" // key 4+12, value 4+4+26 + }, // object total: 112 + { // value 4 + object 16 + 2*12 + "type" : "fax", // key 4+6, value 4+4+6 + "number": "646 555-4567" // key 4+12, value 4+4+26 + } // object total: 110 + ] // array total: 248 + } // great total: 736 bytes we end up using roughly 1kb. The uncompressed text file used roughly 500 bytes. */ @@ -61,6 +61,8 @@ namespace QtJson typedef uint offset; struct Array; struct Object; +struct Value; +struct Entry; static inline int alignedSize(int size) { return (size + 7) & ~7; } @@ -103,66 +105,6 @@ struct QStackString }; - -struct Value -{ - uint size; - uint val : 29; - uint type : 3; - - inline char *data() const { return (char *)(this + 1); } - - bool toBoolean() const; - double toNumber() const; - int toInt() const; - QString toString() const; - QStackString shallowString() const; - Array *array() const; - Object *object() const; - - static inline Value *alloc(int size) { Value *v = (Value *)malloc(size); v->size = size; return v; } - static inline Value *fromBoolean(bool b) { - Value *v = alloc(sizeof(Value)); - v->type = BooleanValue; - v->val = b; - return v; - } - static inline Value *fromNumber(double d) { - Value *v = alloc(sizeof(Value) + sizeof(double)); - v->type = NumberValue; - *(double *)(v->data()) = d; - return v; - } - static inline Value *fromString(const QString &string) { - Value *v = alloc(sizeof(Value) + qStringSize(string)); - v->type = StringValue; - v->val = string.length(); - memcpy(v->data(), string.constData(), sizeof(ushort)*string.length()); - return v; - } - static inline Value *fromArray(const Array *a); - static inline Value *fromObject(const Object *o); -}; - - -struct Entry { - uint size; - offset valueOffset; - uint keyLength; - ushort *keyData() const { return (ushort *)(this + 1); } - // keydata - // value data follows key data - - QStackString shallowKey() const { return QStackString(keyData(), keyLength); } - QString key() const - { - return QString((const QChar *)keyData(), keyLength); - } - Value *value() const { - return reinterpret_cast<Value *>(((char *)this) + valueOffset); - } -}; - struct Base { uint size; @@ -173,7 +115,7 @@ struct Base inline offset *table() const { return (offset *) (((char *) this) + tableOffset); } - void reserveSpace(uint dataSize, int posInTable, uint numItems) + int reserveSpace(uint dataSize, int posInTable, uint numItems) { Q_ASSERT(posInTable >= 0 && posInTable <= (int)length); @@ -186,6 +128,7 @@ struct Base table()[posInTable + i] = off; length += numItems; size += dataSize + numItems * sizeof(offset); + return off; } void removeItems(int pos, int numItems) @@ -199,27 +142,107 @@ struct Base struct Object : public Base { + Entry *entryAt(int i) const { return reinterpret_cast<Entry *>(((char *)this) + table()[i]); } - int indexOf(const QString &key) { - for (int i = 0; i < (int)length; ++i) { - Entry *e = entryAt(i); - if (e->shallowKey() == key) - return i; - } - return -1; - } + inline int indexOf(const QString &key); }; struct Array : public Base { - inline Value *at(int i) const { - return reinterpret_cast<Value *>(((char *)this) + table()[i]); + inline Value at(int i) const; + inline Value &operator [](int i); +}; + + +struct Value +{ + uint val : 28; + uint compressed : 1; + uint type : 3; + + inline char *data(const Base *b) const { return ((char *)b) + val; } + + bool toBoolean() const; + double toNumber(const Base *b) const; +// int toInt() const; + QString toString(const Base *b) const; + QStackString shallowString(const Base *b) const; + Array *array(const Base *b) const; + Object *object(const Base *b) const; + + inline void setNull() { + val = 0; + compressed = 0; + type = NullValue; + } + + inline void setBool(bool b) { + val = b; + compressed = false; + type = BooleanValue; + } + +// inline void setInt(int i) { +// val = i; +// compressed = true; +// type = NumberValue; +// } + + inline void setString(Base *b, offset off, const QString &str) { + val = off; + compressed = false; + type = StringValue; + memcpy(((char *)b) + off, str.constData(), str.length()*sizeof(ushort)); + } + + inline void setObject(Base *b, offset off, const Object *o) { + val = off; + compressed = false; + type = StringValue; + memcpy(((char *)b) + off, o, o->size); + } +}; + +inline Value Array::at(int i) const +{ + return * (Value *) (((char *) this) + tableOffset + i*sizeof(Value)); +} + +inline Value &Array::operator [](int i) +{ + return * (Value *) (((char *) this) + tableOffset + i*sizeof(Value)); +} + + +struct Entry { + uint size; + Value value; + uint keyLength; + ushort *keyData() const { return (ushort *)(this + 1); } + // keydata + // value data follows key data + + QStackString shallowKey() const { return QStackString(keyData(), keyLength); } + QString key() const + { + return QString((const QChar *)keyData(), keyLength); } }; +inline int Object::indexOf(const QString &key) +{ + for (int i = 0; i < (int)length; ++i) { + Entry *e = entryAt(i); + if (e->shallowKey() == key) + return i; + } + return -1; +} + + struct Header { uint size; uint tag; // 'qbjs' @@ -235,72 +258,44 @@ inline bool Value::toBoolean() const return val != 0; } -inline double Value::toNumber() const +inline double Value::toNumber(const Base *b) const { Q_ASSERT(type == NumberValue); - return *(double *)((char *)(this+1)); + return *(double *)((char *)b + val); } -inline int Value::toInt() const -{ - Q_ASSERT(type == NumberValue); - return (int)*(double *)((char *)(this+1)); -} +//inline int Value::toInt() const +//{ +// Q_ASSERT(type == NumberValue); +// return (int)*(double *)((char *)(this+1)); +//} -inline QString Value::toString() const +inline QString Value::toString(const Base *b) const { - return QString((const QChar *)data(), val); + char *d = data(b); + int l = *(int *)d; + const QChar *c = (const QChar *)(d + sizeof(int)); + return QString(c, l); } -inline QStackString Value::shallowString() const +inline QStackString Value::shallowString(const Base *b) const { - return QStackString((ushort *)data(), val); + char *d = data(b); + int l = *(int *)d; + const ushort *c = (const ushort *)(d + sizeof(int)); + return QStackString(c, l); } -inline Array *Value::array() const +inline Array *Value::array(const Base *b) const { Q_ASSERT(type == ArrayValue); - return reinterpret_cast<Array *>(data()); + return reinterpret_cast<Array *>(data(b)); } -inline Object *Value::object() const +inline Object *Value::object(const Base *b) const { Q_ASSERT(type == ObjectValue); - return reinterpret_cast<Object *>(data()); -} - -Value *Value::fromArray(const Array *a) -{ - int size = a ? a->size : sizeof(Array); - Value *v = alloc(sizeof(Value) + size); - v->type = ArrayValue; - if (a) { - memcpy(v->data(), a, size); - } else { - Array *array = v->array(); - array->size = sizeof(Array); - array->length = 0; - array->tableOffset = 0; - array->unused = 0; - } - return v; -} - -Value *Value::fromObject(const Object *o) -{ - int size = o ? o->size : sizeof(Object); - Value *v = alloc(sizeof(Value) + size); - v->type = ObjectValue; - if (o) { - memcpy(v->data(), o, o->size); - } else { - Object *object = v->object(); - object->size = sizeof(Object); - object->length = 0; - object->tableOffset = 0; - object->unused = 0; - } - return v; + return reinterpret_cast<Object *>(data(b)); } @@ -339,11 +334,6 @@ struct Data { return JsonObject(const_cast<Data *>(this), o); } - JsonValue toValue(Value *v) const - { - return JsonValue(const_cast<Data *>(this), v); - } - JsonArray toArray(Array *a) const { return JsonArray(const_cast<Data *>(this), a); diff --git a/src/qjsonarray.cpp b/src/qjsonarray.cpp index a161066..5266b30 100644 --- a/src/qjsonarray.cpp +++ b/src/qjsonarray.cpp @@ -69,7 +69,7 @@ QVariantList JsonArray::toVariantList() const if (a) { for (int i = 0; i < (int)a->length; ++i) - list.append(JsonValue(d, a->at(i)).toVariant()); + list.append(JsonValue(d, a, a->at(i)).toVariant()); } return list; } @@ -96,7 +96,7 @@ JsonValue JsonArray::at(int i) const if (!a || i < 0 || i >= (int)a->length) return JsonValue(); - return d->toValue(a->at(i)); + return JsonValue(d, a, a->at(i)); } JsonValue JsonArray::first() const @@ -131,7 +131,7 @@ JsonValue JsonArray::takeAt(int i) detach(); - JsonValue v(d, a->at(i)); + JsonValue v(d, a, a->at(i)); v.detach(); removeAt(i); @@ -143,23 +143,20 @@ void JsonArray::insert(int i, const JsonValue &value) { Q_ASSERT (i >= 0 && i <= (int)(a ? a->length : 0)); - Value *v = value.v; - int valueSize = v ? v->size : sizeof(Value); + int valueSize = value.requiredStorage(); - detach(valueSize + sizeof(offset)); // offset for the new index entry + detach(valueSize + sizeof(offset) + sizeof(Value)); // offset for the new index entry if (!a->length) a->tableOffset = sizeof(Array); - a->reserveSpace(valueSize, i, 1); - if (v) { - memcpy(a->at(i), v, v->size); - } else { - Value *n = a->at(i); - n->type = NullValue; - n->val = 0; - n->size = sizeof(Value); - } + int valueOffset = a->reserveSpace(valueSize, i, 1); + Value &v = (*a)[i]; + v.type = value.t; + v.compressed = false; + v.val = value.valueToStore(valueOffset); + if (valueSize) + value.copyData((char *)a + valueOffset); } bool JsonArray::contains(const JsonValue &element) const @@ -196,7 +193,7 @@ bool JsonArray::operator==(const JsonArray &other) const return false; for (int i = 0; i < (int)a->length; ++i) { - if (d->toValue(a->at(i)) != other.d->toValue(other.a->at(i))) + if (JsonValue(d, a, a->at(i)) != JsonValue(other.d, other.a, other.a->at(i))) return false; } return true; diff --git a/src/qjsonglobal.h b/src/qjsonglobal.h index 0f67820..09cc9fb 100644 --- a/src/qjsonglobal.h +++ b/src/qjsonglobal.h @@ -8,11 +8,12 @@ namespace QtJson { // ### FIXME // namespace Private { - class Data; - class Object; - class Header; - class Array; - class Value; + struct Data; + struct Base; + struct Object; + struct Header; + struct Array; + struct Value; // }; class JsonValue; @@ -22,8 +23,8 @@ namespace QtJson enum ValueType { NullValue = 0x0, - NumberValue = 0x1, - BooleanValue = 0x2, + BooleanValue = 0x1, + NumberValue = 0x2, StringValue = 0x3, ArrayValue = 0x4, ObjectValue = 0x5 diff --git a/src/qjsonobject.cpp b/src/qjsonobject.cpp index da386b8..1dbdaa7 100644 --- a/src/qjsonobject.cpp +++ b/src/qjsonobject.cpp @@ -77,7 +77,7 @@ QVariantMap JsonObject::toVariantMap() const QVariantMap map; for (uint i = 0; i < o->length; ++i) { Entry *e = o->entryAt(i); - map.insert(e->key(), JsonValue(d, e->value()).toVariant()); + map.insert(e->key(), JsonValue(d, o, e->value).toVariant()); } return map; } @@ -129,16 +129,14 @@ JsonValue JsonObject::value(const QString &key) const for (uint i = 0; i < o->length; ++i) { Entry *e = o->entryAt(i); if (e->shallowKey() == key) - return d->toValue(e->value()); + return JsonValue(d, o, e->value); } return JsonValue(); } void JsonObject::insert(const QString &key, const JsonValue &value) { - Value *v = value.v; - - int valueSize = v ? v->size : sizeof(Value); + int valueSize = value.requiredStorage(); int valueOffset = sizeof(Entry) + qStringSize(key); int requiredSize = valueOffset + valueSize; @@ -157,15 +155,11 @@ void JsonObject::insert(const QString &key, const JsonValue &value) e->size = requiredSize; e->keyLength = key.length(); memcpy(e->keyData(), key.constData(), sizeof(ushort)*key.length()); - e->valueOffset = valueOffset; - if (v) { - memcpy(e->value(), v, v->size); - } else { - Value *n = e->value(); - n->type = NullValue; - n->val = 0; - n->size = sizeof(Value); - } + e->value.type = value.t; + e->value.compressed = false; + e->value.val = value.valueToStore(d->offsetOf(e) + valueOffset); + if (valueSize) + value.copyData((char *)e + valueOffset); } void JsonObject::remove(const QString &key) @@ -193,7 +187,7 @@ JsonValue JsonObject::take(const QString &key) Entry *e = o->entryAt(index); o->removeItems(index, 1); d->needsCompaction = true; - return d->toValue(e->value()); + return JsonValue(d, o, e->value); } bool JsonObject::contains(const QString &key) const @@ -226,7 +220,7 @@ bool JsonObject::operator==(const JsonObject &other) const for (uint i = 0; i < o->length; ++i) { Entry *e = o->entryAt(i); - JsonValue v = d->toValue(e->value()); + JsonValue v(d, o, e->value); if (other.value(e->key()) != v) return false; } diff --git a/src/qjsonvalue.cpp b/src/qjsonvalue.cpp index 0241482..b5da375 100644 --- a/src/qjsonvalue.cpp +++ b/src/qjsonvalue.cpp @@ -6,103 +6,145 @@ #include <qvariant.h> #include <qstringlist.h> +#include <qdebug.h> using namespace QtJson; +static const Base emptyBase = { sizeof(Base), 0, 0, 0 }; + JsonValue::JsonValue() - : d(0), v(0) + : t(NullValue), d(0), dbl(0.) { } -JsonValue::JsonValue(Data *data, Value *value) - : d(data), v(value) +JsonValue::JsonValue(Data *data, Base *base, const Value &v) + : d(0) { - d->ref.ref(); + t = (ValueType)v.type; + switch (t) { + case NullValue: + dbl = 0; + break; + case BooleanValue: + b = v.val; + break; + case NumberValue: + dbl = v.toNumber(base); + break; + case StringValue: { + QString s = v.toString(base); + stringData = *reinterpret_cast<QStringData **>(&s); + stringData->ref.ref(); + break; + } + case ArrayValue: + d = data; + array = v.array(base); + break; + case ObjectValue: + d = data; + object = v.object(base); + break; + } + if (d) + d->ref.ref(); } JsonValue::JsonValue(bool b) - : d(0), v(0) + : t(BooleanValue), d(0) { - v = Value::fromBoolean(b); - d = new Data((char *)v, v->size); - d->ref.ref(); + this->b = b; } JsonValue::JsonValue(double n) - : d(0), v(0) + : t(NumberValue), d(0) { - v = Value::fromNumber(n); - d = new Data((char *)v, v->size); - d->ref.ref(); + this->dbl = n; } JsonValue::JsonValue(int n) - : d(0), v(0) + : t(NumberValue), d(0) { - v = Value::fromNumber((double)n); - d = new Data((char *)v, v->size); - d->ref.ref(); + this->dbl = n; } JsonValue::JsonValue(const QString &s) - : d(0), v(0) + : t(StringValue), d(0) { - v = Value::fromString(s); - d = new Data((char *)v, v->size); - d->ref.ref(); + stringData = *(QStringData **)(&s); + stringData->ref.ref(); } JsonValue::JsonValue(const QLatin1String &s) + : t(StringValue), d(0) { // ### FIXME: Avoid creating the temp QString below - v = Value::fromString(QString(s)); - d = new Data((char *)v, v->size); - d->ref.ref(); - + QString str(s); + stringData = *(QStringData **)(&str); + stringData->ref.ref(); } JsonValue::JsonValue(const JsonArray &a) - : d(0), v(0) + : t(ArrayValue), d(a.d) { - v = Value::fromArray(a.a); - d = new Data((char *)v, v->size); - d->ref.ref(); + array = a.a; + if (d) + d->ref.ref(); } JsonValue::JsonValue(const JsonObject &o) - : d(0), v(0) + : t(ObjectValue), d(o.d) { - v = Value::fromObject(o.o); - d = new Data((char *)v, v->size); - d->ref.ref(); + object = o.o; + if (d) + d->ref.ref(); } JsonValue::~JsonValue() { + if (t == StringValue && stringData && !stringData->ref.deref()) + free(stringData); + if (d && !d->ref.deref()) delete d; } JsonValue::JsonValue(const JsonValue &other) { + t = other.t; d = other.d; - v = other.v; + memcpy(raw, other.raw, sizeof(double)); if (d) d->ref.ref(); + + if (t == StringValue && stringData) + stringData->ref.ref(); } JsonValue &JsonValue::operator =(const JsonValue &other) { + if (t == StringValue && stringData && !stringData->ref.deref()) + free(stringData); + + t = other.t; + dbl = other.dbl; + if (d != other.d) { + if (d && !d->ref.deref()) delete d; + t = other.t; d = other.d; - v = other.v; + dbl = other.dbl; if (d) d->ref.ref(); + } + if (t == StringValue && stringData) + stringData->ref.ref(); + return *this; } @@ -111,8 +153,9 @@ JsonValue JsonValue::fromVariant(const QVariant &variant) switch (variant.type()) { case QVariant::Bool: return JsonValue(variant.toBool()); - case QVariant::Double: case QVariant::Int: + return JsonValue(variant.toInt()); + case QVariant::Double: case QVariant::LongLong: case QVariant::ULongLong: case QVariant::UInt: @@ -136,19 +179,17 @@ JsonValue JsonValue::fromVariant(const QVariant &variant) QVariant JsonValue::toVariant() const { - ValueType type = v ? (ValueType)v->type : NullValue; - - switch (type) { + switch (t) { case BooleanValue: - return v->toBoolean(); + return b; case NumberValue: - return v->toNumber(); + return dbl; case StringValue: - return v->toString(); + return toString(); case ArrayValue: - return JsonArray(d, v->array()).toVariantList(); + return JsonArray(d, array).toVariantList(); case ObjectValue: - return JsonObject(d, v->object()).toVariantMap(); + return JsonObject(d, object).toVariantMap(); case NullValue: break; } @@ -158,10 +199,7 @@ QVariant JsonValue::toVariant() const ValueType JsonValue::type() const { - if (!d) - return NullValue; - - return (ValueType)v->type; + return t; } void JsonValue::setValue(bool b) @@ -201,91 +239,67 @@ void JsonValue::setValue(const JsonObject &o) bool JsonValue::toBool() const { - if (!d) - return false; - - if (v->type != BooleanValue) + if (t != BooleanValue) return false; - return v->toBoolean(); + return b; } double JsonValue::toNumber() const { - if (!d) - return 0; - - if (v->type != NumberValue) + if (t != NumberValue) return 0; - return v->toNumber(); + return dbl; } int JsonValue::toInt() const { - if (!d) - return 0; - - if (v->type != NumberValue) + if (t != NumberValue) return 0; - return v->toInt(); + return (int)dbl; } QString JsonValue::toString() const { - if (!d) - return QString(); - - if (v->type != StringValue) + if (t != StringValue) return QString(); - return v->toString(); + stringData->ref.ref(); // the constructor below doesn't add a ref. + return QString(*(const QConstStringData<1> *)stringData); } JsonArray JsonValue::toArray() const { - if (!d) + if (!d || t != ArrayValue) return JsonArray(); - if (v->type != ArrayValue) - return JsonArray(); - Array *a = v->array(); - return d->toArray(a); + return JsonArray(d, array); } JsonObject JsonValue::toObject() const { - if (!d) + if (!d || t != ObjectValue) return JsonObject(); - if (v->type != ObjectValue) - return JsonObject(); - Object *o = v->object(); - return d->toObject(o); + return JsonObject(d, object); } bool JsonValue::operator==(const JsonValue &other) const { - if (v == other.v) - return true; - - if (!v) - return other.v->type == NullValue; - if (!other.v) - return v->type == NullValue; - if (v->type != other.v->type) + if (t != other.t) return false; - switch ((ValueType)v->type) { - case NumberValue: - return v->toNumber() == other.v->toNumber(); + switch (t) { + case NullValue: + break; case BooleanValue: - return v->toBoolean() == other.v->toBoolean(); + return b == other.b; + case NumberValue: + return dbl == other.dbl; case StringValue: - return v->shallowString() == other.v->shallowString(); + return toString() == other.toString(); case ArrayValue: - return d->toArray(v->array()) == other.d->toArray(other.v->array()); + return JsonArray(d, array) == JsonArray(other.d, other.array); case ObjectValue: - return d->toObject(v->object()) == other.d->toObject(other.v->object()); - case NullValue: - break; + return JsonObject(d, object) == JsonObject(other.d, other.object); } return true; } @@ -297,10 +311,70 @@ bool JsonValue::operator!=(const JsonValue &other) const void JsonValue::detach() { - Data *x = d->detach(d->offsetOf(v), v->size); + if (!d) + return; + + Data *x = d->detach(d->offsetOf(object), object->size); x->ref.ref(); if (!d->ref.deref()) delete d; d = x; - v = d->_value; + object = d->_object; +} + +int JsonValue::requiredStorage() const +{ + switch (t) { + case NumberValue: + return sizeof(double); + case StringValue: + return sizeof(uint) + sizeof(ushort)*stringData->size; + case ArrayValue: + return array ? array->size : sizeof(Array); + case ObjectValue: + return object ? object->size : sizeof(Object); + case NullValue: + case BooleanValue: + break; + } + return 0; +} + +uint JsonValue::valueToStore(uint offset) const +{ + switch (t) { + case NullValue: + break; + case BooleanValue: + return b; + case NumberValue: + case StringValue: + case ArrayValue: + case ObjectValue: + return offset; + } + return 0; +} + +void JsonValue::copyData(char *dest) const +{ + switch (t) { + case NumberValue: + memcpy(dest, raw, sizeof(dbl)); + break; + case StringValue: { + QString str = toString(); + *((int *)dest) = str.length(); + memcpy(dest + sizeof(int), str.constData(), str.length()*sizeof(ushort)); + break; + } + case ArrayValue: + case ObjectValue: { + const Base *b = array ? array : &emptyBase; + memcpy(dest, b, b->size); + break; + } + default: + break; + } } diff --git a/src/qjsonvalue.h b/src/qjsonvalue.h index 16e5da4..2c90f04 100644 --- a/src/qjsonvalue.h +++ b/src/qjsonvalue.h @@ -52,11 +52,24 @@ public: private: friend class Data; + friend class Value; friend class JsonArray; friend class JsonObject; - JsonValue(Data *data, Value *value); - Data *d; - Value *v; + JsonValue(Data *d, Base *b, const Value& v); + int requiredStorage() const; + uint valueToStore(uint offset) const; + void copyData(char *dest) const; + + ValueType t; + Data *d; // needed for Object and Array + union { + char raw[sizeof(double)]; + bool b; + double dbl; + QStringData *stringData; + Object *object; + Array *array; + }; }; } diff --git a/src/qjsonwriter.cpp b/src/qjsonwriter.cpp index 3ebc192..394f66b 100644 --- a/src/qjsonwriter.cpp +++ b/src/qjsonwriter.cpp @@ -134,30 +134,30 @@ static QByteArray escapedString(const QStackString &s) return ba; } -static void valueToJson(const Value *v, QByteArray &json, int indent) +static void valueToJson(const Base *b, const Value &v, QByteArray &json, int indent) { - ValueType type = v ? (ValueType)v->type : NullValue; + ValueType type = (ValueType)v.type; switch (type) { case BooleanValue: - json += v->val ? "true" : "false"; + json += v.val ? "true" : "false"; break; case NumberValue: - json += QByteArray::number(v->toNumber()); + json += QByteArray::number(v.toNumber(b)); break; case StringValue: json += '"'; - json += escapedString(v->shallowString()); + json += escapedString(v.shallowString(b)); json += '"'; break; case ArrayValue: json += "[\n"; - arrayContentToJson(v->array(), json, indent + 1); + arrayContentToJson(v.array(b), json, indent + 1); json += QByteArray(4*indent, ' '); json += "]"; break; case ObjectValue: json += "{\n"; - objectContentToJson(v->object(), json, indent + 1); + objectContentToJson(v.object(b), json, indent + 1); json += QByteArray(4*indent, ' '); json += "}"; break; @@ -177,7 +177,7 @@ static void arrayContentToJson(const Array *a, QByteArray &json, int indent) uint i = 0; while (1) { json += indentString; - valueToJson(a->at(i), json, indent); + valueToJson(a, a->at(i), json, indent); if (++i == a->length) { json += '\n'; @@ -203,8 +203,7 @@ static void objectContentToJson(const Object *o, QByteArray &json, int indent) json += '"'; json += escapedString(e->shallowKey()); json += "\": "; - const Value *v = e->value(); - valueToJson(v, json, indent); + valueToJson(o, e->value, json, indent); if (++i == o->length) { json += '\n'; diff --git a/tests/auto/tst_qtjson.cpp b/tests/auto/tst_qtjson.cpp index 3b6fc60..da1cc57 100644 --- a/tests/auto/tst_qtjson.cpp +++ b/tests/auto/tst_qtjson.cpp @@ -102,6 +102,7 @@ void TestQtJson::cleanup() void TestQtJson::testValueSimple() { JsonValue value(true); + QCOMPARE(value.type(), BooleanValue); QCOMPARE(value.toNumber(), 0.); QCOMPARE(value.toInt(), 0); QCOMPARE(value.toString(), QString()); @@ -110,6 +111,7 @@ void TestQtJson::testValueSimple() QCOMPARE(value.toArray(), JsonArray()); value.setValue(999.); + QCOMPARE(value.type(), NumberValue); QCOMPARE(value.toNumber(), 999.); QCOMPARE(value.toInt(), 999); QCOMPARE(value.toString(), QString()); @@ -147,6 +149,7 @@ void TestQtJson::testObjectSimple() { JsonObject object; object.insert("number", 999.); + QCOMPARE(object.value("number").type(), NumberValue); QCOMPARE(object.value("number").toNumber(), 999.); object.insert("string", QString::fromLatin1("test")); QCOMPARE(object.value("string").toString(), QString("test")); @@ -185,6 +188,7 @@ void TestQtJson::testArraySimple() array.append(QString::fromLatin1("test")); array.append(true); + JsonValue val = array.at(0); QCOMPARE(array.at(0).toNumber(), 999.); QCOMPARE(array.at(1).toString(), QString("test")); QCOMPARE(array.at(2).toBool(), true); @@ -329,6 +333,7 @@ void TestQtJson::testArrayNestedEmpty() JsonObject object; JsonArray inner; object.insert("inner", inner); + JsonValue val = object.value("inner"); JsonArray value = object.value("inner").toArray(); QCOMPARE(value.size(), 0); QCOMPARE(value, inner); |