CommonLibSSE (powerof3)
Loading...
Searching...
No Matches
PCH.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <bit>
6#include <bitset>
7#include <cassert>
8#include <cmath>
9#include <concepts>
10#include <cstdarg>
11#include <cstddef>
12#include <cstdint>
13#include <cstdio>
14#include <cstdlib>
15#include <cstring>
16#include <ctime>
17#include <cwchar>
18#include <cwctype>
19#include <exception>
20#include <execution>
21#include <filesystem>
22#include <format>
23#include <fstream>
24#include <functional>
25#include <intrin.h>
26#include <iomanip>
27#include <ios>
28#include <istream>
29#include <iterator>
30#include <limits>
31#include <locale>
32#include <map>
33#include <memory>
34#include <mutex>
35#include <new>
36#include <numeric>
37#include <optional>
38#include <random>
39#include <ranges>
40#include <regex>
41#include <set>
42#include <source_location>
43#include <span>
44#include <sstream>
45#include <stack>
46#include <stdexcept>
47#include <string>
48#include <string_view>
49#include <system_error>
50#include <thread>
51#include <tuple>
52#include <type_traits>
53#include <typeinfo>
54#include <utility>
55#include <variant>
56#include <vector>
57
58static_assert(
59 std::is_integral_v<std::time_t> && sizeof(std::time_t) == sizeof(std::size_t),
60 "wrap std::time_t instead");
61
62#include "REX/REX/Enum.h"
63#include "REX/REX/EnumSet.h"
64#include "REX/W32/KERNEL32.h"
65#include "REX/W32/USER32.h"
66
67#pragma warning(push)
68#include <binary_io/file_stream.hpp>
69#include <spdlog/spdlog.h>
70#pragma warning(pop)
71
72namespace SKSE
73{
74 using namespace std::literals;
75
76 namespace stl
77 {
78 template <class CharT>
79 using basic_zstring = std::basic_string_view<CharT>;
80
83
84 // owning pointer
85 template <
86 class T,
87 class = std::enable_if_t<
88 std::is_pointer_v<T>>>
89 using owner = T;
90
91 // non-owning pointer
92 template <
93 class T,
94 class = std::enable_if_t<
95 std::is_pointer_v<T>>>
96 using observer = T;
97
98 // non-null pointer
99 template <
100 class T,
101 class = std::enable_if_t<
102 std::is_pointer_v<T>>>
103 using not_null = T;
104
105 namespace nttp
106 {
107 template <class CharT, std::size_t N>
108 struct string
109 {
110 using char_type = CharT;
112 using const_pointer = const char_type*;
115 using size_type = std::size_t;
116
117 static constexpr auto npos = static_cast<std::size_t>(-1);
118
119 consteval string(const_pointer a_string) noexcept
120 {
121 for (size_type i = 0; i < N; ++i) {
122 c[i] = a_string[i];
123 }
124 }
125
126 [[nodiscard]] consteval const_reference operator[](size_type a_pos) const noexcept
127 {
128 assert(a_pos < N);
129 return c[a_pos];
130 }
131
132 [[nodiscard]] consteval const_reference back() const noexcept { return (*this)[size() - 1]; }
133 [[nodiscard]] consteval const_pointer data() const noexcept { return c; }
134 [[nodiscard]] consteval bool empty() const noexcept { return this->size() == 0; }
135 [[nodiscard]] consteval const_reference front() const noexcept { return (*this)[0]; }
136 [[nodiscard]] consteval size_type length() const noexcept { return N; }
137 [[nodiscard]] consteval size_type size() const noexcept { return length(); }
138
139 template <std::size_t POS = 0, std::size_t COUNT = npos>
140 [[nodiscard]] consteval auto substr() const noexcept
141 {
142 return string < CharT, COUNT != npos ? COUNT : N - POS > (this->data() + POS);
143 }
144
145 char_type c[N] = {};
146 };
147
148 template <class CharT, std::size_t N>
149 string(const CharT (&)[N]) -> string<CharT, N - 1>;
150 }
151
152 template <class EF>
153 requires(std::invocable<std::remove_reference_t<EF>>)
155 {
156 public:
157 // 1)
158 template <class Fn>
159 explicit scope_exit(Fn&& a_fn) noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
160 std::is_nothrow_constructible_v<EF, Fn&>) //
161 requires(!std::is_same_v<std::remove_cvref_t<Fn>, scope_exit> &&
162 std::is_constructible_v<EF, Fn>)
163 {
164 static_assert(std::invocable<Fn>);
165
166 if constexpr (!std::is_lvalue_reference_v<Fn> &&
167 std::is_nothrow_constructible_v<EF, Fn>) {
168 _fn.emplace(std::forward<Fn>(a_fn));
169 } else {
170 _fn.emplace(a_fn);
171 }
172 }
173
174 // 2)
175 scope_exit(scope_exit&& a_rhs) noexcept(std::is_nothrow_move_constructible_v<EF> ||
176 std::is_nothrow_copy_constructible_v<EF>) //
177 requires(std::is_nothrow_move_constructible_v<EF> ||
178 std::is_copy_constructible_v<EF>)
179 {
180 static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
181 static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
182
183 if (a_rhs.active()) {
184 if constexpr (std::is_nothrow_move_constructible_v<EF>) {
185 _fn.emplace(std::forward<EF>(*a_rhs._fn));
186 } else {
187 _fn.emplace(a_rhs._fn);
188 }
189 a_rhs.release();
190 }
191 }
192
193 // 3)
194 scope_exit(const scope_exit&) = delete;
195
196 ~scope_exit() noexcept
197 {
198 if (_fn.has_value()) {
199 (*_fn)();
200 }
201 }
202
203 void release() noexcept { _fn.reset(); }
204
205 private:
206 [[nodiscard]] bool active() const noexcept { return _fn.has_value(); }
207
208 std::optional<std::remove_reference_t<EF>> _fn;
209 };
210
211 template <class EF>
213
214 // backwards compat
215 template <
216 class E,
217 class U = std::underlying_type_t<E>>
218 class enumeration : public REX::EnumSet<E, U>
219 {
221
222 public:
223 using enum_type = E;
225
226 using super::super;
227 using super::operator=;
228 using super::operator*;
229 };
230
231 template <class... Args>
233 std::common_type_t<Args...>,
234 std::underlying_type_t<
235 std::common_type_t<Args...>>>;
236 }
237}
238
239namespace SKSE
240{
241 namespace stl
242 {
243 template <class T>
245 public std::atomic_ref<T>
246 {
247 private:
248 using super = std::atomic_ref<T>;
249
250 public:
251 using value_type = typename super::value_type;
252
253 explicit atomic_ref(volatile T& a_obj) noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
254 super(const_cast<value_type&>(a_obj))
255 {}
256
257 using super::super;
258 using super::operator=;
259 };
260
261 template <class T>
262 atomic_ref(volatile T&) -> atomic_ref<T>;
263
264 template class atomic_ref<std::int8_t>;
265 template class atomic_ref<std::uint8_t>;
266 template class atomic_ref<std::int16_t>;
267 template class atomic_ref<std::uint16_t>;
268 template class atomic_ref<std::int32_t>;
269 template class atomic_ref<std::uint32_t>;
270 template class atomic_ref<std::int64_t>;
271 template class atomic_ref<std::uint64_t>;
272
281
282 template <class T>
283 struct ssizeof
284 {
285 [[nodiscard]] constexpr operator std::ptrdiff_t() const noexcept { return value; }
286
287 [[nodiscard]] constexpr std::ptrdiff_t operator()() const noexcept { return value; }
288
289 static constexpr auto value = static_cast<std::ptrdiff_t>(sizeof(T));
290 };
291
292 template <class T>
293 inline constexpr auto ssizeof_v = ssizeof<T>::value;
294
295 template <class T, class U>
296 [[nodiscard]] auto adjust_pointer(U* a_ptr, std::ptrdiff_t a_adjust) noexcept
297 {
298 auto addr = a_ptr ? reinterpret_cast<std::uintptr_t>(a_ptr) + a_adjust : 0;
299 if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
300 return reinterpret_cast<std::add_cv_t<T>*>(addr);
301 } else if constexpr (std::is_const_v<U>) {
302 return reinterpret_cast<std::add_const_t<T>*>(addr);
303 } else if constexpr (std::is_volatile_v<U>) {
304 return reinterpret_cast<std::add_volatile_t<T>*>(addr);
305 } else {
306 return reinterpret_cast<T*>(addr);
307 }
308 }
309
310 template <class T>
311 void emplace_vtable(T* a_ptr)
312 {
313 reinterpret_cast<std::uintptr_t*>(a_ptr)[0] = T::VTABLE[0].address();
314 }
315
316 template <class T>
317 void memzero(volatile T* a_ptr, std::size_t a_size = sizeof(T))
318 {
319 const auto begin = reinterpret_cast<volatile char*>(a_ptr);
320 constexpr char val{ 0 };
321 std::fill_n(begin, a_size, val);
322 }
323
324 template <class... Args>
325 [[nodiscard]] inline auto pun_bits(Args... a_args) //
326 requires(std::same_as<std::remove_cv_t<Args>, bool> && ...)
327 {
328 constexpr auto ARGC = sizeof...(Args);
329
330 std::bitset<ARGC> bits;
331 std::size_t i = 0;
332 ((bits[i++] = a_args), ...);
333
334 if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
335 return bits.to_ulong();
336 } else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
337 return bits.to_ullong();
338 } else {
339 static_assert(false && sizeof...(Args));
340 }
341 }
342
343 [[nodiscard]] inline auto utf8_to_utf16(std::string_view a_in) noexcept
344 -> std::optional<std::wstring>
345 {
346 const auto cvt = [&](wchar_t* a_dst, std::size_t a_length) {
349 0,
350 a_in.data(),
351 static_cast<int>(a_in.length()),
352 a_dst,
353 static_cast<int>(a_length));
354 };
355
356 const auto len = cvt(nullptr, 0);
357 if (len == 0) {
358 return std::nullopt;
359 }
360
361 std::wstring out(len, '\0');
362 if (cvt(out.data(), out.length()) == 0) {
363 return std::nullopt;
364 }
365
366 return out;
367 }
368
369 [[nodiscard]] inline auto utf16_to_utf8(std::wstring_view a_in) noexcept
370 -> std::optional<std::string>
371 {
372 const auto cvt = [&](char* a_dst, std::size_t a_length) {
375 0,
376 a_in.data(),
377 static_cast<int>(a_in.length()),
378 a_dst,
379 static_cast<int>(a_length),
380 nullptr,
381 nullptr);
382 };
383
384 const auto len = cvt(nullptr, 0);
385 if (len == 0) {
386 return std::nullopt;
387 }
388
389 std::string out(len, '\0');
390 if (cvt(out.data(), out.length()) == 0) {
391 return std::nullopt;
392 }
393
394 return out;
395 }
396
397 [[noreturn]] inline void report_and_fail(std::string_view a_msg, std::source_location a_loc = std::source_location::current())
398 {
399 const auto body = [&]() {
400 const std::filesystem::path p = a_loc.file_name();
401 auto filename = p.lexically_normal().generic_string();
402
403 const std::regex r{ R"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
404 std::smatch matches;
405 if (std::regex_search(filename, matches, r)) {
406 filename = matches[1].str();
407 }
408
409 return utf8_to_utf16(
410 std::format(
411 "{}({}): {}"sv,
412 filename,
413 a_loc.line(),
414 a_msg))
415 .value_or(L"<character encoding error>"s);
416 }();
417
418 const auto caption = []() {
419 std::vector<wchar_t> buf;
420 buf.reserve(REX::W32::MAX_PATH);
421 buf.resize(REX::W32::MAX_PATH / 2);
422 std::uint32_t result = 0;
423 do {
424 buf.resize(buf.size() * 2);
427 buf.data(),
428 static_cast<std::uint32_t>(buf.size()));
429 } while (result && result == buf.size() && buf.size() <= std::numeric_limits<std::uint32_t>::max());
430
431 if (result && result != buf.size()) {
432 std::filesystem::path p(buf.begin(), buf.begin() + result);
433 return p.filename().native();
434 } else {
435 return L""s;
436 }
437 }();
438
439 spdlog::log(
440 spdlog::source_loc{
441 a_loc.file_name(),
442 static_cast<int>(a_loc.line()),
443 a_loc.function_name() },
444 spdlog::level::critical,
445 a_msg);
446 REX::W32::MessageBoxW(nullptr, body.c_str(), (caption.empty() ? nullptr : caption.c_str()), 0);
448 }
449
450 template <class To, class From>
451 [[nodiscard]] To unrestricted_cast(From a_from) noexcept
452 {
453 if constexpr (std::is_same_v<
454 std::remove_cv_t<From>,
455 std::remove_cv_t<To>>) {
456 return To{ a_from };
457
458 // From != To
459 } else if constexpr (std::is_reference_v<From>) {
460 return stl::unrestricted_cast<To>(std::addressof(a_from));
461
462 // From: NOT reference
463 } else if constexpr (std::is_reference_v<To>) {
465 std::add_pointer_t<
466 std::remove_reference_t<To>>>(a_from);
467
468 // To: NOT reference
469 } else if constexpr (std::is_pointer_v<From> &&
470 std::is_pointer_v<To>) {
471 return static_cast<To>(
472 const_cast<void*>(
473 static_cast<const volatile void*>(a_from)));
474 } else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
475 (std::is_integral_v<From> && std::is_pointer_v<To>)) {
476 return reinterpret_cast<To>(a_from);
477 } else {
478 union
479 {
480 std::remove_cv_t<std::remove_reference_t<From>> from;
481 std::remove_cv_t<std::remove_reference_t<To>> to;
482 };
483
484 from = std::forward<From>(a_from);
485 return to;
486 }
487 }
488 }
489}
490
491namespace RE
492{
493 using namespace std::literals;
494 namespace stl = SKSE::stl;
495}
496
497namespace REL
498{
499 using namespace std::literals;
500 namespace stl = SKSE::stl;
501}
502
503#ifdef SKYRIM_SUPPORT_AE
504# define RELOCATION_ID(SE, AE) REL::ID(AE)
505#else
506# define RELOCATION_ID(SE, AE) REL::ID(SE)
507#endif
508
509#include "REL/REL.h"
510
511#include "RE/Offsets.h"
512#include "RE/Offsets_NiRTTI.h"
513#include "RE/Offsets_RTTI.h"
514#include "RE/Offsets_VTABLE.h"
515
516#include "RE/B/BSCoreTypes.h"
517#include "RE/S/SFTypes.h"
Definition EnumSet.h:9
Definition PCH.h:246
typename super::value_type value_type
Definition PCH.h:251
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition PCH.h:253
Definition PCH.h:219
U underlying_type
Definition PCH.h:224
E enum_type
Definition PCH.h:223
Definition PCH.h:155
scope_exit(Fn &&a_fn) noexcept(std::is_nothrow_constructible_v< EF, Fn >||std::is_nothrow_constructible_v< EF, Fn & >)
Definition PCH.h:159
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:175
~scope_exit() noexcept
Definition PCH.h:196
void release() noexcept
Definition PCH.h:203
Definition ID.h:6
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:35
std::uint32_t GetModuleFileNameW(HMODULE a_module, wchar_t *a_name, std::uint32_t a_nameLen) noexcept
HANDLE GetCurrentProcess() noexcept
Definition AbsorbEffect.h:6
Definition PCH.h:77
T not_null
Definition PCH.h:103
To unrestricted_cast(From a_from) noexcept
Definition PCH.h:451
std::basic_string_view< CharT > basic_zstring
Definition PCH.h:79
void memzero(volatile T *a_ptr, std::size_t a_size=sizeof(T))
Definition PCH.h:317
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition PCH.h:397
T owner
Definition PCH.h:89
T observer
Definition PCH.h:96
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition PCH.h:369
void emplace_vtable(T *a_ptr)
Definition PCH.h:311
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition PCH.h:296
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition PCH.h:343
basic_zstring< wchar_t > zwstring
Definition PCH.h:82
auto pun_bits(Args... a_args)
Definition PCH.h:325
basic_zstring< char > zstring
Definition PCH.h:81
constexpr auto ssizeof_v
Definition PCH.h:293
Definition API.h:14
Definition PCH.h:109
consteval bool empty() const noexcept
Definition PCH.h:134
const char_type & const_reference
Definition PCH.h:114
consteval auto substr() const noexcept
Definition PCH.h:140
consteval const_reference operator[](size_type a_pos) const noexcept
Definition PCH.h:126
const char_type * const_pointer
Definition PCH.h:112
consteval const_pointer data() const noexcept
Definition PCH.h:133
std::size_t size_type
Definition PCH.h:115
char_type c[N]
Definition PCH.h:145
consteval const_reference back() const noexcept
Definition PCH.h:132
consteval string(const_pointer a_string) noexcept
Definition PCH.h:119
char_type & reference
Definition PCH.h:113
char_type * pointer
Definition PCH.h:111
static constexpr auto npos
Definition PCH.h:117
consteval size_type length() const noexcept
Definition PCH.h:136
consteval size_type size() const noexcept
Definition PCH.h:137
consteval const_reference front() const noexcept
Definition PCH.h:135
CharT char_type
Definition PCH.h:110
Definition PCH.h:284
constexpr std::ptrdiff_t operator()() const noexcept
Definition PCH.h:287