diff options
author | David Zeuthen <davidz@redhat.com> | 2008-12-15 19:15:05 -0500 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2008-12-15 19:15:05 -0500 |
commit | 8b6011e7b4740a204d336f71810e2c3729819a62 (patch) | |
tree | 8801058f23eee1e7066032a29bf2cd504c6d04dc | |
parent | 8759f2a86ca44b8ca73fb182e880637595cbf231 (diff) |
take a #GEqualFunc and add index_of() and friends
-rw-r--r-- | docs/eggdbus/eggdbus-sections.txt | 4 | ||||
-rw-r--r-- | src/eggdbus/eggdbusarrayseq.c | 279 | ||||
-rw-r--r-- | src/eggdbus/eggdbusarrayseq.h | 51 | ||||
-rw-r--r-- | src/tests/testclient.c | 106 |
4 files changed, 358 insertions, 82 deletions
diff --git a/docs/eggdbus/eggdbus-sections.txt b/docs/eggdbus/eggdbus-sections.txt index 8c1056d..a9b91ee 100644 --- a/docs/eggdbus/eggdbus-sections.txt +++ b/docs/eggdbus/eggdbus-sections.txt @@ -426,6 +426,7 @@ EggDBusArraySeq egg_dbus_array_seq_new egg_dbus_array_seq_new_full egg_dbus_array_seq_get_flags +egg_dbus_array_seq_set_equal_func egg_dbus_array_seq_size egg_dbus_array_seq_set_size egg_dbus_array_seq_get_element_size @@ -439,6 +440,9 @@ egg_dbus_array_seq_set egg_dbus_array_seq_set_dup egg_dbus_array_seq_add egg_dbus_array_seq_add_dup +egg_dbus_array_seq_index_of +egg_dbus_array_seq_contains +egg_dbus_array_seq_remove egg_dbus_array_seq_steal_data egg_dbus_array_seq_add_byte egg_dbus_array_seq_add_int16 diff --git a/src/eggdbus/eggdbusarrayseq.c b/src/eggdbus/eggdbusarrayseq.c index 1c9dfd6..286125a 100644 --- a/src/eggdbus/eggdbusarrayseq.c +++ b/src/eggdbus/eggdbusarrayseq.c @@ -37,20 +37,29 @@ * * The array will automatically grow when elements are added and all accessor functions * dealing with index-based access checks if the index is within bounds. If an index - * is not within the bounds of the array a warning is issued on <literal>stderr</literal> - * using g_error() (e.g. causing program termination). + * is not within the bounds of the array a warning is issued using g_error() (causing + * program termination). * - * When possible (e.g. for integral and #G_TYPE_OBJECT derived types), the array will - * also check that the type of an inserted element matches the element type of the - * array. If the check fails, a warning is issued using g_error(). + * When possible (e.g. for integral types when the C convenience functions + * are used and #G_TYPE_OBJECT derived types), type checking will be performed to ensure + * an inserted element is compatible element type of the array. If the check fails, a + * warning is issued using g_error() (causing program termination). * * The array type has a notion of <emphasis>static elements</emphasis> that can be used * to do away with copying/freeing data if certain assumptions can be made about the * data passed in. See #EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC for details. * + * For implementing operations that involve comparing if two elements are equal (such + * as egg_dbus_array_seq_contains()), a #GEqualFunc is needed. For most types (such as + * #G_TYPE_STRING and #G_TYPE_INT), the default one is used but for e.g. #G_TYPE_OBJECT + * derived types one will need to be provided. Note that said operations are + * <emphasis>optional</emphasis> in the sense that if a #GEqualFunc is not provided + * other operations will still work; the operations needing the equality function + * will just fail and call g_error() (causing program termination). + * * By default, the array takes ownership when inserting elements meaning that the * programmer gives up his reference. In addition, there is convenience API to - * make the array insert a copy of the item; see egg_dbus_array_seq_add_dup() for + * make the array insert a copy of the element; see egg_dbus_array_seq_add_dup() for * example. * * Items extracted from the array are owned by the array. There is also convenience @@ -64,15 +73,6 @@ * * TODO: * - * To implement contains(), index_of() and remove() we need to get the user to pass - * a #GEqualFunc. Sometimes we can infer this function directly (e.g. for strings) but - * for boxed and object types we can't. Probably need a way to set the equal_func. - * And also take it possibly from both constructors (passing %NULL would mean - * use default; user can override with set_equal_func (NULL). - * Also need a #EggDBusArraySeqFlags flag for whether we have an equal func. And document - * that contains() + friends can fail runtime if we don't have an equal func (which is - * fine). - * * Want to have the notion of a read-only array; for example, in a modern world * #GVolumeMonitor would pass out read-only arrays of volumes (since the user * can't add anything to them). Can easily be implemented with #EggDBusArraySeqFlags. @@ -121,6 +121,10 @@ typedef struct /* cached value of G_IS_OBJECT_TYPE() to avoid overhead on every insertion */ gboolean element_type_is_gobject_derived; + GEqualFunc equal_func; + + EggDBusArraySeqFlags flags; + } EggDBusArraySeqPrivate; enum @@ -241,6 +245,26 @@ free_elem_static (EggDBusArraySeq *array_seq, /* ---------------------------------------------------------------------------------------------------- */ +#define IMPL_EQUAL_FUNC(type) \ + static gboolean \ + _##type##_equal (gconstpointer v1, gconstpointer v2) \ + { \ + const type *a = v1; \ + const type *b = v2; \ + return *a == *b; \ + } + +IMPL_EQUAL_FUNC (guchar); +IMPL_EQUAL_FUNC (gint); +IMPL_EQUAL_FUNC (gint64); +IMPL_EQUAL_FUNC (gboolean); +IMPL_EQUAL_FUNC (gdouble); +IMPL_EQUAL_FUNC (glong); +IMPL_EQUAL_FUNC (gfloat); +IMPL_EQUAL_FUNC (gint16); + +/* ---------------------------------------------------------------------------------------------------- */ + static void ensure_size (EggDBusArraySeq *array_seq, guint minimum_size) @@ -291,19 +315,17 @@ egg_dbus_array_seq_class_init (EggDBusArraySeqClass *klass) /** * egg_dbus_array_seq_new: - * @element_type: A #GType. + * @element_type: The type of the elements in the array. * - * Creates a new array where inserted data is stolen by the array (unless methods like - * egg_dbus_array_seq_set_dup() and egg_dbus_array_seq_add_dup() are used) and freed - * when the array is finalized. Use egg_dbus_array_seq_new() to change this behavior. + * Creates a new array that holds elements of @element_type with the default (if any) function + * for comparing equality. * * Allowed values for @element_type include the types #EGG_DBUS_TYPE_INT16, #EGG_DBUS_TYPE_UINT16 * as well as any fundamental type known by the GObject library, and any type derived from any * of the aforementioned types. Note that for #G_TYPE_INTERFACE, only instances deriving from * #G_TYPE_OBJECT are supported. * - * See egg_dbus_array_seq_new() for a variant of this function with - * more complicated options. + * See egg_dbus_array_seq_new() for a variant of this function with more complicated options. * * Returns: A new #EggDBusArraySeq. Free with g_object_unref(). **/ @@ -312,14 +334,16 @@ egg_dbus_array_seq_new (GType element_type) { return egg_dbus_array_seq_new_full (element_type, EGG_DBUS_ARRAY_SEQ_FLAGS_NONE, + NULL, 0, NULL); } /** * egg_dbus_array_seq_new_full: - * @element_type: A #GType. + * @element_type: The type of the elements in the array. * @flags: A combination of flags from #EggDBusArraySeqFlags. + * @equal_func: A function that compares whether to elements are equal or %NULL to use default if one such exists. * @size: The number of elements in the @data parameter or 0 if @data is %NULL. * @data: Either %NULL (in which case @size must be 0) or raw memory to initialize the array with. * @@ -327,6 +351,13 @@ egg_dbus_array_seq_new (GType element_type) * See egg_dbus_array_seq_new() for details on allowed values of @element_type and required memory * layout of @data. * + * If @equal_func is %NULL, the default equality function is used if one exists for @element_type + * (there is no natural equality function if @element_type is a subtype of #G_TYPE_OBJECT, #G_TYPE_INTERFACE + * or #G_TYPE_BOXED). Note that if the elements holds a fixed-size type (such as #G_TYPE_INT), the + * parameters passed to @equal_func will be the address of the element (e.g. a #gint<!-- -->*). Otherwise + * (for arrays holding non-fixed sizes) the pointer stored in the array is passed (e.g. a #GFile<!-- -->* + * if the array holds elements of #G_TYPE_FILE). + * * If #EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC is set in @flags, then elements are never copied (and methods like * e.g. egg_dbus_array_seq_add_dup() will behave like egg_dbus_array_seq_add()) which can help with * performance. On the other hand, if this flag is passed, you must guarantee that any elements inserted @@ -337,28 +368,35 @@ egg_dbus_array_seq_new (GType element_type) EggDBusArraySeq * egg_dbus_array_seq_new_full (GType element_type, EggDBusArraySeqFlags flags, + GEqualFunc equal_func, guint size, gconstpointer data) { + GType fundamental_type; EggDBusArraySeq *array_seq; EggDBusArraySeqPrivate *priv; - guint n; gboolean not_supported; gpointer *given_data; - GType fundamental_type; + guint n; array_seq = EGG_DBUS_ARRAY_SEQ (g_object_new (EGG_DBUS_TYPE_ARRAY_SEQ, NULL)); priv = EGG_DBUS_ARRAY_SEQ_GET_PRIVATE (array_seq); - array_seq->flags = flags; + priv->flags = flags; array_seq->size = size; array_seq->element_type = element_type; + priv->equal_func = equal_func; + not_supported = FALSE; - /* first compute copy_func, free_func and element_size; switch on fundamental type */ fundamental_type = G_TYPE_FUNDAMENTAL (array_seq->element_type); + + if (flags & EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC) + g_error ("You cannot pass EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC in flags"); + + /* first compute copy_func, free_func, element_size and equal_func */ switch (fundamental_type) { case G_TYPE_OBJECT: @@ -385,53 +423,67 @@ egg_dbus_array_seq_new_full (GType element_type, priv->copy_func = copy_elem_string; priv->free_func = free_elem_string; array_seq->element_size = sizeof (gpointer); + + if (priv->equal_func == NULL) + priv->equal_func = g_str_equal; + break; case G_TYPE_UCHAR: case G_TYPE_CHAR: array_seq->element_size = sizeof (guchar); + if (priv->equal_func == NULL) + priv->equal_func = _guchar_equal; break; case G_TYPE_INT: case G_TYPE_UINT: array_seq->element_size = sizeof (gint); + if (priv->equal_func == NULL) + priv->equal_func = _gint_equal; break; case G_TYPE_INT64: case G_TYPE_UINT64: array_seq->element_size = sizeof (gint64); + if (priv->equal_func == NULL) + priv->equal_func = _gint64_equal; break; case G_TYPE_BOOLEAN: array_seq->element_size = sizeof (gboolean); + if (priv->equal_func == NULL) + priv->equal_func = _gboolean_equal; break; case G_TYPE_DOUBLE: array_seq->element_size = sizeof (gdouble); + if (priv->equal_func == NULL) + priv->equal_func = _gdouble_equal; break; case G_TYPE_LONG: - array_seq->element_size = sizeof (glong); - break; - case G_TYPE_ULONG: - array_seq->element_size = sizeof (gulong); + array_seq->element_size = sizeof (glong); + if (priv->equal_func == NULL) + priv->equal_func = _glong_equal; break; case G_TYPE_FLOAT: array_seq->element_size = sizeof (gfloat); - break; - - case G_TYPE_POINTER: - array_seq->element_size = sizeof (gpointer); + if (priv->equal_func == NULL) + priv->equal_func = _gfloat_equal; break; case G_TYPE_ENUM: + case G_TYPE_FLAGS: array_seq->element_size = sizeof (gint); + if (priv->equal_func == NULL) + priv->equal_func = _gint_equal; break; - case G_TYPE_FLAGS: - array_seq->element_size = sizeof (gint); + case G_TYPE_POINTER: + array_seq->element_size = sizeof (gpointer); break; default: @@ -442,6 +494,8 @@ egg_dbus_array_seq_new_full (GType element_type, array_seq->element_type == EGG_DBUS_TYPE_UINT16) { array_seq->element_size = sizeof (gint16); + if (priv->equal_func == NULL) + priv->equal_func = _gint16_equal; } else { @@ -450,14 +504,18 @@ egg_dbus_array_seq_new_full (GType element_type, break; } - /* warn if STATIC was passed but element is a fixed-size type; this is a programmer-error */ - if (priv->copy_func == NULL && (array_seq->flags & EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC)) + /* warn/abort if STATIC was passed but element is a fixed-size type; this is a programmer-error */ + if (priv->copy_func == NULL && (priv->flags & EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC)) { g_error ("Using EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC doesn't make sense for " "fixed-size type %s.", g_type_name (array_seq->element_type)); } + /* sort out equal function */ + if (priv->equal_func != NULL) + priv->flags |= EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC; + if (not_supported) { /* didn't recognize type; this is a programmer/user error; contract says we can only manage @@ -468,7 +526,7 @@ egg_dbus_array_seq_new_full (GType element_type, } /* if the passed in objects are static; use non-op copy(), free() implementations */ - if (array_seq->flags & EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC) + if (priv->flags & EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC) { priv->copy_func = copy_elem_static; priv->free_func = free_elem_static; @@ -502,6 +560,45 @@ egg_dbus_array_seq_new_full (GType element_type, return array_seq; } +/** + * egg_dbus_array_seq_set_equal_func: + * @array_seq: A #EggDBusArraySeq. + * @equal_func: A #GEqualFunc or %NULL. + * + * Sets the function for comparing equality. + **/ +void +egg_dbus_array_seq_set_equal_func (EggDBusArraySeq *array_seq, + GEqualFunc equal_func) +{ + EggDBusArraySeqPrivate *priv; + + priv = EGG_DBUS_ARRAY_SEQ_GET_PRIVATE (array_seq); + + priv->equal_func = equal_func; + + if (equal_func == NULL) + priv->flags &= ~EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC; + else + priv->flags |= EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC; +} + +static gboolean +check_have_equal_func (EggDBusArraySeq *array_seq) +{ + EggDBusArraySeqPrivate *priv; + + priv = EGG_DBUS_ARRAY_SEQ_GET_PRIVATE (array_seq); + + if (G_LIKELY (priv->equal_func != NULL)) + return TRUE; + + g_error ("no equal_func set for EggDBusArraySeq<%s>", + g_type_name (array_seq->element_type)); + + return FALSE; +} + static gboolean check_index (EggDBusArraySeq *array_seq, gint index) @@ -551,7 +648,7 @@ egg_dbus_array_seq_get_flags (EggDBusArraySeq *array_seq) priv = EGG_DBUS_ARRAY_SEQ_GET_PRIVATE (array_seq); - return array_seq->flags; + return priv->flags; } /** @@ -868,7 +965,7 @@ egg_dbus_array_seq_set_internal (EggDBusArraySeq *array_seq, * egg_dbus_array_seq_set: * @array_seq: A #EggDBusArraySeq. * @index: Zero-based index of element. - * @value: The item to insert. + * @value: The value to insert. * * Replaces the element at @index in @array_seq with @value. * @@ -890,7 +987,7 @@ egg_dbus_array_seq_set (EggDBusArraySeq *array_seq, * egg_dbus_array_seq_set_dup: * @array_seq: A #EggDBusArraySeq. * @index: Zero-based index of element. - * @value: The item to insert. + * @value: The value to insert. * * Replaces the element at @index in @array_seq with a copy/reference of @value. * @@ -910,7 +1007,7 @@ egg_dbus_array_seq_set_dup (EggDBusArraySeq *array_seq, /** * egg_dbus_array_seq_add: * @array_seq: A #EggDBusArraySeq. - * @value: The item to insert. + * @value: The value to insert. * * Appends @value to the end of @array_seq. The size of @array_seq will grow by one. * @@ -937,7 +1034,7 @@ egg_dbus_array_seq_add (EggDBusArraySeq *array_seq, /** * egg_dbus_array_seq_add_dup: * @array_seq: A #EggDBusArraySeq. - * @value: The item to insert. + * @value: The value to insert. * * Appends a copy of @value to the end of @array_seq. The size of @array_seq will grow by one. * @@ -958,6 +1055,95 @@ egg_dbus_array_seq_add_dup (EggDBusArraySeq *array_seq, return TRUE; } +/** + * egg_dbus_array_seq_index_of: + * @array_seq: A #EggDBusArraySeq. + * @value: The value to check for. + * + * Find the first occurence of an element equal to @value in @array_seq. + * + * This method is optional. It is a programing error to call this method on @array_seq + * if the flag #EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC isn't set. + * + * Returns: The index of the first occurence of an element equal to @value + * in @array_seq or -1 if no such elements exist. + **/ +gint +egg_dbus_array_seq_index_of (EggDBusArraySeq *array_seq, + gconstpointer value) +{ + EggDBusArraySeqPrivate *priv; + guint n; + + if (!check_have_equal_func (array_seq)) + return -1; + + priv = EGG_DBUS_ARRAY_SEQ_GET_PRIVATE (array_seq); + + for (n = 0; n < array_seq->size; n++) + { + gboolean found; + + if (priv->copy_func != NULL) + found = priv->equal_func (array_seq->data.v_ptr[n], value); + else + found = priv->equal_func (array_seq->data.v_byte + n * array_seq->element_size, value); + + if (found) + break; + } + + return n == array_seq->size ? -1 : (gint) n; +} + +/** + * egg_dbus_array_seq_contains: + * @array_seq: A #EggDBusArraySeq. + * @value: The value to check for. + * + * Check if @array_seq contains an element equal to @value. + * + * This method is optional. It is a programing error to call this method on @array_seq + * if the flag #EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC isn't set. + * + * Returns: %TRUE if @array_seq contains one or more elements equal to @value. + **/ +gboolean +egg_dbus_array_seq_contains (EggDBusArraySeq *array_seq, + gconstpointer value) +{ + return egg_dbus_array_seq_index_of (array_seq, value) != -1; +} + +/** + * egg_dbus_array_seq_remove: + * @array_seq: A #EggDBusArraySeq. + * @value: The value to remove. + * + * Remove the first occurence of elements equal to @value from @array_seq. + * + * This method is optional. It is a programing error to call this method on @array_seq + * if the flag #EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC isn't set. + * + * Returns: %TRUE if an element was removed. + **/ +gboolean +egg_dbus_array_seq_remove (EggDBusArraySeq *array_seq, + gconstpointer value) +{ + gint index; + + index = egg_dbus_array_seq_index_of (array_seq, value); + + if (index == -1) + return FALSE; + + egg_dbus_array_seq_remove_at (array_seq, index); + return TRUE; +} + + + /* ---------------------------------------------------------------------------------------------------- */ @@ -1140,7 +1326,7 @@ egg_dbus_array_seq_new_for_double (guint size, #define EGG_DBUS_ARRAY_SEQ_NEW_FOR_VALIST(ctype, promoted_ctype, gtype) \ guint n = 0; \ promoted_ctype elem = first_value; \ - ctype *data = (ctype *) g_new0 (ctype, size); \ + ctype *data = (ctype *) g_new0 (ctype, size); \ do \ { \ data[n] = (ctype) elem; \ @@ -1148,7 +1334,7 @@ egg_dbus_array_seq_new_for_double (guint size, n++; \ } \ while (n < size); \ - return egg_dbus_array_seq_new_full (gtype, 0, size, data); + return egg_dbus_array_seq_new_full (gtype, 0, NULL, size, data); /** @@ -1322,7 +1508,6 @@ egg_dbus_array_seq_new_for_double_valist (guint size, EGG_DBUS_ARRAY_SEQ_NEW_FOR_VALIST (gdouble, gdouble, G_TYPE_DOUBLE); } - /* ---------------------------------------------------------------------------------------------------- */ #define EGG_DBUS_ARRAY_SEQ_GET(name,failval) \ diff --git a/src/eggdbus/eggdbusarrayseq.h b/src/eggdbus/eggdbusarrayseq.h index afd3e32..e3699b3 100644 --- a/src/eggdbus/eggdbusarrayseq.h +++ b/src/eggdbus/eggdbusarrayseq.h @@ -43,18 +43,19 @@ typedef struct _EggDBusArraySeqClass EggDBusArraySeqClass; * EggDBusArraySeqFlags: * @EGG_DBUS_ARRAY_SEQ_FLAGS_NONE: No flags set. * @EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC: Elements are never copied; users of the array must ensure that inserted elements are alive for the duration of the lifetime of the array. + * @EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC: Is set only if there's an equal function for comparing elements. If this flag is not set, certain operations such as egg_dbus_array_seq_contains() on the array are not supported. You can not pass this flag in any of the constructors. * * Flags that specify the behavior of an #EggDBusArraySeq instance. */ typedef enum { - EGG_DBUS_ARRAY_SEQ_FLAGS_NONE = 0, - EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC = (1<<0), + EGG_DBUS_ARRAY_SEQ_FLAGS_NONE = 0, + EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC = (1<<0), + EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC = (1<<1), } EggDBusArraySeqFlags; /** * EggDBusArraySeq: - * @flags: Flags describing the behavior of the #EggDBusArraySeq instance. * @size: Number of elements in the array. * @element_type: The #GType of the elements in the array. * @element_size: The size, in bytes, of each element. @@ -85,7 +86,6 @@ struct _EggDBusArraySeq GObject parent_instance; /*< public >*/ - EggDBusArraySeqFlags flags; guint size; GType element_type; gsize element_size; @@ -133,11 +133,15 @@ EggDBusArraySeq *egg_dbus_array_seq_new (GType EggDBusArraySeq *egg_dbus_array_seq_new_full (GType element_type, EggDBusArraySeqFlags flags, + GEqualFunc equal_func, guint size, gconstpointer data) G_GNUC_WARN_UNUSED_RESULT; EggDBusArraySeqFlags egg_dbus_array_seq_get_flags (EggDBusArraySeq *array_seq) G_GNUC_WARN_UNUSED_RESULT; +void egg_dbus_array_seq_set_equal_func (EggDBusArraySeq *array_seq, + GEqualFunc equal_func); + guint egg_dbus_array_seq_size (EggDBusArraySeq *array_seq) G_GNUC_WARN_UNUSED_RESULT; void egg_dbus_array_seq_set_size (EggDBusArraySeq *array_seq, @@ -175,14 +179,19 @@ gboolean egg_dbus_array_seq_add (EggDBusArraySeq gboolean egg_dbus_array_seq_add_dup (EggDBusArraySeq *array_seq, gconstpointer value); -/* C convenience functions for fixed-size arrays */ - -gpointer egg_dbus_array_seq_steal_data (EggDBusArraySeq *array_seq) G_GNUC_WARN_UNUSED_RESULT; +gint egg_dbus_array_seq_index_of (EggDBusArraySeq *array_seq, + gconstpointer value); +gboolean egg_dbus_array_seq_contains (EggDBusArraySeq *array_seq, + gconstpointer value); +gboolean egg_dbus_array_seq_remove (EggDBusArraySeq *array_seq, + gconstpointer value); /* C convenience functions */ +gpointer egg_dbus_array_seq_steal_data (EggDBusArraySeq *array_seq) G_GNUC_WARN_UNUSED_RESULT; + gboolean egg_dbus_array_seq_add_byte (EggDBusArraySeq *array_seq, guchar value); gboolean egg_dbus_array_seq_add_int16 (EggDBusArraySeq *array_seq, @@ -322,34 +331,6 @@ EggDBusArraySeq *egg_dbus_array_seq_new_for_double_valist (guint gdouble first_value, va_list va_args) G_GNUC_WARN_UNUSED_RESULT; - -/* TODO: - * - * - if we want to implement contains() (and index_of() and remove()) we can either - * - require items to implement a new interface EggDBusEquals - * - hmm, unsure this will work for boxed types... - * - carry around a GEqual (need to be settable/gettable, we want constructors to take it too) - * - should have a flag CAN_COMPARE_EQUALITY - * - * - It's fine for an an ArraySeq instance not to have CAN_COMPARE_EQUALITY, - * it just means it's a programmer error and we'll issue a run-time warning - * (similar to the unchecked UnsupportedOperationException mentioned here: - * http://java.sun.com/j2se/1.5.0/docs/guide/collections/designfaq.html#2) - * - * - Ditto is it a progamming error if the user tries to modify an IMMUTABLE - * or READ_ONLY array_seq; again, same argument; we'll just issue a run-time - * warning - * - */ - -/* TODO: algorithms? - * - * - foreach - * - sort (requires equality tests) - * - ... - * - others? - */ - G_END_DECLS #endif /* __ EGG_DBUS_ARRAY_SEQ_H */ diff --git a/src/tests/testclient.c b/src/tests/testclient.c index b0a7861..5c8e471 100644 --- a/src/tests/testclient.c +++ b/src/tests/testclient.c @@ -3558,12 +3558,18 @@ test_egg_dbus_array_seq (void) EggDBusArraySeq *a; const gchar *some_strings[6] = {"zero", "one", "two", "three", "four", NULL}; gchar **string_array; + gint some_ints[8] = {0, 1, 2, 3, 2, 4, 2, 5}; + gint int_2 = 2; + gint int_3 = 3; + GFile *file_2; + GFile *file_3; /* * First, check that all EggDBusArraySeq operations work */ a = egg_dbus_array_seq_new_full (G_TYPE_STRING, 0, + NULL, 5, some_strings); g_assert_cmpuint (egg_dbus_array_seq_get_element_type (a), ==, G_TYPE_STRING); @@ -3648,6 +3654,7 @@ test_egg_dbus_array_seq (void) */ a = egg_dbus_array_seq_new_full (G_TYPE_STRING, EGG_DBUS_ARRAY_SEQ_FLAGS_STATIC, + NULL, 5, some_strings); g_assert_cmpuint (egg_dbus_array_seq_get_element_type (a), ==, G_TYPE_STRING); @@ -3822,6 +3829,8 @@ test_egg_dbus_array_seq (void) g_strfreev (string_array); g_object_unref (a); + /* -------------------------------------------------------------------------------- */ + /* check that types deriving from boxed types work */ a = egg_dbus_array_seq_new (EGG_DBUS_TYPE_OBJECT_PATH_ARRAY); egg_dbus_array_seq_add (a, g_strsplit ("/a/test/path", "/", 0)); @@ -3838,6 +3847,7 @@ test_egg_dbus_array_seq (void) g_assert_cmpstr (a->data.v_strv[1][2], ==, "path"); g_object_unref (a); + /* -------------------------------------------------------------------------------- */ /* Arrays containing GObject derived instances are very similar to arrays containg boxed * instances... so we don't need to test them very carefully since we've already tested @@ -3862,6 +3872,7 @@ test_egg_dbus_array_seq (void) g_test_trap_assert_stderr ("*Cannot insert an element of type GLocalFile into a EggDBusArraySeq<TestSubject>*"); g_object_unref (a); + /* -------------------------------------------------------------------------------- */ /* Check that an array of a type deriving from GInterface works (as long as the * instances implenting the type are GObject derived). Since GFile is actually an interface @@ -3875,6 +3886,100 @@ test_egg_dbus_array_seq (void) g_assert_cmpuint (egg_dbus_array_seq_size (a), ==, 3); g_object_unref (a); + /* -------------------------------------------------------------------------------- */ + + /* check that equal_func is properly inferred and works */ + a = egg_dbus_array_seq_new (G_TYPE_STRING); + g_assert (egg_dbus_array_seq_get_flags (a) & EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC); + egg_dbus_array_seq_add_dup (a, "zero"); + egg_dbus_array_seq_add_dup (a, "one"); + egg_dbus_array_seq_add_dup (a, "two"); + egg_dbus_array_seq_add_dup (a, "three"); + egg_dbus_array_seq_add_dup (a, "two"); + egg_dbus_array_seq_add_dup (a, "four"); + egg_dbus_array_seq_add_dup (a, "two"); + egg_dbus_array_seq_add_dup (a, "five"); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, "three"), ==, 3); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, "two"), ==, 2); + g_assert (egg_dbus_array_seq_remove (a, "two")); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, "two"), ==, 3); + g_assert (egg_dbus_array_seq_remove (a, "two")); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, "two"), ==, 4); + g_assert (egg_dbus_array_seq_remove (a, "two")); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, "two"), ==, -1); + g_assert (!egg_dbus_array_seq_remove (a, "two")); + g_object_unref (a); + + /* -------------------------------------------------------------------------------- */ + + /* try for a fixed-size type as well (we don't provide C convenience for these (yet?)) */ + a = egg_dbus_array_seq_new_full (G_TYPE_INT, + 0, + NULL, + 8, + some_ints); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 0), ==, 0); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 1), ==, 1); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 2), ==, 2); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 3), ==, 3); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 4), ==, 2); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 5), ==, 4); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 6), ==, 2); + g_assert_cmpint (egg_dbus_array_seq_get_int (a, 7), ==, 5); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, &int_3), ==, 3); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, &int_2), ==, 2); + g_assert (egg_dbus_array_seq_remove (a, &int_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, &int_2), ==, 3); + g_assert (egg_dbus_array_seq_remove (a, &int_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, &int_2), ==, 4); + g_assert (egg_dbus_array_seq_remove (a, &int_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, &int_2), ==, -1); + g_assert (!egg_dbus_array_seq_remove (a, &int_2)); + g_object_unref (a); + + /* -------------------------------------------------------------------------------- */ + + /* check there is no equal_func by default for GObject types */ + a = egg_dbus_array_seq_new (G_TYPE_FILE); + g_assert (! (egg_dbus_array_seq_get_flags (a) & EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC)); + egg_dbus_array_seq_add (a, g_file_new_for_path ("0.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("1.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("2.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("3.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("2.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("4.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("2.txt")); + egg_dbus_array_seq_add (a, g_file_new_for_path ("5.txt")); + /* we only check that index_of don't work (contains() and remove() are trivial when we + * have index_of() and remove_at() already) + */ + if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR)) + { + gint index; + index = egg_dbus_array_seq_index_of (a, g_file_new_for_path ("/somewhere/file.txt")); + } + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*no equal_func set for EggDBusArraySeq<GFile>*"); + /* check we can set an equal_func post construction and that the equal func works*/ + egg_dbus_array_seq_set_equal_func (a, (GEqualFunc) g_file_equal); + g_assert (egg_dbus_array_seq_get_flags (a) & EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC); + file_2 = g_file_new_for_path ("2.txt"); + file_3 = g_file_new_for_path ("3.txt"); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, file_3), ==, 3); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, file_2), ==, 2); + g_assert (egg_dbus_array_seq_remove (a, file_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, file_2), ==, 3); + g_assert (egg_dbus_array_seq_remove (a, file_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, file_2), ==, 4); + g_assert (egg_dbus_array_seq_remove (a, file_2)); + g_assert_cmpint (egg_dbus_array_seq_index_of (a, file_2), ==, -1); + g_assert (!egg_dbus_array_seq_remove (a, file_2)); + g_object_unref (file_2); + g_object_unref (file_3); + egg_dbus_array_seq_set_equal_func (a, NULL); + g_assert (! (egg_dbus_array_seq_get_flags (a) & EGG_DBUS_ARRAY_SEQ_FLAGS_HAVE_EQUAL_FUNC)); + g_object_unref (a); + } /* ---------------------------------------------------------------------------------------------------- */ @@ -3894,6 +3999,7 @@ main (int argc, char *argv[]) GPid server_pid; g_type_init (); + //g_test_init (&argc, &argv, NULL); /* TODO: launch our own session bus */ |