inkcpp
Loading...
Searching...
No Matches
system.h
1/* Copyright (c) 2024 Julian Benda
2 *
3 * This file is part of inkCPP which is released under MIT license.
4 * See file LICENSE.txt or go to
5 * https://github.com/JBenda/inkcpp for full license details.
6 */
7#pragma once
8
9#include "config.h"
10
11#ifdef INK_ENABLE_UNREAL
12# include "Misc/AssertionMacros.h"
13# include "Misc/CString.h"
14# include "HAL/UnrealMemory.h"
15# include "Hash/CityHash.h"
16#endif
17#ifdef INK_ENABLE_STL
18# ifdef INK_ENABLE_EXCEPTIONS
19# include <exception>
20# endif
21# include <stdexcept>
22# include <optional>
23# include <cctype>
24# include <cstdint>
25#endif
26#ifdef INK_ENABLE_CSTD
27# include <cstdio>
28# include <cstdlib>
29# include <ctype.h>
30# include <cassert>
31#endif
32
33// Platform specific defines //
34
35#ifdef INK_ENABLE_UNREAL
36# define inkZeroMemory(buff, len) FMemory::Memset(buff, 0, len)
37# define FORMAT_STRING_STR "%hs"
38#else
39# define inkZeroMemory ink::internal::zero_memory
40# define FORMAT_STRING_STR "%s"
41#endif
42
43#ifdef INK_ENABLE_UNREAL
44# define inkAssert(condition, text, ...) checkf(condition, TEXT(text), ##__VA_ARGS__)
45# define inkFail(text, ...) checkf(false, TEXT(text), ##__VA_ARGS__)
46#else
47# define inkAssert ink::ink_assert
48# define inkFail(...) ink::ink_assert(false, __VA_ARGS__)
49
50#endif
51
52
53namespace ink
54{
58typedef unsigned int uint32_t;
59
60#ifndef INK_ENABLE_STL
61
63typedef int int32_t;
64typedef short int16_t;
65
67typedef unsigned long long uint64_t;
68typedef unsigned short uint16_t;
69#endif // ndef INK_ENABLE_STL
70
73
76
77
79typedef unsigned char byte_t;
80
82typedef decltype(static_cast<int*>(nullptr) - static_cast<int*>(nullptr)) ptrdiff_t;
83
85static_assert(sizeof(byte_t) == 1);
86static_assert(sizeof(uint16_t) == 2);
87static_assert(sizeof(int16_t) == 2);
88static_assert(sizeof(uint32_t) == 4);
89static_assert(sizeof(int32_t) == 4);
90static_assert(sizeof(uint64_t) == 8);
91static_assert(sizeof(ptrdiff_t) == sizeof(void*));
92
95
97typedef const unsigned char* ip_t;
98
100typedef unsigned int size_t;
101
104
107
109struct list_flag {
110 int16_t list_id;
111 int16_t flag;
112
113 bool operator==(const list_flag& o) const { return list_id == o.list_id && flag == o.flag; }
114
115 bool operator!=(const list_flag& o) const { return ! (*this == o); }
116};
117
118inline list_flag read_list_flag(const char*& ptr)
119{
120 list_flag result = *reinterpret_cast<const list_flag*>(ptr);
121 ptr += sizeof(list_flag);
122 return result;
123}
124
126constexpr list_flag null_flag{-1, -1};
128constexpr list_flag empty_flag{-1, 0};
129
130#ifdef INK_ENABLE_UNREAL
132inline hash_t hash_string(const char* string)
133{
134 return CityHash32(string, FCStringAnsi::Strlen(string));
135}
136#else
137hash_t hash_string(const char* string);
138hash_t hash_data(const unsigned char* data, size_t len);
139#endif
140
141namespace internal
142{
143#ifdef __GNUC__
144#else
145# pragma warning(push)
146# pragma warning( \
147 disable : 4514, \
148 justification : "functions are defined in header file, they do not need to be used." \
149 )
150#endif
152 static inline constexpr bool starts_with(const char* string, const char* prefix)
153 {
154 while (*prefix) {
155 if (*string != *prefix) {
156 return false;
157 }
158 string++;
159 prefix++;
160 }
161 return true;
162 }
163
165 static inline constexpr bool is_whitespace(const char* string, bool includeNewline = true)
166 {
167 // Iterate string
168 while (true) {
169 switch (*(string++)) {
170 case 0: return true;
171 case '\f': [[fallthrough]];
172 case '\r': [[fallthrough]];
173 case '\n':
174 if (! includeNewline)
175 return false;
176 [[fallthrough]];
177 case '\t': [[fallthrough]];
178 case '\v': [[fallthrough]];
179 case ' ': continue;
180 default: return false;
181 }
182 }
183 }
184
185 inline bool is_part_of_word(char character) { return isalpha(character) || isdigit(character); }
186
187 static inline constexpr bool is_whitespace(char character, bool includeNewline = true)
188 {
189 switch (character) {
190 case '\n':
191 if (! includeNewline)
192 return false;
193 case '\t': [[fallthrough]];
194 case ' ': return true;
195 default: return false;
196 }
197 }
198
199#ifndef INK_ENABLE_UNREAL
201 void zero_memory(void* buffer, size_t length);
202#endif
203#ifdef __GNUC__
204#else
205# pragma warning(pop)
206#endif
207} // namespace internal
208
209#ifdef INK_ENABLE_STL
211using ink_exception = std::runtime_error;
212#else
213// Non-STL exception class
214class ink_exception
215{
216public:
217 ink_exception(const char* msg)
218 : _msg(msg)
219 {
220 }
221
222 inline const char* message() const { return _msg; }
223
224private:
225 const char* _msg;
226};
227#endif
228
229#ifdef __GNUC__
230# pragma GCC diagnostic push
231# pragma GCC diagnostic ignored "-Wunused-parameter"
232#else
233# pragma warning(push)
234# pragma warning( \
235 disable : 4100, \
236 justification : "dependend on rtti, exception and stl support not all arguments are needed" \
237 )
238#endif
239// assert
240template<typename... Args>
241void ink_assert(bool condition, const char* msg = nullptr, Args... args)
242{
243 static const char* EMPTY = "";
244 if (msg == nullptr) {
245 msg = EMPTY;
246 }
247 if (! condition) {
248#if defined(INK_ENABLE_STL) || defined(INK_ENABLE_CSTD)
249 if constexpr (sizeof...(args) > 0) {
250 size_t size = snprintf(nullptr, 0, msg, args...) + 1;
251 char* message = static_cast<char*>(malloc(size));
252 snprintf(message, size, msg, args...);
253 msg = message;
254 }
255#endif
256#ifdef INK_ENABLE_EXCEPTIONS
257 throw ink_exception(msg);
258#elif defined(INK_ENABLE_CSTD)
259 fprintf(stderr, "Ink Assert: %s\n", msg);
260 abort();
261#else
262# warning no assertion handling this could lead to invalid code paths
263#endif
264 }
265}
266#ifdef __GNUC__
267# pragma GCC diagnostic pop
268#else
269# pragma warning(pop)
270#endif
271
272template<typename... Args>
273[[noreturn]] inline void ink_assert(const char* msg = nullptr, Args... args)
274{
275 ink_assert(false, msg, args...);
276#ifdef INK_ENABLE_CSTD
277 exit(EXIT_FAILURE);
278#endif
279}
280
281namespace runtime::internal
282{
283 constexpr unsigned abs(int i) { return static_cast<unsigned>(i < 0 ? -i : i); }
284
285 template<typename T>
286 struct always_false {
287 static constexpr bool value = false;
288 };
289
290 template<bool Con, typename T1, typename T2>
291 struct if_type {
292 using type = T1;
293 };
294
295 template<typename T1, typename T2>
296 struct if_type<false, T1, T2> {
297 using type = T2;
298 };
299
300 template<bool Con, typename T1, typename T2>
301 using if_t = typename if_type<Con, T1, T2>::type;
302
303 template<bool Enable, typename T = void>
304 struct enable_if {
305 };
306
307 template<typename T>
308 struct enable_if<true, T> {
309 using type = T;
310 };
311
312 template<bool Enable, typename T = void>
313 using enable_if_t = typename enable_if<Enable, T>::type;
314} // namespace runtime::internal
315
316
317#ifdef INK_ENABLE_STL
321template<typename T>
322using optional = std::optional<T>;
324constexpr std::nullopt_t nullopt = std::nullopt;
325#else
326struct nullopt_t {
327};
328
329constexpr nullopt_t nullopt;
330
331template<typename T>
332class optional
333{
334public:
335 optional() {}
336
337 optional(nullopt_t) {}
338
339 optional(T&& val)
340 : _has_value{true}
341 , _value{val}
342 {
343 }
344
345 optional(const T& val)
346 : _has_value{true}
347 , _value{val}
348 {
349 }
350
351 const T& operator*() const { return value(); }
352
353 T& operator*() { return value(); }
354
355 const T* operator->() const { return &value(); }
356
357 T* operator->() { return &value(); }
358
359 constexpr bool has_value() const { return _has_value; }
360
361 constexpr T& value()
362 {
363 test_value();
364 return _value;
365 }
366
367 constexpr const T& value() const
368 {
369 test_value();
370 return _value;
371 }
372
373 constexpr operator bool() const { return has_value(); }
374
375 template<typename U>
376 constexpr T value_or(U&& u) const
377 {
378 return _has_value ? _value : static_cast<T>(u);
379 }
380
381 template<typename... Args>
382 T& emplace(Args... args)
383 {
384 if (_has_value)
385 _value.~T();
386
387 new (&_value) T(args...);
388 _has_value = true;
389 return _value;
390 }
391
392private:
393 void test_value() const
394 {
395 if (! _has_value) {
396 inkFail("Can't access empty optional!");
397 }
398 }
399
400 bool _has_value = false;
401 T _value;
402};
403#endif
404} // namespace ink
Namespace contaning all modules and classes from InkCPP.
Definition choice.h:11
constexpr list_flag null_flag
value of an unset list_flag
Definition system.h:126
unsigned int uint32_t
define basic numeric type
Definition system.h:58
std::optional< T > optional
custom optional implementation for usage if STL is disabled
Definition system.h:322
const hash_t InvalidHash
Invalid hash value.
Definition system.h:75
uint32_t container_t
Used as the unique identifier for an ink container.
Definition system.h:103
unsigned char byte_t
Byte type.
Definition system.h:79
unsigned int size_t
Used for the size of arrays.
Definition system.h:100
uint32_t offset_t
Verify sizes.
Definition system.h:94
constexpr std::nullopt_t nullopt
an empty optional
Definition system.h:324
std::runtime_error ink_exception
exception type thrown if something goes wrong
Definition system.h:211
uint32_t thread_t
Used to uniquely identify threads.
Definition system.h:106
decltype(static_cast< int * >(nullptr) - static_cast< int * >(nullptr)) ptrdiff_t
Ptr difference type.
Definition system.h:82
constexpr list_flag empty_flag
value representing an empty list
Definition system.h:128
hash_t hash_string(const char *string)
Simple hash for serialization of strings.
Definition system.h:132
const unsigned char * ip_t
Instruction pointer used for addressing within the story instructions.
Definition system.h:97
uint32_t hash_t
Name hash (used for temporary variables)
Definition system.h:72