gb.hpp - #ifndef for many macros

This commit is contained in:
gingerBill 2015-11-17 10:45:07 +00:00
parent 9be05386ac
commit a8f308e2cd
2 changed files with 218 additions and 184 deletions

View File

@ -6,7 +6,7 @@ library | latest version | category | languages | description
----------------|----------------|----------|-----------|------------- ----------------|----------------|----------|-----------|-------------
**gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++ **gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++
**gb_ini.h** | 0.91 | misc | C, C++ | A simple ini file loader library for C & C++ **gb_ini.h** | 0.91 | misc | C, C++ | A simple ini file loader library for C & C++
**gb.hpp** | 0.20 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development **gb.hpp** | 0.20a | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development
## FAQ ## FAQ

400
gb.hpp
View File

@ -1,8 +1,9 @@
// gb.hpp - v0.20 - public domain C++11 helper library - no warranty implied; use at your own risk // gb.hpp - v0.20a - public domain C++11 helper library - no warranty implied; use at your own risk
// (Experimental) A C++11 helper library without STL geared towards game development // (Experimental) A C++11 helper library without STL geared towards game development
/* /*
Version History: Version History:
0.20a - #ifndef for many macros
0.20 - Angle 0.20 - Angle
0.19 - Cache friendly Transform and String fixes 0.19 - Cache friendly Transform and String fixes
0.18 - Hash_Table bug fixes 0.18 - Hash_Table bug fixes
@ -65,6 +66,7 @@ Context:
- Complex - Complex
- Quaternion - Quaternion
- Matrix(2,3,4) - Matrix(2,3,4)
- Angle
- Euler_Angles - Euler_Angles
- Transform - Transform
- Aabb - Aabb
@ -74,12 +76,6 @@ Context:
- Functions & Constants - Functions & Constants
- Type Functions - Type Functions
- Random - Random
- Generator_Type
- Geneartor Definition (Template/Concept)
- Mt19937_32
- Mt19937_64
- Random_Device
- Functions
*/ */
#ifndef GB_INCLUDE_GB_HPP #ifndef GB_INCLUDE_GB_HPP
@ -91,17 +87,20 @@ Context:
// NOTE(bill): Because static means three different things in C/C++ // NOTE(bill): Because static means three different things in C/C++
// Great Design(!) // Great Design(!)
#ifndef global
#define global static #define global static
#define internal static #define internal static
#define local_persist static #define local_persist static
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define _ALLOW_KEYWORD_MACROS #define _ALLOW_KEYWORD_MACROS
#ifndef alignof // Needed for MSVC 2013 'cause Microsoft "loves" standards
#define alignof(x) __alignof(x)
#endif
#endif #endif
#if !defined(alignof) // Needed for MSVC 2013 'cause Microsoft "loves" standards
#define alignof(x) __alignof(x)
#endif
//////////////////////////////// ////////////////////////////////
/// /// /// ///
@ -109,16 +108,26 @@ Context:
/// /// /// ///
//////////////////////////////// ////////////////////////////////
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#ifndef GB_SYSTEM_WINDOWS
#define GB_SYSTEM_WINDOWS 1 #define GB_SYSTEM_WINDOWS 1
#endif
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#ifndef GB_SYSTEM_OSX
#define GB_SYSTEM_OSX 1 #define GB_SYSTEM_OSX 1
#endif
#elif defined(__unix__) #elif defined(__unix__)
#ifndef GB_SYSTEM_UNIX
#define GB_SYSTEM_UNIX 1 #define GB_SYSTEM_UNIX 1
#endif
#if defined(__linux__) #if defined(__linux__)
#ifndef GB_SYSTEM_LINUX
#define GB_SYSTEM_LINUX 1 #define GB_SYSTEM_LINUX 1
#endif
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifndef GB_SYSTEM_FREEBSD
#define GB_SYSTEM_FREEBSD 1 #define GB_SYSTEM_FREEBSD 1
#endif
#else #else
#error This UNIX operating system is not supported by gb.hpp #error This UNIX operating system is not supported by gb.hpp
#endif #endif
@ -133,21 +142,30 @@ Context:
//////////////////////////////// ////////////////////////////////
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN64) #if defined(_WIN64)
#ifndef GB_ARCH_64_BIT
#define GB_ARCH_64_BIT 1 #define GB_ARCH_64_BIT 1
#endif
#else #else
#ifndef GB_ARCH_32_BIT
#define GB_ARCH_32_BIT 1 #define GB_ARCH_32_BIT 1
#endif
#endif #endif
#endif #endif
// TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang // TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang
#if defined(__GNUC__) #if defined(__GNUC__)
#if defined(__x86_64__) || defined(__ppc64__) #if defined(__x86_64__) || defined(__ppc64__)
#ifndef GB_ARCH_64_BIT
#define GB_ARCH_64_BIT 1 #define GB_ARCH_64_BIT 1
#endif
#else #else
#ifndef GB_ARCH_32_BIT
#define GB_ARCH_32_BIT 1 #define GB_ARCH_32_BIT 1
#endif
#endif #endif
#endif #endif
// TODO(bill): Get this to work
// #if !defined(GB_LITTLE_EDIAN) && !defined(GB_BIG_EDIAN) // #if !defined(GB_LITTLE_EDIAN) && !defined(GB_BIG_EDIAN)
// // Source: http://sourceforge.net/p/predef/wiki/Endianness/ // // Source: http://sourceforge.net/p/predef/wiki/Endianness/
@ -225,45 +243,50 @@ Context:
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#if !defined(NDEBUG) #ifndef GB_ARRAY_BOUND_CHECKING
#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
#else
#define GB_ASSERT(x, ...) ((void)sizeof(x))
#endif
#if !defined(GB_ARRAY_BOUND_CHECKING)
#define GB_ARRAY_BOUND_CHECKING 1 #define GB_ARRAY_BOUND_CHECKING 1
#endif #endif
#ifndef GB_DISABLE_COPY
#define GB_DISABLE_COPY(Type) \ #define GB_DISABLE_COPY(Type) \
Type(const Type&) = delete; \ Type(const Type&) = delete; \
Type& operator=(const Type&) = delete Type& operator=(const Type&) = delete
#endif
/// Helper function used as a better alternative to assert which allows for #if !defined(GB_ASSERT)
/// optional printf style error messages #if !defined(NDEBUG)
extern "C" inline void #define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
gb__assert_handler(bool condition, const char* condition_str,
const char* filename, size_t line,
const char* error_text = nullptr, ...)
{
if (condition)
return;
fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str); /// Helper function used as a better alternative to assert which allows for
if (error_text) /// optional printf style error messages
{ extern "C" inline void
fprintf(stderr, " - "); gb__assert_handler(bool condition, const char* condition_str,
const char* filename, size_t line,
const char* error_text = nullptr, ...)
{
if (condition)
return;
va_list args; fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str);
va_start(args, error_text); if (error_text)
vfprintf(stderr, error_text, args); {
va_end(args); fprintf(stderr, " - ");
}
fprintf(stderr, "\n"); va_list args;
// TODO(bill): Get a better way to abort va_start(args, error_text);
*(int*)0 = 0; vfprintf(stderr, error_text, args);
} va_end(args);
}
fprintf(stderr, "\n");
// TODO(bill): Get a better way to abort
*(int*)0 = 0;
}
#else
#define GB_ASSERT(x, ...) ((void)sizeof(x))
#endif
#endif
//////////////////////////////// ////////////////////////////////
/// /// /// ///
@ -271,34 +294,32 @@ gb__assert_handler(bool condition, const char* condition_str,
/// /// /// ///
//////////////////////////////// ////////////////////////////////
#if defined(_MSC_VER) #if defined(_MSC_VER)
extern "C" inline int
gb__vsnprintf_compatible(char* buffer, size_t size, const char* format, va_list args)
{
int result = -1;
if (size > 0)
result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
if (result == -1)
return _vscprintf(format, args);
extern "C" inline int return result;
gb__vsnprintf_compatible(char* buffer, size_t size, const char* format, va_list args) }
{
int result = -1;
if (size > 0)
result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
if (result == -1)
return _vscprintf(format, args);
return result; extern "C" inline int
} gb__snprintf_compatible(char* buffer, size_t size, const char* format, ...)
{
extern "C" inline int va_list args;
gb__snprintf_compatible(char* buffer, size_t size, const char* format, ...) va_start(args, format);
{ int result = gb__vsnprintf_compatible(buffer, size, format, args);
va_list args; va_end(args);
va_start(args, format); return result;
int result = gb__vsnprintf_compatible(buffer, size, format, args); }
va_end(args);
return result;
}
#if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
#define snprintf gb__snprintf_compatible
#define vsnprintf gb__vsnprintf_compatible
#endif // GB_DO_NOT_USE_MSVC_SPRINTF_FIX
#if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
#define snprintf gb__snprintf_compatible
#define vsnprintf gb__vsnprintf_compatible
#endif // GB_DO_NOT_USE_MSVC_SPRINTF_FIX
#endif #endif
#if !defined(__GB_NAMESPACE_PREFIX) && !defined(GB_NO_GB_NAMESPACE) #if !defined(__GB_NAMESPACE_PREFIX) && !defined(GB_NO_GB_NAMESPACE)
@ -327,96 +348,101 @@ __GB_NAMESPACE_START
//////////////////////////////// ////////////////////////////////
#ifndef GB_BASIC_TYPES
#define GB_BASIC_TYPES
#if defined(_MSC_VER)
using u8 = unsigned __int8;
using s8 = signed __int8;
using u16 = unsigned __int16;
using s16 = signed __int16;
using u32 = unsigned __int32;
using s32 = signed __int32;
using u64 = unsigned __int64;
using s64 = signed __int64;
#else
using u8 = unsigned char;
using s8 = signed char;
using u16 = unsigned short;
using s16 = signed short;
using u32 = unsigned int;
using s32 = signed int;
using u64 = unsigned long long;
using s64 = signed long long;
#endif
static_assert( sizeof(u8) == 1, "u8 is not 8 bits");
static_assert(sizeof(u16) == 2, "u16 is not 16 bits");
static_assert(sizeof(u32) == 4, "u32 is not 32 bits");
static_assert(sizeof(u64) == 8, "u64 is not 64 bits");
using f32 = float;
using f64 = double;
#if defined(GB_B8_AS_BOOL)
using b8 = bool;
#else
using b8 = s8;
#endif
using b32 = s32;
// NOTE(bill): (std::)size_t is not used not because it's a bad concept but on
// the platforms that I will be using:
// sizeof(size_t) == sizeof(usize) == sizeof(s64)
// NOTE(bill): This also allows for a signed version of size_t which is similar
// to ptrdiff_t
// NOTE(bill): If (u)intptr is a better fit, please use that.
// NOTE(bill): Also, I hate the `_t` suffix
#if defined(GB_ARCH_64_BIT)
using ssize = s64;
using usize = u64;
#elif defined(GB_ARCH_32_BIT)
using usize = s32;
using usize = u32;
#else
#error Unknown architecture bit size
#endif
static_assert(sizeof(usize) == sizeof(size_t),
"`usize` is not the same size as `size_t`");
static_assert(sizeof(ssize) == sizeof(usize),
"`ssize` is not the same size as `usize`");
using intptr = intptr_t;
using uintptr = uintptr_t;
using ptrdiff = ptrdiff_t;
#if defined(_MSC_VER)
using u8 = unsigned __int8;
using s8 = signed __int8;
using u16 = unsigned __int16;
using s16 = signed __int16;
using u32 = unsigned __int32;
using s32 = signed __int32;
using u64 = unsigned __int64;
using s64 = signed __int64;
#else
using u8 = unsigned char;
using s8 = signed char;
using u16 = unsigned short;
using s16 = signed short;
using u32 = unsigned int;
using s32 = signed int;
using u64 = unsigned long long;
using s64 = signed long long;
#endif #endif
static_assert( sizeof(u8) == 1, "u8 is not 8 bits"); #if !defined(GB_U8_MIN)
static_assert(sizeof(u16) == 2, "u16 is not 16 bits"); #define GB_U8_MIN 0u
static_assert(sizeof(u32) == 4, "u32 is not 32 bits"); #define GB_U8_MAX 0xffu
static_assert(sizeof(u64) == 8, "u64 is not 64 bits"); #define GB_S8_MIN (-0x7f - 1)
#define GB_S8_MAX 0x7f
using f32 = float; #define GB_U16_MIN 0u
using f64 = double; #define GB_U16_MAX 0xffffu
#define GB_S16_MIN (-0x7fff - 1)
#define GB_S16_MAX 0x7fff
#if defined(GB_B8_AS_BOOL) #define GB_U32_MIN 0u
using b8 = bool; #define GB_U32_MAX 0xffffffffu
#else #define GB_S32_MIN (-0x7fffffff - 1)
using b8 = s8; #define GB_S32_MAX 0x7fffffff
#endif
using b32 = s32;
// NOTE(bill): (std::)size_t is not used not because it's a bad concept but on #define GB_U64_MIN 0ull
// the platforms that I will be using: #define GB_U64_MAX 0xffffffffffffffffull
// sizeof(size_t) == sizeof(usize) == sizeof(s64) #define GB_S64_MIN (-0x7fffffffffffffffll - 1)
// NOTE(bill): This also allows for a signed version of size_t which is similar #define GB_S64_MAX 0x7fffffffffffffffll
// to ptrdiff_t
// NOTE(bill): If (u)intptr is a better fit, please use that.
// NOTE(bill): Also, I hate the `_t` suffix
#if defined(GB_ARCH_64_BIT)
using ssize = s64;
using usize = u64;
#elif defined(GB_ARCH_32_BIT)
using usize = s32;
using usize = u32;
#else
#error Unknown architecture bit size
#endif #endif
static_assert(sizeof(usize) == sizeof(size_t), #if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
"`usize` is not the same size as `size_t`");
static_assert(sizeof(ssize) == sizeof(usize),
"`ssize` is not the same size as `usize`");
using intptr = intptr_t;
using uintptr = uintptr_t;
using ptrdiff = ptrdiff_t;
#define GB_U8_MIN 0u
#define GB_U8_MAX 0xffu
#define GB_S8_MIN (-0x7f - 1)
#define GB_S8_MAX 0x7f
#define GB_U16_MIN 0u
#define GB_U16_MAX 0xffffu
#define GB_S16_MIN (-0x7fff - 1)
#define GB_S16_MAX 0x7fff
#define GB_U32_MIN 0u
#define GB_U32_MAX 0xffffffffu
#define GB_S32_MIN (-0x7fffffff - 1)
#define GB_S32_MAX 0x7fffffff
#define GB_U64_MIN 0ull
#define GB_U64_MAX 0xffffffffffffffffull
#define GB_S64_MIN (-0x7fffffffffffffffll - 1)
#define GB_S64_MAX 0x7fffffffffffffffll
#if defined(GB_ARCH_64_BIT)
#define GB_USIZE_MIX GB_U64_MIN #define GB_USIZE_MIX GB_U64_MIN
#define GB_USIZE_MAX GB_U64_MAX #define GB_USIZE_MAX GB_U64_MAX
#define GB_SSIZE_MIX GB_S64_MIN #define GB_SSIZE_MIX GB_S64_MIN
#define GB_SSIZE_MAX GB_S64_MAX #define GB_SSIZE_MAX GB_S64_MAX
#elif defined(GB_ARCH_32_BIT) #elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
#define GB_USIZE_MIX GB_U32_MIN #define GB_USIZE_MIX GB_U32_MIN
#define GB_USIZE_MAX GB_U32_MAX #define GB_USIZE_MAX GB_U32_MAX
@ -424,7 +450,7 @@ using ptrdiff = ptrdiff_t;
#define GB_SSIZE_MAX GB_S32_MAX #define GB_SSIZE_MAX GB_S32_MAX
#endif #endif
#if defined(GB_BASIC_WITHOUT_NAMESPACE) #if defined(GB_BASIC_WITHOUT_NAMESPACE) && !defined(U8_MIN)
#define U8_MIN 0u #define U8_MIN 0u
#define U8_MAX 0xffu #define U8_MAX 0xffu
#define S8_MIN (-0x7f - 1) #define S8_MIN (-0x7f - 1)
@ -445,13 +471,13 @@ using ptrdiff = ptrdiff_t;
#define S64_MIN (-0x7fffffffffffffffll - 1) #define S64_MIN (-0x7fffffffffffffffll - 1)
#define S64_MAX 0x7fffffffffffffffll #define S64_MAX 0x7fffffffffffffffll
#if defined(GB_ARCH_64_BIT) #if defined(GB_ARCH_64_BIT) && !defined(GB_USIZE_MIX)
#define USIZE_MIX U64_MIN #define USIZE_MIX U64_MIN
#define USIZE_MAX U64_MAX #define USIZE_MAX U64_MAX
#define SSIZE_MIX S64_MIN #define SSIZE_MIX S64_MIN
#define SSIZE_MAX S64_MAX #define SSIZE_MAX S64_MAX
#elif defined(GB_ARCH_32_BIT) #elif defined(GB_ARCH_32_BIT) && !defined(GB_USIZE_MIX)
#define USIZE_MIX U32_MIN #define USIZE_MIX U32_MIN
#define USIZE_MAX U32_MAX #define USIZE_MAX U32_MAX
@ -564,60 +590,68 @@ move(T&& t)
{ {
return static_cast<Remove_Reference<T>&&>(t); return static_cast<Remove_Reference<T>&&>(t);
} }
__GB_NAMESPACE_END
//////////////////////////////// ////////////////////////////////
/// /// /// ///
/// Defer /// /// Defer ///
/// /// /// ///
//////////////////////////////// ////////////////////////////////
namespace impl #ifndef GB_DEFER
{ #define GB_DEFER
template <typename Func> __GB_NAMESPACE_START
struct Defer namespace impl
{ {
Func f; template <typename Func>
struct Defer
{
Func f;
Defer(Func&& f) : f{forward<Func>(f)} {} Defer(Func&& f) : f{forward<Func>(f)} {}
~Defer() { f(); }; ~Defer() { f(); };
}; };
template <typename Func> template <typename Func>
inline Defer<Func> inline Defer<Func>
defer_func(Func&& f) { return Defer<Func>(forward<Func>(f)); } defer_func(Func&& f) { return Defer<Func>(forward<Func>(f)); }
} // namespace impl } // namespace impl
__GB_NAMESPACE_END __GB_NAMESPACE_END
// NOTE(bill): These macros are in the global namespace thus, defer can be treated without a __GB_NAMESPACE_PREFIX:: prefix // NOTE(bill): These macros are in the global namespace thus, defer can be treated without a __GB_NAMESPACE_PREFIX:: prefix
#define GB_DEFER_1(x, y) x##y #define GB_DEFER_1(x, y) x##y
#define GB_DEFER_2(x, y) GB_DEFER_1(x, y) #define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
#define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__) #define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__)
#define defer(code) auto GB_DEFER_3(_defer_) = __GB_NAMESPACE_PREFIX::impl::defer_func([&](){code;}) #define defer(code) auto GB_DEFER_3(_defer_) = __GB_NAMESPACE_PREFIX::impl::defer_func([&](){code;})
#endif
#if !defined(GB_CASTS_WITHOUT_NAMESPACE) #if !defined(GB_CASTS_WITHOUT_NAMESPACE)
__GB_NAMESPACE_START __GB_NAMESPACE_START
#endif // GB_CASTS_WITHOUT_NAMESPACE #endif // GB_CASTS_WITHOUT_NAMESPACE
// IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write #ifndef GB_SPECIAL_CASTS
// however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior #define GB_SPECIAL_CASTS
// *(T*)(&u) ~~ pseudo_cast<T>(u) // IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write
template <typename T, typename U> // however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior
inline T // *(T*)(&u) ~~ pseudo_cast<T>(u)
pseudo_cast(const U& u) template <typename T, typename U>
{ inline T
return reinterpret_cast<const T&>(u); pseudo_cast(const U& u)
} {
return reinterpret_cast<const T&>(u);
}
// NOTE(bill): Very similar to doing `*(T*)(&u)` // NOTE(bill): Very similar to doing `*(T*)(&u)`
template <typename Dest, typename Source> template <typename Dest, typename Source>
inline Dest inline Dest
bit_cast(const Source& source) bit_cast(const Source& source)
{ {
static_assert(sizeof(Dest) <= sizeof(Source), static_assert(sizeof(Dest) <= sizeof(Source),
"bit_cast<Dest>(const Source&) - sizeof(Dest) <= sizeof(Source)"); "bit_cast<Dest>(const Source&) - sizeof(Dest) <= sizeof(Source)");
Dest dest; Dest dest;
::memcpy(&dest, &source, sizeof(Dest)); ::memcpy(&dest, &source, sizeof(Dest));
return dest; return dest;
} }
#endif
// FORENOTE(bill): There used to be a magic_cast that was equivalent to // FORENOTE(bill): There used to be a magic_cast that was equivalent to
// a C-style cast but I removed it as I could not get it work as intented // a C-style cast but I removed it as I could not get it work as intented