#pragma once #include "ContainersCommon.hpp" namespace tp { template inline ualni BufferResizeScaling(const ualni size) { return size * tScale; } template inline ualni BufferResizeScalingDown(const ualni size) { return size / tScale; } template inline ualni BufferResizeAddition(const ualni size) { return size + tAddition; } template inline ualni BufferResizeAdditionDown(const ualni size) { return size - tAddition; } template class ConstSizeBuffer { typedef SelectValueOrReference Arg; private: tType mBuff[tSize]; ualni mLoad = 0; public: ConstSizeBuffer() = default; ~ConstSizeBuffer() { for (auto i = 0; i < mLoad; i++) { mBuff[i].~tType(); } } public: [[nodiscard]] ualni size() const { return mLoad; } [[nodiscard]] ualni getBuffSize() const { return tSize; } tType& first() { DEBUG_ASSERT(mLoad) return *mBuff; } const tType& first() const { DEBUG_ASSERT(mLoad) return *mBuff; } tType& last() { DEBUG_ASSERT(mLoad) return mBuff[mLoad - 1]; } const tType& last() const { DEBUG_ASSERT(mLoad) return mBuff[mLoad - 1]; } tType& operator[](ualni aIdx) { DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad) return mBuff[aIdx]; } const tType& operator[](ualni aIdx) const { DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad) return mBuff[aIdx]; } void append(Arg data) { ASSERT(mLoad != tSize) new (&mBuff[mLoad]) tType(data); mLoad++; } void pop() { DEBUG_ASSERT(mLoad) mBuff[mLoad].~tType(); mLoad--; } ConstSizeBuffer& operator=(const tp::InitialierList& init) { for (auto arg : init) { append(arg); } return *this; } void clear() { this->~ConstSizeBuffer(); new (this) ConstSizeBuffer(); } 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::isPointer, IteratorPointer, IteratorReference>::Result { public: explicit Iterator(tType* iter) { this->mIter = iter; } const Iterator& operator*() const { return *this; } Iterator& operator++() { this->mIter++; return *this; } 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); } public: template void archiveWrite(tArchiver& ar) const { ar << mLoad; for (auto item : *this) { ar << item.data(); } } template void archiveRead(tArchiver& ar) { clear(); ar >> mLoad; for (auto i = 0; i < mLoad; i++) { ar >> mBuff[i]; } } }; template , ualni(tResizePolicyDown)(ualni) = BufferResizeScalingDown<2>, ualni tMinSize = 4> class Buffer { typedef SelectValueOrReference Arg; private: tType* mBuff; tAllocator mAllocator; ualni mSize; ualni mLoad; public: Buffer() : mSize(tMinSize), mLoad(0) { mBuff = (tType*) mAllocator.allocate(sizeof(tType) * tMinSize); } 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) { mBuff = (tType*) mAllocator.allocate(sizeof(tType) * mSize); for (ualni i = 0; i < mLoad; i++) { new (&mBuff[i]) tType(in.mBuff[i]); } } void clear() { this->~Buffer(); new (this) Buffer(); } Buffer& operator=(const Buffer& in) { if (this == &in) { return *this; } this->~Buffer(); new (this) Buffer(in); return *this; } ~Buffer() { for (ualni i = 0; i < mLoad; i++) { mBuff[i].~tType(); } mAllocator.deallocate(mBuff); } public: [[nodiscard]] ualni size() const { return mLoad; } [[nodiscard]] ualni getBuffSize() const { return mSize; } [[nodiscard]] const tType* getBuff() const { return mBuff; } [[nodiscard]] tType* getBuff() { return mBuff; } tType& first() { DEBUG_ASSERT(mLoad) return *mBuff; } const tType& first() const { DEBUG_ASSERT(mLoad) return *mBuff; } tType& last() { DEBUG_ASSERT(mLoad) return mBuff[mLoad - 1]; } const tType& last() const { DEBUG_ASSERT(mLoad) return mBuff[mLoad - 1]; } tType& operator[](ualni idx) { DEBUG_ASSERT(idx < mLoad && idx >= 0) return mBuff[idx]; } const tType& operator[](ualni idx) const { DEBUG_ASSERT(idx < mLoad && idx >= 0) return mBuff[idx]; } public: bool operator==(const Buffer& in) const { 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; } } return true; } public: Buffer& operator=(const tp::InitialierList& init) { // TODO : optimize for (auto arg : init) { append(arg); } return *this; } void append(Arg data) { 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 pop() { DEBUG_ASSERT(mLoad) mBuff[mLoad].~tType(); mLoad--; ualni prevSize = tResizePolicyDown(mSize); DEBUG_ASSERT(prevSize < mSize) if (prevSize > mLoad) { resizeBuffer(prevSize); } } void reserve(ualni aSize) { 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(); } } 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::isPointer, IteratorPointer, IteratorReference>::Result { public: explicit Iterator(tType* iter) { this->mIter = iter; } const Iterator& operator*() const { return *this; } tType& data() { return *this->mIter; } Iterator& operator++() { this->mIter++; return *this; } 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); } public: template void archiveWrite(tArchiver& ar) const { ar << mLoad; for (auto item : *this) { ar << item.data(); } } template void archiveRead(tArchiver& ar) { clear(); decltype(mLoad) len; ar >> len; for (auto i = len; i; i--) { // TODO : optimize if (mLoad == mSize) { resizeBuffer(tResizePolicy(mSize)); } ar >> mBuff[mLoad]; mLoad++; } } 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 void generatePermutations(const Buffer>& in, Buffer>& out) { typedef long long Idx; // sanity check 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); } auto dub = Idx(1); for (auto power = (Idx) in.size() - 1; power >= 0; power--) { auto& vec = in[power]; long long i = 0; while (i < len) { for (auto val : vec) { for (auto j = 0; j < dub; j++) { out[power][i] = val; i++; } } } dub *= (Idx) vec.size(); } } }