181 lines
6.0 KiB
C++
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
|