41 #include <source_location>
47 #include <string_view>
48 #include <system_error>
51 #include <type_traits>
58 std::is_integral_v<std::time_t> &&
sizeof(std::time_t) ==
sizeof(std::size_t),
59 "wrap std::time_t instead");
62 #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);
136 [[nodiscard]] consteval
bool empty() const noexcept {
return this->size() == 0; }
139 [[nodiscard]] consteval
size_type size() const noexcept {
return length(); }
141 template <std::
size_t POS = 0, std::
size_t COUNT = npos>
142 [[nodiscard]] consteval
auto substr() const noexcept
144 return string < CharT, COUNT != npos ? COUNT : N - POS > (this->data() + POS);
150 template <
class CharT, std::
size_t N>
151 string(
const CharT (&)[N]) ->
string<CharT, N - 1>;
155 requires(std::invocable<std::remove_reference_t<EF>>)
162 noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
163 std::is_nothrow_constructible_v<EF, Fn&>)
165 std::is_constructible_v<EF, Fn>)
167 static_assert(std::invocable<Fn>);
169 if constexpr (!std::is_lvalue_reference_v<Fn> &&
170 std::is_nothrow_constructible_v<EF, Fn>) {
171 _fn.emplace(std::forward<Fn>(a_fn));
179 noexcept(std::is_nothrow_move_constructible_v<EF> ||
180 std::is_nothrow_copy_constructible_v<EF>)
181 requires(std::is_nothrow_move_constructible_v<EF> ||
182 std::is_copy_constructible_v<EF>)
184 static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
185 static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
187 if (a_rhs.active()) {
188 if constexpr (std::is_nothrow_move_constructible_v<EF>) {
189 _fn.emplace(std::forward<EF>(*a_rhs._fn));
191 _fn.emplace(a_rhs._fn);
202 if (_fn.has_value()) {
207 void release() noexcept { _fn.reset(); }
210 [[nodiscard]]
bool active()
const noexcept {
return _fn.has_value(); }
212 std::optional<std::remove_reference_t<EF>> _fn;
220 class Underlying = std::underlying_type_t<Enum>>
227 static_assert(std::is_enum_v<enum_type>,
"enum_type must be an enum");
228 static_assert(std::is_integral_v<underlying_type>,
"underlying_type must be an integral");
241 template <
class... Args>
243 requires(std::same_as<Args, enum_type> && ...)
265 [[nodiscard]]
explicit constexpr
operator bool() const noexcept {
return _impl !=
static_cast<underlying_type>(0); }
271 template <
class... Args>
273 requires(std::same_as<Args, enum_type> && ...)
279 template <
class... Args>
281 requires(std::same_as<Args, enum_type> && ...)
287 template <
class... Args>
288 [[nodiscard]] constexpr
bool any(Args... a_args)
const noexcept
289 requires(std::same_as<Args, enum_type> && ...)
294 template <
class... Args>
295 [[nodiscard]] constexpr
bool all(Args... a_args)
const noexcept
296 requires(std::same_as<Args, enum_type> && ...)
301 template <
class... Args>
302 [[nodiscard]] constexpr
bool none(Args... a_args)
const noexcept
303 requires(std::same_as<Args, enum_type> && ...)
309 underlying_type _impl{ 0 };
312 template <
class... Args>
314 std::common_type_t<Args...>,
315 std::underlying_type_t<
316 std::common_type_t<Args...>>>;
320 #define SKSE_MAKE_LOGICAL_OP(a_op, a_result) \
321 template <class E, class U1, class U2> \
322 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
324 return a_lhs.get() a_op a_rhs.get(); \
327 template <class E, class U> \
328 [[nodiscard]] constexpr a_result operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
330 return a_lhs.get() a_op a_rhs; \
333 #define SKSE_MAKE_ARITHMETIC_OP(a_op) \
334 template <class E, class U> \
335 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_enum, U a_shift) noexcept \
336 -> enumeration<E, U> \
338 return static_cast<E>(static_cast<U>(a_enum.get()) a_op a_shift); \
341 template <class E, class U> \
342 constexpr auto operator a_op##=(enumeration<E, U>& a_enum, U a_shift) noexcept \
343 -> enumeration<E, U>& \
345 return a_enum = a_enum a_op a_shift; \
348 #define SKSE_MAKE_ENUMERATION_OP(a_op) \
349 template <class E, class U1, class U2> \
350 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U1> a_lhs, enumeration<E, U2> a_rhs) noexcept \
351 -> enumeration<E, std::common_type_t<U1, U2>> \
353 return static_cast<E>(static_cast<U1>(a_lhs.get()) a_op static_cast<U2>(a_rhs.get())); \
356 template <class E, class U> \
357 [[nodiscard]] constexpr auto operator a_op(enumeration<E, U> a_lhs, E a_rhs) noexcept \
358 -> enumeration<E, U> \
360 return static_cast<E>(static_cast<U>(a_lhs.get()) a_op static_cast<U>(a_rhs)); \
363 template <class E, class U> \
364 [[nodiscard]] constexpr auto operator a_op(E a_lhs, enumeration<E, U> a_rhs) noexcept \
365 -> enumeration<E, U> \
367 return static_cast<E>(static_cast<U>(a_lhs) a_op static_cast<U>(a_rhs.get())); \
370 template <class E, class U1, class U2> \
371 constexpr auto operator a_op##=(enumeration<E, U1>& a_lhs, enumeration<E, U2> a_rhs) noexcept \
372 -> enumeration<E, U1>& \
374 return a_lhs = a_lhs a_op a_rhs; \
377 template <class E, class U> \
378 constexpr auto operator a_op##=(enumeration<E, U>& a_lhs, E a_rhs) noexcept \
379 -> enumeration<E, U>& \
381 return a_lhs = a_lhs a_op a_rhs; \
384 template <class E, class U> \
385 constexpr auto operator a_op##=(E& a_lhs, enumeration<E, U> a_rhs) noexcept \
388 return a_lhs = *(a_lhs a_op a_rhs); \
391 #define SKSE_MAKE_INCREMENTER_OP(a_op) \
392 template <class E, class U> \
393 constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs) noexcept \
394 -> enumeration<E, U>& \
396 return a_lhs a_op## = static_cast<E>(1); \
399 template <class E, class U> \
400 [[nodiscard]] constexpr auto operator a_op##a_op(enumeration<E, U>& a_lhs, int) noexcept \
401 -> enumeration<E, U> \
403 const auto tmp = a_lhs; \
418 return static_cast<E
>(~static_cast<U>(a_enum.get()));
444 using super = std::atomic_ref<T>;
449 explicit atomic_ref(
volatile T& a_obj) noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
454 using super::operator=;
481 [[nodiscard]] constexpr
operator std::ptrdiff_t() const noexcept {
return value; }
483 [[nodiscard]] constexpr std::ptrdiff_t
operator()() const noexcept {
return value; }
485 static constexpr
auto value =
static_cast<std::ptrdiff_t
>(
sizeof(T));
491 template <
class T,
class U>
494 auto addr = a_ptr ?
reinterpret_cast<std::uintptr_t
>(a_ptr) + a_adjust : 0;
495 if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
496 return reinterpret_cast<std::add_cv_t<T>*
>(addr);
497 }
else if constexpr (std::is_const_v<U>) {
498 return reinterpret_cast<std::add_const_t<T>*
>(addr);
499 }
else if constexpr (std::is_volatile_v<U>) {
500 return reinterpret_cast<std::add_volatile_t<T>*
>(addr);
502 return reinterpret_cast<T*
>(addr);
509 auto address = T::VTABLE[0].address();
513 reinterpret_cast<std::uintptr_t*
>(a_ptr)[0] = address;
518 void memzero(
volatile T* a_ptr, std::size_t a_size =
sizeof(T))
520 const auto begin =
reinterpret_cast<volatile char*
>(a_ptr);
521 constexpr
char val{ 0 };
522 std::fill_n(begin, a_size, val);
525 template <
class... Args>
527 requires(std::same_as<std::remove_cv_t<Args>,
bool> && ...)
529 constexpr
auto ARGC =
sizeof...(Args);
531 std::bitset<ARGC> bits;
533 ((bits[i++] = a_args), ...);
535 if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
536 return bits.to_ulong();
537 }
else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
538 return bits.to_ullong();
540 static_assert(
false &&
sizeof...(Args));
545 -> std::optional<std::wstring>
547 const auto cvt = [&](
wchar_t* a_dst, std::size_t a_length) {
552 static_cast<int>(a_in.length()),
554 static_cast<int>(a_length));
557 const auto len = cvt(
nullptr, 0);
562 std::wstring out(len,
'\0');
563 if (cvt(out.data(), out.length()) == 0) {
571 -> std::optional<std::string>
573 const auto cvt = [&](
char* a_dst, std::size_t a_length) {
578 static_cast<int>(a_in.length()),
580 static_cast<int>(a_length),
585 const auto len = cvt(
nullptr, 0);
591 if (cvt(out.data(), out.length()) == 0) {
599 std::source_location a_loc = std::source_location::current())
601 const auto body = [&]() -> std::wstring {
602 const std::filesystem::path p = a_loc.file_name();
603 auto filename = p.lexically_normal().generic_string();
605 const std::regex r{ R
"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
607 if (std::regex_search(filename, matches, r)) {
608 filename = matches[1].str();
617 .value_or(L
"<character encoding error>"s);
620 const auto caption = []() {
621 std::vector<wchar_t> buf;
624 std::uint32_t result = 0;
626 buf.resize(buf.size() * 2);
630 static_cast<std::uint32_t
>(buf.size()));
633 if (result && result != buf.size()) {
634 std::filesystem::path p(buf.begin(), buf.begin() + result);
635 return p.filename().native();
644 static_cast<int>(a_loc.line()),
645 a_loc.function_name() },
646 spdlog::level::critical,
650 #ifdef ENABLE_COMMONLIBSSE_TESTING
651 throw std::runtime_error(
utf16_to_utf8(caption.empty() ? body.c_str() : caption.c_str())->c_str());
661 std::source_location a_loc = std::source_location::current())
666 template <
class To,
class From>
669 if constexpr (std::is_same_v<
670 std::remove_cv_t<From>,
671 std::remove_cv_t<To>>) {
675 }
else if constexpr (std::is_reference_v<From>) {
676 return stl::unrestricted_cast<To>(std::addressof(a_from));
679 }
else if constexpr (std::is_reference_v<To>) {
682 std::remove_reference_t<To>>>(a_from);
685 }
else if constexpr (std::is_pointer_v<From> &&
686 std::is_pointer_v<To>) {
687 return static_cast<To
>(
689 static_cast<const volatile void*
>(a_from)));
690 }
else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
691 (std::is_integral_v<From> && std::is_pointer_v<To>)) {
692 return reinterpret_cast<To
>(a_from);
696 std::remove_cv_t<std::remove_reference_t<From>> from;
697 std::remove_cv_t<std::remove_reference_t<To>> to;
700 from = std::forward<From>(a_from);
707 #undef SKSE_MAKE_INCREMENTER_OP
708 #undef SKSE_MAKE_ENUMERATION_OP
709 #undef SKSE_MAKE_ARITHMETIC_OP
710 #undef SKSE_MAKE_LOGICAL_OP
714 using namespace std::literals;
720 using namespace std::literals;
724 #define RELOCATION_ID(a_se, a_ae) REL::RelocationID(a_se, a_ae)
typename super::value_type value_type
Definition: PCH.h:447
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition: PCH.h:449
Underlying underlying_type
Definition: PCH.h:225
constexpr enum_type operator*() const noexcept
Definition: PCH.h:267
constexpr bool none(Args... a_args) const noexcept requires(std
Definition: PCH.h:302
constexpr enumeration(Args... a_values) noexcept requires(std
Definition: PCH.h:242
Enum enum_type
Definition: PCH.h:224
constexpr enumeration & operator=(enum_type a_value) noexcept
Definition: PCH.h:259
constexpr bool all(Args... a_args) const noexcept requires(std
Definition: PCH.h:295
~enumeration() noexcept=default
constexpr enumeration & reset(Args... a_args) noexcept requires(std
Definition: PCH.h:280
constexpr enumeration & set(Args... a_args) noexcept requires(std
Definition: PCH.h:272
constexpr underlying_type underlying() const noexcept
Definition: PCH.h:269
constexpr enumeration() noexcept=default
constexpr bool any(Args... a_args) const noexcept requires(std
Definition: PCH.h:288
constexpr enum_type get() const noexcept
Definition: PCH.h:268
std::int32_t WideCharToMultiByte(std::uint32_t a_codePage, std::uint32_t a_flags, const wchar_t *a_src, std::int32_t a_srcLen, char *a_dst, std::int32_t a_dstLen, const char *a_default, std::int32_t *a_defaultLen)
bool TerminateProcess(HANDLE a_process, std::uint32_t a_exitCode) noexcept
constexpr auto CP_UTF8
Definition: KERNEL32.h:12
std::int32_t MessageBoxW(HWND a_wnd, const wchar_t *a_text, const wchar_t *a_caption, std::uint32_t a_type) noexcept
HMODULE GetCurrentModule() noexcept
std::int32_t MultiByteToWideChar(std::uint32_t a_codePage, std::uint32_t a_flags, const char *a_src, std::int32_t a_srcLen, wchar_t *a_dst, std::int32_t a_dstLen) noexcept
constexpr auto MAX_PATH
Definition: BASE.h:34
std::uint32_t GetModuleFileNameW(HMODULE a_module, wchar_t *a_name, std::uint32_t a_nameLen) noexcept
HANDLE GetCurrentProcess() noexcept
NiColor() max(const NiColor &a_lhs, const NiColor &a_rhs)
Definition: ColorUtil.h:71
Definition: AbsorbEffect.h:6
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(<<)
To unrestricted_cast(From a_from) noexcept
Definition: PCH.h:667
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:518
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:660
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:570
bool emplace_vtable(T *a_ptr)
Definition: PCH.h:507
SKSE_MAKE_INCREMENTER_OP(+)
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition: PCH.h:492
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:544
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:155
bool report_and_error(std::string_view a_msg, bool a_fail=true, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:598
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:415
auto pun_bits(Args... a_args) requires(std
Definition: PCH.h:526
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:489
consteval bool empty() const noexcept
Definition: PCH.h:136
const char_type & const_reference
Definition: PCH.h:110
consteval auto substr() const noexcept
Definition: PCH.h:142
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:135
std::size_t size_type
Definition: PCH.h:111
consteval const_reference back() const noexcept
Definition: PCH.h:134
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:138
consteval char_type value_at(size_type a_pos) const noexcept
Definition: PCH.h:128
consteval size_type size() const noexcept
Definition: PCH.h:139
consteval const_reference front() const noexcept
Definition: PCH.h:137
CharT char_type
Definition: PCH.h:106
constexpr std::ptrdiff_t operator()() const noexcept
Definition: PCH.h:483