This repository has been archived on 2024-11-14. You can view files and clone it, but cannot push or open issues or pull requests.
game-project/source/utils/indexedarray.d
2023-10-02 23:41:01 +13:00

236 lines
No EOL
5.3 KiB
D

module utils.indexedarray;
/**
IndexedArray
Copyright: (c) Enalye 2017
License: Zlib
Authors: Enalye
Repo: https://github.com/Enalye/atelier
*/
import std.parallelism;
import std.range;
import std.typecons;
/**
Special Array that remove fragmentation while keeping indexes valid.
*/
class IndexedArray(T, uint _capacity, bool _useParallelism = false) {
private uint _dataTop = 0u;
private uint _availableIndexesTop = 0u;
private uint _removeTop = 0u;
private T[_capacity] _dataTable;
private uint[_capacity] _availableIndexes;
private uint[_capacity] _translationTable;
private uint[_capacity] _reverseTranslationTable;
private uint[_capacity] _removeTable;
@property {
uint length() const {
return _dataTop;
}
uint capacity() const {
return _capacity;
}
ref T[_capacity] data() {
return _dataTable;
}
}
uint push(T value) {
uint index;
if ((_dataTop + 1u) == _capacity) {
throw new Exception("IndexedArray overload");
}
if (_availableIndexesTop) {
//Take out the last available index on the list.
_availableIndexesTop--;
index = _availableIndexes[_availableIndexesTop];
}
else {
//Or use a new id.
index = _dataTop;
}
//Add the value to the data stack.
_dataTable[_dataTop] = value;
_translationTable[index] = _dataTop;
_reverseTranslationTable[_dataTop] = index;
++_dataTop;
return index;
}
void pop(uint index) {
uint valueIndex = _translationTable[index];
//Push the index on the available indexes stack.
_availableIndexes[_availableIndexesTop] = index;
_availableIndexesTop++;
//Invalidate the index.
_translationTable[index] = -1;
//Take the top value on the stack and fill the gap.
_dataTop--;
if (valueIndex < _dataTop) {
uint userIndex = _reverseTranslationTable[_dataTop];
_dataTable[valueIndex] = _dataTable[_dataTop];
_translationTable[userIndex] = valueIndex;
_reverseTranslationTable[valueIndex] = userIndex;
}
}
void reset() {
_dataTop = 0u;
_availableIndexesTop = 0u;
_removeTop = 0u;
}
void markInternalForRemoval(uint index) {
synchronized {
_removeTable[_removeTop] = _reverseTranslationTable[index];
_removeTop++;
}
}
void markForRemoval(uint index) {
_removeTable[_removeTop] = index;
_removeTop++;
}
void sweepMarkedData() {
for (uint i = 0u; i < _removeTop; i++) {
pop(_removeTable[i]);
}
_removeTop = 0u;
}
static if (_useParallelism) {
int opApply(int delegate(ref T) dlg) {
int result;
foreach (i; parallel(iota(_dataTop))) {
result = dlg(_dataTable[i]);
if (result)
break;
}
return result;
}
}
else {
int opApply(int delegate(ref T) dlg) {
int result;
foreach (i; 0u .. _dataTop) {
result = dlg(_dataTable[i]);
if (result)
break;
}
return result;
}
}
int opApply(int delegate(const ref T) dlg) const {
int result;
foreach (i; 0u .. _dataTop) {
result = dlg(_dataTable[i]);
if (result)
break;
}
return result;
}
static if (_useParallelism) {
int opApply(int delegate(ref T, uint) dlg) {
int result;
foreach (i; parallel(iota(_dataTop))) {
result = dlg(_dataTable[i], i);
if (result)
break;
}
return result;
}
}
else {
int opApply(int delegate(ref T, uint) dlg) {
int result;
foreach (i; 0u .. _dataTop) {
result = dlg(_dataTable[i], i);
if (result)
break;
}
return result;
}
}
int opApply(int delegate(const ref T, uint) dlg) const {
int result;
foreach (i; 0u .. _dataTop) {
result = dlg(_dataTable[i], i);
if (result)
break;
}
return result;
}
int opApply(int delegate(const Tuple!(const uint, const T)) dlg) const {
int result;
foreach (i; 0u .. _dataTop) {
result = dlg(tuple!(const uint, const T)(_reverseTranslationTable[i], _dataTable[i]));
if (result)
break;
}
return result;
}
T opIndex(uint index) {
return _dataTable[_translationTable[index]];
}
bool has(uint index) {
if (index > _dataTop)
return false;
if (_translationTable[index] == -1)
return false;
return true;
}
/// Returns the first element in the list
T first() {
assert(_dataTop > 0);
return _dataTable[0];
}
/// Returns the last element in the list
T last() {
assert(_dataTop > 0);
return _dataTable[_dataTop - 1];
}
}