forked from wheremyfoodat/Panda3DS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.hpp
183 lines (157 loc) · 4.84 KB
/
helpers.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#pragma once
#include <climits>
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <memory>
#include "termcolor.hpp"
// We have to detect and special-case AppleClang at the moment since its C++20 support is finicky and doesn't quite support std::bit_cast
#if defined(__clang__) && defined(__apple_build_version__)
#define HELPERS_APPLE_CLANG
#else
#include <bit>
#endif
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using usize = std::size_t;
using uint = unsigned int;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
namespace Helpers {
template <class... Args>
std::string format(const std::string& fmt, Args&&... args) {
const int size = std::snprintf(nullptr, 0, fmt.c_str(), args...) + 1;
if (size <= 0) {
return {};
}
const auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, fmt.c_str(), args ...);
return std::string(buf.get(), buf.get() + size - 1);
}
// Unconditional panic, unlike panicDev which does not panic on user builds
template <class... Args>
[[noreturn]] static void panic(const char* fmt, Args&&... args) {
std::cout << termcolor::on_red << "[FATAL] ";
std::printf(fmt, args...);
std::cout << termcolor::reset << "\n";
exit(1);
}
#ifdef PANDA3DS_LIMITED_PANICS
template <class... Args>
static void panicDev(const char* fmt, Args&&... args) {}
#else
template <class... Args>
[[noreturn]] static void panicDev(const char* fmt, Args&&... args) {
panic(fmt, args...);
}
#endif
template <class... Args>
static void warn(const char* fmt, Args&&... args) {
std::cout << termcolor::on_red << "[Warning] ";
std::printf(fmt, args...);
std::cout << termcolor::reset << "\n";
}
static constexpr bool buildingInDebugMode() {
#ifdef NDEBUG
return false;
#endif
return true;
}
static constexpr bool isUserBuild() {
#ifdef PANDA3DS_USER_BUILD
return true;
#endif
return false;
}
static constexpr bool isHydraCore() {
#ifdef PANDA3DS_HYDRA_CORE
return true;
#endif
return false;
}
static constexpr bool isAndroid() {
#ifdef __ANDROID__
return true;
#endif
return false;
}
static void debug_printf(const char* fmt, ...) {
if constexpr (buildingInDebugMode()) {
std::va_list args;
va_start(args, fmt);
std::vprintf(fmt, args);
va_end(args);
}
}
/// Sign extend an arbitrary-size value to 32 bits
static constexpr u32 inline signExtend32(u32 value, u32 startingSize) {
auto temp = (s32)value;
auto bitsToShift = 32 - startingSize;
return (u32)(temp << bitsToShift >> bitsToShift);
}
/// Sign extend an arbitrary-size value to 16 bits
static constexpr u16 signExtend16(u16 value, u32 startingSize) {
auto temp = (s16)value;
auto bitsToShift = 16 - startingSize;
return (u16)(temp << bitsToShift >> bitsToShift);
}
/// Create a mask with `count` number of one bits.
template <typename T, usize count>
static constexpr T ones() {
constexpr usize bitsize = CHAR_BIT * sizeof(T);
static_assert(count <= bitsize, "count larger than bitsize of T");
if (count == T(0)) {
return T(0);
}
return static_cast<T>(~static_cast<T>(0)) >> (bitsize - count);
}
/// Extract bits from an integer-type
template <usize offset, typename T>
static constexpr T getBit(T value) {
return (value >> offset) & T(1);
}
/// Extract bits from an integer-type
template <usize offset, usize bits, typename ReturnT, typename ValueT>
static constexpr ReturnT getBits(ValueT value) {
static_assert((offset + bits) <= (CHAR_BIT * sizeof(ValueT)), "Invalid bit range");
static_assert(bits > 0, "Invalid bit size");
return ReturnT(ValueT(value >> offset) & ones<ValueT, bits>());
}
template <usize offset, usize bits, typename ValueT>
static constexpr ValueT getBits(ValueT value) {
return getBits<offset, bits, ValueT, ValueT>(value);
}
#if defined(HELPERS_APPLE_CLANG) || defined(__ANDROID__) || !defined(__cpp_lib_bit_cast)
template <class To, class From>
constexpr To bit_cast(const From& from) noexcept {
return *reinterpret_cast<const To*>(&from);
}
#else
template <class To, class From>
constexpr To bit_cast(const From& from) noexcept {
return std::bit_cast<To, From>(from);
}
#endif
static std::vector<std::string> split(const std::string& s, const char c) {
std::istringstream tmp(s);
std::vector<std::string> result(1);
while (std::getline(tmp, *result.rbegin(), c)) {
result.emplace_back();
}
// Remove temporary slot
result.pop_back();
return result;
}
}; // namespace Helpers
// UDLs for memory size values
constexpr size_t operator""_KB(unsigned long long int x) { return 1024ULL * x; }
constexpr size_t operator""_MB(unsigned long long int x) { return 1024_KB * x; }
constexpr size_t operator""_GB(unsigned long long int x) { return 1024_MB * x; }