First pass memory tool

This commit is contained in:
2023-10-10 08:55:50 -05:00
parent 2423fd9f70
commit 9ad9995663
11 changed files with 183 additions and 99 deletions

View File

@ -16,6 +16,7 @@ set(
set(D ${CMAKE_CURRENT_LIST_DIR})
set(
DAWN_SHARED_SOURCES
${D}/util/memory.cpp
${D}/display/Color.cpp
${D}/assert/assert.cpp
${D}/util/Xml.cpp

View File

@ -11,7 +11,7 @@ void assertTrue(bool_t x, const char message[]) {
if(x != true) {
std::cout << message << std::endl;
throw message;
free(0);
abort();
}
assert(x == true);
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "memory.hpp"
#include "assert/assert.hpp"
uint64_t dawnAllocatedItemCount = -1;
void memoryInit() {
dawnAllocatedItemCount = 0;
}
void memoryDispose() {
assertTrue(dawnAllocatedItemCount <= 0, "memoryDispose: !!!Leaked memory detected (not enough free)!!!");
assertTrue(dawnAllocatedItemCount >= 0, "memoryDispose: !!!Leaked memory detected (too much free)!!!");
dawnAllocatedItemCount = -1;
}
void * memoryAllocate(const size_t size) {
assertTrue(dawnAllocatedItemCount >= 0, "memoryAllocate: Either a memory leak or memoryInit was not called.");
assertTrue(size >= 0, "memoryAllocate: size must be greater than 0 or equal to.");
if(size == 0) {
// Technically this is an implementation specific case, I think it should
// basically be undefined behaviour tbh.
return memoryCallMalloc(size);
}
dawnAllocatedItemCount++;
auto x = (void *)memoryCallMalloc(size);
assertNotNull(x, "memoryAllocate: Failed to allocate memory");
return x;
}
void * memoryAllocateEmpty(const size_t count, const size_t size) {
assertTrue(dawnAllocatedItemCount >= 0, "memoryAllocateEmpty: Either a memory leak or memoryInit was not called.");
assertTrue(count >= 0, "memoryAllocateEmpty: count must be greater than or equal to 0");
assertTrue(size >= 0, "memoryAllocateEmpty: size must be greater than or equal to 0");
if(count == 0 || size == 0) {
// Technically this is an implementation specific case, I think it should
// basically be undefined behaviour tbh.
return memoryCallCalloc(count, size);
}
dawnAllocatedItemCount++;
auto x = (void*)memoryCallCalloc(count, size);
assertNotNull(x, "memoryAllocateEmpty: Failed to allocate memory");
return x;
}
void memoryFree(void *pointer) {
assertTrue(dawnAllocatedItemCount > 0, "memoryFree: Either a memory leak or memoryInit was not called.");
if(pointer == nullptr || pointer == NULL) {
// Technically this is an implementation specific case, I think it should
// basically be undefined behaviour tbh.
return memoryCallFree(pointer);
}
dawnAllocatedItemCount--;
memoryCallFree(pointer);
}
void memoryCopy(void *source, void *destination, size_t size) {
assertTrue(dawnAllocatedItemCount >= 0, "memoryAllocate: Either a memory leak or memoryInit was not called.");
assertNotNull(source, "memoryCopy: source must not be null");
assertNotNull(destination, "memoryCopy: destination must not be null");
assertTrue(destination != source, "memoryCopy: destination must not be source");
assertTrue(size > 0, "memoryCopy: size must be greater than 0");
memcpy(destination, source, size);
}
int32_t memoryCompare(const void *left, const void *right, const size_t size) {
assertTrue(dawnAllocatedItemCount >= 0, "memoryAllocate: Either a memory leak or memoryInit was not called.");
assertTrue(left != right, "memoryCompare: left must not be right");
assertTrue(size > 0, "memoryCompare: size must be greater than 0");
return memcmp(left, right, size);
}
void memorySet(void *dest, uint8_t data, size_t length) {
assertTrue(dawnAllocatedItemCount >= 0, "memoryAllocate: Either a memory leak or memoryInit was not called.");
assertNotNull(dest, "memorySet: dest must not be null");
assertTrue(length > 0, "memorySet: length must be greater than 0");
memset(dest, data, length);
}
size_t memoryReallocate(void **pointer, size_t currentSize, size_t newSize) {
// Create the new buffer
void *newBuffer = memoryAllocate(newSize);
memoryCopy(*pointer, newBuffer, currentSize);
memoryFree(*pointer);
*pointer = newBuffer;
return newSize;
}
void * operator new(size_t size) {
return memoryAllocate(size);
}
void operator delete(void *pointer) {
memoryFree(pointer);
}

View File

@ -6,11 +6,31 @@
*/
#pragma once
#include "assert/assert.hpp"
#include "dawnsharedlibs.hpp"
#if DAWN_DEBUG_BUILD
extern uint64_t dawnAllocatedItemCount;
#endif
extern uint64_t dawnAllocatedItemCount;
static void * memoryCallMalloc(const size_t size) {
return malloc(size);
}
static void * memoryCallCalloc(const size_t num, const size_t size) {
return calloc(num, size);
}
static void memoryCallFree(void *p) {
free(p);
}
/**
* Initializes the memory management system.
*/
void memoryInit();
/**
* Disposes of the memory management system.
*/
void memoryDispose();
/**
* Allocate some space in memory to use for your needs. Memory allocation may
@ -20,44 +40,22 @@
* @param size Size of the array you wish to buffer.
* @return Pointer to the space in memory to use.
*/
static inline void * memoryAllocate(const size_t size) {
assertTrue(size > 0, "memoryAllocate: size must be greater than 0");
#if DAWN_DEBUG_BUILD
dawnAllocatedItemCount++;
#endif
auto x = (void *)malloc(size);
assertNotNull(x, "memoryAllocate: Failed to allocate memory");
return x;
}
void * memoryAllocate(const size_t size);
/**
* Allocate space in memory, where all values are set to 0 (in binary space).
*
* @param size Size of the array.
* @param count Count of elements to allocate.
* @param size Size of each element to allocate.
* @return Pointer to the space in memory to use.
*/
static inline void * memoryFillWithZero(const size_t size) {
assertTrue(size > 0, "memoryFillWithZero: size must be greater than 0");
#if DAWN_DEBUG_BUILD
dawnAllocatedItemCount++;
#endif
auto x = (void*)calloc(1, size);
assertNotNull(x, "memoryFillWithZero: Failed to allocate memory");
return x;
}
void * memoryAllocateEmpty(const size_t count, const size_t size);
/**
* Free some previously allocated memory space.
* @param pointer Pointer in memory to free.
*/
static inline void memoryFree(void *pointer) {
assertNotNull(pointer, "memoryFree: pointer must not be null");
#if DAWN_DEBUG_BUILD
dawnAllocatedItemCount--;
#endif
free(pointer);
}
void memoryFree(void *pointer);
/**
* Copies data from one buffer to another. Typically used for array operations.
@ -66,17 +64,7 @@ static inline void memoryFree(void *pointer) {
* @param destination Destination buffer.
* @param size Size in bytes of data to copy.
*/
static inline void memoryCopy(
void *source,
void *destination,
size_t size
) {
assertNotNull(source, "memoryCopy: source must not be null");
assertNotNull(destination, "memoryCopy: destination must not be null");
assertTrue(destination != source, "memoryCopy: destination must not be source");
assertTrue(size > 0, "memoryCopy: size must be greater than 0");
memcpy(destination, source, size);
}
void memoryCopy(void *source, void *destination, size_t size);
/**
* Compares the data within two memory banks. Shorthand for memcpy.
@ -86,15 +74,7 @@ static inline void memoryCopy(
* @param size Count of bytes to compare.
* @return 0 for equal, <0 for left being greater, >0 for right being greater.
*/
static inline int32_t memoryCompare(
const void *left,
const void *right,
const size_t size
) {
assertTrue(left != right, "memoryCompare: left must not be right");
assertTrue(size > 0, "memoryCompare: size must be greater than 0");
return memcmp(left, right, size);
}
int32_t memoryCompare(const void *left, const void *right, const size_t size);
/**
* Fill destination with a repeating set of bytes.
@ -103,15 +83,7 @@ static inline int32_t memoryCompare(
* @param data Data byte to write.
* @param length How many times to write that byte.
*/
static inline void memorySet(
void *dest,
uint8_t data,
size_t length
) {
assertNotNull(dest, "memorySet: dest must not be null");
assertTrue(length > 0, "memorySet: length must be greater than 0");
memset(dest, data, length);
}
void memorySet(void *dest, uint8_t data, size_t length);
/**
* Reallocate a part of memory. Reallocation simply creates a new buffer that
@ -122,15 +94,24 @@ static inline void memorySet(
* @param newSize The new size of the buffer.
* @return The new size param you provided.
*/
static inline size_t memoryReallocate(
void **pointer,
size_t currentSize,
size_t newSize
) {
// Create the new buffer
void *newBuffer = memoryAllocate(newSize);
memoryCopy(*pointer, newBuffer, currentSize);
memoryFree(*pointer);
*pointer = newBuffer;
return newSize;
}
size_t memoryReallocate(void **pointer, size_t currentSize, size_t newSize);
/**
* Overloads the new operator to use our memory allocation.
*
* @param size Size of the memory to allocate.
* @return Pointer to the memory.
*/
void * operator new(size_t size);
/**
* Overloads the delete operator to use our memory allocation.
*
* @param p Pointer to the memory to free.
*/
void operator delete(void * p);
// Override default memory functions
#define malloc(n) memoryAllocate(n)
#define free(n) memoryFree(n)
#define calloc(n, s) memoryAllocateEmpty(n, s)