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:

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

MikkelKamstrup/GCollection (last edited 2008-07-18 22:27:49 by MikkelKamstrup)