# HG changeset patch # User Jacob Carlborg # Date 1290164104 -3600 # Node ID bffcbc8c392bb061109f75a32fd80f5968e86576 # Parent fc315d786f2469cc423fd40952c245a16a21ced2 Associative arrays are now treated as references. diff -r fc315d786f24 -r bffcbc8c392b orange/serialization/Serializer.d --- a/orange/serialization/Serializer.d Fri Nov 19 11:14:55 2010 +0100 +++ b/orange/serialization/Serializer.d Fri Nov 19 11:55:04 2010 +0100 @@ -51,7 +51,7 @@ private { ErrorCallback errorCallback_; - IArchive archive; + Archive archive; size_t keyCounter; Id idCounter; @@ -72,7 +72,7 @@ void delegate (ArchiveException exception, string[] data) doNothingOnErrorCallback; } - this (IArchive archive) + this (Archive archive) { this.archive = archive; @@ -264,10 +264,18 @@ private void serializeAssociativeArray (T) (T value, string key) { + auto reference = getSerializedReference(value); + + if (reference != Id.max) + return archive.archiveReference(key, reference); + + Id id = nextId; + addSerializedReference(value, id); + string keyType = KeyTypeOfAssociativeArray!(T).stringof; string valueType = ValueTypeOfAssociativeArray!(T).stringof; - archive.archiveAssociativeArray(keyType, valueType, value.length, key, nextId, { + archive.archiveAssociativeArray(keyType, valueType, value.length, key, id, { size_t i; foreach(k, v ; value) @@ -541,12 +549,17 @@ private T deserializeAssociativeArray (T) (string key) { + auto id = deserializeReference(key); + + if (auto reference = getDeserializedReference!(T)(id)) + return *reference; + T value; alias KeyTypeOfAssociativeArray!(T) Key; alias ValueTypeOfAssociativeArray!(T) Value; - archive.unarchiveAssociativeArray(key, (size_t length) { + id = archive.unarchiveAssociativeArray(key, (size_t length) { for (size_t i = 0; i < length; i++) { Key aaKey; @@ -565,45 +578,10 @@ } }); - return value; - } - - /* auto id = deserializeReference(key); - - if (auto reference = getDeserializedReference!(T)(id)) - return *reference; - - T value; - Object val = value; - - archive.unarchiveObject(key, id, val, { - triggerEvents(deserializing, value, { - value = cast(T) val; - auto runtimeType = value.classinfo.name; - - if (runtimeType in deserializers) - { - auto wrapper = getDeserializerWrapper!(T)(runtimeType); - wrapper(value, this, key); - } - - else static if (isSerializable!(T, Serializer)) - value.fromData(this, key); - - else - { - if (isBaseClass(value)) - throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a deserializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__); - - objectStructDeserializeHelper(value); - } - }); - }); - addDeserializedReference(value, id); return value; - */ + } private T deserializePointer (T) (string key) { @@ -742,14 +720,14 @@ private void addSerializedReference (T) (T value, Id id) { - static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); + static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`)); serializedReferences[cast(void*) value] = id; } private void addDeserializedReference (T) (T value, Id id) { - static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); + static assert(isReference!(T) || isAssociativeArray!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object, pointer or associative array.`)); deserializedReferences[id] = cast(void*) value; } @@ -781,7 +759,7 @@ { if (auto array = slice.id in deserializedSlices) return &(cast(T) *array)[slice.offset .. slice.offset + slice.length]; // dereference the array, cast it to the right type, - // slice it and then return a pointer to the result } + // slice it and then return a pointer to the result return null; } @@ -955,271 +933,4 @@ return annotations; } -} -version (none): - void main () - { - - - void serializeObject () - { - serializer.reset; - data = ` - - - - - `; - - serializer.serialize(B()); - assert(archive.data == data); - } - - void serializeStruct () - { - serializer.reset; - data = ` - - - - - `; - - serializer.serialize(B()); - assert(archive.data == data); - } - - // Struct - - - - // String - - serializer.reset; - data = ` - - - - foo - - - `; - - auto c = new C; - c.str = "foo"; - serializer.serialize(c); - assert(archive.data == data); - - // Deserializing - - auto cDeserialized = serializer.deserialize!(C)(data); - assert(c.str == cDeserialized.str); - - // Array - - serializer.reset; - data = ` - - - - - 27 - 382 - 283 - 3820 - 32 - 832 - - - - `; - - auto d = new D; - d.arr = [27, 382, 283, 3820, 32, 832]; - serializer.serialize(d); - assert(archive.data == data); - - // Deserializing - - auto dDeserialized = serializer.deserialize!(D)(data); - assert(d.arr == dDeserialized.arr); - - // Associative Array - - serializer.reset(); - data = ` - - - - - - 1 - - - 2 - - - 3 - - - 4 - - - 6 - - - 7 - - - 39 - - - 472 - - - - - `; - - auto e = new E; - e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7]; - serializer.serialize(e); - assert(archive.data == data); - - // Deserializing - - auto eDeserialized = serializer.deserialize!(E)(data); - //assert(e.aa == eDeserialized.aa); // cannot compare associative array - - // Pointer - - serializer.reset(); - data = ` - - - - - 9 - - 9 - - - `; - - auto f = new F; - f.value = 9; - f.ptr = &f.value; - serializer.serialize(f); - //assert(archive.data == data); // this is not a reliable comparison, the order of int and pointer is not reliable - - // Deserializing - - auto fDeserialized = serializer.deserialize!(F)(data); - assert(*f.ptr == *fDeserialized.ptr); - - // Enum - - serializer.reset(); - data = ` - - - - 1 - - - `; - - auto g = new G; - g.foo = Foo.b; - serializer.serialize(g); - assert(archive.data == data); - - // Deserializing - - auto gDeserialized = serializer.deserialize!(G)(data); - assert(g.foo == gDeserialized.foo); - - // Primitives - - serializer.reset; - data = ` - - - - 1 - a - b - 0 - 0 - 1 - 1 - 0 - 1 - 1 - 1 - 1 - 1 - c - true - - - `; - - auto h = new H; - - h.bool_ = true; - h.byte_ = 1; - h.char_ = 'a'; - //h.cdouble_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!() - //h.cfloat_ = 0.0f + 0.0f * 1.0i; // currently not suppported by to!() - //h.creal_ = 0.0 + 0.0 * 1.0i; // currently not suppported by to!() - h.dchar_ = 'b'; - h.double_ = 0.0; - h.float_ = 0.0f; - //h.idouble_ = 0.0 * 1.0i; // currently not suppported by to!() - //h.ifloat_ = 0.0f * 1.0i; // currently not suppported by to!() - h.int_ = 1; - //h.ireal_ = 0.0 * 1.0i; // currently not suppported by to!() - h.long_ = 1L; - h.real_ = 0.0; - h.short_ = 1; - h.ubyte_ = 1U; - h.uint_ = 1U; - h.ulong_ = 1LU; - h.ushort_ = 1U; - h.wchar_ = 'c'; - - serializer.serialize(h); - //assert(archive.data == data); // this is not a reliable comparison - - // Deserializing - - auto hDeserialized = serializer.deserialize!(H)(data); - assert(h == hDeserialized); - - // Typedef - - serializer.reset(); - data = ` - - - - - 1 - - - - `; - - auto i = new I; - i.a = 1; - serializer.serialize(i); - assert(archive.data == data); - - // Deserializing - - auto iDeserialized = serializer.deserialize!(I)(data); - assert(i.a == iDeserialized.a); - - println("unit tests successful"); - } +} \ No newline at end of file diff -r fc315d786f24 -r bffcbc8c392b orange/serialization/archives/Archive.d --- a/orange/serialization/archives/Archive.d Fri Nov 19 11:14:55 2010 +0100 +++ b/orange/serialization/archives/Archive.d Fri Nov 19 11:55:04 2010 +0100 @@ -47,7 +47,7 @@ size_t id = size_t.max; } -interface IArchive +interface Archive { alias Serializer.Id Id; @@ -113,7 +113,7 @@ Id unarchiveArray (string key, void delegate (size_t length) dg); void unarchiveArray (Id id, void delegate (size_t length) dg); - void unarchiveAssociativeArray (string type, void delegate (size_t length) dg); + Id unarchiveAssociativeArray (string type, void delegate (size_t length) dg); void unarchiveAssociativeArrayKey (string key, void delegate () dg); void unarchiveAssociativeArrayValue (string key, void delegate () dg); @@ -173,7 +173,7 @@ void postProcessArray (Id id); } -abstract class Archive (U) : IArchive +abstract class Base (U) : Archive { version (Tango) alias U[] Data; else mixin ("alias immutable(U)[] Data;"); diff -r fc315d786f24 -r bffcbc8c392b orange/serialization/archives/XMLArchive.d --- a/orange/serialization/archives/XMLArchive.d Fri Nov 19 11:14:55 2010 +0100 +++ b/orange/serialization/archives/XMLArchive.d Fri Nov 19 11:55:04 2010 +0100 @@ -18,9 +18,9 @@ import orange.util._; import orange.xml.XMLDocument; -final class XMLArchive (U = char) : Archive!(U) +final class XMLArchive (U = char) : Base!(U) { - private alias IArchive.Id Id; + private alias Archive.Id Id; private struct Tags { @@ -180,7 +180,8 @@ .attribute(Attributes.keyTypeAttribute, toData(keyType)) .attribute(Attributes.valueTypeAttribute, toData(valueType)) .attribute(Attributes.lengthAttribute, toData(length)) - .attribute(Attributes.keyAttribute, key); + .attribute(Attributes.keyAttribute, key) + .attribute(Attributes.idAttribute, toData(id)); dg(); }; @@ -560,23 +561,29 @@ }; } - void unarchiveAssociativeArray (string key, void delegate (size_t length) dg) + Id unarchiveAssociativeArray (string key, void delegate (size_t length) dg) { - restore(lastElement) in { + return restore!(Id)(lastElement) in { auto element = getElement(Tags.associativeArrayTag, key); if (!element.isValid) - return; + return Id.max; - lastElement = element; + lastElement = element; auto len = getValueOfAttribute(Attributes.lengthAttribute); if (!len) - return; + return Id.max; auto length = fromData!(size_t)(len); + auto id = getValueOfAttribute(Attributes.idAttribute); + + if (!id) + return Id.max; dg(length); + + return id.toId(); }; } diff -r fc315d786f24 -r bffcbc8c392b tests/Serializer.d --- a/tests/Serializer.d Fri Nov 19 11:14:55 2010 +0100 +++ b/tests/Serializer.d Fri Nov 19 11:55:04 2010 +0100 @@ -246,7 +246,7 @@ k = new K; k.a = [3 : 4, 1 : 2, 39 : 472, 6 : 7]; k.b = k.a; - + describe("Serializer") in { describe("serialize object") in { it("should return a serialized object") in { @@ -330,7 +330,7 @@ assert(archive.data().containsDefaultXmlContent()); assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.E" type="E" key="0" id="0"`)); - assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="aa"`)); + assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="aa" id="1"`)); assert(archive.data().containsXmlTag("key", `key="0"`)); assert(archive.data().containsXmlTag("int", `key="0"`, "1")); @@ -497,11 +497,44 @@ }; }; - describe("associative array references") in { - it("should return ") in { + describe("serialize associative array references") in { + it("should return a serialized associative array and a serialized reference") in { serializer.reset(); serializer.serialize(k); - println(archive.data); + + assert(archive.data().containsDefaultXmlContent()); + assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.K" type="K" key="0" id="0"`)); + assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="a" id="1"`)); + + assert(archive.data().containsXmlTag("key", `key="0"`)); + assert(archive.data().containsXmlTag("int", `key="0"`, "1")); + assert(archive.data().containsXmlTag("value", `key="0"`)); + assert(archive.data().containsXmlTag("int", `key="0"`, "2")); + + assert(archive.data().containsXmlTag("key", `key="1"`)); + assert(archive.data().containsXmlTag("int", `key="1"`, "3")); + assert(archive.data().containsXmlTag("value", `key="1"`)); + assert(archive.data().containsXmlTag("int", `key="1"`, "4")); + + assert(archive.data().containsXmlTag("key", `key="2"`)); + assert(archive.data().containsXmlTag("int", `key="2"`, "6")); + assert(archive.data().containsXmlTag("value", `key="2"`)); + assert(archive.data().containsXmlTag("int", `key="2"`, "7")); + + assert(archive.data().containsXmlTag("key", `key="3"`)); + assert(archive.data().containsXmlTag("int", `key="3"`, "39")); + assert(archive.data().containsXmlTag("value", `key="3"`)); + assert(archive.data().containsXmlTag("int", `key="3"`, "472")); + + assert(archive.data().containsXmlTag("reference", `key="b"`, "1")); + }; + }; + + describe("deserialize associative array references") in { + it("should return two deserialized associative arrays pointing to the same data") in { + auto kDeserialized = serializer.deserialize!(K)(archive.data); + + assert(kDeserialized.a is kDeserialized.b); }; }; };