int json_equal(json_t *json1, json_t *json2) { if(!json1 || !json2) return 0; if(json_typeof(json1) != json_typeof(json2)) return 0; /* this covers true, false and null as they are singletons */ if(json1 == json2) return 1; if(json_is_object(json1)) return json_object_equal(json1, json2); if(json_is_array(json1)) return json_array_equal(json1, json2); if(json_is_string(json1)) return json_string_equal(json1, json2); if(json_is_integer(json1)) return json_integer_equal(json1, json2); if(json_is_real(json1)) return json_real_equal(json1, json2); return 0; }
json_t *json_true(void) { static json_t the_true = { .type = JSON_TRUE, .refcount = (unsigned int)1 }; return &the_true; } json_t *json_false(void) { static json_t the_false = { .type = JSON_FALSE, .refcount = (unsigned int)1 }; return &the_false; } json_t *json_null(void) { static json_t the_null = { .type = JSON_NULL, .refcount = (unsigned int)1 }; return &the_null; } /*** deletion ***/ void json_delete(json_t *json) { if(json_is_object(json)) json_delete_object(json_to_object(json)); else if(json_is_array(json)) json_delete_array(json_to_array(json)); else if(json_is_string(json)) json_delete_string(json_to_string(json)); else if(json_is_integer(json)) json_delete_integer(json_to_integer(json)); else if(json_is_real(json)) json_delete_real(json_to_real(json)); /* json_delete is not called for true, false or null */ } /*** equality ***/ int json_equal(json_t *json1, json_t *json2) { if(!json1 || !json2) return 0; if(json_typeof(json1) != json_typeof(json2)) return 0; /* this covers true, false and null as they are singletons */ if(json1 == json2) return 1; if(json_is_object(json1)) return json_object_equal(json1, json2); if(json_is_array(json1)) return json_array_equal(json1, json2); if(json_is_string(json1)) return json_string_equal(json1, json2); if(json_is_integer(json1)) return json_integer_equal(json1, json2); if(json_is_real(json1)) return json_real_equal(json1, json2); return 0; } /*** copying ***/ json_t *json_copy(json_t *json) { if(!json) return NULL; if(json_is_object(json)) return json_object_copy(json); if(json_is_array(json)) return json_array_copy(json); if(json_is_string(json)) return json_string_copy(json); if(json_is_integer(json)) return json_integer_copy(json); if(json_is_real(json)) return json_real_copy(json); if(json_is_true(json) || json_is_false(json) || json_is_null(json)) return json; return NULL; } json_t *json_deep_copy(json_t *json) { if(!json) return NULL; if(json_is_object(json)) return json_object_deep_copy(json); if(json_is_array(json)) return json_array_deep_copy(json); /* for the rest of the types, deep copying doesn't differ from shallow copying */ if(json_is_string(json)) return json_string_copy(json); if(json_is_integer(json)) return json_integer_copy(json); if(json_is_real(json)) return json_real_copy(json); if(json_is_true(json) || json_is_false(json) || json_is_null(json)) return json; return NULL; }
/** * json_node_equal: * @a: (type JsonNode): a JSON node * @b: (type JsonNode): another JSON node * * Check whether @a and @b are equal #JsonNodes, meaning they have the same * type and same values (checked recursively). Note that integer values are * compared numerically, ignoring type, so a double value 4.0 is equal to the * integer value 4. * * Returns: %TRUE if @a and @b are equal; %FALSE otherwise * Since: 1.2 */ gboolean json_node_equal (gconstpointer a, gconstpointer b) { JsonNode *node_a, *node_b; /* unowned */ node_a = (JsonNode *) a; node_b = (JsonNode *) b; /* Identity comparison. */ if (node_a == node_b) return TRUE; /* Eliminate mismatched types rapidly. */ if (!json_type_is_a (node_a, node_b) && !json_type_is_a (node_b, node_a)) { return FALSE; } switch (node_a->type) { case JSON_NODE_NULL: /* Types match already. */ return TRUE; case JSON_NODE_ARRAY: return json_array_equal (json_node_get_array (node_a), json_node_get_array (node_b)); case JSON_NODE_OBJECT: return json_object_equal (json_node_get_object (node_a), json_node_get_object (node_b)); case JSON_NODE_VALUE: /* Handled below. */ break; default: g_assert_not_reached (); } /* Handle values. */ switch (node_a->data.value->type) { case JSON_VALUE_NULL: /* Types already match. */ return TRUE; case JSON_VALUE_BOOLEAN: return (json_node_get_boolean (node_a) == json_node_get_boolean (node_b)); case JSON_VALUE_STRING: return json_string_equal (json_node_get_string (node_a), json_node_get_string (node_b)); case JSON_VALUE_DOUBLE: case JSON_VALUE_INT: { gdouble val_a, val_b; JsonValueType value_type_a, value_type_b; value_type_a = node_a->data.value->type; value_type_b = node_b->data.value->type; /* Integer comparison doesn’t need to involve doubles… */ if (value_type_a == JSON_VALUE_INT && value_type_b == JSON_VALUE_INT) { return (json_node_get_int (node_a) == json_node_get_int (node_b)); } /* …but everything else does. We can use bitwise double equality here, * since we’re not doing any calculations which could introduce floating * point error. We expect that the doubles in the JSON nodes come directly * from strtod() or similar, so should be bitwise equal for equal string * representations. * * Interesting background reading: * http://randomascii.wordpress.com/2012/06/26/\ * doubles-are-not-floats-so-dont-compare-them/ */ if (value_type_a == JSON_VALUE_INT) val_a = json_node_get_int (node_a); else val_a = json_node_get_double (node_a); if (value_type_b == JSON_VALUE_INT) val_b = json_node_get_int (node_b); else val_b = json_node_get_double (node_b); return (val_a == val_b); } case JSON_VALUE_INVALID: default: g_assert_not_reached (); } }