--- vala-0.8.1/vala/valaarraytype.vala	2010-04-21 14:16:20.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/vala/valaarraytype.vala	2010-05-12 13:43:17.334539576 +0300
@@ -58,6 +58,9 @@
 	private ArrayLengthField length_field;
 	private ArrayResizeMethod resize_method;
 	private ArrayMoveMethod move_method;
+	private ArraySortMethod sort_method;
+	private ArrayReverseMethod reverse_method;
+	private ArrayShuffleMethod shuffle_method;
 
 	public ArrayType (DataType element_type, int rank, SourceReference? source_reference) {
 		this.element_type = element_type;
@@ -72,6 +75,12 @@
 			return get_move_method ();
 		} else if (member_name == "resize") {
 			return get_resize_method ();
+		} else if (member_name == "sort") {
+			return get_sort_method ();
+		} else if (member_name == "reverse") {
+			return get_reverse_method ();
+		} else if (member_name == "shuffle") {
+			return get_shuffle_method ();
 		}
 		return null;
 	}
@@ -133,6 +142,57 @@
 		return move_method;
 	}
 
+	private ArraySortMethod get_sort_method () {
+		if (sort_method == null) {
+			sort_method = new ArraySortMethod (source_reference);
+
+			sort_method.return_type = new VoidType ();
+			sort_method.access = SymbolAccessibility.PUBLIC;
+
+			sort_method.set_cname ("_vala_array_sort");
+
+			FormalParameter? compare_param = null;
+			var root_symbol = source_reference.file.context.root;
+			if (source_reference.file.context.profile == Profile.GOBJECT) {
+				var glib_ns = root_symbol.scope.lookup ("GLib");
+				var func_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("CompareFunc"));
+				compare_param = new FormalParameter ("comp_func", func_type);
+			} else {
+				var void_type = new VoidType ();
+				compare_param = new FormalParameter ("comp_func", void_type);
+			}
+
+			compare_param.parameter_type.nullable = true;
+			compare_param.default_expression = new NullLiteral ();
+			sort_method.add_parameter (compare_param);
+		}
+		return sort_method;
+	}
+
+	private ArrayReverseMethod get_reverse_method () {
+		if (reverse_method == null) {
+			reverse_method = new ArrayReverseMethod (source_reference);
+
+			reverse_method.return_type = new VoidType ();
+			reverse_method.access = SymbolAccessibility.PUBLIC;
+
+			reverse_method.set_cname ("_vala_array_reverse");
+		}
+		return reverse_method;
+	}
+
+	private ArrayShuffleMethod get_shuffle_method () {
+		if (shuffle_method == null) {
+			shuffle_method = new ArrayShuffleMethod (source_reference);
+
+			shuffle_method.return_type = new VoidType ();
+			shuffle_method.access = SymbolAccessibility.PUBLIC;
+
+			shuffle_method.set_cname ("_vala_array_shuffle");
+		}
+		return shuffle_method;
+	}
+
 	public override DataType copy () {
 		var result = new ArrayType (element_type.copy (), rank, source_reference);
 		result.value_owned = value_owned;
--- vala-0.8.1/vala/valaarrayshufflemethod.vala	1970-01-01 02:00:00.000000000 +0200
+++ vala-0.8.1-with-sort-and-shuffle/vala/valaarrayshufflemethod.vala	2010-05-03 13:19:00.456562479 +0300
@@ -0,0 +1,38 @@
+/* valaarrayshufflemethod.vala
+ *
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jukka-Pekka Iivonen <jp0409@jippii.fi>
+ */
+
+using GLib;
+
+/**
+ * Represents the Array.shuffle method.
+ */
+public class Vala.ArrayShuffleMethod : Method {
+	/**
+	 * Creates a new array shuffle method.
+	 *
+	 * @return newly created method
+	 */
+	public ArrayShuffleMethod (SourceReference source_reference) {
+		base ("shuffle", new VoidType (), source_reference);
+		external = true;
+	}
+}
--- vala-0.8.1/vala/valaarraysortmethod.vala	1970-01-01 02:00:00.000000000 +0200
+++ vala-0.8.1-with-sort-and-shuffle/vala/valaarraysortmethod.vala	2010-05-04 15:36:09.208073919 +0300
@@ -0,0 +1,38 @@
+/* valaarraysortmethod.vala
+ *
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jukka-Pekka Iivonen <jp0409@jippii.fi>
+ */
+
+using GLib;
+
+/**
+ * Represents the Array.sort method.
+ */
+public class Vala.ArraySortMethod : Method {
+	/**
+	 * Creates a new array sort method.
+	 *
+	 * @return newly created method
+	 */
+	public ArraySortMethod (SourceReference source_reference) {
+		base ("sort", new VoidType (), source_reference);
+		external = true;
+	}
+}
--- vala-0.8.1/vala/valaarrayreversemethod.vala	1970-01-01 02:00:00.000000000 +0200
+++ vala-0.8.1-with-sort-and-shuffle/vala/valaarrayreversemethod.vala	2010-05-10 16:44:35.387468337 +0300
@@ -0,0 +1,38 @@
+/* valaarrayreversemethod.vala
+ *
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jukka-Pekka Iivonen <jp0409@jippii.fi>
+ */
+
+using GLib;
+
+/**
+ * Represents the Array.reverse method.
+ */
+public class Vala.ArrayReverseMethod : Method {
+	/**
+	 * Creates a new array reverse method.
+	 *
+	 * @return newly created method
+	 */
+	public ArrayReverseMethod (SourceReference source_reference) {
+		base ("reverse", new VoidType (), source_reference);
+		external = true;
+	}
+}
--- vala-0.8.1/vala/valamemberaccess.vala	2010-04-21 14:16:20.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/vala/valamemberaccess.vala	2010-05-04 17:08:27.554538853 +0300
@@ -753,6 +753,63 @@
 				if (instance && base_method.parent_symbol is TypeSymbol) {
 					inner.target_type = analyzer.get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
 				}
+
+				if (symbol_reference is ArraySortMethod) {
+					var array_type = (ArrayType) inner.value_type;
+					switch (array_type.element_type.get_cname ()) {
+					case "float":
+					case "double":
+					case "char*":
+					case "glong":
+					case "gulong":
+					case "gunichar":
+					case "gchar":
+					case "guchar":
+					case "gshort":
+					case "gushort":
+					case "gboolean":
+					case "gint":
+					case "guint":
+					case "gint8":
+					case "guint8":
+					case "gint16":
+					case "guint16":
+					case "gint32":
+					case "guint32":
+					case "gint64":
+					case "guint64":
+					case "gsize":
+					// Posix profile types
+					case "long":
+					case "int":
+					case "int32_t":
+					case "uint32_t":
+					case "char":
+						break;
+					default:
+						if (array_type.element_type is ObjectType) {
+							Symbol sym = array_type.element_type.get_member ("compare");
+							if (sym != null) {
+								if (sym is Method) {
+									var mth = sym as Method;
+									var ret_type = mth.return_type.get_lower_case_cname ();
+									if (ret_type != "int" && ret_type != "int32") {
+										Report.error (inner.source_reference, "element type '%s' provides `compare' member which has invalid return type `%s'".printf (array_type.element_type.get_cname (), ret_type));
+										return false;
+									}
+									break;
+								} else {
+									Report.error (inner.source_reference, "element type '%s' provides `compare' member which is not a method".printf (array_type.element_type.get_cname ()));
+									return false;
+								}
+							}
+							Report.error (inner.source_reference, "element type '%s' does not provide `compare' method for Array.sort".printf (array_type.element_type.get_cname ()));
+							return false;
+						}
+						Report.error (inner.source_reference, "invalid element type '%s' for Array.sort".printf (array_type.element_type.get_cname ()));
+						return false;
+					}
+				}
 			} else if (symbol_reference is Property) {
 				var prop = (Property) symbol_reference;
 
--- vala-0.8.1/vala/Makefile.am	2010-04-21 14:16:20.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/vala/Makefile.am	2010-05-10 16:43:49.834621066 +0300
@@ -19,7 +19,10 @@
 	valaarraycreationexpression.vala \
 	valaarraylengthfield.vala \
 	valaarraymovemethod.vala \
+	valaarrayshufflemethod.vala \
+	valaarraysortmethod.vala \
 	valaarrayresizemethod.vala \
+	valaarrayreversemethod.vala \
 	valaarraytype.vala \
 	valaassignment.vala \
 	valaattribute.vala \
--- vala-0.8.1/codegen/valaccodemethodcallmodule.vala	2010-04-21 15:37:56.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/codegen/valaccodemethodcallmodule.vala	2010-05-12 12:12:34.377013356 +0300
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2006-2010  Jürg Billeter
  * Copyright (C) 2006-2008  Raffaele Sandrini
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,7 @@
  * Author:
  * 	Jürg Billeter <j@bitron.ch>
  *	Raffaele Sandrini <raffaele@sandrini.ch>
+ *      Jukka-Pekka Iivonen <jp0409@jippii.fi>
  */
 
 using GLib;
@@ -165,6 +167,12 @@
 			in_arg_map.set (get_param_pos (0), new CCodeIdentifier (array_type.element_type.get_cname ()));
 		} else if (m is ArrayMoveMethod) {
 			requires_array_move = true;
+		} else if (m is ArraySortMethod) {
+			requires_array_sort = true;
+		} else if (m is ArrayReverseMethod) {
+			requires_array_reverse = true;
+		} else if (m is ArrayShuffleMethod) {
+			requires_array_shuffle = true;
 		}
 
 		CCodeExpression instance = null;
