1 // 2 // Copyright (C) 2001-2013 Greg Landrum, Randal M. Henne and Rational Discovery 3 // LLC 4 // 5 // @@ All Rights Reserved @@ 6 // This file is part of the RDKit. 7 // The contents are covered by the terms of the BSD license 8 // which is included in the file license.txt, found at the root 9 // of the RDKit source tree. 10 // 11 12 #include <RDGeneral/export.h> 13 #ifndef __RD_INVARIANT_H__ 14 #define __RD_INVARIANT_H__ 15 16 #include <cassert> 17 #include <string> 18 #include <iostream> 19 #include <stdexcept> 20 21 #include "BoostStartInclude.h" 22 #include <RDGeneral/RDLog.h> 23 #include "BoostEndInclude.h" 24 25 #ifdef RDDEBUG 26 // Enable RDDEBUG for testing whether rdcast 27 // conversions are within numerical limits 28 #include <RDGeneral/BoostStartInclude.h> 29 #include <boost/numeric/conversion/cast.hpp> 30 #include <RDGeneral/BoostEndInclude.h> 31 #endif 32 // 33 // What if no invariant method is defined? 34 // 35 #if !defined INVARIANT_EXCEPTION_METHOD && !defined INVARIANT_ASSERT_METHOD && \ 36 !defined INVARIANT_SILENT_METHOD 37 #define INVARIANT_EXCEPTION_METHOD 1 38 #endif 39 40 // 41 // What if an invariant method is defined, but none are true? 42 // 43 #if !INVARIANT_EXCEPTION_METHOD && !INVARIANT_ASSERT_METHOD && \ 44 !INVARIANT_SILENT_METHOD 45 #undef INVARIANT_EXCEPTION_METHOD 46 #define INVARIANT_EXCEPTION_METHOD 1 47 #endif 48 49 namespace Invar { 50 51 class RDKIT_RDGENERAL_EXPORT Invariant : public std::runtime_error { 52 public: Invariant(const char * prefix,const char * mess,const char * expr,const char * const file,int line)53 Invariant(const char* prefix, const char* mess, const char* expr, 54 const char* const file, int line) 55 : std::runtime_error(prefix), 56 mess_d(mess), 57 expr_d(expr), 58 prefix_d(prefix), 59 file_dp(file), 60 line_d(line) {} Invariant(const char * prefix,const std::string & mess,const char * expr,const char * const file,int line)61 Invariant(const char* prefix, const std::string& mess, const char* expr, 62 const char* const file, int line) 63 : std::runtime_error(prefix), 64 mess_d(mess.c_str()), 65 expr_d(expr), 66 prefix_d(prefix), 67 file_dp(file), 68 line_d(line) {} ~Invariant()69 ~Invariant() noexcept {}; 70 what()71 const char* what() const noexcept override { return mess_d.c_str(); } 72 getFile()73 const char* getFile() const { return file_dp; } 74 getExpression()75 std::string getExpression() const { return expr_d; } 76 getLine()77 int getLine() const { return line_d; } 78 79 std::string toString() const; 80 std::string toUserString() const; // strips build info, adds version 81 82 private: 83 std::string mess_d, expr_d, prefix_d; 84 85 const char* const file_dp; 86 87 int line_d; 88 }; 89 RDKIT_RDGENERAL_EXPORT std::ostream& operator<<(std::ostream& s, 90 const Invariant& inv); 91 } // end of namespace Invar 92 93 #define ASSERT_INVARIANT(expr, mess) assert(expr) 94 95 // 96 // Set desired reporting method 97 // 98 99 #if INVARIANT_EXCEPTION_METHOD 100 101 #define CHECK_INVARIANT(expr, mess) \ 102 if (!(expr)) { \ 103 Invar::Invariant inv("Invariant Violation", mess, #expr, __FILE__, \ 104 __LINE__); \ 105 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 106 throw inv; \ 107 } 108 109 #define PRECONDITION(expr, mess) \ 110 if (!(expr)) { \ 111 Invar::Invariant inv("Pre-condition Violation", mess, #expr, __FILE__, \ 112 __LINE__); \ 113 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 114 throw inv; \ 115 } 116 117 #define POSTCONDITION(expr, mess) \ 118 if (!(expr)) { \ 119 Invar::Invariant inv("Post-condition Violation", mess, #expr, __FILE__, \ 120 __LINE__); \ 121 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 122 throw inv; \ 123 } 124 125 #define UNDER_CONSTRUCTION(fn) \ 126 Invar::Invariant inv("Incomplete Code", \ 127 "This routine is still under development", fn, \ 128 __FILE__, __LINE__); \ 129 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 130 throw inv; 131 132 #define RANGE_CHECK(lo, x, hi) \ 133 if ((lo) > (hi) || (x) < (lo) || (x) > (hi)) { \ 134 std::stringstream errstr; \ 135 errstr << lo << " <= " << x << " <= " << hi; \ 136 Invar::Invariant inv("Range Error", #x, errstr.str().c_str(), __FILE__, \ 137 __LINE__); \ 138 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 139 throw inv; \ 140 } 141 142 #define URANGE_CHECK(x, hi) \ 143 if (x >= (hi)) { \ 144 std::stringstream errstr; \ 145 errstr << x << " < " << hi; \ 146 Invar::Invariant inv("Range Error", #x, errstr.str().c_str(), __FILE__, \ 147 __LINE__); \ 148 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 149 throw inv; \ 150 } 151 152 #define TEST_ASSERT(expr) \ 153 if (!(expr)) { \ 154 Invar::Invariant inv("Test Assert", "Expression Failed: ", #expr, \ 155 __FILE__, __LINE__); \ 156 BOOST_LOG(rdErrorLog) << "\n\n****\n" << inv << "****\n\n"; \ 157 throw inv; \ 158 } 159 160 #elif INVARIANT_ASSERT_METHOD 161 162 #define CHECK_INVARIANT(expr, mess) assert(expr); 163 #define PRECONDITION(expr, mess) assert(expr); 164 #define POSTCONDITION(expr, mess) assert(expr); 165 #define UNDER_CONSTRUCTION(fn) assert(0); 166 #define RANGE_CHECK(lo, x, hi) \ 167 assert((lo) <= (hi) && (x) >= (lo) && (x) <= (hi)); 168 #define URANGE_CHECK(lo, x, hi) assert((hi > 0) && (x < hi)); 169 #define TEST_ASSERT(expr) assert(expr); 170 171 #elif INVARIANT_SILENT_METHOD 172 173 #define CHECK_INVARIANT(expr, mess) 174 #define PRECONDITION(expr, mess) 175 #define POSTCONDITION(expr, mess) 176 #define UNDER_CONSTRUCTION(fn) 177 #define RANGE_CHECK(lo, x, hi) 178 #define URANGE_CHECK(x, hi) 179 #define TEST_ASSERT(expr) 180 181 #endif 182 183 #ifdef RDDEBUG 184 // use rdcast to convert between types 185 // when RDDEBUG is defined, this checks for 186 // validity (overflow, etc) 187 // when RDDEBUG is off, the cast is a no-cost 188 // static_cast 189 #define rdcast boost::numeric_cast 190 #else 191 #define rdcast static_cast 192 #endif 193 194 // Silence warnings for unused params while 195 // still indicating that they are unused 196 #define RDUNUSED_PARAM(x) (void)x; 197 198 #endif 199