gb.hpp v0.25 - gb_math.hpp v0.03

0.25  - Faster Heap_Allocator for Windows using HeapAlloc
0.03  - Remove templated min/max/clamp
This commit is contained in:
gingerBill 2015-11-27 00:20:44 +00:00
parent ddcc482418
commit 2159ae399a
3 changed files with 186 additions and 85 deletions

View File

@ -5,7 +5,7 @@ gb single-file public domain libraries for C & C++
library | latest version | category | languages | description 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.hpp** | 0.24b | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development **gb.hpp** | 0.25 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development
**gb_math.hpp** | 0.02b | math | C++11 | A C++11 math library geared towards game development **gb_math.hpp** | 0.02b | math | C++11 | A C++11 math library geared towards game development
**gb_ini.h** | 0.91a | misc | C, C++ | A simple ini file loader library for C & C++ **gb_ini.h** | 0.91a | misc | C, C++ | A simple ini file loader library for C & C++

143
gb.hpp
View File

@ -1,4 +1,4 @@
// gb.hpp - v0.24b - public domain C++11 helper library - no warranty implied; use at your own risk // gb.hpp - v0.25 - 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
/* /*
@ -218,11 +218,6 @@ CONTENTS:
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#ifndef GB_ARRAY_BOUND_CHECKING
#define GB_ARRAY_BOUND_CHECKING 1
#endif
#ifndef GB_DISABLE_COPY #ifndef GB_DISABLE_COPY
#define GB_DISABLE_COPY(Type) \ #define GB_DISABLE_COPY(Type) \
Type(const Type&) = delete; \ Type(const Type&) = delete; \
@ -838,7 +833,7 @@ namespace thread
Thread make(); Thread make();
void destroy(Thread* t); void destroy(Thread* t);
void start(Thread* t, Thread_Function* func, void* data = nullptr, usize stack_size = 0); void start(Thread* t, Thread_Function* func, void* data = nullptr, usize stack_size = 0);
void stop(Thread* t); void join(Thread* t);
bool is_running(const Thread& t); bool is_running(const Thread& t);
u32 current_id(); u32 current_id();
} // namespace thread } // namespace thread
@ -948,10 +943,18 @@ struct Allocator
/// Allocations are padded with to align them to the desired alignment /// Allocations are padded with to align them to the desired alignment
struct Heap_Allocator : Allocator struct Heap_Allocator : Allocator
{ {
Mutex mutex = mutex::make(); struct Header
{
usize size;
};
s64 total_allocated_count = 0; s64 total_allocated_count = 0;
s64 allocation_count = 0; s64 allocation_count = 0;
#if defined(GB_SYSTEM_WINDOWS)
HANDLE heap_handle = HeapCreate(0, 0, 0);
#endif
Heap_Allocator() = default; Heap_Allocator() = default;
virtual ~Heap_Allocator(); virtual ~Heap_Allocator();
@ -1042,6 +1045,7 @@ void* copy(const void* src, usize bytes, void* dest);
void* move(const void* src, usize bytes, void* dest); void* move(const void* src, usize bytes, void* dest);
bool equals(const void* a, const void* b, usize bytes); bool equals(const void* a, const void* b, usize bytes);
// TODO(bill): Should this be just zero(T*) ???
template <typename T> template <typename T>
T* zero_struct(T* ptr); T* zero_struct(T* ptr);
@ -1049,6 +1053,12 @@ template <typename T>
T* copy_array(const T* src_array, usize count, T* dest_array); T* copy_array(const T* src_array, usize count, T* dest_array);
// TODO(bill): Should I implement something like std::copy, std::fill, std::fill_n ??? // TODO(bill): Should I implement something like std::copy, std::fill, std::fill_n ???
template <typename T>
void swap(T* a, T* b);
template <typename T, usize N>
void swap(T (& a)[N], T (& b)[N]);
} // namespace memory } // namespace memory
void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT); void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT);
@ -1148,6 +1158,10 @@ void format_uint(u64 value, char* buffer, usize len);
/// /// /// ///
//////////////////////////////// ////////////////////////////////
#ifndef GB_ARRAY_BOUND_CHECKING
#define GB_ARRAY_BOUND_CHECKING 1
#endif
/// Dynamic resizable array for POD types only /// Dynamic resizable array for POD types only
template <typename T> template <typename T>
struct Array struct Array
@ -1281,7 +1295,6 @@ template <typename T> void remove_entry(Hash_Table<T>* h, typename const Hash_Ta
template <typename T> void remove_all(Hash_Table<T>* h, u64 key); template <typename T> void remove_all(Hash_Table<T>* h, u64 key);
} // namespace multi_hash_table } // namespace multi_hash_table
//////////////////////////////// ////////////////////////////////
/// /// /// ///
/// Hash /// /// Hash ///
@ -1519,9 +1532,9 @@ Array<T>::Array(const Array<T>& other)
, capacity(0) , capacity(0)
, data(nullptr) , data(nullptr)
{ {
const auto n = other.count; const auto count = other.count;
array::set_capacity(this, n); array::set_capacity(this, count);
memory::copy(other.data, n * sizeof(T), data); memory::copy_array(other.data, count, data);
count = n; count = n;
} }
@ -1552,9 +1565,9 @@ Array<T>::operator=(const Array<T>& other)
{ {
if (allocator == nullptr) if (allocator == nullptr)
allocator = other.allocator; allocator = other.allocator;
const auto n = other.count; const auto count = other.count;
array::resize(this, n); array::resize(this, count);
memory::copy(other.data, n * sizeof(T), data); memory::copy_count(other.data, count, data);
return *this; return *this;
} }
@ -1660,7 +1673,7 @@ append(Array<T>* a, const T* items, usize count)
if (a->capacity <= a->count + static_cast<s64>(count)) if (a->capacity <= a->count + static_cast<s64>(count))
array::grow(a, a->count + count); array::grow(a, a->count + count);
memory::copy(items, count * sizeof(T), &a->data[a->count]); memory::copy_array(items, count, &a->data[a->count]);
a->count += count; a->count += count;
} }
@ -1711,7 +1724,7 @@ set_capacity(Array<T>* a, usize capacity)
if (capacity > 0) if (capacity > 0)
{ {
data = alloc_array<T>(a->allocator, capacity); data = alloc_array<T>(a->allocator, capacity);
memory::copy(a->data, a->count * sizeof(T), data); memory::copy_array(a->data, a->count, data);
} }
dealloc(a->allocator, a->data); dealloc(a->allocator, a->data);
a->data = data; a->data = data;
@ -2200,6 +2213,23 @@ copy_array(const T* src_array, usize count, T* dest_array)
{ {
return static_cast<T*>(memory::copy(src_array, count * sizeof(T), dest_array)); return static_cast<T*>(memory::copy(src_array, count * sizeof(T), dest_array));
} }
template <typename T>
inline void
swap(T* a, T* b)
{
T c = __GB_NAMESPACE_START::move(*a);
*a = __GB_NAMESPACE_START::move(*b);
*b = __GB_NAMESPACE_START::move(c);
}
template <typename T, usize N>
inline void
swap(T (& a)[N], T (& b)[N])
{
for (usize i = 0; i < N; i++)
math::swap(&a[i], &b[i]);
}
} // namespace memory } // namespace memory
@ -2607,7 +2637,7 @@ void
destroy(Thread* t) destroy(Thread* t)
{ {
if (t->is_running) if (t->is_running)
thread::stop(t); thread::join(t);
semaphore::destroy(&t->semaphore); semaphore::destroy(&t->semaphore);
} }
@ -2677,7 +2707,7 @@ start(Thread* t, Thread_Function* func, void* data, usize stack_size)
} }
void void
stop(Thread* t) join(Thread* t)
{ {
if (!t->is_running) if (!t->is_running)
return; return;
@ -2705,13 +2735,11 @@ current_id()
{ {
u32 thread_id; u32 thread_id;
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
u8* thread_local_storage = reinterpret_cast<u8*>(__readgsqword(0x30)); u8* thread_local_storage = reinterpret_cast<u8*>(__readgsqword(0x30));
thread_id = *reinterpret_cast<u32*>(thread_local_storage + 0x48); thread_id = *reinterpret_cast<u32*>(thread_local_storage + 0x48);
#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT) #elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
u32 thread_id;
asm("mov %%gs:0x00,%0" : "=r"(thread_id)); asm("mov %%gs:0x00,%0" : "=r"(thread_id));
#elif defined(GB_ARCH_32_BIT) #elif defined(GB_ARCH_32_BIT)
asm("mov %%gs:0x08,%0" : "=r"(thread_id)); asm("mov %%gs:0x08,%0" : "=r"(thread_id));
@ -2721,7 +2749,6 @@ current_id()
#error Unsupported architecture for thread::current_id() #error Unsupported architecture for thread::current_id()
#endif #endif
return thread_id; return thread_id;
} }
@ -2886,24 +2913,32 @@ free(Data* tmp)
#else #else
//#define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1)
Heap_Allocator::~Heap_Allocator() Heap_Allocator::~Heap_Allocator()
{ {
#if 0 #if defined (GB_SYSTEM_WINDOWS)
GB_ASSERT(allocation_count == 0 && total_allocated() == 0, HeapDestroy(heap_handle);
"Heap Allocator: allocation count = %lld; total allocated = %lld", #else
allocation_count, total_allocated());
#endif #endif
} }
void* void*
Heap_Allocator::alloc(usize size, usize align) Heap_Allocator::alloc(usize size, usize align)
{ {
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
usize total = size + align - (size % align); usize total = size + align - (size % align);
#if defined (GB_SYSTEM_WINDOWS)
total += sizeof(Header);
void* data = HeapAlloc(heap_handle, 0, total);
Header* h = static_cast<Header*>(data);
h->size = total;
data = (h + 1);
#else
// TODO(bill): Find a better malloc alternative for this platform
void* data = malloc(total); void* data = malloc(total);
#endif
total_allocated_count += total; total_allocated_count += total;
allocation_count++; allocation_count++;
@ -2917,27 +2952,34 @@ Heap_Allocator::dealloc(const void* ptr)
if (!ptr) if (!ptr)
return; return;
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
total_allocated_count -= this->allocated_size(ptr); total_allocated_count -= this->allocated_size(ptr);
allocation_count--; allocation_count--;
#if defined (GB_SYSTEM_WINDOWS)
ptr = static_cast<const Header*>(ptr) + 1;
HeapFree(heap_handle, 0, const_cast<void*>(ptr));
#else
::free(const_cast<void*>(ptr)); ::free(const_cast<void*>(ptr));
#endif
} }
inline s64 inline s64
Heap_Allocator::allocated_size(const void* ptr) Heap_Allocator::allocated_size(const void* ptr)
{ {
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
return static_cast<usize>(_msize(const_cast<void*>(ptr))); const Header* h = static_cast<const Header*>(ptr) - 1;
return static_cast<usize>(h->size);
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
return static_cast<usize>(malloc_size(ptr)); return static_cast<usize>(malloc_size(ptr));
#else
#elif defined(GB_SYSTEM_LINUX)
return static_cast<usize>(malloc_usable_size(const_cast<void*>(ptr))); return static_cast<usize>(malloc_usable_size(const_cast<void*>(ptr)));
#else
#error Implement Heap_Allocator::allocated_size
#endif #endif
} }
@ -2971,8 +3013,10 @@ Arena_Allocator::~Arena_Allocator()
if (backing) if (backing)
backing->dealloc(physical_start); backing->dealloc(physical_start);
GB_ASSERT(total_allocated_count == 0, GB_ASSERT(temp_count == 0,
"Memory leak of %ld bytes, maybe you forgot to call arena_allocator::clear()?", total_allocated_count); "%ld Temporary_Arena_Memory have not be cleared", temp_count);
total_allocated_count = 0;
} }
void* void*
@ -3035,7 +3079,6 @@ free(Temporary_Arena_Memory* tmp)
#endif #endif
//////////////////////////////// ////////////////////////////////
/// /// /// ///
/// Memory /// /// Memory ///
@ -3197,17 +3240,19 @@ make(Allocator* a, const void* init_str, Size len)
{ {
usize header_size = sizeof(string::Header); usize header_size = sizeof(string::Header);
void* ptr = alloc(a, header_size + len + 1); void* ptr = alloc(a, header_size + len + 1);
if (!ptr)
return nullptr;
if (!init_str) if (!init_str)
memory::zero(ptr, header_size + len + 1); memory::zero(ptr, header_size + len + 1);
if (ptr == nullptr)
return nullptr;
String str = static_cast<char*>(ptr) + header_size; String str = static_cast<char*>(ptr) + header_size;
string::Header* header = string::header(str); string::Header* header = string::header(str);
header->allocator = a; header->allocator = a;
header->len = len; header->len = len;
header->cap = len; header->cap = len;
if (len && init_str) if (len && init_str)
memory::copy(init_str, len, str); memory::copy(init_str, len, str);
str[len] = '\0'; str[len] = '\0';
@ -3220,10 +3265,11 @@ free(String str)
{ {
if (str == nullptr) if (str == nullptr)
return; return;
string::Header* h = string::header(str); string::Header* h = string::header(str);
Allocator* a = h->allocator;
if (a) if (h->allocator)
dealloc(a, h); dealloc(h->allocator, h);
} }
inline String inline String
@ -3337,7 +3383,7 @@ make_space_for(String* str, Size add_len)
if (available >= add_len) // Return if there is enough space left if (available >= add_len) // Return if there is enough space left
return; return;
void* ptr = reinterpret_cast<string::Header*>(*str) - 1; void* ptr = reinterpret_cast<string::Header*>(str) - 1;
usize old_size = sizeof(string::Header) + string::length(*str) + 1; usize old_size = sizeof(string::Header) + string::length(*str) + 1;
usize new_size = sizeof(string::Header) + new_len + 1; usize new_size = sizeof(string::Header) + new_len + 1;
@ -4302,6 +4348,7 @@ __GB_NAMESPACE_END
/* /*
Version History: Version History:
0.25 - Faster Heap_Allocator for Windows using HeapAlloc
0.24b - Even More Hash_Table Bug Fixes 0.24b - Even More Hash_Table Bug Fixes
0.24a - Hash_Table Bug Fixes 0.24a - Hash_Table Bug Fixes
0.24 - More documentation and bug fixes 0.24 - More documentation and bug fixes

View File

@ -1,9 +1,10 @@
// gb_math.hpp - v0.02b - public domain C++11 math library - no warranty implied; use at your own risk // gb_math.hpp - v0.03 - public domain C++11 math library - no warranty implied; use at your own risk
// A C++11 math library geared towards game development // A C++11 math library geared towards game development
// This is meant to be used the gb.hpp library but it doesn't have to be // This is meant to be used the gb.hpp library but it doesn't have to be
/* /*
Version History: Version History:
0.03 - Remove templated min/max/clamp
0.02b - Typo fixes 0.02b - Typo fixes
0.02a - Better `static` keywords 0.02a - Better `static` keywords
0.02 - More Angle Units and templated min/max/clamp/lerp 0.02 - More Angle Units and templated min/max/clamp/lerp
@ -95,6 +96,21 @@ CONTENTS:
#error This operating system is not supported by gb.hpp #error This operating system is not supported by gb.hpp
#endif #endif
#if defined(_MSC_VER)
// Microsoft Visual Studio
#define GB_COMPILER_MSVC 1
#elif defined(__clang__)
// Clang
#define GB_COMPILER_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__) && !(defined(__clang__) || defined(__INTEL_COMPILER))
// GNU GCC/G++ Compiler
#define GB_COMPILER_GNU_GCC 1
#elif defined(__INTEL_COMPILER)
// Intel C++ Compiler
#define GB_COMPILER_INTEL 1
#endif
//////////////////////////////// ////////////////////////////////
/// /// /// ///
/// Environment Bit Size /// /// Environment Bit Size ///
@ -125,6 +141,7 @@ CONTENTS:
#endif #endif
#endif #endif
// TODO(bill): Get this to work // TODO(bill): Get this to work
// #if !defined(GB_LITTLE_EDIAN) && !defined(GB_BIG_EDIAN) // #if !defined(GB_LITTLE_EDIAN) && !defined(GB_BIG_EDIAN)
@ -911,26 +928,24 @@ f32 kronecker_delta(f32 i, f32 j);
#undef min #undef min
#undef max #undef max
template <typename T> f32 min(f32 x, f32 y);
const T& min(const T& a, const T& b); s32 min(s32 x, s32 y);
s64 min(s64 x, s64 y);
template <typename T> f32 max(f32 x, f32 y);
const T& max(const T& a, const T& b); s32 max(s32 x, s32 y);
s64 max(s64 x, s64 y);
template <typename T> f32 clamp(f32 x, f32 min, f32 max);
T clamp(const T& x, const T& min, const T& max); s32 clamp(s32 x, s32 min, s32 max);
s64 clamp(s64 x, s64 min, s64 max);
// TODO(bill): Should this be a template or just normal function overloading?
template <typename T> template <typename T>
T lerp(const T& x, const T& y, f32 t); T lerp(const T& x, const T& y, f32 t);
bool equals(f32 a, f32 b, f32 precision = F32_PRECISION); bool equals(f32 a, f32 b, f32 precision = F32_PRECISION);
template <typename T>
void swap(T* a, T* b);
template <typename T, usize N>
void swap(T (& a)[N], T (& b)[N]);
// Vector2 functions // Vector2 functions
f32 dot(const Vector2& a, const Vector2& b); f32 dot(const Vector2& a, const Vector2& b);
f32 cross(const Vector2& a, const Vector2& b); f32 cross(const Vector2& a, const Vector2& b);
@ -1138,9 +1153,6 @@ f32 perlin_3d(f32 x, f32 y, f32 z, s32 x_wrap = 0, s32 y_wrap = 0, s32 z_wrap =
namespace math namespace math
{ {
template <typename T> inline const T& min(const T& a, const T& b) { return a < b ? a : b; }
template <typename T> inline const T& max(const T& a, const T& b) { return a > b ? a : b; }
template <typename T> template <typename T>
inline T inline T
clamp(const T& x, const T& min, const T& max) clamp(const T& x, const T& min, const T& max)
@ -2361,29 +2373,71 @@ kronecker_delta(f32 i, f32 j)
return static_cast<f32>(i == j); return static_cast<f32>(i == j);
} }
inline f32
min(f32 x, f32 y)
{
// TODO(bill): Check if this is even good
return x < y ? x : y;
}
inline s32
min(s32 x, s32 y)
{
return y + ((x-y) & (x-y)>>31);
}
inline s64
min(s64 x, s64 y)
{
return y + ((x-y) & (x-y)>>63);
}
inline f32
max(f32 x, f32 y)
{
// TODO(bill): Check if this is even good
return x > y ? x : y;
}
inline s32
max(s32 x, s32 y)
{
return x - ((x-y) & (x-y)>>31);
}
inline s64
max(s64 x, s64 y)
{
return x - ((x-y) & (x-y)>>63);
}
inline f32
clamp(f32 x, f32 min, f32 max)
{
const f32 t = x < min ? min : x;
return t > max ? max : t;
}
inline s32
clamp(s32 x, s32 min, s32 max)
{
const s32 t = x < min ? min : x;
return t > max ? max : t;
}
inline s64
clamp(s64 x, s64 min, s64 max)
{
const s64 t = x < min ? min : x;
return t > max ? max : t;
}
inline bool inline bool
equals(f32 a, f32 b, f32 precision) equals(f32 a, f32 b, f32 precision)
{ {
return ((b <= (a + precision)) && (b >= (a - precision))); return ((b <= (a + precision)) && (b >= (a - precision)));
} }
template <typename T>
inline void
swap(T* a, T* b)
{
T c = __GB_NAMESPACE_PREFIX::move(*a);
*a = __GB_NAMESPACE_PREFIX::move(*b);
*b = __GB_NAMESPACE_PREFIX::move(c);
}
template <typename T, usize N>
inline void
swap(T (& a)[N], T (& b)[N])
{
for (usize i = 0; i < N; i++)
math::swap(&a[i], &b[i]);
}
// Vector2 functions // Vector2 functions
inline f32 inline f32
dot(const Vector2& a, const Vector2& b) dot(const Vector2& a, const Vector2& b)