40#include <source_location>
47#include <system_error>
57 std::is_integral_v<std::time_t> &&
sizeof(std::time_t) ==
sizeof(std::size_t),
58 "wrap std::time_t instead");
61#include <fmt/format.h>
62#include <spdlog/spdlog.h>
71 using namespace std::literals;
75 template <
class CharT>
84 class = std::enable_if_t<
85 std::is_pointer_v<T>>>
91 class = std::enable_if_t<
92 std::is_pointer_v<T>>>
98 class = std::enable_if_t<
99 std::is_pointer_v<T>>>
104 template <
class CharT, std::
size_t N>
114 static constexpr auto npos =
static_cast<std::size_t
>(-1);
137 [[nodiscard]]
consteval bool empty() const noexcept {
return this->
size() == 0; }
142 template <std::
size_t POS = 0, std::
size_t COUNT = npos>
143 [[nodiscard]]
consteval auto substr() const noexcept
145 return string < CharT, COUNT !=
npos ? COUNT : N - POS > (this->
data() + POS);
151 template <
class CharT, std::
size_t N>
152 string(
const CharT (&)[N]) ->
string<CharT, N - 1>;
156 requires(std::invocable<std::remove_reference_t<EF>>)
163 noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
164 std::is_nothrow_constructible_v<EF, Fn&>)
165 requires(!std::is_same_v<std::remove_cvref_t<Fn>,
scope_exit> &&
166 std::is_constructible_v<EF, Fn>)
168 static_assert(std::invocable<Fn>);
170 if constexpr (!std::is_lvalue_reference_v<Fn> &&
171 std::is_nothrow_constructible_v<EF, Fn>) {
172 _fn.emplace(std::forward<Fn>(a_fn));
180 noexcept(std::is_nothrow_move_constructible_v<EF> ||
181 std::is_nothrow_copy_constructible_v<EF>)
182 requires(std::is_nothrow_move_constructible_v<EF> ||
183 std::is_copy_constructible_v<EF>)
185 static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
186 static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
188 if (a_rhs.active()) {
189 if constexpr (std::is_nothrow_move_constructible_v<EF>) {
190 _fn.emplace(std::forward<EF>(*a_rhs._fn));
192 _fn.emplace(a_rhs._fn);
203 if (_fn.has_value()) {
211 [[nodiscard]]
bool active() const noexcept {
return _fn.has_value(); }
213 std::optional<std::remove_reference_t<EF>> _fn;
221 class Underlying = std::underlying_type_t<Enum>>
228 static_assert(std::is_enum_v<enum_type>,
"enum_type must be an enum");
229 static_assert(std::is_integral_v<underlying_type>,
"underlying_type must be an integral");
242 template <
class... Args>
244 requires(std::same_as<Args, enum_type> && ...)
266 [[nodiscard]]
explicit constexpr operator bool() const noexcept {
return _impl !=
static_cast<underlying_type>(0); }
272 template <
class... Args>
274 requires(std::same_as<Args, enum_type> && ...)
280 template <
class... Args>
282 requires(std::same_as<Args, enum_type> && ...)
288 template <
class... Args>
289 [[nodiscard]]
constexpr bool any(Args... a_args)
const noexcept
290 requires(std::same_as<Args, enum_type> && ...)
295 template <
class... Args>
296 [[nodiscard]]
constexpr bool all(Args... a_args)
const noexcept
297 requires(std::same_as<Args, enum_type> && ...)
302 template <
class... Args>
303 [[nodiscard]]
constexpr bool none(Args... a_args)
const noexcept
304 requires(std::same_as<Args, enum_type> && ...)
313 template <
class... Args>
315 std::common_type_t<Args...>,
316 std::underlying_type_t<
317 std::common_type_t<Args...>>>;
321#define SKSE_MAKE_LOGICAL_OP(a_op, a_result) \
322 template <class E, class U1, class U2> \
323 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
325 return a_lhs.get() a_op a_rhs.get(); \
328 template <class E, class U> \
329 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
331 return a_lhs.get() a_op a_rhs; \
334#define SKSE_MAKE_ARITHMETIC_OP(a_op) \
335 template <class E, class U> \
336 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_enum, U a_shift) noexcept \
337 -> enumeration<E, U> \
339 return static_cast<E>(static_cast<U>(a_enum.get()) a_op a_shift); \
342 template <class E, class U> \
343 constexpr auto operator a_op##=(enumeration<E, U>& a_enum, U a_shift) noexcept \
344 -> enumeration<E, U>& \
346 return a_enum = a_enum a_op a_shift; \
349#define SKSE_MAKE_ENUMERATION_OP(a_op) \
350 template <class E, class U1, class U2> \
351 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
352 -> enumeration<E, std::common_type_t<U1, U2>> \
354 return static_cast<E>(static_cast<U1>(a_lhs.get()) a_op static_cast<U2>(a_rhs.get())); \
357 template <class E, class U> \
358 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
359 -> enumeration<E, U> \
361 return static_cast<E>(static_cast<U>(a_lhs.get()) a_op static_cast<U>(a_rhs)); \
364 template <class E, class U> \
365 [[nodiscard]] constexpr auto operator a_op(E a_lhs, enumeration<E, U> a_rhs) noexcept \
366 -> enumeration<E, U> \
368 return static_cast<E>(static_cast<U>(a_lhs) a_op static_cast<U>(a_rhs.get())); \
371 template <class E, class U1, class U2> \
372 constexpr auto operator a_op##=(enumeration<E, U1>& a_lhs, enumeration<E, U2> a_rhs) noexcept \
373 -> enumeration<E, U1>& \
375 return a_lhs = a_lhs a_op a_rhs; \
378 template <class E, class U> \
379 constexpr auto operator a_op##=(enumeration<E, U>& a_lhs, E a_rhs) noexcept \
380 -> enumeration<E, U>& \
382 return a_lhs = a_lhs a_op a_rhs; \
385 template <class E, class U> \
386 constexpr auto operator a_op##=(E& a_lhs, enumeration<E, U> a_rhs) noexcept \
389 return a_lhs = *(a_lhs a_op a_rhs); \
392#define SKSE_MAKE_INCREMENTER_OP(a_op) \
393 template <class E, class U> \
394 constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs) noexcept \
395 -> enumeration<E, U>& \
397 return a_lhs a_op## = static_cast<E>(1); \
400 template <class E, class U> \
401 [[nodiscard]] constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs, int) noexcept \
402 -> enumeration<E, U> \
404 const auto tmp = a_lhs; \
419 return static_cast<E
>(~static_cast<U>(a_enum.get()));
442 public std::atomic_ref<T>
445 using super = std::atomic_ref<T>;
450 explicit atomic_ref(
volatile T& a_obj)
noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
455 using super::operator=;
482 [[nodiscard]]
constexpr operator std::ptrdiff_t() const noexcept {
return value; }
484 [[nodiscard]]
constexpr std::ptrdiff_t
operator()() const noexcept {
return value; }
486 static constexpr auto value =
static_cast<std::ptrdiff_t
>(
sizeof(T));
492 template <
class T,
class U>
495 auto addr = a_ptr ?
reinterpret_cast<std::uintptr_t
>(a_ptr) + a_adjust : 0;
496 if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
497 return reinterpret_cast<std::add_cv_t<T>*
>(addr);
498 }
else if constexpr (std::is_const_v<U>) {
499 return reinterpret_cast<std::add_const_t<T>*
>(addr);
500 }
else if constexpr (std::is_volatile_v<U>) {
501 return reinterpret_cast<std::add_volatile_t<T>*
>(addr);
503 return reinterpret_cast<T*
>(addr);
510 auto address = T::VTABLE[0].address();
514 reinterpret_cast<std::uintptr_t*
>(a_ptr)[0] = address;
519 void memzero(
volatile T* a_ptr, std::size_t a_size =
sizeof(T))
521 const auto begin =
reinterpret_cast<volatile char*
>(a_ptr);
522 constexpr char val{ 0 };
523 std::fill_n(begin, a_size, val);
526 template <
class... Args>
528 requires(std::same_as<std::remove_cv_t<Args>,
bool> && ...)
530 constexpr auto ARGC =
sizeof...(Args);
532 std::bitset<ARGC> bits;
534 ((bits[i++] = a_args), ...);
536 if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
537 return bits.to_ulong();
538 }
else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
539 return bits.to_ullong();
541 static_assert(
false &&
sizeof...(Args));
546 -> std::optional<std::wstring>
548 const auto cvt = [&](
wchar_t* a_dst, std::size_t a_length) {
553 static_cast<int>(a_in.length()),
555 static_cast<int>(a_length));
558 const auto len = cvt(
nullptr, 0);
563 std::wstring out(len,
'\0');
564 if (cvt(out.data(), out.length()) == 0) {
572 -> std::optional<std::string>
574 const auto cvt = [&](
char* a_dst, std::size_t a_length) {
579 static_cast<int>(a_in.length()),
581 static_cast<int>(a_length),
586 const auto len = cvt(
nullptr, 0);
591 std::string out(len,
'\0');
592 if (cvt(out.data(), out.length()) == 0) {
615 const uint_least32_t a_line = __builtin_LINE(),
616 const uint_least32_t a_column = __builtin_COLUMN(),
617 const char*
const a_file = __builtin_FILE(),
618 const char*
const a_function = __builtin_FUNCTION())
noexcept
621 result._line = a_line;
622 result._column = a_column;
623 result._file = a_file;
624 result._function = a_function;
628 [[nodiscard]]
constexpr const char* file_name()
const noexcept
633 [[nodiscard]]
constexpr const char* function_name()
const noexcept
638 [[nodiscard]]
constexpr uint_least32_t line()
const noexcept
643 [[nodiscard]]
constexpr uint_least32_t column()
const noexcept
651 uint_least32_t _line{};
652 uint_least32_t _column{};
653 const char* _file =
"";
654 const char* _function =
"";
661 const auto body = [&]() -> std::wstring {
662 const std::filesystem::path p = a_loc.file_name();
663 auto filename = p.lexically_normal().generic_string();
665 const std::regex r{ R
"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
667 if (std::regex_search(filename, matches, r)) {
668 filename = matches[1].str();
677 .value_or(L
"<character encoding error>"s);
680 const auto caption = []() {
682 std::vector<wchar_t> buf;
683 buf.reserve(maxPath);
684 buf.resize(maxPath / 2);
685 std::uint32_t result = 0;
687 buf.resize(buf.size() * 2);
691 static_cast<std::uint32_t
>(buf.size()));
692 }
while (result && result == buf.size() && buf.size() <= (std::numeric_limits<std::uint32_t>::max)());
694 if (result && result != buf.size()) {
695 std::filesystem::path p(buf.begin(), buf.begin() + result);
696 return p.filename().native();
705 static_cast<int>(a_loc.line()),
706 a_loc.function_name() },
707 spdlog::level::critical,
711#ifdef ENABLE_COMMONLIBSSE_TESTING
712 throw std::runtime_error(
utf16_to_utf8(caption.empty() ? body.c_str() : caption.c_str())->c_str());
714 MessageBox(
nullptr, body.c_str(), (caption.empty() ?
nullptr : caption.c_str()), 0);
727 template <
class Enum>
729 requires(std::is_enum_v<Enum>)
731 return static_cast<std::underlying_type_t<Enum>
>(a_val);
734 template <
class To,
class From>
737 if constexpr (std::is_same_v<
738 std::remove_cv_t<From>,
739 std::remove_cv_t<To>>) {
743 }
else if constexpr (std::is_reference_v<From>) {
744 return stl::unrestricted_cast<To>(std::addressof(a_from));
747 }
else if constexpr (std::is_reference_v<To>) {
750 std::remove_reference_t<To>>>(a_from);
753 }
else if constexpr (std::is_pointer_v<From> &&
754 std::is_pointer_v<To>) {
755 return static_cast<To
>(
757 static_cast<const volatile void*
>(a_from)));
758 }
else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
759 (std::is_integral_v<From> && std::is_pointer_v<To>)) {
760 return reinterpret_cast<To
>(a_from);
764 std::remove_cv_t<std::remove_reference_t<From>> from;
765 std::remove_cv_t<std::remove_reference_t<To>> to;
768 from = std::forward<From>(a_from);
775#undef SKSE_MAKE_INCREMENTER_OP
776#undef SKSE_MAKE_ENUMERATION_OP
777#undef SKSE_MAKE_ARITHMETIC_OP
778#undef SKSE_MAKE_LOGICAL_OP
782 using namespace std::literals;
789 using namespace std::literals;
794#define RELOCATION_ID(a_se, a_ae) REL::RelocationID(a_se, a_ae)
#define SKSE_MAKE_ARITHMETIC_OP(a_op)
Definition PCH.h:334
#define SKSE_MAKE_ENUMERATION_OP(a_op)
Definition PCH.h:349
#define SKSE_MAKE_INCREMENTER_OP(a_op)
Definition PCH.h:392
#define SKSE_MAKE_LOGICAL_OP(a_op, a_result)
Definition PCH.h:321
#define CP_UTF8
Definition WinAPI.h:570
#define MessageBox
Definition WinAPI.h:587
#define GetModuleFileName
Definition WinAPI.h:582
typename super::value_type value_type
Definition PCH.h:448
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition PCH.h:450
constexpr enumeration & set(Args... a_args) noexcept
Definition PCH.h:273
constexpr enumeration & reset(Args... a_args) noexcept
Definition PCH.h:281
constexpr bool all(Args... a_args) const noexcept
Definition PCH.h:296
Underlying underlying_type
Definition PCH.h:226
constexpr bool any(Args... a_args) const noexcept
Definition PCH.h:289
constexpr enum_type operator*() const noexcept
Definition PCH.h:268
Enum enum_type
Definition PCH.h:225
constexpr bool none(Args... a_args) const noexcept
Definition PCH.h:303
constexpr enumeration(Args... a_values) noexcept
Definition PCH.h:243
constexpr enumeration & operator=(enum_type a_value) noexcept
Definition PCH.h:260
~enumeration() noexcept=default
constexpr underlying_type underlying() const noexcept
Definition PCH.h:270
constexpr enumeration() noexcept=default
constexpr enum_type get() const noexcept
Definition PCH.h:269
scope_exit(Fn &&a_fn) noexcept(std::is_nothrow_constructible_v< EF, Fn >||std::is_nothrow_constructible_v< EF, Fn & >)
Definition PCH.h:162
scope_exit(const scope_exit &)=delete
scope_exit(scope_exit &&a_rhs) noexcept(std::is_nothrow_move_constructible_v< EF >||std::is_nothrow_copy_constructible_v< EF >)
Definition PCH.h:179
~scope_exit() noexcept
Definition PCH.h:201
void release() noexcept
Definition PCH.h:208
Definition AbsorbEffect.h:6
Definition Relocation.h:182
void * GetCurrentProcess() noexcept
std::size_t GetMaxPath() noexcept
void * GetCurrentModule() noexcept
int MultiByteToWideChar(unsigned int a_codePage, std::uint32_t a_flags, const char *a_multiByteStr, int a_multiByte, wchar_t *a_wideCharStr, int a_wideChar)
int WideCharToMultiByte(unsigned int a_codePage, std::uint32_t a_flags, const wchar_t *a_wideCharStr, int a_wideChar, char *a_multiByteStr, int a_multiByte, const char *a_defaultChar, int *a_usedDefaultChar)
void TerminateProcess(void *a_process, unsigned int a_exitCode) noexcept
bool report_and_error(std::string_view a_msg, bool a_fail=true, SKSE::stl::source_location a_loc=SKSE::stl::source_location::current())
Definition PCH.h:658
T not_null
Definition PCH.h:100
constexpr auto to_underlying(Enum a_val) noexcept
Definition PCH.h:728
std::source_location source_location
Definition PCH.h:600
To unrestricted_cast(From a_from) noexcept
Definition PCH.h:735
std::basic_string_view< CharT > basic_zstring
Definition PCH.h:76
void memzero(volatile T *a_ptr, std::size_t a_size=sizeof(T))
Definition PCH.h:519
T owner
Definition PCH.h:86
T observer
Definition PCH.h:93
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition PCH.h:571
bool emplace_vtable(T *a_ptr)
Definition PCH.h:508
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition PCH.h:493
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition PCH.h:545
basic_zstring< wchar_t > zwstring
Definition PCH.h:79
constexpr auto operator~(enumeration< E, U > a_enum) noexcept -> enumeration< E, U >
Definition PCH.h:416
void report_and_fail(std::string_view a_msg, SKSE::stl::source_location a_loc=SKSE::stl::source_location::current())
Definition PCH.h:721
auto pun_bits(Args... a_args)
Definition PCH.h:527
basic_zstring< char > zstring
Definition PCH.h:78
constexpr auto ssizeof_v
Definition PCH.h:490
consteval bool empty() const noexcept
Definition PCH.h:137
const char_type & const_reference
Definition PCH.h:111
consteval auto substr() const noexcept
Definition PCH.h:143
consteval const_reference operator[](size_type a_pos) const noexcept
Definition PCH.h:123
const char_type * const_pointer
Definition PCH.h:109
consteval const_pointer data() const noexcept
Definition PCH.h:136
std::size_t size_type
Definition PCH.h:112
char_type c[N]
Definition PCH.h:148
consteval const_reference back() const noexcept
Definition PCH.h:135
consteval string(const_pointer a_string) noexcept
Definition PCH.h:116
char_type & reference
Definition PCH.h:110
char_type * pointer
Definition PCH.h:108
static constexpr auto npos
Definition PCH.h:114
consteval size_type length() const noexcept
Definition PCH.h:139
consteval char_type value_at(size_type a_pos) const noexcept
Definition PCH.h:129
consteval size_type size() const noexcept
Definition PCH.h:140
consteval const_reference front() const noexcept
Definition PCH.h:138
CharT char_type
Definition PCH.h:107
constexpr std::ptrdiff_t operator()() const noexcept
Definition PCH.h:484