More script streaming bits.

This commit is contained in:
Andrzej Kapolka 2014-06-09 14:35:20 -07:00
parent 32cf08ce65
commit fd469c543c
4 changed files with 362 additions and 2 deletions

View file

@ -31,6 +31,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(uint)
REGISTER_SIMPLE_TYPE_STREAMER(float)
REGISTER_SIMPLE_TYPE_STREAMER(QByteArray)
REGISTER_SIMPLE_TYPE_STREAMER(QColor)
REGISTER_SIMPLE_TYPE_STREAMER(QScriptValue)
REGISTER_SIMPLE_TYPE_STREAMER(QString)
REGISTER_SIMPLE_TYPE_STREAMER(QUrl)
REGISTER_SIMPLE_TYPE_STREAMER(QVariantList)
@ -286,6 +287,12 @@ void Bitstream::writeDelta(const QVariant& value, const QVariant& reference) {
streamer->writeRawDelta(*this, value, reference);
}
void Bitstream::writeRawDelta(const QVariant& value, const QVariant& reference) {
const TypeStreamer* streamer = getTypeStreamers().value(value.userType());
_typeStreamerStreamer << streamer;
streamer->writeRawDelta(*this, value, reference);
}
void Bitstream::readRawDelta(QVariant& value, const QVariant& reference) {
TypeReader typeReader;
_typeStreamerStreamer >> typeReader;
@ -310,6 +317,271 @@ void Bitstream::readRawDelta(QObject*& value, const QObject* reference) {
value = objectReader.readDelta(*this, reference);
}
void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& reference) {
if (reference.isUndefined() || reference.isNull()) {
*this << value;
} else if (reference.isBool()) {
if (value.isBool()) {
*this << false;
*this << value.toBool();
} else {
*this << true;
*this << value;
}
} else if (reference.isNumber()) {
if (value.isNumber()) {
*this << false;
*this << value.toNumber();
} else {
*this << true;
*this << value;
}
} else if (reference.isString()) {
if (value.isString()) {
*this << false;
*this << value.toString();
} else {
*this << true;
*this << value;
}
} else if (reference.isVariant()) {
if (value.isVariant()) {
*this << false;
writeRawDelta(value.toVariant(), reference.toVariant());
} else {
*this << true;
*this << value;
}
} else if (reference.isQObject()) {
if (value.isQObject()) {
*this << false;
writeRawDelta(value.toQObject(), reference.toQObject());
} else {
*this << true;
*this << value;
}
} else if (reference.isQMetaObject()) {
if (value.isQMetaObject()) {
*this << false;
*this << value.toQMetaObject();
} else {
*this << true;
*this << value;
}
} else if (reference.isDate()) {
if (value.isDate()) {
*this << false;
*this << value.toDateTime();
} else {
*this << true;
*this << value;
}
} else if (reference.isRegExp()) {
if (value.isRegExp()) {
*this << false;
*this << value.toRegExp();
} else {
*this << true;
*this << value;
}
} else if (reference.isArray()) {
if (value.isArray()) {
*this << false;
int length = value.property(ScriptCache::getInstance()->getLengthString()).toInt32();
*this << length;
int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32();
for (int i = 0; i < length; i++) {
if (i < referenceLength) {
writeDelta(value.property(i), reference.property(i));
} else {
*this << value.property(i);
}
}
} else {
*this << true;
*this << value;
}
} else if (reference.isObject()) {
if (value.isObject()) {
*this << false;
for (QScriptValueIterator it(value); it.hasNext(); ) {
it.next();
QScriptValue referenceValue = reference.property(it.scriptName());
if (it.value() != referenceValue) {
*this << it.scriptName();
writeRawDelta(it.value(), referenceValue);
}
}
for (QScriptValueIterator it(reference); it.hasNext(); ) {
it.next();
if (!value.property(it.scriptName()).isValid()) {
*this << it.scriptName();
writeRawDelta(QScriptValue(), it.value());
}
}
*this << QScriptString();
} else {
*this << true;
*this << value;
}
} else {
*this << value;
}
}
void Bitstream::readRawDelta(QScriptValue& value, const QScriptValue& reference) {
if (reference.isUndefined() || reference.isNull()) {
*this >> value;
} else if (reference.isBool()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
bool boolValue;
*this >> boolValue;
value = QScriptValue(boolValue);
}
} else if (reference.isNumber()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
qsreal numberValue;
*this >> numberValue;
value = QScriptValue(numberValue);
}
} else if (reference.isString()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
QString stringValue;
*this >> stringValue;
value = QScriptValue(stringValue);
}
} else if (reference.isVariant()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
QVariant variant;
readRawDelta(variant, reference.toVariant());
value = ScriptCache::getInstance()->getEngine()->newVariant(variant);
}
} else if (reference.isQObject()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
QObject* object;
readRawDelta(object, reference.toQObject());
value = ScriptCache::getInstance()->getEngine()->newQObject(object, QScriptEngine::ScriptOwnership);
}
} else if (reference.isQMetaObject()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
const QMetaObject* metaObject;
*this >> metaObject;
value = ScriptCache::getInstance()->getEngine()->newQMetaObject(metaObject);
}
} else if (reference.isDate()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
QDateTime dateTime;
*this >> dateTime;
value = ScriptCache::getInstance()->getEngine()->newDate(dateTime);
}
} else if (reference.isRegExp()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
QRegExp regExp;
*this >> regExp;
value = ScriptCache::getInstance()->getEngine()->newRegExp(regExp);
}
} else if (reference.isArray()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
int length;
*this >> length;
value = ScriptCache::getInstance()->getEngine()->newArray(length);
int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32();
for (int i = 0; i < length; i++) {
QScriptValue element;
if (i < referenceLength) {
readDelta(element, reference.property(i));
} else {
*this >> element;
}
value.setProperty(i, element);
}
}
} else if (reference.isObject()) {
bool typeChanged;
*this >> typeChanged;
if (typeChanged) {
*this >> value;
} else {
// start by shallow-copying the reference
value = ScriptCache::getInstance()->getEngine()->newObject();
for (QScriptValueIterator it(reference); it.hasNext(); ) {
it.next();
value.setProperty(it.scriptName(), it.value());
}
// then apply the requested changes
forever {
QScriptString name;
*this >> name;
if (!name.isValid()) {
break;
}
QScriptValue scriptValue;
readRawDelta(scriptValue, reference.property(name));
value.setProperty(name, scriptValue);
}
}
} else {
*this >> value;
}
}
Bitstream& Bitstream::operator<<(bool value) {
if (value) {
_byte |= (1 << _position);
@ -612,11 +884,11 @@ enum ScriptValueType {
const int SCRIPT_VALUE_BITS = 4;
void writeScriptValueType(Bitstream& out, ScriptValueType type) {
static void writeScriptValueType(Bitstream& out, ScriptValueType type) {
out.write(&type, SCRIPT_VALUE_BITS);
}
ScriptValueType readScriptValueType(Bitstream& in) {
static ScriptValueType readScriptValueType(Bitstream& in) {
ScriptValueType type = (ScriptValueType)0;
in.read(&type, SCRIPT_VALUE_BITS);
return type;

View file

@ -292,11 +292,15 @@ public:
template<class T> void writeDelta(const T& value, const T& reference);
template<class T> void readDelta(T& value, const T& reference);
void writeRawDelta(const QVariant& value, const QVariant& reference);
void readRawDelta(QVariant& value, const QVariant& reference);
void writeRawDelta(const QObject* value, const QObject* reference);
void readRawDelta(QObject*& value, const QObject* reference);
void writeRawDelta(const QScriptValue& value, const QScriptValue& reference);
void readRawDelta(QScriptValue& value, const QScriptValue& reference);
template<class T> void writeRawDelta(const T& value, const T& reference);
template<class T> void readRawDelta(T& value, const T& reference);

View file

@ -13,11 +13,90 @@
#include <QNetworkReply>
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QTextStream>
#include "AttributeRegistry.h"
#include "ScriptCache.h"
static int scriptValueMetaTypeId = qRegisterMetaType<QScriptValue>();
bool operator==(const QScriptValue& first, const QScriptValue& second) {
if (first.isUndefined()) {
return second.isUndefined();
} else if (first.isNull()) {
return second.isNull();
} else if (first.isBool()) {
return second.isBool() && first.toBool() == second.toBool();
} else if (first.isNumber()) {
return second.isNumber() && first.toNumber() == second.toNumber();
} else if (first.isString()) {
return second.isString() && first.toString() == second.toString();
} else if (first.isVariant()) {
return second.isVariant() && first.toVariant() == second.toVariant();
} else if (first.isQObject()) {
return second.isQObject() && first.toQObject() == second.toQObject();
} else if (first.isQMetaObject()) {
return second.isQMetaObject() && first.toQMetaObject() == second.toQMetaObject();
} else if (first.isDate()) {
return second.isDate() && first.toDateTime() == second.toDateTime();
} else if (first.isRegExp()) {
return second.isRegExp() && first.toRegExp() == second.toRegExp();
} else if (first.isArray()) {
if (!second.isArray()) {
return false;
}
int length = first.property(ScriptCache::getInstance()->getLengthString()).toInt32();
if (second.property(ScriptCache::getInstance()->getLengthString()).toInt32() != length) {
return false;
}
for (int i = 0; i < length; i++) {
if (first.property(i) != second.property(i)) {
return false;
}
}
return true;
} else if (first.isObject()) {
if (!second.isObject()) {
return false;
}
int propertyCount = 0;
for (QScriptValueIterator it(first); it.hasNext(); ) {
it.next();
if (second.property(it.scriptName()) != it.value()) {
return false;
}
propertyCount++;
}
// make sure the second has exactly as many properties as the first
for (QScriptValueIterator it(second); it.hasNext(); ) {
it.next();
if (--propertyCount < 0) {
return false;
}
}
return true;
} else {
return !second.isValid();
}
}
bool operator!=(const QScriptValue& first, const QScriptValue& second) {
return !(first == second);
}
ScriptCache* ScriptCache::getInstance() {
static ScriptCache cache;
return &cache;

View file

@ -65,6 +65,11 @@ private:
QScriptString _generatorString;
};
Q_DECLARE_METATYPE(QScriptValue)
bool operator==(const QScriptValue& first, const QScriptValue& second);
bool operator!=(const QScriptValue& first, const QScriptValue& second);
/// A program loaded from the network.
class NetworkProgram : public Resource {
Q_OBJECT