236 lines
5.3 KiB
D
236 lines
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];
|
||
|
}
|
||
|
}
|