1 | #pragma once |
2 | |
3 | #include <ore/StringView.h> |
4 | #include <ore/Types.h> |
5 | #include <type_traits> |
6 | #include <utility> |
7 | |
8 | namespace ore { |
9 | |
10 | template <typename T> |
11 | constexpr T AlignUpToPowerOf2(T val, int base) { |
12 | return val + base - 1 & static_cast<unsigned int>(-base); |
13 | } |
14 | |
15 | struct RelocationTable; |
16 | |
17 | struct { |
18 | BinaryBlockHeader* (int type); |
19 | const BinaryBlockHeader* (int type) const; |
20 | BinaryBlockHeader* (); |
21 | const BinaryBlockHeader* () const; |
22 | void (BinaryBlockHeader* block); |
23 | |
24 | u32 ; |
25 | int ; |
26 | }; |
27 | |
28 | struct { |
29 | bool (s64 magic_, int ver_major_, int ver_minor_, int ver_patch_, int ver_sub_) const; |
30 | bool (s64 magic_) const; |
31 | bool (int major, int minor, int patch, int sub) const; |
32 | bool () const; |
33 | bool () const; |
34 | |
35 | bool () const; |
36 | int () const; |
37 | void (int alignment_); |
38 | |
39 | bool () const; |
40 | void (bool relocated); |
41 | |
42 | void (); |
43 | |
44 | int () const; |
45 | void (int size); |
46 | |
47 | StringView () const; |
48 | void (const StringView& name); |
49 | |
50 | RelocationTable* (); |
51 | void (RelocationTable* table); |
52 | |
53 | BinaryBlockHeader* (); |
54 | const BinaryBlockHeader* () const; |
55 | void (BinaryBlockHeader* block); |
56 | |
57 | BinaryBlockHeader* (int type); |
58 | const BinaryBlockHeader* (int type) const; |
59 | |
60 | u64 ; |
61 | u8 ; |
62 | u8 ; |
63 | u8 ; |
64 | u8 ; |
65 | s16 ; |
66 | u8 ; |
67 | u8 ; |
68 | int ; |
69 | u16 ; |
70 | u16 ; |
71 | int ; |
72 | int ; |
73 | }; |
74 | |
75 | template <typename T> |
76 | struct BinTString { |
77 | // Make it impossible to accidentally construct a (partial, broken) copy. |
78 | BinTString(const BinTString&) = delete; |
79 | auto operator=(const BinTString&) = delete; |
80 | |
81 | T* data() { return chars; } |
82 | const T* data() const { return chars; } |
83 | |
84 | T& operator[](size_t idx) { return data()[idx]; } |
85 | const T& operator[](size_t idx) const { return data()[idx]; } |
86 | |
87 | auto begin() { return data(); } |
88 | auto begin() const { return data(); } |
89 | |
90 | auto end() { return data() + length; } |
91 | auto end() const { return data() + length; } |
92 | |
93 | bool empty() const { return length == 0; } |
94 | |
95 | // NOLINTNEXTLINE(google-explicit-constructor) |
96 | operator TStringView<T>() const { return {data(), length}; } |
97 | |
98 | BinTString* NextString() { return const_cast<BinTString*>(std::as_const(*this).NextString()); } |
99 | |
100 | const BinTString* NextString() const { |
101 | // XXX: this shouldn't have to be a separate case. |
102 | if constexpr (std::is_same_v<T, wchar_t>) { |
103 | const auto offset = ((2 + (4 * (length + 1) - 1)) & -4) + 2; |
104 | return reinterpret_cast<const BinTString*>(reinterpret_cast<const char*>(this) + |
105 | offset); |
106 | |
107 | } else { |
108 | // + 1 for the null terminator |
109 | const auto offset = offsetof(BinTString, chars) + sizeof(T) * (length + 1); |
110 | return reinterpret_cast<const BinTString*>( |
111 | reinterpret_cast<const char*>(this) + |
112 | AlignUpToPowerOf2(offset, alignof(BinTString))); |
113 | } |
114 | } |
115 | |
116 | u16 length; |
117 | T chars[1]; |
118 | }; |
119 | |
120 | using BinString = BinTString<char>; |
121 | using BinWString = BinTString<wchar_t>; |
122 | |
123 | template <typename T> |
124 | struct BinTPtr { |
125 | void Clear() { offset_or_ptr = 0; } |
126 | void Set(T* ptr) { offset_or_ptr = reinterpret_cast<u64>(ptr); } |
127 | |
128 | // Only use this after relocation. |
129 | T* Get() { return reinterpret_cast<T*>(offset_or_ptr); } |
130 | const T* Get() const { return reinterpret_cast<const T*>(offset_or_ptr); } |
131 | |
132 | void SetOffset(void* base, void* ptr) { |
133 | offset_or_ptr = static_cast<int>(ptr ? uintptr_t(ptr) - uintptr_t(base) : 0); |
134 | } |
135 | |
136 | u64 GetOffset() const { return offset_or_ptr; } |
137 | |
138 | T* ToPtr(void* base) const { |
139 | const auto offset = static_cast<int>(offset_or_ptr); |
140 | if (offset == 0) |
141 | return nullptr; |
142 | return reinterpret_cast<T*>(reinterpret_cast<char*>(base) + offset); |
143 | } |
144 | |
145 | void Relocate(void* base) { Set(ToPtr(base)); } |
146 | void Unrelocate(void* base) { SetOffset(base, Get()); } |
147 | |
148 | u64 offset_or_ptr; |
149 | }; |
150 | |
151 | static_assert(sizeof(u64) >= sizeof(void*)); |
152 | |
153 | } // namespace ore |
154 | |