Created
May 7, 2014 07:57
-
-
Save vittorioromeo/dd7f64cac29ac18e2241 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SSVUtils/SSVUtils.hpp> | |
using Idx = std::size_t; | |
using Ctr = int; | |
template<typename> class Manager; | |
template<typename> class Handle; | |
template<typename T> class Atom | |
{ | |
template<typename> friend class Manager; | |
template<typename> friend class Handle; | |
private: | |
Idx ctrlIdx; | |
bool alive{false}; | |
T impl; | |
public: | |
inline Atom(Idx mCtrlIdx) : ctrlIdx{mCtrlIdx} { } | |
}; | |
class Controller | |
{ | |
template<typename> friend class Manager; | |
template<typename> friend class Handle; | |
private: | |
Idx idx; | |
Ctr ctr; | |
public: | |
inline Controller(Idx mIdx) noexcept : idx{mIdx} { } | |
}; | |
template<typename T> class Handle | |
{ | |
template<typename> friend class Manager; | |
private: | |
Manager<T>& manager; | |
Idx ctrlIdx; | |
Ctr ctr; | |
inline Handle(Manager<T>& mManager, Idx mCtrlIdx, Ctr mCtr) noexcept | |
: manager(mManager), ctrlIdx{mCtrlIdx}, ctr{mCtr} { } | |
Atom<T>& getAtom(); | |
public: | |
T& get(); | |
bool isAlive(); | |
void destroy(); | |
}; | |
template<typename T> class Storage | |
{ | |
template<typename> friend class Manager; | |
template<typename> friend class Handle; | |
private: | |
Atom<T>* atomArray{nullptr}; | |
Controller* controllerArray{nullptr}; | |
std::size_t capacity{0u}; | |
inline ~Storage() | |
{ | |
deleteArrays(); | |
} | |
inline void deleteArrays() | |
{ | |
delete[] atomArray; | |
delete[] controllerArray; | |
} | |
inline void reserve(std::size_t mCapacity) | |
{ | |
SSVU_ASSERT(mCapacity >= 0); | |
capacity = mCapacity; | |
auto newAtomArray(new Atom<T>[capacity]); | |
auto newControllerArray(new Controller[capacity]); | |
SSVU_ASSERT(newAtomArray != nullptr); | |
SSVU_ASSERT(newControllerArray != nullptr); | |
std::memcpy(newAtomArray, atomArray, sizeof(Atom<T>) * capacity); | |
std::memcpy(newControllerArray, controllerArray, sizeof(Controller) * capacity); | |
//std::copy(atomArray, atomArray + capacity, newAtomArray); | |
//std::copy(controllerArray, controllerArray + capacity, newControllerArray); | |
deleteArrays(); | |
atomArray = newAtomArray; | |
controllerArray = newControllerArray; | |
} | |
}; | |
template<typename T> class Manager | |
{ | |
template<typename> friend class Handle; | |
private: | |
Storage<T> storage; | |
Idx lastFree{0u}; | |
inline void checkResize() | |
{ | |
constexpr std::size_t resizeAmount{10}; | |
// If the last free index is valid, return | |
auto oldSize(storage.capacity); | |
if(oldSize > lastFree) return; | |
// Calculate new size and reserve required memory | |
auto newSize(oldSize + resizeAmount); | |
storage.reserve(newSize); | |
// Initialize reserved memory | |
while(oldSize++ < newSize) | |
{ | |
storage.atomArray[oldSize].ctrlIdx = oldSize; | |
storage.controllerArray[oldSize].idx = oldSize; | |
} | |
} | |
inline void destroy(Idx mCtrlIdx) | |
{ | |
storage.atomArray[storage.controllerArray[mCtrlIdx].idx].alive = false; | |
} | |
public: | |
inline Manager() { } | |
template<typename... TArgs> inline Handle<T> createAtom(TArgs&&... mArgs) | |
{ | |
checkResize(); | |
storage.atomArray[lastFree].impl = T(std::forward<TArgs>(mArgs)...); | |
storage.atomArray[lastFree].alive = true; | |
auto cIdx(storage.atomArray[lastFree].ctrlIdx); | |
storage.controllerArray[cIdx].idx = lastFree; | |
++(storage.controllerArray[cIdx].ctr); | |
++lastFree; | |
return {*this, cIdx, storage.controllerArray[cIdx].ctr}; | |
} | |
inline void refresh() | |
{ | |
// C++14: use polymorphic lambda | |
ssvu::sortStable(storage.atomArray, [](const Atom<T>& mA, const Atom<T>& mB){ return mA.alive > mB.alive; }); | |
auto rIdx(storage.atomArray.size() - 1); | |
for(; !storage.atomArray[rIdx].alive && rIdx > 0; --rIdx) | |
{ | |
auto& controller(storage.controllerArray[storage.atomArray[rIdx].ctrlIdx]); | |
++(controller.ctr); | |
controller.idx = -1; | |
} | |
for(auto fIdx(0u); fIdx <= rIdx; ++fIdx) storage.controllerArray[storage.atomArray[fIdx].ctrlIdx].idx = fIdx; | |
lastFree = rIdx + 1; // ? check | |
} | |
void printState() | |
{ | |
ssvu::lo("ATOMS") << ""; | |
for(const auto& a : storage.atomArray) std::cout << std::setw(4) << std::left << (int)a.alive << " "; | |
std::cout << "\n"; | |
ssvu::lo("CTIDX") << ""; | |
for(const auto& a : storage.controllerArray) std::cout << std::setw(4) << std::left << (int)a.idx << " "; | |
std::cout << "\n"; | |
ssvu::lo("CTCTR") << ""; | |
for(const auto& a : storage.controllerArray) std::cout << std::setw(4) << std::left << (int)a.ctr << " "; | |
std::cout << "\n\n"; | |
ssvu::lo("ASTRS") << "\n"; | |
std::size_t idx{0u}; | |
for(const auto& a : storage.atomArray) std::cout << idx++ << ": " << a.impl << "\n"; | |
std::cout << std::endl; | |
} | |
}; | |
template<typename T> inline Atom<T>& Handle<T>::getAtom() | |
{ | |
SSVU_ASSERT(isAlive()); | |
return manager.storage.atomArray[manager.controllers[ctrlIdx].idx]; | |
} | |
template<typename T> inline T& Handle<T>::get() | |
{ | |
return getAtom().impl; | |
} | |
template<typename T> inline bool Handle<T>::isAlive() | |
{ | |
return manager.storage.controllerArray[ctrlIdx].ctr == ctr; | |
} | |
template<typename T> inline void Handle<T>::destroy() | |
{ | |
return manager.destroy(ctrlIdx); | |
} | |
int main() | |
{ | |
Manager<std::string> test; | |
test.printState(); | |
auto a0 = test.createAtom(); | |
auto a1 = test.createAtom(); | |
auto a2 = test.createAtom(); | |
auto a3 = test.createAtom(); | |
auto a4 = test.createAtom(); | |
auto a5 = test.createAtom(); | |
auto a6 = test.createAtom(); | |
a0.get() = "hi"; | |
a4.get() = "ciao"; | |
a6.get() = "bye"; | |
test.printState(); | |
a2.destroy(); | |
a3.destroy(); | |
a5.destroy(); | |
//test.atoms[2].alive = false; | |
//test.atoms[3].alive = false; | |
//test.atoms[5].alive = false; | |
test.printState(); | |
test.refresh(); | |
test.printState(); | |
ssvu::lo("RESULT") << a0.get() << std::endl; | |
ssvu::lo("RESULT") << a4.get() << std::endl; | |
ssvu::lo("RESULT") << a6.get() << std::endl; | |
ssvu::lo("alive") << a0.isAlive() << std::endl; | |
ssvu::lo("alive") << a1.isAlive() << std::endl; | |
ssvu::lo("alive") << a2.isAlive() << std::endl; | |
ssvu::lo("alive") << a3.isAlive() << std::endl; | |
ssvu::lo("alive") << a4.isAlive() << std::endl; | |
ssvu::lo("alive") << a5.isAlive() << std::endl; | |
ssvu::lo("alive") << a6.isAlive() << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment