changeset 1:11a31bd929f9

Removed dependency on private library
author Jacob Carlborg <doob@me.com>
date Mon, 31 May 2010 16:06:36 +0200
parents f7b078e85f7f
children ea37a9470e3e
files orange/util/CTFE.d orange/util/Reflection.d orange/util/Traits.d orange/util/Use.d orange/util/collection/Array.d orange/util/io.d orange/util/string.d
diffstat 7 files changed, 2359 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/orange/util/CTFE.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/CTFE.d	Mon May 31 16:06:36 2010 +0200
@@ -6,4 +6,157 @@
  */
 module orange.util.CTFE;
 
-public import mambo.util.CTFE;
\ No newline at end of file
+import orange.util.string;
+import orange.util.Traits;
+
+template format (ARGS...)
+{
+	static if (ARGS.length == 0)
+		const format = "";
+	
+	else
+	{
+		static if (is(typeof(ARGS[0]) : string))
+			const format = ARGS[0] ~ format!(ARGS[1 .. $]);
+		
+		else
+		{
+			pragma(msg, typeof(ARGS[0].stringof));
+			const format = toString_!(ARGS[0]) ~ format!(ARGS[1 .. $]);
+		}
+					
+	}
+}
+
+private
+{
+	template toString_ (T)
+	{
+		const toString_ = T.stringof;
+	}
+
+	template toString_ (int i)
+	{
+		const toString_ = itoa!(i);
+	}
+
+	template toString_ (long l)
+	{
+		const toString_ = itoa!(l);
+	}
+
+	template toString_ (bool b)
+	{
+		const toString_ = b ? "true" : "false";
+	}
+
+	template toString_ (float f)
+	{
+		const toString_ = "";
+	}
+	
+	template toString_ (alias a)
+	{
+		const toString_ = a.stringof;
+	}
+}
+
+/**
+ * Compile-time function to get the index of the give element.
+ * 
+ * Performs a linear scan, returning the index of the first occurrence 
+ * of the specified element in the array, or U.max if the array does 
+ * not contain the element.
+ * 
+ * Params:
+ *     arr = the array to get the index of the element from
+ *     element = the element to find
+ *     
+ * Returns: the index of the element or size_t.max if the element was not found.
+ */
+size_t indexOf (T) (T[] arr, T element)
+{
+	static if (is(T == char) || is(T == wchar) || is(T == dchar))
+	{
+		foreach (i, e ; arr)
+			if (e == element)
+				return i;
+	}
+	
+	else
+	{
+		foreach (i, e ; arr)
+			if (e == element)
+				return i;
+	}
+	
+	return size_t.max;
+}
+
+/**
+ * Returns true if the given array contains the given element,
+ * otherwise false.
+ * 
+ * Params:
+ *     arr = the array to search in for the element
+ *     element = the element to search for
+ *     
+ * Returns: true if the array contains the element, otherwise false
+ */
+bool contains (T) (T[] arr, T element)
+{
+	return arr.indexOf(element) != size_t.max;
+}
+
+/**
+ * CTFE, splits the given string on the given pattern
+ * 
+ * Params:
+ *     str = the string to split 
+ *     splitChar = the character to split on
+ *     
+ * Returns: an array of strings containing the splited string
+ */
+T[][] split (T) (T[] str, T splitChar = ',')
+{
+	T[][] arr;
+	size_t x;
+	
+	foreach (i, c ; str)
+	{
+		if (splitChar == c)
+		{
+			if (str[x] == splitChar)
+				x++;
+			
+			arr ~= str[x .. i];
+			x = i;
+		}
+	}
+	
+	if (str[x] == splitChar)
+		x++;
+	
+	arr ~= str[x .. $];
+	
+	return arr;
+}
+
+private:
+	
+template decimalDigit (int n)	// [3]
+{
+	const decimalDigit = "0123456789"[n .. n + 1];
+} 
+
+template itoa (long n)
+{   
+	static if (n < 0)
+		const itoa = "-" ~ itoa!(-n); 
+  
+	else static if (n < 10)
+		const itoa = decimalDigit!(n); 
+  
+	else
+		const itoa = itoa!(n / 10L) ~ decimalDigit!(n % 10L); 
+}
\ No newline at end of file
--- a/orange/util/Reflection.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/Reflection.d	Mon May 31 16:06:36 2010 +0200
@@ -1,9 +1,468 @@
 /**
- * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Copyright: Copyright (c) 2009 Jacob Carlborg.
  * Authors: Jacob Carlborg
- * Version: Initial created: Jan 26, 2010
+ * Version: Initial created: Oct 5, 2009
  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
  */
 module orange.util.Reflection;
 
