/* 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