2018-02-04 03:22:01 +01:00
|
|
|
// Matrix Construct
|
|
|
|
//
|
2018-01-10 22:16:34 +01:00
|
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
2018-02-04 03:22:01 +01:00
|
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
2018-01-10 22:16:34 +01:00
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
2018-02-04 03:22:01 +01:00
|
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
|
|
// full license for this software is available in the LICENSE file.
|
2018-01-10 22:16:34 +01:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#define HAVE_IRCD_UTIL_INSTANCE_LIST_H
|
|
|
|
|
2019-06-23 10:01:26 +02:00
|
|
|
namespace ircd {
|
|
|
|
inline namespace util
|
2018-01-10 22:16:34 +01:00
|
|
|
{
|
|
|
|
template<class T> struct instance_list;
|
2019-06-23 10:01:26 +02:00
|
|
|
}}
|
2018-01-10 22:16:34 +01:00
|
|
|
|
|
|
|
/// The instance_list pattern is where every instance of a class registers
|
|
|
|
/// itself in a static list of all instances and removes itself on dtor.
|
|
|
|
/// IRCd Ex. All clients use instance_list so all clients can be listed for
|
|
|
|
/// an administrator or be interrupted and disconnected on server shutdown.
|
|
|
|
///
|
|
|
|
/// `struct myobj : ircd::instance_list<myobj> {};`
|
|
|
|
///
|
|
|
|
/// * The creator of the class no longer has to manually specify what is
|
|
|
|
/// defined here using unique_iterator; however, one still must provide
|
|
|
|
/// linkage for the static list.
|
|
|
|
///
|
|
|
|
/// * The container pointer used by unique_iterator is eliminated here
|
|
|
|
/// because of the static list.
|
|
|
|
///
|
|
|
|
template<class T>
|
|
|
|
struct ircd::util::instance_list
|
|
|
|
{
|
2019-04-20 01:35:50 +02:00
|
|
|
using allocator_state = ircd::allocator::node<T *>;
|
|
|
|
using allocator_type = typename allocator_state::allocator;
|
|
|
|
using list_type = std::list<T *, allocator_type>;
|
|
|
|
using list_node = typename list_type::iterator::_Node;
|
|
|
|
|
|
|
|
static allocator_state allocator;
|
|
|
|
static list_type list;
|
2018-01-10 22:16:34 +01:00
|
|
|
|
|
|
|
protected:
|
2019-04-20 01:35:50 +02:00
|
|
|
list_node node;
|
|
|
|
typename list_type::iterator it;
|
2018-01-10 22:16:34 +01:00
|
|
|
|
2018-05-07 01:39:28 +02:00
|
|
|
instance_list();
|
2018-09-02 05:45:04 +02:00
|
|
|
instance_list(instance_list &&) noexcept;
|
2018-05-07 07:18:05 +02:00
|
|
|
instance_list(const instance_list &);
|
2018-09-02 05:45:04 +02:00
|
|
|
instance_list &operator=(instance_list &&) noexcept;
|
2018-05-07 07:18:05 +02:00
|
|
|
instance_list &operator=(const instance_list &);
|
2018-05-07 01:39:28 +02:00
|
|
|
~instance_list() noexcept;
|
2018-01-10 22:16:34 +01:00
|
|
|
};
|
2018-05-07 01:39:28 +02:00
|
|
|
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wundefined-var-template"
|
|
|
|
#endif __clang__
|
2018-05-07 01:39:28 +02:00
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T>::instance_list()
|
2018-09-02 05:45:04 +02:00
|
|
|
{
|
2019-04-20 01:35:50 +02:00
|
|
|
const auto &address(reinterpret_cast<uint8_t *>(&node));
|
|
|
|
list.get_allocator().s->next = reinterpret_cast<T **>(address);
|
2019-04-17 05:48:00 +02:00
|
|
|
it = list.emplace(end(list), static_cast<T *>(this));
|
2019-04-20 02:42:34 +02:00
|
|
|
list.get_allocator().s->next = nullptr;
|
2018-09-02 05:45:04 +02:00
|
|
|
}
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif __clang__
|
2018-05-07 01:39:28 +02:00
|
|
|
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wundefined-var-template"
|
|
|
|
#endif __clang__
|
2018-05-07 07:18:05 +02:00
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T>::instance_list(instance_list &&other)
|
2018-09-02 05:45:04 +02:00
|
|
|
noexcept
|
|
|
|
{
|
2019-04-20 01:35:50 +02:00
|
|
|
const auto &address(reinterpret_cast<uint8_t *>(&node));
|
|
|
|
list.get_allocator().s->next = reinterpret_cast<T **>(address);
|
2019-04-17 05:48:00 +02:00
|
|
|
it = list.emplace(end(list), static_cast<T *>(this));
|
2019-04-20 02:42:34 +02:00
|
|
|
list.get_allocator().s->next = nullptr;
|
2018-09-02 05:45:04 +02:00
|
|
|
}
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif __clang__
|
2018-05-07 07:18:05 +02:00
|
|
|
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wundefined-var-template"
|
|
|
|
#endif __clang__
|
2018-05-07 07:18:05 +02:00
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T>::instance_list(const instance_list &other)
|
2018-09-02 05:45:04 +02:00
|
|
|
{
|
2019-04-20 01:35:50 +02:00
|
|
|
const auto &address(reinterpret_cast<uint8_t *>(&node));
|
|
|
|
list.get_allocator().s->next = reinterpret_cast<T **>(address);
|
2019-04-17 05:48:00 +02:00
|
|
|
it = list.emplace(end(list), static_cast<T *>(this));
|
2019-04-20 02:42:34 +02:00
|
|
|
list.get_allocator().s->next = nullptr;
|
2018-09-02 05:45:04 +02:00
|
|
|
}
|
2020-02-03 02:35:33 +01:00
|
|
|
#ifdef __clang__
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif __clang__
|
2018-05-07 07:18:05 +02:00
|
|
|
|
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T> &
|
|
|
|
ircd::util::instance_list<T>::operator=(instance_list &&other)
|
2018-09-02 05:45:04 +02:00
|
|
|
noexcept
|
2018-05-07 07:18:05 +02:00
|
|
|
{
|
|
|
|
assert(it != end(list));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T> &
|
|
|
|
ircd::util::instance_list<T>::operator=(const instance_list &other)
|
|
|
|
{
|
|
|
|
assert(it != end(list));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-05-07 01:39:28 +02:00
|
|
|
template<class T>
|
|
|
|
ircd::util::instance_list<T>::~instance_list()
|
|
|
|
noexcept
|
|
|
|
{
|
|
|
|
assert(it != end(list));
|
|
|
|
list.erase(it);
|
|
|
|
}
|