diff --git a/lib/wp/iterator.c b/lib/wp/iterator.c index c12e0a32..21d73ca3 100644 --- a/lib/wp/iterator.c +++ b/lib/wp/iterator.c @@ -189,3 +189,108 @@ wp_iterator_foreach (WpIterator *self, WpIteratorForeachFunc func, return wp_iterator_default_foreach (self, func, data); } + +struct ptr_array_iterator_data +{ + GPtrArray *array; + GType item_type; + guint index; + void (*set_value) (GValue *, gpointer); +}; + +static void +ptr_array_iterator_reset (WpIterator *it) +{ + struct ptr_array_iterator_data *it_data = wp_iterator_get_user_data (it); + it_data->index = 0; +} + +static gboolean +ptr_array_iterator_next (WpIterator *it, GValue *item) +{ + struct ptr_array_iterator_data *it_data = wp_iterator_get_user_data (it); + + if (it_data->index < it_data->array->len) { + gpointer ptr = g_ptr_array_index (it_data->array, it_data->index++); + g_value_init (item, it_data->item_type); + it_data->set_value (item, ptr); + return TRUE; + } + return FALSE; +} + +static gboolean +ptr_array_iterator_fold (WpIterator *it, WpIteratorFoldFunc func, GValue *ret, + gpointer data) +{ + struct ptr_array_iterator_data *it_data = wp_iterator_get_user_data (it); + gpointer *ptr, *base; + guint len; + + ptr = base = it_data->array->pdata; + len = it_data->array->len; + + while ((ptr - base) < len) { + g_auto (GValue) item = G_VALUE_INIT; + g_value_init (&item, it_data->item_type); + it_data->set_value (&item, *ptr); + if (!func (&item, ret, data)) + return FALSE; + ptr++; + } + return TRUE; +} + +static void +ptr_array_iterator_finalize (WpIterator *it) +{ + struct ptr_array_iterator_data *it_data = wp_iterator_get_user_data (it); + g_ptr_array_unref (it_data->array); +} + +static const WpIteratorMethods ptr_array_iterator_methods = { + .reset = ptr_array_iterator_reset, + .next = ptr_array_iterator_next, + .fold = ptr_array_iterator_fold, + .finalize = ptr_array_iterator_finalize, +}; + +/** + * wp_iterator_new_ptr_array: + * @items: (transfer full): the items to iterate over + * @item_type: the type of each item + * + * Returns: (transfer full): a new iterator that iterates over @items + */ +WpIterator * +wp_iterator_new_ptr_array (GPtrArray * items, GType item_type) +{ + g_autoptr (WpIterator) it = NULL; + struct ptr_array_iterator_data *it_data; + + g_return_val_if_fail (items != NULL, NULL); + + it = wp_iterator_new (&ptr_array_iterator_methods, + sizeof (struct ptr_array_iterator_data)); + it_data = wp_iterator_get_user_data (it); + it_data->array = items; + it_data->item_type = item_type; + it_data->index = 0; + + if (g_type_is_a (item_type, G_TYPE_POINTER)) + it_data->set_value = g_value_set_pointer; + else if (g_type_is_a (item_type, G_TYPE_BOXED)) + it_data->set_value = (void (*) (GValue *, gpointer)) g_value_set_boxed; + else if (g_type_is_a (item_type, G_TYPE_OBJECT)) + it_data->set_value = g_value_set_object; + else if (g_type_is_a (item_type, G_TYPE_INTERFACE)) + it_data->set_value = g_value_set_object; + else if (g_type_is_a (item_type, G_TYPE_VARIANT)) + it_data->set_value = (void (*) (GValue *, gpointer)) g_value_set_variant; + else if (g_type_is_a (item_type, G_TYPE_STRING)) + it_data->set_value = (void (*) (GValue *, gpointer)) g_value_set_string; + else + g_return_val_if_reached (NULL); + + return g_steal_pointer (&it); +} diff --git a/lib/wp/iterator.h b/lib/wp/iterator.h index ddfc61d6..613ae2f7 100644 --- a/lib/wp/iterator.h +++ b/lib/wp/iterator.h @@ -47,12 +47,16 @@ GType wp_iterator_get_type (void); typedef struct _WpIterator WpIterator; +/* ref count */ + WP_API WpIterator *wp_iterator_ref (WpIterator *self); WP_API void wp_iterator_unref (WpIterator *self); +/* iteration api */ + WP_API void wp_iterator_reset (WpIterator *self); @@ -67,6 +71,11 @@ WP_API gboolean wp_iterator_foreach (WpIterator *self, WpIteratorForeachFunc func, gpointer data); +/* constructors */ + +WP_API +WpIterator * wp_iterator_new_ptr_array (GPtrArray * items, GType item_type); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (WpIterator, wp_iterator_unref) G_END_DECLS