diff --git a/include/ircd/util.h b/include/ircd/util.h index 09bfa8e74..5ff691de0 100644 --- a/include/ircd/util.h +++ b/include/ircd/util.h @@ -1038,7 +1038,7 @@ end(const const_iterators &ci) // For objects using the pattern of adding their own instance to a container // in their constructor, storing an iterator as a member, and then removing // themselves using the iterator in their destructor. It is unsafe to do that. -// Use this instead. +// Use this instead; or better, use ircd::instance_list<> // template @@ -1090,6 +1090,58 @@ struct unique_const_iterator }; +/// 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 {};` +/// +/// * 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 +struct instance_list +{ + static std::list list; + + protected: + typename decltype(list)::iterator it; + + instance_list(typename decltype(list)::iterator it) + :it{std::move(it)} + {} + + instance_list() + :it{list.emplace(end(list), static_cast(this))} + {} + + instance_list(const instance_list &) = delete; + instance_list(instance_list &&o) noexcept + :it{std::move(o.it)} + { + o.it = end(list); + } + + instance_list &operator=(const instance_list &) = delete; + instance_list &operator=(instance_list &&o) noexcept + { + std::swap(it, o.it); + return *this; + } + + ~instance_list() noexcept + { + if(it != end(list)) + list.erase(it); + } +}; + + // // Get the index of a tuple element by address at runtime //