/*
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 .
*/
#ifndef idF5E41734950640CDA3C949E0D3A9A30D
#define idF5E41734950640CDA3C949E0D3A9A30D
#include
#include
#include
#include
#include
#include
#include
#include
#if defined (WITH_VERBOSE_OBS_MANAGER) && defined(__GNUC__) && __GNUC__ >= 2 && !defined(NDEBUG)
# define OBS_MANAGER_LOG
#endif
#if defined(OBS_MANAGER_LOG)
# include
#endif
namespace cloonel {
template
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 TreeType;
typedef typename tree::iterator TreeIteratorType;
public:
enum {
Ticket_Null = 0
};
typedef boost::transform_iterator, 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& parOut );
private:
TreeIteratorType GetByTicket_AssertPresent ( TicketType parTicket );
TreeType m_tree;
TicketType m_nextTicket;
};
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template
ObserversManager::ObserversManager() :
m_nextTicket(1)
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template
ObserversManager::~ObserversManager() noexcept {
assert(m_tree.empty());
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template
typename ObserversManager::TicketType ObserversManager::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
void ObserversManager::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
void ObserversManager::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
void ObserversManager::Update (TicketType parTicket, T parObserver) {
std::swap(GetByTicket_AssertPresent(parTicket)->itm, parObserver);
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template
typename ObserversManager::TreeIteratorType ObserversManager::GetByTicket_AssertPresent (TicketType parTicket) {
auto ret = std::find(m_tree.begin(), m_tree.end(), parTicket);
assert(m_tree.end() != ret);
return ret;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template
void ObserversManager::CopyObservers (std::unordered_set& parOut) {
for (const auto& itm : m_tree) {
parOut.insert(itm.itm);
}
}
} //namespace cloonel
#if defined(OBS_MANAGER_LOG)
# undef OBS_MANAGER_LOG
#endif
#endif