changeset 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
files dsss.conf orange/serialization/Serializer.d orange/serialization/archives/Archive.d orange/serialization/archives/XMLArchive.d orange/xml/XMLDocument.d
diffstat 5 files changed, 231 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/dsss.conf	Thu Aug 12 23:24:51 2010 +0200
+++ b/dsss.conf	Mon Oct 04 18:27:21 2010 +0200
@@ -1,1 +1,1 @@
-[orange]
\ No newline at end of file
+[main.d]
\ No newline at end of file
--- a/orange/serialization/Serializer.d	Thu Aug 12 23:24:51 2010 +0200
+++ b/orange/serialization/Serializer.d	Mon Oct 04 18:27:21 2010 +0200
@@ -22,8 +22,8 @@
 private
 {
 	alias orange.util.CTFE.contains ctfeContains;
-	
-	private enum Mode
+
+	enum Mode
 	{
 		serializing,
 		deserializing
@@ -38,7 +38,7 @@
 	static assert(isArchive!(ArchiveType), format!(`The type "`, ArchiveType, `" does not implement the necessary methods to be an archive.`));
 	
 	alias ArchiveType.ErrorCallback ErrorCallback;
-	alias ArchiveType.DataType DataType;
+	alias ArchiveType.DataType DataType;	
 	
 	private
 	{
@@ -120,6 +120,14 @@
 		if (!hasBegunSerializing)
 			hasBegunSerializing = true;
 		
+		serializeInternal(value, key);
+		archive.postProcess;
+
+		return archive.data;
+	}
+	
+	private void serializeInternal (T) (T value, DataType key = null)
+	{
 		if (!key)
 			key = nextKey;
 		
@@ -163,8 +171,6 @@
 			error:
 			throw new SerializationException(format!(`The type "`, T, `" cannot be serialized.`), __FILE__, __LINE__);
 		}
-		
-		return archive.data;
 	}
 	
 	private void serializeObject (T) (T value, DataType key)
@@ -223,10 +229,10 @@
 	}
 
 	private void serializeArray (T) (T value, DataType key)
-	{		
+	{
 		archive.archive(value, key, {
 			foreach (i, e ; value)
-				serialize(e, toDataType(i));
+				serializeInternal(e, toDataType(i));
 		});
 	}
 
@@ -234,7 +240,7 @@
 	{
 		archive.archive(value, key, {
 			foreach(k, v ; value)
-				serialize(v, toDataType(k));
+				serializeInternal(v, toDataType(k));
 		});
 	}
 
@@ -256,7 +262,7 @@
 					throw new SerializationException(`The value with the key "` ~ to!(string)(key) ~ `"` ~ format!(` of the type "`, T, `" cannot be serialized on its own, either implement orange.serialization.Serializable.isSerializable or register a serializer.`), __FILE__, __LINE__);
 				
 				else
-					serialize(*value, key);
+					serializeInternal(*value, key);
 			}				
 		});
 	}
@@ -274,7 +280,7 @@
 	private void serializeTypeDef (T) (T value, DataType key)
 	{
 		archive.archive(value, key, {
-			serialize!(BaseTypeOfTypeDef!(T))(value, key);
+			serializeInternal!(BaseTypeOfTypeDef!(T))(value, key);
 		});
 	}
 	
@@ -470,7 +476,7 @@
 			{
 				alias typeof(T.tupleof[i]) Type;				
 				Type v = value.tupleof[i];
-				serialize(v, toDataType(field));
+				serializeInternal(v, toDataType(field));
 			}				
 		}
 		
--- a/orange/serialization/archives/Archive.d	Thu Aug 12 23:24:51 2010 +0200
+++ b/orange/serialization/archives/Archive.d	Mon Oct 04 18:27:21 2010 +0200
@@ -17,6 +17,21 @@
 
 import orange.serialization.archives.ArchiveException;
 
+struct Slice
+{
+	size_t length;
+	void* ptr;
+	
+	static Slice opCall (T) (T[] value)
+	{
+		Slice slice;
+		slice.length = value.length;
+		slice.ptr = value.ptr;
+		
+		return slice;
+	}
+}
+
 interface IArchive
 {
 	void beginArchiving ();
@@ -53,5 +68,13 @@
 		
 		catch (ConversionException e)
 			throw new ArchiveException(e);
-	}	
+	}
+	
+	protected bool isSliceOf (T, U = T) (T[] a, U[] b)
+	{
+		void* aPtr = a.ptr;
+		void* bPtr = b.ptr;
+		
+		return aPtr >= bPtr && aPtr + a.length * T.sizeof <= bPtr + b.length * U.sizeof;
+	}
 }
\ No newline at end of file
--- 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
--- a/orange/xml/XMLDocument.d	Thu Aug 12 23:24:51 2010 +0200
+++ b/orange/xml/XMLDocument.d	Mon Oct 04 18:27:21 2010 +0200
@@ -24,6 +24,8 @@
 	
 	version = Phobos;
 }
+
+import orange.util.io;
 	
 template Char (T)
 {
@@ -116,25 +118,32 @@
 	{
 	    private InternalNode node;
 	    
-	    version (Phobos)
+	    version (Tango)
+	    {
+		    private static Node opCall (InternalNode node)
+	   		{
+		    	Node proxy;
+	   			proxy.node = node;
+
+	   			return proxy;
+	   		}
+	    }
+	    
+	    else
 	    {
 	        private bool shouldAddToDoc = true;
 	        private bool isRoot = true;
-	    }
-	    
-	    private static Node opCall (InternalNode node, bool shouldAddToDoc = false, bool isRoot = false)
-   		{
-	    	Node proxy;
-   			proxy.node = node;
-
-   			version (Phobos)
-   			{
+	        
+		    private static Node opCall (InternalNode node, bool shouldAddToDoc = false, bool isRoot = false)
+	   		{
+		    	Node proxy;
+	   			proxy.node = node;
    				proxy.shouldAddToDoc = shouldAddToDoc;
    				proxy.isRoot = isRoot;
-   			}
 
-   			return proxy;
-   		}
+	   			return proxy;
+	   		}
+	    }
 	    
 	    public static Node invalid ()
 	    {
@@ -215,6 +224,12 @@
 			version (Tango) return *this;			
 			else return this;
 		}
+		
+		void attach (Node node)
+		{
+			version (Tango) this.node.move(node.node);
+			else this.node.elements ~= node.node;
+		}
 	}
 	
 	struct QueryProxy
@@ -441,4 +456,10 @@
 		else
 			return doc.prolog ~ "\n" ~ join(doc.pretty(indentation), "\n");
 	}
+	
+	Node createNode (tstring name, tstring value = null)
+	{
+		version (Tango) return Node(tree.element(name, value).node.detach);
+		else return Node(new Element(name, value), false, false);
+	}
 }
\ No newline at end of file