source: branches/profile/ARBDB/gb_cb.h

Last change on this file was 12150, checked in by westram, 10 years ago
  • hardcode minimum for callbacklist-elementsize and use that minimum for OSX
File size: 5.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : gb_cb.h                                           //
4//   Purpose   : database callback types                           //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#ifndef GB_CB_H
12#define GB_CB_H
13
14#ifndef ARBDB_H
15#include <arbdb.h>
16#endif
17#ifndef CB_H
18#include <cb.h>
19#endif
20#ifndef _GLIBCXX_LIST
21#include <list>
22#endif
23
24class TypedDatabaseCallback {
25    DatabaseCallback dbcb;
26    GB_CB_TYPE       type;
27
28    static DatabaseCallback MARKED_DELETED;
29
30public:
31    TypedDatabaseCallback(const DatabaseCallback& cb, GB_CB_TYPE type_)
32        : dbcb(cb),
33          type(type_)
34    {}
35
36    TypedDatabaseCallback with_type_changed_to(GB_CB_TYPE type_) const { return TypedDatabaseCallback(dbcb, type_); }
37
38    GB_CB_TYPE get_type() const { return type; }
39
40    void operator()(GBDATA *gbd, GB_CB_TYPE type_) const {
41        GB_CB_TYPE effType = GB_CB_TYPE(type&type_);
42        gb_assert(effType);
43        gb_assert(!is_marked_for_removal());
44        dbcb(gbd, effType);
45    }
46
47    bool sig_is_equal_to(const TypedDatabaseCallback& other) const { // ignores 'clientdata'
48        return type == other.type && dbcb.same_function_as(other.dbcb);
49    }
50    bool is_equal_to(const TypedDatabaseCallback& other) const {
51        return type == other.type && dbcb == other.dbcb;
52    }
53
54    void mark_for_removal() { dbcb = MARKED_DELETED; }
55    bool is_marked_for_removal() const { return dbcb == MARKED_DELETED; }
56
57    char *get_info() const;
58};
59
60template<typename CB>
61struct CallbackList {
62    typedef CB                                cbtype;
63    typedef typename std::list<cbtype>        listtype; // (when you change container, see also arbdb.cxx@CBLISTNODE_TYPE)
64    typedef typename listtype::iterator       itertype;
65    typedef typename listtype::const_iterator const_itertype;
66
67    listtype callbacks;
68
69#if defined(ASSERTION_USED)
70    bool contains_unremoved_callback(const cbtype& like) const;
71#endif
72
73    bool empty() const { return callbacks.empty(); }
74    void add_unchecked(const CB& cb) { callbacks.push_back(cb); }
75    void add(const CB& newcb) {
76        gb_assert(!contains_unremoved_callback(newcb));
77        add_unchecked(newcb);
78    }
79
80    const CB *get_tail() const { return empty() ? NULL : &callbacks.back(); }
81
82};
83
84struct gb_callback {
85    // @@@ make members private
86    TypedDatabaseCallback spec;
87    short                 running; // only used in no-transaction mode
88
89    explicit gb_callback(const TypedDatabaseCallback& spec_)
90        : spec(spec_),
91          running(0)
92    {}
93    gb_callback(const gb_callback& other)
94        : spec(other.spec),
95          running(other.running)
96    {
97        gb_assert(!running); // appears pathological - does it ever happen?
98    }
99    DECLARE_ASSIGNMENT_OPERATOR(gb_callback);
100
101    bool may_be_removed() const { return !running && spec.is_marked_for_removal(); }
102
103    bool call(GBDATA *with, GB_CB_TYPE typemask) {
104        /*! call if matching. only done in NO_TRANSACTION_MODE
105         * @param with database entry passed to callback
106         * @param typemask call only if callback-type and typemask have common bits
107         * @return true if callback has to be removed afterwards
108         */
109        {
110            GB_CB_TYPE matchingType = GB_CB_TYPE(spec.get_type() & typemask);
111            if (matchingType && !spec.is_marked_for_removal()) {
112                ++running;
113                spec(with, matchingType);
114                --running;
115            }
116        }
117        return may_be_removed();
118    }
119};
120
121struct gb_callback_list : public CallbackList<gb_callback> {
122    bool call(GBDATA *with, GB_CB_TYPE typemask) {
123        /*! call all matching callbacks. only done in NO_TRANSACTION_MODE
124         * @param with database entry passed to callback
125         * @param typemask call only if callback-type and typemask have common bits
126         * @return true if some callback in list has to be removed afterwards
127         */
128
129        bool need_del = false;
130        for (itertype cb = callbacks.begin(); cb != callbacks.end(); ) {
131            itertype next = cb; advance(next, 1);
132            need_del = cb->call(with, typemask) || need_del;
133            cb = next;
134        }
135        return need_del;
136    }
137};
138
139struct gb_transaction_save;
140
141struct gb_triggered_callback { // callbacks that will be called during commit
142    // @@@ make members private
143    TypedDatabaseCallback  spec;
144    gb_transaction_save   *old;
145    GBDATA                *gbd;
146
147    gb_triggered_callback(GBDATA *gbd_, gb_transaction_save *old_, const TypedDatabaseCallback& spec_)
148        : spec(spec_),
149          old(old_),
150          gbd(gbd_)
151    {
152        gb_add_ref_gb_transaction_save(old);
153    }
154    gb_triggered_callback(const gb_triggered_callback& other)
155        : spec(other.spec),
156          old(other.old),
157          gbd(other.gbd)
158    {
159        gb_add_ref_gb_transaction_save(old);
160    }
161    DECLARE_ASSIGNMENT_OPERATOR(gb_triggered_callback);
162    ~gb_triggered_callback() {
163        gb_del_ref_gb_transaction_save(old);
164    }
165};
166
167struct gb_pending_callbacks : public CallbackList<gb_triggered_callback> {
168    bool pending() const { return !empty(); }
169    void call_and_forget(GB_CB_TYPE allowedTypes);
170};
171
172#else
173#error gb_cb.h included twice
174#endif // GB_CB_H
Note: See TracBrowser for help on using the repository browser.