duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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_ */