Skip to content

Instantly share code, notes, and snippets.

@Midi12
Last active March 4, 2021 13:17
Show Gist options
  • Save Midi12/c51f5cf1a30379c438e87f118d0c713b to your computer and use it in GitHub Desktop.
Save Midi12/c51f5cf1a30379c438e87f118d0c713b to your computer and use it in GitHub Desktop.
Simple memory manager for struct allocated in Dart using ffi
import 'dart:ffi';
// library
final DynamicLibrary _kernel32 = DynamicLibrary.open('kernel32.dll');
typedef HeapAllocNative_t = Pointer Function(Pointer, Uint32, IntPtr);
typedef HeapAlloc_d = Pointer Function(Pointer, int, int);
final HeapAlloc_d pfnHeapAlloc = _kernel32.lookupFunction<HeapAllocNative_t, HeapAlloc_d>('HeapAlloc');
typedef HeapFree_t = Int32 Function(Pointer heap, Uint32 flags, Pointer memory);
typedef HeapFree_d = int Function(Pointer heap, int flags, Pointer memory);
final HeapFree_d pfnHeapFree = _kernel32.lookupFunction<HeapFree_t, HeapFree_d>('HeapFree');
typedef GetProcessHeap_t = Pointer Function();
typedef GetProcessHeap_d = Pointer Function();
final GetProcessHeap_t pfnGetProcessHeap = _kernel32.lookupFunction<GetProcessHeap_t, GetProcessHeap_d>('GetProcessHeap');
final HEAP_ZERO_MEMORY = 0x00000008;
Pointer<T> zero_allocate<T extends NativeType>({int count = 1}) {
// ignore: omit_local_variable_types
final int totalSize = count * sizeOf<T>();
// ignore: omit_local_variable_types
Pointer<T> result = pfnHeapAlloc(pfnGetProcessHeap(), HEAP_ZERO_MEMORY, totalSize).cast();
if (result.address == 0) {
return nullptr;
}
return result;
}
bool internal_free<T extends NativeType>(Pointer<T> ptr) {
return pfnHeapFree(pfnGetProcessHeap(), 0, ptr) != 0;
}
extension DisposableStructExtension on Struct {
static final List<Struct> _objects = [];
static T allocate<T extends Struct>({int count = 1}) {
var ref = zero_allocate<T>(count: count).ref;
DisposableStructExtension._objects.add(ref);
return ref;
}
static void disposeAll() {
var _freedObjects = [];
DisposableStructExtension._objects.forEach((object) {
object.free(shouldRemove: false);
_freedObjects.add(object);
});
DisposableStructExtension._objects.removeWhere((object) => _freedObjects.contains(object));
}
void free({bool shouldRemove = true}) {
if (DisposableStructExtension._objects.contains(this)) {
internal_free(addressOf);
if (shouldRemove) {
DisposableStructExtension._objects.remove(this);
}
print('disposed');
}
}
}
// application
class Test extends Struct {
@Uint32()
int a;
@Uint32()
int b;
@Uint32()
int c;
}
const allocate = DisposableStructExtension.allocate;
const disposeAll = DisposableStructExtension.disposeAll;
void main(List<String> arguments) {
var t = allocate<Test>();
t.a = 12;
print(t.a);
var t2 = allocate<Test>();
t2.b = 42;
print(t2.b);
var t3 = allocate<Test>();
t3.c = 1337;
print(t3.c);
t3.free();
// at program exit
disposeAll();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment