New class to manage subscribers and give IDs.

This commit is contained in:
King_DuckZ 2014-02-21 23:11:02 +01:00
parent 05a8d0188c
commit 402681762a

129
src/observersmanager.hpp Normal file
View file

@ -0,0 +1,129 @@
#ifndef idF5E41734950640CDA3C949E0D3A9A30D
#define idF5E41734950640CDA3C949E0D3A9A30D
#include <cassert>
#include <vector>
#include <algorithm>
#include <iterator>
#include <ciso646>
namespace cloonel {
namespace implem {
template <typename T>
class Iterator {
public:
Iterator ( const std::vector<bool>& parOccupied, std::vector<T>& 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<bool>& m_occupied;
std::vector<T>& m_items;
std::size_t m_pos;
};
} //namespace implem
template <typename T>
class ObserversManager {
public:
typedef size_t TicketType;
typedef implem::Iterator<T> 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<T> m_list;
std::vector<bool> m_occupied;
std::size_t m_usedCount;
};
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
ObserversManager<T>::ObserversManager() :
m_usedCount(0)
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
typename ObserversManager<T>::TicketType ObserversManager<T>::Add (T parObserver) {
m_list.push_back(parObserver);
m_occupied.push_back(true);
++m_usedCount;
return static_cast<TicketType>(m_list.size());
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::Remove (TicketType parTicket) noexcept {
assert(static_cast<std::size_t>(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