DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/Containers

929 lines
31 KiB
Plaintext
Raw Permalink Normal View History

2024-12-24 23:49:36 +00:00
/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#pragma once
#include <osgEarth/Common>
#include <osgEarth/Threading>
#include <osg/ref_ptr>
#include <osg/observer_ptr>
#include <osg/Math>
#include <list>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <thread>
namespace osgEarth { namespace Util
{
/**
* A std::map-like map that uses a vector.
* This benchmarks much faster than std::map or std::unordered_map for small sets.
*/
template<typename KEY,typename DATA,typename LESS=std::less<KEY>>
struct vector_map
{
struct ENTRY {
KEY first;
DATA second;
};
using value_type = DATA;
using container_t = std::vector<ENTRY>;
using iterator = typename container_t::iterator;
using const_iterator = typename container_t::const_iterator;
container_t _container;
inline bool keys_equal(const KEY& a, const KEY& b) const {
return LESS()(a, b) == false && LESS()(b, a) == false;
}
inline DATA& operator[](const KEY& key) {
for(unsigned i=0; i<_container.size(); ++i) {
if (keys_equal(_container[i].first, key)) {
return _container[i].second;
}
}
_container.resize(_container.size()+1);
_container.back().first = key;
return _container.back().second;
}
inline const_iterator begin() const { return _container.begin(); }
inline const_iterator end() const { return _container.end(); }
inline iterator begin() { return _container.begin(); }
inline iterator end() { return _container.end(); }
inline iterator find(const KEY& key) {
for (unsigned i = 0; i < _container.size(); ++i) {
if (keys_equal(_container[i].first, key)) {
return _container.begin() + i;
}
}
return _container.end();
}
inline const_iterator find(const KEY& key) const {
for(unsigned i=0; i<_container.size(); ++i) {
if (keys_equal(_container[i].first, key)) {
return _container.begin()+i;
}
}
return _container.end();
}
inline bool empty() const { return _container.empty(); }
inline void clear() { _container.clear(); }
inline void erase(const KEY& key) {
for(unsigned i=0; i<_container.size(); ++i) {
if (keys_equal(_container[i].first, key)) {
if (i+1 < _container.size()) {
_container[i] = _container[_container.size()-1];
}
_container.resize(_container.size()-1);
break;
}
}
}
inline int indexOf(const KEY& key) const {
for(unsigned i=0; i<_container.size(); ++i) {
if (keys_equal(_container[i].first, key)) {
return i;
}
}
return -1;
}
inline int size() const { return _container.size(); }
template<typename InputIterator>
void insert(InputIterator a, InputIterator b) {
for(InputIterator i = a; i != b; ++i) (*this)[i->first] = i->second;
}
};
template<typename DATA>
struct vector_set
{
typedef std::vector<DATA> container_t;
typedef typename container_t::iterator iterator;
typedef typename container_t::const_iterator const_iterator;
typedef typename container_t::size_type size_type;
container_t _container;
inline const_iterator begin() const { return _container.begin(); }
inline const_iterator end() const { return _container.end(); }
inline iterator begin() { return _container.begin(); }
inline iterator end() { return _container.end(); }
inline std::pair<typename vector_set<DATA>::const_iterator, bool> insert(const DATA& data) {
const_iterator i = find(data);
if (i != end()) {
return std::make_pair(i, false);
}
else {
_container.push_back(data);
return std::make_pair(_container.end()-1, true);
}
}
inline const_iterator find(const DATA& data) const {
for (unsigned i = 0; i < _container.size(); ++i) {
if (_container[i] == data) {
return _container.begin() + i;
}
}
return _container.end();
}
inline bool contains(const DATA& data) const {
return find(data) != _container.end();
}
inline bool empty() const { return _container.empty(); }
inline void clear() { _container.clear(); }
inline size_type erase(const DATA& data) {
for (unsigned i = 0; i < _container.size(); ++i) {
if (_container[i] == data) {
if (i + 1 < _container.size()) {
_container[i] = _container[_container.size() - 1];
}
_container.resize(_container.size() - 1);
return 1;
}
}
return 0;
}
inline int size() const { return _container.size(); }
template<typename InputIterator>
void insert(InputIterator a, InputIterator b) {
for (InputIterator i = a; i != b; ++i)
insert(*i);
}
};
//------------------------------------------------------------------------
struct CacheStats
{
public:
CacheStats( unsigned entries, unsigned maxEntries, unsigned queries, float hitRatio )
: _entries(entries), _maxEntries(maxEntries), _queries(queries), _hitRatio(hitRatio) { }
/** dtor */
virtual ~CacheStats() { }
unsigned _entries;
unsigned _maxEntries;
unsigned _queries;
float _hitRatio;
};
//------------------------------------------------------------------------
/**
* Least-recently-used cache class.
* K = key type, T = value type
*
* usage:
* LRUCache<K,T> cache;
* cache.insert( key, value );
* LRUCache<K,T>::Record rec;
* if ( cache.get( key, rec ) )
* const T& value = rec.value();
*/
template<typename K, typename T, typename COMPARE=std::less<K> >
class LRUCache
{
public:
struct Record {
Record() : _valid(false) { }
Record(const T& value) : _value(value), _valid(true) { }
bool valid() const { return _valid; }
const T& value() const { return _value; }
private:
bool _valid;
T _value;
friend class LRUCache;
};
using Functor = std::function<void(const K&, const T&)>;
protected:
typedef typename std::list<K>::iterator lru_iter;
typedef typename std::list<K> lru_type;
typedef typename std::pair<T, lru_iter> map_value_type;
typedef typename std::unordered_map<K, map_value_type> map_type;
typedef typename map_type::iterator map_iter;
typedef typename map_type::const_iterator map_const_iter;
map_type _map;
lru_type _lru;
unsigned _max;
unsigned _buf;
unsigned _queries;
unsigned _hits;
bool _threadsafe;
mutable std::mutex _mutex;
public:
LRUCache( unsigned max =100 ) : _max(max), _threadsafe(false) {
_queries = 0;
_hits = 0;
setMaxSize_impl(max);
}
LRUCache( bool threadsafe, unsigned max =100 ) : _max(max), _threadsafe(threadsafe) {
_queries = 0;
_hits = 0;
setMaxSize_impl(max);
}
/** dtor */
virtual ~LRUCache() { }
void insert( const K& key, const T& value ) {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
insert_impl( key, value );
}
else {
insert_impl( key, value );
}
}
bool get( const K& key, Record& out ) {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
get_impl( key, out );
}
else {
get_impl( key, out );
}
return out.valid();
}
bool has( const K& key ) {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
return has_impl( key );
}
else {
return has_impl( key );
}
}
void erase( const K& key ) {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
erase_impl( key );
}
else {
erase_impl( key );
}
}
void clear() {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
clear_impl();
}
else {
clear_impl();
}
}
void setMaxSize( unsigned max ) {
if ( _threadsafe ) {
std::lock_guard<std::mutex> lock(_mutex);
setMaxSize_impl( max );
}
else {
setMaxSize_impl( max );
}
}
unsigned getMaxSize() const {
return _max;
}
CacheStats getStats() const {
return CacheStats(
_map.size(), _max, _queries, _queries > 0 ? (float)_hits/(float)_queries : 0.0f );
}
void forEach(const Functor& functor) const {
if (_threadsafe) {
std::lock_guard<std::mutex> lock(_mutex);
iterate_impl(functor);
}
else {
iterate_impl(functor);
}
}
private:
void insert_impl( const K& key, const T& value ) {
map_iter mi = _map.find( key );
if ( mi != _map.end() ) {
_lru.erase( mi->second.second );
mi->second.first = value;
_lru.push_back( key );
mi->second.second = _lru.end();
mi->second.second--;
}
else {
_lru.push_back( key );
lru_iter last = _lru.end(); last--;
_map[key] = std::make_pair(value, last);
}
if ( _map.size() > _max ) {
for( unsigned i=0; i < _buf; ++i ) {
const K& key = _lru.front();
_map.erase( key );
_lru.pop_front();
}
}
}
void get_impl( const K& key, Record& result ) {
_queries++;
map_iter mi = _map.find( key );
if ( mi != _map.end() ) {
_lru.erase( mi->second.second );
_lru.push_back( key );
lru_iter new_iter = _lru.end(); new_iter--;
mi->second.second = new_iter;
_hits++;
result._value = mi->second.first;
result._valid = true;
}
}
bool has_impl( const K& key ) {
return _map.find( key ) != _map.end();
}
void erase_impl( const K& key ) {
map_iter mi = _map.find( key );
if ( mi != _map.end() ) {
_lru.erase( mi->second.second );
_map.erase( mi );
}
}
void clear_impl() {
_lru.clear();
_map.clear();
_queries = 0;
_hits = 0;
}
void setMaxSize_impl( unsigned max ) {
_max = osg::maximum(max,10u);
_buf = _max/10u;
while( _map.size() > _max ) {
const K& key = _lru.front();
_map.erase( key );
_lru.pop_front();
}
}
void iterate_impl(const Functor& func) const {
for (auto i : _map)
func(i.first, i.second.first);
}
};
//--------------------------------------------------------------------
/**
* Same of osg::InlineVector, but with a superclass template parameter.
*/
template<class ValueT, class SuperClass>
class InlineVector : public SuperClass
{
typedef typename std::vector<ValueT> vector_type;
public:
typedef typename vector_type::allocator_type allocator_type;
typedef typename vector_type::value_type value_type;
typedef typename vector_type::const_pointer const_pointer;
typedef typename vector_type::pointer pointer;
typedef typename vector_type::const_reference const_reference;
typedef typename vector_type::reference reference;
typedef typename vector_type::const_iterator const_iterator;
typedef typename vector_type::iterator iterator;
typedef typename vector_type::const_reverse_iterator const_reverse_iterator;
typedef typename vector_type::reverse_iterator reverse_iterator;
typedef typename vector_type::size_type size_type;
typedef typename vector_type::difference_type difference_type;
explicit InlineVector() : _impl()
{
}
explicit InlineVector(size_type initial_size, const value_type& fill_value = value_type())
: _impl(initial_size, fill_value)
{
}
template<class InputIterator>
InlineVector(InputIterator first, InputIterator last)
: _impl(first, last)
{
}
InlineVector(const vector_type& other)
: _impl(other)
{
}
InlineVector(const InlineVector& other)
: _impl(other._impl)
{
}
InlineVector& operator=(const vector_type& other)
{
_impl = other;
return *this;
}
InlineVector& operator=(const InlineVector& other)
{
_impl = other._impl;
return *this;
}
virtual ~InlineVector() {}
void clear() { _impl.clear(); }
void resize(size_type new_size, const value_type& fill_value = value_type()) { _impl.resize(new_size, fill_value); }
void reserve(size_type new_capacity) { _impl.reserve(new_capacity); }
void swap(vector_type& other) { _impl.swap(other); }
void swap(InlineVector& other) { _impl.swap(other._impl); }
bool empty() const { return _impl.empty(); }
size_type size() const { return _impl.size(); }
size_type capacity() const { return _impl.capacity(); }
size_type max_size() const { return _impl.max_size(); }
allocator_type get_allocator() const { return _impl.get_allocator(); }
const_iterator begin() const { return _impl.begin(); }
iterator begin() { return _impl.begin(); }
const_iterator end() const { return _impl.end(); }
iterator end() { return _impl.end(); }
const_reverse_iterator rbegin() const { return _impl.rbegin(); }
reverse_iterator rbegin() { return _impl.rbegin(); }
const_reverse_iterator rend() const { return _impl.rend(); }
reverse_iterator rend() { return _impl.rend(); }
const_reference operator[](size_type index) const { return _impl[index]; }
reference operator[](size_type index) { return _impl[index]; }
const_reference at(size_type index) const { return _impl.at(index); }
reference at(size_type index) { return _impl.at(index); }
void assign(size_type count, const value_type& value) { _impl.assign(count, value); }
template<class Iter>
void assign(Iter first, Iter last) { _impl.assign(first, last); }
void push_back(const value_type& value) { _impl.push_back(value); }
void pop_back() { _impl.pop_back(); }
iterator erase(iterator where) { return _impl.erase(where); }
iterator erase(iterator first, iterator last) { return _impl.erase(first, last); }
iterator insert(iterator where, const value_type& value) { return _impl.insert(where, value); }
template<class InputIterator>
void insert(iterator where, InputIterator first, InputIterator last)
{
_impl.insert(where, first, last);
}
void insert(iterator where, size_type count, const value_type& value)
{
_impl.insert(where, count, value);
}
const_reference back() const { return _impl.back(); }
reference back() { return _impl.back(); }
const_reference front() const { return _impl.front(); }
reference front() { return _impl.front(); }
vector_type& asVector() { return _impl; }
const vector_type& asVector() const { return _impl; }
friend inline bool operator==(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl == right._impl; }
friend inline bool operator==(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl == right; }
friend inline bool operator==(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left == right._impl; }
friend inline bool operator!=(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl != right._impl; }
friend inline bool operator!=(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl != right; }
friend inline bool operator!=(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left != right._impl; }
friend inline bool operator<(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl < right._impl; }
friend inline bool operator<(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl < right; }
friend inline bool operator<(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left < right._impl; }
friend inline bool operator>(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl > right._impl; }
friend inline bool operator>(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl > right; }
friend inline bool operator>(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left > right._impl; }
friend inline bool operator<=(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl <= right._impl; }
friend inline bool operator<=(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl <= right; }
friend inline bool operator<=(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left <= right._impl; }
friend inline bool operator>=(const InlineVector<ValueT,SuperClass>& left, const InlineVector<ValueT,SuperClass>& right) { return left._impl >= right._impl; }
friend inline bool operator>=(const InlineVector<ValueT,SuperClass>& left, const std::vector<ValueT>& right) { return left._impl >= right; }
friend inline bool operator>=(const std::vector<ValueT>& left, const InlineVector<ValueT,SuperClass>& right) { return left >= right._impl; }
private:
vector_type _impl;
};
/** Template for per-thread data storage */
template<typename T>
struct PerThread : public std::mutex
{
PerThread() { }
T& get() {
std::lock_guard<std::mutex> lock(*this);
return _data[std::this_thread::get_id()];
}
void clear() {
std::lock_guard<std::mutex> lock(*this);
_data.clear();
}
typedef typename std::unordered_map<std::thread::id,T> container_t;
typedef typename container_t::iterator iterator;
// NB. lock before using these!
iterator begin() { return _data.begin(); }
iterator end() { return _data.end(); }
private:
container_t _data;
};
/** Template for thread safe per-object data storage */
template<typename KEY, typename DATA>
struct PerObjectMap
{
PerObjectMap() { }
bool threadsafe = true;
DATA& get(KEY k)
{
{
osgEarth::Threading::ScopedReadLock readLock(_mutex);
typename std::unordered_map<KEY,DATA>::iterator i = _data.find(k);
if ( i != _data.end() )
return i->second;
}
{
osgEarth::Threading::ScopedWriteLock lock(_mutex);
typename std::unordered_map<KEY,DATA>::iterator i = _data.find(k);
if ( i != _data.end() )
return i->second;
else
return _data[k];
}
}
void remove(KEY k)
{
osgEarth::Threading::ScopedWriteLock exclusive(_mutex);
_data.erase( k );
}
private:
std::unordered_map<KEY,DATA> _data;
osgEarth::Threading::ReadWriteMutex _mutex;
};
/** Template for thread safe per-object data storage */
template<typename KEY, typename DATA>
struct PerObjectFastMap
{
PerObjectFastMap() { }
bool threadsafe = true;
struct Functor {
virtual void operator()(DATA& data) =0;
};
struct ConstFunctor {
virtual void operator()(const DATA& data) const =0;
};
DATA& get(KEY k)
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
typename std::unordered_map<KEY,DATA>::iterator i = _data.find(k);
if ( i != _data.end() )
return i->second;
else
return _data[k];
}
void remove(KEY k)
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
_data.erase( k );
}
void forEach(Functor& functor)
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
for (typename std::unordered_map<KEY, DATA>::iterator i = _data.begin(); i != _data.end(); ++i)
functor.operator()(i->second);
}
void forEach(std::function<void(DATA&)> functor)
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
for (auto& entry : _data)
functor(entry.second);
}
void forEach(ConstFunctor& functor) const
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
for (typename std::unordered_map<KEY, DATA>::const_iterator i = _data.begin(); i != _data.end(); ++i)
functor.operator()(i->second);
}
void forEach(std::function<void(const DATA&)> functor) const
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
for (auto& entry : _data)
functor(entry.second);
}
unsigned size() const
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
return _data.size();
}
void clear()
{
osgEarth::Threading::scoped_lock_if lock(_mutex, threadsafe);
_data.clear();
}
private:
std::unordered_map<KEY,DATA> _data;
mutable std::mutex _mutex;
};
/** Template for thread safe per-object data storage */
template<typename KEY, typename DATA>
struct PerObjectRefMap
{
PerObjectRefMap() { }
DATA* get(KEY k)
{
osgEarth::Threading::ScopedReadLock lock(_mutex);
typename std::unordered_map<KEY,osg::ref_ptr<DATA>>::const_iterator i = _data.find(k);
if ( i != _data.end() )
return i->second.get();
return 0L;
}
DATA* getOrCreate(KEY k, DATA* newDataIfNeeded)
{
osg::ref_ptr<DATA> _refReleaser = newDataIfNeeded;
{
osgEarth::Threading::ScopedReadLock lock(_mutex);
typename std::unordered_map<KEY,osg::ref_ptr<DATA>>::const_iterator i = _data.find(k);
if ( i != _data.end() )
return i->second.get();
}
{
osgEarth::Threading::ScopedWriteLock lock(_mutex);
typename std::unordered_map<KEY,osg::ref_ptr<DATA>>::iterator i = _data.find(k);
if ( i != _data.end() )
return i->second.get();
_data[k] = newDataIfNeeded;
return newDataIfNeeded;
}
}
void remove(KEY k)
{
osgEarth::Threading::ScopedWriteLock exclusive(_mutex);
_data.erase( k );
}
void remove(DATA* data)
{
osgEarth::Threading::ScopedWriteLock exclusive(_mutex);
for( typename std::unordered_map<KEY,osg::ref_ptr<DATA>>::iterator i = _data.begin(); i != _data.end(); ++i )
{
if ( i->second.get() == data )
{
_data.erase( i );
break;
}
}
}
private:
std::unordered_map<KEY,osg::ref_ptr<DATA>> _data;
osgEarth::Threading::ReadWriteMutex _mutex;
};
// borrowed from osg::buffered_object. Auto-resizing array.
template<class T>
class AutoArray
{
public:
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
inline AutoArray() { }
inline AutoArray(unsigned int size) : _array(size) { }
AutoArray& operator = (const AutoArray& rhs)
{
_array = rhs._array;
return *this;
}
inline void setAllElementsTo(const T& t) { std::fill(_array.begin(), _array.end(), t); }
inline void clear() { _array.clear(); }
inline bool empty() const { return _array.empty(); }
inline unsigned int size() const { return _array.size(); }
inline void resize(unsigned int newSize) { _array.resize(newSize); }
inline iterator begin() { return _array.begin(); }
inline const_iterator begin() const { return _array.begin(); }
inline iterator end() { return _array.end(); }
inline const_iterator end() const { return _array.end(); }
inline T& operator[] (unsigned int pos)
{
if (_array.size() <= pos)
_array.resize(pos + 1);
return _array[pos];
}
inline const T& operator[] (unsigned int pos) const
{
// automatically resize array.
if (_array.size() <= pos)
_array.resize(pos + 1);
return _array[pos];
}
inline T& back() { return _array[size()-1]; }
inline const T& back() const { return _array[size()-1]; }
protected:
mutable std::vector<T> _array;
};
// A generic osg::Referenced vector
template<typename T>
class RefVector : public InlineVector<T, osg::Referenced>
{
};
/**
* Thread-safe queue.
*/
template<typename T>
class MutexedQueue
{
public:
//! Push a new item safely
void push(const T& t) {
std::lock_guard<std::mutex> lock(_m);
_queue.push(t);
}
//! Remove the front item safely
void pop() {
std::lock_guard<std::mutex> lock(_m);
_queue.pop();
}
//! Safely return a copy of the item at the head of
//! the queue
T front() {
std::lock_guard<std::mutex> lock(_m);
return _queue.empty() ? _default : _queue.front();
}
//! Safely remove the item at the head of the queue
//! and return it
T take_front() {
std::lock_guard<std::mutex> lock(_m);
T t = _queue.empty() ? _default : _queue.front();
if (_queue.empty() == false)
_queue.pop();
return t;
}
//! Safely clear the queue
void clear() {
std::lock_guard<std::mutex> lock(_m);
_queue.swap(std::queue<T>());
}
//! True if the queue is empty (but only at the
//! instant of the call.)
bool empty() const {
return _queue.empty();
}
private:
std::queue<T> _queue;
mutable std::mutex _m;
T _default;
};
/**
* A circular list that you can pull pointers from
* NOT thread safe.
*/
template<typename T>
class OSGEARTH_EXPORT RoundRobin {
public:
using iterator = typename std::list<T>::iterator;
using const_iterator = typename std::list<T>::const_iterator;
void add(const T& t) {
_list.push_back(t);
if (_list.size() == 1)
_iter = begin();
}
T next() {
OE_HARD_ASSERT(_list.size() > 0);
T t = *_iter++;
if (_iter == end()) _iter = begin();
return t;
}
iterator begin() {
return _list.begin();
}
const_iterator begin() const {
return _list.begin();
}
iterator end() {
return _list.end();
}
const_iterator end() const {
return _list.end();
}
bool empty() const {
return _list.empty();
}
private:
std::list<T> _list;
iterator _iter;
};
} }