Mercurial > projects > orange
diff orange/serialization/archives/XMLArchive.d @ 20:9a575087b961
Added support for slices. Strings and arrays are now treated as references.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 04 Oct 2010 18:27:21 +0200 |
parents | 3d42ea434d46 |
children | 51f05fd6a626 |
line wrap: on
line diff
--- a/orange/serialization/archives/XMLArchive.d Thu Aug 12 23:24:51 2010 +0200 +++ b/orange/serialization/archives/XMLArchive.d Mon Oct 04 18:27:21 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); @@ -361,18 +417,8 @@ auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); auto name = fromDataType!(string)(runtimeType); - id = getValueOfAttribute(Attributes.idAttribute); - - 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); + id = getValueOfAttribute(Attributes.idAttribute); + T result = cast(T) newInstance(name); addUnarchivedReference(result, id); @@ -391,16 +437,34 @@ 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); + + 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); @@ -409,8 +473,11 @@ return T.init; lastElement = element; - auto length = getValueOfAttribute(Attributes.lengthAttribute); + auto length = getValueOfAttribute(Attributes.lengthAttribute); value.length = fromDataType!(size_t)(length); + slice.id = getValueOfAttribute(Attributes.idAttribute); + + addUnarchivedSlice(value, slice.id); return value; } @@ -553,9 +620,11 @@ } } - 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; @@ -587,6 +656,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) @@ -603,6 +679,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++); @@ -624,6 +708,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; @@ -661,4 +760,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