Mercurial > projects > orange
diff orange/serialization/archives/XMLArchive.d @ 22:963b756ed579
Resolved merge conflicts.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 04 Oct 2010 20:42:45 +0200 |
parents | 8ab9588b92bf 51f05fd6a626 |
children | 55f0a9d5df8d |
line wrap: on
line diff
--- a/orange/serialization/archives/XMLArchive.d Sat Aug 14 17:24:42 2010 +0200 +++ b/orange/serialization/archives/XMLArchive.d Mon Oct 04 20:42:45 2010 +0200 @@ -40,7 +40,8 @@ static const DataType associativeArrayTag = "associativeArray"; static const DataType typedefTag = "typedef"; static const DataType nullTag = "null"; - static const DataType enumTag = "enum"; + static const DataType enumTag = "enum"; + static const DataType sliceTag = "slice"; } private struct Attributes @@ -53,10 +54,48 @@ static const DataType idAttribute = "id"; static const DataType keyTypeAttribute = "keyType"; static const DataType valueTypeAttribute = "valueType"; + static const DataType offsetAttribute = "offset"; } private { + struct ArrayNode + { + XMLDocument!(U).Node parent; + XMLDocument!(U).Node node; + DataType id; + DataType key; + } + + struct Array + { + void* ptr; + size_t length; + size_t elementSize; + + static Array opCall (T) (T[] value) + { + Array array; + array.ptr = value.ptr; + array.length = value.length; + array.elementSize = T.sizeof; + + return array; + } + + bool isSliceOf (Array b) + { + return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize; + } + } + + struct Slice + { + size_t length; + size_t offset; + DataType id; + } + DataType archiveType = "org.dsource.orange.xml"; DataType archiveVersion = "0.1"; @@ -71,6 +110,9 @@ DataType[void*] archivedReferences; void*[DataType] unarchivedReferences; + ArrayNode[Array] arraysToBeArchived; + void[][DataType] unarchivedSlices; + size_t idCounter; } @@ -228,18 +270,32 @@ } private void archiveString (T) (T value, DataType key) - { - lastElement.element(Tags.stringTag, toDataType(value)) - .attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof)) - .attribute(Attributes.keyAttribute, key); + { + archiveArrayImpl(value, key, Tags.stringTag, toDataType(value)); } private void archiveArray (T) (T value, DataType key) - { - lastElement = lastElement.element(Tags.arrayTag) - .attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof)) + { + archiveArrayImpl(value, key, Tags.arrayTag); + } + + private void archiveArrayImpl (T) (T value, DataType key, DataType tag, DataType content = null) + { + DataType id = nextId; + auto parent = lastElement; + + if (value.length == 0) + lastElement = lastElement.element(tag); + + else + lastElement = doc.createNode(tag, content); + + lastElement.attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof)) .attribute(Attributes.lengthAttribute, toDataType(value.length)) - .attribute(Attributes.keyAttribute, key); + .attribute(Attributes.keyAttribute, key) + .attribute(Attributes.idAttribute, id); + + arraysToBeArchived[Array(value)] = ArrayNode(parent, lastElement, id, key); } private void archiveAssociativeArray (T) (T value, DataType key) @@ -314,7 +370,7 @@ value = unarchiveString!(T)(key); else static if (isArray!(T)) - value = unarchiveArray!(T)(key); + value = unarchiveArray!(T)(key, callDelegate); else static if (isAssociativeArray!(T)) value = unarchiveAssociativeArray!(T)(key); @@ -362,7 +418,7 @@ auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); if (!runtimeType) - return T.init; + return T.init; auto name = fromDataType!(string)(runtimeType); id = getValueOfAttribute(Attributes.idAttribute); @@ -370,16 +426,7 @@ if (!id) return T.init; - T result; - - /*static if (is(typeof(T._ctor))) - { - ParameterTupleOf!(typeof(T._ctor)) params; - result = factory!(T, typeof(params))(name, params); - } - - else*/ - result = cast(T) newInstance(name); + T result = cast(T) newInstance(name); addUnarchivedReference(result, id); @@ -398,16 +445,37 @@ private T unarchiveString (T) (DataType key) { + auto slice = unarchiveSlice(key); + + if (auto tmp = getUnarchivedSlice!(T)(slice)) + return *tmp; + auto element = getElement(Tags.stringTag, key); if (!element.isValid) return T.init; - return fromDataType!(T)(element.value); + auto value = fromDataType!(T)(element.value); + slice.id = getValueOfAttribute(Attributes.idAttribute, element); + + if (!slice.id) + return T.init; + + addUnarchivedSlice(value, slice.id); + + return value; } - private T unarchiveArray (T) (DataType key) - { + private T unarchiveArray (T) (DataType key, ref bool callDelegate) + { + auto slice = unarchiveSlice(key); + + if (auto tmp = getUnarchivedSlice!(T)(slice)) + { + callDelegate = false; + return *tmp; + } + T value; auto element = getElement(Tags.arrayTag, key); @@ -422,6 +490,12 @@ return T.init; value.length = fromDataType!(size_t)(length); + slice.id = getValueOfAttribute(Attributes.idAttribute); + + if (!slice.id) + return T.init; + + addUnarchivedSlice(value, slice.id); return value; } @@ -564,12 +638,14 @@ } return doc.Node.invalid; - } + } } - private DataType getValueOfAttribute (DataType attribute) + private DataType getValueOfAttribute (DataType attribute, doc.Node element = doc.Node.invalid) { - auto set = lastElement.query.attribute(attribute); + if (!element.isValid) element = lastElement; + + auto set = element.query.attribute(attribute); if (set.nodes.length == 1) return set.nodes[0].value; @@ -585,8 +661,8 @@ errorCallback(new ArchiveException(`Could not unarchive the value of the attribute "` ~ to!(string)(attribute) ~ `" due to malformed data.`, __FILE__, __LINE__), [attribute]); } } - - return null; + + return null; } private void addArchivedReference (T) (T value, DataType id) @@ -603,6 +679,13 @@ unarchivedReferences[id] = cast(void*) value; } + private void addUnarchivedSlice (T) (T value, DataType id) + { + static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`)); + + unarchivedSlices[id] = value; + } + private DataType getArchivedReference (T) (T value) { if (auto tmp = cast(void*) value in archivedReferences) @@ -619,6 +702,14 @@ return null; } + private T* getUnarchivedSlice (T) (Slice slice) + { + if (auto array = slice.id in unarchivedSlices) + return &(cast(T) *array)[slice.offset .. slice.length + 1]; // dereference the array, cast it to the right type, + // slice it and then return a pointer to the result + return null; + } + private DataType nextId () { return toDataType(idCounter++); @@ -640,6 +731,21 @@ return cast(DataType) null; } + private Slice unarchiveSlice (DataType key) + { + auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false); + + if (element.isValid) + { + auto length = fromDataType!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element)); + auto offset = fromDataType!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element)); + + return Slice(length, offset, element.value); + } + + return Slice.init; + } + private struct AssociativeArrayVisitor (Key, Value) { private XMLArchive archive; @@ -677,4 +783,32 @@ return result; } } + + public void postProcess () + { + bool foundSlice = true; + + foreach (slice, sliceNode ; arraysToBeArchived) + { + foreach (array, arrayNode ; arraysToBeArchived) + { + if (slice.isSliceOf(array) && slice != array) + { + sliceNode.parent.element(Tags.sliceTag, arrayNode.id) + .attribute(Attributes.keyAttribute, sliceNode.key) + .attribute(Attributes.offsetAttribute, toDataType((slice.ptr - array.ptr) / slice.elementSize)) + .attribute(Attributes.lengthAttribute, toDataType(slice.length)); + + foundSlice = true; + break; + } + + else + foundSlice = false; + } + + if (!foundSlice) + sliceNode.parent.attach(sliceNode.node); + } + } } \ No newline at end of file