mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
utils: intrusive_list sorting functions
This commit is contained in:
@@ -109,6 +109,20 @@ namespace e2d
|
|||||||
swap_next(l, r);
|
swap_next(l, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void transfer_nodes(node_ptr p, node_ptr b, node_ptr e) noexcept {
|
||||||
|
if ( b != e ) {
|
||||||
|
node_ptr prev_p = p->prev_;
|
||||||
|
node_ptr prev_b = b->prev_;
|
||||||
|
node_ptr prev_e = e->prev_;
|
||||||
|
prev_e->next_ = p;
|
||||||
|
p->prev_ = prev_e;
|
||||||
|
prev_b->next_ = e;
|
||||||
|
e->prev_ = prev_b;
|
||||||
|
prev_p->next_ = b;
|
||||||
|
b->prev_ = prev_p;
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
node_ptr prev_{nullptr};
|
node_ptr prev_{nullptr};
|
||||||
node_ptr next_{nullptr};
|
node_ptr next_{nullptr};
|
||||||
@@ -252,15 +266,15 @@ namespace e2d
|
|||||||
void swap(intrusive_list& other) noexcept;
|
void swap(intrusive_list& other) noexcept;
|
||||||
|
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void clear_and_dispose(Disposer&& disposer);
|
void clear_and_dispose(Disposer disposer);
|
||||||
void clear() noexcept;
|
void clear() noexcept;
|
||||||
|
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void pop_back_and_dispose(Disposer&& disposer);
|
void pop_back_and_dispose(Disposer disposer);
|
||||||
void pop_back() noexcept;
|
void pop_back() noexcept;
|
||||||
|
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void pop_front_and_dispose(Disposer&& disposer);
|
void pop_front_and_dispose(Disposer disposer);
|
||||||
void pop_front() noexcept;
|
void pop_front() noexcept;
|
||||||
|
|
||||||
void push_back(T& v) noexcept;
|
void push_back(T& v) noexcept;
|
||||||
@@ -268,9 +282,20 @@ namespace e2d
|
|||||||
iterator insert(const_iterator pos, T& v) noexcept;
|
iterator insert(const_iterator pos, T& v) noexcept;
|
||||||
|
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
iterator erase_and_dispose(const_iterator pos, Disposer&& disposer);
|
iterator erase_and_dispose(const_iterator pos, Disposer disposer);
|
||||||
iterator erase(const_iterator pos) noexcept;
|
iterator erase(const_iterator pos) noexcept;
|
||||||
|
|
||||||
|
void splice(const_iterator pos, intrusive_list& x) noexcept;
|
||||||
|
void splice(const_iterator pos, const_iterator f, const_iterator e) noexcept;
|
||||||
|
|
||||||
|
template < typename Predicate >
|
||||||
|
void merge(intrusive_list& x, Predicate predicate);
|
||||||
|
void merge(intrusive_list& x);
|
||||||
|
|
||||||
|
template < typename Predicate >
|
||||||
|
void sort(Predicate predicate);
|
||||||
|
void sort();
|
||||||
|
|
||||||
static iterator iterator_to(T& v) noexcept;
|
static iterator iterator_to(T& v) noexcept;
|
||||||
static const_iterator iterator_to(const T& v) noexcept;
|
static const_iterator iterator_to(const T& v) noexcept;
|
||||||
|
|
||||||
@@ -408,7 +433,7 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T, typename Tag >
|
template < typename T, typename Tag >
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void intrusive_list<T,Tag>::clear_and_dispose(Disposer&& disposer) {
|
void intrusive_list<T,Tag>::clear_and_dispose(Disposer disposer) {
|
||||||
while ( !empty() ) {
|
while ( !empty() ) {
|
||||||
pop_back_and_dispose(disposer);
|
pop_back_and_dispose(disposer);
|
||||||
}
|
}
|
||||||
@@ -421,7 +446,7 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T, typename Tag >
|
template < typename T, typename Tag >
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void intrusive_list<T,Tag>::pop_back_and_dispose(Disposer&& disposer) {
|
void intrusive_list<T,Tag>::pop_back_and_dispose(Disposer disposer) {
|
||||||
E2D_ASSERT(!empty());
|
E2D_ASSERT(!empty());
|
||||||
node_ptr node = root_.prev_;
|
node_ptr node = root_.prev_;
|
||||||
node->unlink();
|
node->unlink();
|
||||||
@@ -435,7 +460,7 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T, typename Tag >
|
template < typename T, typename Tag >
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
void intrusive_list<T,Tag>::pop_front_and_dispose(Disposer&& disposer) {
|
void intrusive_list<T,Tag>::pop_front_and_dispose(Disposer disposer) {
|
||||||
E2D_ASSERT(!empty());
|
E2D_ASSERT(!empty());
|
||||||
node_ptr node = root_.next_;
|
node_ptr node = root_.next_;
|
||||||
node->unlink();
|
node->unlink();
|
||||||
@@ -471,7 +496,7 @@ namespace e2d
|
|||||||
|
|
||||||
template < typename T, typename Tag >
|
template < typename T, typename Tag >
|
||||||
template < typename Disposer >
|
template < typename Disposer >
|
||||||
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::erase_and_dispose(const_iterator pos, Disposer&& disposer) {
|
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::erase_and_dispose(const_iterator pos, Disposer disposer) {
|
||||||
node_ptr node = pos.node();
|
node_ptr node = pos.node();
|
||||||
E2D_ASSERT(node != &root_ && node->is_linked());
|
E2D_ASSERT(node != &root_ && node->is_linked());
|
||||||
++pos;
|
++pos;
|
||||||
@@ -485,6 +510,70 @@ namespace e2d
|
|||||||
return erase_and_dispose(pos, null_disposer());
|
return erase_and_dispose(pos, null_disposer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
void intrusive_list<T,Tag>::splice(const_iterator pos, intrusive_list& x) noexcept {
|
||||||
|
intrusive_list_hook<Tag>::transfer_nodes(pos.node(), x.begin().node(), x.end().node());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
void intrusive_list<T,Tag>::splice(const_iterator pos, const_iterator f, const_iterator e) noexcept {
|
||||||
|
intrusive_list_hook<Tag>::transfer_nodes(pos.node(), f.node(), e.node());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
template < typename Predicate >
|
||||||
|
void intrusive_list<T,Tag>::merge(intrusive_list& x, Predicate predicate) {
|
||||||
|
const_iterator b(cbegin()), e(cend()), ex(x.cend());
|
||||||
|
while ( !x.empty() ) {
|
||||||
|
const_iterator ix(x.cbegin());
|
||||||
|
while ( b != e && !predicate(*ix, *b) ) {
|
||||||
|
++b;
|
||||||
|
}
|
||||||
|
if ( b == e ) {
|
||||||
|
splice(e, x);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
++ix;
|
||||||
|
} while ( ix != ex && predicate(*ix, *b) );
|
||||||
|
splice(b, x.begin(), ix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
void intrusive_list<T,Tag>::merge(intrusive_list& x) {
|
||||||
|
merge(x, std::less<value_type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
template < typename Predicate >
|
||||||
|
void intrusive_list<T,Tag>::sort(Predicate predicate) {
|
||||||
|
if ( root_.next_ != &root_ && root_.next_ != root_.prev_ ) {
|
||||||
|
intrusive_list left_list;
|
||||||
|
intrusive_list right_list;
|
||||||
|
|
||||||
|
const_iterator mid(cbegin()), tail(cend());
|
||||||
|
while ( (mid != tail) && (++mid != tail) ) {
|
||||||
|
--tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
left_list.splice(left_list.cbegin(), cbegin(), mid);
|
||||||
|
right_list.splice(right_list.cbegin(), *this);
|
||||||
|
|
||||||
|
left_list.sort(predicate);
|
||||||
|
right_list.sort(predicate);
|
||||||
|
|
||||||
|
splice(cbegin(), left_list);
|
||||||
|
merge(right_list, predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T, typename Tag >
|
||||||
|
void intrusive_list<T,Tag>::sort() {
|
||||||
|
sort(std::less<value_type>());
|
||||||
|
}
|
||||||
|
|
||||||
template < typename T, typename Tag >
|
template < typename T, typename Tag >
|
||||||
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::iterator_to(T& v) noexcept {
|
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::iterator_to(T& v) noexcept {
|
||||||
node_t& node = static_cast<node_t&>(v);
|
node_t& node = static_cast<node_t&>(v);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include "_utils.hpp"
|
#include "_utils.hpp"
|
||||||
using namespace e2d;
|
using namespace e2d;
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct ilist_tag1 {};
|
struct ilist_tag1 {};
|
||||||
@@ -21,6 +23,10 @@ namespace
|
|||||||
obj_t() = default;
|
obj_t() = default;
|
||||||
obj_t(int ni) : i(ni) {}
|
obj_t(int ni) : i(ni) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator<(const obj_t& l, const obj_t& r) noexcept {
|
||||||
|
return l.i < r.i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("intrusive_list") {
|
TEST_CASE("intrusive_list") {
|
||||||
@@ -433,4 +439,36 @@ TEST_CASE("intrusive_list") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SECTION("sort") {
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 rnd(rd());
|
||||||
|
|
||||||
|
std::uniform_int_distribution<u32> uni_size(0, 1024);
|
||||||
|
std::uniform_int_distribution<i32> uni_number(-65536, 65535);
|
||||||
|
|
||||||
|
const auto pred = [](const obj_t& l, const obj_t& r) noexcept {
|
||||||
|
return l.i < r.i;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto r_pred = [](const obj_t& l, const obj_t& r) noexcept {
|
||||||
|
return l.i > r.i;
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( std::size_t i = 0; i < 1024; ++i ) {
|
||||||
|
vector<std::unique_ptr<obj_t>> objs;
|
||||||
|
intrusive_list<obj_t, ilist_tag1> l;
|
||||||
|
for ( u32 b = 0, e = uni_size(rnd); b < e; ++b ) {
|
||||||
|
objs.push_back(std::make_unique<obj_t>(uni_number(rnd)));
|
||||||
|
l.push_back(*objs.back());
|
||||||
|
}
|
||||||
|
l.sort();
|
||||||
|
REQUIRE(std::is_sorted(l.cbegin(), l.cend()));
|
||||||
|
l.sort(r_pred);
|
||||||
|
REQUIRE(std::is_sorted(l.cbegin(), l.cend(), r_pred));
|
||||||
|
l.sort(pred);
|
||||||
|
REQUIRE(std::is_sorted(l.cbegin(), l.cend(), pred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user