After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 516696 - PATCH: list creation functions
PATCH: list creation functions
Status: RESOLVED OBSOLETE
Product: glib
Classification: Platform
Component: glist
unspecified
Other All
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2008-02-15 16:36 UTC by Jukka-Pekka Iivonen
Modified: 2018-05-24 11:12 UTC
See Also:
GNOME target: ---
GNOME version: Unversioned Enhancement


Attachments
g_list_new and g_slist_new patch (3.34 KB, patch)
2008-08-20 12:00 UTC, Jukka-Pekka Iivonen
none Details | Review

Description Jukka-Pekka Iivonen 2008-02-15 16:36:47 UTC
There is currently not simple list creation functions that would construct a linked list from an argument list. They are very nice, for example, when your function wants to return a list of results like:

...
   return g_list_new(a, b, c, NULL);
}

Here is code for them. Please, include them in glib/glist.c.

Regards,
Jukka-Pekka Iivonen


GList *
g_list_new(gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GList*   list = g_list_append( NULL, p );

        if ( p == NULL )
                return NULL;

        va_start( argp, p );
        while ( NULL != ( s = va_arg( argp, gpointer ) ) ) {
                list = g_list_append( list, s );
        }

        va_end( argp );

        return list;
}

GSList *
g_slist_new(gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GSList*  list = g_slist_append( NULL, p );

        if ( p == NULL )
                return NULL;

        va_start( argp, p );
        while ( NULL != ( s = va_arg( argp, gpointer ) ) ) {
                list = g_slist_append( list, s );
        }

        va_end( argp );

        return list;
}
Comment 1 Jukka-Pekka Iivonen 2008-02-15 17:31:38 UTC
The code without a nasty memory leak is here...


GList *
g_list_new(gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GList*   list;

        if ( p == NULL )
                return NULL;

        list = g_list_append( NULL, p );
        va_start( argp, p );
        while ( NULL != ( s = va_arg( argp, gpointer ) ) ) {
                list = g_list_append( list, s );
        }

        va_end( argp );

        return list;
}

GSList *
g_slist_new(gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GSList*  list;

        if ( p == NULL )
                return NULL;

        list = g_slist_append( NULL, p );
        va_start( argp, p );
        while ( NULL != ( s = va_arg( argp, gpointer ) ) ) {
                list = g_slist_append( list, s );
        }

        va_end( argp );

        return list;
}
Comment 2 Tim Janik 2008-08-18 12:52:57 UTC
Your implementations have O(n^2) complexity, you'll want to use *list_prepend inside the loop and then return *list_reverse (list);
Also adding GCC 0-sentinel attributes could be helpfull here.
Comment 3 Jukka-Pekka Iivonen 2008-08-18 14:02:12 UTC
You are right. For longer input it might matter quite a lot. Here is the fixed version.


GList *
g_list_new (gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GList*   list;

        if ( p == NULL )
                return NULL;

        list = g_list_prepend ( NULL, p );
        va_start ( argp, p );
        while ( NULL != ( s = va_arg ( argp, gpointer ) ) ) {
                list = g_list_prepend ( list, s );
        }

        va_end ( argp );

        return g_list_reverse ( list );
}

GSList *
g_slist_new (gpointer p, ...)
{
        gpointer s;
        va_list  argp;
        GSList*  list;

        if ( p == NULL )
                return NULL;

        list = g_slist_prepend ( NULL, p );
        va_start ( argp, p );
        while ( NULL != ( s = va_arg ( argp, gpointer ) ) ) {
                list = g_slist_prepend ( list, s );
        }

        va_end ( argp );

        return g_slist_reverse ( list );
}
Comment 4 Tim Janik 2008-08-18 14:08:13 UTC
(In reply to comment #3)
> You are right. For longer input it might matter quite a lot. Here is the fixed
> version.
> 
> 
> GList *
> g_list_new (gpointer p, ...)
> {
[...]

Thanks, It'd also be good if you tried to rework the code according to the GLib coding style, e.g. put spaces like "func (arg)", and add documentation comments in the usual manner (mentioning Since: 2.19, etc, there're plenty of examples in glib). Finally, please produce a patch with diff -up against GLib trunk and attach the patch file here, rather than adding raw code inside comments (which tends to bloat the reports after a few iterations).
Comment 5 Jukka-Pekka Iivonen 2008-08-20 12:00:05 UTC
Created attachment 117044 [details] [review]
g_list_new and g_slist_new patch

Here is the patch with gtk-doc comments.
Comment 6 Jukka-Pekka Iivonen 2017-11-04 13:55:31 UTC
Maybe this just adds confusion but if one is not scared of macros or Boost pre-processor library the list creation can be done like this without any overhead:

------

#include <boost/preprocessor/facilities/overload.hpp>


#define G_LIST_NEW(t,...) BOOST_PP_OVERLOAD(_G_LIST_NEW_,__VA_ARGS__)(t,__VA_ARGS__)
#define _G_LIST_NEW_0(t) {t = NULL;}
#define _G_LIST_NEW_1(t,_0) {_G_LIST_NEW_0(t) GList _t = { _0, t }; t = _g_list_alloc (); *t=_t;}
#define _G_LIST_NEW_2(t,_0,_1) {_G_LIST_NEW_1(t,_1) GList _t = { _0, t }; t = _g_list_alloc (); *t=_t;}
#define _G_LIST_NEW_3(t,_0,_1,_2) {_G_LIST_NEW_2(t,_1,_2) GList _t = { _0, t }; t = _g_list_alloc (); *t=_t;}
#define _G_LIST_NEW_4(t,_0,_1,_2,_3) {_G_LIST_NEW_3(t,_1,_2,_3) GList _t = { _0, t }; t = _g_list_alloc (); *t=_t;}
#define _G_LIST_NEW_5(t,_0,_1,_2,_3,_4) {_G_LIST_NEW_4(t,_1,_2,_3,_4) GList _t = { _0, t }; t = _g_list_alloc (); *t=_t;}

...

int main ()
{
    GList* list;
    ...
    G_LIST_NEW(list,a,b,c,d,e);
}

--------

But, of course, internals of GList (or a compatible type with different name) should be public. In real code, the name of temporary variable, _t, could be '_ ## t' in order to avoid conflicts. Also dependes on C99 compliance.
Comment 7 GNOME Infrastructure Team 2018-05-24 11:12:57 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glib/issues/122.