38 #include <source_location>
44 #include <string_view>
45 #include <system_error>
48 #include <type_traits>
55 std::is_integral_v<std::time_t> &&
sizeof(std::time_t) ==
sizeof(std::size_t),
56 "wrap std::time_t instead");
59 #include <binary_io/file_stream.hpp>
60 #include <boost/stl_interfaces/iterator_interface.hpp>
61 #include <fmt/format.h>
62 #include <spdlog/spdlog.h>
69 using namespace std::literals;
73 template <
class CharT>
82 class = std::enable_if_t<
83 std::is_pointer_v<T>>>
89 class = std::enable_if_t<
90 std::is_pointer_v<T>>>
96 class = std::enable_if_t<
97 std::is_pointer_v<T>>>
102 template <
class CharT, std::
size_t N>
112 static constexpr
auto npos =
static_cast<std::size_t
>(-1);
129 [[nodiscard]] consteval
bool empty() const noexcept {
return this->size() == 0; }
132 [[nodiscard]] consteval
size_type size() const noexcept {
return length(); }
134 template <std::
size_t POS = 0, std::
size_t COUNT = npos>
135 [[nodiscard]] consteval
auto substr() const noexcept
137 return string < CharT, COUNT != npos ? COUNT : N - POS > (this->data() + POS);
143 template <
class CharT, std::
size_t N>
144 string(
const CharT (&)[N]) ->
string<CharT, N - 1>;
148 requires(std::invocable<std::remove_reference_t<EF>>)
155 noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
156 std::is_nothrow_constructible_v<EF, Fn&>)
158 std::is_constructible_v<EF, Fn>)
160 static_assert(std::invocable<Fn>);
162 if constexpr (!std::is_lvalue_reference_v<Fn> &&
163 std::is_nothrow_constructible_v<EF, Fn>) {
164 _fn.emplace(std::forward<Fn>(a_fn));
172 noexcept(std::is_nothrow_move_constructible_v<EF> ||
173 std::is_nothrow_copy_constructible_v<EF>)
174 requires(std::is_nothrow_move_constructible_v<EF> ||
175 std::is_copy_constructible_v<EF>)
177 static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
178 static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
180 if (a_rhs.active()) {
181 if constexpr (std::is_nothrow_move_constructible_v<EF>) {
182 _fn.emplace(std::forward<EF>(*a_rhs._fn));
184 _fn.emplace(a_rhs._fn);
195 if (_fn.has_value()) {
200 void release() noexcept { _fn.reset(); }
203 [[nodiscard]]
bool active()
const noexcept {
return _fn.has_value(); }
205 std::optional<std::remove_reference_t<EF>> _fn;
213 class Underlying = std::underlying_type_t<Enum>>
220 static_assert(std::is_enum_v<enum_type>,
"enum_type must be an enum");
221 static_assert(std::is_integral_v<underlying_type>,
"underlying_type must be an integral");
234 template <
class... Args>
236 requires(std::same_as<Args, enum_type>&&...) :
257 [[nodiscard]]
explicit constexpr
operator bool() const noexcept {
return _impl !=
static_cast<underlying_type>(0); }
263 template <
class... Args>
265 requires(std::same_as<Args, enum_type>&&...)
271 template <
class... Args>
273 requires(std::same_as<Args, enum_type>&&...)
279 template <
class... Args>
280 [[nodiscard]] constexpr
bool any(Args... a_args)
const noexcept
281 requires(std::same_as<Args, enum_type>&&...)
286 template <
class... Args>
287 [[nodiscard]] constexpr
bool all(Args... a_args)
const noexcept
288 requires(std::same_as<Args, enum_type>&&...)
293 template <
class... Args>
294 [[nodiscard]] constexpr
bool none(Args... a_args)
const noexcept
295 requires(std::same_as<Args, enum_type>&&...)
301 underlying_type _impl{ 0 };
304 template <
class... Args>
306 std::common_type_t<Args...>,
307 std::underlying_type_t<
308 std::common_type_t<Args...>>>;
312 #define SKSE_MAKE_LOGICAL_OP(a_op, a_result) \
313 template <class E, class U1, class U2> \
314 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
316 return a_lhs.get() a_op a_rhs.get(); \
319 template <class E, class U> \
320 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
322 return a_lhs.get() a_op a_rhs; \
325 #define SKSE_MAKE_ARITHMETIC_OP(a_op) \
326 template <class E, class U> \
327 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_enum, U a_shift) noexcept \
328 ->enumeration<E, U> \
330 return static_cast<E>(static_cast<U>(a_enum.get()) a_op a_shift); \
333 template <class E, class U> \
334 constexpr auto operator a_op##=(enumeration<E, U>& a_enum, U a_shift) noexcept \
335 ->enumeration<E, U>& \
337 return a_enum = a_enum a_op a_shift; \
340 #define SKSE_MAKE_ENUMERATION_OP(a_op) \
341 template <class E, class U1, class U2> \
342 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
343 ->enumeration<E, std::common_type_t<U1, U2>> \
345 return static_cast<E>(static_cast<U1>(a_lhs.get()) a_op static_cast<U2>(a_rhs.get())); \
348 template <class E, class U> \
349 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
350 ->enumeration<E, U> \
352 return static_cast<E>(static_cast<U>(a_lhs.get()) a_op static_cast<U>(a_rhs)); \
355 template <class E, class U> \
356 [[nodiscard]] constexpr auto operator a_op(E a_lhs, enumeration<E, U> a_rhs) noexcept \
357 ->enumeration<E, U> \
359 return static_cast<E>(static_cast<U>(a_lhs) a_op static_cast<U>(a_rhs.get())); \
362 template <class E, class U1, class U2> \
363 constexpr auto operator a_op##=(enumeration<E, U1>& a_lhs, enumeration<E, U2> a_rhs) noexcept \
364 ->enumeration<E, U1>& \
366 return a_lhs = a_lhs a_op a_rhs; \
369 template <class E, class U> \
370 constexpr auto operator a_op##=(enumeration<E, U>& a_lhs, E a_rhs) noexcept \
371 ->enumeration<E, U>& \
373 return a_lhs = a_lhs a_op a_rhs; \
376 template <class E, class U> \
377 constexpr auto operator a_op##=(E& a_lhs, enumeration<E, U> a_rhs) noexcept \
380 return a_lhs = *(a_lhs a_op a_rhs); \
383 #define SKSE_MAKE_INCREMENTER_OP(a_op) \
384 template <class E, class U> \
385 constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs) noexcept \
386 ->enumeration<E, U>& \
388 return a_lhs a_op## = static_cast<E>(1); \
391 template <class E, class U> \
392 [[nodiscard]] constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs, int) noexcept \
393 ->enumeration<E, U> \
395 const auto tmp = a_lhs; \
410 return static_cast<E
>(~static_cast<U>(a_enum.get()));
436 using super = std::atomic_ref<T>;
441 explicit atomic_ref(
volatile T& a_obj) noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
446 using super::operator=;
473 [[nodiscard]] constexpr
operator std::ptrdiff_t() const noexcept {
return value; }
475 [[nodiscard]] constexpr std::ptrdiff_t
operator()() const noexcept {
return value; }
477 static constexpr
auto value =
static_cast<std::ptrdiff_t
>(
sizeof(T));
483 template <
class T,
class U>
486 auto addr = a_ptr ?
reinterpret_cast<std::uintptr_t
>(a_ptr) + a_adjust : 0;
487 if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
488 return reinterpret_cast<std::add_cv_t<T>*
>(addr);
489 }
else if constexpr (std::is_const_v<U>) {
490 return reinterpret_cast<std::add_const_t<T>*
>(addr);
491 }
else if constexpr (std::is_volatile_v<U>) {
492 return reinterpret_cast<std::add_volatile_t<T>*
>(addr);
494 return reinterpret_cast<T*
>(addr);
499 void memzero(
volatile T* a_ptr, std::size_t a_size =
sizeof(T))
501 const auto begin =
reinterpret_cast<volatile char*
>(a_ptr);
502 constexpr
char val{ 0 };
503 std::fill_n(begin, a_size, val);
506 template <
class... Args>
508 requires(std::same_as<std::remove_cv_t<Args>,
bool>&&...)
510 constexpr
auto ARGC =
sizeof...(Args);
512 std::bitset<ARGC> bits;
514 ((bits[i++] = a_args), ...);
516 if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
517 return bits.to_ulong();
518 }
else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
519 return bits.to_ullong();
521 static_assert(
false &&
sizeof...(Args));
526 -> std::optional<std::wstring>
528 const auto cvt = [&](
wchar_t* a_dst, std::size_t a_length) {
533 static_cast<int>(a_in.length()),
535 static_cast<int>(a_length));
538 const auto len = cvt(
nullptr, 0);
543 std::wstring out(len,
'\0');
544 if (cvt(out.data(), out.length()) == 0) {
552 -> std::optional<std::string>
554 const auto cvt = [&](
char* a_dst, std::size_t a_length) {
559 static_cast<int>(a_in.length()),
561 static_cast<int>(a_length),
566 const auto len = cvt(
nullptr, 0);
572 if (cvt(out.data(), out.length()) == 0) {
579 [[noreturn]]
inline void report_and_fail(std::string_view a_msg, std::source_location a_loc = std::source_location::current())
581 const auto body = [&]() {
582 const std::filesystem::path p = a_loc.file_name();
583 auto filename = p.lexically_normal().generic_string();
585 const std::regex r{ R
"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
587 if (std::regex_search(filename, matches, r)) {
588 filename = matches[1].str();
597 .value_or(L
"<character encoding error>"s);
600 const auto caption = []() {
602 std::vector<wchar_t> buf;
603 buf.reserve(maxPath);
604 buf.resize(maxPath / 2);
605 std::uint32_t result = 0;
607 buf.resize(buf.size() * 2);
611 static_cast<std::uint32_t
>(buf.size()));
612 }
while (result && result == buf.size() && buf.size() <= std::numeric_limits<std::uint32_t>::max());
614 if (result && result != buf.size()) {
615 std::filesystem::path p(buf.begin(), buf.begin() + result);
616 return p.filename().native();
625 static_cast<int>(a_loc.line()),
626 a_loc.function_name() },
627 spdlog::level::critical,
629 WinAPI::MessageBox(
nullptr, body.c_str(), (caption.empty() ?
nullptr : caption.c_str()), 0);
633 template <
class Enum>
637 return static_cast<std::underlying_type_t<Enum>
>(a_val);
640 template <
class To,
class From>
643 if constexpr (std::is_same_v<
644 std::remove_cv_t<From>,
645 std::remove_cv_t<To>>) {
649 }
else if constexpr (std::is_reference_v<From>) {
650 return stl::unrestricted_cast<To>(std::addressof(a_from));
653 }
else if constexpr (std::is_reference_v<To>) {
656 std::remove_reference_t<To>>>(a_from);
659 }
else if constexpr (std::is_pointer_v<From> &&
660 std::is_pointer_v<To>) {
661 return static_cast<To
>(
663 static_cast<const volatile void*
>(a_from)));
664 }
else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
665 (std::is_integral_v<From> && std::is_pointer_v<To>)) {
666 return reinterpret_cast<To
>(a_from);
670 std::remove_cv_t<std::remove_reference_t<From>> from;
671 std::remove_cv_t<std::remove_reference_t<To>> to;
674 from = std::forward<From>(a_from);
681 #undef SKSE_MAKE_INCREMENTER_OP
682 #undef SKSE_MAKE_ENUMERATION_OP
683 #undef SKSE_MAKE_ARITHMETIC_OP
684 #undef SKSE_MAKE_LOGICAL_OP
688 using namespace std::literals;
695 using namespace std::literals;
typename super::value_type value_type
Definition: PCH.h:439
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition: PCH.h:441
Underlying underlying_type
Definition: PCH.h:218
constexpr enum_type operator*() const noexcept
Definition: PCH.h:259
constexpr bool none(Args... a_args) const noexcept requires(std
Definition: PCH.h:294
constexpr enumeration(Args... a_values) noexcept requires(std
Definition: PCH.h:235
Enum enum_type
Definition: PCH.h:217
constexpr enumeration & operator=(enum_type a_value) noexcept
Definition: PCH.h:251
constexpr bool all(Args... a_args) const noexcept requires(std
Definition: PCH.h:287
~enumeration() noexcept=default
constexpr enumeration & reset(Args... a_args) noexcept requires(std
Definition: PCH.h:272
constexpr enumeration & set(Args... a_args) noexcept requires(std
Definition: PCH.h:264
constexpr underlying_type underlying() const noexcept
Definition: PCH.h:261
constexpr enumeration() noexcept=default
constexpr bool any(Args... a_args) const noexcept requires(std
Definition: PCH.h:280
constexpr enum_type get() const noexcept
Definition: PCH.h:260
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:98
SKSE_MAKE_ENUMERATION_OP(<<)
constexpr auto to_underlying(Enum a_val) noexcept requires(std
Definition: PCH.h:634
To unrestricted_cast(From a_from) noexcept
Definition: PCH.h:641
std::basic_string_view< CharT > basic_zstring
Definition: PCH.h:74
void memzero(volatile T *a_ptr, std::size_t a_size=sizeof(T))
Definition: PCH.h:499
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:579
scope_exit(EF) -> scope_exit< EF >
T owner
Definition: PCH.h:84
T observer
Definition: PCH.h:91
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:551
SKSE_MAKE_INCREMENTER_OP(+)
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition: PCH.h:484
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:525
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:148
SKSE_MAKE_LOGICAL_OP(==, bool)
basic_zstring< wchar_t > zwstring
Definition: PCH.h:77
constexpr auto operator~(enumeration< E, U > a_enum) noexcept -> enumeration< E, U >
Definition: PCH.h:407
auto pun_bits(Args... a_args) requires(std
Definition: PCH.h:507
SKSE_MAKE_ARITHMETIC_OP(<<)
basic_zstring< char > zstring
Definition: PCH.h:76
enumeration(Args...) -> enumeration< std::common_type_t< Args... >, std::underlying_type_t< std::common_type_t< Args... >>>
constexpr auto ssizeof_v
Definition: PCH.h:481
consteval bool empty() const noexcept
Definition: PCH.h:129
const char_type & const_reference
Definition: PCH.h:109
consteval auto substr() const noexcept
Definition: PCH.h:135
consteval const_reference operator[](size_type a_pos) const noexcept
Definition: PCH.h:121
const char_type * const_pointer
Definition: PCH.h:107
consteval const_pointer data() const noexcept
Definition: PCH.h:128
std::size_t size_type
Definition: PCH.h:110
consteval const_reference back() const noexcept
Definition: PCH.h:127
consteval string(const_pointer a_string) noexcept
Definition: PCH.h:114
char_type & reference
Definition: PCH.h:108
char_type * pointer
Definition: PCH.h:106
consteval size_type length() const noexcept
Definition: PCH.h:131
consteval size_type size() const noexcept
Definition: PCH.h:132
consteval const_reference front() const noexcept
Definition: PCH.h:130
CharT char_type
Definition: PCH.h:105
constexpr std::ptrdiff_t operator()() const noexcept
Definition: PCH.h:475