diff --git a/README.md b/README.md index 40756a5..71a3043 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ gb single-file public domain libraries for C & C++ library | latest version | category | languages | description ----------------|----------------|----------|-----------|------------- **gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++ -**gb.hpp** | 0.22 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development +**gb.hpp** | 0.23 | 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_ini.h** | 0.91 | misc | C, C++ | A simple ini file loader library for C & C++ diff --git a/gb.hpp b/gb.hpp index c2c064a..13c8e4d 100644 --- a/gb.hpp +++ b/gb.hpp @@ -1,8 +1,9 @@ -// gb.hpp - v0.22 - public domain C++11 helper library - no warranty implied; use at your own risk +// gb.hpp - v0.23 - 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 /* Version History: + 0.23 - Move Semantics for Array and Hash_Table 0.22 - Code rearrangment into namespaces 0.21d - Fix array::free 0.21c - Fix Another Typo causing unresolved external symbol @@ -861,11 +862,6 @@ struct Allocator /// the allocation and align them to the desired alignment struct Heap_Allocator : Allocator { - struct Header - { - s64 size; - }; - Mutex mutex = mutex::make(); s64 total_allocated_count = 0; s64 allocation_count = 0; @@ -922,12 +918,6 @@ struct Temp_Allocator : Allocator virtual s64 total_allocated() { return -1; } }; - -namespace heap_allocator -{ -Heap_Allocator::Header* get_header_ptr(const void* ptr); -} // namespace heap_allocator - namespace arena_allocator { void clear(Arena_Allocator* arena); @@ -957,7 +947,6 @@ bool equals(const void* a, const void* b, usize bytes); inline void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT) { GB_ASSERT(a != nullptr); return a->alloc(size, align); } inline void dealloc(Allocator* a, const void* ptr) { GB_ASSERT(a != nullptr); return a->dealloc(ptr); } -// TODO(bill): Should I overload free() or not would that be too confusing? template inline T* alloc_struct(Allocator* a) { return static_cast(alloc(a, sizeof(T), alignof(T))); } @@ -1064,28 +1053,18 @@ struct Array T* data; Array() = default; - Array(const Array& array); explicit Array(Allocator* a, usize count = 0); + ~Array(); + + Array(const Array& array); + Array(Array&& array); + Array& operator=(const Array& array); + Array& operator=(Array&& array); - inline const T& - operator[](usize index) const - { -#if GB_ARRAY_BOUND_CHECKING - GB_ASSERT(index < static_cast(capacity), "Array out of bounds"); -#endif - return data[index]; - } - - inline T& - operator[](usize index) - { -#if GB_ARRAY_BOUND_CHECKING - GB_ASSERT(index < static_cast(capacity), "Array out of bounds"); -#endif - return data[index]; - } + const T& operator[](usize index) const; + T& operator[](usize index); }; namespace array @@ -1096,6 +1075,7 @@ template void free(Array* array); /// Appends `item` to the end of the array template void append(Array* a, const T& item); +template void append(Array* a, T&& item); /// Appends `items[count]` to the end of the array template void append(Array* a, const T* items, usize count); @@ -1158,6 +1138,7 @@ template bool has(const Hash_Table& h, u64 key); template const T& get(const Hash_Table& h, u64 key, const T& default_value); /// Sets the value for the key in the hash table template void set(Hash_Table* h, u64 key, const T& value); +template void set(Hash_Table* h, u64 key, T&& value); /// Removes the key from the hash table if it exists template void remove(Hash_Table* h, u64 key); /// Resizes the hash table's lookup table to the specified size @@ -1184,6 +1165,7 @@ template typename const Hash_Table::Entry* find_next(const Hash_ /// Inserts the `value` as an additional value for the specified key template void insert(Hash_Table* h, u64 key, const T& value); +template void insert(Hash_Table* h, u64 key, T&& value); /// Removes a specified entry `e` from the hash table template void remove_entry(Hash_Table* h, typename const Hash_Table::Entry* e); /// Removes all entries with from the hash table with the specified key @@ -1511,12 +1493,27 @@ Array::Array(const Array& other) count = n; } +template +inline +Array::Array(Array&& other) +: allocator(nullptr) +, count(0) +, capacity(0) +, data(nullptr) +{ + *this = move(other); +} + + template inline Array::~Array() { if (allocator && capacity > 0) dealloc(allocator, data); + count = 0; + capacity = 0; + data = nullptr; } @@ -1533,6 +1530,44 @@ Array::operator=(const Array& other) } +template +Array& +Array::operator=(Array&& other) +{ + if (this != &other) + { + if (allocator && capacity > 0) + dealloc(allocator, data); + + *this = move(other); + } + + return *this; +} + + + +template +inline const T& +Array::operator[](usize index) const +{ +#if GB_ARRAY_BOUND_CHECKING + GB_ASSERT(index < static_cast(capacity), "Array out of bounds"); +#endif + return data[index]; +} + +template +inline T& +Array::operator[](usize index) +{ +#if GB_ARRAY_BOUND_CHECKING + GB_ASSERT(index < static_cast(capacity), "Array out of bounds"); +#endif + return data[index]; +} + + namespace array { template @@ -1557,9 +1592,9 @@ free(Array* a) { if (a->allocator) dealloc(a->allocator, a->data); - a->count = 0; + a->count = 0; a->capacity = 0; - a->data = nullptr; + a->data = nullptr; } template @@ -1571,6 +1606,16 @@ append(Array* a, const T& item) a->data[a->count++] = item; } + +template +inline void +append(Array* a, T&& item) +{ + if (a->capacity < a->count + 1) + array::grow(a); + a->data[a->count++] = move(item); +} + template inline void append(Array* a, const T* items, usize count) @@ -1578,7 +1623,7 @@ append(Array* a, const T* items, usize count) if (a->capacity <= a->count + static_cast(count)) array::grow(a, a->count + count); - memory::copy(&a->data[a->count], items, count * sizeof(T)); + memory::copy(a->data + a->count, items, count * sizeof(T)); a->count += count; } @@ -1595,7 +1640,7 @@ template inline void clear(Array* a) { - array::resize(a, 0); + a->count = 0; } template @@ -1640,7 +1685,8 @@ template inline void grow(Array* a, usize min_capacity) { - usize capacity = 2 * a->capacity + 2; + // TODO(bill): Decide on decent growing formula for Array + usize capacity = 2 * a->capacity + 8; if (capacity < min_capacity) capacity = min_capacity; set_capacity(a, capacity); @@ -1930,6 +1976,19 @@ set(Hash_Table* h, u64 key, const T& value) impl::grow(h); } +template +inline void +set(Hash_Table* h, u64 key, T&& value) +{ + if (h->hashes.count == 0) + impl::grow(h); + + const s64 index = impl::find_or_make_entry(h, key); + h->entries[index].value = move(value); + if (impl::is_full(h)) + impl::grow(h); +} + template inline void remove(Hash_Table* h, u64 key) @@ -2041,6 +2100,20 @@ insert(Hash_Table* h, u64 key, const T& value) hash_table::impl::grow(h); } +template +inline void +insert(Hash_Table* h, u64 key, T&& value) +{ + if (h->hashes.count == 0) + hash_table::impl::grow(h); + + auto next = hash_table::impl::make_entry(h, key); + h->entries[next].value = move(value); + + if (hash_table::impl::is_full(h)) + hash_table::impl::grow(h); +} + template inline void remove_entry(Hash_Table* h, typename const Hash_Table::Entry* e) @@ -2563,7 +2636,7 @@ is_running(const Thread& thread) -#define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1) +//#define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1) Heap_Allocator::~Heap_Allocator() { #if 0 @@ -2573,37 +2646,15 @@ Heap_Allocator::~Heap_Allocator() #endif } -namespace heap_allocator -{ -inline Heap_Allocator::Header* -get_header_ptr(const void* ptr) -{ - const usize* data = reinterpret_cast(ptr) - 1; - - while (*data == GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE) - data--; - - return (Heap_Allocator::Header*)(data); -} -} // namespace heap_allocator - void* Heap_Allocator::alloc(usize size, usize align) { mutex::lock(&mutex); defer (mutex::unlock(&mutex)); - const usize total = size + align + sizeof(Header); - Header* h = static_cast(::malloc(total)); - h->size = total; + usize total = size + align - (size % align); + void* data = malloc(total); - void* data = memory::align_forward(h + 1, align); - { // Pad header - usize* ptr = reinterpret_cast(h+1); - - while (ptr != data) - *ptr++ = GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE; - } total_allocated_count += total; allocation_count++; @@ -2619,13 +2670,10 @@ Heap_Allocator::dealloc(const void* ptr) mutex::lock(&mutex); defer (mutex::unlock(&mutex)); - - Header* h = heap_allocator::get_header_ptr(ptr); - - total_allocated_count -= h->size; + total_allocated_count -= this->allocated_size(ptr); allocation_count--; - ::free(h); + ::free(const_cast(ptr)); } s64 @@ -2634,7 +2682,15 @@ Heap_Allocator::allocated_size(const void* ptr) mutex::lock(&mutex); defer (mutex::unlock(&mutex)); - return heap_allocator::get_header_ptr(ptr)->size; +#if defined(GB_SYSTEM_WINDOWS) + return static_cast(_msize(const_cast(ptr))); +#elif defined(GB_SYSTEM_OSX) + return static_cast(malloc_size(ptr)); +#else + return static_cast(malloc_usable_size(const_cast(ptr))); + return +#endif + } s64