mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
Fix KLinkedList; make it work even with strict aliasing
This commit is contained in:
parent
4078c9a07d
commit
cfeebbd1c9
1 changed files with 201 additions and 145 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <mesosphere/core/util.h>
|
||||||
#include <mesosphere/interfaces/ISlabAllocated.hpp>
|
#include <mesosphere/interfaces/ISlabAllocated.hpp>
|
||||||
|
|
||||||
namespace mesosphere
|
namespace mesosphere
|
||||||
|
@ -15,31 +16,50 @@ template<typename T>
|
||||||
class KLinkedList final {
|
class KLinkedList final {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct List {
|
|
||||||
Node *last;
|
struct List final {
|
||||||
Node *first;
|
struct Node final : public ISlabAllocated<Node> {
|
||||||
size_t size = 0;
|
|
||||||
|
struct Link final {
|
||||||
|
Link *prev = nullptr;
|
||||||
|
Link *next = nullptr;
|
||||||
|
|
||||||
|
Node &parent()
|
||||||
|
{
|
||||||
|
return *detail::GetParentFromMember(this, &Node::link);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node &parent() const
|
||||||
|
{
|
||||||
|
return *detail::GetParentFromMember(this, &Node::link);
|
||||||
|
}
|
||||||
|
|
||||||
|
T &data() { return parent().data; }
|
||||||
|
const T &data() const { return parent().data; }
|
||||||
};
|
};
|
||||||
|
|
||||||
List list;
|
Link link{};
|
||||||
|
|
||||||
struct Node final : public ISlabAllocated<Node> {
|
|
||||||
//friend class KLinkedList;
|
|
||||||
Node *prev = nullptr;
|
|
||||||
Node *next = nullptr;
|
|
||||||
T data{};
|
T data{};
|
||||||
|
|
||||||
Node() = default;
|
Node() = default;
|
||||||
Node(const Node &other) = default;
|
Node(const Node &other) = default;
|
||||||
Node(Node &&other) = default;
|
Node(Node &&other) = default;
|
||||||
explicit Node(const T &data) : Node(), data{other} {}
|
explicit Node(const T &data) : ISlabAllocated<Node>(), data{data} {}
|
||||||
explicit Node(const T &&data) : Node(), data{other} {}
|
explicit Node(const T &&data) : ISlabAllocated<Node>(), data{data} {}
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
explicit Node(Args&& ...args) : Node(), data{std::forward<Args>(args)...} {}
|
explicit Node(Args&& ...args) : ISlabAllocated<Node>(), data{std::forward<Args>(args)...} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mutable typename Node::Link link{};
|
||||||
|
typename Node::Link *last() const { return link.prev; }
|
||||||
|
typename Node::Link *first() const { return link.next; }
|
||||||
|
|
||||||
void insert_node_after(Node *pos, Node *nd)
|
size_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
List list;
|
||||||
|
|
||||||
|
void insert_node_after(typename List::Node::Link *pos, typename List::Node::Link *nd)
|
||||||
{
|
{
|
||||||
// if pos is last & list is empty, ->next writes to first, etc.
|
// if pos is last & list is empty, ->next writes to first, etc.
|
||||||
pos->next->prev = nd;
|
pos->next->prev = nd;
|
||||||
|
@ -49,7 +69,7 @@ class KLinkedList final {
|
||||||
++list.size;
|
++list.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_node_before(Node *pos, Node *nd)
|
void insert_node_before(typename List::Node::Link *pos, typename List::Node::Link *nd)
|
||||||
{
|
{
|
||||||
pos->prev->next = nd;
|
pos->prev->next = nd;
|
||||||
nd->prev = pos->prev;
|
nd->prev = pos->prev;
|
||||||
|
@ -58,7 +78,7 @@ class KLinkedList final {
|
||||||
++list.size;
|
++list.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_node(Node *nd)
|
void remove_node(typename List::Node::Link *nd)
|
||||||
{
|
{
|
||||||
nd->prev->next = nd->next;
|
nd->prev->next = nd->next;
|
||||||
nd->next->prev = nd->prev;
|
nd->next->prev = nd->prev;
|
||||||
|
@ -95,12 +115,12 @@ class KLinkedList final {
|
||||||
|
|
||||||
reference operator*()
|
reference operator*()
|
||||||
{
|
{
|
||||||
return node->data;
|
return node->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer operator->()
|
pointer operator->()
|
||||||
{
|
{
|
||||||
return &node->data;
|
return &node->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator &operator++()
|
Iterator &operator++()
|
||||||
|
@ -135,13 +155,15 @@ class KLinkedList final {
|
||||||
private:
|
private:
|
||||||
friend class KLinkedList;
|
friend class KLinkedList;
|
||||||
|
|
||||||
KLinkedList::Node *node;
|
typename KLinkedList::List::Node::Link *node;
|
||||||
|
|
||||||
explicit Iterator(KLinkedList::Node *node) : node{node} {}
|
explicit Iterator(typename KLinkedList::List::Node::Link *node) : node{node} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using pointer = T *;
|
using pointer = T *;
|
||||||
using const_pointer = const T *;
|
using const_pointer = const T *;
|
||||||
|
using reference = T &;
|
||||||
|
using const_reference = const T &;
|
||||||
using void_pointer = void *;
|
using void_pointer = void *;
|
||||||
using const_void_ptr = const void *;
|
using const_void_ptr = const void *;
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
@ -152,41 +174,42 @@ class KLinkedList final {
|
||||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
KLinkedList() : list{(Node *)&list, (Node *)&list} {};
|
KLinkedList() : list{{&list.link, &list.link}} {};
|
||||||
explicit KLinkedList(size_t count, const T &value) : KLinkedList()
|
explicit KLinkedList(size_t count, const T &value) : KLinkedList()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit KLinkedList(size_t count) : KLinkedList()
|
explicit KLinkedList(size_t count) : KLinkedList()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
Node *nd = new Node;
|
auto *nd = new typename List::Node;
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
|
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
|
||||||
explicit KLinkedList(InputIt first, InputIt last) : KLinkedList()
|
KLinkedList(InputIt first, InputIt last) : KLinkedList()
|
||||||
{
|
{
|
||||||
for (InputIt it = first; it != last; ++it) {
|
for (InputIt it = first; it != last; ++it) {
|
||||||
Node *nd = new Node{*it};
|
auto *nd = new typename List::Node{*it};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(KLinkedList &other) noexcept
|
void swap(KLinkedList &other) noexcept
|
||||||
{
|
{
|
||||||
using std::swap; // Enable ADL
|
using std::swap; // Enable ADL
|
||||||
swap(list.first, other.list.first);
|
swap(list.link, other.list.link);
|
||||||
swap(list.last, other.list.last);
|
|
||||||
swap(list.size, other.list.size);
|
swap(list.size, other.list.size);
|
||||||
|
list.first()->prev = list.last()->next = &list.link;
|
||||||
|
other.list.first()->prev = other.list.last()->next = &other.list.link;
|
||||||
}
|
}
|
||||||
|
|
||||||
KLinkedList(KLinkedList &&other) noexcept : KLinkedList()
|
KLinkedList(KLinkedList &&other) noexcept : KLinkedList()
|
||||||
|
@ -197,10 +220,10 @@ class KLinkedList final {
|
||||||
|
|
||||||
void clear() noexcept
|
void clear() noexcept
|
||||||
{
|
{
|
||||||
Node *nxt;
|
typename List::Node::Link *nxt;
|
||||||
for (Node nd = list.first; nd != (Node *)&list; nd = nxt) {
|
for (typename List::Node::Link *nd = list.first(); nd != &list.link; nd = nxt) {
|
||||||
nxt = nd->next;
|
nxt = nd->next;
|
||||||
delete nd;
|
delete &nd->parent();
|
||||||
}
|
}
|
||||||
list.size = 0;
|
list.size = 0;
|
||||||
}
|
}
|
||||||
|
@ -212,59 +235,59 @@ class KLinkedList final {
|
||||||
|
|
||||||
KLinkedList &operator=(KLinkedList other)
|
KLinkedList &operator=(KLinkedList other)
|
||||||
{
|
{
|
||||||
swap(*this, other);
|
swap(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
KLinkedList &operator=(std::initializer_list<T> ilist)
|
KLinkedList &operator=(std::initializer_list<T> ilist)
|
||||||
{
|
{
|
||||||
KLinkedList tmp{ilist};
|
KLinkedList tmp{ilist};
|
||||||
swap(*this, tmp);
|
swap(tmp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign(size_t count, const T &value)
|
void assign(size_t count, const T &value)
|
||||||
{
|
{
|
||||||
KLinkedList tmp{count, value};
|
KLinkedList tmp{count, value};
|
||||||
swap(*this, tmp);
|
swap(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
|
template<typename InputIt, typename = std::enable_if_t<!std::is_integral_v<InputIt>>>
|
||||||
void assign(InputIt first, InputIt last)
|
void assign(InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
KLinkedList tmp{first, last};
|
KLinkedList tmp{first, last};
|
||||||
swap(*this, tmp);
|
swap(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign(std::initializer_list<T> ilist)
|
void assign(std::initializer_list<T> ilist)
|
||||||
{
|
{
|
||||||
KLinkedList tmp{ilist};
|
KLinkedList tmp{ilist};
|
||||||
swap(*this, tmp);
|
swap(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
T &front() { return list.first->data; }
|
T &front() { return list.first()->data(); }
|
||||||
const T &front() const { return list.first->data; }
|
const T &front() const { return list.first()->data(); }
|
||||||
|
|
||||||
T &back() { return list.last->data; }
|
T &back() { return list.last()->data(); }
|
||||||
const T &back(); const { return list.last->data; }
|
const T &back() const { return list.last()->data(); }
|
||||||
|
|
||||||
const_iterator cbegin() const noexcept { return const_iterator{list.first}; }
|
const_iterator cbegin() const noexcept { return const_iterator{list.first()}; }
|
||||||
const_iterator cend() const noexcept { return const_iterator{(Node *)&list}; }
|
const_iterator cend() const noexcept { return const_iterator{&list.link}; }
|
||||||
|
|
||||||
const_iterator begin() const noexcept { return cbegin(); }
|
const_iterator begin() const noexcept { return cbegin(); }
|
||||||
const_iterator end() const noexcept { return cend(); }
|
const_iterator end() const noexcept { return cend(); }
|
||||||
|
|
||||||
iterator begin() noexcept { return iterator{list.first}; }
|
iterator begin() noexcept { return iterator{list.first()}; }
|
||||||
iterator end() noexcept { return iterator{(Node *)&list}; }
|
iterator end() noexcept { return iterator{&list.link}; }
|
||||||
|
|
||||||
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{list.last}; }
|
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{list.last()}; }
|
||||||
const_reverse_iterator crend() const noexcept { return const_reverse_iterator{(Node *)&list}; }
|
const_reverse_iterator crend() const noexcept { return const_reverse_iterator{&list.link}; }
|
||||||
|
|
||||||
const_reverse_iterator rbegin() const noexcept { return crbegin(); }
|
const_reverse_iterator rbegin() const noexcept { return crbegin(); }
|
||||||
const_reverse_iterator rend() const noexcept { return crend(); }
|
const_reverse_iterator rend() const noexcept { return crend(); }
|
||||||
|
|
||||||
reverse_iterator rbegin() const noexcept { return reverse_iterator{list.last}; }
|
reverse_iterator rbegin() noexcept { return reverse_iterator{list.last()}; }
|
||||||
reverse_iterator rend() const noexcept { return reverse_iterator{(Node *)&list}; }
|
reverse_iterator rend() noexcept { return reverse_iterator{&list.link}; }
|
||||||
|
|
||||||
KLinkedList(const KLinkedList &other) : KLinkedList(other.cbegin(), other.cend()) {}
|
KLinkedList(const KLinkedList &other) : KLinkedList(other.cbegin(), other.cend()) {}
|
||||||
|
|
||||||
|
@ -273,17 +296,17 @@ class KLinkedList final {
|
||||||
|
|
||||||
iterator insert(const_iterator pos, const T &value)
|
iterator insert(const_iterator pos, const T &value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(pos.node, nd);
|
insert_node_after(pos.node, &nd->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert(const_iterator pos, T &&value)
|
iterator insert(const_iterator pos, T &&value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_before(pos.node, nd);
|
insert_node_before(pos.node, &nd->link);
|
||||||
return iterator{nd};
|
return iterator{&nd->link};
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert(const_iterator pos, size_t count, const T &value)
|
iterator insert(const_iterator pos, size_t count, const T &value)
|
||||||
|
@ -299,33 +322,38 @@ class KLinkedList final {
|
||||||
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
iterator insert(const_iterator pos, InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
// Note: our list definition allows --begin() to be well defined
|
// Note: our list definition allows --begin() to be well defined
|
||||||
Node *f = nullptr;
|
typename List::Node::Link *f = nullptr;
|
||||||
Node *p = pos.node->prev;
|
typename List::Node::Link *p = pos.node->prev;
|
||||||
for(InputIt it = first; it != last; ++it) {
|
for(InputIt it = first; it != last; ++it) {
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{*it};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(p, nd);
|
insert_node_after(p, &nd->link);
|
||||||
p = nd;
|
p = &nd->link;
|
||||||
f = f == nullptr ? nd : f;
|
f = f == nullptr ? p : f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iterator{f};
|
return iterator{f};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator insert(const_iterator pos, std::initializer_list<T> ilist)
|
||||||
|
{
|
||||||
|
return insert(pos, ilist.begin(), ilist.end());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
iterator emplace(const_iterator pos, Args &&...args)
|
iterator emplace(const_iterator pos, Args &&...args)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{std::forward<Args>(args)...};
|
auto *nd = new typename List::Node{std::forward<Args>(args)...};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_before(pos.node, nd);
|
insert_node_before(pos.node, &nd->link);
|
||||||
return iterator{nd};
|
return iterator{&nd->link};
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator erase(const_iterator pos)
|
iterator erase(const_iterator pos)
|
||||||
{
|
{
|
||||||
iterator ret{pos->next};
|
iterator ret{pos.node->next};
|
||||||
remove_node(pos.node);
|
remove_node(pos.node);
|
||||||
delete pos.node;
|
delete &pos.node->parent();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,59 +368,62 @@ class KLinkedList final {
|
||||||
|
|
||||||
void push_back(const T &value)
|
void push_back(const T &value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T &&value)
|
void push_back(T &&value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class... Args>
|
template< class... Args>
|
||||||
T &emplace_back(Args&&... args)
|
T &emplace_back(Args&&... args)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{std::forward<Args>(args)...};
|
auto *nd = new typename List::Node{std::forward<Args>(args)...};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
return nd->data;
|
return nd->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_back()
|
void pop_back()
|
||||||
{
|
{
|
||||||
remove_node(list.last);
|
auto *nd = list.last();
|
||||||
delete list.last;
|
remove_node(nd);
|
||||||
|
delete &nd->parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_front(const T &value)
|
void push_front(const T &value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_before(list.first, nd);
|
insert_node_before(list.first(), &nd->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_front(T &&value)
|
void push_front(T &&value)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{value};
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_before(list.first, nd);
|
insert_node_before(list.first(), &nd->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class... Args>
|
template< class... Args>
|
||||||
T &emplace_front(Args&&... args)
|
T &emplace_front(Args&&... args)
|
||||||
{
|
{
|
||||||
Node *nd = new Node{std::forward<Args>(args)...};
|
auto *nd = new typename List::Node{std::forward<Args>(args)...};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_before(list.first, nd);
|
insert_node_before(list.first(), &nd->link);
|
||||||
return nd->data;
|
return nd->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_front()
|
void pop_front()
|
||||||
{
|
{
|
||||||
remove_node(list.first);
|
auto *nd = list.first();
|
||||||
|
remove_node(nd);
|
||||||
|
delete &nd->parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(size_t count)
|
void resize(size_t count)
|
||||||
|
@ -402,10 +433,11 @@ class KLinkedList final {
|
||||||
pop_back();
|
pop_back();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < count - list.size; i++) {
|
size_t s = list.size;
|
||||||
Node *nd = new Node;
|
for (size_t i = 0; i < count - s; i++) {
|
||||||
|
auto *nd = new typename List::Node;
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,26 +449,33 @@ class KLinkedList final {
|
||||||
pop_back();
|
pop_back();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < count - list.size; i++) {
|
size_t s = list.size;
|
||||||
Node *nd = new Node{value};
|
for (size_t i = 0; i < count - s; i++) {
|
||||||
|
auto *nd = new typename List::Node{value};
|
||||||
kassert(nd != nullptr);
|
kassert(nd != nullptr);
|
||||||
insert_node_after(list.last, nd);
|
insert_node_after(list.last(), &nd->link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void splice(const_iterator pos, KLinkedList &&other)
|
void splice(const_iterator pos, KLinkedList &&other)
|
||||||
{
|
{
|
||||||
Node *before = pos.node->prev;
|
//auto *current = pos.node;
|
||||||
Node *after = pos.node->next;
|
auto *before = pos.node->prev;
|
||||||
before->next = other.list.first;
|
auto *after = pos.node; //current == &list.link ? current : pos.node->next;
|
||||||
|
before->next = other.list.first();
|
||||||
before->next->prev = before;
|
before->next->prev = before;
|
||||||
after->prev = other.list.last;
|
after->prev = other.list.last();
|
||||||
after->prev->next = after;
|
after->prev->next = after;
|
||||||
|
|
||||||
list.size += other.list.size;
|
list.size += other.list.size;
|
||||||
other.list.size = 0;
|
other.list.size = 0;
|
||||||
other.list.first = other.list.last = (Node *)&other.list;
|
other.list.link.prev = other.list.link.next = &other.list.link;
|
||||||
|
}
|
||||||
|
|
||||||
|
void splice(const_iterator pos, KLinkedList &other)
|
||||||
|
{
|
||||||
|
splice(pos, std::move(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
void splice(const_iterator pos, KLinkedList &&other, const_iterator it)
|
void splice(const_iterator pos, KLinkedList &&other, const_iterator it)
|
||||||
|
@ -445,11 +484,17 @@ class KLinkedList final {
|
||||||
insert_node_before(pos.node, it.node);
|
insert_node_before(pos.node, it.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splice(const_iterator pos, KLinkedList &other, const_iterator it)
|
||||||
|
{
|
||||||
|
splice(pos, std::move(other), it);
|
||||||
|
}
|
||||||
|
|
||||||
void splice(const_iterator pos, KLinkedList &&other, const_iterator first, const_iterator last)
|
void splice(const_iterator pos, KLinkedList &&other, const_iterator first, const_iterator last)
|
||||||
{
|
{
|
||||||
if (*this == other) {
|
if (*this == other) {
|
||||||
Node *before = pos.node->prev;
|
auto *current = pos.node;
|
||||||
Node *after = pos.node->next;
|
auto *before = pos.node->prev;
|
||||||
|
auto *after = current == &list.link ? current : pos.node->next;
|
||||||
before->next = first.node;
|
before->next = first.node;
|
||||||
before->next->prev = before;
|
before->next->prev = before;
|
||||||
after->prev = last.node;
|
after->prev = last.node;
|
||||||
|
@ -466,6 +511,11 @@ class KLinkedList final {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splice(const_iterator pos, KLinkedList &other, const_iterator first, const_iterator last)
|
||||||
|
{
|
||||||
|
splice(pos, std::move(other), first, last);
|
||||||
|
}
|
||||||
|
|
||||||
size_t remove(const T &value)
|
size_t remove(const T &value)
|
||||||
{
|
{
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
@ -485,6 +535,7 @@ class KLinkedList final {
|
||||||
size_t remove_if(UnaryPredicate p)
|
size_t remove_if(UnaryPredicate p)
|
||||||
{
|
{
|
||||||
const_iterator next;
|
const_iterator next;
|
||||||
|
size_t n = 0;
|
||||||
for (const_iterator it = cbegin(); it != cend(); ) {
|
for (const_iterator it = cbegin(); it != cend(); ) {
|
||||||
if (p(*it)) {
|
if (p(*it)) {
|
||||||
it = erase(it);
|
it = erase(it);
|
||||||
|
@ -497,18 +548,18 @@ class KLinkedList final {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Compare>
|
template<typename Compare>
|
||||||
void merge(KLinkedList &other, Compare p)
|
void merge(KLinkedList &&other, Compare p)
|
||||||
{
|
{
|
||||||
Node hd{};
|
typename List::Node::Link hd{};
|
||||||
Node *cur = &hd;
|
auto *cur = &hd;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (list.size > 0 && other.list.size > 0) {
|
while (list.size > 0 && other.list.size > 0) {
|
||||||
if (p(list.first, other.list.first)) {
|
if (p(list.first()->data(), other.list.first()->data())) {
|
||||||
cur->next = list.first;
|
cur->next = list.first();
|
||||||
remove_node(list.first);
|
remove_node(list.first());
|
||||||
} else {
|
} else {
|
||||||
cur->next = other.list.first;
|
cur->next = other.list.first();
|
||||||
other.remove_node(other.list.first);
|
other.remove_node(other.list.first());
|
||||||
}
|
}
|
||||||
cur->next->prev = cur;
|
cur->next->prev = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
|
@ -517,75 +568,77 @@ class KLinkedList final {
|
||||||
|
|
||||||
// Steal the remaining elements
|
// Steal the remaining elements
|
||||||
if (list.size > 0) {
|
if (list.size > 0) {
|
||||||
cur->next = list.first;
|
cur->next = list.first();
|
||||||
list.first->prev = cur;
|
list.first()->prev = cur;
|
||||||
|
cur = list.last();
|
||||||
n += list.size;
|
n += list.size;
|
||||||
} else if (other.list.size > 0) {
|
} else if (other.list.size > 0) {
|
||||||
cur->next = other.list.first;
|
cur->next = other.list.first();
|
||||||
other.list.first->prev = cur;
|
other.list.first()->prev = cur;
|
||||||
|
cur = other.list.last();
|
||||||
n += other.list.size;
|
n += other.list.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Reset the other list to put it in a valid state
|
// Reset the other list to put it in a valid state
|
||||||
other.list.first = other.list.last = (Node *)other.list;
|
other.list.link.prev = other.list.link.next = &other.list.link;
|
||||||
other.list.size = 0;
|
other.list.size = 0;
|
||||||
|
|
||||||
// Finally, normalize the result and assign it to this
|
// Finally, normalize the result and assign it to this
|
||||||
list.first = hd.next;
|
list.link.next = hd.next;
|
||||||
list.last = cur;
|
list.link.prev = cur;
|
||||||
list.size = n;
|
list.size = n;
|
||||||
list.first->prev = list.last->next = (Node *)list;
|
list.first()->prev = list.last()->next = &list.link;
|
||||||
}
|
|
||||||
|
|
||||||
void merge(KLinkedList &other)
|
|
||||||
{
|
|
||||||
merge(other, std::less{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Compare>
|
|
||||||
void merge(KLinkedList &&other, Compare p)
|
|
||||||
{
|
|
||||||
KLinkedList &o = other;
|
|
||||||
merge(o, p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge(KLinkedList &&other)
|
void merge(KLinkedList &&other)
|
||||||
{
|
{
|
||||||
merge(other, std::less{});
|
merge(other, std::less<T>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Compare>
|
||||||
|
void merge(KLinkedList &other, Compare p)
|
||||||
|
{
|
||||||
|
merge(std::move(other), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge(KLinkedList &other)
|
||||||
|
{
|
||||||
|
merge(other, std::less<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void reverse() noexcept
|
void reverse() noexcept
|
||||||
{
|
{
|
||||||
Node hd{};
|
typename List::Node::Link hd{};
|
||||||
Node *cur = &hd;
|
auto *cur = &hd;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
while (list.size > 0) {
|
while (list.size > 0) {
|
||||||
cur->next = list.last;
|
cur->next = list.last();
|
||||||
remove_node(list.last);
|
remove_node(list.last());
|
||||||
cur->next->prev = cur;
|
cur->next->prev = cur;
|
||||||
n++;
|
n++;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
list.first = hd.next;
|
list.link.next = hd.next;
|
||||||
list.last = cur;
|
list.link.prev = cur;
|
||||||
list.size = n;
|
list.size = n;
|
||||||
list.first->prev = list.last->next = (Node *)list;
|
list.first()->prev = list.last()->next = &list.link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename BinaryPredicate>
|
template<typename BinaryPredicate>
|
||||||
size_t unique(BinaryPredicate p)
|
size_t unique(BinaryPredicate p)
|
||||||
{
|
{
|
||||||
Node *nxt;
|
typename List::Node::Link *nxt;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for (Node *nd = list.first; nd != (Node *)list; nd = nxt) {
|
for (auto *nd = list.first(); nd != &list.link; nd = nxt) {
|
||||||
nxt = nd->next;
|
nxt = nd->next;
|
||||||
for (Node *nd2 = nxt; nd2 != (Node *)list && p(nd->data, nd2->data); nd2 = nxt) {
|
for (auto *nd2 = nxt; nd2 != &list.link && p(nd->data(), nd2->data()); nd2 = nxt) {
|
||||||
nxt = nd2->next;
|
nxt = nd2->next;
|
||||||
remove_node(nd2);
|
remove_node(nd2);
|
||||||
delete nd2;
|
delete &nd2->parent();
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +648,7 @@ class KLinkedList final {
|
||||||
|
|
||||||
size_t unique()
|
size_t unique()
|
||||||
{
|
{
|
||||||
return unique(std::equal_to);
|
return unique(std::equal_to<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort: a PITA to implement and not needed anyway
|
// sort: a PITA to implement and not needed anyway
|
||||||
|
@ -612,22 +665,22 @@ class KLinkedList final {
|
||||||
|
|
||||||
friend bool operator<(const KLinkedList &lhs, const KLinkedList &rhs)
|
friend bool operator<(const KLinkedList &lhs, const KLinkedList &rhs)
|
||||||
{
|
{
|
||||||
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less{});
|
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator>(const KLinkedList &lhs, const KLinkedList &rhs)
|
friend bool operator>(const KLinkedList &lhs, const KLinkedList &rhs)
|
||||||
{
|
{
|
||||||
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater{});
|
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator<=(const KLinkedList &lhs, const KLinkedList &rhs)
|
friend bool operator<=(const KLinkedList &lhs, const KLinkedList &rhs)
|
||||||
{
|
{
|
||||||
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less_equal{});
|
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less_equal<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator>=(const KLinkedList &lhs, const KLinkedList &rhs)
|
friend bool operator>=(const KLinkedList &lhs, const KLinkedList &rhs)
|
||||||
{
|
{
|
||||||
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater_equal{});
|
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater_equal<T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
friend void swap(KLinkedList &lhs, KLinkedList &rhs)
|
friend void swap(KLinkedList &lhs, KLinkedList &rhs)
|
||||||
|
@ -637,4 +690,7 @@ class KLinkedList final {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename InputIt>
|
||||||
|
KLinkedList(InputIt b, InputIt e) -> KLinkedList<typename std::iterator_traits<InputIt>::value_type>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue