Apply formating to all files. CLeanup
This commit is contained in:
parent
43e374f269
commit
744c01c5d0
928 changed files with 14515 additions and 21480 deletions
|
|
@ -1,18 +1,14 @@
|
|||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace tp {
|
||||
|
||||
static ModuleManifest* sModuleDependencies[] = { &gModuleBase,nullptr };
|
||||
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
|
||||
|
||||
void* DefaultAllocator::allocate(ualni size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void DefaultAllocator::deallocate(void* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace tp {
|
||||
|
||||
static ModuleManifest* sModuleDependencies[] = { &gModuleBase, nullptr };
|
||||
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
|
||||
|
||||
void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
|
||||
|
||||
void DefaultAllocator::deallocate(void* p) { free(p); }
|
||||
}
|
||||
|
|
@ -5,20 +5,27 @@
|
|||
|
||||
namespace tp {
|
||||
|
||||
template<ualni tScale = 2>
|
||||
inline ualni BufferResizeScaling(ualni const size) { return size * tScale; }
|
||||
template <ualni tScale = 2>
|
||||
inline ualni BufferResizeScaling(const ualni size) {
|
||||
return size * tScale;
|
||||
}
|
||||
|
||||
template<ualni tScale = 2>
|
||||
inline ualni BufferResizeScalingDown(ualni const size) { return size / tScale; }
|
||||
template <ualni tScale = 2>
|
||||
inline ualni BufferResizeScalingDown(const ualni size) {
|
||||
return size / tScale;
|
||||
}
|
||||
|
||||
template<ualni tAddition = 1>
|
||||
inline ualni BufferResizeAddition(ualni const size) { return size + tAddition; }
|
||||
template <ualni tAddition = 1>
|
||||
inline ualni BufferResizeAddition(const ualni size) {
|
||||
return size + tAddition;
|
||||
}
|
||||
|
||||
template<ualni tAddition = 1>
|
||||
inline ualni BufferResizeAdditionDown(ualni const size) { return size - tAddition; }
|
||||
template <ualni tAddition = 1>
|
||||
inline ualni BufferResizeAdditionDown(const ualni size) {
|
||||
return size - tAddition;
|
||||
}
|
||||
|
||||
|
||||
template<typename tType, ualni tSize>
|
||||
template <typename tType, ualni tSize>
|
||||
class ConstSizeBuffer {
|
||||
typedef SelectValueOrReference<tType> Arg;
|
||||
|
||||
|
|
@ -37,6 +44,7 @@ namespace tp {
|
|||
|
||||
public:
|
||||
[[nodiscard]] ualni size() const { return mLoad; }
|
||||
|
||||
[[nodiscard]] ualni getBuffSize() const { return tSize; }
|
||||
|
||||
tType& first() {
|
||||
|
|
@ -94,28 +102,32 @@ namespace tp {
|
|||
}
|
||||
|
||||
public:
|
||||
|
||||
class IteratorPointer {
|
||||
protected:
|
||||
tType* mIter;
|
||||
|
||||
public:
|
||||
IteratorPointer() = default;
|
||||
|
||||
tType& operator->() { return *mIter; }
|
||||
|
||||
const tType& operator->() const { return *mIter; }
|
||||
};
|
||||
|
||||
class IteratorReference {
|
||||
protected:
|
||||
tType* mIter;
|
||||
|
||||
public:
|
||||
IteratorReference() = default;
|
||||
|
||||
tType* operator->() { return mIter; }
|
||||
|
||||
const tType* operator->() const { return mIter; }
|
||||
};
|
||||
|
||||
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
|
||||
public:
|
||||
|
||||
explicit Iterator(tType* iter) { this->mIter = iter; }
|
||||
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
|
@ -126,19 +138,16 @@ namespace tp {
|
|||
}
|
||||
|
||||
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
|
||||
|
||||
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
|
||||
};
|
||||
|
||||
[[nodiscard]] Iterator begin() const {
|
||||
return Iterator(mBuff);
|
||||
}
|
||||
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
|
||||
|
||||
[[nodiscard]] Iterator end() const {
|
||||
return Iterator(mBuff + mLoad);
|
||||
}
|
||||
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mLoad); }
|
||||
|
||||
public:
|
||||
template<class tArchiver>
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mLoad;
|
||||
for (auto item : *this) {
|
||||
|
|
@ -146,7 +155,7 @@ namespace tp {
|
|||
}
|
||||
}
|
||||
|
||||
template<class tArchiver>
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
clear();
|
||||
ar >> mLoad;
|
||||
|
|
@ -156,13 +165,7 @@ namespace tp {
|
|||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename tType,
|
||||
class tAllocator = DefaultAllocator,
|
||||
ualni (tResizePolicy)(ualni) = BufferResizeScaling<2>,
|
||||
ualni (tResizePolicyDown)(ualni) = BufferResizeScalingDown<2>,
|
||||
ualni tMinSize = 4
|
||||
>
|
||||
template <typename tType, class tAllocator = DefaultAllocator, ualni(tResizePolicy)(ualni) = BufferResizeScaling<2>, ualni(tResizePolicyDown)(ualni) = BufferResizeScalingDown<2>, ualni tMinSize = 4>
|
||||
class Buffer {
|
||||
typedef SelectValueOrReference<tType> Arg;
|
||||
|
||||
|
|
@ -173,17 +176,25 @@ namespace tp {
|
|||
ualni mLoad;
|
||||
|
||||
public:
|
||||
Buffer() : mSize(tMinSize), mLoad(0) {
|
||||
Buffer() :
|
||||
mSize(tMinSize),
|
||||
mLoad(0) {
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * tMinSize);
|
||||
}
|
||||
|
||||
explicit Buffer(ualni size) : mSize(size), mLoad(0) {
|
||||
explicit Buffer(ualni size) :
|
||||
mSize(size),
|
||||
mLoad(0) {
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * size);
|
||||
}
|
||||
|
||||
Buffer(const Buffer& in) : mSize(in.mSize), mLoad(in.mLoad) {
|
||||
Buffer(const Buffer& in) :
|
||||
mSize(in.mSize),
|
||||
mLoad(in.mLoad) {
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * mSize);
|
||||
for (ualni i = 0; i < mLoad; i++) new (&mBuff[i]) tType(in.mBuff[i]);
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
new (&mBuff[i]) tType(in.mBuff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
|
@ -192,44 +203,48 @@ namespace tp {
|
|||
}
|
||||
|
||||
Buffer& operator=(const Buffer& in) {
|
||||
if (this == &in) return *this;
|
||||
if (this == &in) {
|
||||
return *this;
|
||||
}
|
||||
this->~Buffer();
|
||||
new (this) Buffer(in);
|
||||
return *this;
|
||||
new (this) Buffer(in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Buffer() {
|
||||
for (ualni i = 0; i < mLoad; i++) mBuff[i].~tType();
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
mBuff[i].~tType();
|
||||
}
|
||||
mAllocator.deallocate(mBuff);
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] ualni size() const {
|
||||
return mLoad;
|
||||
}
|
||||
[[nodiscard]] ualni size() const { return mLoad; }
|
||||
|
||||
[[nodiscard]] ualni getBuffSize() const { return mSize; }
|
||||
|
||||
[[nodiscard]] const tType* getBuff() const { return mBuff; }
|
||||
|
||||
[[nodiscard]] tType* getBuff() { return mBuff; }
|
||||
|
||||
[[nodiscard]] ualni getBuffSize() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
tType& first() {
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return *mBuff;
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return *mBuff;
|
||||
}
|
||||
|
||||
const tType& first() const {
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return *mBuff;
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return *mBuff;
|
||||
}
|
||||
|
||||
tType& last() {
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return mBuff[mLoad - 1];
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return mBuff[mLoad - 1];
|
||||
}
|
||||
|
||||
const tType& last() const {
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return mBuff[mLoad - 1];
|
||||
DEBUG_ASSERT(mLoad)
|
||||
return mBuff[mLoad - 1];
|
||||
}
|
||||
|
||||
tType& operator[](ualni idx) {
|
||||
|
|
@ -244,10 +259,16 @@ namespace tp {
|
|||
|
||||
public:
|
||||
bool operator==(const Buffer& in) const {
|
||||
if (this == &in) return true;
|
||||
if (mLoad != in.mLoad) return false;
|
||||
if (this == &in) {
|
||||
return true;
|
||||
}
|
||||
if (mLoad != in.mLoad) {
|
||||
return false;
|
||||
}
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
if (mBuff[i] != in.mBuff[i]) return false;
|
||||
if (mBuff[i] != in.mBuff[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -262,67 +283,86 @@ namespace tp {
|
|||
}
|
||||
|
||||
void append(Arg data) {
|
||||
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
|
||||
if (mLoad == mSize) {
|
||||
resizeBuffer(tResizePolicy(mSize));
|
||||
}
|
||||
new (&mBuff[mLoad]) tType(data);
|
||||
mLoad++;
|
||||
}
|
||||
|
||||
void append(const Buffer& in) {
|
||||
if (!in.mLoad) return;
|
||||
auto newLoad = mLoad + in.mLoad;
|
||||
auto newSize = mSize;
|
||||
while (newLoad >= newSize) newSize = tResizePolicy(newSize);
|
||||
if (newSize != mSize) resizeBuffer(newSize);
|
||||
for (auto i = mLoad; i < newLoad; i++) new (&mBuff[i]) tType(in.mBuff[i - mLoad]);
|
||||
mLoad = newLoad;
|
||||
}
|
||||
void append(const Buffer& in) {
|
||||
if (!in.mLoad) {
|
||||
return;
|
||||
}
|
||||
auto newLoad = mLoad + in.mLoad;
|
||||
auto newSize = mSize;
|
||||
while (newLoad >= newSize) {
|
||||
newSize = tResizePolicy(newSize);
|
||||
}
|
||||
if (newSize != mSize) {
|
||||
resizeBuffer(newSize);
|
||||
}
|
||||
for (auto i = mLoad; i < newLoad; i++) {
|
||||
new (&mBuff[i]) tType(in.mBuff[i - mLoad]);
|
||||
}
|
||||
mLoad = newLoad;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
DEBUG_ASSERT(mLoad)
|
||||
mBuff[mLoad].~tType();
|
||||
mLoad--;
|
||||
ualni prevSize = tResizePolicyDown(mSize);
|
||||
DEBUG_ASSERT(prevSize < mSize)
|
||||
if (prevSize > mLoad) resizeBuffer(prevSize);
|
||||
DEBUG_ASSERT(prevSize < mSize)
|
||||
if (prevSize > mLoad) {
|
||||
resizeBuffer(prevSize);
|
||||
}
|
||||
}
|
||||
|
||||
void reserve(ualni aSize) {
|
||||
for (ualni i = 0; i < mLoad; i++) mBuff[i].~tType();
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
mBuff[i].~tType();
|
||||
}
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * aSize);
|
||||
mSize = aSize;
|
||||
mLoad = aSize;
|
||||
for (ualni i = 0; i < mLoad; i++) new (mBuff + i) tType();
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
new (mBuff + i) tType();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
class IteratorPointer {
|
||||
protected:
|
||||
tType* mIter;
|
||||
|
||||
public:
|
||||
IteratorPointer() = default;
|
||||
|
||||
tType& operator->() { return *mIter; }
|
||||
|
||||
const tType& operator->() const { return *mIter; }
|
||||
};
|
||||
|
||||
class IteratorReference {
|
||||
protected:
|
||||
tType* mIter;
|
||||
|
||||
public:
|
||||
IteratorReference() = default;
|
||||
|
||||
tType* operator->() { return mIter; }
|
||||
|
||||
const tType* operator->() const { return mIter; }
|
||||
};
|
||||
|
||||
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
|
||||
public:
|
||||
|
||||
explicit Iterator(tType* iter) { this->mIter = iter; }
|
||||
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
||||
tType& data() {
|
||||
return *this->mIter;
|
||||
}
|
||||
tType& data() { return *this->mIter; }
|
||||
|
||||
Iterator& operator++() {
|
||||
this->mIter++;
|
||||
|
|
@ -330,20 +370,16 @@ namespace tp {
|
|||
}
|
||||
|
||||
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
|
||||
|
||||
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
|
||||
};
|
||||
|
||||
[[nodiscard]] Iterator begin() const {
|
||||
return Iterator(mBuff);
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator end() const {
|
||||
return Iterator(mBuff + mLoad);
|
||||
}
|
||||
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
|
||||
|
||||
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mLoad); }
|
||||
|
||||
public:
|
||||
template<class tArchiver>
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mLoad;
|
||||
for (auto item : *this) {
|
||||
|
|
@ -351,45 +387,56 @@ namespace tp {
|
|||
}
|
||||
}
|
||||
|
||||
template<class tArchiver>
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
clear();
|
||||
decltype(mLoad) len;
|
||||
ar >> len;
|
||||
for (auto i = len; i; i--) {
|
||||
// TODO : optimize
|
||||
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
|
||||
if (mLoad == mSize) {
|
||||
resizeBuffer(tResizePolicy(mSize));
|
||||
}
|
||||
ar >> mBuff[mLoad];
|
||||
mLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void resizeBuffer(ualni newSize) {
|
||||
DEBUG_ASSERT(newSize >= mLoad)
|
||||
auto const oldBuff = mBuff;
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * newSize);
|
||||
for (ualni i = 0; i < mLoad; i++) new (&mBuff[i]) tType(oldBuff[i]);
|
||||
for (ualni i = 0; i < mLoad; i++) oldBuff[i].~tType();
|
||||
mAllocator.deallocate(oldBuff);
|
||||
mSize = newSize;
|
||||
}
|
||||
private:
|
||||
void resizeBuffer(ualni newSize) {
|
||||
DEBUG_ASSERT(newSize >= mLoad)
|
||||
const auto oldBuff = mBuff;
|
||||
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * newSize);
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
new (&mBuff[i]) tType(oldBuff[i]);
|
||||
}
|
||||
for (ualni i = 0; i < mLoad; i++) {
|
||||
oldBuff[i].~tType();
|
||||
}
|
||||
mAllocator.deallocate(oldBuff);
|
||||
mSize = newSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename tType>
|
||||
template <typename tType>
|
||||
void generatePermutations(const Buffer<Buffer<tType>>& in, Buffer<Buffer<tType>>& out) {
|
||||
typedef long long Idx;
|
||||
|
||||
// sanity check
|
||||
for (const auto & vec : in) {
|
||||
if (!vec.size()) return;
|
||||
for (const auto& vec : in) {
|
||||
if (!vec.size()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out.resize(in.size());
|
||||
auto len = Idx(1);
|
||||
for (const auto & vec : in) len *= (Idx) vec.size();
|
||||
for (auto i = 0; i < in.size(); i++) out[i].resize(len);
|
||||
for (const auto& vec : in) {
|
||||
len *= (Idx) vec.size();
|
||||
}
|
||||
for (auto i = 0; i < in.size(); i++) {
|
||||
out[i].resize(len);
|
||||
}
|
||||
|
||||
auto dub = Idx(1);
|
||||
for (auto power = (Idx) in.size() - 1; power >= 0; power--) {
|
||||
|
|
|
|||
|
|
@ -1,125 +1,125 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename tType, ualni tSizeX, ualni tSizeY>
|
||||
using ConstSizeBuffer2D = ConstSizeBuffer<ConstSizeBuffer<tType, tSizeX>, tSizeY>;
|
||||
|
||||
template <typename tType, class tAllocator = DefaultAllocator>
|
||||
class Buffer2D {
|
||||
public:
|
||||
typedef ualni Index;
|
||||
typedef Pair<Index, Index> Index2D;
|
||||
typedef SelectValueOrReference<tType> tTypeArg;
|
||||
|
||||
private:
|
||||
tAllocator mAlloc;
|
||||
tType* mBuff = nullptr;
|
||||
Index2D mSize = {0, 0};
|
||||
|
||||
void deleteBuffer() {
|
||||
if (!mBuff) {
|
||||
return;
|
||||
}
|
||||
for (ualni i = 0; i < mSize.x * mSize.y; i++) {
|
||||
mBuff[i].~tType();
|
||||
}
|
||||
mAlloc.deallocate(mBuff);
|
||||
}
|
||||
|
||||
void allocateBuffer(Index2D size) {
|
||||
deleteBuffer();
|
||||
mBuff = (tType*) mAlloc.allocate(sizeof(tType) * size.x * size.y);
|
||||
for (ualni i = 0; i < mSize.x * mSize.y; i++) {
|
||||
new (mBuff + i) tType();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Buffer2D() = default;
|
||||
|
||||
~Buffer2D() {
|
||||
deleteBuffer();
|
||||
mSize = {0, 0};
|
||||
}
|
||||
|
||||
explicit Buffer2D(Index2D aSize) { reserve(aSize); }
|
||||
|
||||
[[nodiscard]] Index2D size() const { return {mSize.x, mSize.y}; }
|
||||
|
||||
tType* getBuff() const { return mBuff; }
|
||||
|
||||
inline tType& get(const Index2D& at) {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
return *(mBuff + mSize.x * at.y + at.x);
|
||||
}
|
||||
|
||||
inline const tType& get(const Index2D& at) const {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
return *(mBuff + mSize.x * at.y + at.x);
|
||||
}
|
||||
|
||||
inline void set(const Index2D& at, tTypeArg value) {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
*(mBuff + mSize.x * at.y + at.x) = value;
|
||||
}
|
||||
|
||||
void reserve(const Index2D& newSize) {
|
||||
if (mSize.x != newSize.x || mSize.y != newSize.y) {
|
||||
allocateBuffer(newSize);
|
||||
mSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
void assign(tType value) {
|
||||
DEBUG_ASSERT(mBuff);
|
||||
Index len = mSize.x * mSize.y;
|
||||
for (Index i = 0; i < len; i++) {
|
||||
mBuff[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Buffer2D& in) const {
|
||||
if (&in == this) {
|
||||
return true;
|
||||
}
|
||||
if (in.size() != size()) {
|
||||
return false;
|
||||
}
|
||||
for (auto i = 0; i < mSize.x * mSize.y; i++) {
|
||||
if (mBuff[i] != in.mBuff[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mSize;
|
||||
for (auto i = 0; i < mSize.x; i++) {
|
||||
for (auto j = 0; j < mSize.y; j++) {
|
||||
ar << get(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
decltype(mSize) size;
|
||||
deleteBuffer();
|
||||
ar >> size;
|
||||
reserve(size);
|
||||
for (auto i = 0; i < mSize.x; i++) {
|
||||
for (auto j = 0; j < mSize.y; j++) {
|
||||
ar >> get(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename tType, ualni tSizeX, ualni tSizeY>
|
||||
using ConstSizeBuffer2D = ConstSizeBuffer<ConstSizeBuffer<tType, tSizeX>, tSizeY>;
|
||||
|
||||
template <typename tType, class tAllocator = DefaultAllocator>
|
||||
class Buffer2D {
|
||||
public:
|
||||
typedef ualni Index;
|
||||
typedef Pair<Index, Index> Index2D;
|
||||
typedef SelectValueOrReference<tType> tTypeArg;
|
||||
|
||||
private:
|
||||
tAllocator mAlloc;
|
||||
tType* mBuff = nullptr;
|
||||
Index2D mSize = { 0, 0 };
|
||||
|
||||
void deleteBuffer() {
|
||||
if (!mBuff) {
|
||||
return;
|
||||
}
|
||||
for (ualni i = 0; i < mSize.x * mSize.y; i++) {
|
||||
mBuff[i].~tType();
|
||||
}
|
||||
mAlloc.deallocate(mBuff);
|
||||
}
|
||||
|
||||
void allocateBuffer(Index2D size) {
|
||||
deleteBuffer();
|
||||
mBuff = (tType*) mAlloc.allocate(sizeof(tType) * size.x * size.y);
|
||||
for (ualni i = 0; i < mSize.x * mSize.y; i++) {
|
||||
new (mBuff + i) tType();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Buffer2D() = default;
|
||||
|
||||
~Buffer2D() {
|
||||
deleteBuffer();
|
||||
mSize = { 0, 0 };
|
||||
}
|
||||
|
||||
explicit Buffer2D(Index2D aSize) { reserve(aSize); }
|
||||
|
||||
[[nodiscard]] Index2D size() const { return { mSize.x, mSize.y }; }
|
||||
|
||||
tType* getBuff() const { return mBuff; }
|
||||
|
||||
inline tType& get(const Index2D& at) {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
return *(mBuff + mSize.x * at.y + at.x);
|
||||
}
|
||||
|
||||
inline const tType& get(const Index2D& at) const {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
return *(mBuff + mSize.x * at.y + at.x);
|
||||
}
|
||||
|
||||
inline void set(const Index2D& at, tTypeArg value) {
|
||||
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
|
||||
*(mBuff + mSize.x * at.y + at.x) = value;
|
||||
}
|
||||
|
||||
void reserve(const Index2D& newSize) {
|
||||
if (mSize.x != newSize.x || mSize.y != newSize.y) {
|
||||
allocateBuffer(newSize);
|
||||
mSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
void assign(tType value) {
|
||||
DEBUG_ASSERT(mBuff);
|
||||
Index len = mSize.x * mSize.y;
|
||||
for (Index i = 0; i < len; i++) {
|
||||
mBuff[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Buffer2D& in) const {
|
||||
if (&in == this) {
|
||||
return true;
|
||||
}
|
||||
if (in.size() != size()) {
|
||||
return false;
|
||||
}
|
||||
for (auto i = 0; i < mSize.x * mSize.y; i++) {
|
||||
if (mBuff[i] != in.mBuff[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mSize;
|
||||
for (auto i = 0; i < mSize.x; i++) {
|
||||
for (auto j = 0; j < mSize.y; j++) {
|
||||
ar << get(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
decltype(mSize) size;
|
||||
deleteBuffer();
|
||||
ar >> size;
|
||||
reserve(size);
|
||||
for (auto i = 0; i < mSize.x; i++) {
|
||||
for (auto j = 0; j < mSize.y; j++) {
|
||||
ar >> get(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,18 +9,18 @@ namespace tp {
|
|||
class DefaultAllocator {
|
||||
public:
|
||||
DefaultAllocator() = default;
|
||||
static void *allocate(ualni);
|
||||
static void deallocate(void *);
|
||||
static void* allocate(ualni);
|
||||
static void deallocate(void*);
|
||||
};
|
||||
|
||||
class DefaultSaverLoader {
|
||||
public:
|
||||
DefaultSaverLoader() = default;
|
||||
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
static void write(const Type&) {}
|
||||
|
||||
template<typename Type>
|
||||
template <typename Type>
|
||||
static void read(Type&) {}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,327 +1,325 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
#include "TypeInfo.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type, class Allocator = DefaultAllocator>
|
||||
class List {
|
||||
|
||||
typedef SelectValueOrReference<Type> TypeArg;
|
||||
typedef ualni Index;
|
||||
|
||||
public:
|
||||
|
||||
struct Node {
|
||||
Type data;
|
||||
Node* next = nullptr;
|
||||
Node* prev = nullptr;
|
||||
Node() = default;
|
||||
explicit Node(TypeArg p_data) : data(p_data) {}
|
||||
Type& operator->() { return data; }
|
||||
};
|
||||
|
||||
class IteratorPointer {
|
||||
protected:
|
||||
Node* mIter;
|
||||
public:
|
||||
IteratorPointer() = default;
|
||||
Type& operator->() { return (mIter->data); }
|
||||
const Type& operator->() const { return (mIter->data); }
|
||||
};
|
||||
|
||||
class IteratorReference {
|
||||
protected:
|
||||
Node* mIter;
|
||||
public:
|
||||
IteratorReference() = default;
|
||||
Type* operator->() { return &(mIter->data); }
|
||||
const Type* operator->() const { return &(mIter->data); }
|
||||
};
|
||||
|
||||
class Iterator : public TypeSelect<TypeTraits<Type>::isPointer, IteratorPointer, IteratorReference>::Result {
|
||||
public:
|
||||
|
||||
explicit Iterator(Node* iter) { this->mIter = iter; }
|
||||
|
||||
Node* node() { return this->mIter; }
|
||||
Type& data() { return this->mIter->data; }
|
||||
const Node* node() const { return this->mIter; }
|
||||
const Type& data() const { return this->mIter->data; }
|
||||
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
||||
Iterator& operator++() {
|
||||
this->mIter = this->mIter->next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
|
||||
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
|
||||
};
|
||||
|
||||
private:
|
||||
Node* mFirst = nullptr;
|
||||
Node* mLast = nullptr;
|
||||
Index mLength = 0;
|
||||
Allocator mAlloc;
|
||||
|
||||
public:
|
||||
|
||||
List() = default;
|
||||
List(const List& in) { this->operator=(in); }
|
||||
List(const InitialierList<Type>& list) { operator=(list); }
|
||||
|
||||
[[nodiscard]] inline Node* first() const { return mFirst; }
|
||||
[[nodiscard]] inline Node* last() const { return mLast; }
|
||||
[[nodiscard]] inline Index length() const { return mLength; }
|
||||
|
||||
[[nodiscard]] Node* newNode() { return new (mAlloc.allocate(sizeof(Node))) Node(); }
|
||||
[[nodiscard]] Node* newNode(TypeArg arg) { return new (mAlloc.allocate(sizeof(Node))) Node(arg); }
|
||||
[[nodiscard]] Node* newNodeNotConstructed() {
|
||||
auto node = (Node*) mAlloc.allocate(sizeof(Node));
|
||||
node->next = node->prev = nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Allocator& getAllocator() const { return mAlloc; }
|
||||
|
||||
void deleteNode(Node* node) {
|
||||
node->~Node();
|
||||
mAlloc.deallocate(node);
|
||||
}
|
||||
|
||||
Node* addNodeBack() {
|
||||
auto const out = newNode();
|
||||
pushBack(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
Node* addNodeFront() {
|
||||
auto const out = newNode();
|
||||
pushFront(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void attach(Node* node, Node* node_to) {
|
||||
if (node_to) {
|
||||
if (node_to->next) {
|
||||
node->next = node_to->next;
|
||||
node->next->prev = node;
|
||||
}
|
||||
node_to->next = node;
|
||||
node->prev = node_to;
|
||||
if (node_to == mLast) {
|
||||
mLast = node;
|
||||
}
|
||||
} else {
|
||||
if (mFirst) {
|
||||
mFirst->prev = node;
|
||||
node->next = mFirst;
|
||||
mFirst = node;
|
||||
} else {
|
||||
mFirst = mLast = node;
|
||||
}
|
||||
}
|
||||
mLength++;
|
||||
}
|
||||
|
||||
void detach(Node* node) {
|
||||
if (node->next) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
if (node->prev) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
if (node == mLast) {
|
||||
mLast = mLast->prev;
|
||||
}
|
||||
if (node == mFirst) {
|
||||
mFirst = mFirst->next;
|
||||
}
|
||||
mLength--;
|
||||
}
|
||||
|
||||
[[nodiscard]] Node* findIdx(Index idx) const {
|
||||
DEBUG_ASSERT(mFirst && idx < mLength && idx >= 0)
|
||||
Node* found = mFirst;
|
||||
for (int i = 0; i != idx; i++) {
|
||||
found = found->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
[[nodiscard]] Node* find(const TypeArg data) const {
|
||||
Node* found = mFirst;
|
||||
for (alni i = 0; data != found->data; i++) {
|
||||
if (i == length()) return nullptr;
|
||||
if (!found->next) {
|
||||
return nullptr;
|
||||
}
|
||||
found = found->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const Type& operator[](Index idx) const {
|
||||
DEBUG_ASSERT(idx < mLength)
|
||||
return find(idx)->data;
|
||||
}
|
||||
|
||||
void pushBack(Node* new_node) { attach(new_node, mLast); }
|
||||
void pushFront(Node* new_node) { attach(new_node, nullptr); }
|
||||
void pushBack(TypeArg data) { pushBack(newNode(data)); }
|
||||
void pushFront(TypeArg data) { pushFront(newNode(data)); }
|
||||
|
||||
void popBack() {
|
||||
DEBUG_ASSERT(mLast)
|
||||
auto const tmp = mLast;
|
||||
detach(mLast);
|
||||
deleteNode(tmp);
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
DEBUG_ASSERT(mFirst)
|
||||
auto temp = mFirst;
|
||||
detach(mFirst);
|
||||
deleteNode(temp);
|
||||
}
|
||||
|
||||
void insert(Node* node, Index idx) {
|
||||
if (!mLength) {
|
||||
attach(node, mLast);
|
||||
} else if (idx >= mLength) {
|
||||
attach(node, nullptr);
|
||||
} else {
|
||||
attach(node, find(idx)->prev);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(TypeArg data, Index idx) {
|
||||
insert(newNode(data), idx);
|
||||
}
|
||||
|
||||
void removeNode(Node* node) {
|
||||
detach(node);
|
||||
deleteNode(node);
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
while (mFirst) {
|
||||
popFront();
|
||||
}
|
||||
}
|
||||
|
||||
// copies data
|
||||
List& operator+=(const List& in) {
|
||||
for (auto node : in) {
|
||||
pushBack(node.data());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator+=(const InitialierList<Type>& list) {
|
||||
for (auto item : list) {
|
||||
pushBack(item);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator=(const List& in) {
|
||||
if (this == &in) { return *this; }
|
||||
removeAll();
|
||||
(*this) += in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator=(const InitialierList<Type>& list) {
|
||||
removeAll();
|
||||
*this += list;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const List& in) const {
|
||||
if (&in == this) { return true; }
|
||||
if (in.length() != length()) {
|
||||
return false;
|
||||
}
|
||||
Node* left = in.first();
|
||||
Node* right = first();
|
||||
while (left && right) {
|
||||
if (left->data != right->data) {
|
||||
return false;
|
||||
}
|
||||
left = left->next;
|
||||
right = right->next;
|
||||
}
|
||||
if (left != right) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename compare_val>
|
||||
[[nodiscard]] Node* find(bool (*found)(Node* node, compare_val val), compare_val value) const {
|
||||
for (Node* node = mFirst; node; node = node->next) {
|
||||
if (found(node, value)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator begin() const {
|
||||
Iterator out(mFirst);
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator end() const {
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
|
||||
void invert() {
|
||||
Node* iter = mFirst;
|
||||
Node* tmp;
|
||||
while (iter) {
|
||||
tmp = iter;
|
||||
iter = iter->next;
|
||||
swap(tmp->next, tmp->prev);
|
||||
}
|
||||
swap(mFirst, mLast);
|
||||
}
|
||||
|
||||
void detachAll() {
|
||||
while (mFirst) {
|
||||
detach(mFirst);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mLength;
|
||||
for (auto item : *this) {
|
||||
ar << item.data();
|
||||
}
|
||||
}
|
||||
|
||||
template<class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
removeAll();
|
||||
decltype(mLength) len;
|
||||
ar >> len;
|
||||
for (auto i = len; i; i--) {
|
||||
auto node = newNodeNotConstructed();
|
||||
ar >> node->data;
|
||||
pushBack(node);
|
||||
}
|
||||
}
|
||||
|
||||
~List() {
|
||||
removeAll();
|
||||
}
|
||||
};
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
#include "TypeInfo.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Type, class Allocator = DefaultAllocator>
|
||||
class List {
|
||||
|
||||
typedef SelectValueOrReference<Type> TypeArg;
|
||||
typedef ualni Index;
|
||||
|
||||
public:
|
||||
struct Node {
|
||||
Type data;
|
||||
Node* next = nullptr;
|
||||
Node* prev = nullptr;
|
||||
Node() = default;
|
||||
explicit Node(TypeArg p_data) :
|
||||
data(p_data) {}
|
||||
Type& operator->() { return data; }
|
||||
};
|
||||
|
||||
class IteratorPointer {
|
||||
protected:
|
||||
Node* mIter;
|
||||
|
||||
public:
|
||||
IteratorPointer() = default;
|
||||
Type& operator->() { return (mIter->data); }
|
||||
const Type& operator->() const { return (mIter->data); }
|
||||
};
|
||||
|
||||
class IteratorReference {
|
||||
protected:
|
||||
Node* mIter;
|
||||
|
||||
public:
|
||||
IteratorReference() = default;
|
||||
Type* operator->() { return &(mIter->data); }
|
||||
const Type* operator->() const { return &(mIter->data); }
|
||||
};
|
||||
|
||||
class Iterator : public TypeSelect<TypeTraits<Type>::isPointer, IteratorPointer, IteratorReference>::Result {
|
||||
public:
|
||||
explicit Iterator(Node* iter) { this->mIter = iter; }
|
||||
|
||||
Node* node() { return this->mIter; }
|
||||
Type& data() { return this->mIter->data; }
|
||||
const Node* node() const { return this->mIter; }
|
||||
const Type& data() const { return this->mIter->data; }
|
||||
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
||||
Iterator& operator++() {
|
||||
this->mIter = this->mIter->next;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
|
||||
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
|
||||
};
|
||||
|
||||
private:
|
||||
Node* mFirst = nullptr;
|
||||
Node* mLast = nullptr;
|
||||
Index mLength = 0;
|
||||
Allocator mAlloc;
|
||||
|
||||
public:
|
||||
List() = default;
|
||||
List(const List& in) { this->operator=(in); }
|
||||
List(const InitialierList<Type>& list) { operator=(list); }
|
||||
|
||||
[[nodiscard]] inline Node* first() const { return mFirst; }
|
||||
[[nodiscard]] inline Node* last() const { return mLast; }
|
||||
[[nodiscard]] inline Index length() const { return mLength; }
|
||||
|
||||
[[nodiscard]] Node* newNode() { return new (mAlloc.allocate(sizeof(Node))) Node(); }
|
||||
[[nodiscard]] Node* newNode(TypeArg arg) { return new (mAlloc.allocate(sizeof(Node))) Node(arg); }
|
||||
[[nodiscard]] Node* newNodeNotConstructed() {
|
||||
auto node = (Node*) mAlloc.allocate(sizeof(Node));
|
||||
node->next = node->prev = nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Allocator& getAllocator() const { return mAlloc; }
|
||||
|
||||
void deleteNode(Node* node) {
|
||||
node->~Node();
|
||||
mAlloc.deallocate(node);
|
||||
}
|
||||
|
||||
Node* addNodeBack() {
|
||||
auto const out = newNode();
|
||||
pushBack(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
Node* addNodeFront() {
|
||||
auto const out = newNode();
|
||||
pushFront(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void attach(Node* node, Node* node_to) {
|
||||
if (node_to) {
|
||||
if (node_to->next) {
|
||||
node->next = node_to->next;
|
||||
node->next->prev = node;
|
||||
}
|
||||
node_to->next = node;
|
||||
node->prev = node_to;
|
||||
if (node_to == mLast) {
|
||||
mLast = node;
|
||||
}
|
||||
} else {
|
||||
if (mFirst) {
|
||||
mFirst->prev = node;
|
||||
node->next = mFirst;
|
||||
mFirst = node;
|
||||
} else {
|
||||
mFirst = mLast = node;
|
||||
}
|
||||
}
|
||||
mLength++;
|
||||
}
|
||||
|
||||
void detach(Node* node) {
|
||||
if (node->next) {
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
if (node->prev) {
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
if (node == mLast) {
|
||||
mLast = mLast->prev;
|
||||
}
|
||||
if (node == mFirst) {
|
||||
mFirst = mFirst->next;
|
||||
}
|
||||
mLength--;
|
||||
}
|
||||
|
||||
[[nodiscard]] Node* findIdx(Index idx) const {
|
||||
DEBUG_ASSERT(mFirst && idx < mLength && idx >= 0)
|
||||
Node* found = mFirst;
|
||||
for (int i = 0; i != idx; i++) {
|
||||
found = found->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
[[nodiscard]] Node* find(const TypeArg data) const {
|
||||
Node* found = mFirst;
|
||||
for (alni i = 0; data != found->data; i++) {
|
||||
if (i == length()) return nullptr;
|
||||
if (!found->next) {
|
||||
return nullptr;
|
||||
}
|
||||
found = found->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const Type& operator[](Index idx) const {
|
||||
DEBUG_ASSERT(idx < mLength)
|
||||
return find(idx)->data;
|
||||
}
|
||||
|
||||
void pushBack(Node* new_node) { attach(new_node, mLast); }
|
||||
void pushFront(Node* new_node) { attach(new_node, nullptr); }
|
||||
void pushBack(TypeArg data) { pushBack(newNode(data)); }
|
||||
void pushFront(TypeArg data) { pushFront(newNode(data)); }
|
||||
|
||||
void popBack() {
|
||||
DEBUG_ASSERT(mLast)
|
||||
auto const tmp = mLast;
|
||||
detach(mLast);
|
||||
deleteNode(tmp);
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
DEBUG_ASSERT(mFirst)
|
||||
auto temp = mFirst;
|
||||
detach(mFirst);
|
||||
deleteNode(temp);
|
||||
}
|
||||
|
||||
void insert(Node* node, Index idx) {
|
||||
if (!mLength) {
|
||||
attach(node, mLast);
|
||||
} else if (idx >= mLength) {
|
||||
attach(node, nullptr);
|
||||
} else {
|
||||
attach(node, find(idx)->prev);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(TypeArg data, Index idx) { insert(newNode(data), idx); }
|
||||
|
||||
void removeNode(Node* node) {
|
||||
detach(node);
|
||||
deleteNode(node);
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
while (mFirst) {
|
||||
popFront();
|
||||
}
|
||||
}
|
||||
|
||||
// copies data
|
||||
List& operator+=(const List& in) {
|
||||
for (auto node : in) {
|
||||
pushBack(node.data());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator+=(const InitialierList<Type>& list) {
|
||||
for (auto item : list) {
|
||||
pushBack(item);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator=(const List& in) {
|
||||
if (this == &in) {
|
||||
return *this;
|
||||
}
|
||||
removeAll();
|
||||
(*this) += in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
List& operator=(const InitialierList<Type>& list) {
|
||||
removeAll();
|
||||
*this += list;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const List& in) const {
|
||||
if (&in == this) {
|
||||
return true;
|
||||
}
|
||||
if (in.length() != length()) {
|
||||
return false;
|
||||
}
|
||||
Node* left = in.first();
|
||||
Node* right = first();
|
||||
while (left && right) {
|
||||
if (left->data != right->data) {
|
||||
return false;
|
||||
}
|
||||
left = left->next;
|
||||
right = right->next;
|
||||
}
|
||||
if (left != right) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename compare_val>
|
||||
[[nodiscard]] Node* find(bool (*found)(Node* node, compare_val val), compare_val value) const {
|
||||
for (Node* node = mFirst; node; node = node->next) {
|
||||
if (found(node, value)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator begin() const {
|
||||
Iterator out(mFirst);
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator end() const { return Iterator(nullptr); }
|
||||
|
||||
void invert() {
|
||||
Node* iter = mFirst;
|
||||
Node* tmp;
|
||||
while (iter) {
|
||||
tmp = iter;
|
||||
iter = iter->next;
|
||||
swap(tmp->next, tmp->prev);
|
||||
}
|
||||
swap(mFirst, mLast);
|
||||
}
|
||||
|
||||
void detachAll() {
|
||||
while (mFirst) {
|
||||
detach(mFirst);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << mLength;
|
||||
for (auto item : *this) {
|
||||
ar << item.data();
|
||||
}
|
||||
}
|
||||
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
removeAll();
|
||||
decltype(mLength) len;
|
||||
ar >> len;
|
||||
for (auto i = len; i; i--) {
|
||||
auto node = newNodeNotConstructed();
|
||||
ar >> node->data;
|
||||
pushBack(node);
|
||||
}
|
||||
}
|
||||
|
||||
~List() { removeAll(); }
|
||||
};
|
||||
}
|
||||
|
|
@ -1,405 +1,378 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template<typename Key>
|
||||
ualni DefaultHashFunc(SelectValueOrReference<Key> key) {
|
||||
return hash(key);
|
||||
}
|
||||
|
||||
template<typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni(*tHashFunc)(SelectValueOrReference<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
|
||||
class Map {
|
||||
|
||||
enum {
|
||||
MAP_PERTURB_SHIFT = 5,
|
||||
MAP_MIN_SIZE = 4,
|
||||
MAP_MAX_LOAD_PERCENTAGE = 66,
|
||||
};
|
||||
|
||||
typedef SelectValueOrReference<tKey> KeyArg;
|
||||
typedef SelectValueOrReference<tVal> ValArg;
|
||||
|
||||
public:
|
||||
|
||||
class Node {
|
||||
friend Map;
|
||||
Node(KeyArg aKey, ValArg aVal) : key(aKey), val(aVal) {}
|
||||
public:
|
||||
tKey key;
|
||||
tVal val;
|
||||
};
|
||||
|
||||
struct Idx {
|
||||
alni idx = -1;
|
||||
[[nodiscard]] bool isValid() const { return bool(*this); }
|
||||
explicit operator bool() const { return idx != -1; }
|
||||
};
|
||||
|
||||
private:
|
||||
tAllocator mAlloc;
|
||||
Node** mTable = nullptr;
|
||||
ualni mNSlots = 0;
|
||||
ualni mNEntries = 0;
|
||||
|
||||
private:
|
||||
|
||||
constexpr halnf maxLoadFactor() { return halnf(MAP_MAX_LOAD_PERCENTAGE) / 100.f; }
|
||||
|
||||
inline Node** newTable(const ualni len) {
|
||||
return new(mAlloc.allocate(sizeof(Node*) * len)) Node*[len]();
|
||||
}
|
||||
|
||||
inline Node* newNode(KeyArg key, ValArg val) {
|
||||
return new(mAlloc.allocate(sizeof(Node))) Node(key, val);
|
||||
}
|
||||
|
||||
inline Node* newNodeNotConstructed() {
|
||||
return (Node*) mAlloc.allocate(sizeof(Node));
|
||||
}
|
||||
|
||||
inline void deleteTable(Node** table) {
|
||||
mAlloc.deallocate(table);
|
||||
}
|
||||
|
||||
inline void deleteNode(Node* p) {
|
||||
p->~Node();
|
||||
mAlloc.deallocate(p);
|
||||
}
|
||||
|
||||
void markDeletedSlot(ualni idx) const {
|
||||
mTable[idx] = (Node*)-1;
|
||||
}
|
||||
|
||||
static bool isDeletedNode(Node* node) {
|
||||
return node == (Node*)-1;
|
||||
}
|
||||
|
||||
void rehash() {
|
||||
alni nSlotsOld = mNSlots;
|
||||
Node** tableOld = mTable;
|
||||
|
||||
mNSlots = next2pow((uhalni)((1.f / (maxLoadFactor())) * mNEntries + 1));
|
||||
mTable = newTable(mNSlots);
|
||||
mNEntries = 0;
|
||||
|
||||
for (alni i = 0; i < nSlotsOld; i++) {
|
||||
if (!tableOld[i] || isDeletedNode(tableOld[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alni idx = findSlotWrite(tableOld[i]->key);
|
||||
mTable[idx] = tableOld[i];
|
||||
mNEntries++;
|
||||
}
|
||||
|
||||
deleteTable(tableOld);
|
||||
}
|
||||
|
||||
alni findSlotRead(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
alni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx])) {
|
||||
goto SKIP;
|
||||
}
|
||||
if (!mTable[idx]) {
|
||||
return -1;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
SKIP:
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
// compares keys only when collisions occur
|
||||
alni findSlotReadExisting(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
alni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx])) {
|
||||
goto SKIP;
|
||||
}
|
||||
if (!mTable[idx]) {
|
||||
return -1;
|
||||
}
|
||||
if (mTable[((5 * idx) + 1 + shift) & mask] == nullptr) {
|
||||
return idx;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
SKIP:
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
ualni findSlotWrite(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
ualni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx]) || !mTable[idx]) {
|
||||
return idx;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
void put(Node* node) {
|
||||
const ualni idx = findSlotWrite(node->key);
|
||||
|
||||
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
|
||||
mNEntries++;
|
||||
}
|
||||
|
||||
mTable[idx] = node;
|
||||
|
||||
if ((halnf)mNEntries / mNSlots > maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Map() {
|
||||
MODULE_SANITY_CHECK(gModuleContainers)
|
||||
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
|
||||
mTable = newTable(mNSlots);
|
||||
}
|
||||
|
||||
Map(const Map& in) {
|
||||
this->operator=(in);
|
||||
}
|
||||
|
||||
Node** buff() const {
|
||||
return mTable;
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni size() const {
|
||||
return mNEntries;
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni slotsSize() const {
|
||||
return mNEntries;
|
||||
}
|
||||
|
||||
[[nodiscard]] const tAllocator& getAllocator() const {
|
||||
return mAlloc;
|
||||
}
|
||||
|
||||
void put(KeyArg key, ValArg val) {
|
||||
const ualni idx = findSlotWrite(key);
|
||||
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
|
||||
mTable[idx] = newNode(key, val);
|
||||
mNEntries++;
|
||||
} else {
|
||||
mTable[idx]->val = val;
|
||||
}
|
||||
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
// undefined behavior if item is not presents
|
||||
tVal& get(KeyArg key) {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
return mTable[findSlotReadExisting(key)]->val;
|
||||
}
|
||||
|
||||
const tVal& get(KeyArg key) const {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
return mTable[findSlotReadExisting(key)]->val;
|
||||
}
|
||||
|
||||
[[nodiscard]] Idx presents(KeyArg key) const { return { findSlotRead(key) }; }
|
||||
|
||||
void remove(KeyArg key) {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
auto idx = findSlotReadExisting(key);
|
||||
|
||||
deleteNode(mTable[idx]);
|
||||
|
||||
markDeletedSlot(idx);
|
||||
|
||||
mNEntries--;
|
||||
if (halnf(mNEntries / mNSlots) < 1.f - maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
const tVal& getSlotVal(ualni slot) const {
|
||||
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
|
||||
return mTable[slot]->val;
|
||||
}
|
||||
|
||||
tVal& getSlotVal(ualni slot) {
|
||||
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
|
||||
return mTable[slot]->val;
|
||||
}
|
||||
|
||||
const tVal& getSlotVal(Idx slot) const {
|
||||
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
|
||||
return mTable[slot.idx]->val;
|
||||
}
|
||||
|
||||
tVal& getSlotVal(Idx slot) {
|
||||
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
|
||||
return mTable[slot.idx]->val;
|
||||
}
|
||||
|
||||
Map& operator=(const Map& in) {
|
||||
if (this == &in) {
|
||||
return *this;
|
||||
}
|
||||
removeAll();
|
||||
mNSlots = in.mNSlots;
|
||||
mTable = newTable(mNSlots);
|
||||
for (alni i = 0; i < mNSlots; i++) {
|
||||
if (in.mTable[i] && !isDeletedNode(in.mTable[i])) {
|
||||
put(in.mTable[i]->key, in.mTable[i]->val);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Map& in) const {
|
||||
if (this == &in) {
|
||||
return true;
|
||||
}
|
||||
if (in.mNEntries != mNEntries) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : in) {
|
||||
if (!presents(i->key) || get(i->key) != i->val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
for (ualni i = 0; i < mNSlots; i++) {
|
||||
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||
deleteNode(mTable[i]);
|
||||
}
|
||||
}
|
||||
deleteTable(mTable);
|
||||
mTable = newTable(tTableInitialSize);
|
||||
mNSlots = tTableInitialSize;
|
||||
mNEntries = 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] alni slotIdx(alni entry_idx_in) const {
|
||||
alni entry_idx = -1;
|
||||
for (alni slot_idx = 0; slot_idx < mNSlots; slot_idx++) {
|
||||
if (mTable[slot_idx]) {
|
||||
entry_idx++;
|
||||
}
|
||||
if (entry_idx == entry_idx_in) {
|
||||
return slot_idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Node* GetEntry(ualni idx) {
|
||||
auto slot = slotIdx(idx);
|
||||
DEBUG_ASSERT(slot != -1 && "Key error")
|
||||
return mTable[slot];
|
||||
}
|
||||
|
||||
const Node* GetEntry(ualni idx) const {
|
||||
auto slot = slotIdx(idx);
|
||||
DEBUG_ASSERT(slot != -1 && "Key error")
|
||||
return mTable[slot];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
class Iterator {
|
||||
const Map* map;
|
||||
Node* mIter;
|
||||
alni mSlot;
|
||||
alni mEntry;
|
||||
|
||||
friend Map;
|
||||
explicit Iterator(const Map* _map) {
|
||||
mSlot = -1;
|
||||
mEntry = -1;
|
||||
map = _map;
|
||||
this->operator++();
|
||||
}
|
||||
|
||||
public:
|
||||
Node* operator->() { return mIter; }
|
||||
const Node* operator->() const { return mIter; }
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
||||
bool operator!=(ualni idx) const { return mSlot != idx; }
|
||||
|
||||
void operator++() {
|
||||
mSlot++;
|
||||
while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != map->mNSlots)) {
|
||||
mSlot++;
|
||||
}
|
||||
if (mSlot != map->mNSlots) {
|
||||
mIter = map->mTable[mSlot];
|
||||
mEntry++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] Iterator begin() const {
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni end() const {
|
||||
return mNSlots;
|
||||
}
|
||||
|
||||
template<class Archiver>
|
||||
void archiveWrite(Archiver& ar) const {
|
||||
ar << mNEntries;
|
||||
for (auto item : *this) {
|
||||
ar << item->val;
|
||||
ar << item->key;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archiver>
|
||||
void archiveRead(Archiver& ar) {
|
||||
removeAll();
|
||||
decltype(mNSlots) len;
|
||||
ar >> len;
|
||||
for (auto i = len; i; i--) {
|
||||
auto node = newNodeNotConstructed();
|
||||
ar >> node->val;
|
||||
ar >> node->key;
|
||||
put(node);
|
||||
}
|
||||
}
|
||||
|
||||
~Map() {
|
||||
for (ualni i = 0; i < mNSlots; i++) {
|
||||
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||
deleteNode(mTable[i]);
|
||||
}
|
||||
}
|
||||
deleteTable(mTable);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename Key>
|
||||
ualni DefaultHashFunc(SelectValueOrReference<Key> key) {
|
||||
return hash(key);
|
||||
}
|
||||
|
||||
template <typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni (*tHashFunc)(SelectValueOrReference<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
|
||||
class Map {
|
||||
|
||||
enum {
|
||||
MAP_PERTURB_SHIFT = 5,
|
||||
MAP_MIN_SIZE = 4,
|
||||
MAP_MAX_LOAD_PERCENTAGE = 66,
|
||||
};
|
||||
|
||||
typedef SelectValueOrReference<tKey> KeyArg;
|
||||
typedef SelectValueOrReference<tVal> ValArg;
|
||||
|
||||
public:
|
||||
class Node {
|
||||
friend Map;
|
||||
Node(KeyArg aKey, ValArg aVal) :
|
||||
key(aKey),
|
||||
val(aVal) {}
|
||||
|
||||
public:
|
||||
tKey key;
|
||||
tVal val;
|
||||
};
|
||||
|
||||
struct Idx {
|
||||
alni idx = -1;
|
||||
[[nodiscard]] bool isValid() const { return bool(*this); }
|
||||
explicit operator bool() const { return idx != -1; }
|
||||
};
|
||||
|
||||
private:
|
||||
tAllocator mAlloc;
|
||||
Node** mTable = nullptr;
|
||||
ualni mNSlots = 0;
|
||||
ualni mNEntries = 0;
|
||||
|
||||
private:
|
||||
constexpr halnf maxLoadFactor() { return halnf(MAP_MAX_LOAD_PERCENTAGE) / 100.f; }
|
||||
|
||||
inline Node** newTable(const ualni len) { return new (mAlloc.allocate(sizeof(Node*) * len)) Node*[len](); }
|
||||
|
||||
inline Node* newNode(KeyArg key, ValArg val) { return new (mAlloc.allocate(sizeof(Node))) Node(key, val); }
|
||||
|
||||
inline Node* newNodeNotConstructed() { return (Node*) mAlloc.allocate(sizeof(Node)); }
|
||||
|
||||
inline void deleteTable(Node** table) { mAlloc.deallocate(table); }
|
||||
|
||||
inline void deleteNode(Node* p) {
|
||||
p->~Node();
|
||||
mAlloc.deallocate(p);
|
||||
}
|
||||
|
||||
void markDeletedSlot(ualni idx) const { mTable[idx] = (Node*) -1; }
|
||||
|
||||
static bool isDeletedNode(Node* node) { return node == (Node*) -1; }
|
||||
|
||||
void rehash() {
|
||||
alni nSlotsOld = mNSlots;
|
||||
Node** tableOld = mTable;
|
||||
|
||||
mNSlots = next2pow((uhalni) ((1.f / (maxLoadFactor())) * mNEntries + 1));
|
||||
mTable = newTable(mNSlots);
|
||||
mNEntries = 0;
|
||||
|
||||
for (alni i = 0; i < nSlotsOld; i++) {
|
||||
if (!tableOld[i] || isDeletedNode(tableOld[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
alni idx = findSlotWrite(tableOld[i]->key);
|
||||
mTable[idx] = tableOld[i];
|
||||
mNEntries++;
|
||||
}
|
||||
|
||||
deleteTable(tableOld);
|
||||
}
|
||||
|
||||
alni findSlotRead(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
alni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx])) {
|
||||
goto SKIP;
|
||||
}
|
||||
if (!mTable[idx]) {
|
||||
return -1;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
SKIP:
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
// compares keys only when collisions occur
|
||||
alni findSlotReadExisting(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
alni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx])) {
|
||||
goto SKIP;
|
||||
}
|
||||
if (!mTable[idx]) {
|
||||
return -1;
|
||||
}
|
||||
if (mTable[((5 * idx) + 1 + shift) & mask] == nullptr) {
|
||||
return idx;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
SKIP:
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
ualni findSlotWrite(KeyArg key) const {
|
||||
ualni const hashed_key = tHashFunc(key);
|
||||
ualni const mask = mNSlots - 1;
|
||||
ualni const shift = (hashed_key >> MAP_PERTURB_SHIFT) & ~1;
|
||||
ualni idx = hashed_key & mask;
|
||||
NEXT:
|
||||
if (isDeletedNode(mTable[idx]) || !mTable[idx]) {
|
||||
return idx;
|
||||
}
|
||||
if (mTable[idx]->key == key) {
|
||||
return idx;
|
||||
}
|
||||
idx = ((5 * idx) + 1 + shift) & mask;
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
void put(Node* node) {
|
||||
const ualni idx = findSlotWrite(node->key);
|
||||
|
||||
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
|
||||
mNEntries++;
|
||||
}
|
||||
|
||||
mTable[idx] = node;
|
||||
|
||||
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Map() {
|
||||
MODULE_SANITY_CHECK(gModuleContainers)
|
||||
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
|
||||
mTable = newTable(mNSlots);
|
||||
}
|
||||
|
||||
Map(const Map& in) { this->operator=(in); }
|
||||
|
||||
Node** buff() const { return mTable; }
|
||||
|
||||
[[nodiscard]] ualni size() const { return mNEntries; }
|
||||
|
||||
[[nodiscard]] ualni slotsSize() const { return mNEntries; }
|
||||
|
||||
[[nodiscard]] const tAllocator& getAllocator() const { return mAlloc; }
|
||||
|
||||
void put(KeyArg key, ValArg val) {
|
||||
const ualni idx = findSlotWrite(key);
|
||||
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
|
||||
mTable[idx] = newNode(key, val);
|
||||
mNEntries++;
|
||||
} else {
|
||||
mTable[idx]->val = val;
|
||||
}
|
||||
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
// undefined behavior if item is not presents
|
||||
tVal& get(KeyArg key) {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
return mTable[findSlotReadExisting(key)]->val;
|
||||
}
|
||||
|
||||
const tVal& get(KeyArg key) const {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
return mTable[findSlotReadExisting(key)]->val;
|
||||
}
|
||||
|
||||
[[nodiscard]] Idx presents(KeyArg key) const { return { findSlotRead(key) }; }
|
||||
|
||||
void remove(KeyArg key) {
|
||||
DEBUG_ASSERT(findSlotRead(key) != -1 && "Key Error")
|
||||
auto idx = findSlotReadExisting(key);
|
||||
|
||||
deleteNode(mTable[idx]);
|
||||
|
||||
markDeletedSlot(idx);
|
||||
|
||||
mNEntries--;
|
||||
if (halnf(mNEntries / mNSlots) < 1.f - maxLoadFactor()) {
|
||||
rehash();
|
||||
}
|
||||
}
|
||||
|
||||
const tVal& getSlotVal(ualni slot) const {
|
||||
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
|
||||
return mTable[slot]->val;
|
||||
}
|
||||
|
||||
tVal& getSlotVal(ualni slot) {
|
||||
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
|
||||
return mTable[slot]->val;
|
||||
}
|
||||
|
||||
const tVal& getSlotVal(Idx slot) const {
|
||||
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
|
||||
return mTable[slot.idx]->val;
|
||||
}
|
||||
|
||||
tVal& getSlotVal(Idx slot) {
|
||||
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
|
||||
return mTable[slot.idx]->val;
|
||||
}
|
||||
|
||||
Map& operator=(const Map& in) {
|
||||
if (this == &in) {
|
||||
return *this;
|
||||
}
|
||||
removeAll();
|
||||
mNSlots = in.mNSlots;
|
||||
mTable = newTable(mNSlots);
|
||||
for (alni i = 0; i < mNSlots; i++) {
|
||||
if (in.mTable[i] && !isDeletedNode(in.mTable[i])) {
|
||||
put(in.mTable[i]->key, in.mTable[i]->val);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Map& in) const {
|
||||
if (this == &in) {
|
||||
return true;
|
||||
}
|
||||
if (in.mNEntries != mNEntries) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : in) {
|
||||
if (!presents(i->key) || get(i->key) != i->val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
for (ualni i = 0; i < mNSlots; i++) {
|
||||
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||
deleteNode(mTable[i]);
|
||||
}
|
||||
}
|
||||
deleteTable(mTable);
|
||||
mTable = newTable(tTableInitialSize);
|
||||
mNSlots = tTableInitialSize;
|
||||
mNEntries = 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] alni slotIdx(alni entry_idx_in) const {
|
||||
alni entry_idx = -1;
|
||||
for (alni slot_idx = 0; slot_idx < mNSlots; slot_idx++) {
|
||||
if (mTable[slot_idx]) {
|
||||
entry_idx++;
|
||||
}
|
||||
if (entry_idx == entry_idx_in) {
|
||||
return slot_idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Node* GetEntry(ualni idx) {
|
||||
auto slot = slotIdx(idx);
|
||||
DEBUG_ASSERT(slot != -1 && "Key error")
|
||||
return mTable[slot];
|
||||
}
|
||||
|
||||
const Node* GetEntry(ualni idx) const {
|
||||
auto slot = slotIdx(idx);
|
||||
DEBUG_ASSERT(slot != -1 && "Key error")
|
||||
return mTable[slot];
|
||||
}
|
||||
|
||||
public:
|
||||
class Iterator {
|
||||
const Map* map;
|
||||
Node* mIter;
|
||||
alni mSlot;
|
||||
alni mEntry;
|
||||
|
||||
friend Map;
|
||||
explicit Iterator(const Map* _map) {
|
||||
mSlot = -1;
|
||||
mEntry = -1;
|
||||
map = _map;
|
||||
this->operator++();
|
||||
}
|
||||
|
||||
public:
|
||||
Node* operator->() { return mIter; }
|
||||
const Node* operator->() const { return mIter; }
|
||||
const Iterator& operator*() const { return *this; }
|
||||
|
||||
bool operator!=(ualni idx) const { return mSlot != idx; }
|
||||
|
||||
void operator++() {
|
||||
mSlot++;
|
||||
while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != map->mNSlots)) {
|
||||
mSlot++;
|
||||
}
|
||||
if (mSlot != map->mNSlots) {
|
||||
mIter = map->mTable[mSlot];
|
||||
mEntry++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] Iterator begin() const { return Iterator(this); }
|
||||
|
||||
[[nodiscard]] ualni end() const { return mNSlots; }
|
||||
|
||||
template <class Archiver>
|
||||
void archiveWrite(Archiver& ar) const {
|
||||
ar << mNEntries;
|
||||
for (auto item : *this) {
|
||||
ar << item->val;
|
||||
ar << item->key;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archiver>
|
||||
void archiveRead(Archiver& ar) {
|
||||
removeAll();
|
||||
decltype(mNSlots) len;
|
||||
ar >> len;
|
||||
for (auto i = len; i; i--) {
|
||||
auto node = newNodeNotConstructed();
|
||||
ar >> node->val;
|
||||
ar >> node->key;
|
||||
put(node);
|
||||
}
|
||||
}
|
||||
|
||||
~Map() {
|
||||
for (ualni i = 0; i < mNSlots; i++) {
|
||||
if (mTable[i] && !isDeletedNode(mTable[i])) {
|
||||
deleteNode(mTable[i]);
|
||||
}
|
||||
}
|
||||
deleteTable(mTable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,400 +1,375 @@
|
|||
#pragma once
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename NumericType>
|
||||
struct AvlNumericKey {
|
||||
|
||||
NumericType val;
|
||||
|
||||
AvlNumericKey() = default;
|
||||
AvlNumericKey(NumericType val) : val(val) {}
|
||||
|
||||
inline bool descentRight(AvlNumericKey in) const { return in.val > val; }
|
||||
inline bool descentLeft(AvlNumericKey in) const { return in.val < val; }
|
||||
inline bool exactNode(AvlNumericKey in) const { return in.val == val; }
|
||||
|
||||
inline AvlNumericKey getFindKey(/**/) const { return *this; }
|
||||
inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; }
|
||||
inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; }
|
||||
|
||||
inline void updateTreeCacheCallBack() {}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data, class Allocator = DefaultAllocator>
|
||||
class AvlTree {
|
||||
typedef SelectValueOrReference<Key> KeyArg;
|
||||
typedef SelectValueOrReference<Data> DataArg;
|
||||
|
||||
public:
|
||||
class Node {
|
||||
friend AvlTree;
|
||||
|
||||
private:
|
||||
Node(KeyArg aKey, DataArg aData) : key(aKey), data(aData) {}
|
||||
|
||||
public:
|
||||
Data data;
|
||||
Key key;
|
||||
|
||||
private:
|
||||
Node* mLeft = nullptr;
|
||||
Node* mRight = nullptr;
|
||||
Node* mParent = nullptr;
|
||||
ualni mHeight = 0;
|
||||
|
||||
private:
|
||||
inline bool descentRight(KeyArg aKey) const { return key.descentRight(aKey); }
|
||||
inline bool descentLeft(KeyArg aKey) const { return key.descentLeft(aKey); }
|
||||
inline bool exactNode(KeyArg aKey) const { return key.exactNode(aKey); }
|
||||
|
||||
inline KeyArg getFindKey(const Node* node = nullptr) const { return key.getFindKey(/*node*/); }
|
||||
inline KeyArg keyInRightSubtree(KeyArg aKey) const { return key.keyInRightSubtree(aKey); }
|
||||
inline KeyArg keyInLeftSubtree(KeyArg aKey) const { return key.keyInLeftSubtree(aKey); }
|
||||
|
||||
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(); }
|
||||
};
|
||||
|
||||
private:
|
||||
Node* mRoot = nullptr;
|
||||
ualni mSize = 0;
|
||||
Allocator mAlloc;
|
||||
|
||||
private:
|
||||
|
||||
inline void deleteNode(Node* node) {
|
||||
node->~Node();
|
||||
mAlloc.deallocate(node);
|
||||
}
|
||||
|
||||
inline Node* newNode(KeyArg key, DataArg data) {
|
||||
return new (mAlloc.allocate(sizeof(Node))) Node(key, data);
|
||||
}
|
||||
|
||||
inline void injectNodeInstead(Node* place, Node* inject) {
|
||||
// TODO : swap instead of copy
|
||||
place->data = inject->data;
|
||||
place->key = inject->key;
|
||||
}
|
||||
|
||||
inline alni getNodeHeight(const Node* node) const {
|
||||
return node ? node->mHeight : -1;
|
||||
}
|
||||
|
||||
// returns new head
|
||||
Node* rotateLeft(Node* pivot) {
|
||||
DEBUG_ASSERT(pivot);
|
||||
|
||||
Node* const head = pivot;
|
||||
Node* const right = pivot->mRight;
|
||||
Node* const right_left = right->mLeft;
|
||||
Node* const parent = pivot->mParent;
|
||||
|
||||
// parents
|
||||
if (right_left) right_left->mParent = head;
|
||||
head->mParent = right;
|
||||
right->mParent = parent;
|
||||
|
||||
// children
|
||||
head->mRight = right_left;
|
||||
right->mLeft = head;
|
||||
|
||||
// heights
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
|
||||
right->mHeight = 1 + max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight));
|
||||
|
||||
// cache
|
||||
head->updateTreeCacheCallBack();
|
||||
right->updateTreeCacheCallBack();
|
||||
|
||||
return right;
|
||||
}
|
||||
|
||||
Node* rotateRight(Node* pivot) {
|
||||
DEBUG_ASSERT(pivot);
|
||||
|
||||
Node* const head = pivot;
|
||||
Node* const left = pivot->mLeft;
|
||||
Node* const left_right = left->mRight;
|
||||
Node* const parent = pivot->mParent;
|
||||
|
||||
// parents
|
||||
if (left_right) left_right->mParent = head;
|
||||
head->mParent = left;
|
||||
left->mParent = parent;
|
||||
|
||||
// children
|
||||
head->mLeft = left_right;
|
||||
left->mRight = head;
|
||||
|
||||
// heights
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
|
||||
left->mHeight = 1 + max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight));
|
||||
|
||||
// cache
|
||||
head->updateTreeCacheCallBack();
|
||||
left->updateTreeCacheCallBack();
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// recursively returns valid isLeft or isRight child or root
|
||||
Node* insertUtil(Node* head, KeyArg key, DataArg data) {
|
||||
|
||||
Node* insertedNode;
|
||||
|
||||
if (head == nullptr) {
|
||||
mSize++;
|
||||
Node* out = newNode(key, data);
|
||||
out->updateTreeCacheCallBack();
|
||||
return out;
|
||||
}
|
||||
else if (head->exactNode(key)) {
|
||||
return head;
|
||||
}
|
||||
else if (head->descentRight(key)) {
|
||||
insertedNode = insertUtil(head->mRight, head->keyInRightSubtree(key), data);
|
||||
head->mRight = insertedNode;
|
||||
insertedNode->mParent = head;
|
||||
}
|
||||
else {
|
||||
insertedNode = insertUtil(head->mLeft, head->keyInLeftSubtree(key), data);
|
||||
head->mLeft = insertedNode;
|
||||
insertedNode->mParent = head;
|
||||
}
|
||||
|
||||
// update height
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
|
||||
|
||||
alni balance = alni(getNodeHeight(head->mRight) - getNodeHeight(head->mLeft));
|
||||
|
||||
if (balance > 1) {
|
||||
if (head->mRight->descentRight(head->keyInRightSubtree(key))) {
|
||||
return rotateLeft(head);
|
||||
}
|
||||
else {
|
||||
head->mRight = rotateRight(head->mRight);
|
||||
return rotateLeft(head);
|
||||
}
|
||||
}
|
||||
else if (balance < -1) {
|
||||
if (head->mLeft->descentLeft(head->keyInLeftSubtree(key))) {
|
||||
return rotateRight(head);
|
||||
}
|
||||
else {
|
||||
head->mLeft = rotateLeft(head->mLeft);
|
||||
return rotateRight(head);
|
||||
}
|
||||
}
|
||||
|
||||
head->updateTreeCacheCallBack();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* removeUtil(Node* head, KeyArg key) {
|
||||
if (head == nullptr) return head;
|
||||
|
||||
if (head->exactNode(key)) {
|
||||
if (head->mRight && head->mLeft) {
|
||||
Node* min = minNode(head->mRight);
|
||||
auto const& newKey = min->getFindKey(head->mRight);
|
||||
injectNodeInstead(head, min);
|
||||
head->mRight = removeUtil(head->mRight, newKey);
|
||||
}
|
||||
else if (head->mRight) {
|
||||
injectNodeInstead(head, head->mRight);
|
||||
deleteNode(head->mRight);
|
||||
head->mRight = nullptr;
|
||||
mSize--;
|
||||
}
|
||||
else if (head->mLeft) {
|
||||
injectNodeInstead(head, head->mLeft);
|
||||
deleteNode(head->mLeft);
|
||||
head->mLeft = nullptr;
|
||||
mSize--;
|
||||
}
|
||||
else {
|
||||
deleteNode(head);
|
||||
mSize--;
|
||||
head = nullptr;
|
||||
}
|
||||
}
|
||||
else if (head->descentRight(key)) {
|
||||
head->mRight = removeUtil(head->mRight, head->keyInRightSubtree(key));
|
||||
}
|
||||
else if (head->descentLeft(key)) {
|
||||
head->mLeft = removeUtil(head->mLeft, head->keyInLeftSubtree(key));
|
||||
}
|
||||
|
||||
if (head == nullptr) return head;
|
||||
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
|
||||
alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
||||
|
||||
if (balance < -1) {
|
||||
if (getNodeHeight(head->mLeft->mLeft) >= getNodeHeight(head->mLeft->mRight)) {
|
||||
return rotateRight(head);
|
||||
}
|
||||
else {
|
||||
head->mLeft = rotateLeft(head->mLeft);
|
||||
return rotateRight(head);
|
||||
}
|
||||
}
|
||||
else if (balance > 1) {
|
||||
if (getNodeHeight(head->mRight->mRight) >= getNodeHeight(head->mRight->mLeft)) {
|
||||
return rotateLeft(head);
|
||||
}
|
||||
else {
|
||||
head->mRight = rotateRight(head->mRight);
|
||||
return rotateLeft(head);
|
||||
}
|
||||
}
|
||||
|
||||
head->updateTreeCacheCallBack();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
AvlTree() {
|
||||
MODULE_SANITY_CHECK(gModuleContainers)
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni size() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
Node* head() const {
|
||||
return this->mRoot;
|
||||
}
|
||||
|
||||
void insert(KeyArg key, DataArg data) {
|
||||
mRoot = insertUtil(mRoot, key, data);
|
||||
mRoot->mParent = nullptr;
|
||||
}
|
||||
|
||||
void remove(KeyArg key) {
|
||||
mRoot = removeUtil(mRoot, key);
|
||||
if (mRoot) mRoot->mParent = nullptr;
|
||||
}
|
||||
|
||||
Node* maxNode(Node* head) const {
|
||||
if (!head) return nullptr;
|
||||
while (head->mRight != nullptr) {
|
||||
head = head->mRight;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* minNode(Node* head) const {
|
||||
if (!head) return nullptr;
|
||||
while (head->mLeft != nullptr) {
|
||||
head = head->mLeft;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* find(KeyArg key) const {
|
||||
Node* iter = mRoot;
|
||||
while (true) {
|
||||
if (!iter) return nullptr;
|
||||
if (iter->exactNode(key)) return iter;
|
||||
if (iter->descentLeft(key)) {
|
||||
key = iter->keyInLeftSubtree(key);
|
||||
iter = iter->mLeft;
|
||||
} else {
|
||||
key = iter->keyInRightSubtree(key);
|
||||
iter = iter->mRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node* findLessOrEq(KeyArg key) const {
|
||||
Node* iter = mRoot;
|
||||
while (true) {
|
||||
if (!iter) return nullptr;
|
||||
if (iter->exactNode(key)) return iter;
|
||||
if (iter->descentLeft(key)) {
|
||||
if (iter->mLeft) {
|
||||
key = iter->keyInLeftSubtree(key);
|
||||
iter = iter->mLeft;
|
||||
} else {
|
||||
return iter;
|
||||
}
|
||||
} else {
|
||||
if (iter->mRight) {
|
||||
key = iter->keyInRightSubtree(key);
|
||||
iter = iter->mRight;
|
||||
} else {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns first invalid node
|
||||
const Node* findInvalidNode(const Node* head) const {
|
||||
if (head == nullptr) return nullptr;
|
||||
|
||||
if (head->mLeft) {
|
||||
// TODO: incomplete test
|
||||
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
|
||||
if (head->mLeft->mParent != head) return head;
|
||||
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
if (head->mRight) {
|
||||
if (!head->descentRight(head->mRight->getFindKey(head))) return head;
|
||||
if (head->mRight->mParent != head) return head;
|
||||
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
if (head->mLeft && head->mRight) {
|
||||
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
||||
|
||||
if (balance > 1 || balance < -1) return head;
|
||||
|
||||
const Node* ret = findInvalidNode(head->mRight);
|
||||
|
||||
if (ret) return ret;
|
||||
|
||||
return findInvalidNode(head->mLeft);
|
||||
}
|
||||
|
||||
bool isValid() { return findInvalidNode(head()) == nullptr; }
|
||||
|
||||
template<typename tFunctor>
|
||||
void traverse(Node* node, bool after, tFunctor functor) {
|
||||
if (!after) functor(node);
|
||||
if (node->mLeft) traverse(node->mLeft, after, functor);
|
||||
if (node->mRight) traverse(node->mRight, after, functor);
|
||||
if (after) functor(node);
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
traverse(mRoot, true, [this](Node* node) {
|
||||
deleteNode(node);
|
||||
});
|
||||
mRoot = nullptr;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
template<class tArchiver>
|
||||
void archiveWrite(tArchiver& file) const {
|
||||
FAIL("not implemented")
|
||||
}
|
||||
|
||||
template<class tArchiver>
|
||||
void archiveRead(tArchiver&) {
|
||||
FAIL("not implemented")
|
||||
}
|
||||
};
|
||||
#pragma once
|
||||
|
||||
#include "ContainersCommon.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
template <typename NumericType>
|
||||
struct AvlNumericKey {
|
||||
|
||||
NumericType val;
|
||||
|
||||
AvlNumericKey() = default;
|
||||
AvlNumericKey(NumericType val) :
|
||||
val(val) {}
|
||||
|
||||
inline bool descentRight(AvlNumericKey in) const { return in.val > val; }
|
||||
inline bool descentLeft(AvlNumericKey in) const { return in.val < val; }
|
||||
inline bool exactNode(AvlNumericKey in) const { return in.val == val; }
|
||||
|
||||
inline AvlNumericKey getFindKey(/**/) const { return *this; }
|
||||
inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; }
|
||||
inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; }
|
||||
|
||||
inline void updateTreeCacheCallBack() {}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data, class Allocator = DefaultAllocator>
|
||||
class AvlTree {
|
||||
typedef SelectValueOrReference<Key> KeyArg;
|
||||
typedef SelectValueOrReference<Data> DataArg;
|
||||
|
||||
public:
|
||||
class Node {
|
||||
friend AvlTree;
|
||||
|
||||
private:
|
||||
Node(KeyArg aKey, DataArg aData) :
|
||||
key(aKey),
|
||||
data(aData) {}
|
||||
|
||||
public:
|
||||
Data data;
|
||||
Key key;
|
||||
|
||||
private:
|
||||
Node* mLeft = nullptr;
|
||||
Node* mRight = nullptr;
|
||||
Node* mParent = nullptr;
|
||||
ualni mHeight = 0;
|
||||
|
||||
private:
|
||||
inline bool descentRight(KeyArg aKey) const { return key.descentRight(aKey); }
|
||||
inline bool descentLeft(KeyArg aKey) const { return key.descentLeft(aKey); }
|
||||
inline bool exactNode(KeyArg aKey) const { return key.exactNode(aKey); }
|
||||
|
||||
inline KeyArg getFindKey(const Node* node = nullptr) const { return key.getFindKey(/*node*/); }
|
||||
inline KeyArg keyInRightSubtree(KeyArg aKey) const { return key.keyInRightSubtree(aKey); }
|
||||
inline KeyArg keyInLeftSubtree(KeyArg aKey) const { return key.keyInLeftSubtree(aKey); }
|
||||
|
||||
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(); }
|
||||
};
|
||||
|
||||
private:
|
||||
Node* mRoot = nullptr;
|
||||
ualni mSize = 0;
|
||||
Allocator mAlloc;
|
||||
|
||||
private:
|
||||
inline void deleteNode(Node* node) {
|
||||
node->~Node();
|
||||
mAlloc.deallocate(node);
|
||||
}
|
||||
|
||||
inline Node* newNode(KeyArg key, DataArg data) { return new (mAlloc.allocate(sizeof(Node))) Node(key, data); }
|
||||
|
||||
inline void injectNodeInstead(Node* place, Node* inject) {
|
||||
// TODO : swap instead of copy
|
||||
place->data = inject->data;
|
||||
place->key = inject->key;
|
||||
}
|
||||
|
||||
inline alni getNodeHeight(const Node* node) const { return node ? node->mHeight : -1; }
|
||||
|
||||
// returns new head
|
||||
Node* rotateLeft(Node* pivot) {
|
||||
DEBUG_ASSERT(pivot);
|
||||
|
||||
Node* const head = pivot;
|
||||
Node* const right = pivot->mRight;
|
||||
Node* const right_left = right->mLeft;
|
||||
Node* const parent = pivot->mParent;
|
||||
|
||||
// parents
|
||||
if (right_left) right_left->mParent = head;
|
||||
head->mParent = right;
|
||||
right->mParent = parent;
|
||||
|
||||
// children
|
||||
head->mRight = right_left;
|
||||
right->mLeft = head;
|
||||
|
||||
// heights
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
|
||||
right->mHeight = 1 + max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight));
|
||||
|
||||
// cache
|
||||
head->updateTreeCacheCallBack();
|
||||
right->updateTreeCacheCallBack();
|
||||
|
||||
return right;
|
||||
}
|
||||
|
||||
Node* rotateRight(Node* pivot) {
|
||||
DEBUG_ASSERT(pivot);
|
||||
|
||||
Node* const head = pivot;
|
||||
Node* const left = pivot->mLeft;
|
||||
Node* const left_right = left->mRight;
|
||||
Node* const parent = pivot->mParent;
|
||||
|
||||
// parents
|
||||
if (left_right) left_right->mParent = head;
|
||||
head->mParent = left;
|
||||
left->mParent = parent;
|
||||
|
||||
// children
|
||||
head->mLeft = left_right;
|
||||
left->mRight = head;
|
||||
|
||||
// heights
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
|
||||
left->mHeight = 1 + max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight));
|
||||
|
||||
// cache
|
||||
head->updateTreeCacheCallBack();
|
||||
left->updateTreeCacheCallBack();
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
// recursively returns valid isLeft or isRight child or root
|
||||
Node* insertUtil(Node* head, KeyArg key, DataArg data) {
|
||||
|
||||
Node* insertedNode;
|
||||
|
||||
if (head == nullptr) {
|
||||
mSize++;
|
||||
Node* out = newNode(key, data);
|
||||
out->updateTreeCacheCallBack();
|
||||
return out;
|
||||
} else if (head->exactNode(key)) {
|
||||
return head;
|
||||
} else if (head->descentRight(key)) {
|
||||
insertedNode = insertUtil(head->mRight, head->keyInRightSubtree(key), data);
|
||||
head->mRight = insertedNode;
|
||||
insertedNode->mParent = head;
|
||||
} else {
|
||||
insertedNode = insertUtil(head->mLeft, head->keyInLeftSubtree(key), data);
|
||||
head->mLeft = insertedNode;
|
||||
insertedNode->mParent = head;
|
||||
}
|
||||
|
||||
// update height
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
|
||||
|
||||
alni balance = alni(getNodeHeight(head->mRight) - getNodeHeight(head->mLeft));
|
||||
|
||||
if (balance > 1) {
|
||||
if (head->mRight->descentRight(head->keyInRightSubtree(key))) {
|
||||
return rotateLeft(head);
|
||||
} else {
|
||||
head->mRight = rotateRight(head->mRight);
|
||||
return rotateLeft(head);
|
||||
}
|
||||
} else if (balance < -1) {
|
||||
if (head->mLeft->descentLeft(head->keyInLeftSubtree(key))) {
|
||||
return rotateRight(head);
|
||||
} else {
|
||||
head->mLeft = rotateLeft(head->mLeft);
|
||||
return rotateRight(head);
|
||||
}
|
||||
}
|
||||
|
||||
head->updateTreeCacheCallBack();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* removeUtil(Node* head, KeyArg key) {
|
||||
if (head == nullptr) return head;
|
||||
|
||||
if (head->exactNode(key)) {
|
||||
if (head->mRight && head->mLeft) {
|
||||
Node* min = minNode(head->mRight);
|
||||
auto const& newKey = min->getFindKey(head->mRight);
|
||||
injectNodeInstead(head, min);
|
||||
head->mRight = removeUtil(head->mRight, newKey);
|
||||
} else if (head->mRight) {
|
||||
injectNodeInstead(head, head->mRight);
|
||||
deleteNode(head->mRight);
|
||||
head->mRight = nullptr;
|
||||
mSize--;
|
||||
} else if (head->mLeft) {
|
||||
injectNodeInstead(head, head->mLeft);
|
||||
deleteNode(head->mLeft);
|
||||
head->mLeft = nullptr;
|
||||
mSize--;
|
||||
} else {
|
||||
deleteNode(head);
|
||||
mSize--;
|
||||
head = nullptr;
|
||||
}
|
||||
} else if (head->descentRight(key)) {
|
||||
head->mRight = removeUtil(head->mRight, head->keyInRightSubtree(key));
|
||||
} else if (head->descentLeft(key)) {
|
||||
head->mLeft = removeUtil(head->mLeft, head->keyInLeftSubtree(key));
|
||||
}
|
||||
|
||||
if (head == nullptr) return head;
|
||||
|
||||
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
|
||||
alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
||||
|
||||
if (balance < -1) {
|
||||
if (getNodeHeight(head->mLeft->mLeft) >= getNodeHeight(head->mLeft->mRight)) {
|
||||
return rotateRight(head);
|
||||
} else {
|
||||
head->mLeft = rotateLeft(head->mLeft);
|
||||
return rotateRight(head);
|
||||
}
|
||||
} else if (balance > 1) {
|
||||
if (getNodeHeight(head->mRight->mRight) >= getNodeHeight(head->mRight->mLeft)) {
|
||||
return rotateLeft(head);
|
||||
} else {
|
||||
head->mRight = rotateRight(head->mRight);
|
||||
return rotateLeft(head);
|
||||
}
|
||||
}
|
||||
|
||||
head->updateTreeCacheCallBack();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
public:
|
||||
AvlTree() { MODULE_SANITY_CHECK(gModuleContainers) }
|
||||
|
||||
[[nodiscard]] ualni size() const { return mSize; }
|
||||
|
||||
Node* head() const { return this->mRoot; }
|
||||
|
||||
void insert(KeyArg key, DataArg data) {
|
||||
mRoot = insertUtil(mRoot, key, data);
|
||||
mRoot->mParent = nullptr;
|
||||
}
|
||||
|
||||
void remove(KeyArg key) {
|
||||
mRoot = removeUtil(mRoot, key);
|
||||
if (mRoot) mRoot->mParent = nullptr;
|
||||
}
|
||||
|
||||
Node* maxNode(Node* head) const {
|
||||
if (!head) return nullptr;
|
||||
while (head->mRight != nullptr) {
|
||||
head = head->mRight;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* minNode(Node* head) const {
|
||||
if (!head) return nullptr;
|
||||
while (head->mLeft != nullptr) {
|
||||
head = head->mLeft;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
Node* find(KeyArg key) const {
|
||||
Node* iter = mRoot;
|
||||
while (true) {
|
||||
if (!iter) return nullptr;
|
||||
if (iter->exactNode(key)) return iter;
|
||||
if (iter->descentLeft(key)) {
|
||||
key = iter->keyInLeftSubtree(key);
|
||||
iter = iter->mLeft;
|
||||
} else {
|
||||
key = iter->keyInRightSubtree(key);
|
||||
iter = iter->mRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node* findLessOrEq(KeyArg key) const {
|
||||
Node* iter = mRoot;
|
||||
while (true) {
|
||||
if (!iter) return nullptr;
|
||||
if (iter->exactNode(key)) return iter;
|
||||
if (iter->descentLeft(key)) {
|
||||
if (iter->mLeft) {
|
||||
key = iter->keyInLeftSubtree(key);
|
||||
iter = iter->mLeft;
|
||||
} else {
|
||||
return iter;
|
||||
}
|
||||
} else {
|
||||
if (iter->mRight) {
|
||||
key = iter->keyInRightSubtree(key);
|
||||
iter = iter->mRight;
|
||||
} else {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns first invalid node
|
||||
const Node* findInvalidNode(const Node* head) const {
|
||||
if (head == nullptr) return nullptr;
|
||||
|
||||
if (head->mLeft) {
|
||||
// TODO: incomplete test
|
||||
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
|
||||
if (head->mLeft->mParent != head) return head;
|
||||
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
if (head->mRight) {
|
||||
if (!head->descentRight(head->mRight->getFindKey(head))) return head;
|
||||
if (head->mRight->mParent != head) return head;
|
||||
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
if (head->mLeft && head->mRight) {
|
||||
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
|
||||
}
|
||||
|
||||
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
|
||||
|
||||
if (balance > 1 || balance < -1) return head;
|
||||
|
||||
const Node* ret = findInvalidNode(head->mRight);
|
||||
|
||||
if (ret) return ret;
|
||||
|
||||
return findInvalidNode(head->mLeft);
|
||||
}
|
||||
|
||||
bool isValid() { return findInvalidNode(head()) == nullptr; }
|
||||
|
||||
template <typename tFunctor>
|
||||
void traverse(Node* node, bool after, tFunctor functor) {
|
||||
if (!after) functor(node);
|
||||
if (node->mLeft) traverse(node->mLeft, after, functor);
|
||||
if (node->mRight) traverse(node->mRight, after, functor);
|
||||
if (after) functor(node);
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
traverse(mRoot, true, [this](Node* node) { deleteNode(node); });
|
||||
mRoot = nullptr;
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class tArchiver>
|
||||
void archiveWrite(tArchiver& file) const {
|
||||
FAIL("not implemented")
|
||||
}
|
||||
|
||||
template <class tArchiver>
|
||||
void archiveRead(tArchiver&) {
|
||||
FAIL("not implemented")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Buffer2D.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
|
|
@ -11,8 +11,8 @@ const ualni size = 1000;
|
|||
TEST_DEF_STATIC(Simple1) {
|
||||
Buffer2D<int, HeapAlloc> buff;
|
||||
buff.reserve({ 4, 4 });
|
||||
buff.set( { 2, 2 }, 5);
|
||||
TEST(buff.get( { 2, 2 } ) == 5);
|
||||
buff.set({ 2, 2 }, 5);
|
||||
TEST(buff.get({ 2, 2 }) == 5);
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Simple2) {
|
||||
|
|
@ -20,6 +20,6 @@ TEST_DEF_STATIC(Simple2) {
|
|||
}
|
||||
|
||||
TEST_DEF(Buffer2d) {
|
||||
testSimple1();
|
||||
testSimple2();
|
||||
testSimple1();
|
||||
testSimple2();
|
||||
}
|
||||
|
|
@ -1,34 +1,37 @@
|
|||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
const ualni size = 1000;
|
||||
|
||||
TEST_DEF_STATIC(Simple1) {
|
||||
Buffer<TestClass, HeapAlloc> buff;
|
||||
TEST(buff.size() == 0);
|
||||
for (auto i : Range(size * 10)) {
|
||||
buff.append(TestClass(i));
|
||||
}
|
||||
TEST(buff.size() == size * 10);
|
||||
while (buff.size()) buff.pop();
|
||||
TEST(buff.size() == 0);
|
||||
Buffer<TestClass, HeapAlloc> buff;
|
||||
TEST(buff.size() == 0);
|
||||
for (auto i : Range(size * 10)) {
|
||||
buff.append(TestClass(i));
|
||||
}
|
||||
TEST(buff.size() == size * 10);
|
||||
while (buff.size())
|
||||
buff.pop();
|
||||
TEST(buff.size() == 0);
|
||||
}
|
||||
|
||||
TEST_DEF_STATIC(Simple2) {
|
||||
Buffer<TestClass, HeapAlloc> buff(size);
|
||||
TEST(buff.size() == 0);
|
||||
for (auto i : Range(size * 10)) buff.append(TestClass(i));
|
||||
TEST(buff.size() == size * 10);
|
||||
while (buff.size()) buff.pop();
|
||||
TEST(buff.size() == 0);
|
||||
Buffer<TestClass, HeapAlloc> buff(size);
|
||||
TEST(buff.size() == 0);
|
||||
for (auto i : Range(size * 10))
|
||||
buff.append(TestClass(i));
|
||||
TEST(buff.size() == size * 10);
|
||||
while (buff.size())
|
||||
buff.pop();
|
||||
TEST(buff.size() == 0);
|
||||
}
|
||||
|
||||
TEST_DEF(Buffer) {
|
||||
testSimple1();
|
||||
testSimple2();
|
||||
testSimple1();
|
||||
testSimple2();
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Archiver.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "Tests.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Map.hpp"
|
||||
#include "Archiver.hpp"
|
||||
#include "Map.hpp"
|
||||
#include "Testing.hpp"
|
||||
#include "Tests.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
|
||||
#include "Tests.hpp"
|
||||
#include "Testing.hpp"
|
||||
|
||||
static bool init(const tp::ModuleManifest* self) {
|
||||
tp::gTesting.setRootName(self->getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
|
||||
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
testList();
|
||||
testMap();
|
||||
testAvl();
|
||||
testBuffer();
|
||||
testBuffer2d();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
||||
#include "Tests.hpp"
|
||||
#include "Testing.hpp"
|
||||
|
||||
static bool init(const tp::ModuleManifest* self) {
|
||||
tp::gTesting.setRootName(self->getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
|
||||
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
|
||||
|
||||
if (!testModule.initialize()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
testList();
|
||||
testMap();
|
||||
testAvl();
|
||||
testBuffer();
|
||||
testBuffer2d();
|
||||
|
||||
testModule.deinitialize();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "Allocators.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
class TestClass {
|
||||
tp::ualni val2 = 0;
|
||||
tp::ualni val1;
|
||||
|
||||
public:
|
||||
explicit TestClass(tp::ualni val) :
|
||||
val1(val) {}
|
||||
|
||||
explicit TestClass(tp::ualni val) : val1(val) {}
|
||||
|
||||
template<class Saver>
|
||||
template <class Saver>
|
||||
void write(Saver& file) const {
|
||||
file.write(val1);
|
||||
}
|
||||
|
||||
template<class Loader>
|
||||
template <class Loader>
|
||||
void read(Loader& file) {
|
||||
file.read(val1);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const TestClass& in) const {
|
||||
return in.val1 == val1;
|
||||
}
|
||||
[[nodiscard]] bool operator==(const TestClass& in) const { return in.val1 == val1; }
|
||||
|
||||
[[nodiscard]] tp::ualni getVal() const { return val1; }
|
||||
void setVal(tp::ualni val) { val1 = val; }
|
||||
};
|
||||
|
||||
|
||||
void testList();
|
||||
void testMap();
|
||||
void testAvl();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#include "NewPlacement.hpp"
|
||||
|
||||
#include "Testing.hpp"
|
||||
#include "Tests.hpp"
|
||||
#include "Tree.hpp"
|
||||
#include "Testing.hpp"
|
||||
|
||||
using namespace tp;
|
||||
|
||||
|
|
@ -29,7 +29,8 @@ TEST_DEF_STATIC(Persistance) {
|
|||
const auto size = 1000;
|
||||
|
||||
struct Item {
|
||||
Item() : data(0) {}
|
||||
Item() :
|
||||
data(0) {}
|
||||
bool presents = false;
|
||||
TestClass data;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue