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);
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
node_ptr prev_{nullptr};
|
||||
node_ptr next_{nullptr};
|
||||
@@ -252,15 +266,15 @@ namespace e2d
|
||||
void swap(intrusive_list& other) noexcept;
|
||||
|
||||
template < typename Disposer >
|
||||
void clear_and_dispose(Disposer&& disposer);
|
||||
void clear_and_dispose(Disposer disposer);
|
||||
void clear() noexcept;
|
||||
|
||||
template < typename Disposer >
|
||||
void pop_back_and_dispose(Disposer&& disposer);
|
||||
void pop_back_and_dispose(Disposer disposer);
|
||||
void pop_back() noexcept;
|
||||
|
||||
template < typename Disposer >
|
||||
void pop_front_and_dispose(Disposer&& disposer);
|
||||
void pop_front_and_dispose(Disposer disposer);
|
||||
void pop_front() noexcept;
|
||||
|
||||
void push_back(T& v) noexcept;
|
||||
@@ -268,9 +282,20 @@ namespace e2d
|
||||
iterator insert(const_iterator pos, T& v) noexcept;
|
||||
|
||||
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;
|
||||
|
||||
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 const_iterator iterator_to(const T& v) noexcept;
|
||||
|
||||
@@ -408,7 +433,7 @@ namespace e2d
|
||||
|
||||
template < typename T, typename Tag >
|
||||
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() ) {
|
||||
pop_back_and_dispose(disposer);
|
||||
}
|
||||
@@ -421,7 +446,7 @@ namespace e2d
|
||||
|
||||
template < typename T, typename Tag >
|
||||
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());
|
||||
node_ptr node = root_.prev_;
|
||||
node->unlink();
|
||||
@@ -435,7 +460,7 @@ namespace e2d
|
||||
|
||||
template < typename T, typename Tag >
|
||||
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());
|
||||
node_ptr node = root_.next_;
|
||||
node->unlink();
|
||||
@@ -471,7 +496,7 @@ namespace e2d
|
||||
|
||||
template < typename T, typename Tag >
|
||||
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();
|
||||
E2D_ASSERT(node != &root_ && node->is_linked());
|
||||
++pos;
|
||||
@@ -485,6 +510,70 @@ namespace e2d
|
||||
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 >
|
||||
typename intrusive_list<T,Tag>::iterator intrusive_list<T,Tag>::iterator_to(T& v) noexcept {
|
||||
node_t& node = static_cast<node_t&>(v);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "_utils.hpp"
|
||||
using namespace e2d;
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ilist_tag1 {};
|
||||
@@ -21,6 +23,10 @@ namespace
|
||||
obj_t() = default;
|
||||
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") {
|
||||
@@ -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