diff --git a/server/Makefile.am b/server/Makefile.am index edecf6c5..ab5ba8e1 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -97,6 +97,7 @@ libserver_la_SOURCES = \ cursor-channel-client.h \ cursor-channel.h \ utils.hpp \ + safe-list.hpp \ dcc.cpp \ dcc.h \ dcc-private.h \ diff --git a/server/meson.build b/server/meson.build index 458d6f31..aaa173ae 100644 --- a/server/meson.build +++ b/server/meson.build @@ -57,6 +57,7 @@ spice_server_sources = [ 'cursor-channel-client.h', 'cursor-channel.h', 'utils.hpp', + 'safe-list.hpp', 'dcc.cpp', 'dcc.h', 'dcc-private.h', diff --git a/server/safe-list.hpp b/server/safe-list.hpp new file mode 100644 index 00000000..1edbe532 --- /dev/null +++ b/server/safe-list.hpp @@ -0,0 +1,115 @@ +/* + Copyright (C) 2020 Red Hat, Inc. + + This library 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.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* Implementation of a list with more "safe" iterators. + * Specifically the item under an iterator can be removed while scanning + * the list. This to allow objects in the list to delete themselves from + * the list. + */ +#pragma once + +#include +#include +#include + +#include "push-visibility.h" + +namespace red { + +template +class safe_list +{ + typedef typename std::forward_list wrapped; + typename std::forward_list list; + class iterator; +public: + void push_front(const T& v) + { + list.push_front(v); + } + void remove(const T& v) + { + list.remove(v); + } + void clear() + { + list.clear(); + } + void pop_front() + { + list.pop_front(); + } + iterator begin() noexcept + { + return iterator(list.begin()); + } + iterator end() noexcept + { + return iterator(list.end()); + } + size_t size() + { + return std::distance(begin(), end()); + } + bool empty() const + { + return list.empty(); + } +}; + +template +class safe_list::iterator: public std::iterator +{ + typedef typename std::forward_list::iterator wrapped; + wrapped curr, next; +public: + iterator(wrapped curr) : + curr(curr), + next(curr != wrapped() ? ++curr : wrapped()) + { + } + iterator& operator++() + { + curr = next; + if (next != wrapped()) { + ++next; + } + return *this; + } + iterator operator++(int) + { + iterator tmp(*this); + operator++(); + return tmp; + } + bool operator==(const iterator& rhs) const + { + return curr == rhs.curr; + } + bool operator!=(const iterator& rhs) const + { + return curr != rhs.curr; + } + T& operator*() + { + return *curr; + } +}; + +} // namespace red + +#include "pop-visibility.h"