@@ -262,6 +270,130 @@
 			var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
 			csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
 			in_arg_map.set (get_param_pos (0.1), csizeof);
+		} else if (m is ArraySortMethod) {
+			var array_type = (ArrayType) ma.inner.value_type;
+			var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			in_arg_map.set (get_param_pos (0.1), csizeof);
+
+			CCodeExpression lenexpr = head.get_array_length_cexpression (ma.inner, 1);
+			for (int dim=2; dim<=array_type.rank; dim++) {
+				lenexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, lenexpr, head.get_array_length_cexpression (ma.inner, dim));
+			}
+			in_arg_map.set (get_param_pos (0.2), lenexpr);
+
+			string? comp_func = null;
+			string func_type_cast;
+			if (context.profile == Profile.GOBJECT) {
+				func_type_cast = "(GCompareFunc)";
+			} else {
+				func_type_cast = "(int (*)(const void *, const void *))";
+			}
+
+			if (context.profile == Profile.GOBJECT) {
+				switch (array_type.element_type.get_cname ()) {
+				case "float":
+				case "double":
+				case "gunichar":
+				case "guchar":
+				case "guint8":
+				case "gint16":
+				case "guint16":
+				case "gint32":
+				case "guint32":
+				case "gint64":
+				case "guint64":
+				case "gsize":
+					comp_func = array_type.element_type.get_cname ();
+					requires_compare_func.add (comp_func);
+					break;
+				case "char*":
+					comp_func = "string";
+					requires_compare_func.add (comp_func);
+					break;
+				case "glong":
+					comp_func = "long";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gulong":
+					comp_func = "ulong";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gchar":
+					comp_func = "char";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gshort":
+					comp_func = "short";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gushort":
+					comp_func = "ushort";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gboolean":
+				case "gint":
+					comp_func = "int";
+					requires_compare_func.add (comp_func);
+					break;
+				case "guint":
+					comp_func = "uint";
+					requires_compare_func.add (comp_func);
+					break;
+				case "gint8":
+					comp_func = "int8";
+					requires_compare_func.add (comp_func);
+					break;
+				default:
+					Symbol sym = array_type.element_type.get_member ("compare");
+					assert (sym != null);
+					comp_func = array_type.element_type.get_lower_case_cname ();
+					requires_compare_func.add (array_type.element_type.get_cname ());
+					break;
+				}
+			} else {
+				switch (array_type.element_type.get_cname ()) {
+				case "int":
+				case "int32_t":
+				case "uint32_t":
+				case "long":
+				case "char":
+					comp_func = array_type.element_type.get_cname ();
+					requires_compare_func.add (comp_func);
+					break;
+				case "char*":
+					comp_func = "string";
+					requires_compare_func.add (comp_func);
+					break;
+				default:
+					message ("Type: %s is missing from the supported array element types for sorting", array_type.element_type.get_cname ());
+					break;
+				}
+			}
+			var comp_func_const = new CCodeConstant ("%s _vala_compare_%s".printf (func_type_cast, comp_func));
+			in_arg_map.set (get_param_pos (0.3), comp_func_const);
+		} else if (m is ArrayReverseMethod) {
+			var array_type = (ArrayType) ma.inner.value_type;
+			var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			in_arg_map.set (get_param_pos (0.1), csizeof);
+
+			CCodeExpression lenexpr = head.get_array_length_cexpression (ma.inner, 1);
+			for (int dim=2; dim<=array_type.rank; dim++) {
+				lenexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, lenexpr, head.get_array_length_cexpression (ma.inner, dim));
+			}
+			in_arg_map.set (get_param_pos (0.2), lenexpr);
+		} else if (m is ArrayShuffleMethod) {
+			var array_type = (ArrayType) ma.inner.value_type;
+			var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			in_arg_map.set (get_param_pos (0.1), csizeof);
+
+			CCodeExpression lenexpr = head.get_array_length_cexpression (ma.inner, 1);
+			for (int dim=2; dim<=array_type.rank; dim++) {
+				lenexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, lenexpr, head.get_array_length_cexpression (ma.inner, dim));
+			}
+			in_arg_map.set (get_param_pos (0.2), lenexpr);
 		} else if (m is DynamicMethod) {
 			m.clear_parameters ();
 			int param_nr = 1;
--- vala-0.8.1/codegen/valaccodememberaccessmodule.vala	2010-04-21 15:37:56.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/codegen/valaccodememberaccessmodule.vala	2010-05-10 16:49:04.565164963 +0300
@@ -46,7 +46,7 @@
 		if (expr.symbol_reference is Method) {
 			var m = (Method) expr.symbol_reference;
 
-			if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod)) {
+			if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArraySortMethod || m is ArrayReverseMethod || m is ArrayShuffleMethod)) {
 				generate_method_declaration (m, source_declarations);
 
 				if (!m.external && m.external_package) {
--- vala-0.8.1/codegen/valaccodebasemodule.vala	2010-04-21 15:37:56.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/codegen/valaccodebasemodule.vala	2010-05-10 16:36:28.826421262 +0300
@@ -206,10 +206,14 @@
 	public bool gvaluecollector_h_needed;
 	public bool requires_array_free;
 	public bool requires_array_move;
+	public bool requires_array_sort;
+	public bool requires_array_shuffle;
+	public bool requires_array_reverse;
 	public bool requires_array_length;
 	public bool requires_strcmp0;
 	public bool dbus_glib_h_needed;
 	public bool dbus_glib_h_needed_in_header;
+	public HashSet<string> requires_compare_func;
 
 	public Set<string> wrappers;
 	Set<Symbol> generated_external_symbols;
@@ -513,6 +517,15 @@
 	public virtual void append_vala_array_move () {
 	}
 
+	public virtual void append_vala_array_sort () {
+	}
+
+	public virtual void append_vala_array_reverse () {
+	}
+
+	public virtual void append_vala_array_shuffle () {
+	}
+
 	public virtual void append_vala_array_length () {
 	}
 
@@ -570,8 +583,12 @@
 		dbus_glib_h_needed_in_header = false;
 		requires_array_free = false;
 		requires_array_move = false;
+		requires_array_sort = false;
+		requires_array_reverse = false;
+		requires_array_shuffle = false;
 		requires_array_length = false;
 		requires_strcmp0 = false;
+		requires_compare_func = new HashSet<string> (str_hash, str_equal);
 
 		wrappers = new HashSet<string> (str_hash, str_equal);
 		generated_external_symbols = new HashSet<Symbol> ();
@@ -595,6 +612,15 @@
 		if (requires_array_move) {
 			append_vala_array_move ();
 		}
+		if (requires_array_sort) {
+			append_vala_array_sort ();
+		}
+		if (requires_array_reverse) {
+			append_vala_array_reverse ();
+		}
+		if (requires_array_shuffle) {
+			append_vala_array_shuffle ();
+		}
 		if (requires_array_length) {
 			append_vala_array_length ();
 		}
--- vala-0.8.1/codegen/valaccodearraymodule.vala	2010-04-21 15:37:56.000000000 +0300
+++ vala-0.8.1-with-sort-and-shuffle/codegen/valaccodearraymodule.vala	2010-05-12 13:58:22.514539366 +0300
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2006-2009  Jürg Billeter
  * Copyright (C) 2006-2008  Raffaele Sandrini
+ * Copyright (C) 2010  Jukka-Pekka Iivonen
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,7 @@
  * Author:
  * 	Jürg Billeter <j@bitron.ch>
  *	Raffaele Sandrini <raffaele@sandrini.ch>
+ *      Jukka-Pekka Iivonen <jp0409@jippii.fi>
  */
 
 
@@ -673,6 +675,300 @@
 		source_type_member_definition.append (fun);
 	}
 
+	public override void append_vala_array_sort () {
+		source_declarations.add_include ("stdlib.h");
+
+		var fun = new CCodeFunction ("_vala_array_sort", "void");
+		fun.modifiers = CCodeModifiers.STATIC;
+		if (context.profile == Profile.GOBJECT) {
+			fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
+			fun.add_parameter (new CCodeFormalParameter ("comp_func", "GCompareFunc"));
+			fun.add_parameter (new CCodeFormalParameter ("user_comp_func", "void*"));
+		} else {
+			fun.add_parameter (new CCodeFormalParameter ("array", "void*"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "size_t"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "size_t"));
+			fun.add_parameter (new CCodeFormalParameter ("", "int (*comp_func)(const void *, const void *)"));
+			fun.add_parameter (new CCodeFormalParameter ("user_comp_func", "void*"));
+		}
+		source_declarations.add_type_member_declaration (fun.copy ());
+
+		fun.block = new CCodeBlock ();
+
+		var qsort_call = new CCodeFunctionCall (new CCodeIdentifier ("qsort"));
+		qsort_call.add_argument (new CCodeConstant ("array"));
+		qsort_call.add_argument (new CCodeConstant ("array_length"));
+		qsort_call.add_argument (new CCodeConstant ("element_size"));
+		qsort_call.add_argument (new CCodeConstant ("(int (*)(const void *a, const void *b)) comp_func"));
+
+		var qsort_user_call = new CCodeFunctionCall (new CCodeIdentifier ("g_qsort_with_data"));
+		qsort_user_call.add_argument (new CCodeConstant ("array"));
+		qsort_user_call.add_argument (new CCodeConstant ("array_length"));
+		qsort_user_call.add_argument (new CCodeConstant ("element_size"));
+		qsort_user_call.add_argument (new CCodeConstant ("(GCompareDataFunc) _vala_qsort_compare"));
+		qsort_user_call.add_argument (new CCodeConstant ("user_comp_func"));
+
+		var qsort_block = new CCodeBlock ();
+		qsort_block.add_statement (new CCodeExpressionStatement (qsort_call));
+
+		var user_qsort_block = new CCodeBlock ();
+		user_qsort_block.add_statement (new CCodeExpressionStatement (qsort_user_call));
+		var inner_if_stat = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeConstant ("comp_func"), new CCodeConstant ("NULL")), qsort_block, null);
+		var inner_if_block = new CCodeBlock ();
+		inner_if_block.add_statement (inner_if_stat);
+		var if_stat = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("user_comp_func"), new CCodeConstant ("NULL")), inner_if_block, user_qsort_block);
+		fun.block.add_statement (if_stat);
+
+		source_type_member_definition.append (fun);
+
+
+		// Add _vala_qsort_compare for user defined comparison methods
+		fun = new CCodeFunction ("_vala_qsort_compare", "int");
+		fun.modifiers = CCodeModifiers.STATIC;
+		if (context.profile == Profile.GOBJECT) {
+			fun.add_parameter (new CCodeFormalParameter ("a", "gpointer"));
+			fun.add_parameter (new CCodeFormalParameter ("b", "gpointer"));
+			fun.add_parameter (new CCodeFormalParameter ("comp_func", "GCompareFunc"));
+		} else {
+			fun.add_parameter (new CCodeFormalParameter ("a", "void*"));
+			fun.add_parameter (new CCodeFormalParameter ("b", "void*"));
+			fun.add_parameter (new CCodeFormalParameter ("", "int (*comp_func)(const void *, const void *)"));
+		}
+		source_declarations.add_type_member_declaration (fun.copy ());
+		fun.block = new CCodeBlock ();
+		var cdecla = new CCodeDeclaration ("const gpointer*");
+		cdecla.add_declarator (new CCodeVariableDeclarator ("pa"));
+		fun.block.prepend_statement (cdecla);
+		var cdeclb = new CCodeDeclaration ("const gpointer*");
+		cdeclb.add_declarator (new CCodeVariableDeclarator ("pb"));
+		fun.block.prepend_statement (cdeclb);
+
+		fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("pa"), new CCodeConstant ("(const gpointer*) a"))));
+		fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("pb"), new CCodeConstant ("(const gpointer*) b"))));
+
+		fun.block.add_statement (new CCodeReturnStatement (new CCodeConstant ("comp_func (*pa, *pb)")));
+		source_type_member_definition.append (fun);
+
+		// Add _vala_compare_*
+		string[] simple_types;
+		if (context.profile == Profile.GOBJECT) {
+			simple_types = new string[] { "string", "gunichar", "char", "guchar", "double", "float", "long", "ulong", "int", "uint", "short", "ushort", "gsize", "gint8", "guint8", "gint16", "guint16", "gint32", "guint32", "gint64", "guint64" };
+		} else {
+			simple_types = new string[] { "string", "char", "int", "long", "int32_t", "uint32_t" };
+		}
+
+		foreach (string comptype in requires_compare_func) {
+			string fn_name = comptype;
+			if (! (comptype in simple_types)) {
+				fn_name = comptype.down ().replace ("*", "");
+			}
+			fun = new CCodeFunction ("_vala_compare_%s".printf (fn_name), "int");
+			fun.modifiers = CCodeModifiers.STATIC;
+			if (context.profile == Profile.GOBJECT) {
+				fun.add_parameter (new CCodeFormalParameter ("a", "gpointer"));
+				fun.add_parameter (new CCodeFormalParameter ("b", "gpointer"));
+			} else {
+				fun.add_parameter (new CCodeFormalParameter ("a", "void*"));
+				fun.add_parameter (new CCodeFormalParameter ("b", "void*"));
+			}
+			source_declarations.add_type_member_declaration (fun.copy ());
+			fun.block = new CCodeBlock ();
+
+			string ctypename = comptype;
+			if (comptype == "string") {
+				ctypename = "char*";
+			}
+			cdecla = new CCodeDeclaration ("%s*".printf (ctypename));
+			cdeclb = new CCodeDeclaration ("%s*".printf (ctypename));
+
+			cdecla.add_declarator (new CCodeVariableDeclarator ("pa"));
+			fun.block.prepend_statement (cdecla);
+			cdeclb.add_declarator (new CCodeVariableDeclarator ("pb"));
+			fun.block.prepend_statement (cdeclb);
+
+			fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("pa"), new CCodeConstant ("(%s*) a".printf (ctypename)))));
+			fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("pb"), new CCodeConstant ("(%s*) b".printf (ctypename)))));
+
+			if (comptype in simple_types) {
+				if (comptype == "string") {
+					string cmethod = "(pa == NULL && pb == NULL) ? 0 : (pa == NULL) ? -1 : (pb == NULL) ? 1 : strcmp (*pa, *pb)";
+					if (context.profile == Profile.GOBJECT) {
+						cmethod = "g_strcmp0 (*pa, *pb)";
+					}
+					fun.block.add_statement (new CCodeReturnStatement (new CCodeConstant (cmethod)));
+				} else {
+					fun.block.add_statement (new CCodeReturnStatement (new CCodeConstant ("(pa == NULL && pb == NULL) ? 0 : (pa == NULL) ? -1 : (pb == NULL) ? 1 : (*pa < *pb) ? -1 : ((*pa == *pb) ? 0: 1)")));
+				}
+			} else {
+				fun.block.add_statement (new CCodeReturnStatement (new CCodeConstant ("(pa == NULL && pb == NULL) ? 0 : (pa == NULL) ? -1 : (pb == NULL) ? 1 : %s_compare (*pa, *pb)".printf (fn_name))));
+			}
+
+			source_type_member_definition.append (fun);
+		}
+	}
+
+	public override void append_vala_array_reverse () {
+		source_declarations.add_include ("string.h");
+
+		var fun = new CCodeFunction ("_vala_array_reverse", "void");
+		fun.modifiers = CCodeModifiers.STATIC;
+		if (context.profile == Profile.GOBJECT) {
+			fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
+		} else {
+			fun.add_parameter (new CCodeFormalParameter ("array", "void*"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "size_t"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "size_t"));
+		}
+		source_declarations.add_type_member_declaration (fun.copy ());
+
+		fun.block = new CCodeBlock ();
+		var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.DIV, new CCodeIdentifier ("array_length"), new CCodeConstant ("2")));
+		var cbody = new CCodeBlock ();
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("i"));
+		fun.block.prepend_statement (cdecl);
+		cdecl = new CCodeDeclaration ("void*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("tmpbuf"));
+		fun.block.prepend_statement (cdecl);
+
+		string malloc_name = "g_malloc";
+		if (context.profile != Profile.GOBJECT) {
+			malloc_name = "malloc";
+		}
+		var init_call = new CCodeFunctionCall (new CCodeIdentifier (malloc_name));
+		init_call.add_argument (new CCodeConstant ("element_size"));
+
+		fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("tmpbuf"), init_call)));
+
+		var newidecl = new CCodeDeclaration ("int");
+		newidecl.add_declarator (new CCodeVariableDeclarator ("newi"));
+		cbody.prepend_statement (newidecl);
+
+		cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("newi"), new CCodeConstant ("array_length - i - 1"))));
+
+		var totmp_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		totmp_call.add_argument (new CCodeConstant ("tmpbuf"));
+		totmp_call.add_argument (new CCodeConstant ("(((char*) array) + (i*element_size))"));
+		totmp_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (totmp_call));
+
+		var toarr_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		toarr_call.add_argument (new CCodeConstant ("(((char*) array) + (i*element_size))"));
+		toarr_call.add_argument (new CCodeConstant ("(((char*) array) + (newi*element_size))"));
+		toarr_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (toarr_call));
+
+		var tonew_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		tonew_call.add_argument (new CCodeConstant ("(((char*) array) + (newi*element_size))"));
+		tonew_call.add_argument (new CCodeConstant ("tmpbuf"));
+		tonew_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (tonew_call));
+
+		var cfor = new CCodeForStatement (cforcond, cbody);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
+
+		string free_name = "g_free";
+		if (context.profile != Profile.GOBJECT) {
+			free_name = "free";
+		}
+		var free_call = new CCodeFunctionCall (new CCodeIdentifier (free_name));
+		free_call.add_argument (new CCodeConstant ("tmpbuf"));
+
+		fun.block.add_statement (cfor);
+		fun.block.add_statement (new CCodeExpressionStatement (free_call));
+		source_type_member_definition.append (fun);
+	}
+
+	public override void append_vala_array_shuffle () {
+		source_declarations.add_include ("string.h");
+
+		var fun = new CCodeFunction ("_vala_array_shuffle", "void");
+		fun.modifiers = CCodeModifiers.STATIC;
+		if (context.profile == Profile.GOBJECT) {
+			fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
+		} else {
+			fun.add_parameter (new CCodeFormalParameter ("array", "void*"));
+			fun.add_parameter (new CCodeFormalParameter ("element_size", "size_t"));
+			fun.add_parameter (new CCodeFormalParameter ("array_length", "size_t"));
+		}
+		source_declarations.add_type_member_declaration (fun.copy ());
+
+		fun.block = new CCodeBlock ();
+		var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
+		var cbody = new CCodeBlock ();
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("i"));
+		fun.block.prepend_statement (cdecl);
+		cdecl = new CCodeDeclaration ("void*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("tmpbuf"));
+		fun.block.prepend_statement (cdecl);
+
+		string malloc_name = "g_malloc";
+		if (context.profile != Profile.GOBJECT) {
+			malloc_name = "malloc";
+		}
+		var init_call = new CCodeFunctionCall (new CCodeIdentifier (malloc_name));
+		init_call.add_argument (new CCodeConstant ("element_size"));
+
+		fun.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("tmpbuf"), init_call)));
+
+		var newidecl = new CCodeDeclaration ("int");
+		newidecl.add_declarator (new CCodeVariableDeclarator ("newi"));
+		cbody.prepend_statement (newidecl);
+
+		if (context.profile == Profile.GOBJECT) {
+			var rand_call = new CCodeFunctionCall (new CCodeIdentifier ("g_random_int_range"));
+			rand_call.add_argument (new CCodeConstant ("0"));
+			rand_call.add_argument (new CCodeConstant ("array_length"));
+			cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("newi"), rand_call)));
+		} else {
+			var rand_call = new CCodeBinaryExpression (CCodeBinaryOperator.MOD, new CCodeFunctionCall (new CCodeIdentifier ("rand")), new CCodeConstant ("array_length"));
+			cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("newi"), rand_call)));
+		}
+
+
+		var totmp_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		totmp_call.add_argument (new CCodeConstant ("tmpbuf"));
+		totmp_call.add_argument (new CCodeConstant ("(((char*) array) + (i*element_size))"));
+		totmp_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (totmp_call));
+
+		var toarr_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		toarr_call.add_argument (new CCodeConstant ("(((char*) array) + (i*element_size))"));
+		toarr_call.add_argument (new CCodeConstant ("(((char*) array) + (newi*element_size))"));
+		toarr_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (toarr_call));
+
+		var tonew_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		tonew_call.add_argument (new CCodeConstant ("(((char*) array) + (newi*element_size))"));
+		tonew_call.add_argument (new CCodeConstant ("tmpbuf"));
+		tonew_call.add_argument (new CCodeConstant ("element_size"));
+		cbody.add_statement (new CCodeExpressionStatement (tonew_call));
+
+		var cfor = new CCodeForStatement (cforcond, cbody);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
+
+		string free_name = "g_free";
+		if (context.profile != Profile.GOBJECT) {
+			free_name = "free";
+		}
+		var free_call = new CCodeFunctionCall (new CCodeIdentifier (free_name));
+		free_call.add_argument (new CCodeConstant ("tmpbuf"));
+
+		fun.block.add_statement (cfor);
+		fun.block.add_statement (new CCodeExpressionStatement (free_call));
+		source_type_member_definition.append (fun);
+	}
+
+
 	public override void append_vala_array_length () {
 		var fun = new CCodeFunction ("_vala_array_length", "gint");
 		fun.modifiers = CCodeModifiers.STATIC;
