summaryrefslogtreecommitdiff
path: root/src/syncevo/GLibSupport.h
blob: 36a431f5a05ab999aec75182ccc9fd72d18fa231 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
/*
 * Copyright (C) 2011 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef INCL_GLIB_SUPPORT
# define INCL_GLIB_SUPPORT

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <syncevo/util.h>

#ifdef HAVE_GLIB
# include <glib-object.h>
# include <gio/gio.h>
#else
typedef void *GMainLoop;
#endif

#include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/utility/value_init.hpp>

#include <iterator>
#include <memory>

#include <syncevo/declarations.h>
SE_BEGIN_CXX

enum {
    GLIB_SELECT_NONE = 0,
    GLIB_SELECT_READ = 1,
    GLIB_SELECT_WRITE = 2
};

enum GLibSelectResult {
    GLIB_SELECT_TIMEOUT,      /**< returned because not ready after given amount of time */
    GLIB_SELECT_READY,        /**< fd is ready */
    GLIB_SELECT_QUIT          /**< something else caused the loop to quit, return to caller immediately */
};

/**
 * Waits for one particular file descriptor to become ready for reading
 * and/or writing. Keeps the given loop running while waiting.
 *
 * @param  loop       loop to keep running; must not be NULL
 * @param  fd         file descriptor to watch, -1 for none
 * @param  direction  read, write, both, or none (then fd is ignored)
 * @param  timeout    timeout in seconds + nanoseconds from now, NULL for no timeout, empty value for immediate return
 * @return see GLibSelectResult
 */
GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *timeout);

#ifdef HAVE_GLIB

// Signal callback. Specializations will handle varying number of parameters.
template<class S> struct GObjectSignalHandler {
    // static void handler();
    // No specialization defined for the requested function prototype.
};

