summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-12-07 21:19:07 +0100
committerHicks James <jamey.hicks@nokia.com>2011-12-08 15:15:43 +0100
commit01ad456e4477a36a12162ef9866bd28b7202bfee (patch)
treec9b1c850a97af13bce78413cdf70c06dd69c8514
parentd02f9658c47599c4f07c269d18fbc503cafdffc2 (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.h288
-rw-r--r--src/qjsonarray.cpp29
-rw-r--r--src/qjsonglobal.h15
-rw-r--r--src/qjsonobject.cpp26
-rw-r--r--src/qjsonvalue.cpp266
-rw-r--r--src/qjsonvalue.h19
-rw-r--r--src/qjsonwriter.cpp19
-rw-r--r--tests/auto/tst_qtjson.cpp5
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);