CommonLibSSE (powerof3)
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 
58 static_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 
72 namespace 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;
111  using pointer = char_type*;
112  using const_pointer = const char_type*;
114  using const_reference = 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>>) class scope_exit
154  {
155  public:
156  // 1)
157  template <class Fn>
158  explicit scope_exit(Fn&& a_fn) noexcept(std::is_nothrow_constructible_v<EF, Fn> ||
159  std::is_nothrow_constructible_v<EF, Fn&>) //
160  requires(!std::is_same_v<std::remove_cvref_t<Fn>, scope_exit> &&
161  std::is_constructible_v<EF, Fn>)
162  {
163  static_assert(std::invocable<Fn>);
164 
165  if constexpr (!std::is_lvalue_reference_v<Fn> &&
166  std::is_nothrow_constructible_v<EF, Fn>) {
167  _fn.emplace(std::forward<Fn>(a_fn));
168  } else {
169  _fn.emplace(a_fn);
170  }
171  }
172 
173  // 2)
174  scope_exit(scope_exit&& a_rhs) noexcept(std::is_nothrow_move_constructible_v<EF> ||
175  std::is_nothrow_copy_constructible_v<EF>) //
176  requires(std::is_nothrow_move_constructible_v<EF> ||
177  std::is_copy_constructible_v<EF>)
178  {
179  static_assert(!(std::is_nothrow_move_constructible_v<EF> && !std::is_move_constructible_v<EF>));
180  static_assert(!(!std::is_nothrow_move_constructible_v<EF> && !std::is_copy_constructible_v<EF>));
181 
182  if (a_rhs.active()) {
183  if constexpr (std::is_nothrow_move_constructible_v<EF>) {
184  _fn.emplace(std::forward<EF>(*a_rhs._fn));
185  } else {
186  _fn.emplace(a_rhs._fn);
187  }
188  a_rhs.release();
189  }
190  }
191 
192  // 3)
193  scope_exit(const scope_exit&) = delete;
194 
195  ~scope_exit() noexcept
196  {
197  if (_fn.has_value()) {
198  (*_fn)();
199  }
200  }
201 
202  void release() noexcept { _fn.reset(); }
203 
204  private:
205  [[nodiscard]] bool active() const noexcept { return _fn.has_value(); }
206 
207  std::optional<std::remove_reference_t<EF>> _fn;
208  };
209 
210  template <class EF>
211  scope_exit(EF) -> scope_exit<EF>;
212 
213  // backwards compat
214  template <
215  class E,
216  class U = std::underlying_type_t<E>>
217  class enumeration : public REX::EnumSet<E, U>
218  {
219  using super = REX::EnumSet<E, U>;
220 
221  public:
222  using enum_type = E;
223  using underlying_type = U;
224 
225  using super::super;
226  using super::operator=;
227  using super::operator*;
228  };
229 
230  template <class... Args>
232  std::common_type_t<Args...>,
233  std::underlying_type_t<
234  std::common_type_t<Args...>>>;
235  }
236 }
237 
238 namespace SKSE
239 {
240  namespace stl
241  {
242  template <class T>
243  class atomic_ref :
244  public std::atomic_ref<T>
245  {
246  private:
247  using super = std::atomic_ref<T>;
248 
249  public:
250  using value_type = typename super::value_type;
251 
252  explicit atomic_ref(volatile T& a_obj) noexcept(std::is_nothrow_constructible_v<super, value_type&>) :
253  super(const_cast<value_type&>(a_obj))
254  {}
255 
256  using super::super;
257  using super::operator=;
258  };
259 
260  template <class T>
261  atomic_ref(volatile T&) -> atomic_ref<T>;
262 
263  template class atomic_ref<std::int8_t>;
264  template class atomic_ref<std::uint8_t>;
265  template class atomic_ref<std::int16_t>;
266  template class atomic_ref<std::uint16_t>;
267  template class atomic_ref<std::int32_t>;
268  template class atomic_ref<std::uint32_t>;
269  template class atomic_ref<std::int64_t>;
270  template class atomic_ref<std::uint64_t>;
271 
280 
281  template <class T>
282  struct ssizeof
283  {
284  [[nodiscard]] constexpr operator std::ptrdiff_t() const noexcept { return value; }
285 
286  [[nodiscard]] constexpr std::ptrdiff_t operator()() const noexcept { return value; }
287 
288  static constexpr auto value = static_cast<std::ptrdiff_t>(sizeof(T));
289  };
290 
291  template <class T>
292  inline constexpr auto ssizeof_v = ssizeof<T>::value;
293 
294  template <class T, class U>
295  [[nodiscard]] auto adjust_pointer(U* a_ptr, std::ptrdiff_t a_adjust) noexcept
296  {
297  auto addr = a_ptr ? reinterpret_cast<std::uintptr_t>(a_ptr) + a_adjust : 0;
298  if constexpr (std::is_const_v<U> && std::is_volatile_v<U>) {
299  return reinterpret_cast<std::add_cv_t<T>*>(addr);
300  } else if constexpr (std::is_const_v<U>) {
301  return reinterpret_cast<std::add_const_t<T>*>(addr);
302  } else if constexpr (std::is_volatile_v<U>) {
303  return reinterpret_cast<std::add_volatile_t<T>*>(addr);
304  } else {
305  return reinterpret_cast<T*>(addr);
306  }
307  }
308 
309  template <class T>
310  void emplace_vtable(T* a_ptr)
311  {
312  reinterpret_cast<std::uintptr_t*>(a_ptr)[0] = T::VTABLE[0].address();
313  }
314 
315  template <class T>
316  void memzero(volatile T* a_ptr, std::size_t a_size = sizeof(T))
317  {
318  const auto begin = reinterpret_cast<volatile char*>(a_ptr);
319  constexpr char val{ 0 };
320  std::fill_n(begin, a_size, val);
321  }
322 
323  template <class... Args>
324  [[nodiscard]] inline auto pun_bits(Args... a_args) //
325  requires(std::same_as<std::remove_cv_t<Args>, bool>&&...)
326  {
327  constexpr auto ARGC = sizeof...(Args);
328 
329  std::bitset<ARGC> bits;
330  std::size_t i = 0;
331  ((bits[i++] = a_args), ...);
332 
333  if constexpr (ARGC <= std::numeric_limits<unsigned long>::digits) {
334  return bits.to_ulong();
335  } else if constexpr (ARGC <= std::numeric_limits<unsigned long long>::digits) {
336  return bits.to_ullong();
337  } else {
338  static_assert(false && sizeof...(Args));
339  }
340  }
341 
342  [[nodiscard]] inline auto utf8_to_utf16(std::string_view a_in) noexcept
343  -> std::optional<std::wstring>
344  {
345  const auto cvt = [&](wchar_t* a_dst, std::size_t a_length) {
348  0,
349  a_in.data(),
350  static_cast<int>(a_in.length()),
351  a_dst,
352  static_cast<int>(a_length));
353  };
354 
355  const auto len = cvt(nullptr, 0);
356  if (len == 0) {
357  return std::nullopt;
358  }
359 
360  std::wstring out(len, '\0');
361  if (cvt(out.data(), out.length()) == 0) {
362  return std::nullopt;
363  }
364 
365  return out;
366  }
367 
368  [[nodiscard]] inline auto utf16_to_utf8(std::wstring_view a_in) noexcept
369  -> std::optional<std::string>
370  {
371  const auto cvt = [&](char* a_dst, std::size_t a_length) {
374  0,
375  a_in.data(),
376  static_cast<int>(a_in.length()),
377  a_dst,
378  static_cast<int>(a_length),
379  nullptr,
380  nullptr);
381  };
382 
383  const auto len = cvt(nullptr, 0);
384  if (len == 0) {
385  return std::nullopt;
386  }
387 
388  std::string out(len, '\0');
389  if (cvt(out.data(), out.length()) == 0) {
390  return std::nullopt;
391  }
392 
393  return out;
394  }
395 
396  [[noreturn]] inline void report_and_fail(std::string_view a_msg, std::source_location a_loc = std::source_location::current())
397  {
398  const auto body = [&]() {
399  const std::filesystem::path p = a_loc.file_name();
400  auto filename = p.lexically_normal().generic_string();
401 
402  const std::regex r{ R"((?:^|[\\\/])(?:include|src)[\\\/](.*)$)" };
403  std::smatch matches;
404  if (std::regex_search(filename, matches, r)) {
405  filename = matches[1].str();
406  }
407 
408  return utf8_to_utf16(
409  std::format(
410  "{}({}): {}"sv,
411  filename,
412  a_loc.line(),
413  a_msg))
414  .value_or(L"<character encoding error>"s);
415  }();
416 
417  const auto caption = []() {
418  std::vector<wchar_t> buf;
419  buf.reserve(REX::W32::MAX_PATH);
420  buf.resize(REX::W32::MAX_PATH / 2);
421  std::uint32_t result = 0;
422  do {
423  buf.resize(buf.size() * 2);
426  buf.data(),
427  static_cast<std::uint32_t>(buf.size()));
428  } while (result && result == buf.size() && buf.size() <= std::numeric_limits<std::uint32_t>::max());
429 
430  if (result && result != buf.size()) {
431  std::filesystem::path p(buf.begin(), buf.begin() + result);
432  return p.filename().native();
433  } else {
434  return L""s;
435  }
436  }();
437 
438  spdlog::log(
439  spdlog::source_loc{
440  a_loc.file_name(),
441  static_cast<int>(a_loc.line()),
442  a_loc.function_name() },
443  spdlog::level::critical,
444  a_msg);
445  REX::W32::MessageBoxW(nullptr, body.c_str(), (caption.empty() ? nullptr : caption.c_str()), 0);
447  }
448 
449  template <class To, class From>
450  [[nodiscard]] To unrestricted_cast(From a_from) noexcept
451  {
452  if constexpr (std::is_same_v<
453  std::remove_cv_t<From>,
454  std::remove_cv_t<To>>) {
455  return To{ a_from };
456 
457  // From != To
458  } else if constexpr (std::is_reference_v<From>) {
459  return stl::unrestricted_cast<To>(std::addressof(a_from));
460 
461  // From: NOT reference
462  } else if constexpr (std::is_reference_v<To>) {
463  return *stl::unrestricted_cast<
464  std::add_pointer_t<
465  std::remove_reference_t<To>>>(a_from);
466 
467  // To: NOT reference
468  } else if constexpr (std::is_pointer_v<From> &&
469  std::is_pointer_v<To>) {
470  return static_cast<To>(
471  const_cast<void*>(
472  static_cast<const volatile void*>(a_from)));
473  } else if constexpr ((std::is_pointer_v<From> && std::is_integral_v<To>) ||
474  (std::is_integral_v<From> && std::is_pointer_v<To>)) {
475  return reinterpret_cast<To>(a_from);
476  } else {
477  union
478  {
479  std::remove_cv_t<std::remove_reference_t<From>> from;
480  std::remove_cv_t<std::remove_reference_t<To>> to;
481  };
482 
483  from = std::forward<From>(a_from);
484  return to;
485  }
486  }
487  }
488 }
489 
490 namespace RE
491 {
492  using namespace std::literals;
493  namespace stl = SKSE::stl;
494 }
495 
496 namespace REL
497 {
498  using namespace std::literals;
499  namespace stl = SKSE::stl;
500 }
501 
502 #ifdef SKYRIM_SUPPORT_AE
503 # define RELOCATION_ID(SE, AE) REL::ID(AE)
504 #else
505 # define RELOCATION_ID(SE, AE) REL::ID(SE)
506 #endif
507 
508 #include "REL/REL.h"
509 
510 #include "RE/Offsets.h"
511 #include "RE/Offsets_NiRTTI.h"
512 #include "RE/Offsets_RTTI.h"
513 #include "RE/Offsets_VTABLE.h"
514 
515 #include "RE/B/BSCoreTypes.h"
516 #include "RE/S/SFTypes.h"
Definition: EnumSet.h:9
Definition: PCH.h:245
typename super::value_type value_type
Definition: PCH.h:250
atomic_ref(volatile T &a_obj) noexcept(std::is_nothrow_constructible_v< super, value_type & >)
Definition: PCH.h:252
Definition: PCH.h:218
U underlying_type
Definition: PCH.h:223
E enum_type
Definition: PCH.h:222
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
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 >
Definition: PCH.h:77
atomic_ref(volatile T &) -> atomic_ref< T >
T not_null
Definition: PCH.h:103
To unrestricted_cast(From a_from) noexcept
Definition: PCH.h:450
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:316
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:396
scope_exit(EF) -> scope_exit< EF >
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:368
void emplace_vtable(T *a_ptr)
Definition: PCH.h:310
auto adjust_pointer(U *a_ptr, std::ptrdiff_t a_adjust) noexcept
Definition: PCH.h:295
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:342
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:153
basic_zstring< wchar_t > zwstring
Definition: PCH.h:82
auto pun_bits(Args... a_args) requires(std
Definition: PCH.h:324
basic_zstring< char > zstring
Definition: PCH.h:81
enumeration(Args...) -> enumeration< std::common_type_t< Args... >, std::underlying_type_t< std::common_type_t< Args... >>>
constexpr auto ssizeof_v
Definition: PCH.h:292
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
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
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:283
constexpr std::ptrdiff_t operator()() const noexcept
Definition: PCH.h:286