GCollection Draft
A quick draft on some ideas for a generic GIterable and GCollection API for glib. The GCollection draft is still not public.
Premises
- Don't use full GObjects, they are too heavy
- Iterators should be stack allocatable for programmer convenience
- Must have extremely light overhead
- Must be very convenient to work with for language bindings and native C developers
Be able to wrap existing collections such as GList, GSList, GArray, and GPtrArray, without breaking anything
Core Idea
Follow the example of GBoxed with g_*_register_static.
Code
Yes there is code:
Draft patch 1 implementing a GIterable type, with a sample wrapping GStrv as an iterable. The patch was generated against glib rev 5882.
GIterable
Iterables are registered with:
g_iterable_type_register_static (const char *name, GIterNextFunc iter_next, GIterHasNextFunc iter_has_next GIterBreakFunc iter_break);
The signatures of the GIterator*Func friends are
gpointer (*GIterNextFunc) (GIter *iter); gboolean (*GIterHasNextFunc) (GIter *iter); void (*GIterBreakFunc) (GIter *iter);
The GIter is defined as follows
typedef struct { /* Users can fill in arbitrary data here */ gpointer user_data; /* This member is reserved for the GIterable implementor */ gpointer iter_data; } GIter;
GIter API
/** * g_iter_next * @type: %GType of @iterable * @iter: If the 'iter_data' member is %NULL trigger a new iteration using @iter * @iterable: The iterable to iterate over * * Get the next available item from an iterator. If you pass a #GIter with a %NULL 'iter_data' member * a new iteration will be started. * * When the last item has been read with this function @iterable is free to free up any resources * associated with the iteration. Normally this would be the data under the 'iter_data' member * of @iter. * * Returns: %NULL if there are no more items to read */ gpointer g_iter_next (GType type, GIter *iter, gpointer *iterable); /** * g_iter_has_next * @type: %GType of @iterable * @iter: If the 'iter_data' member is %NULL trigger a new iteration using @iter * @iterable: The iterable to iterate over * * Inspect if items can be read with g_iter_next(). * * Returns: If the next call to g_iter_next() will return non-%NULL */ gboolean g_iter_has_next (GType type, GIter *iter, gpointer *iterable); /** * g_iter_break * @type: %GType of @iterable * @iter: An iterator that has been initialized either via g_iter_next() or g_iter_has_next() * @iterable: The iterable to iterate over * * Prematurely terminate an iteration. The @iterable may free all resources related to the iteration. * * Normally the iterable will free all associated data when the iteration is complete and g_iter_has_next() has returned %FALSE. */ gboolean g_iter_break (GType type, GIter *iter, gpointer *iterable);
GIter Examples
Allocate a GIter and set all struct members to NULL. A GIter with all NULL members are considered a clean initialized iterator (in fact it is enough for the 'iter_data' member to be NULL).
Counting the elements in an iterable:
guint count_elements (GType type, gpointer *iterable) { guint count = 0; GIter iter = {0,}; while (g_iter_has_next (type, &iter, iterable)) { g_iter_next (type, &iter, iterable); ++count; } return count; }
Checking if an iterable has more than 10 elements:
gboolean has_more_than_10_elements (GType type, gpointer *iterable) { guint count = 0; GIter iter = {0,}; while (g_iter_has_next (type, &iter, iterable)) { g_iter_next (type, &iter, iterable); ++count; if (count >= 10) { g_iter_break (type, &iter, iterable); return TRUE; } } return FALSE; }