blob: 0ffdbbe9627ae94f2c2211fd736afdc689420543 [file] [log] [blame]
// Copyright (c) 2021, 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.
part of dart.ffi;
// Examples can assume:
// late Allocator allocator;
// late Allocator calloc;
/// Manages memory on the native heap.
///
/// When allocating memory, prefer calling this allocator directly as a
/// function (see [AllocatorAlloc.call] for details).
///
/// This interface provides only the [allocate] method to allocate a block of
/// bytes, and the [free] method to release such a block again.
/// Implementations only need to provide those two methods.
/// The [AllocatorAlloc.call] extension method is defined in terms of those
/// lower-level operations.
///
/// An example of an allocator wrapping another to count the number of
/// allocations:
///
/// ```dart
/// class CountingAllocator implements Allocator {
/// final Allocator _wrappedAllocator;
/// int _totalAllocations = 0;
/// int _nonFreedAllocations = 0;
///
/// CountingAllocator([Allocator? allocator])
/// : _wrappedAllocator = allocator ?? calloc;
///
/// int get totalAllocations => _totalAllocations;
///
/// int get nonFreedAllocations => _nonFreedAllocations;
///
/// @override
/// Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
/// final result =
/// _wrappedAllocator.allocate<T>(byteCount, alignment: alignment);
/// _totalAllocations++;
/// _nonFreedAllocations++;
/// return result;
/// }
///
/// @override
/// void free(Pointer<NativeType> pointer) {
/// _wrappedAllocator.free(pointer);
/// _nonFreedAllocations--;
/// }
/// }
/// ```
@Since('2.12')
abstract class Allocator {
/// This interface is meant to be implemented, not extended or mixed in.
Allocator._() {
throw UnsupportedError("Cannot be instantiated");
}
/// Allocates [byteCount] bytes of memory on the native heap.
///
/// If [alignment] is provided, the allocated memory will be at least aligned
/// to [alignment] bytes.
///
/// To allocate a multiple of `sizeOf<T>()` bytes, call the allocator
/// directly as a function: `allocator<T>(count)` (see [AllocatorAlloc.call]
/// for details).
///
/// ```dart
/// // This allocates two bytes. If you intended two Int32's, this is an
/// // error.
/// allocator.allocate<Int32>(2);
///
/// // This allocates eight bytes, which is enough space for two Int32's.
/// // However, this is not the idiomatic way.
/// allocator.allocate<Int32>(sizeOf<Int32>() * 2);
///
/// // The idiomatic way to allocate space for two Int32 is to call the
/// // allocator directly as a function.
/// allocator<Int32>(2);
/// ```
///
/// Throws an [ArgumentError] if the number of bytes or alignment cannot be
/// satisfied.
Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment});
/// Releases memory allocated on the native heap.
///
/// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
/// freed.
void free(Pointer pointer);
}
/// Extension on [Allocator] to provide allocation with [NativeType].
@Since('2.12')
extension AllocatorAlloc on Allocator {
/// Allocates `sizeOf<T>() * count` bytes of memory using [allocate].
///
/// ```dart
/// // This allocates eight bytes, which is enough space for two Int32's.
/// allocator<Int32>(2);
/// ```
///
/// This extension method must be invoked with a compile-time constant [T].
///
/// To allocate a specific number of bytes, not just a multiple of
/// `sizeOf<T>()`, use [allocate].
/// To allocate with a non constant [T], use [allocate].
/// Prefer [call] for normal use, and use [allocate] for implementing an
/// [Allocator] in terms of other allocators.
external Pointer<T> call<T extends NativeType>([int count = 1]);
}