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