// 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 allocate(int byteCount, {int? alignment}) { /// final result = /// _wrappedAllocator.allocate(byteCount, alignment: alignment); /// _totalAllocations++; /// _nonFreedAllocations++; /// return result; /// } /// /// @override /// void free(Pointer 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()` bytes, call the allocator directly /// as a function: `allocator(count)` (see [AllocatorAlloc.call] for /// details). /// /// ```dart /// // This allocates two bytes. If you intended two Int32's, this is an /// // error. /// allocator.allocate(2); /// /// // This allocates eight bytes, which is enough space for two Int32's. /// // However, this is not the idiomatic way. /// allocator.allocate(sizeOf() * 2); /// /// // The idiomatic way to allocate space for two Int32 is to call the /// // allocator directly as a function. /// allocator(2); /// ``` /// /// Throws an [ArgumentError] if the number of bytes or alignment cannot be /// satisfied. Pointer allocate(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() * count` bytes of memory using [allocate]. /// /// ```dart /// // This allocates eight bytes, which is enough space for two Int32's. /// allocator(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()`, 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 call([int count = 1]); }