/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
#include
namespace ams::util {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
/* Forward declare implementation class for Node. */
namespace impl {
class IntrusiveListImpl;
}
class IntrusiveListNode {
NON_COPYABLE(IntrusiveListNode);
private:
friend class impl::IntrusiveListImpl;
IntrusiveListNode *m_prev;
IntrusiveListNode *m_next;
public:
constexpr ALWAYS_INLINE IntrusiveListNode() : m_prev(this), m_next(this) { /* ... */ }
constexpr ALWAYS_INLINE bool IsLinked() const {
return m_next != this;
}
private:
ALWAYS_INLINE void LinkPrev(IntrusiveListNode *node) {
/* We can't link an already linked node. */
AMS_ASSERT(!node->IsLinked());
this->SplicePrev(node, node);
}
ALWAYS_INLINE void SplicePrev(IntrusiveListNode *first, IntrusiveListNode *last) {
/* Splice a range into the list. */
auto last_prev = last->m_prev;
first->m_prev = m_prev;
last_prev->m_next = this;
m_prev->m_next = first;
m_prev = last_prev;
}
ALWAYS_INLINE void LinkNext(IntrusiveListNode *node) {
/* We can't link an already linked node. */
AMS_ASSERT(!node->IsLinked());
return this->SpliceNext(node, node);
}
ALWAYS_INLINE void SpliceNext(IntrusiveListNode *first, IntrusiveListNode *last) {
/* Splice a range into the list. */
auto last_prev = last->m_prev;
first->m_prev = this;
last_prev->m_next = m_next;
m_next->m_prev = last_prev;
m_next = first;
}
ALWAYS_INLINE void Unlink() {
this->Unlink(m_next);
}
ALWAYS_INLINE void Unlink(IntrusiveListNode *last) {
/* Unlink a node from a next node. */
auto last_prev = last->m_prev;
m_prev->m_next = last;
last->m_prev = m_prev;
last_prev->m_next = this;
m_prev = last_prev;
}
ALWAYS_INLINE IntrusiveListNode *GetPrev() {
return m_prev;
}
ALWAYS_INLINE const IntrusiveListNode *GetPrev() const {
return m_prev;
}
ALWAYS_INLINE IntrusiveListNode *GetNext() {
return m_next;
}
ALWAYS_INLINE const IntrusiveListNode *GetNext() const {
return m_next;
}
};
/* DEPRECATED: static_assert(std::is_literal_type::value); */
namespace impl {
class IntrusiveListImpl {
NON_COPYABLE(IntrusiveListImpl);
private:
IntrusiveListNode m_root_node;
public:
template
class Iterator;
using value_type = IntrusiveListNode;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type *;
using const_pointer = const value_type *;
using reference = value_type &;
using const_reference = const value_type &;
using iterator = Iterator;
using const_iterator = Iterator;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
template
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveListImpl::value_type;
using difference_type = typename IntrusiveListImpl::difference_type;
using pointer = typename std::conditional::type;
using reference = typename std::conditional::type;
private:
pointer m_node;
public:
ALWAYS_INLINE explicit Iterator(pointer n) : m_node(n) { /* ... */ }
ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return m_node == rhs.m_node;
}
ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs);
}
ALWAYS_INLINE pointer operator->() const {
return m_node;
}
ALWAYS_INLINE reference operator*() const {
return *m_node;
}
ALWAYS_INLINE Iterator &operator++() {
m_node = m_node->m_next;
return *this;
}
ALWAYS_INLINE Iterator &operator--() {
m_node = m_node->m_prev;
return *this;
}
ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
ALWAYS_INLINE operator Iterator() const {
return Iterator(m_node);
}
ALWAYS_INLINE Iterator GetNonConstIterator() const {
return Iterator(const_cast(m_node));
}
};
public:
constexpr ALWAYS_INLINE IntrusiveListImpl() : m_root_node() { /* ... */ }
/* Iterator accessors. */
ALWAYS_INLINE iterator begin() {
return iterator(m_root_node.GetNext());
}
ALWAYS_INLINE const_iterator begin() const {
return const_iterator(m_root_node.GetNext());
}
ALWAYS_INLINE iterator end() {
return iterator(std::addressof(m_root_node));
}
ALWAYS_INLINE const_iterator end() const {
return const_iterator(std::addressof(m_root_node));
}
ALWAYS_INLINE iterator iterator_to(reference v) {
/* Only allow iterator_to for values in lists. */
AMS_ASSERT(v.IsLinked());
return iterator(std::addressof(v));
}
ALWAYS_INLINE const_iterator iterator_to(const_reference v) const {
/* Only allow iterator_to for values in lists. */
AMS_ASSERT(v.IsLinked());
return const_iterator(std::addressof(v));
}
/* Content management. */
ALWAYS_INLINE bool empty() const {
return !m_root_node.IsLinked();
}
ALWAYS_INLINE size_type size() const {
return static_cast(std::distance(this->begin(), this->end()));
}
ALWAYS_INLINE reference back() {
return *m_root_node.GetPrev();
}
ALWAYS_INLINE const_reference back() const {
return *m_root_node.GetPrev();
}
ALWAYS_INLINE reference front() {
return *m_root_node.GetNext();
}
ALWAYS_INLINE const_reference front() const {
return *m_root_node.GetNext();
}
ALWAYS_INLINE void push_back(reference node) {
m_root_node.LinkPrev(std::addressof(node));
}
ALWAYS_INLINE void push_front(reference node) {
m_root_node.LinkNext(std::addressof(node));
}
ALWAYS_INLINE void pop_back() {
m_root_node.GetPrev()->Unlink();
}
ALWAYS_INLINE void pop_front() {
m_root_node.GetNext()->Unlink();
}
ALWAYS_INLINE iterator insert(const_iterator pos, reference node) {
pos.GetNonConstIterator()->LinkPrev(std::addressof(node));
return iterator(std::addressof(node));
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o) {
splice_impl(pos, o.begin(), o.end());
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first) {
AMS_UNUSED(o);
const_iterator last(first);
std::advance(last, 1);
splice_impl(pos, first, last);
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first, const_iterator last) {
AMS_UNUSED(o);
splice_impl(pos, first, last);
}
ALWAYS_INLINE iterator erase(const_iterator pos) {
if (pos == this->end()) {
return this->end();
}
iterator it(pos.GetNonConstIterator());
(it++)->Unlink();
return it;
}
ALWAYS_INLINE void clear() {
while (!this->empty()) {
this->pop_front();
}
}
private:
ALWAYS_INLINE void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
if (_first == _last) {
return;
}
iterator pos(_pos.GetNonConstIterator());
iterator first(_first.GetNonConstIterator());
iterator last(_last.GetNonConstIterator());
first->Unlink(std::addressof(*last));
pos->SplicePrev(std::addressof(*first), std::addressof(*first));
}
};
}
template
class IntrusiveList {
NON_COPYABLE(IntrusiveList);
private:
impl::IntrusiveListImpl m_impl;
public:
template
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type *;
using const_pointer = const value_type *;
using reference = value_type &;
using const_reference = const value_type &;
using iterator = Iterator;
using const_iterator = Iterator;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
template
class Iterator {
public:
friend class ams::util::IntrusiveList;
using ImplIterator = typename std::conditional::type;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveList::value_type;
using difference_type = typename IntrusiveList::difference_type;
using pointer = typename std::conditional::type;
using reference = typename std::conditional::type;
private:
ImplIterator m_iterator;
private:
explicit ALWAYS_INLINE Iterator(ImplIterator it) : m_iterator(it) { /* ... */ }
ALWAYS_INLINE ImplIterator GetImplIterator() const {
return m_iterator;
}
public:
ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return m_iterator == rhs.m_iterator;
}
ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs);
}
ALWAYS_INLINE pointer operator->() const {
return std::addressof(Traits::GetParent(*m_iterator));
}
ALWAYS_INLINE reference operator*() const {
return Traits::GetParent(*m_iterator);
}
ALWAYS_INLINE Iterator &operator++() {
++m_iterator;
return *this;
}
ALWAYS_INLINE Iterator &operator--() {
--m_iterator;
return *this;
}
ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this};
++m_iterator;
return it;
}
ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this};
--m_iterator;
return it;
}
ALWAYS_INLINE operator Iterator() const {
return Iterator(m_iterator);
}
};
private:
static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(reference ref) {
return Traits::GetNode(ref);
}
static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(const_reference ref) {
return Traits::GetNode(ref);
}
static constexpr ALWAYS_INLINE reference GetParent(IntrusiveListNode &node) {
return Traits::GetParent(node);
}
static constexpr ALWAYS_INLINE const_reference GetParent(IntrusiveListNode const &node) {
return Traits::GetParent(node);
}
public:
constexpr ALWAYS_INLINE IntrusiveList() : m_impl() { /* ... */ }
/* Iterator accessors. */
ALWAYS_INLINE iterator begin() {
return iterator(m_impl.begin());
}
ALWAYS_INLINE const_iterator begin() const {
return const_iterator(m_impl.begin());
}
ALWAYS_INLINE iterator end() {
return iterator(m_impl.end());
}
ALWAYS_INLINE const_iterator end() const {
return const_iterator(m_impl.end());
}
ALWAYS_INLINE const_iterator cbegin() const {
return this->begin();
}
ALWAYS_INLINE const_iterator cend() const {
return this->end();
}
ALWAYS_INLINE reverse_iterator rbegin() {
return reverse_iterator(this->end());
}
ALWAYS_INLINE const_reverse_iterator rbegin() const {
return const_reverse_iterator(this->end());
}
ALWAYS_INLINE reverse_iterator rend() {
return reverse_iterator(this->begin());
}
ALWAYS_INLINE const_reverse_iterator rend() const {
return const_reverse_iterator(this->begin());
}
ALWAYS_INLINE const_reverse_iterator crbegin() const {
return this->rbegin();
}
ALWAYS_INLINE const_reverse_iterator crend() const {
return this->rend();
}
ALWAYS_INLINE iterator iterator_to(reference v) {
return iterator(m_impl.iterator_to(GetNode(v)));
}
ALWAYS_INLINE const_iterator iterator_to(const_reference v) const {
return const_iterator(m_impl.iterator_to(GetNode(v)));
}
/* Content management. */
ALWAYS_INLINE bool empty() const {
return m_impl.empty();
}
ALWAYS_INLINE size_type size() const {
return m_impl.size();
}
ALWAYS_INLINE reference back() {
AMS_ASSERT(!m_impl.empty());
return GetParent(m_impl.back());
}
ALWAYS_INLINE const_reference back() const {
AMS_ASSERT(!m_impl.empty());
return GetParent(m_impl.back());
}
ALWAYS_INLINE reference front() {
AMS_ASSERT(!m_impl.empty());
return GetParent(m_impl.front());
}
ALWAYS_INLINE const_reference front() const {
AMS_ASSERT(!m_impl.empty());
return GetParent(m_impl.front());
}
ALWAYS_INLINE void push_back(reference ref) {
m_impl.push_back(GetNode(ref));
}
ALWAYS_INLINE void push_front(reference ref) {
m_impl.push_front(GetNode(ref));
}
ALWAYS_INLINE void pop_back() {
AMS_ASSERT(!m_impl.empty());
m_impl.pop_back();
}
ALWAYS_INLINE void pop_front() {
AMS_ASSERT(!m_impl.empty());
m_impl.pop_front();
}
ALWAYS_INLINE iterator insert(const_iterator pos, reference ref) {
return iterator(m_impl.insert(pos.GetImplIterator(), GetNode(ref)));
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o) {
m_impl.splice(pos.GetImplIterator(), o.m_impl);
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o, const_iterator first) {
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator());
}
ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o, const_iterator first, const_iterator last) {
m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator(), last.GetImplIterator());
}
ALWAYS_INLINE iterator erase(const_iterator pos) {
return iterator(m_impl.erase(pos.GetImplIterator()));
}
ALWAYS_INLINE void clear() {
m_impl.clear();
}
};
template>
class IntrusiveListMemberTraits;
template
class IntrusiveListMemberTraits {
public:
using ListType = IntrusiveList;
private:
friend class IntrusiveList;
static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return parent.*Member;
}
static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return parent.*Member;
}
static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return util::GetParentReference(std::addressof(node));
}
static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return util::GetParentReference(std::addressof(node));
}
private:
static constexpr TypedStorage DerivedStorage = {};
static_assert(std::addressof(GetParent(GetNode(GetReference(DerivedStorage)))) == GetPointer(DerivedStorage));
};
template>
class IntrusiveListMemberTraitsDeferredAssert;
template
class IntrusiveListMemberTraitsDeferredAssert {
public:
using ListType = IntrusiveList;
static constexpr bool IsValid() {
TypedStorage DerivedStorage = {};
return std::addressof(GetParent(GetNode(GetReference(DerivedStorage)))) == GetPointer(DerivedStorage);
}
private:
friend class IntrusiveList;
static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return parent.*Member;
}
static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return parent.*Member;
}
static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return util::GetParentReference(std::addressof(node));
}
static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return util::GetParentReference(std::addressof(node));
}
};
template
class IntrusiveListBaseNode : public IntrusiveListNode{};
template
class IntrusiveListBaseTraits {
public:
using ListType = IntrusiveList;
private:
friend class IntrusiveList;
static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return static_cast(parent);
}
static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return static_cast(parent);
}
static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return static_cast(node);
}
static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return static_cast(node);
}
};
#pragma GCC pop_options
}