Skip to content
This repository was archived by the owner on Jan 17, 2024. It is now read-only.

Commit f46c1f4

Browse files
Allocation utilities. (#7)
* Allocation utilities. * Comments
1 parent e6aea0a commit f46c1f4

File tree

6 files changed

+91
-9
lines changed

6 files changed

+91
-9
lines changed

lib/ffi.dart

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
export 'src/utf8.dart';
66
export 'src/utf16.dart';
7+
export 'src/allocation.dart' show allocate, free;

lib/src/allocation.dart

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
import 'dart:io';
7+
8+
// Note that kernel32.dll is the correct name in both 32-bit and 64-bit.
9+
final DynamicLibrary stdlib = Platform.isWindows
10+
? DynamicLibrary.open("kernel32.dll")
11+
: DynamicLibrary.process();
12+
13+
typedef PosixMallocNative = Pointer Function(IntPtr);
14+
typedef PosixMalloc = Pointer Function(int);
15+
final PosixMalloc posixMalloc =
16+
stdlib.lookupFunction<PosixMallocNative, PosixMalloc>("malloc");
17+
18+
typedef PosixFreeNative = Void Function(Pointer);
19+
typedef PosixFree = void Function(Pointer);
20+
final PosixFree posixFree =
21+
stdlib.lookupFunction<PosixFreeNative, PosixFree>("free");
22+
23+
typedef WinGetProcessHeapFn = Pointer Function();
24+
final WinGetProcessHeapFn winGetProcessHeap = stdlib
25+
.lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>("GetProcessHeap");
26+
final Pointer processHeap = winGetProcessHeap();
27+
28+
typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
29+
typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
30+
final WinHeapAlloc winHeapAlloc =
31+
stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>("HeapAlloc");
32+
33+
typedef WinHeapFreeNative = Int32 Function(
34+
Pointer heap, Uint32 flags, Pointer memory);
35+
typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
36+
final WinHeapFree winHeapFree =
37+
stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>("HeapFree");
38+
39+
/// Allocates memory on the native heap.
40+
///
41+
/// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
42+
/// against the default public heap. Allocation of either element size or count
43+
/// of 0 is undefined.
44+
///
45+
/// Throws an ArgumentError on failure to allocate.
46+
Pointer<T> allocate<T extends NativeType>({int count = 1}) {
47+
final int totalSize = count * sizeOf<T>();
48+
Pointer<T> result;
49+
if (Platform.isWindows) {
50+
result = winHeapAlloc(processHeap, /*flags=*/ 0, totalSize).cast();
51+
} else {
52+
result = posixMalloc(totalSize).cast();
53+
}
54+
if (result.address == 0) {
55+
throw ArgumentError("Could not allocate $totalSize bytes.");
56+
}
57+
return result;
58+
}
59+
60+
/// Releases memory on the native heap.
61+
///
62+
/// For POSIX-based systems, this uses free. On Windows, it uses HeapFree
63+
/// against the default public heap. It may only be used against pointers
64+
/// allocated in a manner equivalent to [allocate].
65+
///
66+
/// Throws an ArgumentError on failure to free.
67+
///
68+
// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
69+
// of testing the return integer to be non-zero.
70+
void free(Pointer pointer) {
71+
if (Platform.isWindows) {
72+
if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
73+
throw ArgumentError("Could not free $pointer.");
74+
}
75+
} else {
76+
posixFree(pointer);
77+
}
78+
}

lib/src/utf16.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'dart:convert';
66
import 'dart:ffi';
77
import 'dart:typed_data';
88

9+
import 'package:ffi/ffi.dart';
10+
911
/// [Utf16] implements conversion between Dart strings and null-terminated
1012
/// Utf6-encoded "char*" strings in C.
1113
///
@@ -21,8 +23,7 @@ class Utf16 extends Struct<Utf16> {
2123
/// Returns a malloc-allocated pointer to the result.
2224
static Pointer<Utf16> toUtf16(String s) {
2325
final units = s.codeUnits;
24-
final Pointer<Uint16> result =
25-
Pointer<Uint16>.allocate(count: units.length + 1);
26+
final Pointer<Uint16> result = allocate<Uint16>(count: units.length + 1);
2627
final Uint16List nativeString =
2728
result.asExternalTypedData(count: units.length + 1);
2829
nativeString.setAll(0, units);

lib/src/utf8.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import 'dart:convert';
66
import 'dart:ffi';
77
import 'dart:typed_data';
88

9+
import 'package:ffi/ffi.dart';
10+
911
const int _kMaxSmi64 = (1 << 62) - 1;
1012
const int _kMaxSmi32 = (1 << 30) - 1;
1113
final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
@@ -54,7 +56,7 @@ class Utf8 extends Struct<Utf8> {
5456
static Pointer<Utf8> toUtf8(String string) {
5557
final units = utf8.encode(string);
5658
final Pointer<Uint8> result =
57-
Pointer<Uint8>.allocate(count: units.length + 1);
59+
allocate<Uint8>(count: units.length + 1);
5860
final Uint8List nativeString =
5961
result.asExternalTypedData(count: units.length + 1);
6062
nativeString.setAll(0, units);

test/utf16_test.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ main() {
1616
converted.asExternalTypedData(count: start.codeUnits.length + 1);
1717
final matcher = equals(start.codeUnits.toList()..add(0));
1818
expect(end, matcher);
19-
converted.free();
19+
free(converted);
2020
});
2121

2222
test("toUtf16 emoji", () {
@@ -27,6 +27,6 @@ main() {
2727
converted.cast<Uint16>().asExternalTypedData(count: length + 1);
2828
final matcher = equals(start.codeUnits.toList()..add(0));
2929
expect(end, matcher);
30-
converted.free();
30+
free(converted);
3131
});
3232
}

test/utf8_test.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:test/test.dart';
99
import 'package:ffi/ffi.dart';
1010

1111
Pointer<Uint8> _bytesFromList(List<int> ints) {
12-
final Pointer<Uint8> ptr = Pointer.allocate(count: ints.length);
12+
final Pointer<Uint8> ptr = allocate(count: ints.length);
1313
final Uint8List list = ptr.asExternalTypedData(count: ints.length);
1414
list.setAll(0, ints);
1515
return ptr;
@@ -24,7 +24,7 @@ main() {
2424
final matcher =
2525
equals([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 10, 0]);
2626
expect(end, matcher);
27-
converted.free();
27+
free(converted);
2828
});
2929

3030
test("fromUtf8 ASCII", () {
@@ -43,7 +43,7 @@ main() {
4343
final matcher =
4444
equals([240, 159, 152, 142, 240, 159, 145, 191, 240, 159, 146, 172, 0]);
4545
expect(end, matcher);
46-
converted.free();
46+
free(converted);
4747
});
4848

4949
test("formUtf8 emoji", () {
@@ -60,7 +60,7 @@ main() {
6060
final Uint8List end =
6161
converted.cast<Uint8>().asExternalTypedData(count: length + 1);
6262
expect(end, equals([237, 160, 128, 225, 128, 128, 0]));
63-
converted.free();
63+
free(converted);
6464
});
6565

6666
test("fromUtf8 unpaired surrogate", () {

0 commit comments

Comments
 (0)