-public import mambo.util.Reflection;
\ No newline at end of file
+import orange.util.CTFE;
+import orange.util.string;
+
+/**
+ * Returns the name of the given function
+ * 
+ * Params:
+ *     func = the function alias to get the name of
+ *     
+ * Returns: the name of the function 
+ */
+template functionNameOf (alias func)
+{
+	version(LDC)
+		const functionNameOf = (&func).stringof[1 .. $];
+	
+	else
+		const functionNameOf = (&func).stringof[2 .. $];
+}
+
+/**
+ * Returns the parameter names of the given function
+ * 
+ * Params:
+ *     func = the function alias to get the parameter names of
+ *     
+ * Returns: an array of strings containing the parameter names 
+ */
+template parameterNamesOf (alias func)
+{
+	const parameterNamesOf = parameterNamesOfImpl!(func);
+}
+
+/**
+ * Returns the parameter names of the given function
+ *  
+ * Params:
+ *     func = the function alias to get the parameter names of
+ *     
+ * Returns: an array of strings containing the parameter names 
+ */
+private string[] parameterNamesOfImpl (alias func) ()
+{
+	string funcStr = typeof(&func).stringof;
+
+	auto start = funcStr.indexOf('(');
+	auto end = funcStr.indexOf(')');
+	
+	const firstPattern = ' ';
+	const secondPattern = ',';
+	
+	funcStr = funcStr[start + 1 .. end];
+	
+	if (funcStr == "")
+		return null;
+		
+	funcStr ~= secondPattern;
+	
+	string token;
+	string[] arr;
+	
+	foreach (c ; funcStr)
+	{		
+		if (c != firstPattern && c != secondPattern)
+			token ~= c;
+		
+		else
+		{			
+			if (token)
+				arr ~= token;
+			
+			token = null;
+		}			
+	}
+	
+	if (arr.length == 1)
+		return arr;
+	
+	string[] result;
+	bool skip = false;
+	
+	foreach (str ; arr)
+	{
+		skip = !skip;
+		
+		if (skip)
+			continue;
+		
+		result ~= str;
+	}
+	
+	return result;
+}
+
+/**
+ * Helper function for callWithNamedArguments
+ * 
+ * Returns:
+ */
+private string buildFunction (alias func, string args) ()
+{
+	const str = split(args);
+	string[] params;
+	string[] values;
+	auto mixinString = functionNameOf!(func) ~ "(";
+	
+	foreach (s ; str)
+	{
+		auto index = s.indexOf('=');
+		params ~= s[0 .. index];
+		values ~= s[index + 1 .. $];
+	}		
+
+	const parameterNames = parameterNamesOf!(func);
+
+	foreach (i, s ; parameterNames)
+	{
+		auto index = params.indexOf(s);
+		
+		if (index != params.length)
+			mixinString ~= values[index] ~ ",";
+	}
+	
+	return mixinString[0 .. $ - 1] ~ ");";
+}
+
+/**
+ * Calls the given function with named arguments
+ * 
+ * Params:
+ *     func = an alias to the function to call
+ *     args = a string containing the arguments to call using this syntax: `arg2=value,arg1="value"`
+ */
+void callWithNamedArguments (alias func, string args) ()
+{
+	mixin(buildFunction!(func, args));
+}
+
+/**
+ * Evaluates to true if T has a instance method with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasInstanceMethod (T, string method)
+{
+	const hasInstanceMethod = is(typeof({
+		T t;
+		mixin("auto f = &t." ~ method ~ ";");
+	}));
+}
+
+/**
+ * Evaluates to true if T has a class method with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasClassMethod (T, string method)
+{
+	const hasClassMethod = is(typeof({
+		mixin("auto f = &T." ~ method ~ ";");
+	}));
+}
+
+/**
+ * Evaluates to true if T has a either a class method or a instance method with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasMethod (T, string method)
+{
+	const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method);
+}
+
+/**
+ * Evaluates to true if T has a field with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		field = the name of the field
+ */
+template hasField (T, string field)
+{
+	const hasField = hasFieldImpl!(T, field, 0);
+}
+
+private template hasFieldImpl (T, string field, size_t i)
+{
+	static if (T.tupleof.length == i)
+		const hasFieldImpl = false;
+	
+	else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
+		const hasFieldImpl = true;
+	
+	else
+		const hasFieldImpl = hasFieldImpl!(T, field, i + 1);		
+}
+
+/**
+ * Evaluates to an array of strings containing the names of the fields in the given type
+ */
+template fieldsOf (T)
+{
+	const fieldsOf = fieldsOfImpl!(T, 0);
+}
+
+/**
+ * Implementation for fieldsOf
+ * 
+ * Returns: an array of strings containing the names of the fields in the given type
+ */
+template fieldsOfImpl (T, size_t i)
+{
+	static if (T.tupleof.length == 0)
+		const fieldsOfImpl = [""];
+	
+	else static if (T.tupleof.length - 1 == i)
+		const fieldsOfImpl = [T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $]];
+	
+	else
+		const fieldsOfImpl = T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] ~ fieldsOfImpl!(T, i + 1);
+}
+
+/**
+ * Evaluates to the type of the field with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		field = the name of the field
+ */
+template TypeOfField (T, string field)
+{
+	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
+
+	alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
+}
+
+private template TypeOfFieldImpl (T, string field, size_t i)
+{
+	static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
+		alias typeof(T.tupleof[i]) TypeOfFieldImpl;
+	
+	else
+		alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
+}
+
+/**
+ * Evaluates to a string containing the name of the field at given position in the type given type.
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		position = the position of the field in the tupleof array
+ */
+template nameOfFieldAt (T, size_t position)
+{
+	static if (T.tupleof[position].stringof.length > T.stringof.length + 3)
+		const nameOfFieldAt = T.tupleof[position].stringof[1 + T.stringof.length + 2 .. $];
+	
+	else
+		const nameOfFieldAt = "";
+}
+
+/**
+ * Sets the given value to the filed with the given name
+ * 
+ * Params:
+ *     t = an instance of the type that has the field
+ *     value = the value to set
+ */
+void setValueOfField (T, U, string field) (ref T t, U value)
+in
+{
+	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
+}
+body
+{
+	const len = T.stringof.length; 
+	
+	foreach (i, dummy ; typeof(T.tupleof))
+	{
+		const f = T.tupleof[i].stringof[1 + len + 2 .. $];
+		
+		static if (f == field)
+		{
+			t.tupleof[i] = value;
+			break;
+		}
+	}
+}
+
+/**
+ * Gets the value of the field with the given name
+ * 
+ * Params:
+ *     t = an instance of the type that has the field
+ *      
+ * Returns: the value of the field
+ */
+U getValueOfField (T, U, string field) (T t)
+in
+{
+	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
+}
+body
+{
+	const len = T.stringof.length; 
+	
+	foreach (i, dummy ; typeof(T.tupleof))
+	{
+		const f = T.tupleof[i].stringof[1 + len + 2 .. $];
+		
+		static if (f == field)
+			return t.tupleof[i];
+	}
+}
+
+/**
+ * Gets all the class names in the given string of D code
+ * 
+ * Params:
+ *     code = a string containg the code to get the class names from	
+ * 
+ * Returns: the class names
+ */
+string[] getClassNames (string code) ()
+{
+	const fileContent = code;
+	const classString = "class";
+	bool foundPossibleClass;
+	bool foundClass;
+	string[] classNames;
+	string className;
+	
+	for (size_t i = 0; i < fileContent.length; i++)
+	{		
+		final c = fileContent[i];
+		
+		if (foundPossibleClass)
+		{
+			if (c == ' ' || c == '\n')
+				foundClass = true;
+			
+			foundPossibleClass = false;
+		}
+		
+		else if (foundClass)
+		{			
+			if (c == '{')
+			{
+				classNames ~= className;
+				foundClass = false;
+				className = "";
+			}
+			
+			else if (c != ' ' && c != '\n')
+				className ~= c;
+		}
+		
+		else
+		{
+			if (i + classString.length < fileContent.length)
+			{
+				if (fileContent[i .. i + classString.length] == classString)
+				{
+					if (i > 0)
+					{
+						if (fileContent[i - 1] == ' ' || fileContent[i - 1] == '\n' || fileContent[i - 1] == ';' || fileContent[i - 1] == '}')
+						{
+							foundPossibleClass = true;
+							i += classString.length - 1;
+							continue;
+						}
+					}
+					
+					else
+					{
+						foundPossibleClass = true;
+						i += classString.length - 1;
+						continue;
+					}
+				}
+			}
+		}
+	}
+	
+	return classNames;
+}
+
+/**
+ * Creates a new instance of class with the given name
+ * 
+ * Params:
+ *     name = the fully qualified name of the class
+ *     args = the arguments to the constructor
+ *     
+ * Returns: the newly created instance or null
+ */
+T factory (T, ARGS...) (string name, ARGS args)
+{	
+	auto classInfo = ClassInfo.find(name);
+	
+	if (!classInfo)
+		return null;
+	
+	auto object = newInstance(classInfo);
+	
+	if (classInfo.flags & 8 && classInfo.defaultConstructor is null)
+	{
+		auto o = cast(T) object;
+		
+		static if (is(typeof(o._ctor(args))))
+			return o._ctor(args);
+		
+		else
+			return null;
+	}
+	
+	else
+	{
+		if (classInfo.flags & 8 && classInfo.defaultConstructor !is null)
+		{
+			Object delegate () ctor;
+			ctor.ptr = cast(void*) object;
+			ctor.funcptr = cast(Object function()) classInfo.defaultConstructor;
+			
+			return cast(T) ctor();
+		}
+		
+		else
+			return cast(T) object;
+	}
+}
+
+private
+{
+	version (LDC)
+		extern (C) Object _d_allocclass(ClassInfo);
+	
+	else
+		extern (C) Object _d_newclass(ClassInfo);
+}
+
+Object newInstance (ClassInfo classInfo)
+{
+	version (LDC)
+	{		
+		Object object = _d_allocclass(classInfo);
+        (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[];
+        
+        return object;
+	}
+
+	else
+		return _d_newclass(classInfo);
+}
\ No newline at end of file
--- a/orange/util/Traits.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/Traits.d	Mon May 31 16:06:36 2010 +0200
@@ -6,12 +6,172 @@
  */
 module orange.util.Traits;
 
-public import mambo.util.Traits;
-
 import orange.serialization.Serializable;
 import orange.serialization.archives.Archive;
 import orange.util._;
 
+version (Tango)
+{
+	import Tango = tango.core.Traits;
+	alias Tango.BaseTypeTupleOf BaseTypeTupleOf;
+	alias Tango.ParameterTupleOf ParameterTupleOf;
+	alias Tango.ReturnTypeOf ReturnTypeOf;
+}
+
+else
+{
+	import Phobos = std.traits;
+	alias Phobos.BaseTypeTuple BaseTypeTupleOf;
+	alias Phobos.ParameterTypeTuple ParameterTupleOf;
+	alias Phobos.ReturnType ReturnTypeOf;
+	
+	version = Phobos;
+}
+
+template isPrimitive (T)
+{
+	const bool isPrimitive = is(T == bool) ||
+						is(T == byte) ||
+						is(T == cdouble) ||
+						//is(T == cent) ||
+						is(T == cfloat) ||
+						is(T == char) ||
+						is(T == creal) ||
+						is(T == dchar) ||
+						is(T == double) ||
+						is(T == float) ||
+						is(T == idouble) ||
+						is(T == ifloat) ||
+						is(T == int) ||
+						is(T == ireal) ||
+						is(T == long) ||
+						is(T == real) ||
+						is(T == short) ||
+						is(T == ubyte) ||
+						//is(T == ucent) ||
+						is(T == uint) ||
+						is(T == ulong) ||
+						is(T == ushort) ||
+						is(T == wchar);
+}
+
+template isChar (T)
+{
+	const bool isChar = is(T == char) || is(T == wchar) || is(T == dchar);
+}
+
+template isClass (T)
+{
+	const bool isClass = is(T == class);
+}
+
+template isInterface (T)
+{
+	const bool isInterface = is(T == interface);
+}
+
+template isObject (T)
+{
+	const bool isObject = isClass!(T) || isInterface!(T);
+}
+
+template isStruct (T)
+{
+	const bool isStruct = is(T == struct);
+}
+
+template isArray (T)
+{
+	static if (is(T U : U[]))
+		const bool isArray = true;
+	
+	else
+		const bool isArray = false;
+}
+
+template isString (T)
+{
+	const bool isString = is(T : char[]) || is(T : wchar[]) || is(T : dchar[]);
+}
+
+template isAssociativeArray (T)
+{
+	const bool isAssociativeArray = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T);
+}
+
+template isPointer (T)
+{
+	static if (is(T U : U*))
+		const bool isPointer = true;
+	
+	else
+		const bool isPointer = false;
+}
+
+template isFunctionPointer (T)
+{
+	const bool isFunctionPointer = is(typeof(*T) == function);
+}
+
+template isEnum (T)
+{
+	const bool isEnum = is(T == enum);
+}
+
+template isReference (T)
+{
+	const bool isReference = isObject!(T) || isPointer!(T);
+}
+
+template isTypeDef (T)
+{
+	const bool isTypeDef = is(T == typedef);
+}
+
+template isVoid (T)
+{
+	const bool isVoid = is(T == void);
+}
+
+template BaseTypeOfArray (T)
+{
+	static if (is(T U : U[]))
+		alias BaseTypeOfArray!(U) BaseTypeOfArray;
+	
+	else
+		alias T BaseTypeOfArray;
+}
+
+template BaseTypeOfPointer (T)
+{
+	static if (is(T U : U*))
+		alias BaseTypeOfPointer!(U) BaseTypeOfPointer;
+	
+	else
+		alias T BaseTypeOfPointer;
+}
+
+template BaseTypeOfTypeDef (T)
+{
+	static if (is(T U == typedef))
+		alias BaseTypeOfTypeDef!(U) BaseTypeOfTypeDef;
+	
+	else
+		alias T BaseTypeOfTypeDef;
+}
+
+template KeyTypeOfAssociativeArray (T)
+{
+	static assert(isAssociativeArray!(T), "The type needs to be an associative array");
+	alias typeof(T.init.keys[0]) KeyTypeOfAssociativeArray;
+}
+
+template ValueTypeOfAssociativeArray (T)
+{
+	static assert(isAssociativeArray!(T), "The type needs to be an associative array");
+	alias typeof(T.init.values[0]) ValueTypeOfAssociativeArray;
+}
+
 template isArchive (T)
 {
 	const isArchive = is(typeof({
--- a/orange/util/Use.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/Use.d	Mon May 31 16:06:36 2010 +0200
@@ -6,8 +6,6 @@
  */
 module orange.util.Use;
 
-import mambo.io;
-
 version (Tango)
 {
 	import tango.core.Tuple;
@@ -62,6 +60,7 @@
 		return dg(deleg, *value);
 	}
 }
+
 RestoreStruct!(U, T) restore (U = void, T) (ref T val)
 {
 	RestoreStruct!(U, T) restoreStruct;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/orange/util/collection/Array.d	Mon May 31 16:06:36 2010 +0200
@@ -0,0 +1,625 @@
+/**
+ * Copyright: Copyright (c) 2008-2009 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: 2008
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ * 
+ */
+module orange.util.collection.Array;
+
+version (Tango)
+{
+	static import tango.core.Array;
+	import tango.stdc.string : memmove;
+	static import tango.text.Util;
+}
+
+else
+{
+	version = Phobos;
+	
+	import std.c.string : memmove;
+}	
+
+/**
+ * Inserts the specified element at the specified position in the array. Shifts the
+ * element currently at that position (if any) and any subsequent elements to the right.
+ * 
+ * Params:
+ *     arr = the array to insert the element into
+ *     index = the index at which the specified element is to be inserted
+ *     element = the element to be inserted
+ *     
+ * Returns: the modified array
+ *     
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the $(D_PARAM index) argument is
+ *         greater than the length of this array.
+ */
+T[] insert (T, U = size_t) (ref T[] arr, U index, T element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.insert: The length of the array was 0");
+	assert(index <= arr.length, "mambo.collection.Array.insert: The index was greater than the length of the array");
+}
+body
+{
+	if (index == arr.length)
+	{
+		arr ~= element;
+		return arr;
+	}
+
+	else if (index == 0)
+		arr = element ~ arr;
+
+	else
+		arr = arr[0 .. index] ~ element ~ arr[index .. $];
+
+	return arr;
+}
+
+/**
+ * Inserts the specified elements at the specified position in the array. Shifts the
+ * element currently at that position (if any) and any subsequent elements to the right.
+ * 
+ * Params:
+ *     arr = the array to insert the element into
+ *     index = the index at which the specified element is to be inserted
+ *     element = the element to be inserted
+ *     
+ * Returns: the modified array
+ *     
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the $(D_PARAM index) argument is
+ *         not less or equal than the length of this array. 
+ */
+T[] insert (T, U = size_t) (ref T[] arr, U index, T[] element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.insert: The length of the array was 0");
+	assert(index <= arr.length, "mambo.collection.Array.insert: The index was greater than the length of the array");
+}
+body
+{
+	if (index == arr.length)
+	{
+		arr ~= element;
+		return arr;
+	}
+
+	else if (index == 0)
+		arr = element ~ arr;
+
+	else
+		arr = arr[0 .. index] ~ element ~ arr[index .. $];
+
+	return arr;
+}
+
+/**
+ * Inserts the specified element at the specified position in the array. Shifts the
+ * element currently at that position (if any) and any subsequent elements to the right.
+ * 
+ * Params:
+ *     arr = the array to add the element to
+ *     index = the index at which the specified element is to be inserted
+ *     element = the element to be inserted
+ *     
+ * Returns: the modified array    
+ *     
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the $(D_PARAM index) argument is
+ *         not less than the length of this array.
+ */
+T[] add (T, U = size_t) (ref T[] arr, U index, T element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.add: The length of the array was 0");
+	assert(index <= arr.length, "mambo.collection.Array.add: The index was greater than the length of the array");
+}
+body
+{
+	return insert(arr, index, element);
+}
+
+/**
+ * Appends the specified element to the end of the array.
+ * 
+ * Params:
+ *     arr = the array to add the element to
+ *     element = element to be appended to this list
+ *     
+ * Returns: the modified array
+ */
+T[] add (T) (ref T[] arr, T element)
+{
+	return arr ~= element;
+}
+
+/**
+ * Removes the element at the specified position in the array if it could find it and
+ * returns it. Shifts any subsequent elements to the left.
+ * 
+ * Params:
+ *     arr = the array to remove the element from
+ *     index = the index of the element to be removed
+ *     
+ * Returns: the element that was removed
+ * 
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the $(D_PARAM index) argument is
+ *         not less than the length of this array.
+ */
+T remove (T, U = size_t) (ref T[] arr, U index)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.remove: The length of the array was 0");
+	assert(index < arr.length, "mambo.collection.Array.remove: The index was greater than the length of the array");
+}
+body
+{
+	T ret = arr[index];
+	
+	if (index == 0)
+		arr = arr[1 .. $];
+	
+	else if (index == arr.length - 1)
+		arr = arr[0 .. $ - 1];
+	
+	else
+	{
+		if (index < arr.length - 1)
+			memmove(&arr[index], &arr[index + 1], T.sizeof * (arr.length - index - 1));
+
+	    arr.length = arr.length - 1;
+	}
+	
+	return ret;
+}
+
+/**
+ * Removes the specified element from the array if it could find it and returns it.
+ * Shifts any subsequent elements to the left.
+ * 
+ * Params:
+ *     arr = the array to remove the element from
+ *     element = the element to be removed
+ *     
+ * Returns: the element that was removed or T.max
+ * 
+ * Throws: AssertException if the length of the array is 0
+ */
+T remove (T) (ref T[] arr, T element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.remove: The length of the array was 0");
+}
+out (result)
+{
+	assert(result is element);
+}
+body
+{
+	size_t index = arr.indexOf(element);
+
+	if (index == size_t.max)
+		return T.max;
+
+	return arr.remove(index);
+}
+
+/**
+ * Returns the index of the first occurrence of the specified element in the array, or
+ * U.max if the array does not contain the element. 
+ * 
+ * Params:
+ *     arr = the array to get the index of the element from
+ *     element = the element to find
+ *     start = the index where to begin the search
+ *     
+ * Returns: the index of the element or U.max if it's not in the array
+ * 
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the return value is greater or   
+ * 		   equal to the length of the array.
+ */
+U indexOf (T, U = size_t) (T[] arr, T element, U start = 0)
+in
+{
+	assert(start >= 0, "mambo.collection.Array.indexOf: The start index was less than 0");
+}
+body
+{
+	version (Tango)
+	{
+		U index = tango.text.Util.locate(arr, element, start);
+		
+		if (index == arr.length)
+			index = U.max;
+
+		return index;
+	}
+
+	else
+	{
+		if (start > arr.length)
+			start = arr.length;
+		
+		for (U i = start; i < arr.length; i++)
+			if (arr[i] == element)
+				return i;
+		
+		return U.max;
+	}
+}
+
+/**
+ * Returns $(D_KEYWORD true) if the array contains the specified element.
+ * 
+ * Params:
+ *     arr = the array to check if it contains the element
+ *     element = the element whose presence in the array is to be tested
+ *     
+ * Returns: $(D_KEYWORD true) if the array contains the specified element
+ * 
+ * Throws: AssertException if the length of the array is 0
+ */
+bool contains (T) (T[] arr, T element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.contains: The length of the array was 0");
+}
+body
+{
+	return arr.indexOf!(T, size_t)(element) < size_t.max;
+}
+
+/**
+ * Returns $(D_KEYWORD true) if this array contains no elements.
+ * 
+ * Params:
+ *     arr = the array to check if it's empty
+ *
+ * Returns: $(D_KEYWORD true) if this array contains no elements
+ */
+bool isEmpty (T) (T[] arr)
+{
+	return arr.length == 0;
+}
+
+/**
+ * Returns $(D_KEYWORD true) if this array contains no elements.
+ * 
+ * Params:
+ *     arr = the array to check if it's empty
+ *
+ * Returns: $(D_KEYWORD true) if this array contains no elements
+ */
+alias isEmpty empty;
+
+/**
+ * Removes all of the elements from this array. The array will be empty after this call
+ * returns.
+ * 
+ * Params:
+ *     arr = the array to clear
+ * 
+ * Returns: the cleared array
+ *
+ * Throws: AssertException if length of the return array isn't 0
+ */
+T[] clear (T) (T[] arr)
+out (result)
+{
+	assert(result.length == 0, "mambo.collection.Array.clear: The length of the resulting array was not 0");
+}
+body
+{
+	return arr.length = 0;
+}
+
+/**
+ * Returns the element at the specified position in the array.
+ * 
+ * Params:
+ * 	   arr = the array to get the element from
+ *     index = index of the element to return
+ *     
+ * Returns: the element at the specified position in the array
+ * 
+ * Throws: AssertException if the length of the array is 0
+ * Throws: AssertException if the $(D_PARAM index) argument is
+ *         not less than the length of this array.
+ */
+T get (T, U = size_t) (T[] arr, U index)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.get: The length of the array was 0");
+	assert(index < arr.length, "mambo.collection.Array.get: The index was greater than the length of the array");
+}
+body
+{
+	return arr[index];
+}
+
+/**
+ * Returns the index of the last occurrence of the specifed element
+ * 
+ * Params:
+ *     arr = the array to get the index of the element from
+ *     element = the element to find the index of
+ *     
+ * Returns: the index of the last occurrence of the element in the
+ *          specified array, or U.max 
+ *          if the element does not occur.
+ *          
+ * Throws: AssertException if the length of the array is 0 
+ * Throws: AssertException if the return value is less than -1 or
+ * 		   greater than the length of the array - 1.
+ */
+U lastIndexOf (T, U = size_t) (T[] arr, T element)
+in
+{
+	assert(arr.length > 0, "mambo.collection.Array.lastIndexOf: The length of the array was 0");
+}
+body
+{
+	version (Tango)
+	{
+		U index = tango.text.Util.locatePrior(arr, element);
+
+		if (index == arr.length)
+			return U.max;
+
+		return index;
+	}
+
+	else
+	{
+		foreach_reverse (i, e ; arr)
+			if (e is element)
+				return i;
+
+		return U.max;
+	}
+}
+
+/**
+ * Returns the number of elements in the specified array. 
+ * 
+ * Params:
+ *     arr = the array to get the number of elements from
+ *     
+ * Returns: the number of elements in this list
+ */
+U size (T, U = size_t) (T[] arr)
+{
+	return arr.length;
+}
+
+/**
+ * Finds the first occurence of element in arr
+ * 
+ * Params:
+ *     arr = the array to find the element in
+ *     element = the element to find
+ *     start = at which position to start finding
+ *     
+ * Returns: the index of the first match or U.max if no match was found.
+ */
+alias indexOf find;
+
+/**
+ * Replaces a section of $(D_PARAM arr) with elements starting at $(D_PARAM pos) ending
+ * $(D_PARAM n) elements after
+ * 
+ * Params:
+ *     arr = the array to do the replace in
+ *     pos = position within the array of the first element of the section to be replaced
+ *     n = length of the section to be replaced within the array
+ *     elements = the elements to replace with
+ *     
+ * Throws:
+ * 		AssertException if pos is greater than the length of the array
+ * 
+ * Returns: the array
+ */
+T[] replace (T, U = size_t) (ref T[] arr, U pos, U n, T[] elements)
+in
+{
+	assert(pos <= arr.length, "mambo.collection.Array.replace: The position was greter than the length of the array");
+}
+body
+{
+	U i;
+	U nr = n;
+	
+	if (nr > arr.length)
+		nr = arr.length - 1;
+	
+	if (nr == elements.length)
+	{
+		U eIndex;
+
+		for (i = pos, eIndex = 0; i <= nr; i++, eIndex++)
+			arr[i] = elements[eIndex];			
+		
+		return arr;
+	}
+	
+	else if (elements.length == 0)
+	{
+		U index = pos + n;
+		
+		if (index >= arr.length)
+			index = arr.length;
+		
+		return arr = arr[0 .. pos] ~ arr[index .. $];
+	}
+	
+	else
+	{
+		U eIndex;
+		
+		for (i = pos, eIndex = 0; eIndex < nr && i < arr.length && eIndex < elements.length; i++, eIndex++)
+			arr[i] = elements[eIndex];
+		
+		// no positions left and elements are left in elements, insert elements
+		if (eIndex < elements.length)
+			return arr = arr[0 .. i] ~ elements[eIndex .. $] ~ arr[i .. $];
+		
+		// positions left to replace but no elements, remove those positions
+		else if (nr > eIndex)
+		{
+			U index = pos + nr;
+			
+			if (index >= arr.length)
+				index = arr.length;			
+			
+			return arr = arr[0 .. pos + eIndex] ~ arr[index .. $];
+		}
+			
+	}
+	
+	return arr;
+}
+
+/**
+ * Erases a part of the array content, shortening the length of the array.
+ * 
+ * Params:
+ *     arr = the array to erase elements from
+ *     start = the position within the array of the first element to be erased
+ *     n = amount of elements to be removed. It may remove less elements if the
+ *     	   end of the array is reached before the n elements have been erased.
+ *     	   The default value of n indicates that all the elements until the end
+ *     	   of the array should be erased.
+ *     
+ * Throws:
+ * 		AssertException if pos is greater than the length of the array
+ *     
+ * Returns: the array
+ */
+T[] erase (T, U = size_t) (ref T[] arr, U start = 0, U n = U.max)
+in
+{
+	assert(start <= arr.length, "mambo.collection.Array.erase: The start position was greater than the length of the array");
+}
+body
+{	
+	U end;
+	
+	if (n == U.max)
+		end = arr.length;
+	
+	else
+	{
+		end = start + n;
+		
+		if (end > arr.length)
+			end = arr.length;
+	}
+	
+	return arr = arr[0 .. start] ~ arr[end .. $]; 
+}
+
+/**
+ * Compares to arrays. Returns 0 if the content matches, less than zero 
+ * if a is "less" than b, or greater than zero where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ */
+int compare (T, U = size_t) (T[] a, T[] b, U end = U.max)
+{
+	U ia = end;
+	U ib = end;	
+	
+	if (ia > a.length)
+		ia = a.length;
+	
+	if (ib > b.length)
+		ib = b.length;
+	
+	return typeid(T[]).compare(&a[0 .. ia], &b[0 .. ib]);
+}
+
+/**
+ * Compares the content of the given array to the content of a comparing 
+ * array, which is formed according to the arguments passed.
+ * 
+ * The function returns 0 if all the elements in the compared contents compare
+ * equal, a negative value if the first element that does not match compares to
+ * less in the array than in the comparing array, and a positive value in
+ * the opposite case.
+ * 
+ * Params:
+ *     a = the first array to compare with
+ *     pos = position of the beginning of the compared slice, i.e. the first element in the array (in a) to be compared against the comparing array.
+ *     n = length of the compared slice.
+ *     b = array with the content to be used as comparing array.
+ *     
+ * Returns: 0 if the compared array are equal, otherwise a number different from 0 is returned, with its sign indicating whether the array is considered greater than the comparing array passed as parameter (positive sign), or smaller (negative sign).
+ * 
+ * Throws: AssertException if pos is specified with a position greater than the length of the corresponding array
+ */
+int compare (T, U = size_t) (T[] a, size_t pos, size_t n, T[] b)
+in
+{
+	assert(pos <= b.length);
+}
+body
+{
+	U end = pos + n;
+	
+	if (end > b.length)
+		end = b.length;
+	
+	return typeid(T[]).compare(&b[pos .. end], &a[0 .. $]);
+}
+
+/**
+ * Reserves the given amount of allocated storage for the given array.
+ * 
+ * Params:
+ *     a = the array to reserve allocated storage for
+ *     capacity = the amount of allocated storage to be reserved
+ */
+void reserve (T) (ref T[] a, size_t amount = 0)
+{
+	a = (new T[amount])[0 .. 0]; 
+}
+
+/**
+ * Returns true if a begins with b
+ * 
+ * Params:
+ *     a = the array to
+ *     b = 
+ *     
+ * Returns: true if a begins with b, otherwise false
+ */
+bool beginsWith (T) (T[] a, T[] b)
+{
+	return a.length > b.length && a[0 .. b.length] == b;
+}
+
+/**
+ * Returns true if a ends with b
+ * 
+ * Params:
+ *     a = the array to
+ *     b = 
+ *     
+ * Returns: true if a ends with b, otherwise false
+ */
+bool endsWith (T) (T[] a, T[] b)
+{
+	return a.length > b.length && a[$ - b.length .. $] == b;
+}
\ No newline at end of file
--- a/orange/util/io.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/io.d	Mon May 31 16:06:36 2010 +0200
@@ -1,3 +1,82 @@
+/**
+ * Copyright: Copyright (c) 2007-2008 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: 2007
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ * 
+ */
 module orange.util.io;
 
-public import mambo.io;
\ No newline at end of file
+version (Tango)
+{
+	import tango.io.Stdout;
+	import tango.io.Console;
+	
+	import orange.util.string;
+}
+
+else 
+	import std.stdio;
+
+/**
+ * Print to the standard output
+ * 
+ * Params:
+ *     args = what to print
+ */
+void print (A...)(A args)
+{
+	version (Tango)
+	{
+		const string fmt = "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}";
+				
+		static assert (A.length <= fmt.length / 2, "mambo.io.print :: too many arguments");
+		
+		Stdout.format(fmt[0 .. args.length * 2], args).flush;
+	}
+		
+	
+	else
+		foreach(t ; a)
+			writef(t);
+}
+
+/**
+ * Print to the standard output, adds a new line
+ * 
+ * Params:
+ *     args = what to print
+ */
+void println (A...)(A args)
+{
+	version (Tango)
+	{
+		const string fmt = "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}"
+					        "{}{}{}{}{}{}{}{}";
+
+		static assert (A.length <= fmt.length / 2, "mambo.io.println :: too many arguments");
+		
+		Stdout.formatln(fmt[0 .. args.length * 2], args);
+	}
+
+	else
+	{
+		foreach(t ; args)
+			writef(t);
+		
+		writef("\n");
+	}
+}
+
+/**
+ * Read from the standard input
+ * 
+ * Returns: what was read
+ */
+string read ()
+{
+	return Cin.get;
+}
--- a/orange/util/string.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/string.d	Mon May 31 16:06:36 2010 +0200
@@ -1,9 +1,881 @@
 /**
- * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Copyright: Copyright (c) 2008-2009 Jacob Carlborg. All rights reserved.
  * Authors: Jacob Carlborg
- * Version: Initial created: Jan 26, 2010
+ * Version: Initial created: 2008
  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ * 
  */
 module orange.util.string;
 
-public import mambo.string;
\ No newline at end of file
+public import orange.util.collection.Array;
+
+version (Tango)
+{
+	static import tango.stdc.stringz;
+	import tango.text.Unicode : toFold, isDigit;
+	import tango.text.convert.Utf;
+	import tango.text.Util;
+	
+	alias tango.stdc.stringz.toStringz toStringz;
+	alias tango.stdc.stringz.toString16z toString16z;
+	alias tango.stdc.stringz.toString32z toString32z;
+	
+	alias tango.stdc.stringz.fromStringz fromStringz;
+	alias tango.stdc.stringz.fromString16z fromString16z;
+	alias tango.stdc.stringz.fromString32z fromString32z;
+	
+	alias tango.text.convert.Utf.toString16 toString16;
+	alias tango.text.convert.Utf.toString32 toString32;
+}
+
+else
+{	
+	import std.string;
+	import std.utf;
+	import std.ctype : isxdigit;
+	
+	version = Phobos;
+	
+	private alias std.string.tolower toFold;
+	
+	alias std.utf.toUTF8 toString;
+	alias std.utf.toUTF16 toString16;
+	alias std.utf.toUTF32 toString32;
+	
+	alias std.string.toStringz toStringz;
+	alias std.utf.toUTF16z toString16z;
+	
+	alias std.string.toString fromStringz;
+}
+
+version (Tango)
+{
+	/**
+	 * string alias
+	 */
+	alias char[] string;
+
+	/**
+	 * wstring alias
+	 */
+	alias wchar[] wstring;
+
+	/**
+	 * dstring alias
+	 */
+	alias dchar[] dstring;
+}
+
+/**
+ * Compares the $(D_PSYMBOL string) to another $(D_PSYMBOL string), ignoring case
+ * considerations.  Two strings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two strings  are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL string) first string to compare to
+ *     anotherString = The $(D_PSYMBOL string) to compare the first $(D_PSYMBOL string) with
+ *     
+ * Returns: $(D_KEYWORD true) if the arguments is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL string) ignoring case; $(D_KEYWORD false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the strings is 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (string str, string anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{	
+	if (str == anotherString)
+		return true;
+
+	return toFold(str) == toFold(anotherString);
+}
+
+/**
+ * Compares the $(D_PSYMBOL wstring) to another $(D_PSYMBOL wstring), ignoring case
+ * considerations. Two wstrings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two wstrings are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL wstring) first string to compre to
+ *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL wstring) against
+ *     
+ * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL wstring) ignoring case; (D_KEYWORD
+ *          false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the wstrings is 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (wstring str, wstring anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{
+	if (str == anotherString)
+		return true;
+
+	version (Tango)
+		return toFold(str) == toFold(anotherString);
+
+	else
+		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
+}
+
+/**
+ * Compares the $(D_PSYMBOL dstring) to another $(D_PSYMBOL dstring), ignoring case
+ * considerations. Two wstrings are considered equal ignoring case if they are of the
+ * same length and corresponding characters in the two wstrings are equal ignoring case.
+ * 
+ * Params:
+ *     str = The $(D_PSYMBOL dstring) first string to compare to
+ *     anotherString = The $(D_PSYMBOL wstring) to compare the first $(D_PSYMBOL dstring) against
+ *     
+ * Returns: $(D_KEYWORD true) if the argument is not $(D_KEYWORD null) and it
+ *          represents an equivalent $(D_PSYMBOL dstring) ignoring case; $(D_KEYWORD false) otherwise
+ *          
+ * Throws: AssertException if the length of any of the dstrings are 0
+ *          
+ * See_Also: opEquals(Object)
+ */
+bool equalsIgnoreCase (dstring str, dstring anotherString)
+in
+{
+	assert(str.length > 0, "mambo.string.equalsIgnoreCase: The length of the first string was 0");
+	assert(anotherString.length > 0, "mambo.string.equalsIgnoreCase: The length of the second string was 0");
+}
+body
+{
+	if (str == anotherString)
+		return true;
+
+	version (Tango)
+		return toFold(str) == toFold(anotherString);
+
+	else
+		return toFold(toUTF8(str)) == toFold(toUTF8(anotherString));
+}
+
+/**
+ * Returns the char value at the specified index. An index ranges from 0 to length - 1.
+ * The first $(D_KEYWORD char) value of the sequence is at index 0, the next at index 1,
+ * and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the string to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the string.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the string.
+ */
+char charAt (string str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
+ * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
+ * at index 1, and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the wstring to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the wstring.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the wstring is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the wstring.
+ */
+wchar charAt (wstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns the $(D_KEYWORD char) value at the specified index. An index ranges from 0 to
+ * length - 1. The first $(D_KEYWORD char) value of the sequence is at index 0, the next
+ * at index 1, and so on, as for array indexing.
+ * 
+ * Params:
+ * 	   str = the dstring to get the $(D_KEYWORD char) from
+ *     index = the index of the $(D_KEYWORD char) value.
+ *     
+ * Returns: the $(D_KEYWORD char) value at the specified index of the dstring.
+ *          The first $(D_KEYWORD char) value is at index 0.
+ * 
+ * Throws: AssertException if the length of the dstring is 0
+ * Throws: AssertException if the $(D_CODE index) argument is
+ *         not less than the length of the dstring.
+ */
+dchar charAt (dstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.charAt: The length of the string was 0");
+	assert(index <= str.length, "mambo.string.charAt: The index was to greater than the length of the string");
+}
+body
+{
+	return str[index];
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+string substring (string str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	return str[beginIndex .. endIndex].dup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+wstring substring (wstring str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	return str[beginIndex .. endIndex].dup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * at the specified $(D_PARAM beginIndex) and extends to the character at index
+ * $(D_PARAM endIndex) - 1. Thus the length of the substring is $(D_PARAM endIndex - beginIndex).
+ * 
+ * Examples:
+ * ---
+ * "hamburger".substring(4, 8) returns "urge"
+ * "smiles".substring(1, 5) returns "mile"
+ * ---
+ * 
+ * Params:
+ * 	   str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive.
+ *     endIndex = the ending index, exclusive.
+ *     
+ * Returns: the specified substring.
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than $(D_PARAM endIndex).
+ * Throws: AssertException if $(D_PARAM endIndex) is larger than the 
+ *  	   length of the $(D_PSYMBOL string).
+ */
+dstring substring (dstring str, size_t beginIndex, size_t endIndex)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(beginIndex < endIndex, "mambo.string.substring: The first index was greater the second");
+	assert(endIndex <= str.length, "mambo.string.substring: The second index was greater then the length of the string");
+}
+body
+{
+	return str[beginIndex .. endIndex].dup;
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+string substring (string str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+wstring substring (wstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the specified string. The substring begins
+ * with the character at the specified index and extends to the end of the string. 
+ * 
+ * Examples:
+ * ---
+ * "unhappy".substring(2) returns "happy"
+ * "Harbison".substring(3) returns "bison"
+ * "emptiness".substring(9) returns "" (an empty string)
+ * ---
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     beginIndex = the beginning index, inclusive
+ *     
+ * Returns: the specified substring
+ * 
+ * Throws: AssertException if the length of the string is 0
+ * Throws: AssertException if the $(D_PARAM beginIndex) is 
+ * 		   larger than the length of the string.
+ */
+dstring substring (dstring str, size_t index)
+in
+{
+	assert(str.length > 0, "mambo.string.substring: The length of the string was 0");
+	assert(index < str.length, "mambo.string.substring: The index was greater than the length of the string");
+}
+body
+{
+	return str.substring(index, str.length);
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+string substr (string str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	return str[pos .. end].dup;
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+wstring substr (wstring str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	return str[pos .. end].dup;
+}
+
+/**
+ * Returns a new string that is a substring of the given string.
+ * 
+ * This substring is the character sequence that starts at character
+ * position pos and has a length of n characters.
+ * 
+ * Params:
+ *     str = the string to get the substring from
+ *     pos = position of a character in the current string to be used 
+ *     		 as starting character for the substring.
+ *     n = Length of the substring. If this value would make the 
+ *     	   substring to span past the end of the current string content,
+ *     	   only those characters until the end of the string are used. 
+ *     	   size_t.max is the greatest possible value for an element of
+ *     	   type size_t, therefore, when this value is used, all the
+ *     	   characters between pos and the end of the string are used as
+ *     	   the initialization substring.
+ *     
+ * Returns: a string containing a substring of the given string
+ * 
+ * Throws: AssertException if pos is greater than the length of the string
+ */
+dstring substr (dstring str, size_t pos = 0, size_t n = size_t.max)
+in
+{
+	assert(pos < str.length, "mambo.string.substr: The given position was greater than the length of the string.");
+}
+body
+{
+	size_t end;
+	
+	if (n == size_t.max)
+		end = str.length;
+	
+	else
+	{
+		end = pos + n;
+		
+		if (end > str.length)
+			end = str.length;
+	}
+	
+	return str[pos .. end].dup;
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (string str, string sub, size_t start = 0)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub, start);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.find(str, sub, start);
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (wstring str, wstring sub, size_t start = 0)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub, start);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.find(str, sub, start);
+}
+
+/**
+ * Finds the first occurence of sub in str
+ * 
+ * Params:
+ *     str = the string to find in
+ *     sub = the substring to find
+ *     start = where to start finding
+ *     
+ * Returns: the index of the substring or size_t.max when nothing was found
+ */
+size_t find (dstring str, dstring sub, size_t start = 0)
+{
+	version (Tango)
+	{
+		size_t index = str.locatePattern(sub, start);
+		
+		if (index == str.length)
+			return size_t.max;
+		
+		return index;
+	}
+	
+	else
+		return std.string.find(str, sub, start);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (string a, string b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (wstring a, wstring b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.collection.array.compare
+ */
+int compareIgnoreCase (U = size_t) (dstring a, dstring b, U end = U.max)
+{
+	return a.toFold().compare(b.toFold(), end);
+}
+
+/**
+ * Compares to strings, ignoring case differences. Returns 0 if the content
+ * matches, less than zero if a is "less" than b, or greater than zero
+ * where a is "bigger".
+ * 
+ * Params:
+ *     a = the first array 
+ *     b = the second array
+ *     end = the index where the comparision will end
+ *     
+ * Returns: Returns 0 if the content matches, less than zero if a is 
+ * 			"less" than b, or greater than zero where a is "bigger".
+ * 
+ * See_Also: mambo.string.compareIgnoreCase
+ */
+alias compareIgnoreCase icompare;
+
+/**
+ * Checks if the given character is a hexdecimal digit character.
+ * Hexadecimal digits are any of: 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
+ * 
+ * Params:
+ *     ch = the character to be checked
+ *     
+ * Returns: true if the given character is a hexdecimal digit character otherwise false
+ */
+bool isHexDigit (dchar ch)
+{
+	version (Tango)
+	{
+		switch (ch)
+		{
+			case 'A': return true;				
+			case 'B': return true;
+			case 'C': return true;
+			case 'D': return true;
+			case 'E': return true;
+			case 'F': return true;
+			
+			case 'a': return true;
+			case 'b': return true;
+			case 'c': return true;
+			case 'd': return true;
+			case 'e': return true;
+			case 'f': return true;
+			
+			default: break;
+		}
+		
+		if (isDigit(ch))
+			return true;
+	}
+
+	else
+		if (isxdigit(ch) != 0)
+			return true;
+		
+	return false;
+}
+
+/*version (Tango)
+{
+	string toString (string str)
+	{
+		return str;
+	}
+	
+	string toString (wstring str)
+	{
+		return tango.text.convert.Utf.toString(str);
+	}
+	
+	string toString (dstring str)
+	{
+		return tango.text.convert.Utf.toString(str);
+	}
+}*/
+
+version (Phobos)
+{	
+	/**
+	 * Converts the given string to C-style 0 terminated string.
+	 * 
+	 * Params:
+	 *     str = the string to convert
+	 *     
+	 * Returns: the a C-style 0 terminated string.
+	 */
+	dchar* toString32z (dstring str)
+	{
+		return (str ~ '\0').ptr;
+	}
+	
+	/**
+	 * Converts a C-style 0 terminated string to a wstring
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string
+	 *     
+	 * Returns: the converted wstring
+	 */
+	wstring fromString16z (wchar* str)
+	{
+		return str[0 .. strlen(str)];
+	}
+	
+	/**
+	 * Converts a C-style 0 terminated string to a dstring
+	 * Params:
+	 *     str = the C-style 0 terminated string
+	 *     
+	 * Returns: the converted dstring
+	 */
+	dstring fromString32z (dchar* str)
+	{
+		return str[0 .. strlen(str)];
+	}
+	
+	/**
+	 * Gets the length of the given C-style 0 terminated string
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string to get the length of
+	 *     
+	 * Returns: the length of the string
+	 */
+	size_t strlen (wchar* str)
+	{
+		size_t i = 0;
+		
+		if (str)
+			while(*str++)
+				++i;
+		
+		return i;
+	}
+	
+	/**
+	 * Gets the length of the given C-style 0 terminated string
+	 * 
+	 * Params:
+	 *     str = the C-style 0 terminated string to get the length of
+	 *     
+	 * Returns: the length of the string
+	 */
+	size_t strlen (dchar* str)
+	{
+		size_t i = 0;
+		
+		if (str)
+			while(*str++)
+				++i;
+		
+		return i;
+	}
+}
\ No newline at end of file