Created
November 24, 2024 15:17
-
-
Save kassane/60137547d5e3f8428ad157a6f8853c1d to your computer and use it in GitHub Desktop.
Revisions
-
kassane created this gist
Nov 24, 2024 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,233 @@ // 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; })); }