source: branches/stable/ARBDB/gb_cb.h

Last change on this file was 16763, checked in by westram, 6 years ago
File size: 6.1 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 CB& 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() ? NULp : &callbacks.back(); }
81
82    template <typename PRED>
83    void remove_callbacks_that(PRED shallRemove) {
84        bool prev_running = false;
85
86        for (itertype cb = callbacks.begin(); cb != callbacks.end(); ) {
87            bool this_running = cb->running;
88
89            if (shallRemove(*cb)) {
90                if (prev_running || this_running) {
91                    cb->spec.mark_for_removal();
92                    ++cb;
93                }
94                else {
95                    cb = callbacks.erase(cb);
96                }
97            }
98            else {
99                ++cb;
100            }
101            prev_running = this_running;
102        }
103    }
104};
105
106struct gb_callback {
107    // @@@ make members private
108    TypedDatabaseCallback spec;
109    short                 running; // only used in no-transaction mode
110
111    explicit gb_callback(const TypedDatabaseCallback& spec_)
112        : spec(spec_),
113          running(0)
114    {}
115    gb_callback(const gb_callback& other)
116        : spec(other.spec),
117          running(other.running)
118    {
119        gb_assert(!running); // appears pathological - does it ever happen?
120    }
121    DECLARE_ASSIGNMENT_OPERATOR(gb_callback);
122
123    bool may_be_removed() const { return !running && spec.is_marked_for_removal(); }
124
125    bool call(GBDATA *with, GB_CB_TYPE typemask) {
126        /*! call if matching. only done in NO_TRANSACTION_MODE
127         * @param with database entry passed to callback
128         * @param typemask call only if callback-type and typemask have common bits
129         * @return true if callback has to be removed afterwards
130         */
131        {
132            GB_CB_TYPE matchingType = GB_CB_TYPE(spec.get_type() & typemask);
133            if (matchingType && !spec.is_marked_for_removal()) {
134                ++running;
135                spec(with, matchingType);
136                --running;
137            }
138        }
139        return may_be_removed();
140    }
141};
142
143struct gb_callback_list : public CallbackList<gb_callback> {
144    bool call(GBDATA *with, GB_CB_TYPE typemask) {
145        /*! call all matching callbacks. only done in NO_TRANSACTION_MODE
146         * @param with database entry passed to callback
147         * @param typemask call only if callback-type and typemask have common bits
148         * @return true if some callback in list has to be removed afterwards
149         */
150
151        bool need_del = false;
152        for (itertype cb = callbacks.begin(); cb != callbacks.end(); ) {
153            itertype next = cb; advance(next, 1);
154            need_del = cb->call(with, typemask) || need_del;
155            cb = next;
156        }
157        return need_del;
158    }
159};
160
161struct gb_transaction_save;
162
163struct gb_triggered_callback { // callbacks that will be called during commit
164    // @@@ make members private
165    TypedDatabaseCallback  spec;
166    gb_transaction_save   *old;
167    GBDATA                *gbd;
168
169    gb_triggered_callback(GBDATA *gbd_, gb_transaction_save *old_, const TypedDatabaseCallback& spec_)
170        : spec(spec_),
171          old(old_),
172          gbd(gbd_)
173    {
174        gb_add_ref_gb_transaction_save(old);
175    }
176    gb_triggered_callback(const gb_triggered_callback& other)
177        : spec(other.spec),
178          old(other.old),
179          gbd(other.gbd)
180    {
181        gb_add_ref_gb_transaction_save(old);
182    }
183    DECLARE_ASSIGNMENT_OPERATOR(gb_triggered_callback);
184    ~gb_triggered_callback() {
185        gb_del_ref_gb_transaction_save(old);
186    }
187};
188
189struct gb_pending_callbacks : public CallbackList<gb_triggered_callback> {
190    bool pending() const { return !empty(); }
191    void call_and_forget(GB_CB_TYPE allowedTypes);
192};
193
194#else
195#error gb_cb.h included twice
196#endif // GB_CB_H
Note: See TracBrowser for help on using the repository browser.