// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_CTX_LIST_H namespace ircd::ctx { struct list; } /// A special linked-list for contexts. Each ircd::ctx has space for one and /// only one node on its internal ctx::ctx structure. It can only participate /// in one ctx::list at a time. This forms the structural basis for mutexes, /// condition variables and other interleaving primitives which form queues /// of contexts. /// /// This device is strictly for context switching purposes. It is minimal, /// usage is specific to this purpose, and not a general list to be used /// elsewhere. Furthermore, this is too lightweight for even the /// ircd::allocator::node strategy. Custom operations are implemented for /// maximum space efficiency in both the object instance and the ctx::ctx. /// struct ircd::ctx::list { struct node; private: ctx *head {nullptr}; ctx *tail {nullptr}; // Get next or prev entry in ctx static const ctx *next(const ctx *const &); static const ctx *prev(const ctx *const &); static ctx *&next(ctx *const &); static ctx *&prev(ctx *const &); public: const ctx *front() const; const ctx *back() const; ctx *front(); ctx *back(); // iteration bool for_each(const std::function &) const; bool for_each(const std::function &); void for_each(const std::function &) const; void for_each(const std::function &); // reverse iteration bool rfor_each(const std::function &) const; bool rfor_each(const std::function &); void rfor_each(const std::function &) const; void rfor_each(const std::function &); bool empty() const; size_t size() const; void push_front(ctx *const & = current); void push_back(ctx *const & = current); void push(ctx *const & = current); // push_back ctx *pop_front(); ctx *pop_back(); ctx *pop(); // pop_front void remove(ctx *const & = current); list() = default; list(list &&) noexcept; list(const list &) = delete; list &operator=(list &&) noexcept; list &operator=(const list &) = delete; ~list() noexcept; }; struct ircd::ctx::list::node { ctx *prev {nullptr}; ctx *next {nullptr}; }; inline ircd::ctx::list::list(list &&o) noexcept :head{std::move(o.head)} ,tail{std::move(o.tail)} { o.head = nullptr; o.tail = nullptr; } inline ircd::ctx::list & ircd::ctx::list::operator=(list &&o) noexcept { this->~list(); head = std::move(o.head); tail = std::move(o.tail); o.head = nullptr; o.tail = nullptr; return *this; } inline ircd::ctx::list::~list() noexcept { assert(empty()); } inline ircd::ctx::ctx * ircd::ctx::list::pop() { return pop_front(); } inline void ircd::ctx::list::push(ctx *const &c) { push_back(c); } inline size_t ircd::ctx::list::size() const { size_t i{0}; for_each([&i](const ctx &) { ++i; }); return i; } inline bool ircd::ctx::list::empty() const { assert((!head && !tail) || (head && tail)); return !head; } inline ircd::ctx::ctx * ircd::ctx::list::back() { return tail; } inline ircd::ctx::ctx * ircd::ctx::list::front() { return head; } inline const ircd::ctx::ctx * ircd::ctx::list::back() const { return tail; } inline const ircd::ctx::ctx * ircd::ctx::list::front() const { return head; }