/* This file is part of Raul. * Copyright (C) 2007-2009 David Robillard * * Raul 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 2 of the License, or (at your option) any later * version. * * Raul 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 details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef RAUL_LIST_HPP #define RAUL_LIST_HPP #include #include #include #include "raul/Deletable.hpp" #include "raul/AtomicPtr.hpp" #include "raul/AtomicInt.hpp" namespace Raul { /** A realtime safe, (partially) thread safe doubly-linked list. * * Elements can be added safely while another thread is reading the list. * Like a typical ringbuffer, this is single-reader single-writer threadsafe * only. See documentation for specific functions for specifics. */ template class List : public Raul::Deletable, public boost::noncopyable { public: /** A node in a List. * * This is exposed so the user can allocate Nodes in different thread * than the list reader, and insert (e.g. via an Event) it later in the * reader thread. */ class Node : public Raul::Deletable { public: explicit Node(T elem) : _elem(elem) {} virtual ~Node() {} template explicit Node(const typename List::Node& copy) : _elem(copy._elem), _prev(copy._prev), _next(copy._next) {} Node* prev() const { return _prev.get(); } void prev(Node* ln) { _prev = ln; } Node* next() const { return _next.get(); } void next(Node* ln) { _next = ln; } T& elem() { return _elem;} const T& elem() const { return _elem; } private: T _elem; AtomicPtr _prev; AtomicPtr _next; }; List(size_t size=0, Node* head=NULL, Node* tail=NULL) : _size(size) , _end_iter(this) , _const_end_iter(this) { _head = head; _tail = tail; _end_iter._listnode = NULL; _const_end_iter._listnode = NULL; } ~List(); void push_back(Node* elem); ///< Realtime Safe void push_back(T& elem); ///< NOT Realtime Safe void append(List& list); void clear(); /// Valid only in the write thread unsigned size() const { return static_cast(_size.get()); } /// Valid for any thread bool empty() { return (_head.get() == NULL); } class iterator; /** Realtime safe const iterator for a List. */ class const_iterator { public: explicit const_iterator(const List* const list); const_iterator(const iterator& i) : _list(i._list), _listnode(i._listnode) {} inline const T& operator*(); inline const T* operator->(); inline const_iterator& operator++(); inline bool operator!=(const const_iterator& iter) const; inline bool operator!=(const iterator& iter) const; inline bool operator==(const const_iterator& iter) const; inline bool operator==(const iterator& iter) const; inline typename List::Node* node() { return _listnode; } inline const typename List::Node* node() const { return _listnode; } friend class List; private: const List* _list; const typename List::Node* _listnode; }; /** Realtime safe iterator for a List. */ class iterator { public: explicit iterator(List* const list); inline T& operator*(); inline T* operator->(); inline iterator& operator++(); inline bool operator!=(const iterator& iter) const; inline bool operator!=(const const_iterator& iter) const; inline bool operator==(const iterator& iter) const; inline bool operator==(const const_iterator& iter) const; friend class List; friend class List::const_iterator; private: const List* _list; typename List::Node* _listnode; }; void chop_front(List& front, size_t front_size, Node* front_tail); Node* erase(const iterator iter); iterator find(const T& val); iterator begin(); const_iterator begin() const; const iterator end() const; T& front() { return *begin(); } const T& front() const { return *begin(); } Node* head() { return _head.get(); } const Node* head() const { return _head.get(); } private: AtomicPtr _head; AtomicPtr _tail; ///< writer only AtomicInt _size; iterator _end_iter; const_iterator _const_end_iter; }; } // namespace Raul #endif // RAUL_LIST_HPP #include "ListImpl.hpp"