Refactoring in ObserversManager.
Pull out the storage part so the class is more tidy.
This commit is contained in:
parent
173d5d2f99
commit
103689a29a
2 changed files with 204 additions and 101 deletions
195
src/linearmap.hpp
Normal file
195
src/linearmap.hpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
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 idEA67296D7EC847B58BB3D52DBC9E51BA
|
||||
#define idEA67296D7EC847B58BB3D52DBC9E51BA
|
||||
|
||||
#include <vector>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <iterator>
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace cloonel {
|
||||
namespace implem {
|
||||
template <typename I, typename S>
|
||||
class LinearMapIterator : public boost::iterator_facade<LinearMapIterator<I, S>, typename std::iterator_traits<I>::value_type, typename std::iterator_traits<I>::iterator_category, typename std::iterator_traits<I>::reference, typename std::iterator_traits<I>::difference_type> {
|
||||
|
||||
typedef boost::iterator_facade<LinearMapIterator<I, S>, typename std::iterator_traits<I>::value_type, typename std::iterator_traits<I>::iterator_category, typename std::iterator_traits<I>::reference, typename std::iterator_traits<I>::difference_type> parent_type;
|
||||
|
||||
typedef typename parent_type::reference reference;
|
||||
typedef typename parent_type::value_type value_type;
|
||||
typedef S size_type;
|
||||
public:
|
||||
LinearMapIterator ( I parItemsStart, I parItemsEnd, std::vector<bool>::const_iterator parOccupiedStart ) :
|
||||
m_itStart(parItemsStart),
|
||||
m_itEnd(parItemsEnd),
|
||||
m_itOccupied(parOccupiedStart)
|
||||
{
|
||||
}
|
||||
~LinearMapIterator ( void ) noexcept = default;
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment ( void ) {
|
||||
do {
|
||||
++m_itStart;
|
||||
++m_itOccupied;
|
||||
} while (m_itEnd != m_itStart and not *m_itOccupied);
|
||||
}
|
||||
bool equal ( const LinearMapIterator& parOther ) const {
|
||||
return m_itStart == parOther.m_itStart;
|
||||
}
|
||||
reference dereference ( void ) const {
|
||||
return *m_itStart;
|
||||
}
|
||||
void advance ( size_type parAdv ) {
|
||||
while (parAdv and m_itEnd != m_itStart) {
|
||||
increment();
|
||||
--parAdv;
|
||||
}
|
||||
}
|
||||
|
||||
I m_itStart;
|
||||
const I m_itEnd;
|
||||
std::vector<bool>::const_iterator m_itOccupied;
|
||||
};
|
||||
} //namespace implem
|
||||
|
||||
template <typename T, typename Container=std::vector<T> >
|
||||
class LinearMap {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef T value_type;
|
||||
typedef typename implem::LinearMapIterator<typename Container::iterator, size_type> iterator;
|
||||
typedef typename implem::LinearMapIterator<typename Container::const_iterator, size_type> const_iterator;
|
||||
|
||||
LinearMap ( void ) = default;
|
||||
LinearMap ( LinearMap&& parOther );
|
||||
~LinearMap ( void ) noexcept = default;
|
||||
|
||||
size_type size ( void ) const { return m_usedCount; }
|
||||
size_type max_size ( void ) const noexcept { return m_list.max_size(); }
|
||||
size_type capacity ( void ) const noexcept { return m_list.capacity(); }
|
||||
void shrink_to_fit ( void );
|
||||
bool empty ( void ) const noexcept { return m_list.empty(); }
|
||||
void push_back ( const value_type& parNew );
|
||||
void push_back ( value_type&& parNew );
|
||||
void swap ( LinearMap& parOther );
|
||||
void clear ( void );
|
||||
iterator erase_absolute ( size_type parIndex );
|
||||
iterator at_absolute ( size_type parIndex );
|
||||
|
||||
iterator begin ( void ) { return iterator(m_list.begin(), m_list.end(), m_occupied.cbegin()); }
|
||||
iterator end ( void ) { return iterator(m_list.end(), m_list.end(), m_occupied.cend()); }
|
||||
const_iterator begin ( void ) const { return const_iterator(m_list.begin(), m_list.end(), m_occupied.cbegin()); }
|
||||
const_iterator end ( void ) const { return const_iterator(m_list.end(), m_list.end(), m_occupied.cend()); }
|
||||
const_iterator cbegin ( void ) const { return const_iterator(m_list.begin(), m_list.end(), m_occupied.cbegin()); }
|
||||
const_iterator cend ( void ) const { return const_iterator(m_list.end(), m_list.end(), m_occupied.cend()); }
|
||||
|
||||
private:
|
||||
Container m_list;
|
||||
std::vector<bool> m_occupied;
|
||||
size_type m_usedCount;
|
||||
};
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
void LinearMap<T, Container>::shrink_to_fit() {
|
||||
m_list.shrink_to_fit();
|
||||
m_occupied.shrink_to_fit();
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
void LinearMap<T, Container>::push_back (const value_type& parNew) {
|
||||
m_list.push_back(parNew);
|
||||
m_occupied.push_back(true);
|
||||
++m_usedCount;
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
void LinearMap<T, Container>::push_back (value_type&& parNew) {
|
||||
m_list.push_back(std::move(parNew));
|
||||
m_occupied.push_back(true);
|
||||
++m_usedCount;
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
void LinearMap<T, Container>::swap (LinearMap& parOther) {
|
||||
m_list.swap(parOther.m_list);
|
||||
m_occupied.swap(parOther.m_occupied);
|
||||
std::swap(m_usedCount, parOther.m_usedCount);
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
void LinearMap<T, Container>::clear() {
|
||||
m_list.clear();
|
||||
m_occupied.clear();
|
||||
m_usedCount = 0;
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
typename LinearMap<T, Container>::iterator LinearMap<T, Container>::erase_absolute (size_type parIndex) {
|
||||
auto ret = at_absolute(parIndex);
|
||||
++ret;
|
||||
|
||||
m_occupied[parIndex] = false;
|
||||
--m_usedCount;
|
||||
|
||||
size_type deleCount = 0;
|
||||
for (auto itOcc = m_occupied.rbegin(), itOccEND = m_occupied.rend(); itOcc != itOccEND and not *itOcc; ++itOcc) {
|
||||
++deleCount;
|
||||
}
|
||||
|
||||
if (deleCount) {
|
||||
assert(deleCount <= m_occupied.size());
|
||||
const auto newSize = m_occupied.size() - deleCount;
|
||||
m_occupied.resize(newSize);
|
||||
m_list.resize(newSize);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T, typename Container>
|
||||
typename LinearMap<T, Container>::iterator LinearMap<T, Container>::at_absolute (size_type parIndex) {
|
||||
assert(m_usedCount > 0);
|
||||
assert(m_list.size() == m_occupied.size());
|
||||
assert(parIndex < m_list.size());
|
||||
assert(m_occupied[parIndex]);
|
||||
|
||||
return begin() + std::count_if(m_occupied.begin(), m_occupied.begin() + parIndex, [] (bool a) { return a; });
|
||||
}
|
||||
} //namespace cloonel
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef idF5E41734950640CDA3C949E0D3A9A30D
|
||||
#define idF5E41734950640CDA3C949E0D3A9A30D
|
||||
|
||||
#include "linearmap.hpp"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
@ -27,101 +28,31 @@
|
|||
#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() + static_cast<std::vector<bool>::difference_type>(m_pos + 1), m_occupied.end(), true);
|
||||
if (m_occupied.end() != itNext)
|
||||
m_pos = static_cast<std::size_t>(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;
|
||||
typedef typename LinearMap<T>::iterator iterator;
|
||||
|
||||
ObserversManager ( void );
|
||||
ObserversManager ( void ) = default;
|
||||
~ObserversManager ( void ) noexcept = default;
|
||||
|
||||
TicketType Add ( T parObserver );
|
||||
void Remove ( TicketType parTicket ) noexcept;
|
||||
void Update ( TicketType parTicket, T parObserver );
|
||||
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); }
|
||||
std::size_t size ( void ) const { return m_list.size(); }
|
||||
iterator begin ( void ) { return m_list.begin(); }
|
||||
iterator end ( void ) { return m_list.end(); }
|
||||
|
||||
private:
|
||||
std::vector<T> m_list;
|
||||
std::vector<bool> m_occupied;
|
||||
std::size_t m_usedCount;
|
||||
LinearMap<T> m_list;
|
||||
};
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -129,37 +60,14 @@ namespace cloonel {
|
|||
///--------------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
std::size_t deleCount = 0;
|
||||
for (auto itOcc = m_occupied.rbegin(), itOccEND = m_occupied.rend(); itOcc != itOccEND and not *itOcc; ++itOcc) {
|
||||
++deleCount;
|
||||
}
|
||||
|
||||
if (deleCount) {
|
||||
assert(deleCount <= m_occupied.size());
|
||||
const std::size_t newSize = m_occupied.size() - deleCount;
|
||||
m_occupied.resize(newSize);
|
||||
m_list.resize(newSize);
|
||||
}
|
||||
m_list.erase_absolute(parTicket - 1);
|
||||
}
|
||||
|
||||
///--------------------------------------------------------------------------
|
||||
///--------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
void ObserversManager<T>::Update (TicketType parTicket, T parObserver) {
|
||||
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());
|
||||
|
||||
std::swap(m_list[parTicket - 1], parObserver);
|
||||
std::swap(*m_list.at_absolute(parTicket - 1), parObserver);
|
||||
}
|
||||
} //namespace cloonel
|
||||
|
||||
|
|
Loading…
Reference in a new issue