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;
}