common.hpp (10342B)
1 #ifndef _C4_YML_COMMON_HPP_ 2 #define _C4_YML_COMMON_HPP_ 3 4 #include <cstddef> 5 #include <c4/substr.hpp> 6 #include <c4/yml/export.hpp> 7 8 9 #ifndef RYML_USE_ASSERT 10 # define RYML_USE_ASSERT C4_USE_ASSERT 11 #endif 12 13 14 #if RYML_USE_ASSERT 15 # define RYML_ASSERT(cond) RYML_CHECK(cond) 16 # define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg) 17 #else 18 # define RYML_ASSERT(cond) 19 # define RYML_ASSERT_MSG(cond, msg) 20 #endif 21 22 23 #if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK) 24 # define RYML_DEBUG_BREAK() 25 #else 26 # define RYML_DEBUG_BREAK() \ 27 { \ 28 if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \ 29 { \ 30 C4_DEBUG_BREAK(); \ 31 } \ 32 } 33 #endif 34 35 36 #define RYML_CHECK(cond) \ 37 do { \ 38 if(!(cond)) \ 39 { \ 40 RYML_DEBUG_BREAK() \ 41 c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \ 42 } \ 43 } while(0) 44 45 #define RYML_CHECK_MSG(cond, msg) \ 46 do \ 47 { \ 48 if(!(cond)) \ 49 { \ 50 RYML_DEBUG_BREAK() \ 51 c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \ 52 } \ 53 } while(0) 54 55 56 #if C4_CPP >= 14 57 # define RYML_DEPRECATED(msg) [[deprecated(msg)]] 58 #else 59 # if defined(_MSC_VER) 60 # define RYML_DEPRECATED(msg) __declspec(deprecated(msg)) 61 # else // defined(__GNUC__) || defined(__clang__) 62 # define RYML_DEPRECATED(msg) __attribute__((deprecated(msg))) 63 # endif 64 #endif 65 66 67 //----------------------------------------------------------------------------- 68 //----------------------------------------------------------------------------- 69 //----------------------------------------------------------------------------- 70 71 namespace c4 { 72 namespace yml { 73 74 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast") 75 76 enum : size_t { 77 /** a null position */ 78 npos = size_t(-1), 79 /** an index to none */ 80 NONE = size_t(-1) 81 }; 82 83 84 //----------------------------------------------------------------------------- 85 //----------------------------------------------------------------------------- 86 //----------------------------------------------------------------------------- 87 88 //! holds a position into a source buffer 89 struct RYML_EXPORT LineCol 90 { 91 //! number of bytes from the beginning of the source buffer 92 size_t offset; 93 //! line 94 size_t line; 95 //! column 96 size_t col; 97 98 LineCol() : offset(), line(), col() {} 99 //! construct from line and column 100 LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {} 101 //! construct from offset, line and column 102 LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {} 103 }; 104 105 106 //! a source file position 107 struct RYML_EXPORT Location : public LineCol 108 { 109 csubstr name; 110 111 operator bool () const { return !name.empty() || line != 0 || offset != 0; } 112 113 Location() : LineCol(), name() {} 114 Location( size_t l, size_t c) : LineCol{ l, c}, name( ) {} 115 Location( csubstr n, size_t l, size_t c) : LineCol{ l, c}, name(n) {} 116 Location( csubstr n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(n) {} 117 Location(const char *n, size_t l, size_t c) : LineCol{ l, c}, name(to_csubstr(n)) {} 118 Location(const char *n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(to_csubstr(n)) {} 119 }; 120 121 122 //----------------------------------------------------------------------------- 123 124 /** the type of the function used to report errors. This function must 125 * interrupt execution, either by raising an exception or calling 126 * std::abort(). 127 * 128 * @warning the error callback must never return: it must either abort 129 * or throw an exception. Otherwise, the parser will enter into an 130 * infinite loop, or the program may crash. */ 131 using pfn_error = void (*)(const char* msg, size_t msg_len, Location location, void *user_data); 132 /** the type of the function used to allocate memory */ 133 using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data); 134 /** the type of the function used to free memory */ 135 using pfn_free = void (*)(void* mem, size_t size, void *user_data); 136 137 /** trigger an error: call the current error callback. */ 138 RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc); 139 /** @overload error */ 140 inline void error(const char *msg, size_t msg_len) 141 { 142 error(msg, msg_len, Location{}); 143 } 144 /** @overload error */ 145 template<size_t N> 146 inline void error(const char (&msg)[N], Location loc) 147 { 148 error(msg, N-1, loc); 149 } 150 /** @overload error */ 151 template<size_t N> 152 inline void error(const char (&msg)[N]) 153 { 154 error(msg, N-1, Location{}); 155 } 156 157 //----------------------------------------------------------------------------- 158 159 /** a c-style callbacks class 160 * 161 * @warning the error callback must never return: it must either abort 162 * or throw an exception. Otherwise, the parser will enter into an 163 * infinite loop, or the program may crash. */ 164 struct RYML_EXPORT Callbacks 165 { 166 void * m_user_data; 167 pfn_allocate m_allocate; 168 pfn_free m_free; 169 pfn_error m_error; 170 171 Callbacks(); 172 Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error_); 173 174 bool operator!= (Callbacks const& that) const { return !operator==(that); } 175 bool operator== (Callbacks const& that) const 176 { 177 return (m_user_data == that.m_user_data && 178 m_allocate == that.m_allocate && 179 m_free == that.m_free && 180 m_error == that.m_error); 181 } 182 }; 183 184 /** set the global callbacks. 185 * 186 * @warning the error callback must never return: it must either abort 187 * or throw an exception. Otherwise, the parser will enter into an 188 * infinite loop, or the program may crash. */ 189 RYML_EXPORT void set_callbacks(Callbacks const& c); 190 /// get the global callbacks 191 RYML_EXPORT Callbacks const& get_callbacks(); 192 /// set the global callbacks back to their defaults 193 RYML_EXPORT void reset_callbacks(); 194 195 /// @cond dev 196 #define _RYML_CB_ERR(cb, msg_literal) \ 197 do \ 198 { \ 199 const char msg[] = msg_literal; \ 200 RYML_DEBUG_BREAK() \ 201 (cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \ 202 } while(0) 203 #define _RYML_CB_CHECK(cb, cond) \ 204 do \ 205 { \ 206 if(!(cond)) \ 207 { \ 208 const char msg[] = "check failed: " #cond; \ 209 RYML_DEBUG_BREAK() \ 210 (cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \ 211 } \ 212 } while(0) 213 #ifdef RYML_USE_ASSERT 214 #define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond)) 215 #else 216 #define _RYML_CB_ASSERT(cb, cond) do {} while(0) 217 #endif 218 #define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data) 219 #define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), (T), (num), nullptr) 220 #define _RYML_CB_FREE(cb, buf, T, num) \ 221 do { \ 222 (cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \ 223 (buf) = nullptr; \ 224 } while(0) 225 226 227 228 namespace detail { 229 template<int8_t signedval, uint8_t unsignedval> 230 struct _charconstant_t 231 : public std::conditional<std::is_signed<char>::value, 232 std::integral_constant<int8_t, signedval>, 233 std::integral_constant<uint8_t, unsignedval>>::type 234 {}; 235 #define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value 236 } // namespace detail 237 238 239 namespace detail { 240 struct _SubstrWriter 241 { 242 substr buf; 243 size_t pos; 244 _SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) {} 245 void append(csubstr s) 246 { 247 C4_ASSERT(!s.overlaps(buf)); 248 if(pos + s.len <= buf.len) 249 memcpy(buf.str + pos, s.str, s.len); 250 pos += s.len; 251 } 252 void append(char c) 253 { 254 if(pos < buf.len) 255 buf.str[pos] = c; 256 ++pos; 257 } 258 void append_n(char c, size_t numtimes) 259 { 260 if(pos + numtimes < buf.len) 261 memset(buf.str + pos, c, numtimes); 262 pos += numtimes; 263 } 264 size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; } 265 size_t excess() const { return pos > buf.len ? pos - buf.len : 0; } 266 //! get the part written so far 267 csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; } 268 //! get the part that is still free to write to (the remainder) 269 substr rem() { return pos < buf.len ? buf.sub(pos) : buf.last(0); } 270 271 size_t advance(size_t more) { pos += more; return pos; } 272 }; 273 } // namespace detail 274 275 /// @endcond 276 277 C4_SUPPRESS_WARNING_GCC_CLANG_POP 278 279 } // namespace yml 280 } // namespace c4 281 282 #endif /* _C4_YML_COMMON_HPP_ */