clooneljump/src/observersmanager.hpp

181 lines
6.0 KiB
C++

/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef idF5E41734950640CDA3C949E0D3A9A30D
#define idF5E41734950640CDA3C949E0D3A9A30D
#include <cassert>
#include <vector>
#include <algorithm>
#include <iterator>
#include <ciso646>
#include <tree.hh>
#include <boost/iterator/transform_iterator.hpp>
#include <unordered_set>
#if defined (WITH_VERBOSE_OBS_MANAGER) && defined(__GNUC__) && __GNUC__ >= 2 && !defined(NDEBUG)
# define OBS_MANAGER_LOG
#endif
#if defined(OBS_MANAGER_LOG)
# include <iostream>
#endif
namespace cloonel {
template <typename T>
class ObserversManager {
public:
typedef size_t TicketType;
private:
struct TicketedWrapper {
TicketedWrapper ( void ) = default;
TicketedWrapper ( T parItem, TicketType parTicket ) :
itm(parItem),
ticket(parTicket)
{
}
T itm;
TicketType ticket;
bool operator== ( const TicketedWrapper& parOther ) const { return parOther.ticket == ticket; }
bool operator== ( TicketType parOther ) const { return parOther == ticket; }
};
static T& TicketedWrapperToItm ( TicketedWrapper& parWrapper ) { return parWrapper.itm; }
typedef tree<TicketedWrapper> TreeType;
typedef typename tree<TicketedWrapper>::iterator TreeIteratorType;
public:
enum {
Ticket_Null = 0
};
typedef boost::transform_iterator<std::function<T&(TicketedWrapper&)>, TreeIteratorType> iterator;
ObserversManager ( void );
~ObserversManager ( void ) noexcept;
TicketType Add ( T parObserver, TicketType parParent=Ticket_Null );
void Remove ( TicketType parTicket ) noexcept;
void RemoveAll ( void ) noexcept;
void Update ( TicketType parTicket, T parObserver );
std::size_t size ( void ) const { return m_tree.size(); }
iterator begin ( void ) { return iterator(m_tree.begin(), &TicketedWrapperToItm); }
iterator end ( void ) { return iterator(m_tree.end(), &TicketedWrapperToItm); }
void CopyObservers ( std::unordered_set<T>& parOut );
private:
TreeIteratorType GetByTicket_AssertPresent ( TicketType parTicket );
TreeType m_tree;
TicketType m_nextTicket;
};
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
ObserversManager<T>::ObserversManager() :
m_nextTicket(1)
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
ObserversManager<T>::~ObserversManager() noexcept {
assert(m_tree.empty());
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
typename ObserversManager<T>::TicketType ObserversManager<T>::Add (T parObserver, TicketType parParent) {
const auto currTicket = m_nextTicket;
if (Ticket_Null == parParent)
m_tree.insert(m_tree.begin(), TicketedWrapper(parObserver, currTicket));
else
m_tree.append_child(GetByTicket_AssertPresent(parParent), TicketedWrapper(parObserver, currTicket));
#if defined(OBS_MANAGER_LOG)
std::cout << __PRETTY_FUNCTION__ << " registering " << currTicket << " as a child of " << parParent << "\n";
#endif
++m_nextTicket;
return currTicket;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::Remove (TicketType parTicket) noexcept {
auto deleme = GetByTicket_AssertPresent(parTicket);
#if defined(OBS_MANAGER_LOG)
for (auto it(deleme); it != m_tree.end(); ++it) {
std::cout << __PRETTY_FUNCTION__ << " unregistering " << it->ticket << "\n";
}
#endif
m_tree.erase(deleme);
if (parTicket == m_nextTicket - 1)
--m_nextTicket;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::RemoveAll() noexcept {
if (not m_tree.empty()) {
for (typename TreeType::sibling_iterator it(m_tree.begin()), itEND(m_tree.end()); it != itEND; ++it) {
const TicketType ticket = it->ticket;
this->Remove(ticket);
}
assert(m_tree.empty());
}
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::Update (TicketType parTicket, T parObserver) {
std::swap(GetByTicket_AssertPresent(parTicket)->itm, parObserver);
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
typename ObserversManager<T>::TreeIteratorType ObserversManager<T>::GetByTicket_AssertPresent (TicketType parTicket) {
auto ret = std::find(m_tree.begin(), m_tree.end(), parTicket);
assert(m_tree.end() != ret);
return ret;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::CopyObservers (std::unordered_set<T>& parOut) {
for (const auto& itm : m_tree) {
parOut.insert(itm.itm);
}
}
} //namespace cloonel
#if defined(OBS_MANAGER_LOG)
# undef OBS_MANAGER_LOG
#endif
#endif