Commit 12d04083 authored by neverlord's avatar neverlord

maintenance

parent 30e1e116
......@@ -152,6 +152,8 @@ nobase_library_include_HEADERS = \
cppa/get.hpp \
cppa/group.hpp \
cppa/guard_expr.hpp \
cppa/intrusive/bidirectional_iterator.hpp \
cppa/intrusive/doubly_linked_list.hpp \
cppa/intrusive/forward_iterator.hpp \
cppa/intrusive/single_reader_queue.hpp \
cppa/intrusive/singly_linked_list.hpp \
......
......@@ -266,3 +266,5 @@ cppa/detail/value_guard.hpp
cppa/detail/tuple_iterator.hpp
cppa/match_expr.hpp
cppa/detail/pseudo_tuple.hpp
cppa/intrusive/doubly_linked_list.hpp
cppa/intrusive/bidirectional_iterator.hpp
......@@ -65,12 +65,13 @@ class abstract_actor : public Base
struct queue_node
{
queue_node* next; // intrusive next pointer
queue_node* prev; // intrusive previous pointer
bool marked; // denotes if this node is currently processed
actor_ptr sender;
any_tuple msg;
queue_node() : next(nullptr), marked(false) { }
queue_node() : next(nullptr), prev(nullptr), marked(false) { }
queue_node(actor* from, any_tuple content)
: next(nullptr), marked(false), sender(from), msg(std::move(content))
: next(nullptr), prev(nullptr), marked(false), sender(from), msg(std::move(content))
{
}
};
......
......@@ -67,9 +67,6 @@ struct mailman_add_peer
class mailman_job
{
friend class intrusive::singly_linked_list<mailman_job>;
friend class intrusive::single_reader_queue<mailman_job>;
public:
enum job_type
......@@ -80,7 +77,7 @@ class mailman_job
kill_type
};
inline mailman_job() : next(nullptr), m_type(invalid_type) { }
inline mailman_job() : next(nullptr), prev(nullptr), m_type(invalid_type) { }
mailman_job(process_information_ptr piptr,
actor_ptr const& from,
......@@ -123,9 +120,11 @@ class mailman_job
return m_type == kill_type;
}
mailman_job* next;
mailman_job* prev;
private:
mailman_job* next;
job_type m_type;
// unrestricted union
union
......
......@@ -43,9 +43,6 @@ namespace cppa { namespace detail {
class post_office_msg
{
friend class intrusive::singly_linked_list<post_office_msg>;
friend class intrusive::single_reader_queue<post_office_msg>;
public:
enum msg_type
......@@ -87,7 +84,7 @@ class post_office_msg
inline proxy_exited(actor_proxy_ptr const& who) : proxy_ptr(who) { }
};
inline post_office_msg() : next(nullptr), m_type(invalid_type) { }
inline post_office_msg() : next(0), prev(0), m_type(invalid_type) { }
post_office_msg(native_socket_type arg0,
process_information_ptr const& arg1,
......@@ -130,9 +127,11 @@ class post_office_msg
~post_office_msg();
private:
post_office_msg* next;
post_office_msg* prev;
private:
msg_type m_type;
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa 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 3 of the License *
* or (at your option) any later version. *
* *
* libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef BIDIRECTIONAL_ITERATOR_HPP
#define BIDIRECTIONAL_ITERATOR_HPP
#include <iterator>
namespace cppa { namespace intrusive {
/**
* @brief A forward iterator for intrusive lists.
*/
template<class T>
class bidirectional_iterator
{
public:
typedef T value_type;
typedef value_type& reference;
typedef value_type const& const_reference;
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
inline bidirectional_iterator(pointer ptr = nullptr) : m_ptr(ptr) { }
bidirectional_iterator(bidirectional_iterator const&) = default;
bidirectional_iterator& operator=(bidirectional_iterator const&) = default;
inline bidirectional_iterator& operator++()
{
m_ptr = m_ptr->next;
return *this;
}
inline bidirectional_iterator operator++(int)
{
bidirectional_iterator tmp{*this};
m_ptr = m_ptr->next;
return tmp;
}
inline bidirectional_iterator& operator--()
{
m_ptr = m_ptr->prev;
return *this;
}
inline bidirectional_iterator operator--(int)
{
bidirectional_iterator tmp{*this};
m_ptr = m_ptr->prev;
return tmp;
}
inline explicit operator bool() { return m_ptr != nullptr; }
inline bool operator!() { return m_ptr != nullptr; }
inline reference operator*() { return *m_ptr; }
inline const_reference operator*() const { return *m_ptr; }
inline pointer operator->() { return m_ptr; }
inline const_pointer operator->() const { return m_ptr; }
/**
* @brief Returns the element this iterator points to.
*/
inline pointer ptr() { return m_ptr; }
/**
* @brief Returns the element this iterator points to.
*/
inline const_pointer ptr() const { return m_ptr; }
private:
pointer m_ptr;
};
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator==(bidirectional_iterator<T> const& lhs,
bidirectional_iterator<T> const& rhs)
{
return lhs.ptr() == rhs.ptr();
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator==(bidirectional_iterator<T> const& lhs, T const* rhs)
{
return lhs.ptr() == rhs;
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator==(T const* lhs, bidirectional_iterator<T> const& rhs)
{
return lhs == rhs.ptr();
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator==(bidirectional_iterator<T> const& lhs, decltype(nullptr))
{
return lhs.ptr() == nullptr;
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator==(decltype(nullptr), bidirectional_iterator<T> const& rhs)
{
return rhs.ptr() == nullptr;
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator!=(bidirectional_iterator<T> const& lhs,
bidirectional_iterator<T> const& rhs)
{
return !(lhs == rhs);
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator!=(bidirectional_iterator<T> const& lhs, T const* rhs)
{
return !(lhs == rhs);
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator!=(T const* lhs, bidirectional_iterator<T> const& rhs)
{
return !(lhs == rhs);
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator!=(bidirectional_iterator<T> const& lhs, decltype(nullptr))
{
return !(lhs == nullptr);
}
/**
* @relates bidirectional_iterator
*/
template<class T>
inline bool operator!=(decltype(nullptr), bidirectional_iterator<T> const& rhs)
{
return !(nullptr == rhs);
}
} } // namespace cppa::intrusive
#endif // BIDIRECTIONAL_ITERATOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa 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 3 of the License *
* or (at your option) any later version. *
* *
* libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef DOUBLY_LINKED_LIST_HPP
#define DOUBLY_LINKED_LIST_HPP
#include <cstddef>
#include <utility>
#include "cppa/config.hpp"
#include "cppa/intrusive/bidirectional_iterator.hpp"
namespace cppa { namespace intrusive {
/**
* @brief A singly linked list similar to std::forward_list
* but intrusive and with push_back() support.
* @tparam T A class providing a @p next pointer and a default constructor.
*/
template<class T>
class doubly_linked_list
{
doubly_linked_list(doubly_linked_list const&) = delete;
doubly_linked_list& operator=(doubly_linked_list const&) = delete;
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef value_type& reference;
typedef value_type const& const_reference;
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef bidirectional_iterator<value_type> iterator;
typedef bidirectional_iterator<const value_type> const_iterator;
doubly_linked_list() : m_head(), m_tail()
{
init();
}
doubly_linked_list(doubly_linked_list&& other) : m_head(), m_tail()
{
init();
*this = std::move(other);
}
doubly_linked_list& operator=(doubly_linked_list&& other)
{
clear();
if (other.not_empty())
{
connect(head(), other.first());
connect(other.last(), tail());
other.init();
}
return *this;
}
/**
* @brief Creates a list from given [first, last] range.
*/
static doubly_linked_list from(std::pair<pointer, pointer> const& p)
{
doubly_linked_list result;
connect(result.head(), p.first);
connect(p.second, result.tail());
return result;
}
~doubly_linked_list() { clear(); }
// element access
inline reference front() { return *first(); }
inline const_reference front() const { return *first(); }
inline reference back() { return *last(); }
inline const_reference back() const { return *last(); }
// iterators
inline iterator begin() { return first(); }
inline const_iterator begin() const { return first(); }
inline const_iterator cbegin() const { return first(); }
inline iterator end() { return tail(); }
inline const_iterator end() const { return tail(); }
inline const_iterator cend() const { return tail(); }
// capacity
/**
* @brief Returns true if <tt>{@link begin()} == {@link end()}</tt>.
*/
inline bool empty() const { return first() == tail(); }
/**
* @brief Returns true if <tt>{@link begin()} != {@link end()}</tt>.
*/
inline bool not_empty() const { return first() != tail(); }
// no size member function because it would have O(n) complexity
// modifiers
/**
* @brief Deletes all elements.
* @post {@link empty()}
*/
void clear()
{
if (not_empty())
{
auto i = first();
auto t = tail();
while (i != t)
{
pointer next = i->next;
delete i;
i = next;
}
init();
}
}
/**
* @brief Inserts @p what after @p pos.
* @returns An iterator to the inserted element.
*/
iterator insert(iterator pos, pointer what)
{
connect(pos->prev, what);
connect(what, pos.ptr());
return what;
}
/**
* @brief Constructs an element from @p args in-place after @p pos.
* @returns An iterator to the inserted element.
*/
template<typename... Args>
iterator emplace(iterator pos, Args&&... args)
{
return insert(pos, new value_type(std::forward<Args>(args)...));
}
/**
* @brief Deletes the element after @p pos.
* @returns An iterator to the element following the erased one.
*/
iterator erase(iterator pos)
{
CPPA_REQUIRE(pos != nullptr);
CPPA_REQUIRE(pos != end());
auto prev = pos->prev;
auto next = pos->next;
connect(prev, next);
delete pos.ptr();
return next;
}
/**
* @brief Removes the element after @p pos from the list and returns it.
*/
pointer take(iterator pos)
{
CPPA_REQUIRE(pos != nullptr);
connect(pos->prev, pos->next);
return pos.ptr();
}
/**
* @brief Appends @p what to the list.
*/
void push_back(pointer what)
{
connect(last(), what);
connect(what, tail());
}
/**
* @brief Creates an element from @p args in-place and appends it
* to the list.
*/
template<typename... Args>
void emplace_back(Args&&... args)
{
push_back(new value_type(std::forward<Args>(args)...));
}
/**
* @brief Inserts @p what as the first element of the list.
*/
void push_front(pointer what)
{
connect(what, first());
connect(head(), what);
}
/**
* @brief Creates an element from @p args and inserts it
* as the first element of the list.
*/
template<typename... Args>
void emplace_front(Args&&... args)
{
push_front(new value_type(std::forward<Args>(args)...));
}
/**
* @brief Deletes the first element of the list.
*/
void pop_front()
{
if (not_empty()) erase(first());
}
void pop_back()
{
if (not_empty()) erase(last());
}
/**
* @brief Returns the content of the list as [first, last] sequence.
* @post {@link empty()}
*/
std::pair<pointer, pointer> take()
{
auto result = std::make_pair(first(), last());
init();
return result;
}
/**
* @brief Moves all elements from @p other to @p *this.
* The elements are inserted after @p pos.
* @pre <tt>@p pos != {@link end()}</tt>
* @pre <tt>this != &other</tt>
*/
void splice(iterator pos, doubly_linked_list&& other)
{
CPPA_REQUIRE(pos != nullptr);
CPPA_REQUIRE(this != &other);
if (empty())
{
*this = std::move(other);
}
else if (other.not_empty())
{
connect(last(), other.first());
connect(other.last(), tail());
other.init();
}
}
/**
* @brief Removes all elements for which predicate @p p returns @p true.
*/
template<typename UnaryPredicate>
void remove_if(UnaryPredicate p)
{
for (auto i = begin(); i != end(); )
{
if (p(*i))
{
i = erase(i);
}
else
{
++i;
}
}
}
/**
* @brief Removes all elements that are equal to @p value.
*/
void remove(value_type const& value)
{
remove_if([&](value_type const& other) { return value == other; });
}
private:
value_type m_head;
value_type m_tail;
inline value_type* head() { return &m_head; }
inline value_type const* head() const { return &m_head; }
inline value_type* first() { return m_head.next; }
inline value_type const* first() const { return m_head.next; }
inline value_type* tail() { return &m_tail; }
inline value_type const* tail() const { return &m_tail; }
inline value_type* last() { return m_tail.prev; }
inline value_type const* last() const { return m_tail.prev; }
static inline void connect(value_type* lhs, value_type* rhs)
{
lhs->next = rhs;
rhs->prev = lhs;
}
inline void init()
{
connect(&m_head, &m_tail);
}
};
} } // namespace cppa::intrusive
#endif // DOUBLY_LINKED_LIST_HPP
......@@ -36,6 +36,7 @@
#include <memory>
#include "cppa/detail/thread.hpp"
#include "cppa/intrusive/doubly_linked_list.hpp"
namespace cppa { namespace intrusive {
......@@ -60,8 +61,7 @@ class single_reader_queue
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef std::unique_ptr<value_type> unique_value_ptr;
typedef std::list<unique_value_ptr> cache_type;
typedef doubly_linked_list<value_type> cache_type;
typedef typename cache_type::iterator cache_iterator;
/**
......@@ -240,13 +240,12 @@ class single_reader_queue
// next iteration element
pointer next = e->next;
// insert e to private cache (convert to LIFO order)
tmp.push_front(unique_value_ptr{e});
//m_cache.insert(iter, unique_value_ptr{e});
tmp.push_front(e);
// next iteration
e = next;
}
if (iter) *iter = tmp.begin();
m_cache.splice(m_cache.end(), tmp);
m_cache.splice(m_cache.end(), std::move(tmp));
return true;
}
// next iteration
......@@ -259,10 +258,7 @@ class single_reader_queue
{
if (!m_cache.empty() || fetch_new_data())
{
auto result = m_cache.front().release();
m_cache.pop_front();
return result;
//return m_cache.take_after(m_cache.before_begin());
return m_cache.take(m_cache.begin());
}
return nullptr;
}
......
......@@ -91,9 +91,7 @@ bool abstract_event_based_actor::invoke_from_cache()
{
for (auto i = m_mailbox_pos; i != m_mailbox.cache().end(); ++i)
{
auto& ptr = *i;
CPPA_REQUIRE(ptr.get() != nullptr);
if (handle_message(*ptr))
if (handle_message(*i))
{
m_mailbox.cache().erase(i);
return true;
......
......@@ -70,7 +70,7 @@ void converted_thread_context::enqueue(actor* sender, const any_tuple& msg)
void converted_thread_context::dequeue(partial_function& rules) /*override*/
{
auto rm_fun = [&](queue_node_ptr& node) { return dq(*node, rules); };
auto rm_fun = [&](queue_node& node) { return dq(node, rules); };
auto& mbox_cache = m_mailbox.cache();
auto mbox_end = mbox_cache.end();
auto iter = std::find_if(mbox_cache.begin(), mbox_end, rm_fun);
......@@ -87,9 +87,9 @@ void converted_thread_context::dequeue(behavior& rules) /*override*/
{
auto timeout = now();
timeout += rules.timeout();
auto rm_fun = [&](queue_node_ptr& node)
auto rm_fun = [&](queue_node& node)
{
return dq(*node, rules.get_partial_function());
return dq(node, rules.get_partial_function());
};
auto& mbox_cache = m_mailbox.cache();
auto mbox_end = mbox_cache.end();
......
......@@ -52,13 +52,13 @@ mailman_job::mailman_job(process_information_ptr piptr,
const actor_ptr& from,
const channel_ptr& to,
const any_tuple& content)
: next(nullptr), m_type(send_job_type)
: next(nullptr), prev(nullptr), m_type(send_job_type)
{
new (&m_send_job) mailman_send_job (piptr, from, to, content);
}
mailman_job::mailman_job(native_socket_type sockfd, const process_information_ptr& pinfo)
: next(0), m_type(add_peer_type)
: next(nullptr), prev(nullptr), m_type(add_peer_type)
{
new (&m_add_socket) mailman_add_peer (sockfd, pinfo);
}
......
......@@ -55,6 +55,7 @@ post_office_msg::post_office_msg(native_socket_type arg0,
const actor_proxy_ptr& arg2,
std::unique_ptr<attachable>&& arg3)
: next(nullptr)
, prev(nullptr)
, m_type(add_peer_type)
{
new (&m_add_peer_msg) add_peer(arg0, arg1, arg2, std::move(arg3));
......@@ -62,6 +63,7 @@ post_office_msg::post_office_msg(native_socket_type arg0,
post_office_msg::post_office_msg(native_socket_type arg0, const actor_ptr& arg1)
: next(nullptr)
, prev(nullptr)
, m_type(add_server_socket_type)
{
new (&m_add_server_socket) add_server_socket(arg0, arg1);
......@@ -69,6 +71,7 @@ post_office_msg::post_office_msg(native_socket_type arg0, const actor_ptr& arg1)
post_office_msg::post_office_msg(const actor_proxy_ptr& proxy_ptr)
: next(nullptr)
, prev(nullptr)
, m_type(proxy_exited_type)
{
new (&m_proxy_exited) proxy_exited(proxy_ptr);
......
......@@ -98,7 +98,7 @@ void yielding_actor::yield_until_not_empty()
void yielding_actor::dequeue(partial_function& fun)
{
auto rm_fun = [&](queue_node_ptr& node) { return dq(*node, fun) == dq_done; };
auto rm_fun = [&](queue_node& node) { return dq(node, fun) == dq_done; };
dequeue_impl(rm_fun);
}
......@@ -107,9 +107,9 @@ void yielding_actor::dequeue(behavior& bhvr)
if (bhvr.timeout().valid())
{
request_timeout(bhvr.timeout());
auto rm_fun = [&](queue_node_ptr& node) -> bool
auto rm_fun = [&](queue_node& node) -> bool
{
switch (dq(*node, bhvr.get_partial_function()))
switch (dq(node, bhvr.get_partial_function()))
{
case dq_timeout_occured:
bhvr.handle_timeout();
......
......@@ -42,8 +42,9 @@ namespace { size_t s_iint_instances = 0; }
struct iint
{
iint* next;
iint* prev;
int value;
inline iint(int val = 0) : next(nullptr), value(val) { ++s_iint_instances; }
inline iint(int val = 0) : next(0), prev(0), value(val) { ++s_iint_instances; }
~iint() { --s_iint_instances; }
};
......@@ -63,11 +64,28 @@ inline bool operator==(int lhs, iint const& rhs)
}
typedef cppa::intrusive::singly_linked_list<iint> iint_list;
typedef cppa::intrusive::doubly_linked_list<iint> diint_list;
typedef cppa::intrusive::single_reader_queue<iint> iint_queue;
size_t test__intrusive_containers()
{
CPPA_TEST(test__intrusive_containers);
{
diint_list dlist1;
dlist1.emplace_back(1);
dlist1.emplace_back(2);
dlist1.emplace_back(3);
CPPA_CHECK_EQUAL(1, dlist1.front().value);
CPPA_CHECK_EQUAL(3, dlist1.back().value);
dlist1.remove_if([](iint const& i) { return i.value % 2 == 1; });
CPPA_CHECK_EQUAL(2, dlist1.front().value);
CPPA_CHECK_EQUAL(2, dlist1.back().value);
dlist1.erase(dlist1.begin());
CPPA_CHECK(dlist1.empty());
}
iint_list ilist1;
ilist1.push_back(new iint(1));
ilist1.emplace_back(2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment