source: trunk/TEMPLATES/arb_error.h

Last change on this file was 18959, checked in by westram, 3 years ago
File size: 5.8 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_error.h                                        //
4//   Purpose   : replacement for GB_ERROR                           //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2009   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#ifndef ARB_ERROR_H
13#define ARB_ERROR_H
14
15// ARB_ERROR is a dropin replacement for GB_ERROR (C++ only)
16//
17// If CHECK_ERROR_DROP is undefined (e.g. in NDEBUG version)
18// there should be nearly no runtime overhead compared with plain GB_ERROR
19//
20// If CHECK_ERROR_DROP is defined
21// the following actions cause an assertion failure:
22//
23// * not "using" an error (regardless whether an error occurred or not)
24// * "using" an error several times (regardless whether an error occurred or not)
25// * overwriting an error (if error is not NULp)
26// * declaring errors as global variables
27//
28// Code changes needed:
29// * replace GB_ERROR by ARB_ERROR
30// * use error.deliver() whereever an existing error is "used"
31// * rewrite code that uses 'static GB_ERROR' (no longer allowed)
32//
33// "Using" an error means e.g.
34// * display error to user (e.g. aw_message_if())
35// * construct a new error based on an error (e.g. GB_end_transaction)
36//
37// Sometimes an error result is known to be always no error.
38// In this case use error.expect_no_error() to mark the error as "used"
39
40
41#ifndef SMARTPTR_H
42#include <smartptr.h>
43#endif
44
45#if defined(DEBUG)
46#define CHECK_ERROR_DROP
47#if defined(DEVEL_RALF)
48// #define EXTRA_ERROR_INFO
49#endif // DEVEL_RALF
50#endif // DEBUG
51
52#if defined(CHECK_ERROR_DROP)
53
54class ARB_undropable_error : virtual Noncopyable {
55    GB_ERROR    gberr;
56    bool        delivered;
57#if defined(EXTRA_ERROR_INFO)
58    const char *file;
59    size_t      line;
60#endif // EXTRA_ERROR_INFO
61public:
62    ARB_undropable_error(GB_ERROR gberr_) : gberr(gberr_), delivered(false)
63#if defined(EXTRA_ERROR_INFO)
64                                          , file(__FILE__), line(__LINE__)
65#endif // EXTRA_ERROR_INFO
66    {}
67    ~ARB_undropable_error() {
68        arb_assert(delivered);                      // oops - error has been dropped
69
70        // Note: if this fails from inside exit() a static ARB_ERROR was declared
71        // This is no longer allowed
72    }
73
74    GB_ERROR deliver() {
75        GB_ERROR err = gberr;
76        drop();
77        return err;
78    }
79
80    GB_ERROR look() const { return gberr; }
81
82    void drop() {
83        arb_assert(!delivered);                     // oops - error delivered/dropped twice
84        gberr     = NULp;
85        delivered = true;
86    }
87
88    void Set(GB_ERROR err) {
89        arb_assert(!gberr);                  // oops - you are trying to overwrite an existing error
90        gberr     = err;
91        delivered = false;
92    }
93};
94
95#endif // CHECK_ERROR_DROP
96
97
98
99class ARB_ERROR {
100    // unittest at ../SL/HEADERTESTS/arb_error.cxx@TEST_class_ARB_ERROR
101
102#if defined(CHECK_ERROR_DROP)
103    mutable SmartPtr<ARB_undropable_error> error;
104    GB_ERROR look() const { return error->look(); }
105public:
106    explicit ARB_ERROR() : error(new ARB_undropable_error(NULp)) {}
107    ARB_ERROR(GB_ERROR gberr) : error(new ARB_undropable_error(gberr)) {}
108    GB_ERROR deliver() const { return error->deliver(); }
109    ARB_ERROR& operator = (GB_ERROR gberr) { error->Set(gberr); return *this; }
110#else
111    GB_ERROR error;
112    GB_ERROR look() const { return error; }
113public:
114    explicit ARB_ERROR() : error(NULp) {}
115    ARB_ERROR(GB_ERROR gberr) : error(gberr) {}
116    GB_ERROR deliver() const { return error; }
117    ARB_ERROR& operator = (GB_ERROR gberr) { error = gberr; return *this; }
118#endif // CHECK_ERROR_DROP
119
120    // common for both ARB_ERROR flavors:
121private:
122    bool occurred() const { return look(); }
123
124public:
125    ARB_ERROR(const ARB_ERROR& err) : error(err.error) {}
126    ARB_ERROR& operator = (const ARB_ERROR& err) {  // assigning an error to a new error
127        if (error != err.error) *this = err.deliver(); // delivers the error
128        return *this;
129    }
130
131    operator bool() const { return occurred(); } // needed for 'if (!error)' and similar
132
133    void set_handled() const {
134        arb_assert(occurred()); // oops - tried to handle an error that did not occur
135        deliver();              // deliver and drop
136    }
137
138    void expect_no_error() const {
139        arb_assert(!occurred()); // oops - no error expected here
140        deliver();               // mark impossible errors as "used"
141    }
142
143    GB_ERROR preserve() const { return look(); } // look, but do not deliver
144
145#if defined(DEBUG)
146    void dump() const {
147        printf("ARB_ERROR='%s'\n", look());
148    }
149#endif // DEBUG
150};
151
152class Validity {
153    // basically a bool telling whether sth is valid
154    // (if invalid -> knows why)
155    const char *why_invalid;
156public:
157    Validity() : why_invalid(NULp) {}
158    Validity(bool valid, const char *why_invalid_)
159        : why_invalid(valid ? NULp : why_invalid_)
160    {}
161    Validity(const Validity& other) : why_invalid(other.why_invalid) {}
162    Validity& operator = (const Validity& other) {
163#if defined(ASSERTION_USED)
164        arb_assert(!why_invalid); // attempt to overwrite invalidity!
165#endif
166        why_invalid = other.why_invalid;
167        return *this;
168    }
169
170    operator bool() const { return !why_invalid; }
171    const char *why_not() const { return why_invalid; }
172
173    void assert_is_valid() const {
174#if defined(ASSERTION_USED)
175        if (why_invalid) {
176            fprintf(stderr, "Invalid: %s\n", why_invalid);
177            arb_assert(0);
178        }
179#endif
180    }
181};
182
183#else
184#error arb_error.h included twice
185#endif // ARB_ERROR_H
Note: See TracBrowser for help on using the repository browser.