Created
November 24, 2024 15:17
-
-
Save kassane/60137547d5e3f8428ad157a6f8853c1d to your computer and use it in GitHub Desktop.
Dlang betterC mode test - DynArray w/ Arena Allocator (like zig) & ScopedRef D class instanciation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Works in betterC mode (tested on: ldc2 & opend-ldc2) | |
module arena; | |
struct Arena | |
{ | |
void* start; | |
size_t used; | |
size_t capacity; | |
static scope Arena* create(size_t capacity) | |
{ | |
auto arena = cast(Arena*) malloc(Arena.sizeof); | |
if (!arena) | |
return null; | |
arena.start = malloc(capacity); | |
if (!arena.start) | |
{ | |
free(arena); | |
return null; | |
} | |
arena.used = 0; | |
arena.capacity = capacity; | |
return arena; | |
} | |
scope void* alloc(size_t size) | |
{ | |
if (used + size > capacity) | |
return null; | |
void* ptr = cast(void*)(cast(ubyte*) start + used); | |
used += size; | |
return ptr; | |
} | |
void reset() | |
{ | |
used = 0; | |
} | |
void destroy() | |
{ | |
if (start) | |
free(start); | |
free(&this); | |
} | |
~this() | |
{ | |
destroy(); | |
} | |
import core.stdc.stdlib : malloc, free; | |
} | |
struct DynArray(T) | |
{ | |
T* ptr; | |
size_t length; | |
size_t capacity; | |
Arena* arena; | |
static DynArray!T create(Arena* arena, size_t initialCapacity = 16) | |
{ | |
DynArray!T arr; | |
arr.arena = arena; | |
arr.capacity = initialCapacity; | |
arr.ptr = cast(T*) arena.alloc(T.sizeof * initialCapacity); | |
arr.length = 0; | |
return arr; | |
} | |
bool push(T value) | |
{ | |
if (length >= capacity) | |
{ | |
size_t newCapacity = capacity * 2; | |
T* newPtr = cast(T*) arena.alloc(T.sizeof * newCapacity); | |
if (!newPtr) | |
return false; | |
for (size_t i = 0; i < length; i++) | |
newPtr[i] = ptr[i]; | |
ptr = newPtr; | |
capacity = newCapacity; | |
} | |
ptr[length++] = value; | |
return true; | |
} | |
T* opIndex(size_t index) | |
{ | |
if (index >= length) | |
return null; | |
return &ptr[index]; | |
} | |
} | |
extern (C) void main() | |
{ | |
auto arena = Arena.create(1024); | |
scope (exit) | |
arena.destroy(); | |
assert(arena !is null); | |
auto arr = DynArray!int.create(arena); | |
assert(arr.capacity == 16); | |
assert(arr.length == 0); | |
// Push test | |
for (int i = 0; i < 10; i++) | |
assert(arr.push(i)); | |
assert(arr.length == 10); | |
// Access test | |
for (size_t i = 0; i < arr.length; i++) | |
{ | |
assert(*arr[i] == i); | |
} | |
for (int i = 0; i < 20; i++) | |
assert(arr.push(i)); | |
assert(arr.length == 30); | |
// final contents | |
for (size_t i = 0; i < arr.length; i++) | |
{ | |
printf("arr[%zu] = %d\n", i, *arr[i]); | |
} | |
{ | |
auto foo = ScopedRef!Foo.make(); | |
assert(foo.x == 1); | |
assert(foo.y == 2); | |
} | |
} | |
class Foo | |
{ | |
int x; | |
int y; | |
this() @nogc nothrow @safe | |
{ | |
x = 1; | |
y = 2; | |
printf("Foo ctor\n"); | |
} | |
~this() @nogc nothrow @safe | |
{ | |
printf("Foo dtor\n"); | |
} | |
} | |
pragma(printf) | |
extern (C) void printf(scope const(char)* fmt, scope...) @nogc nothrow; | |
struct ScopedRef(T) | |
{ | |
T value; | |
alias value this; | |
static ScopedRef!T make(Args...)(auto ref Args args) @nogc @safe nothrow | |
{ | |
import core.exception : onOutOfMemoryError; | |
enum tsize = __traits(classInstanceSize, T); | |
T t = () @trusted { | |
auto _t = cast(T) malloc(tsize); | |
if (!_t) | |
onOutOfMemoryError(); | |
import core.stdc.string : memcpy; | |
memcpy(cast(void*) _t, __traits(initSymbol, T).ptr, tsize); | |
return _t; | |
}(); | |
if (!t) | |
return ScopedRef!T(null); | |
import core.lifetime : forward; | |
t.__ctor(forward!args); | |
return ScopedRef!T(t); | |
} | |
~this() @nogc nothrow | |
{ | |
if (value) | |
{ | |
static if (__traits(hasMember, T, "__xdtor")) | |
value.__xdtor(); | |
free(cast(void*) value); | |
value = null; | |
} | |
} | |
@disable this(this); | |
import core.stdc.stdlib : malloc, free; | |
} | |
@("basic creation and destruction") | |
@safe @nogc nothrow | |
unittest | |
{ | |
auto foo = ScopedRef!Foo.make(); | |
assert(foo.x == 1); | |
assert(foo.y == 2); | |
} | |
@("null case") | |
@safe @nogc nothrow | |
unittest | |
{ | |
auto foo = ScopedRef!Foo(null); | |
assert(foo.value is null); | |
} | |
@("copy construction is disabled") | |
@safe @nogc nothrow | |
unittest | |
{ | |
static assert(!__traits(compiles, { | |
auto foo1 = ScopedRef!Foo.make(); | |
auto foo2 = foo1; | |
})); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment