Last active
March 4, 2021 13:17
-
-
Save Midi12/c51f5cf1a30379c438e87f118d0c713b to your computer and use it in GitHub Desktop.
Simple memory manager for struct allocated in Dart using ffi
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 characters
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