diff --git a/src/observersmanager.hpp b/src/observersmanager.hpp new file mode 100644 index 0000000..6fd74d0 --- /dev/null +++ b/src/observersmanager.hpp @@ -0,0 +1,129 @@ +#ifndef idF5E41734950640CDA3C949E0D3A9A30D +#define idF5E41734950640CDA3C949E0D3A9A30D + +#include +#include +#include +#include +#include + +namespace cloonel { + namespace implem { + template + class Iterator { + public: + Iterator ( const std::vector& parOccupied, std::vector& parItems, bool parEnd ) : + m_occupied(parOccupied), + m_items(parItems), + m_pos(parEnd ? m_occupied.size() : 0) + { + assert(m_occupied.size() == m_items.size()); + } + Iterator ( const Iterator& parOther ) : + m_occupied(parOther.m_occupied), + m_items(parOther.m_items), + m_pos(parOther.m_pos) + { + } + ~Iterator ( void ) noexcept = default; + + T operator-> ( void ) { + assert(m_pos < m_occupied.size()); + assert(m_occupied[m_pos]); + return m_items[m_pos]; + } + T operator* ( void ) { + assert(m_pos < m_occupied.size()); + assert(m_occupied[m_pos]); + return m_items[m_pos]; + } + + Iterator& operator++ ( void ) { + if (m_occupied.size() == m_pos) + return *this; + auto itNext = std::find(m_occupied.begin() + m_pos + 1, m_occupied.end(), true); + if (m_occupied.end() != itNext) + m_pos = itNext - m_occupied.begin(); + else + m_pos = m_occupied.size(); + return *this; + } + Iterator operator++ ( int ) { + Iterator prevState(*this); + ++(*this); + return prevState; + } + + bool operator== ( const Iterator& parOther ) const { + return m_pos == parOther.m_pos and &m_items == &parOther.m_items; + } + bool operator!= ( const Iterator& parOther ) const { return not this->operator==(parOther); } + + private: + const std::vector& m_occupied; + std::vector& m_items; + std::size_t m_pos; + }; + } //namespace implem + + template + class ObserversManager { + public: + typedef size_t TicketType; + typedef implem::Iterator iterator; + + ObserversManager ( void ); + ~ObserversManager ( void ) noexcept = default; + + TicketType Add ( T parObserver ); + void Remove ( TicketType parTicket ) noexcept; + std::size_t size ( void ) const { return m_usedCount; } + iterator begin ( void ) { return iterator(m_occupied, m_list, false); } + iterator end ( void ) { return iterator(m_occupied, m_list, true); } + + private: + std::vector m_list; + std::vector m_occupied; + std::size_t m_usedCount; + }; + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + ObserversManager::ObserversManager() : + m_usedCount(0) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + typename ObserversManager::TicketType ObserversManager::Add (T parObserver) { + m_list.push_back(parObserver); + m_occupied.push_back(true); + ++m_usedCount; + return static_cast(m_list.size()); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::Remove (TicketType parTicket) noexcept { + assert(static_cast(parTicket) <= m_list.size()); + assert(m_occupied[parTicket - 1]); + assert(m_usedCount > 0); + assert(m_list.size() == m_occupied.size()); + + m_occupied[parTicket - 1] = false; + --m_usedCount; + + auto lastNull = std::find(m_occupied.rbegin(), m_occupied.rend(), false); + if (m_occupied.rend() != lastNull) { + const std::size_t newSize = m_occupied.size() - (lastNull - m_occupied.rbegin()) + 1; + m_occupied.resize(newSize); + m_list.resize(newSize); + } + } +} //namespace cloonel + +#endif