feat: initial commit, basic arena
This commit is contained in:
22
.clang-format
Normal file
22
.clang-format
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AlignOperands: DontAlign
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BreakBeforeBraces: WebKit
|
||||||
|
IndentCaseLabels: false
|
||||||
|
TabWidth: 4
|
||||||
|
IndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
UseTab: ForContinuationAndIndentation
|
||||||
|
ColumnLimit: 0
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SpaceBeforeParens: false
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bin/
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
# ni-arena
|
# ni-arena
|
||||||
|
|
||||||
Arena Allocator of the NI-C system
|
Arena Allocator of the NI-C system
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- [ni-const](https://codecave.studiosi.es/studiosi/ni-const) constants library of the NI-C system
|
||||||
27
makefile
Normal file
27
makefile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
RELEASE_flags=-DNDEBUG -O2 -g0
|
||||||
|
DEBUG_flags=-std=c23 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr bin
|
||||||
|
|
||||||
|
format:
|
||||||
|
clang-format -i test/niarena_test.c
|
||||||
|
clang-format -i test/niarena_test_alloc_arena.c
|
||||||
|
clang-format -i test/niarena_test_alloc_buffer.c
|
||||||
|
clang-format -i niarena.h
|
||||||
|
|
||||||
|
test: bin/test
|
||||||
|
bin/niarena_test
|
||||||
|
bin/niarena_test_alloc_arena
|
||||||
|
bin/niarena_test_alloc_buffer
|
||||||
|
|
||||||
|
leaks: bin/test
|
||||||
|
leaks --atExit -- bin/niarena_test
|
||||||
|
|
||||||
|
.PHONY: clean format test
|
||||||
|
|
||||||
|
bin/test: test/niarena_test.c
|
||||||
|
mkdir -p bin/test
|
||||||
|
cc ${DEBUG_flags} test/niarena_test.c -o bin/niarena_test
|
||||||
|
cc ${DEBUG_flags} test/niarena_test_alloc_buffer.c -o bin/niarena_test_alloc_buffer
|
||||||
|
cc ${DEBUG_flags} test/niarena_test_alloc_buffer.c -o bin/niarena_test_alloc_arena
|
||||||
94
niarena.h
Normal file
94
niarena.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../ni-const/niconst.h"
|
||||||
|
|
||||||
|
// If custom memory management is provided, including this
|
||||||
|
// header can be skipped
|
||||||
|
#ifndef NIAREA_NO_STDLIB
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The size can be defined by overriding this constant
|
||||||
|
#ifndef NIARENA_ARENA_SIZE
|
||||||
|
#define NIARENA_ARENA_SIZE NICONST_MIB_B(4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Custom memory management can be defined as well.
|
||||||
|
// Either both or none must be defined
|
||||||
|
#if (!defined(NIARENA_MALLOC) && defined(NIARENA_FREE)) || (defined(NIARENA_MALLOC) && !defined(NIARENA_FREE))
|
||||||
|
#error "Either both NIARENA_MALLOC and NIARENA_FREE have to be defined or neither of them"
|
||||||
|
#endif
|
||||||
|
#ifndef NIARENA_MALLOC
|
||||||
|
#define NIARENA_MALLOC(sz) malloc(sz)
|
||||||
|
#endif
|
||||||
|
#ifndef NIARENA_FREE
|
||||||
|
#define NIARENA_FREE(p) free(p)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Definitions
|
||||||
|
typedef struct _NIArena {
|
||||||
|
void *buffer;
|
||||||
|
size_t capacity;
|
||||||
|
size_t offset;
|
||||||
|
} NIArena;
|
||||||
|
|
||||||
|
const char *niarena_get_error(void);
|
||||||
|
NIArena *niarena_new(void);
|
||||||
|
void *niarena_alloc(NIArena *arena, size_t size);
|
||||||
|
void niarena_delete(NIArena *arena);
|
||||||
|
|
||||||
|
#ifdef NIARENA_IMPLEMENTATION
|
||||||
|
|
||||||
|
static const char *niarena__error_reason = "";
|
||||||
|
|
||||||
|
static void
|
||||||
|
niarena_error(const char *reason)
|
||||||
|
{
|
||||||
|
niarena__error_reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
niarena_get_error(void)
|
||||||
|
{
|
||||||
|
return niarena__error_reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
NIArena *
|
||||||
|
niarena_new(void)
|
||||||
|
{
|
||||||
|
NIArena *arena = NIARENA_MALLOC(sizeof(NIArena));
|
||||||
|
if(arena == NULL) {
|
||||||
|
niarena_error("niarena_new: out of memory allocating arena");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
arena->buffer = NIARENA_MALLOC(NIARENA_ARENA_SIZE);
|
||||||
|
if(arena->buffer == NULL) {
|
||||||
|
NIARENA_FREE(arena);
|
||||||
|
niarena_error("niarena_new: out of memory allocating buffer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
arena->capacity = NIARENA_ARENA_SIZE;
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
niarena_alloc(NIArena *arena, size_t size)
|
||||||
|
{
|
||||||
|
if((arena->capacity - arena->offset) < size) {
|
||||||
|
// The allocation is invalid, but the contents of the arena
|
||||||
|
// can still be used (previous allocations).
|
||||||
|
niarena_error("niarena_alloc: out of memory inside of the arena");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
arena->offset += size;
|
||||||
|
return (void *)((char *)arena->buffer + arena->offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
niarena_delete(NIArena *arena)
|
||||||
|
{
|
||||||
|
NIARENA_FREE(arena->buffer);
|
||||||
|
NIARENA_FREE(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
52
test/niarena_test.c
Normal file
52
test/niarena_test.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#define N_INTS_TEST 4
|
||||||
|
#define NIARENA_ARENA_SIZE (N_INTS_TEST * sizeof(int))
|
||||||
|
#define NIARENA_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include "../niarena.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
test_arena_new()
|
||||||
|
{
|
||||||
|
NIArena *arena = niarena_new();
|
||||||
|
assert(arena->offset == 0);
|
||||||
|
assert(arena->capacity == (N_INTS_TEST * sizeof(int)));
|
||||||
|
niarena_delete(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_arena_allocations()
|
||||||
|
{
|
||||||
|
NIArena *arena = niarena_new();
|
||||||
|
|
||||||
|
int *ns[N_INTS_TEST];
|
||||||
|
for(int i = 1; i <= N_INTS_TEST + 1; i++) {
|
||||||
|
int *p = (int *)niarena_alloc(arena, sizeof(int));
|
||||||
|
if(i == N_INTS_TEST + 1) {
|
||||||
|
// Invalid allocation does not invalidate the rest
|
||||||
|
assert(p == NULL);
|
||||||
|
const char *err = niarena_get_error();
|
||||||
|
assert(strcmp(err, "niarena_alloc: out of memory inside of the arena") == 0);
|
||||||
|
} else {
|
||||||
|
assert(arena->offset == i * sizeof(int));
|
||||||
|
*p = 1234 + i;
|
||||||
|
ns[i - 1] = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 1; i <= N_INTS_TEST; i++) {
|
||||||
|
assert(*ns[i - 1] == 1234 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
niarena_delete(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
test_arena_new();
|
||||||
|
test_arena_allocations();
|
||||||
|
printf("== TESTS SUCCESSFUL ==\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
42
test/niarena_test_alloc_arena.c
Normal file
42
test/niarena_test_alloc_arena.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void *
|
||||||
|
bad_malloc(size_t sz)
|
||||||
|
{
|
||||||
|
(void)sz;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#define NIARENA_MALLOC(sz) bad_malloc(sz)
|
||||||
|
|
||||||
|
void
|
||||||
|
mock_free(void *p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
#define NIARENA_FREE(p) mock_free(p)
|
||||||
|
|
||||||
|
#define N_INTS_TEST 4
|
||||||
|
#define NIARENA_ARENA_SIZE (N_INTS_TEST * sizeof(int))
|
||||||
|
#define NIARENA_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include "../niarena.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
niarena_test_malloc_fail_arena()
|
||||||
|
{
|
||||||
|
NIArena *arena = niarena_new();
|
||||||
|
assert(arena == NULL);
|
||||||
|
const char *err = niarena_get_error();
|
||||||
|
assert(strcmp(err, "niarena_new: out of memory allocating arena") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
niarena_test_malloc_fail_arena();
|
||||||
|
printf("== TESTS SUCCESSFUL ==\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
46
test/niarena_test_alloc_buffer.c
Normal file
46
test/niarena_test_alloc_buffer.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int call_count = 0;
|
||||||
|
void *
|
||||||
|
bad_malloc(size_t sz)
|
||||||
|
{
|
||||||
|
call_count++;
|
||||||
|
if(call_count != 2) {
|
||||||
|
return malloc(sz);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#define NIARENA_MALLOC(sz) bad_malloc(sz)
|
||||||
|
|
||||||
|
void
|
||||||
|
mock_free(void *p)
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
#define NIARENA_FREE(p) mock_free(p)
|
||||||
|
|
||||||
|
#define N_INTS_TEST 4
|
||||||
|
#define NIARENA_ARENA_SIZE (N_INTS_TEST * sizeof(int))
|
||||||
|
#define NIARENA_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include "../niarena.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
niarena_test_malloc_fail_buffer()
|
||||||
|
{
|
||||||
|
NIArena *arena = niarena_new();
|
||||||
|
assert(arena == NULL);
|
||||||
|
const char *err = niarena_get_error();
|
||||||
|
assert(strcmp(err, "niarena_new: out of memory allocating buffer") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
niarena_test_malloc_fail_buffer();
|
||||||
|
printf("== TESTS SUCCESSFUL ==\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user