template<> struct GObjectSignalHandler<void ()> {
    static void handler(gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void ()> *>(data))();
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1> struct GObjectSignalHandler<void (A1)> {
    static void handler(A1 a1, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1)> *>(data))(a1);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2> struct GObjectSignalHandler<void (A1, A2)> {
    static void handler(A1 a1, A2 a2, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2)> *>(data))(a1, a2);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3> struct GObjectSignalHandler<void (A1, A2, A3)> {
    static void handler(A1 a1, A2 a2, A3 a3, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3)> *>(data))(a1, a2, a3);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4> struct GObjectSignalHandler<void (A1, A2, A3, A4)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4)> *>(data))(a1, a2, a3, a4);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4, class A5> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5)> *>(data))(a1, a2, a3, a4, a5);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4, class A5, class A6> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6)> *>(data))(a1, a2, a3, a4, a5, a6);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7)> *>(data))(a1, a2, a3, a4, a5, a6, a7);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
    static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, gpointer data) throw () {
        try {
            (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

enum RefOwnership
{
    TRANSFER_REF = false, /**<
                           * Create new smart pointer which steals an existing reference without
                           * increasing the reference count of the object.
                           */
    ADD_REF = true        /**<
                           * Create new smart pointer which increases the reference count when
                           * storing the pointer to the object.
                           */
};


template<class C> class TrackGObject : public boost::intrusive_ptr<C> {
    typedef boost::intrusive_ptr<C> Base_t;

    // Frees the instance of boost::function which was allocated
    // by connectSignal.
    template<class S> static void signalDestroy(gpointer data, GClosure *closure) throw () {
        try {
            delete reinterpret_cast< boost::function<void ()> *>(data);
        } catch (...) {
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }

 public:
    TrackGObject(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
    TrackGObject() {}
    TrackGObject(const TrackGObject &other) : Base_t(other) {}
    operator C * () const { return Base_t::get(); }
    operator bool () const { return Base_t::get() != NULL; }
    C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }

    static  TrackGObject steal(C *ptr) { return TrackGObject(ptr, TRANSFER_REF); }

    template<class S> guint connectSignal(const char *signal,
                                          const boost::function<S> &callback) {
        return g_signal_connect_data(Base_t::get(), signal,
                                     G_CALLBACK(&GObjectSignalHandler<S>::handler),
                                     new boost::function<S>(callback),
                                     &signalDestroy<S>,
                                     GConnectFlags(0));
    }
    void disconnectSignal(guint handlerID) {
        g_signal_handler_disconnect(static_cast<gpointer>(Base_t::get()),
                                    handlerID);
    }
};

template<class C> class StealGObject : public TrackGObject<C> {
 public:
    StealGObject(C *ptr) : TrackGObject<C>(ptr, TRANSFER_REF) {}
    StealGObject() {}
    StealGObject(const StealGObject &other) : TrackGObject<C>(other) {}
};

template<class C> class TrackGLib : public boost::intrusive_ptr<C> {
    typedef boost::intrusive_ptr<C> Base_t;

 public:
 TrackGLib(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
    TrackGLib() {}
    TrackGLib(const TrackGLib &other) : Base_t(other) {}
    operator C * () const { return Base_t::get(); }
    operator bool () const { return Base_t::get() != NULL; }
    C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }

    static  TrackGLib steal(C *ptr) { return TrackGLib(ptr, TRANSFER_REF); }
};

template<class C> class StealGLib : public TrackGLib<C> {
 public:
    StealGLib(C *ptr) : TrackGLib<C>(ptr, TRANSFER_REF) {}
    StealGLib() {}
    StealGLib(const StealGLib &other) : TrackGLib<C>(other) {}
};

/**
 * Defines a shared pointer for a GObject-based type, with intrusive
 * reference counting. Use *outside* of SyncEvolution namespace
 * (i.e. outside of SE_BEGIN/END_CXX. This is necessary because some
 * functions must be put into the boost namespace. The type itself is
 * *inside* the SyncEvolution namespace.
 *
 * connectSignal() connects a GObject signal to a boost::function with
 * the function signature S. Returns the handler ID, which can be
 * passed to g_signal_handler_disconnect() to remove the connection.
 *
 * Example:
 * SE_GOBJECT_TYPE(GFile)
 * SE_GOBJECT_TYPE(GObject)
 * SE_BEGIN_CXX
 * {
 *   // reference normally increased during construction,
 *   // steal() avoids that
 *   GFileCXX filecxx = GFileCXX::steal(g_file_new_for_path("foo"));
 *   GFile *filec = filecxx.get(); // does not increase reference count
 *   // file freed here as filecxx gets destroyed
 * }
 *
 * GObjectCXX object(...);
 * // Define signature explicitly because it cannot be guessed from
 * // boost::bind() result.
 * object.connectSignal<void (GObject *gobject, GParamSpec *pspec)>("notify",
 *                                                                  boost::bind(...));
 * // Signature is taken from boost::function parameter.
 * guint handlerID =
 *     object.connectSignal("notify",
 *                          boost::function<void (GObject *, GParamSpec *)>(boost::bind(...)));
 * object.disconnectSignal(handlerID);
 * SE_END_CXX
 */
#define SE_GOBJECT_TYPE(_x) \
    void inline intrusive_ptr_add_ref(_x *ptr) { g_object_ref(ptr); } \
    void inline intrusive_ptr_release(_x *ptr) { g_object_unref(ptr); } \
    SE_BEGIN_CXX \
    typedef TrackGObject<_x> _x ## CXX; \
    typedef StealGObject<_x> _x ## StealCXX; \
    SE_END_CXX \

/**
 * Defines a CXX smart pointer similar to SE_GOBJECT_TYPE,
 * but for types which have their own _ref and _unref
 * calls.
 *
 * Example:
 * SE_GLIB_TYPE(GMainLoop, g_main_loop)
 */
#define SE_GLIB_TYPE(_x, _func_prefix) \
    void inline intrusive_ptr_add_ref(_x *ptr) { _func_prefix ## _ref(ptr); } \
    void inline intrusive_ptr_release(_x *ptr) { _func_prefix ## _unref(ptr); } \
    SE_BEGIN_CXX \
    typedef TrackGLib<_x> _x ## CXX; \
    typedef StealGLib<_x> _x ## StealCXX; \
    SE_END_CXX

SE_END_CXX

SE_GOBJECT_TYPE(GFile)
SE_GOBJECT_TYPE(GFileMonitor)
SE_GLIB_TYPE(GMainLoop, g_main_loop)
SE_GLIB_TYPE(GAsyncQueue, g_async_queue)

SE_BEGIN_CXX

/**
 * Wrapper around g_file_monitor_file().
 * Not copyable because monitor is tied to specific callback
 * via memory address.
 */
class GLibNotify : public boost::noncopyable
{
 public:
    typedef boost::function<void (GFile *, GFile *, GFileMonitorEvent)> callback_t;

    GLibNotify(const char *file, 
               const callback_t &callback);
 private:
    GFileMonitorCXX m_monitor;
    callback_t m_callback;
};

/**
 * Wraps GError. Where a GError** is expected, simply pass
 * a GErrorCXX instance.
 */
struct GErrorCXX {
    GError *m_gerror;

    /** empty error, NULL pointer */
    GErrorCXX() : m_gerror(NULL) {}

    /** copies error content */
    GErrorCXX(const GErrorCXX &other) : m_gerror(g_error_copy(other.m_gerror)) {}
    GErrorCXX &operator =(const GErrorCXX &other) {
        if (m_gerror != other.m_gerror) {
            if (m_gerror) {
                g_clear_error(&m_gerror);
            }
            if (other.m_gerror) {
                m_gerror = g_error_copy(other.m_gerror);
            }
        }
        return *this;
    }
    GErrorCXX &operator =(const GError* err) {
        if (err != m_gerror) {
            if (m_gerror) {
                g_clear_error(&m_gerror);
            }
            if (err) {
                m_gerror = g_error_copy(err);
            }
        }
        return *this;
    }

    /** For convenient access to GError members (message, domain, ...) */
    const GError * operator-> () const { return m_gerror; }

    /**
     * For passing to C functions. They must not free the GError,
     * because GErrorCXX retains ownership.
     */
    operator const GError * () const { return m_gerror; }

    /** error description, with fallback if not set (not expected, so not localized) */
    operator const char * () { return m_gerror ? m_gerror->message : "<<no error>>"; }

    /** clear error */
    ~GErrorCXX() { g_clear_error(&m_gerror); }

    /** clear error if any is set */
    void clear() { g_clear_error(&m_gerror); }

    /** transfer ownership of error back to caller */
    GError *release() { GError *gerror = m_gerror; m_gerror = NULL; return gerror; }

    /** checks whether the current error is the one passed as parameters */
    bool matches(GQuark domain, gint code) { return g_error_matches(m_gerror, domain, code); }

    /**
     * Use this when passing GErrorCXX instance to C functions which need to set it.
     * Make sure the pointer isn't set yet (new GErrorCXX instance, reset if
     * an error was encountered before) or the GNOME functions will complain
     * when overwriting the existing error.
     */
    operator GError ** () { return &m_gerror; }

    /** true if error set */
    operator bool () { return m_gerror != NULL; }

    /**
     * always throws an exception, including information from GError if available:
     * <action>: <error message>|failure
     */
    void throwError(const std::string &action);
    static void throwError(const std::string &action, const GError *err);
};

template<class T> void NoopDestructor(T *) {}
template<class T> void GObjectDestructor(T *ptr) { g_object_unref(ptr); }
template<class T> void GFreeDestructor(T *ptr) { g_free(static_cast<void *>(ptr)); }

/**
 * Copies strings from a collection into a newly allocated, NULL
 * terminated array. Copying the strings is optional. Suggested
 * usage is:
 *
 * C collection;
 * collection.push_back(...);
 * boost::scoped_array<char *> array(AllocStringArray(collection));
 *
 */
template<typename T> char **AllocStringArray(const T &strings,
                                             const char **(*allocArray)(size_t) = NULL,
                                             void (*freeArray)(const char **) = NULL,
                                             const char *(*copyString)(const char *) = NULL,
                                             const void (*freeString)(char *) = NULL)
{
    size_t arraySize = strings.size() + 1;
    const char **array = NULL;
    array = allocArray ? allocArray(arraySize) : new const char *[arraySize];
    if (!array) {
        throw std::bad_alloc();
    }
    try {
        memset(array, 0, sizeof(*array) * arraySize);
        size_t i = 0;
        BOOST_FOREACH(const std::string &str, strings) {
            array[i] = copyString ? copyString(str.c_str()) : str.c_str();
            if (!array[i]) {
                throw std::bad_alloc();
            }
            i++;
        }
    } catch (...) {
        if (freeString) {
            for (const char **ptr = array;
                 *ptr;
                 ptr++) {
                freeString(const_cast<char *>(*ptr));
            }
        }
        if (freeArray) {
            freeArray(array);
        }
        throw;
    }
    return const_cast<char **>(array);
}


/**
 * Wraps a G[S]List of pointers to a specific type.
 * Can be used with boost::FOREACH and provides forward iterators
 * (two-way iterators and reverse iterators also possible, but not implemented).
 * Frees the list and optionally (not turned on by default) also frees
 * the data contained in it, using the provided destructor class.
 * Use GObjectDestructor for GObject instances.
 *
 * @param T    the type of the instances pointed to inside the list
 * @param L    GList or GSList
 * @param D    destructor function freeing a T instance
 */
template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX : boost::noncopyable {
    L *m_list;

    static void listFree(GSList *l) { g_slist_free(l); }
    static void listFree(GList *l) { g_list_free(l); }

    static GSList *listPrepend(GSList *list, T *entry) { return g_slist_prepend(list, (gpointer)entry); }
    static GList *listPrepend(GList *list, T *entry) { return g_list_prepend(list, (gpointer)entry); }

    static GSList *listAppend(GSList *list, T *entry) { return g_slist_append(list, (gpointer)entry); }
    static GList *listAppend(GList *list, T *entry) { return g_list_append(list, (gpointer)entry); }

 public:
    typedef T * value_type;

    /** by default initialize an empty list; if parameter is not NULL,
        owership is transferred to the new instance of GListCXX */
    GListCXX(L *list = NULL) : m_list(list) {}

    /** free list */
    ~GListCXX() { clear(); }

    /** free old content, take owership of new one */
    void reset(L *list = NULL) {
        clear();
        m_list = list;
    }

    bool empty() { return m_list == NULL; }

    /** clear error if any is set */
    void clear() {
#if 1
        BOOST_FOREACH(T *entry, *this) {
            D(entry);
        }
#else
        for (iterator it = begin();
             it != end();
             ++it) {
            D(*it);
        }
#endif
        listFree(m_list);
        m_list = NULL;
    }

    /**
     * Use this when passing GListCXX instance to C functions which need to set it.
     * Make sure the pointer isn't set yet (new GListCXX instance or cleared).
     */
    operator L ** () { return &m_list; }

    /**
     * Cast to plain G[S]List, for use in functions which do not modify the list.
     */
    operator L * () { return m_list; }

    class iterator : public std::iterator<std::forward_iterator_tag, T *> {
        L *m_entry;
    public:
        iterator(L *list) : m_entry(list) {}
        iterator(const iterator &other) : m_entry(other.m_entry) {}
        /**
         * boost::foreach needs a reference as return code here,
         * which forces us to do type casting on the address of the void * pointer,
         * then dereference the pointer. The reason is that typecasting the
         * pointer value directly yields an rvalue, which can't be used to initialize
         * the reference return value.
         */
        T * &operator -> () const { return *getEntryPtr(); }
        T * &operator * () const { return *getEntryPtr(); }
        iterator & operator ++ () { m_entry = m_entry->next; return *this; }
        iterator operator ++ (int) { return iterator(m_entry->next); }
        bool operator == (const iterator &other) { return m_entry == other.m_entry; }
        bool operator != (const iterator &other) { return m_entry != other.m_entry; }

    private:
        /**
         * Used above, necessary to hide the fact that we do type
         * casting tricks. Otherwise the compiler will complain about
         * *(T **)&m_entry->data with "dereferencing type-punned
         * pointer will break strict-aliasing rules".
         *
         * That warning is about breaking assumptions that the compiler
         * uses for optimizations. The hope is that those optimzations
         * aren't done here, and/or are disabled by using a function.
         */
        T** getEntryPtr() const { return (T **)&m_entry->data; }
    };
    iterator begin() { return iterator(m_list); }
    iterator end() { return iterator(NULL); }

    class const_iterator : public std::iterator<std::forward_iterator_tag, T *> {
        L *m_entry;
        T *m_value;

    public:
        const_iterator(L *list) : m_entry(list) {}
        const_iterator(const const_iterator &other) : m_entry(other.m_entry) {}
        T * &operator -> () const { return *getEntryPtr(); }
        T * &operator * () const { return *getEntryPtr(); }
        const_iterator & operator ++ () { m_entry = m_entry->next; return *this; }
        const_iterator operator ++ (int) { return iterator(m_entry->next); }
        bool operator == (const const_iterator &other) { return m_entry == other.m_entry; }
        bool operator != (const const_iterator &other) { return m_entry != other.m_entry; }

    private:
        T** getEntryPtr() const { return (T **)&m_entry->data; }
    };

    const_iterator begin() const { return const_iterator(m_list); }
    const_iterator end() const { return const_iterator(NULL); }

    void push_back(T *entry) { m_list = listAppend(m_list, entry); }
    void push_front(T *entry) { m_list = listPrepend(m_list, entry); }
};

/** use this for a list which owns the strings it points to */
typedef GListCXX<char, GList, GFreeDestructor<char> > GStringListFreeCXX;
/** use this for a list which does not own the strings it points to */
typedef GListCXX<char, GList> GStringListNoFreeCXX;

/**
 * Wraps a C gchar array and takes care of freeing the memory.
 */
class PlainGStr : public boost::shared_ptr<gchar>
{
    public:
        PlainGStr() {}
        PlainGStr(gchar *str) : boost::shared_ptr<char>(str, g_free) {}
        PlainGStr(const PlainGStr &other) : boost::shared_ptr<gchar>(other) {}    
        operator const gchar *() const { return &**this; }
        const gchar *c_str() const { return &**this; }
};

// empty template, need specialization based on parameter and return types
template <class T, class F, F *finish, class A1, class A2, class A3, class A4, class A5> struct GAsyncReady5 {};
template <class T, class F, F *finish, class A1, class A2, class A3, class A4> struct GAsyncReady4 {};
template <class T, class F, F *finish, class A1, class A2, class A3> struct GAsyncReady3 {};
template <class T, class F, F *finish, class A1, class A2> struct GAsyncReady2 {};
template <class T, class F, F *finish, class A1> struct GAsyncReady1 {};

// empty template, need specializations based on arity
template<class F, F *finish, int arity> struct GAsyncReadyCXX {};

// five parameters of finish function
template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 5> :
    public GAsyncReady5<typename boost::function_traits<F>::result_type,
                        F, finish,
                        typename boost::function_traits<F>::arg1_type,
                        typename boost::function_traits<F>::arg2_type,
                        typename boost::function_traits<F>::arg3_type,
                        typename boost::function_traits<F>::arg4_type,
                        typename boost::function_traits<F>::arg5_type>
{
};

// four parameters
template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 4> :
    public GAsyncReady4<typename boost::function_traits<F>::result_type,
                        F, finish,
                        typename boost::function_traits<F>::arg1_type,
                        typename boost::function_traits<F>::arg2_type,
                        typename boost::function_traits<F>::arg3_type,
                        typename boost::function_traits<F>::arg4_type>
{
};

// three parameters
template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 3> :
    public GAsyncReady3<typename boost::function_traits<F>::result_type,
                        F, finish,
                        typename boost::function_traits<F>::arg1_type,
                        typename boost::function_traits<F>::arg2_type,
                        typename boost::function_traits<F>::arg3_type>
{
};

// two parameters
template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 2> :
    public GAsyncReady2<typename boost::function_traits<F>::result_type,
                        F, finish,
                        typename boost::function_traits<F>::arg1_type,
                        typename boost::function_traits<F>::arg2_type>
{
};

// one parameter
template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 1> :
    public GAsyncReady1<typename boost::function_traits<F>::result_type,
                        F, finish,
                        typename boost::function_traits<F>::arg1_type>
{
};


// For finish functions with return parameters the assumption is that
// they have a non-void return value. Otherwise there would be no need
// for the return parameters.
//
// result = GObject, GAsyncResult, A3, A4, A5
template<class T, class F, F *finish, class A1, class A3, class A4, class A5> struct GAsyncReady5<T, F, finish, A1, GAsyncResult *, A3, A4, A5>
{
    typedef typename boost::remove_pointer<A3>::type A3_t;
    typedef typename boost::remove_pointer<A4>::type A4_t;
    typedef typename boost::remove_pointer<A5>::type A5_t;
    typedef boost::function<void (T, A3_t, A4_t, A5_t)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            A3_t retval1 = boost::value_initialized<A3_t>();
            A4_t retval2 = boost::value_initialized<A4_t>();
            A5_t retval3 = boost::value_initialized<A5_t>();
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result, &retval1, &retval2, &retval3);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, retval1, retval2, retval3);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// result = GObject, GAsyncResult, A3, A4, GError
template<class T, class F, F *finish, class A1, class A3, class A4> struct GAsyncReady5<T, F, finish, A1, GAsyncResult *, A3, A4, GError **>
{
    typedef typename boost::remove_pointer<A3>::type A3_t;
    typedef typename boost::remove_pointer<A4>::type A4_t;
    typedef boost::function<void (T, A3_t, A4_t, const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            A3_t retval1 = boost::value_initialized<A3_t>();
            A4_t retval2 = boost::value_initialized<A4_t>();
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result, &retval1, &retval2, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, retval1, retval2, gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// result = GObject, GAsyncResult, A3, A4
template<class T, class F, F *finish, class A1, class A3, class A4> struct GAsyncReady4<T, F, finish, A1, GAsyncResult *, A3, A4>
{
    typedef typename boost::remove_pointer<A3>::type A3_t;
    typedef typename boost::remove_pointer<A4>::type A4_t;
    typedef boost::function<void (T, A3_t, A4_t)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            A3_t retval1 = boost::value_initialized<A3_t>();
            A4_t retval2 = boost::value_initialized<A4_t>();
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result, &retval1, &retval2);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, retval1, retval2);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// result = GObject, GAsyncResult, A3, GError
template<class T, class F, F *finish, class A1, class A3> struct GAsyncReady4<T, F, finish, A1, GAsyncResult *, A3, GError **>
{
    typedef typename boost::remove_pointer<A3>::type A3_t;
    typedef boost::function<void (T, A3_t, const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            A3_t retval = boost::value_initialized<A3_t>();
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result, &retval, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, retval, gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// res = GObject, GAsyncResult, GError
template <class T, class F, F *finish, class A1> struct GAsyncReady3<T, F, finish, A1, GAsyncResult *, GError **>{
    typedef boost::function<void (T, const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// void = GObject, GAsyncResult, GError
template<class F, F *finish, class A1> struct GAsyncReady3<void, F, finish, A1, GAsyncResult *, GError **>
{
    typedef boost::function<void (const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            finish(reinterpret_cast<A1>(sourceObject),
                   result, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// result = GObject, GAsyncResult
template<class T, class F, F *finish, class A1> struct GAsyncReady2<T, F, finish, A1, GAsyncResult *>
{
    typedef boost::function<void (T)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            T t = finish(reinterpret_cast<A1>(sourceObject),
                         result);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// result = GAsyncResult, GError
template<class T, class F, F *finish> struct GAsyncReady2<T, F, finish, GAsyncResult *, GError **> {
 public:
    typedef boost::function<void (T, const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            T t = finish(result, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(t, gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// void  = GObject, GAsyncResult
template<class F, F *finish, class A1> struct GAsyncReady2<void, F, finish, A1, GAsyncResult *>
{
    typedef boost::function<void ()> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            finish(reinterpret_cast<A1>(sourceObject),
                   result);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)();
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

// void = GAsyncResult, GError
template<class F, F *finish> struct GAsyncReady2<void, F, finish, GAsyncResult *, GError **>
{
    typedef boost::function<void (const GError *)> CXXFunctionCB_t;

    static void handleGLibResult(GObject *sourceObject,
                                 GAsyncResult *result,
                                 gpointer userData) throw () {
        try {
            GErrorCXX gerror;
            finish(result, gerror);
            std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
            (*cb)(gerror);
        } catch (...) {
            // called from C, must not let exception escape
            Exception::handle(HANDLE_EXCEPTION_FATAL);
        }
    }
};

/**
 * convenience macro for picking the GAsyncReadyCXX that matches the _prepare call:
 * first switch based on arity of the finish function, then on its type
 */
#define SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare) \
    GAsyncReadyCXX< boost::remove_pointer<typeof(_prepare ## _finish)>::type, \
                    & _prepare ## _finish, \
                    boost::function_traits<boost::remove_pointer<typeof(_prepare ## _finish)>::type>::arity >

/**
 * Macro for asynchronous methods which use a GAsyncReadyCallback to
 * indicate completion. The assumption is that there is a matching
 * _finish function for the function which starts the operation.
 *
 * The boost::function callback will be called exactly once, with the
 * following parameters:
 * - return value of the _finish call, if non-void
 * - all return parameters of the _finish call, in the order
 *   in which they appear there
 * - a GError is passed as "const GError *", with NULL if the
 *   _finish function did not set an error; it does not have to
 *   be freed.
 *
 * Other parameters must be freed if required by the _finish semantic.
 *
 * Use boost::bind() with a boost::weak_ptr as second
 * parameter when the callback belongs to an instance which is
 * not guaranteed to be around when the operation completes.
 *
 * Example:
 *
 *  static void asyncCB(const GError *gerror, const char *func, bool &failed, bool &done) {
 *      done = true;
 *      if (gerror) {
 *          failed = true;
 *          // log gerror->message or store in GErrorCXX
 *      }
 *  }
 *
 *  bool done = false, failed = false;
 *  SYNCEVO_GLIB_CALL_ASYNC(folks_individual_aggregator_prepare,
 *                          boost::bind(asyncCB, _1,
 *                                      "folks_individual_aggregator_prepare",
 *                                      boost::ref(failed), boost::ref(done)),
 *                          aggregator);
 *
 *  // Don't continue unless finished, because the callback will write
 *  // into "done" and possibly "failed".
 *  while (!done) {
 *      g_main_context_iteration(NULL, true);
 *  }
 *
 * @param _prepare     name of the function which starts the operation
 * @param _cb          boost::function with GError pointer and optional result value;
 *                     exceptions are considered fatal
 * @param _args        parameters of _prepare, without the final GAsyncReadyCallback + user_data pair;
 *                     usually at least a GCancellable pointer is part of the arguments
 */
#define SYNCEVO_GLIB_CALL_ASYNC(_prepare, _cb, _args...) \
    _prepare(_args, \
             SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::handleGLibResult, \
             new SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::CXXFunctionCB_t(_cb))

// helper class for finish method with some kind of result other than void
template<class T> class GAsyncReadyDoneCXX
{
 public:
    template<class R> static void storeResult(GErrorCXX &gerrorStorage,
                                              R &resultStorage,
                                              bool &done,
                                              T result,
                                              const GError *gerror) {
        done = true;
        gerrorStorage = gerror;
        resultStorage = result;
    }

    template<class R> static boost::function<void (T, const GError *)> createCB(R &result, GErrorCXX &gerror, bool &done) {
        return boost::bind(storeResult<R>, boost::ref(gerror), boost::ref(result), boost::ref(done), _1, _2);
    }
};

// helper class for finish method with void result
template<> class GAsyncReadyDoneCXX<void>
{
 public:
    static void storeResult(GErrorCXX &gerrorStorage,
                            bool &done,
                            const GError *gerror) {
        done = true;
        gerrorStorage = gerror;
    }

    static boost::function<void (const GError *)> createCB(const int *dummy, GErrorCXX &gerror, bool &done) {
        return boost::bind(storeResult, boost::ref(gerror), boost::ref(done), _1);
    }
};

/**
 * Like SYNCEVO_GLIB_CALL_ASYNC, but blocks until the operation
 * has finished.
 *
 * @param _res         an instance which will hold the result when done, NULL when result is void
 * @param _gerror      a GErrorCXX instance which will hold an error
 *                     pointer afterwards in case of a failure
 */
#define SYNCEVO_GLIB_CALL_SYNC(_res, _gerror, _prepare, _args...) \
    do { \
        bool done = false; \
        SYNCEVO_GLIB_CALL_ASYNC(_prepare, \
                                GAsyncReadyDoneCXX<boost::function<typeof(_prepare ## _finish)>::result_type>::createCB(_res, _gerror, done), \
                                _args); \
        while (!done) { \
            g_main_context_iteration(NULL, true); \
        } \
    } while (false); \

#endif

SE_END_CXX

#endif // INCL_GLIB_SUPPORT