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

Commit

Permalink
Allocation utilities. (#7)
Browse files Browse the repository at this point in the history
* Allocation utilities.

* Comments
  • Loading branch information
sjindel-google authored Oct 9, 2019
1 parent e6aea0a commit f46c1f4
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

export 'src/utf8.dart';
export 'src/utf16.dart';
export 'src/allocation.dart' show allocate, free;
78 changes: 78 additions & 0 deletions lib/src/allocation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:ffi';
import 'dart:io';

// Note that kernel32.dll is the correct name in both 32-bit and 64-bit.
final DynamicLibrary stdlib = Platform.isWindows
? DynamicLibrary.open("kernel32.dll")
: DynamicLibrary.process();

typedef PosixMallocNative = Pointer Function(IntPtr);
typedef PosixMalloc = Pointer Function(int);
final PosixMalloc posixMalloc =
stdlib.lookupFunction<PosixMallocNative, PosixMalloc>("malloc");

typedef PosixFreeNative = Void Function(Pointer);
typedef PosixFree = void Function(Pointer);
final PosixFree posixFree =
stdlib.lookupFunction<PosixFreeNative, PosixFree>("free");

typedef WinGetProcessHeapFn = Pointer Function();
final WinGetProcessHeapFn winGetProcessHeap = stdlib
.lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>("GetProcessHeap");
final Pointer processHeap = winGetProcessHeap();

typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
final WinHeapAlloc winHeapAlloc =
stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>("HeapAlloc");

typedef WinHeapFreeNative = Int32 Function(
Pointer heap, Uint32 flags, Pointer memory);
typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
final WinHeapFree winHeapFree =
stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>("HeapFree");

/// Allocates memory on the native heap.
///
/// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
/// against the default public heap. Allocation of either element size or count
/// of 0 is undefined.
///
/// Throws an ArgumentError on failure to allocate.
Pointer<T> allocate<T extends NativeType>({int count = 1}) {
final int totalSize = count * sizeOf<T>();
Pointer<T> result;
if (Platform.isWindows) {
result = winHeapAlloc(processHeap, /*flags=*/ 0, totalSize).cast();
} else {
result = posixMalloc(totalSize).cast();
}
if (result.address == 0) {
throw ArgumentError("Could not allocate $totalSize bytes.");
}
return result;
}

/// Releases memory on the native heap.
///
/// For POSIX-based systems, this uses free. On Windows, it uses HeapFree
/// against the default public heap. It may only be used against pointers
/// allocated in a manner equivalent to [allocate].
///
/// Throws an ArgumentError on failure to free.
///
// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
// of testing the return integer to be non-zero.
void free(Pointer pointer) {
if (Platform.isWindows) {
if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
throw ArgumentError("Could not free $pointer.");
}
} else {
posixFree(pointer);
}
}
5 changes: 3 additions & 2 deletions lib/src/utf16.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';

import 'package:ffi/ffi.dart';

/// [Utf16] implements conversion between Dart strings and null-terminated
/// Utf6-encoded "char*" strings in C.
///
Expand All @@ -21,8 +23,7 @@ class Utf16 extends Struct<Utf16> {
/// Returns a malloc-allocated pointer to the result.
static Pointer<Utf16> toUtf16(String s) {
final units = s.codeUnits;
final Pointer<Uint16> result =
Pointer<Uint16>.allocate(count: units.length + 1);
final Pointer<Uint16> result = allocate<Uint16>(count: units.length + 1);
final Uint16List nativeString =
result.asExternalTypedData(count: units.length + 1);
nativeString.setAll(0, units);
Expand Down
4 changes: 3 additions & 1 deletion lib/src/utf8.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';

import 'package:ffi/ffi.dart';

const int _kMaxSmi64 = (1 << 62) - 1;
const int _kMaxSmi32 = (1 << 30) - 1;
final int _maxSize = sizeOf<IntPtr>() == 8 ? _kMaxSmi64 : _kMaxSmi32;
Expand Down Expand Up @@ -54,7 +56,7 @@ class Utf8 extends Struct<Utf8> {
static Pointer<Utf8> toUtf8(String string) {
final units = utf8.encode(string);
final Pointer<Uint8> result =
Pointer<Uint8>.allocate(count: units.length + 1);
allocate<Uint8>(count: units.length + 1);
final Uint8List nativeString =
result.asExternalTypedData(count: units.length + 1);
nativeString.setAll(0, units);
Expand Down
4 changes: 2 additions & 2 deletions test/utf16_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ main() {
converted.asExternalTypedData(count: start.codeUnits.length + 1);
final matcher = equals(start.codeUnits.toList()..add(0));
expect(end, matcher);
converted.free();
free(converted);
});

test("toUtf16 emoji", () {
Expand All @@ -27,6 +27,6 @@ main() {
converted.cast<Uint16>().asExternalTypedData(count: length + 1);
final matcher = equals(start.codeUnits.toList()..add(0));
expect(end, matcher);
converted.free();
free(converted);
});
}
8 changes: 4 additions & 4 deletions test/utf8_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:test/test.dart';
import 'package:ffi/ffi.dart';

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

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

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

test("fromUtf8 unpaired surrogate", () {
Expand Down

0 comments on commit f46c1f4

Please sign in to comment.