[vala] Support struct comparison



commit a04d18379da5c4cd4f4e860f68cad6647e20b4a0
Author: Jürg Billeter <j bitron ch>
Date:   Fri Oct 9 12:29:00 2009 +0200

    Support struct comparison
    
    Based on patch by Marc-André Lureau, fixes bug 530605.

 codegen/valaccodebasemodule.vala |  161 +++++++++++++++++++++++++++++++------
 tests/Makefile.am                |    1 +
 tests/structs/bug530605.vala     |   23 ++++++
 3 files changed, 159 insertions(+), 26 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 2266fb6..fe56e1d 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -2322,6 +2322,132 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		}
 	}
 
+	void make_comparable_cexpression (DataType left_type, ref CCodeExpression cleft, DataType right_type, ref CCodeExpression cright) {
+		var left_type_as_struct = left_type.data_type as Struct;
+		var right_type_as_struct = right_type.data_type as Struct;
+
+		if (left_type.data_type is Class && !((Class) left_type.data_type).is_compact &&
+		    right_type.data_type is Class && !((Class) right_type.data_type).is_compact) {
+			var left_cl = (Class) left_type.data_type;
+			var right_cl = (Class) right_type.data_type;
+
+			if (left_cl != right_cl) {
+				if (left_cl.is_subtype_of (right_cl)) {
+					cleft = generate_instance_cast (cleft, right_cl);
+				} else if (right_cl.is_subtype_of (left_cl)) {
+					cright = generate_instance_cast (cright, left_cl);
+				}
+			}
+		} else if (left_type_as_struct != null && right_type_as_struct != null) {
+			if (left_type is StructValueType) {
+				// real structs (uses compare/equal function)
+				if (!left_type.nullable) {
+					cleft = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cleft);
+				}
+				if (!right_type.nullable) {
+					cright = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cright);
+				}
+			} else {
+				// integer or floating or boolean type
+				if (left_type.nullable && right_type.nullable) {
+					// FIXME also compare contents, not just address
+				} else if (left_type.nullable) {
+					// FIXME check left value is not null
+					cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
+				} else if (right_type.nullable) {
+					// FIXME check right value is not null
+					cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
+				}
+			}
+		}
+	}
+
+	private string generate_struct_equal_function (Struct st) {
+		string equal_func = "_%sequal".printf (st.get_lower_case_cprefix ());
+
+		if (!add_wrapper (equal_func)) {
+			// wrapper already defined
+			return equal_func;
+		}
+		// declaration
+
+		var function = new CCodeFunction (equal_func, "gboolean");
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("s1", "const " + st.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("s2", "const " + st.get_cname () + "*"));
+
+		// definition
+		var cblock = new CCodeBlock ();
+
+		// if (s1 == s2) return TRUE;
+		{
+			var block = new CCodeBlock ();
+			block.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
+
+			var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeIdentifier ("s2"));
+			var cif = new CCodeIfStatement (cexp, block);
+			cblock.add_statement (cif);
+		}
+		// if (s1 == NULL || s2 == NULL) return FALSE;
+		{
+			var block = new CCodeBlock ();
+			block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
+
+			var cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s1"), new CCodeConstant ("NULL"));
+			var cif = new CCodeIfStatement (cexp, block);
+			cblock.add_statement (cif);
+
+			cexp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("s2"), new CCodeConstant ("NULL"));
+			cif = new CCodeIfStatement (cexp, block);
+			cblock.add_statement (cif);
+		}
+
+		foreach (Field f in st.get_fields ()) {
+			if (f.binding != MemberBinding.INSTANCE) {
+				// we only compare instance fields
+				continue;
+			}
+
+			CCodeExpression cexp; // if (cexp) return FALSE;
+			var s1 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s1"), f.name); // s1->f
+			var s2 = (CCodeExpression) new CCodeMemberAccess.pointer (new CCodeIdentifier ("s2"), f.name); // s2->f
+			make_comparable_cexpression (f.field_type, ref s1, f.field_type, ref s2);
+
+			if (!(f.field_type is NullType) && f.field_type.compatible (string_type)) {
+				requires_strcmp0 = true;
+				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_strcmp0"));
+				ccall.add_argument (s1);
+				ccall.add_argument (s2);
+				cexp = ccall;
+			} else if (f.field_type is StructValueType) {
+				var equalfunc = generate_struct_equal_function (f.field_type.data_type as Struct);
+				var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
+				ccall.add_argument (s1);
+				ccall.add_argument (s2);
+				cexp = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
+			} else {
+				cexp = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, s1, s2);
+			}
+
+			var block = new CCodeBlock ();
+			block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
+			var cif = new CCodeIfStatement (cexp, block);
+			cblock.add_statement (cif);
+		}
+
+		cblock.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
+
+		// append to file
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = cblock;
+		source_type_member_definition.append (function);
+
+		return equal_func;
+	}
+
 	private string generate_struct_dup_wrapper (ValueType value_type) {
 		string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
 
@@ -4149,32 +4275,15 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		
 		if (expr.operator == BinaryOperator.EQUALITY ||
 		    expr.operator == BinaryOperator.INEQUALITY) {
-			var left_type_as_struct = expr.left.value_type.data_type as Struct;
-			var right_type_as_struct = expr.right.value_type.data_type as Struct;
+			make_comparable_cexpression (expr.left.value_type, ref cleft, expr.right.value_type, ref cright);
 
-			if (expr.left.value_type.data_type is Class && !((Class) expr.left.value_type.data_type).is_compact &&
-			    expr.right.value_type.data_type is Class && !((Class) expr.right.value_type.data_type).is_compact) {
-				var left_cl = (Class) expr.left.value_type.data_type;
-				var right_cl = (Class) expr.right.value_type.data_type;
-				
-				if (left_cl != right_cl) {
-					if (left_cl.is_subtype_of (right_cl)) {
-						cleft = generate_instance_cast (cleft, right_cl);
-					} else if (right_cl.is_subtype_of (left_cl)) {
-						cright = generate_instance_cast (cright, left_cl);
-					}
-				}
-			} else if (left_type_as_struct != null && right_type_as_struct != null) {
-				// FIXME generate and use compare/equal function for real structs
-				if (expr.left.value_type.nullable && expr.right.value_type.nullable) {
-					// FIXME also compare contents, not just address
-				} else if (expr.left.value_type.nullable) {
-					// FIXME check left value is not null
-					cleft = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cleft);
-				} else if (expr.right.value_type.nullable) {
-					// FIXME check right value is not null
-					cright = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cright);
-				}
+			if (expr.left.value_type is StructValueType && expr.right.value_type is StructValueType) {
+				var equalfunc = generate_struct_equal_function ((Struct) expr.left.value_type.data_type as Struct);
+				var ccall = new CCodeFunctionCall (new CCodeIdentifier (equalfunc));
+				ccall.add_argument (cleft);
+				ccall.add_argument (cright);
+				cleft = ccall;
+				cright = new CCodeConstant ("TRUE");
 			}
 		}
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 09d0640..9698cfa 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -40,6 +40,7 @@ TESTS = \
 	enums/enums.vala \
 	structs/structs.vala \
 	structs/gvalue.vala \
+	structs/bug530605.vala \
 	structs/bug583603.vala \
 	structs/bug595587.vala \
 	delegates/delegates.vala \
diff --git a/tests/structs/bug530605.vala b/tests/structs/bug530605.vala
new file mode 100644
index 0000000..030564f
--- /dev/null
+++ b/tests/structs/bug530605.vala
@@ -0,0 +1,23 @@
+struct Foo {
+	int bar;
+	string baz;
+
+	public Foo (int bar, string baz) {
+		this.bar = bar;
+		this.baz = baz;
+	}
+}
+
+void main () {
+	Foo a = Foo (42, "hello");
+	Foo b = Foo (42, "hello");
+	Foo? c = Foo (42, "hello");
+	Foo d = Foo (42, "world");
+	Foo e = Foo (23, "hello");
+
+	assert (a == b);
+	assert (a == c);
+	assert (a != d);
+	assert (a != e);
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]