Line data Source code
1 : /***************************************************************************
2 : *
3 : * The IPPL Framework
4 : *
5 : ***************************************************************************/
6 :
7 : #ifndef PASSERT_H
8 : #define PASSERT_H
9 : #include <exception>
10 : #include <stdexcept>
11 : #include <string>
12 :
13 : #include "Utility/IpplInfo.h"
14 : //////////////////////////////////////////////////////////////////////
15 : //
16 : // This is a compile time assert.
17 : // That is, if you say:
18 : // CTAssert<true>::test();
19 : // it compiles just fine and inserts no code.
20 : // If you say:
21 : // CTAssert<false>::test();
22 : // you get a compile error that it can't find CTAssert<false>::test().
23 : //
24 : // The template argument can of course be a calculation of const bools
25 : // that are known at compile time.
26 : //
27 : //////////////////////////////////////////////////////////////////////
28 :
29 : template <bool B>
30 : struct IpplCTAssert {};
31 :
32 : template <>
33 : struct IpplCTAssert<true> {
34 : static void test() {}
35 : };
36 :
37 : #if defined(NOCTAssert)
38 : #define CTAssert(c)
39 : #else
40 : #define CTAssert(c) IpplCTAssert<(c)>::test()
41 : #endif
42 :
43 : //===========================================================================//
44 : // class assertion - exception notification class for assertions
45 :
46 : // This class should really be derived from std::runtime_error, but
47 : // unfortunately we don't have good implementation of the library standard
48 : // yet, on compilers other than KCC. So, this class will keep with the
49 : // "what" method evidenced in the standard, but dispense with inheriting from
50 : // classes for which we don't have implementations...
51 : //===========================================================================//
52 :
53 : class assertion : public std::runtime_error {
54 : char* msg;
55 :
56 : public:
57 : assertion(const char* cond, const char* file, int line);
58 :
59 : assertion(const char* m);
60 :
61 : assertion(const assertion& a);
62 :
63 0 : ~assertion() throw() { delete[] msg; }
64 :
65 : assertion& operator=(const assertion& a);
66 :
67 : using std::runtime_error::what;
68 :
69 0 : virtual const char* what() { return msg; };
70 : };
71 :
72 : //---------------------------------------------------------------------------//
73 : // Now we define a run time assertion mechanism. We will call it "PAssert",
74 : // to reflect the idea that this is for use in IPPL per se, recognizing that
75 : // there are numerous other assertion facilities in use in client codes.
76 : //---------------------------------------------------------------------------//
77 :
78 : // These are the functions that will be called in the assert macros.
79 : void toss_cookies(const char* cond, const char* file, int line);
80 : template <class S, class T>
81 0 : void toss_cookies(const char* cond, const char* astr, const char* bstr, S a, T b, const char* file,
82 : int line) {
83 0 : std::string what = "Assertion '" + std::string(cond) + "' failed. \n";
84 0 : what += std::string(astr) + " = " + std::to_string(a) + ", ";
85 0 : what += std::string(bstr) + " = " + std::to_string(b) + "\n";
86 0 : what += "in \n";
87 0 : what += std::string(file) + ", line " + std::to_string(line);
88 :
89 0 : throw std::runtime_error(what);
90 0 : }
91 : void insist(const char* cond, const char* msg, const char* file, int line);
92 :
93 : //---------------------------------------------------------------------------//
94 : // The PAssert macro is intended to be used for validating preconditions
95 : // which must be true in order for following code to be correct, etc. For
96 : // example, PAssert( x > 0. ); y = sqrt(x); If the assertion fails, the code
97 : // should just bomb. Philosophically, it should be used to feret out bugs in
98 : // preceding code, making sure that prior results are within reasonable
99 : // bounds before proceeding to use those results in further computation, etc.
100 : //---------------------------------------------------------------------------//
101 :
102 : #ifdef NOPAssert
103 : #define PAssert(c)
104 : #define PAssert_EQ(a, b)
105 : #define PAssert_NE(a, b)
106 : #define PAssert_LT(a, b)
107 : #define PAssert_LE(a, b)
108 : #define PAssert_GT(a, b)
109 : #define PAssert_GE(a, b)
110 : #else
111 : #ifdef __HIP_PLATFORM_AMD__ // toss_cookies are not supported so just do a no-operation
112 : #define PAssert(c)
113 : #define PAssert_CMP(cmp, a, b)
114 : #else
115 : #define PAssert(c) \
116 : if (!(c)) \
117 : toss_cookies(#c, __FILE__, __LINE__);
118 : #define PAssert_CMP(cmp, a, b) \
119 : if (!(cmp)) \
120 : toss_cookies(#cmp, #a, #b, a, b, __FILE__, __LINE__);
121 : #endif
122 : #define PAssert_EQ(a, b) PAssert_CMP(a == b, a, b)
123 : #define PAssert_NE(a, b) PAssert_CMP(a != b, a, b)
124 : #define PAssert_LT(a, b) PAssert_CMP(a < b, a, b)
125 : #define PAssert_LE(a, b) PAssert_CMP(a <= b, a, b)
126 : #define PAssert_GT(a, b) PAssert_CMP(a > b, a, b)
127 : #define PAssert_GE(a, b) PAssert_CMP(a >= b, a, b)
128 : #endif
129 :
130 : //---------------------------------------------------------------------------//
131 : // The PInsist macro is akin to the PAssert macro, but it provides the
132 : // opportunity to specify an instructive message. The idea here is that you
133 : // should use Insist for checking things which are more or less under user
134 : // control. If the user makes a poor choice, we "insist" that it be
135 : // corrected, providing a corrective hint.
136 : //---------------------------------------------------------------------------//
137 :
138 : #define PInsist(c, m) \
139 : if (!(c)) \
140 : insist(#c, m, __FILE__, __LINE__);
141 :
142 : //---------------------------------------------------------------------------//
143 : // NOTE: We provide a way to eliminate assertions, but not insistings. The
144 : // idea is that PAssert is used to perform sanity checks during program
145 : // development, which you might want to eliminate during production runs for
146 : // performance sake. PInsist is used for things which really really must be
147 : // true, such as "the file must've been opened", etc. So, use PAssert for
148 : // things which you want taken out of production codes (like, the check might
149 : // inhibit inlining or something like that), but use PInsist for those things
150 : // you want checked even in a production code.
151 : //---------------------------------------------------------------------------//
152 :
153 : #endif // PASSERT_H
154 :
155 : // vi: set et ts=4 sw=4 sts=4:
156 : // Local Variables:
157 : // mode:c
158 : // c-basic-offset: 4
159 : // indent-tabs-mode: nil
160 : // require-final-newline: nil
161 : // End:
|