Better Allocation system
This commit is contained in:
parent
16c31df712
commit
0d09743505
|
@ -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.25a | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development
|
**gb.hpp** | 0.26 | 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++
|
||||||
|
|
||||||
|
|
430
gb.hpp
430
gb.hpp
|
@ -1,4 +1,4 @@
|
||||||
// gb.hpp - v0.25a - public domain C++11 helper library - no warranty implied; use at your own risk
|
// gb.hpp - v0.26 - 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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,7 +30,6 @@ CONTENTS:
|
||||||
- Allocator
|
- Allocator
|
||||||
- Heap Allocator
|
- Heap Allocator
|
||||||
- Arena Allocator
|
- Arena Allocator
|
||||||
- Temporary Arena Memory
|
|
||||||
- Functions
|
- Functions
|
||||||
- String
|
- String
|
||||||
- Array
|
- Array
|
||||||
|
@ -224,6 +223,12 @@ CONTENTS:
|
||||||
Type& operator=(const Type&) = delete
|
Type& operator=(const Type&) = delete
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GB_DISABLE_MOVE
|
||||||
|
#define GB_DISABLE_MOVE(Type) \
|
||||||
|
Type(Type&&) = delete; \
|
||||||
|
Type& operator=(Type&&) = delete
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(GB_ASSERT)
|
#if !defined(GB_ASSERT)
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
|
#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
|
||||||
|
@ -747,6 +752,11 @@ __GB_NAMESPACE_START
|
||||||
template <typename T, usize N>
|
template <typename T, usize N>
|
||||||
inline usize array_count(T(& )[N]) { return N; }
|
inline usize array_count(T(& )[N]) { return N; }
|
||||||
|
|
||||||
|
inline s64 kilobytes(s64 x) { return (x) * 1024ll; }
|
||||||
|
inline s64 megabytes(s64 x) { return kilobytes(x) * 1024ll; }
|
||||||
|
inline s64 gigabytes(s64 x) { return megabytes(x) * 1024ll; }
|
||||||
|
inline s64 terabytes(s64 x) { return gigabytes(x) * 1024ll; }
|
||||||
|
|
||||||
/// Mutex
|
/// Mutex
|
||||||
struct Mutex
|
struct Mutex
|
||||||
{
|
{
|
||||||
|
@ -841,106 +851,27 @@ u32 current_id();
|
||||||
|
|
||||||
/// Default alignment for memory allocations
|
/// Default alignment for memory allocations
|
||||||
#ifndef GB_DEFAULT_ALIGNMENT
|
#ifndef GB_DEFAULT_ALIGNMENT
|
||||||
#if defined(GB_ARCH_32_BIT)
|
#define GB_DEFAULT_ALIGNMENT 8
|
||||||
#define GB_DEFAULT_ALIGNMENT 4
|
#endif
|
||||||
#elif defined(GB_ARCH_64_BIT)
|
|
||||||
#define GB_DEFAULT_ALIGNMENT 8
|
|
||||||
#else
|
|
||||||
#define GB_DEFAULT_ALIGNMENT 4
|
|
||||||
#endif
|
|
||||||
#endif GB_DEFAULT_ALIGNMENT
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): This is just an idea I have been having
|
|
||||||
#if 0 || defined(GB_USE_C_STYLE_ALLOCATOR)
|
|
||||||
|
|
||||||
|
/// Base class for memory allocators - Pretty much a vtable
|
||||||
struct Allocator
|
struct Allocator
|
||||||
{
|
{
|
||||||
// TODO(bill): Should I even have these typedefs?
|
|
||||||
using Alloc = void*(struct Allocator* a, usize size, usize align);
|
|
||||||
using Dealloc = void (struct Allocator* a, const void* ptr);
|
|
||||||
using Allocated_Size = s64 (struct Allocator* a, const void* ptr);
|
|
||||||
using Total_Allocated = s64 (struct Allocator* a);
|
|
||||||
|
|
||||||
void* data;
|
|
||||||
|
|
||||||
Alloc* alloc;
|
|
||||||
Dealloc* dealloc;
|
|
||||||
Allocated_Size* allocated_size;
|
|
||||||
Total_Allocated* total_allocated;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace heap_allocator
|
|
||||||
{
|
|
||||||
struct Data
|
|
||||||
{
|
|
||||||
Mutex mutex = mutex::make();
|
|
||||||
s64 total_allocated_count = 0;
|
|
||||||
s64 allocation_count = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Allocator make();
|
|
||||||
void destroy(Allocator* heap_allocator);
|
|
||||||
} // namespace heap_allocator
|
|
||||||
|
|
||||||
|
|
||||||
namespace arena_allocator
|
|
||||||
{
|
|
||||||
struct Data
|
|
||||||
{
|
|
||||||
Allocator* backing;
|
|
||||||
void* physical_start;
|
|
||||||
s64 total_size;
|
|
||||||
s64 total_allocated_count;
|
|
||||||
s64 temp_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
Allocator make(Allocator* backing, usize size);
|
|
||||||
Allocator make(void* start, usize size);
|
|
||||||
void destroy(Allocator* arena);
|
|
||||||
void clear(Allocator* arena);
|
|
||||||
} // namespace arena_allocator
|
|
||||||
|
|
||||||
namespace temporary_arena_memory
|
|
||||||
{
|
|
||||||
struct Data
|
|
||||||
{
|
|
||||||
Allocator* arena;
|
|
||||||
s64 original_count;
|
|
||||||
};
|
|
||||||
Data make(Allocator* arena);
|
|
||||||
void free(Data* tmp);
|
|
||||||
} // namespace temporary_arena_memory
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/// Base class for memory allocators
|
|
||||||
struct Allocator
|
|
||||||
{
|
|
||||||
Allocator() {}
|
|
||||||
virtual ~Allocator() {}
|
|
||||||
|
|
||||||
GB_DISABLE_COPY(Allocator);
|
|
||||||
|
|
||||||
/// Allocates the specified amount of memory aligned to the specified alignment
|
/// Allocates the specified amount of memory aligned to the specified alignment
|
||||||
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT) = 0;
|
void* (*alloc)(Allocator* a, usize size, usize align);
|
||||||
/// Deallocates/frees an allocation made with alloc()
|
/// Deallocates/frees an allocation made with alloc()
|
||||||
virtual void dealloc(const void* ptr) = 0;
|
void (*dealloc)(Allocator* a, const void* ptr);
|
||||||
/// Returns the amount of usuable memory allocated at `ptr`.
|
/// Returns the amount of usuable memory allocated at `ptr`.
|
||||||
///
|
///
|
||||||
/// If the allocator does not support tracking of the allocation size,
|
/// If the allocator does not support tracking of the allocation size,
|
||||||
/// the function will return -1
|
/// the function will return -1
|
||||||
virtual s64 allocated_size(const void* ptr) = 0;
|
s64 (*allocated_size)(Allocator* a, const void* ptr);
|
||||||
/// Returns the total amount of memory allocated by this allocator
|
/// Returns the total amount of memory allocated by this allocator
|
||||||
///
|
///
|
||||||
/// If the allocator does not track memory, the function will return -1
|
/// If the allocator does not track memory, the function will return -1
|
||||||
virtual s64 total_allocated() = 0;
|
s64 (*total_allocated)(Allocator* a);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// An allocator that uses the `malloc()`.
|
|
||||||
/// Allocations are padded with to align them to the desired alignment
|
|
||||||
struct Heap_Allocator : Allocator
|
struct Heap_Allocator : Allocator
|
||||||
{
|
{
|
||||||
struct Header
|
struct Header
|
||||||
|
@ -948,49 +879,21 @@ struct Heap_Allocator : Allocator
|
||||||
usize size;
|
usize size;
|
||||||
};
|
};
|
||||||
|
|
||||||
s64 total_allocated_count = 0;
|
s64 total_allocated_count;
|
||||||
s64 allocation_count = 0;
|
s64 allocation_count;
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
HANDLE heap_handle = HeapCreate(0, 0, 0);
|
HANDLE heap_handle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Heap_Allocator() = default;
|
|
||||||
virtual ~Heap_Allocator();
|
|
||||||
|
|
||||||
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
|
|
||||||
virtual void dealloc(const void* ptr);
|
|
||||||
virtual s64 allocated_size(const void* ptr);
|
|
||||||
virtual s64 total_allocated();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <usize BUFFER_SIZE>
|
namespace heap_allocator
|
||||||
struct Temp_Allocator : Allocator
|
|
||||||
{
|
{
|
||||||
u8 buffer[BUFFER_SIZE];
|
Heap_Allocator make();
|
||||||
Allocator* backing;
|
void destroy(Heap_Allocator* heap);
|
||||||
u8* physical_start;
|
} // namespaceheap_allocator
|
||||||
u8* current_pointer;
|
|
||||||
u8* physical_end;
|
|
||||||
usize chunk_size; // Chunks to allocate from backing allocator
|
|
||||||
|
|
||||||
explicit Temp_Allocator(Allocator* backing);
|
// TODO(bill): Implement more Allocator types
|
||||||
virtual ~Temp_Allocator();
|
|
||||||
|
|
||||||
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
|
|
||||||
virtual void dealloc(const void*) {}
|
|
||||||
virtual s64 allocated_size(const void*) { return -1; }
|
|
||||||
virtual s64 total_allocated() { return -1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Predefined Temp_Allocator sizes to prevent unneeded template instantiation
|
|
||||||
using Temp_Allocator_64 = Temp_Allocator<64>;
|
|
||||||
using Temp_Allocator_128 = Temp_Allocator<128>;
|
|
||||||
using Temp_Allocator_256 = Temp_Allocator<256>;
|
|
||||||
using Temp_Allocator_512 = Temp_Allocator<512>;
|
|
||||||
using Temp_Allocator_1024 = Temp_Allocator<1024>;
|
|
||||||
using Temp_Allocator_2048 = Temp_Allocator<2048>;
|
|
||||||
using Temp_Allocator_4096 = Temp_Allocator<4096>;
|
|
||||||
|
|
||||||
struct Arena_Allocator : Allocator
|
struct Arena_Allocator : Allocator
|
||||||
{
|
{
|
||||||
|
@ -999,37 +902,28 @@ struct Arena_Allocator : Allocator
|
||||||
s64 total_size;
|
s64 total_size;
|
||||||
s64 total_allocated_count;
|
s64 total_allocated_count;
|
||||||
s64 temp_count;
|
s64 temp_count;
|
||||||
|
|
||||||
explicit Arena_Allocator(Allocator* backing, usize size);
|
|
||||||
explicit Arena_Allocator(void* start, usize size);
|
|
||||||
virtual ~Arena_Allocator();
|
|
||||||
|
|
||||||
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
|
|
||||||
virtual void dealloc(const void* ptr);
|
|
||||||
virtual s64 allocated_size(const void* ptr);
|
|
||||||
virtual s64 total_allocated();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace arena_allocator
|
||||||
|
{
|
||||||
|
Arena_Allocator make(Allocator* backing, usize size);
|
||||||
|
Arena_Allocator make(void* start, usize size);
|
||||||
|
void destroy(Arena_Allocator* arena);
|
||||||
|
void clear(Arena_Allocator* arena);
|
||||||
|
} // namespace arena_allocator
|
||||||
|
|
||||||
struct Temporary_Arena_Memory
|
struct Temporary_Arena_Memory
|
||||||
{
|
{
|
||||||
Arena_Allocator* arena;
|
Arena_Allocator* arena;
|
||||||
s64 original_count;
|
s64 original_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace arena_allocator
|
|
||||||
{
|
|
||||||
void clear(Arena_Allocator* arena);
|
|
||||||
} // namespace arena_allocator
|
|
||||||
|
|
||||||
namespace temporary_arena_memory
|
namespace temporary_arena_memory
|
||||||
{
|
{
|
||||||
Temporary_Arena_Memory make(Arena_Allocator* arena);
|
Temporary_Arena_Memory make(Arena_Allocator* arena);
|
||||||
void free(Temporary_Arena_Memory* tmp);
|
void free(Temporary_Arena_Memory* tmp);
|
||||||
} // namespace temporary_arena_memory
|
} // namespace temporary_arena_memory
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace memory
|
namespace memory
|
||||||
{
|
{
|
||||||
void* align_forward(void* ptr, usize align);
|
void* align_forward(void* ptr, usize align);
|
||||||
|
@ -1097,7 +991,7 @@ struct Header
|
||||||
inline Header* header(String str) { return (Header*)str - 1; }
|
inline Header* header(String str) { return (Header*)str - 1; }
|
||||||
|
|
||||||
String make(Allocator* a, const char* str = "");
|
String make(Allocator* a, const char* str = "");
|
||||||
String make(Allocator* a, const void* str, Size len);
|
String make(Allocator* a, const void* str, Size length_in_bytes);
|
||||||
void free(String str);
|
void free(String str);
|
||||||
|
|
||||||
String duplicate(Allocator* a, const String str);
|
String duplicate(Allocator* a, const String str);
|
||||||
|
@ -1111,7 +1005,7 @@ void clear(String str);
|
||||||
void append(String* str, char c);
|
void append(String* str, char c);
|
||||||
void append(String* str, const String other);
|
void append(String* str, const String other);
|
||||||
void append_cstring(String* str, const char* other);
|
void append_cstring(String* str, const char* other);
|
||||||
void append(String* str, const void* other, Size len);
|
void append(String* str, const void* other, Size length_in_bytes);
|
||||||
|
|
||||||
void make_space_for(String* str, Size add_len);
|
void make_space_for(String* str, Size add_len);
|
||||||
usize allocation_size(const String str);
|
usize allocation_size(const String str);
|
||||||
|
@ -1166,6 +1060,8 @@ void format_uint(u64 value, char* buffer, usize len);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Array
|
struct Array
|
||||||
{
|
{
|
||||||
|
using Type = T;
|
||||||
|
|
||||||
Allocator* allocator;
|
Allocator* allocator;
|
||||||
s64 count;
|
s64 count;
|
||||||
s64 capacity;
|
s64 capacity;
|
||||||
|
@ -1229,6 +1125,8 @@ template <typename T> inline const T* end(const Array<T>& a) { return a.data +
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Hash_Table
|
struct Hash_Table
|
||||||
{
|
{
|
||||||
|
using Type = T;
|
||||||
|
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
u64 key;
|
u64 key;
|
||||||
|
@ -1453,54 +1351,8 @@ bool get_pos(File* file, s64* pos);
|
||||||
/// Allocators ///
|
/// Allocators ///
|
||||||
/// ///
|
/// ///
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
#if !defined(GB_USE_C_STYLE_ALLOCATOR)
|
|
||||||
template <usize BUFFER_SIZE>
|
|
||||||
Temp_Allocator<BUFFER_SIZE>::Temp_Allocator(Allocator* backing_)
|
|
||||||
: backing(backing_)
|
|
||||||
, chunk_size(4 * 1024) // 4K - page size
|
|
||||||
{
|
|
||||||
current_pointer = physical_start = buffer;
|
|
||||||
physical_end = physical_start + BUFFER_SIZE;
|
|
||||||
*reinterpret_cast<void**>(physical_start) = nullptr;
|
|
||||||
current_pointer = static_cast<u8*>(memory::pointer_add(current_pointer, sizeof(void*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <usize BUFFER_SIZE>
|
|
||||||
Temp_Allocator<BUFFER_SIZE>::~Temp_Allocator()
|
|
||||||
{
|
|
||||||
void* ptr = *reinterpret_cast<void**>(buffer);
|
|
||||||
while (ptr)
|
|
||||||
{
|
|
||||||
void* next = *static_cast<void**>(ptr);
|
|
||||||
backing->dealloc(ptr);
|
|
||||||
ptr = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <usize BUFFER_SIZE>
|
|
||||||
void*
|
|
||||||
Temp_Allocator<BUFFER_SIZE>::alloc(usize size, usize align)
|
|
||||||
{
|
|
||||||
current_pointer = static_cast<u8*>(memory::align_forward(current_pointer, align));
|
|
||||||
if (static_cast<intptr>(size) > (physical_end - current_pointer))
|
|
||||||
{
|
|
||||||
usize to_allocate = sizeof(void*) + size + align;
|
|
||||||
if (to_allocate < chunk_size)
|
|
||||||
to_allocate = chunk_size;
|
|
||||||
chunk_size *= 2;
|
|
||||||
void* ptr = backing->alloc(to_allocate);
|
|
||||||
*reinterpret_cast<void**>(physical_start) = ptr;
|
|
||||||
current_pointer = physical_start = static_cast<u8*>(ptr);
|
|
||||||
*reinterpret_cast<void**>(physical_start) = 0;
|
|
||||||
current_pointer = static_cast<u8*>(memory::pointer_add(current_pointer, sizeof(void*)));
|
|
||||||
current_pointer = static_cast<u8*>(memory::align_forward(current_pointer, align));
|
|
||||||
}
|
|
||||||
|
|
||||||
void* result = current_pointer;
|
|
||||||
current_pointer += size;
|
|
||||||
return (result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
/// ///
|
/// ///
|
||||||
/// Array ///
|
/// Array ///
|
||||||
|
@ -2913,25 +2765,23 @@ free(Data* tmp)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
Heap_Allocator::~Heap_Allocator()
|
|
||||||
{
|
|
||||||
#if defined (GB_SYSTEM_WINDOWS)
|
|
||||||
HeapDestroy(heap_handle);
|
|
||||||
#else
|
|
||||||
|
|
||||||
#endif
|
namespace heap_allocator
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
Heap_Allocator::alloc(usize size, usize align)
|
|
||||||
{
|
{
|
||||||
|
namespace functions
|
||||||
|
{
|
||||||
|
internal_linkage void*
|
||||||
|
alloc(Allocator* a, usize size, usize align)
|
||||||
|
{
|
||||||
|
Heap_Allocator* heap = reinterpret_cast<Heap_Allocator*>(a);
|
||||||
|
|
||||||
usize total = size + align - (size % align);
|
usize total = size + align - (size % align);
|
||||||
|
|
||||||
#if defined (GB_SYSTEM_WINDOWS)
|
#if defined (GB_SYSTEM_WINDOWS)
|
||||||
total += sizeof(Header);
|
total += sizeof(Heap_Allocator::Header);
|
||||||
|
|
||||||
void* data = HeapAlloc(heap_handle, 0, total);
|
void* data = HeapAlloc(heap->heap_handle, 0, total);
|
||||||
Header* h = static_cast<Header*>(data);
|
Heap_Allocator::Header* h = static_cast<Heap_Allocator::Header*>(data);
|
||||||
h->size = total;
|
h->size = total;
|
||||||
data = (h + 1);
|
data = (h + 1);
|
||||||
|
|
||||||
|
@ -2940,24 +2790,26 @@ Heap_Allocator::alloc(usize size, usize align)
|
||||||
void* data = malloc(total);
|
void* data = malloc(total);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
total_allocated_count += total;
|
heap->total_allocated_count += total;
|
||||||
allocation_count++;
|
heap->allocation_count++;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
internal_linkage void
|
||||||
Heap_Allocator::dealloc(const void* ptr)
|
dealloc(Allocator* a, const void* ptr)
|
||||||
{
|
{
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
total_allocated_count -= this->allocated_size(ptr);
|
Heap_Allocator* heap = reinterpret_cast<Heap_Allocator*>(a);
|
||||||
allocation_count--;
|
|
||||||
|
heap->total_allocated_count -= allocated_size(heap, ptr);
|
||||||
|
heap->allocation_count--;
|
||||||
|
|
||||||
#if defined (GB_SYSTEM_WINDOWS)
|
#if defined (GB_SYSTEM_WINDOWS)
|
||||||
ptr = static_cast<const Header*>(ptr) + 1;
|
ptr = static_cast<const Heap_Allocator::Header*>(ptr) + 1;
|
||||||
HeapFree(heap_handle, 0, const_cast<void*>(ptr));
|
HeapFree(heap->heap_handle, 0, const_cast<void*>(ptr));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
::free(const_cast<void*>(ptr));
|
::free(const_cast<void*>(ptr));
|
||||||
|
@ -2966,10 +2818,10 @@ Heap_Allocator::dealloc(const void* ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64
|
inline s64
|
||||||
Heap_Allocator::allocated_size(const void* ptr)
|
allocated_size(Allocator* a, const void* ptr)
|
||||||
{
|
{
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
const Header* h = static_cast<const Header*>(ptr) - 1;
|
const auto* h = static_cast<const Heap_Allocator::Header*>(ptr) - 1;
|
||||||
return static_cast<usize>(h->size);
|
return static_cast<usize>(h->size);
|
||||||
|
|
||||||
#elif defined(GB_SYSTEM_OSX)
|
#elif defined(GB_SYSTEM_OSX)
|
||||||
|
@ -2979,69 +2831,128 @@ Heap_Allocator::allocated_size(const void* ptr)
|
||||||
return static_cast<usize>(malloc_usable_size(const_cast<void*>(ptr)));
|
return static_cast<usize>(malloc_usable_size(const_cast<void*>(ptr)));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error Implement Heap_Allocator::allocated_size
|
#error Implement heap_allocator::allocated_size
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64
|
inline s64
|
||||||
Heap_Allocator::total_allocated()
|
total_allocated(Allocator* a)
|
||||||
{
|
{
|
||||||
return total_allocated_count;
|
return reinterpret_cast<Heap_Allocator*>(a)->total_allocated_count;
|
||||||
}
|
}
|
||||||
|
} // namespace functions
|
||||||
|
|
||||||
Arena_Allocator::Arena_Allocator(Allocator* backing_, usize size)
|
Heap_Allocator make()
|
||||||
: backing(backing_)
|
|
||||||
, physical_start(nullptr)
|
|
||||||
, total_size(size)
|
|
||||||
, temp_count(0)
|
|
||||||
, total_allocated_count(0)
|
|
||||||
{
|
{
|
||||||
physical_start = backing->alloc(size);
|
Heap_Allocator heap = {};
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
heap.heap_handle = HeapCreate(0, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
heap.alloc = functions::alloc;
|
||||||
|
heap.dealloc = functions::dealloc;
|
||||||
|
heap.allocated_size = functions::allocated_size;
|
||||||
|
heap.total_allocated = functions::total_allocated;
|
||||||
|
|
||||||
|
return heap;
|
||||||
}
|
}
|
||||||
|
void
|
||||||
Arena_Allocator::Arena_Allocator(void* start, usize size)
|
destroy(Heap_Allocator* heap)
|
||||||
: backing(nullptr)
|
|
||||||
, physical_start(start)
|
|
||||||
, total_size(size)
|
|
||||||
, temp_count(0)
|
|
||||||
, total_allocated_count(0)
|
|
||||||
{
|
{
|
||||||
|
#if defined (GB_SYSTEM_WINDOWS)
|
||||||
|
HeapDestroy(heap->heap_handle);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
} // namespace heap_allocator
|
||||||
|
|
||||||
Arena_Allocator::~Arena_Allocator()
|
|
||||||
|
|
||||||
|
namespace arena_allocator
|
||||||
{
|
{
|
||||||
if (backing)
|
namespace functions
|
||||||
backing->dealloc(physical_start);
|
|
||||||
|
|
||||||
GB_ASSERT(temp_count == 0,
|
|
||||||
"%ld Temporary_Arena_Memory have not be cleared", temp_count);
|
|
||||||
|
|
||||||
total_allocated_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
Arena_Allocator::alloc(usize size, usize align)
|
|
||||||
{
|
{
|
||||||
|
internal_linkage void*
|
||||||
|
alloc(Allocator* a, usize size, usize align)
|
||||||
|
{
|
||||||
|
Arena_Allocator* arena = reinterpret_cast<Arena_Allocator*>(a);
|
||||||
|
|
||||||
s64 actual_size = size + align;
|
s64 actual_size = size + align;
|
||||||
|
|
||||||
if (total_allocated_count + actual_size > total_size)
|
if (arena->total_allocated_count + actual_size > arena->total_size)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
void* ptr = memory::align_forward(memory::pointer_add(physical_start, total_allocated_count), align);
|
void* ptr = memory::align_forward(memory::pointer_add(arena->physical_start, arena->total_allocated_count), align);
|
||||||
|
|
||||||
total_allocated_count += actual_size;
|
arena->total_allocated_count += actual_size;
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Arena_Allocator::dealloc(const void*) {}
|
inline void
|
||||||
|
dealloc(Allocator* a, const void*) {}
|
||||||
|
|
||||||
inline s64 Arena_Allocator::allocated_size(const void*) { return -1; }
|
inline s64 allocated_size(Allocator*, const void*) { return -1; }
|
||||||
|
|
||||||
inline s64 Arena_Allocator::total_allocated() { return total_allocated_count; }
|
inline s64
|
||||||
|
total_allocated(Allocator* a)
|
||||||
namespace arena_allocator
|
|
||||||
{
|
{
|
||||||
|
return reinterpret_cast<Arena_Allocator*>(a)->total_allocated_count;
|
||||||
|
}
|
||||||
|
} // namespace functions
|
||||||
|
|
||||||
|
Arena_Allocator
|
||||||
|
make(Allocator* backing, usize size)
|
||||||
|
{
|
||||||
|
Arena_Allocator arena = {};
|
||||||
|
|
||||||
|
arena.backing = backing;
|
||||||
|
arena.physical_start = nullptr;
|
||||||
|
arena.total_size = size;
|
||||||
|
arena.temp_count = 0;
|
||||||
|
arena.total_allocated_count = 0;
|
||||||
|
|
||||||
|
arena.physical_start = alloc(arena.backing, size);
|
||||||
|
|
||||||
|
arena.alloc = functions::alloc;
|
||||||
|
arena.dealloc = functions::dealloc;
|
||||||
|
arena.allocated_size = functions::allocated_size;
|
||||||
|
arena.total_allocated = functions::total_allocated;
|
||||||
|
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena_Allocator
|
||||||
|
make(void* start, usize size)
|
||||||
|
{
|
||||||
|
Arena_Allocator arena = {};
|
||||||
|
|
||||||
|
arena.backing = nullptr;
|
||||||
|
arena.physical_start = start;
|
||||||
|
arena.total_size = size;
|
||||||
|
arena.temp_count = 0;
|
||||||
|
arena.total_allocated_count = 0;
|
||||||
|
|
||||||
|
arena.alloc = functions::alloc;
|
||||||
|
arena.dealloc = functions::dealloc;
|
||||||
|
arena.allocated_size = functions::allocated_size;
|
||||||
|
arena.total_allocated = functions::total_allocated;
|
||||||
|
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
destroy(Arena_Allocator* arena)
|
||||||
|
{
|
||||||
|
if (arena->backing)
|
||||||
|
dealloc(arena->backing, arena->physical_start);
|
||||||
|
|
||||||
|
GB_ASSERT(arena->temp_count == 0,
|
||||||
|
"%ld Temporary_Arena_Memory have not be cleared", arena->temp_count);
|
||||||
|
|
||||||
|
arena->total_allocated_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
clear(Arena_Allocator* arena)
|
clear(Arena_Allocator* arena)
|
||||||
{
|
{
|
||||||
|
@ -3070,7 +2981,7 @@ free(Temporary_Arena_Memory* tmp)
|
||||||
{
|
{
|
||||||
if (tmp->arena == nullptr)
|
if (tmp->arena == nullptr)
|
||||||
return;
|
return;
|
||||||
GB_ASSERT(tmp->arena->total_allocated() >= tmp->original_count);
|
GB_ASSERT(total_allocated(tmp->arena) >= tmp->original_count);
|
||||||
tmp->arena->total_allocated_count = tmp->original_count;
|
tmp->arena->total_allocated_count = tmp->original_count;
|
||||||
GB_ASSERT(tmp->arena->temp_count > 0);
|
GB_ASSERT(tmp->arena->temp_count > 0);
|
||||||
tmp->arena->temp_count--;
|
tmp->arena->temp_count--;
|
||||||
|
@ -3193,7 +3104,7 @@ inline void*
|
||||||
alloc(Allocator* a, usize size, usize align)
|
alloc(Allocator* a, usize size, usize align)
|
||||||
{
|
{
|
||||||
GB_ASSERT(a != nullptr);
|
GB_ASSERT(a != nullptr);
|
||||||
return a->alloc(size, align);
|
return a->alloc(a, size, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -3201,21 +3112,21 @@ dealloc(Allocator* a, const void* ptr)
|
||||||
{
|
{
|
||||||
GB_ASSERT(a != nullptr);
|
GB_ASSERT(a != nullptr);
|
||||||
if (ptr)
|
if (ptr)
|
||||||
a->dealloc(ptr);
|
a->dealloc(a, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64
|
inline s64
|
||||||
allocated_size(Allocator* a, const void* ptr)
|
allocated_size(Allocator* a, const void* ptr)
|
||||||
{
|
{
|
||||||
GB_ASSERT(a != nullptr);
|
GB_ASSERT(a != nullptr);
|
||||||
return a->allocated_size(ptr);
|
return a->allocated_size(a, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64
|
inline s64
|
||||||
total_allocated(Allocator* a)
|
total_allocated(Allocator* a)
|
||||||
{
|
{
|
||||||
GB_ASSERT(a != nullptr);
|
GB_ASSERT(a != nullptr);
|
||||||
return a->total_allocated();
|
return a->total_allocated(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3383,7 +3294,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 = string::header(*str);
|
||||||
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;
|
||||||
|
|
||||||
|
@ -3391,9 +3302,13 @@ make_space_for(String* str, Size add_len)
|
||||||
void* new_ptr = impl::string_realloc(a, ptr, old_size, new_size);
|
void* new_ptr = impl::string_realloc(a, ptr, old_size, new_size);
|
||||||
if (new_ptr == nullptr)
|
if (new_ptr == nullptr)
|
||||||
return;
|
return;
|
||||||
*str = static_cast<char*>(new_ptr) + sizeof(string::Header);
|
|
||||||
|
|
||||||
string::header(*str)->cap = new_len;
|
string::Header* header = static_cast<string::Header*>(new_ptr);
|
||||||
|
header->allocator = a;
|
||||||
|
header->len = len;
|
||||||
|
header->cap = new_len;
|
||||||
|
|
||||||
|
*str = reinterpret_cast<String>(header + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
usize
|
usize
|
||||||
|
@ -4348,6 +4263,7 @@ __GB_NAMESPACE_END
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Version History:
|
Version History:
|
||||||
|
0.26 - Better Allocation system
|
||||||
0.25a - Array bug fix
|
0.25a - Array bug fix
|
||||||
0.25 - Faster Heap_Allocator for Windows using HeapAlloc
|
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
|
||||||
|
|
Loading…
Reference in New Issue