blob: 4d1689350827672abecf0af91b114fb373b2a971 [file] [log] [blame]
#ifndef JSON5EncoderCpp_native
#define JSON5EncoderCpp_native
#include <array>
#include <cstdint>
#include <type_traits>
namespace JSON5EncoderCpp {
template <class From>
constexpr std::uint32_t cast_to_uint32(
const From &unsigned_from,
typename std::enable_if<
!std::is_signed<From>::value
>::type* = nullptr
) {
return static_cast<std::uint32_t>(unsigned_from);
}
template <class From>
constexpr std::uint32_t cast_to_uint32(
const From &from,
typename std::enable_if<
std::is_signed<From>::value
>::type* = nullptr
) {
return cast_to_uint32(static_cast<typename std::make_unsigned<From>::type>(from));
}
template <class From>
constexpr std::int32_t cast_to_int32(const From &from) {
return static_cast<std::int32_t>(cast_to_uint32(from));
}
struct AlwaysTrue {
inline AlwaysTrue() = default;
inline ~AlwaysTrue() = default;
inline AlwaysTrue(const AlwaysTrue&) = default;
inline AlwaysTrue(AlwaysTrue&&) = default;
inline AlwaysTrue &operator =(const AlwaysTrue&) = default;
inline AlwaysTrue &operator =(AlwaysTrue&&) = default;
template <class T>
inline AlwaysTrue(T&&) : AlwaysTrue() {}
template <class T>
inline bool operator ==(T&&) const { return true; }
inline operator bool () const { return true; }
};
static inline bool obj_has_iter(const PyObject *obj) {
const auto *cls = Py_TYPE(obj);
return cls->tp_iter != nullptr;
}
constexpr char HEX[] = "0123456789abcdef";
struct EscapeDct {
using Item = std::array<char, 8>; // length, upto 6 characters, terminator (actually not needed)
static constexpr std::size_t length = 0x100;
using Items = Item[length];
static const Items items;
static const std::uint64_t is_escaped_lo;
static const std::uint64_t is_escaped_hi;
static inline bool is_escaped(std::uint32_t c) {
if (c < 0x40) {
return (is_escaped_lo & (static_cast<std::uint64_t>(1) << c)) != 0;
} else if (c < 0x80) {
return (is_escaped_hi & (static_cast<std::uint64_t>(1) << (c - 0x40))) != 0;
} else {
return true;
}
}
template <class S>
static inline std::size_t find_unescaped_range(const S *start, Py_ssize_t length) {
Py_ssize_t index = 0;
while ((index < length) && !is_escaped(start[index])) {
++index;
}
return index;
}
};
static inline bool unicode_is_lo_surrogate(std::uint32_t ch) {
return 0xDC00u <= ch && ch <= 0xDFFFu;
}
static inline bool unicode_is_hi_surrogate(std::uint32_t ch) {
return 0xD800u <= ch && ch <= 0xDBFFu;
}
static inline std::uint32_t unicode_join_surrogates(std::uint32_t hi, std::uint32_t lo) {
return (((hi & 0x03FFu) << 10) | (lo & 0x03FFu)) + 0x10000u;
}
template <typename T>
struct has_ob_shash {
template <typename C> static std::uint8_t test(decltype(&C::ob_shash)) ;
template <typename C> static std::uint64_t test(...);
enum { value = sizeof(test<T>(0)) == sizeof(std::uint8_t) };
};
template <typename T>
struct has_hash {
template <typename C> static std::uint8_t test(decltype(&C::hash)) ;
template <typename C> static std::uint64_t test(...);
enum { value = sizeof(test<T>(0)) == sizeof(std::uint8_t) };
};
template<class T, bool ob_shash = has_ob_shash<T>::value, bool hash = has_hash<T>::value>
struct ResetHash_;
template<class T>
struct ResetHash_ <T, true, false> {
static inline void reset(T *obj) {
obj->ob_shash = -1; // CPython: str
}
};
template<class T>
struct ResetHash_ <T, false, true> {
static inline void reset(T *obj) {
obj->hash = -1; // CPython: bytes
}
};
template<class T>
struct ResetHash_ <T, false, false> {
static inline void reset(T *obj) {
(void) 0; // PyPy
}
};
template <class T>
static inline void reset_hash(T *obj) {
ResetHash_<T>::reset(obj);
}
static int iter_next(PyObject *iterator, PyObject **value) {
Py_XDECREF(*value);
PyObject *v = PyIter_Next(iterator);
*value = v;
if (v) {
return true;
} else if (!PyErr_Occurred()) {
return 0;
} else {
return -1;
}
}
static inline AlwaysTrue exception_thrown() {
return true;
}
// https://stackoverflow.com/a/65258501/416224
#ifdef __GNUC__ // GCC 4.8+, Clang, Intel and other compilers compatible with GCC (-std=c++0x or above)
[[noreturn]] inline __attribute__((always_inline)) void unreachable() { __builtin_unreachable(); }
#elif defined(_MSC_VER) // MSVC
[[noreturn]] __forceinline void unreachable() { __assume(false); }
#else // ???
inline void unreachable() {}
#endif
#include "./_escape_dct.hpp"
const EscapeDct ESCAPE_DCT;
const char VERSION[] =
# include "./VERSION.inc"
;
static constexpr std::size_t VERSION_LENGTH = sizeof(VERSION) - 1;
const char LONGDESCRIPTION[] =
# include "./DESCRIPTION.inc"
;
static constexpr std::size_t LONGDESCRIPTION_LENGTH = sizeof(LONGDESCRIPTION) - 1;
#ifdef __GNUC__
# define JSON5EncoderCpp_expect(cond, likely) __builtin_expect(!!(cond), !!(likely))
#else
# define JSON5EncoderCpp_expect(cond, likely) !!(cond)
#endif
}
#endif