blob: a424f5efb3166bea7ee2176153a04ea3c8b24448 [file] [edit]
// Copyright (c) 2025, 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:typed_data';
/// Pointer to a memory location in [Uint32Arena].
///
/// The pointer is also represented with a 32-bit unsigned integer which
/// can be stored into [Uint32Arena].
extension type const ArenaPointer(int _index) {
/// Invalid pointer value.
static const ArenaPointer Null = ArenaPointer(0xffffffff);
/// Pointer to the [size]-th element after [this].
ArenaPointer operator +(int size) {
assert(this != Null);
return ArenaPointer(_index + size);
}
/// Number of 32-bit elements between [base] and [this] pointers.
int operator -(ArenaPointer base) {
assert(this != Null);
assert(base != Null);
return this._index - base._index;
}
/// 32-bit unsigned integer value of this pointer.
int toInt() => _index;
}
/// Growable arena containing 32-bit unsigned integer elements.
mixin class Uint32Arena {
/// Initial capacity of the arena.
static const int initialSize = 1024;
/// Maximum size of the arena.
static const int maxSize = 0x80000000;
Uint32List _buffer = Uint32List(initialSize);
int _used = 0;
/// Loads 32-bit unsigned integer value stored at [ptr].
///
/// [ptr] should point to a valid, previously allocated location.
@pragma("vm:prefer-inline")
int operator [](ArenaPointer ptr) {
assert(ptr._index < _used);
return _buffer[ptr._index];
}
/// Stores low 32 bits of [value] at [ptr].
///
/// [ptr] should point to a valid, previously allocated location.
@pragma("vm:prefer-inline")
void operator []=(ArenaPointer ptr, int value) {
assert(ptr._index < _used);
_buffer[ptr._index] = value;
}
/// Allocate [size] 32-bit elements in this arena and
/// returns pointer to the first element.
///
/// Allocated elements are zero-initialized.
/// Expands arena storage as needed, up to [maxSize].
/// Returns [ArenaPointer.Null] if [size] is zero.
@pragma("vm:prefer-inline")
ArenaPointer allocate(int size) {
assert(size >= 0);
if (size == 0) {
return ArenaPointer.Null;
}
final index = _used;
if (index > _buffer.length - size) {
_expand(size);
}
_used += size;
return ArenaPointer(index);
}
@pragma("vm:never-inline")
void _expand(int size) {
assert(size > 0);
int capacity = _buffer.length;
while (_used > capacity - size) {
capacity = capacity << 1;
if (capacity > maxSize) {
throw StateError('Cannot grow arena beyond $maxSize elements');
}
}
Uint32List old = _buffer;
_buffer = Uint32List(capacity);
_buffer.setRange(0, _used, old);
}
}