39 #include <source_location>
45 #include <string_view>
46 #include <system_error>
49 #include <type_traits>
56 std::is_integral_v<std::time_t> &&
sizeof(std::time_t) ==
sizeof(std::size_t),
57 "wrap std::time_t instead");
60 #include <binary_io/file_stream.hpp>
61 #include <boost/stl_interfaces/iterator_interface.hpp>
62 #include <fmt/format.h>
63 #include <spdlog/spdlog.h>
70 using namespace std::literals;
74 template <
class CharT>
83 class = std::enable_if_t<
84 std::is_pointer_v<T>>>
90 class = std::enable_if_t<
91 std::is_pointer_v<T>>>
97 class = std::enable_if_t<
98 std::is_pointer_v<T>>>
103 template <
class CharT, std::
size_t N>
113 static constexpr
auto npos =
static_cast<std::size_t
>(-1);
130 [[nodiscard]] consteval
bool empty() const noexcept {
return this->size() == 0; }
133 [[nodiscard]] consteval
size_type size() const noexcept {
return length(); }
135 template <std::
size_t POS = 0, std::
size_t COUNT = npos>
136 [[nodiscard]] consteval
auto substr() const noexcept
138 return string < CharT, COUNT != npos ? COUNT : N - POS > (this->data() + POS);
144 template <
class CharT, std::
size_t N>
145 string(
const CharT (&)[N]) ->
string<CharT, N - 1>;
147 template <
class CharT, std::
size_t N>
157 static constexpr
auto npos =
static_cast<std::size_t
>(-1);
174 [[nodiscard]] consteval
bool empty() const noexcept {
return this->size() == 0; }
177 [[nodiscard]] consteval
size_type size() const noexcept {
return length(); }
179 template <std::
size_t POS = 0, std::
size_t COUNT = npos>
180 [[nodiscard]] consteval
auto substr() const noexcept
182 return string < CharT, COUNT != npos ? COUNT : N - 1 - POS > (this->data() + POS);
190 requires(std::invocable<std::remove_reference_t<EF>>)
197 noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
198 std::is_nothrow_constructible_v<EF, Fn&>)
200 std::is_constructible_v<EF, Fn>)
202 static_assert(std::invocable<Fn>);
204 if constexpr (!std::is_lvalue_reference_v<Fn> &&
205 std::is_nothrow_constructible_v<EF, Fn>) {
206 _fn.emplace(std::forward<Fn>(a_fn));
214 noexcept(std::is_nothrow_move_constructible_v<EF> ||
215 std::is_nothrow_copy_constructible_v<EF>)
216 requires(std::is_nothrow_move_constructible_v<EF> ||
217 std::is_copy_constructible_v<EF>)
219 static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
220 static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
222 if (a_rhs.active()) {
223 if constexpr (std::is_nothrow_move_constructible_v<EF>) {
224 _fn.emplace(std::forward<EF>(*a_rhs._fn));
226 _fn.emplace(a_rhs._fn);
237 if (_fn.has_value()) {
242 void release() noexcept { _fn.reset(); }
245 [[nodiscard]]
bool active()
const noexcept {
return _fn.has_value(); }
247 std::optional<std::remove_reference_t<EF>> _fn;
255 class Underlying = std::underlying_type_t<Enum>>
262 static_assert(std::is_enum_v<enum_type>,
"enum_type must be an enum");
263 static_assert(std::is_integral_v<underlying_type>,
"underlying_type must be an integral");
276 template <
class... Args>
278 requires(std::same_as<Args, enum_type>&&...) :
299 [[nodiscard]]
explicit constexpr
operator bool() const noexcept {
return _impl !=
static_cast<underlying_type>(0); }
305 template <
class... Args>
307 requires(std::same_as<Args, enum_type>&&...)
313 template <
class... Args>
315 requires(std::same_as<Args, enum_type>&&...)
321 template <
class... Args>
322 [[nodiscard]] constexpr
bool any(Args... a_args)
const noexcept
323 requires(std::same_as<Args, enum_type>&&...)
328 template <
class... Args>
329 [[nodiscard]] constexpr
bool all(Args... a_args)
const noexcept
330 requires(std::same_as<Args, enum_type>&&...)
335 template <
class... Args>
336 [[nodiscard]] constexpr
bool none(Args... a_args)
const noexcept
337 requires(std::same_as<Args, enum_type>&&...)
343 underlying_type _impl{ 0 };
346 template <
class... Args>
348 std::common_type_t<Args...>,
349 std::underlying_type_t<
350 std::common_type_t<Args...>>>;
354 #define SKSE_MAKE_LOGICAL_OP(a_op, a_result) \
355 template <class E, class U1, class U2> \
356 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
358 return a_lhs.get() a_op a_rhs.get(); \
361 template <class E, class U> \
362 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
364 return a_lhs.get() a_op a_rhs; \
367 #define SKSE_MAKE_ARITHMETIC_OP(a_op) \
368 template <class E, class U> \
369 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_enum, U a_shift) noexcept \
370 ->enumeration<E, U> \
372 return static_cast<E>(static_cast<U>(a_enum.get()) a_op a_shift); \
375 template <class E, class U> \
376 constexpr auto operator a_op##=(enumeration<E, U>& a_enum, U a_shift) noexcept \
377 ->enumeration<E, U>& \
379 return a_enum = a_enum a_op a_shift; \
382 #define SKSE_MAKE_ENUMERATION_OP(a_op) \
383 template <class E, class U1, class U2> \
384 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
385 ->enumeration<E, std::common_type_t<U1, U2>> \
387 return static_cast<E>(static_cast<U1>(a_lhs.get()) a_op static_cast<U2>(a_rhs.get())); \
390 template <class E, class U> \
391 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
392 ->enumeration<E, U> \
394 return static_cast<E>(static_cast<U>(a_lhs.get()) a_op static_cast<U>(a_rhs)); \
397 template <class E, class U> \
398 [[nodiscard]] constexpr auto operator a_op(E a_lhs, enumeration<E, U> a_rhs) noexcept \
399 ->enumeration<E, U> \
401 return static_cast<E>(static_cast<U>(a_lhs) a_op static_cast<U>(a_rhs.get())); \
404 template <class E, class U1, class U2> \
405 constexpr auto operator a_op##=(enumeration<E, U1>& a_lhs, enumeration<E, U2> a_rhs) noexcept \
406 ->enumeration<E, U1>& \
408 return a_lhs = a_lhs a_op a_rhs; \
411 template <class E, class U> \
412 constexpr auto operator a_op##=(enumeration<E, U>& a_lhs, E a_rhs) noexcept \
413 ->enumeration<E, U>& \
415 return a_lhs = a_lhs a_op a_rhs; \
418 template <class E, class U> \
419 constexpr auto operator a_op##=(E& a_lhs, enumeration<E, U> a_rhs) noexcept \
422 return a_lhs = *(a_lhs a_op a_rhs); \
425 #define SKSE_MAKE_INCREMENTER_OP(a_op) \
426 template <class E, class U> \
427 constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs) noexcept \
428 ->enumeration<E, U>& \
430 return a_lhs a_op## = static_cast<E>(1); \
433 template <class E, class U> \
434 [[nodiscard]] constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs, int) noexcept \
435 ->enumeration<E, U> \
437 const auto tmp = a_lhs; \
452 return static_cast<E
>(~static_cast<U>(a_enum.get()));
478 using super = std::atomic_ref<T>;
483 explicit atomic_ref(
volatile T& a_obj) noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
488 using super::operator=;
515 [[nodiscard]] constexpr
operator std::ptrdiff_t() const noexcept {
return value; }
517 [[nodiscard]] constexpr std::ptrdiff_t
operator()() const noexcept {
return value; }
519 static constexpr
auto value =
static_cast<std::ptrdiff_t
>(
sizeof(T));
525 template <
class T,
class U>
528 auto addr = a_ptr ?
reinterpret_cast<std::uintptr_t
>(a_ptr) + a_adjust : 0;
529 if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
530 return reinterpret_cast<std::add_cv_t<T>*
>(addr);
531 }
else if constexpr (std::is_const_v<U>) {
532 return reinterpret_cast<std::add_const_t<T>*
>(addr);
533 }
else if constexpr (std::is_volatile_v<U>) {
534 return reinterpret_cast<std::add_volatile_t<T>*
>(addr);
536 return reinterpret_cast<T*
>(addr);
541 void memzero(
volatile T* a_ptr, std::size_t a_size =
sizeof(T))
543 const auto begin =
reinterpret_cast<volatile char*
>(a_ptr);
544 constexpr
char val{ 0 };
545 std::fill_n(begin, a_size, val);
548 template <
class... Args>
550 requires(std::same_as<std::remove_cv_t<Args>,
bool>&&...)
552 constexpr
auto ARGC =
sizeof...(Args);
554 std::bitset<ARGC> bits;
556 ((bits[i++] = a_args), ...);
558 if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
559 return bits.to_ulong();
560 }
else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
561 return bits.to_ullong();
563 static_assert(
false &&
sizeof...(Args));
568 -> std::optional<std::wstring>
570 const auto cvt = [&](
wchar_t* a_dst, std::size_t a_length) {
575 static_cast<int>(a_in.length()),
577 static_cast<int>(a_length));
580 const auto len = cvt(
nullptr, 0);
585 std::wstring out(len,
'\0');
586 if (cvt(out.data(), out.length()) == 0) {
594 -> std::optional<std::string>
596 const auto cvt = [&](
char* a_dst, std::size_t a_length) {
601 static_cast<int>(a_in.length()),
603 static_cast<int>(a_length),
608 const auto len = cvt(
nullptr, 0);
614 if (cvt(out.data(), out.length()) == 0) {
621 [[noreturn]]
inline void report_and_fail(std::string_view a_msg, std::source_location a_loc = std::source_location::current())
623 const auto body = [&]() {
624 const std::filesystem::path p = a_loc.file_name();
625 auto filename = p.lexically_normal().generic_string();
627 const std::regex r{ R
"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
629 if (std::regex_search(filename, matches, r)) {
630 filename = matches[1].str();
639 .value_or(L
"<character encoding error>"s);
642 const auto caption = []() {
644 std::vector<wchar_t> buf;
645 buf.reserve(maxPath);
646 buf.resize(maxPath / 2);
647 std::uint32_t result = 0;
649 buf.resize(buf.size() * 2);
653 static_cast<std::uint32_t
>(buf.size()));
654 }
while (result && result == buf.size() && buf.size() <= std::numeric_limits<std::uint32_t>::max());
656 if (result && result != buf.size()) {
657 std::filesystem::path p(buf.begin(), buf.begin() + result);
658 return p.filename().native();
667 static_cast<int>(a_loc.line()),
668 a_loc.function_name() },
669 spdlog::level::critical,
671 WinAPI::MessageBox(
nullptr, body.c_str(), (caption.empty() ?
nullptr : caption.c_str()), 0);
675 template <
class Enum>
679 return static_cast<std::underlying_type_t<Enum>
>(a_val);
682 template <
class To,
class From>
685 if constexpr (std::is_same_v<
686 std::remove_cv_t<From>,
687 std::remove_cv_t<To>>) {
691 }
else if constexpr (std::is_reference_v<From>) {
692 return stl::unrestricted_cast<To>(std::addressof(a_from));
695 }
else if constexpr (std::is_reference_v<To>) {
698 std::remove_reference_t<To>>>(a_from);
701 }
else if constexpr (std::is_pointer_v<From> &&
702 std::is_pointer_v<To>) {
703 return static_cast<To
>(
705 static_cast<const volatile void*
>(a_from)));
706 }
else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
707 (std::is_integral_v<From> && std::is_pointer_v<To>)) {
708 return reinterpret_cast<To
>(a_from);
712 std::remove_cv_t<std::remove_reference_t<From>> from;
713 std::remove_cv_t<std::remove_reference_t<To>> to;
716 from = std::forward<From>(a_from);
723 #undef SKSE_MAKE_INCREMENTER_OP
724 #undef SKSE_MAKE_ENUMERATION_OP
725 #undef SKSE_MAKE_ARITHMETIC_OP
726 #undef SKSE_MAKE_LOGICAL_OP
730 using namespace std::literals;
737 using namespace std::literals;
typename super::value_type value_type
Definition: PCH.h:481
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition: PCH.h:483
Underlying underlying_type
Definition: PCH.h:260
constexpr enum_type operator*() const noexcept
Definition: PCH.h:301
constexpr bool none(Args... a_args) const noexcept requires(std
Definition: PCH.h:336
constexpr enumeration(Args... a_values) noexcept requires(std
Definition: PCH.h:277
Enum enum_type
Definition: PCH.h:259
constexpr enumeration & operator=(enum_type a_value) noexcept
Definition: PCH.h:293
constexpr bool all(Args... a_args) const noexcept requires(std
Definition: PCH.h:329
~enumeration() noexcept=default
constexpr enumeration & reset(Args... a_args) noexcept requires(std
Definition: PCH.h:314
constexpr enumeration & set(Args... a_args) noexcept requires(std
Definition: PCH.h:306
constexpr underlying_type underlying() const noexcept
Definition: PCH.h:303
constexpr enumeration() noexcept=default
constexpr bool any(Args... a_args) const noexcept requires(std
Definition: PCH.h:322
constexpr enum_type get() const noexcept
Definition: PCH.h:302
Definition: Relocation.h:60
Definition: AbsorbEffect.h:6
std::size_t GetMaxPath() noexcept
void * GetCurrentModule() noexcept
std::uint32_t GetModuleFileName(void *a_module, char *a_filename, std::uint32_t a_size) 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)
std::int32_t MessageBox(void *a_wnd, const char *a_text, const char *a_caption, unsigned int a_type) noexcept
constexpr auto CP_UTF8
Definition: WinAPI.h:5
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 * GetCurrentProcess() noexcept
void TerminateProcess(void *a_process, unsigned int a_exitCode) noexcept
string(const CharT(&)[N]) -> string< CharT, N - 1 >
atomic_ref(volatile T &) -> atomic_ref< T >
T not_null
Definition: PCH.h:99
SKSE_MAKE_ENUMERATION_OP(<<)
constexpr auto to_underlying(Enum a_val) noexcept requires(std
Definition: PCH.h:676
To unrestricted_cast(From a_from) noexcept
Definition: PCH.h:683
std::basic_string_view< CharT > basic_zstring
Definition: PCH.h:75
void memzero(volatile T *a_ptr, std::size_t a_size=sizeof(T))
Definition: PCH.h:541
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:621
scope_exit(EF) -> scope_exit< EF >
T owner
Definition: PCH.h:85
T observer
Definition: PCH.h:92
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:593
SKSE_MAKE_INCREMENTER_OP(+)
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition: PCH.h:526
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:567
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:190
SKSE_MAKE_LOGICAL_OP(==, bool)
basic_zstring< wchar_t > zwstring
Definition: PCH.h:78
constexpr auto operator~(enumeration< E, U > a_enum) noexcept -> enumeration< E, U >
Definition: PCH.h:449
auto pun_bits(Args... a_args) requires(std
Definition: PCH.h:549
SKSE_MAKE_ARITHMETIC_OP(<<)
basic_zstring< char > zstring
Definition: PCH.h:77
enumeration(Args...) -> enumeration< std::common_type_t< Args... >, std::underlying_type_t< std::common_type_t< Args... >>>
constexpr auto ssizeof_v
Definition: PCH.h:523
consteval bool empty() const noexcept
Definition: PCH.h:130
const char_type & const_reference
Definition: PCH.h:110
consteval auto substr() const noexcept
Definition: PCH.h:136
consteval const_reference operator[](size_type a_pos) const noexcept
Definition: PCH.h:122
const char_type * const_pointer
Definition: PCH.h:108
consteval const_pointer data() const noexcept
Definition: PCH.h:129
std::size_t size_type
Definition: PCH.h:111
consteval const_reference back() const noexcept
Definition: PCH.h:128
consteval string(const_pointer a_string) noexcept
Definition: PCH.h:115
char_type & reference
Definition: PCH.h:109
char_type * pointer
Definition: PCH.h:107
consteval size_type length() const noexcept
Definition: PCH.h:132
consteval size_type size() const noexcept
Definition: PCH.h:133
consteval const_reference front() const noexcept
Definition: PCH.h:131
CharT char_type
Definition: PCH.h:106
consteval zstring(const char_type(&a_string)[N]) noexcept
Definition: PCH.h:159
std::size_t size_type
Definition: PCH.h:155
consteval const_pointer data() const noexcept
Definition: PCH.h:173
consteval const_reference back() const noexcept
Definition: PCH.h:172
const char_type * const_pointer
Definition: PCH.h:152
consteval const_reference front() const noexcept
Definition: PCH.h:175
consteval size_type length() const noexcept
Definition: PCH.h:176
const char_type & const_reference
Definition: PCH.h:154
consteval size_type size() const noexcept
Definition: PCH.h:177
CharT char_type
Definition: PCH.h:150
char_type * pointer
Definition: PCH.h:151
char_type & reference
Definition: PCH.h:153
consteval const_reference operator[](size_type a_pos) const noexcept
Definition: PCH.h:166
consteval bool empty() const noexcept
Definition: PCH.h:174
consteval auto substr() const noexcept
Definition: PCH.h:180
constexpr std::ptrdiff_t operator()() const noexcept
Definition: PCH.h:517