#pragma once
#include "mpd/value_iterator/value_iterator.h"
#include <memory>
#include <cassert>
#include <stdexcept>
#include <vector>
#ifdef DEBUG_THE_TRACK_CLASS
#include <iostream>
#include <iomanip>
#endif
#ifdef _MSC_VER
#define noexcept(X) throw()
#define DEFAULTED {}
namespace std {
template<class T>
struct is_copy_constructible
:std::conditional<__has_copy(T), std::true_type, std::false_type>::type
{};
template<class T>
struct is_copy_assignable
:std::conditional<__has_assign(T), std::true_type, std::false_type>::type
{};
}
#else
#define DEFAULTED = default;
#endif
/*This container matches the same interface with the following exceptions
The elements are non-contiguous.
There is no capacity(), reserve(), shrink_to_fit(), or data() member functions.
Iterators and references are never invalidated, unless the element has been erased/cleared
Virtually all operations are logarithmic. (including iterator advancement)
*/
namespace mpd {
enum side_type {left=0, right=1};
static side_type other(side_type side) noexcept(true) {return side!=left?left:right;}
struct use_def_ctor{}; //when "constructing from" this, the default constructor is used instead
template<class type, class allocator>
class track_base;
template<class allocator>
class track_base<void, allocator>{
protected:
typedef typename allocator::difference_type difference_type;
typedef typename allocator::size_type size_type;
struct node {
typedef typename allocator::template rebind<node>::other node_allocator_type;
typedef typename node_allocator_type::reference reference;
//typedef typename node_allocator_type::const_reference const_reference;
typedef typename node_allocator_type::pointer pointer;
typedef typename node_allocator_type::const_pointer const_pointer;
size_type nodes_on_left;
pointer parent;
pointer child[2];
node() noexcept(true) :nodes_on_left(), parent(), child() {}
pointer& parent_ptr_to_this() noexcept(true) {return parent->child[get_side()];}
const_pointer down_to_far(side_type dir) const noexcept(true) {
const_pointer ptr=this;
while(ptr->child[dir])
ptr = ptr->child[dir];
return ptr;
}
pointer down_to_far(side_type dir) noexcept(true)
{return const_cast<pointer>(((const_pointer)this)->down_to_far(dir));}
side_type get_side() const noexcept(true) {return parent->child[right]==this ? right : left;}
size_type num_nodes_on(side_type dir, size_type total_nodes) const noexcept(true)
{if (dir == right) return total_nodes-nodes_on_left-1; return nodes_on_left;}
size_type child_offset(side_type dir, size_type my_offset) noexcept(true)
{if (dir == right) return my_offset+nodes_on_left+1; return my_offset;}
const_pointer find_parent_on(side_type dir) const noexcept(true) {
const_pointer ptr=this;
while(ptr->get_side() == dir)
ptr = ptr->parent;
return ptr->parent;
}
size_type get_size() const noexcept(true) {
size_type r = nodes_on_left;
const_pointer ptr=child[right];
while(ptr) {
r += ptr->nodes_on_left + 1;
ptr = ptr->child[right];
}
return r;
}
const_pointer find_root() const noexcept(true) {
const_pointer ptr=this;
while(ptr->parent)
ptr = ptr->parent;
assert(ptr->child[right]==nullptr);
return ptr;
}
pointer find_root() noexcept(true)
{return const_cast<pointer>(((const_pointer)this)->find_root());}
const_pointer find_one_to(side_type dir) const noexcept(true) {
const_pointer ptr=this;
if(ptr->child[dir]) return ptr->child[dir]->down_to_far(other(dir));
return ptr->find_parent_on(dir);
}
pointer find_one_to(side_type dir) noexcept(true)
{return const_cast<pointer>(((const_pointer)this)->find_one_to(dir));}
const_pointer down_to_offset(size_type index) const noexcept(true) { //cannot go up
const_pointer ptr=this;
while(ptr->nodes_on_left != index) {
if (ptr->nodes_on_left > index) {
ptr = ptr->child[left];
} else{
index = index - ptr->nodes_on_left - 1;
ptr = ptr->child[right];
}
}
return ptr;
}
pointer down_to_offset(size_type index) noexcept(true)
{return const_cast<pointer>(((const_pointer)this)->down_to_offset(index));}
const_pointer find_many_to(side_type dir, size_type count) const noexcept(true) { //can go up
const_pointer ptr=this;
if (dir == right) {
for(;;) {
if (count == 0) return ptr;
if (ptr->parent == nullptr) return ptr->down_to_offset(count);
if (ptr->get_side() == left) {
unsigned nodes_on_right = ptr->parent->nodes_on_left - ptr->nodes_on_left - 1;
if (count <= nodes_on_right)
return ptr->child[right]->down_to_offset(count-1);
count -= nodes_on_right + 1;
ptr = ptr->parent;
} else {
count += ptr->parent->nodes_on_left + 1;
ptr = ptr->parent;
}
}
} else {
for(;;) {
if (count == 0) return ptr;
if (ptr->nodes_on_left >= count)
return ptr->child[left]->down_to_offset(ptr->nodes_on_left - count);
count -= ptr->nodes_on_left + 1;
ptr = ptr->parent;
}
}
}
pointer find_many_to(side_type dir, size_type count) noexcept(true)
{return const_cast<pointer>(((const_pointer)this)->find_many_to(dir, count));}
size_type get_index() const noexcept(true) {
const_pointer ptr=this;
size_type o = ptr->nodes_on_left;
while(ptr->parent) {
if (ptr->get_side()==left)
ptr = ptr->parent;
else {
ptr = ptr->parent;
o += ptr->nodes_on_left + 1;
}
}
return o;
}
void change_size(side_type dir, difference_type count) noexcept(true){
pointer ptr = this;
if (dir == left)
ptr->nodes_on_left += count;
while(ptr->parent != nullptr) {
dir = ptr->get_side();
ptr = ptr->parent;
if (dir == left)
ptr->nodes_on_left += count;
}
}
bool is_just_to(side_type dir, const_pointer oldroot) const noexcept(true) {
oldroot = oldroot->child[dir];
while(oldroot) {
if (oldroot == this)
return true;
oldroot = oldroot->child[!dir];
}
return false;
}
void print_tree() const noexcept(true) {
#ifdef DEBUG_THE_TRACK_CLASS
std::vector<const node*> out(1, find_root()->child[left]);
std::vector<const node*> in;
std::vector<const node*> summary;
const size_type width = 64;
bool recurse;
do {
recurse = false;
in = out;
out.clear();
out.reserve(in.size()*2);
size_type width_per = width/in.size();
for(size_type i=0; i<in.size(); ++i) {
if (in[i]) {
std::cout << std::setw(width_per/2) << std::hex << ((unsigned(in[i])&0xFF0)>>4) << std::setw(width_per-width_per/2) << ' ';
summary.push_back(in[i]);
out.push_back(in[i]->child[left]);
out.push_back(in[i]->child[right]);
if (in[i]->child[left] || in[i]->child[right])
recurse = true;
} else {
std::cout << std::setw(width_per/2) << ". " << std::setw(width_per-width_per/2) << ' ';
out.push_back(nullptr);
out.push_back(nullptr);
}
}
std::cout << '\n';
}while(recurse && out.size()<32);
for(size_type i=0; i<summary.size(); ++i)
std::cout << ((unsigned(summary[i])&0xFF0)>>4) << ' ' << summary[i] << ' ' << summary[i]->nodes_on_left << '\n';
#endif
}
bool sub_tree_valid(size_type total_size) const noexcept(true) {
if (child[left]) {
assert(child[left]->parent == this);
child[left]->sub_tree_valid(nodes_on_left);
} else
assert(nodes_on_left == 0);
if (child[right]) {
assert(child[right]->parent == this);
child[right]->sub_tree_valid(total_size-1-nodes_on_left);
} else
assert(nodes_on_left + 1 == total_size);
return true;
}
bool whole_tree_valid() const noexcept(true) {
#ifdef DEBUG_THE_TRACK_CLASS
const node* p = find_root();
if (p->child[left])
return p->child[left]->sub_tree_valid(p->nodes_on_left);
assert(p->nodes_on_left == 0);
#endif
return true;
}
pointer rotate(side_type dir, pointer newroot) noexcept(true) {
std::cout << "rotating " << newroot << " around " << this << '\n';
print_tree();
assert(newroot->is_just_to(other(dir), this));
assert(whole_tree_valid());
pointer A = child[!dir]; //might be D
pointer B = newroot->parent; //might be F
pointer C = newroot->child[!dir]; //might be NULL
pointer D = newroot;
pointer E = newroot->child[dir]; //might be NULL
pointer F = this;
pointer Z = parent;
size_type sizeofE=0;
if (dir == right)
sizeofE = F->get_index() - D->get_index() - 1;
else
sizeofE = D->nodes_on_left;
side_type D_side = D->get_side();
side_type F_side = get_side();
/*
ROTATES D TO BE NEW ROOT
Z Z
? ?
F* D*
/ \ / \
A* O A* F*
/ \ / \ / \
O B* ---> O B* E O
/ \ / \ / \
O D* O C O O
/ \ / \
C E O O
/ \ / \
O O O O
*/
B->child[D_side] = C;
if (C) C->parent = B;
A = F->child[!dir]; //might be changed
D->child[!dir] = A;
A->parent = D;
F->child[!dir] = E;
if (E) E->parent = F;
D->child[dir] = F;
F->parent = D;
Z->child[F_side] = D;
D->parent = Z;
print_tree();
if (dir==right) {
D->nodes_on_left = F->nodes_on_left - sizeofE- 1;
F->nodes_on_left = sizeofE;
} else {
D->nodes_on_left += F->nodes_on_left + 1;
while(B!=F && B!=D) {
B->nodes_on_left -= sizeofE + 1;
B = B->parent;
}
}
print_tree();
assert(whole_tree_valid());
return newroot;
}
pointer rotate_at_least(side_type dir, size_type& count, size_type total_size) noexcept(true) {
assert(whole_tree_valid());
pointer ptr = child[!dir];
total_size = num_nodes_on(dir, total_size);
size_type check_next = ptr->num_nodes_on(dir, total_size);
while(check_next>count && ptr->child[dir]) {
total_size = check_next;
ptr = ptr->child[dir];
check_next = ptr->num_nodes_on(dir, total_size);
}
count = total_size;
return rotate(dir, ptr);
}
void balance(size_type seek_offset, size_type total_size) noexcept(true) {balance(seek_offset, total_size, false, false);}
void balance(size_type seek_offset, size_type total_size, bool down_left, bool down_right) noexcept(true) {
assert(whole_tree_valid());
//seek_offset may be out of bounds, that's fine
bool did_rotate_thistime;
bool did_rotate_any = false;
pointer ptr = this;
size_type nodes_on_right=0;
do {
did_rotate_thistime = false;
nodes_on_right = ptr->num_nodes_on(right, total_size);
//more than twice as many on the left as right
if (ptr->nodes_on_left > (nodes_on_right+1)*2) {
size_type delta = ptr->nodes_on_left - nodes_on_right*2 - 1;
ptr = ptr->rotate_at_least(right, delta, total_size);
did_rotate_thistime = true;
did_rotate_any = true;
//more than twice as many on the right as left
} else if ((ptr->nodes_on_left+1)*2 < nodes_on_right) {
size_type delta = nodes_on_right - ptr->nodes_on_left*2 - 1;
ptr = ptr->rotate_at_least(left, delta, total_size);
did_rotate_thistime = true;
did_rotate_any = true;
}
} while(did_rotate_thistime);
bool seek_left = false;
bool seek_right = false;
if (seek_offset < ptr->nodes_on_left)
seek_left = true;
if (seek_offset > ptr->nodes_on_left+1 && seek_offset < total_size)
seek_right = true;
if (ptr->child[left] && (did_rotate_any || down_left ||seek_left))
ptr->child[left]->balance(seek_offset, ptr->nodes_on_left, down_left, did_rotate_any);
if (ptr->child[right] && (did_rotate_any || down_right || seek_right)) {
seek_offset -= ptr->nodes_on_left-1;
ptr->child[right]->balance(seek_offset, nodes_on_right, did_rotate_any, down_right);
}
assert(whole_tree_valid());
}
void pop() noexcept(true) {
side_type old_side = get_side();
if (child[left]==nullptr && child[right]==nullptr) {
parent->child[old_side] = nullptr;
} else if (this->child[left]==nullptr || child[right]==nullptr) {
bool child_on_right = (child[right] != nullptr);
parent->child[old_side] = child[child_on_right];
child[child_on_right]->parent = parent;
} else {
pointer replacement = child[left]->down_to_far(right);
side_type replacement_side = replacement->get_side();
//remove references to replacement
replacement->parent->child[replacement_side] = replacement->child[left];
if (replacement->child[left])
replacement->child[left]->parent = replacement->parent;
//nothing points at replacement, set up replacement
replacement->parent = parent;
replacement->child[left] = child[left];
replacement->child[right] = child[right];
//point things at replacement
parent->child[old_side] = replacement;
if (child[left])
child[left]->parent = replacement;
if (child[right])
child[right]->parent = replacement;
}
}
protected:
node(node& nocopy);
node&operator=(node& nocopy);
~node() DEFAULTED
};
struct balance_after_no_matter_what {
balance_after_no_matter_what(node* root, size_type seek_offset) :root_(root), seek_offset_(seek_offset) {}
~balance_after_no_matter_what()
{if (root_->child[left]) root_->child[left]->balance(seek_offset_, root_->nodes_on_left, false, false);}
protected:
node* root_;
size_type seek_offset_;
};
struct add_assign_no_matter_what {
add_assign_no_matter_what(size_type& lhs, size_type& rhs) :lhs_(&lhs), rhs_(&rhs) {}
~add_assign_no_matter_what() {*lhs_ += *rhs_;}
protected:
size_type* lhs_;
size_type* rhs_;
};
struct sub_assign_no_matter_what {
sub_assign_no_matter_what(size_type& lhs, size_type& rhs) :lhs_(&lhs), rhs_(&rhs) {}
~sub_assign_no_matter_what() {*lhs_ -= *rhs_;}
protected:
size_type* lhs_;
size_type* rhs_;
};
struct change_size_no_matter_what {
change_size_no_matter_what(node* ptr, side_type dir, size_type& count) :ptr_(ptr),dir_(dir),count_(&count){}
~change_size_no_matter_what() {ptr_->change_size(dir_, *count_);}
protected:
node* ptr_;
side_type dir_;
size_type* count_;
};
struct assert_valid_after_no_matter_what {
assert_valid_after_no_matter_what(const node* root) :root_(root) {}
~assert_valid_after_no_matter_what()
{assert(root_->whole_tree_valid());}
protected:
const node* root_;
};
};
template<class type, class allocator>
class track_base : private track_base<void, typename allocator::template rebind<char>::other>{
protected:
typedef track_base<void, typename allocator::template rebind<char>::other> parent;
typedef typename parent::node node;
typedef typename parent::balance_after_no_matter_what balance_after_no_matter_what;
typedef typename parent::add_assign_no_matter_what add_assign_no_matter_what;
typedef typename parent::sub_assign_no_matter_what sub_assign_no_matter_what;
typedef typename parent::assert_valid_after_no_matter_what assert_valid_after_no_matter_what;
typedef typename parent::change_size_no_matter_what change_size_no_matter_what;
typedef typename allocator::template rebind<type>::other allocator_type;
typedef typename allocator_type::value_type value_type;
typedef typename allocator_type::const_pointer const_pointer;
typedef typename allocator_type::const_reference const_reference;
typedef typename allocator_type::difference_type difference_type;
typedef typename allocator_type::pointer pointer;
typedef typename allocator_type::reference reference;
typedef typename allocator_type::size_type size_type;
struct payload : public node {
typedef typename allocator::template rebind<payload>::other payload_allocator_type;
value_type data;
payload() :node(), data() {}
template<class U> payload(U&& d) :node(), data(std::forward<U>(d)) {}
void erase(payload_allocator_type& al) {
this->pop();
al.destroy(this);
al.deallocate(this, sizeof(payload));
}
void erase(payload_allocator_type& al, size_type min_index, size_type max_index, size_type total_size, size_type& out_erased) {
assert(min_index<=max_index);
if (max_index+1>this->nodes_on_left && this->child[right]) {
size_type skip = this->nodes_on_left+1;
size_type min = min_index<skip ? 0 : min_index-skip;
size_type max = max_index<skip ? 0 : max_index-skip;
size_type nodes_on_right = this->num_nodes_on(right, total_size);
static_cast<payload*>(this->child[right])->erase(al, min, max, nodes_on_right, out_erased);
}
size_type self_index = this->nodes_on_left; //cache it before we change the nodes_on_left
if (min_index<this->nodes_on_left && this->child[left]) {
size_type erased_on_left=0;
add_assign_no_matter_what t0(out_erased, erased_on_left);
sub_assign_no_matter_what t1(this->nodes_on_left, erased_on_left);
static_cast<payload*>(this->child[left])->erase(al, min_index, max_index, this->nodes_on_left, erased_on_left);
}
if (min_index <= self_index && max_index > self_index) {
erase(al);
++out_erased;
}
}
};
typedef typename payload::payload_allocator_type payload_allocator_type;
struct tree_deleter {
payload_allocator_type* a;
size_type total;
tree_deleter(payload_allocator_type& alloc, size_type total_nodes) noexcept(true) :a(&alloc), total(total_nodes) {}
void operator()(payload* ptr) {size_type e;ptr->erase(*a, 0, total, total, e);}
};
typedef std::unique_ptr<payload, tree_deleter> owning_ptr;
struct just_deallocate {
payload_allocator_type* a;
explicit just_deallocate(payload_allocator_type& alloc) noexcept(true) :a(&alloc) {}
void operator()(payload* ptr) {a->deallocate(ptr, sizeof(payload));}
};
typedef std::unique_ptr<payload, just_deallocate> allocated_ptr;
template <class U>
static owning_ptr construct_from(U&& value, payload_allocator_type& al)
{
allocated_ptr t(al.allocate(sizeof(payload)), just_deallocate(al));
al.construct(t.get(), std::forward<U>(value));
return owning_ptr(t.release(), tree_deleter(al, 1));
}
static owning_ptr construct_from(use_def_ctor, payload_allocator_type& al)
{
allocated_ptr t(al.allocate(sizeof(payload)), just_deallocate(al));
//@@@TODO MSVC10's allocator doesn't have this
//al.construct(t.get());
new(t.get())payload();
return owning_ptr(t.release(), tree_deleter(al, 1));
}
static owning_ptr construct_from(node& rhs, payload_allocator_type& al)
{
owning_ptr p(construct_from(static_cast<payload&>(rhs).data, al));
if(rhs.child[left]){
owning_ptr l(construct_from(*(rhs.child[left]), al));
p.get_deleter().total += l.get_deleter().total;
l->nodes_on_left = l.get_deleter().total;
l->parent = p.get();
p->child[left] = l.release();
}
if(rhs.child[right]){
owning_ptr r(construct_from(*(rhs.child[right]), al));
p.get_deleter().total += r.get_deleter().total;
r->parent = p.get();
p->child[right] = r.release();
}
return p;
}
template <class input_iterator>
node* add_child(node* par, side_type dir, input_iterator first, input_iterator last, payload_allocator_type& al, size_type, std::output_iterator_tag) {
std::vector<value_type> t(first, last); //copy to turn input iterators into random access
size_type out_added=0;
change_size_no_matter_what t0(par, dir, out_added);
return add_child(par, dir, std::make_move_iterator(t.begin()), al, t.size(), out_added);
}
template <class forward_iterator>
node* add_child(node* par, side_type dir, forward_iterator first, forward_iterator last, payload_allocator_type& al, size_type total_its, std::forward_iterator_tag){
if (total_its == 0) total_its = std::distance(first, last);
size_type out_added=0;
change_size_no_matter_what t0(par, dir, out_added);
return add_child(par, dir, first, al, total_its, out_added);
}
template <class forward_iterator>
node* add_child(node* par, side_type dir, forward_iterator first, payload_allocator_type& al, size_type total_its, size_type& out_added){
size_type half = total_its/2;
forward_iterator mid = std::next(first, half);
par->child[dir] = construct_from(*mid, al).release();
node* added = par->child[dir];
out_added += 1;
added->parent = par;
if (half < total_its-1)
add_child(added, right, std::next(mid), al, total_its-half-1, out_added);
if (half <= 0)
return added;
size_type added_on_left = 0;
add_assign_no_matter_what t0(out_added, added_on_left);
add_assign_no_matter_what t1(added->nodes_on_left, added_on_left);
return add_child(added, left, first, al, half, added_on_left);
}
struct root_type : public node, public payload_allocator_type {
//root's parent and child[right] are always nullptr. Always. Period.
root_type() : node(), payload_allocator_type() {}
root_type(node* own_tree, payload_allocator_type& a) :node(), payload_allocator_type(a) {this->child[left] = own_tree;}
explicit root_type(const payload_allocator_type& a) : node(), payload_allocator_type(a) {}
root_type(const root_type& rhs) : node(), payload_allocator_type(rhs) {cpy_ctor_(rhs);}
root_type(const root_type& rhs, const payload_allocator_type& a) : node(), payload_allocator_type(a) {cpy_ctor_(rhs);}
root_type(root_type&& rhs) noexcept(true) : node(), payload_allocator_type() {swap(rhs);}
~root_type() {size_type e=0; if (this->child[left]) static_cast<payload*>(this->child[left])->erase(*this, 0, this->nodes_on_left, this->nodes_on_left, e);}
root_type& operator=(root_type rhs) noexcept(true) {swap(rhs); return *this;}
void swap(root_type& rhs) noexcept(true) {
using std::swap;
swap(this->child[left], rhs.child[left]);
if (this->child[left])
this->child[left]->parent = this;
if (rhs.child[left])
rhs.child[left]->parent = &rhs;
swap(this->nodes_on_left, rhs.nodes_on_left);
swap(static_cast<payload_allocator_type&>(*this), static_cast<payload_allocator_type&>(rhs));
}
private:
void cpy_ctor_(const root_type& rhs) {
this->nodes_on_left = rhs.nodes_on_left;
if (rhs.child[left]) {
this->child[left] = construct_from(*rhs.child[left], *this).release();
this->child[left]->parent = this;
}
}
};
template <class input_iterator>
node* insert(node* ptr, input_iterator first, input_iterator last, root_type& root) {
assert(ptr->find_root() == &root);
assert_valid_after_no_matter_what verify(&root);
side_type side = left;
if (ptr->child[left]) {
side = right;
ptr = ptr->child[left];
ptr = ptr->down_to_far(right);
}
balance_after_no_matter_what t0(&root, ptr->get_index());
return this->add_child(ptr, side, first, last, root, 0, typename std::iterator_traits<input_iterator>::iterator_category());
}
node* erase(node* p, root_type& root) {
assert(p->find_root() == &root);
assert_valid_after_no_matter_what verify(&root);
node* r(p+1);
p->parent->change_size(p->get_side(), -1);
static_cast<payload*>(p)->erase(root);
return r;
}
node* erase(node* first, node* last, root_type& root) {
if (first != last) {
assert(first->find_root() ==&root);
assert( last->find_root() ==&root);
size_type min = first->get_index();
size_type max = last->get_index();
assert(min<max);
size_type out_num_erased=0;
balance_after_no_matter_what t0(&root, min+1);
balance_after_no_matter_what t1(&root, min);
assert_valid_after_no_matter_what verify(&root);
sub_assign_no_matter_what t3(root.nodes_on_left, out_num_erased);
root.print_tree();
static_cast<payload*>(root.child[left])->erase(root, min, max, root.nodes_on_left, out_num_erased);
}
return last;
}
};
template<class type, class allocator=std::allocator<type>>
class track : private track_base<type, typename allocator::template rebind<type>::other>{
protected:
typedef track_base<type, typename allocator::template rebind<type>::other> parent;
typedef typename parent::root_type root_type;
typedef typename parent::node node;
typedef typename parent::payload payload;
typedef typename parent::assert_valid_after_no_matter_what assert_valid_after_no_matter_what;
root_type root;
public:
typedef typename parent::allocator_type allocator_type;
typedef typename parent::value_type value_type;
typedef typename parent::reference reference;
typedef typename parent::const_reference const_reference;
typedef typename parent::pointer pointer;
typedef typename parent::const_pointer const_pointer;
typedef typename parent::difference_type difference_type;
typedef typename parent::size_type size_type;
class const_iterator;
class iterator {
public:
typedef typename allocator_type::difference_type difference_type;
typedef typename allocator_type::value_type value_type;
typedef typename allocator_type::reference reference;
typedef typename allocator_type::pointer pointer;
typedef std::random_access_iterator_tag iterator_category;
iterator() noexcept(true) :ptr() {}
iterator(const iterator& rhs) noexcept(true) :ptr(rhs.ptr) {}
friend bool operator==(const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr==rhs.ptr;}
friend bool operator!=(const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr!=rhs.ptr;}
friend bool operator< (const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr->get_index()< rhs.ptr->get_index();}
friend bool operator<=(const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr->get_index()<=rhs.ptr->get_index();}
friend bool operator> (const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr->get_index()> rhs.ptr->get_index();}
friend bool operator>=(const iterator& lhs, const iterator& rhs) noexcept(true) {return lhs.ptr->get_index()>=rhs.ptr->get_index();}
iterator& operator++() noexcept(true) {ptr=ptr->find_one_to(right); return *this;}
iterator operator++(int) noexcept(true) {iterator t(*this); ++*this; return t;}
iterator& operator--() noexcept(true) {ptr=ptr->find_one_to(left); return *this;}
iterator operator--(int) noexcept(true) {iterator t(*this); --*this; return t;}
iterator& operator+=(size_type o) noexcept(true) {ptr = ptr->find_many_to(right, o); return *this;}
friend iterator operator+(iterator it, size_type o) noexcept(true) {return it+=o;}
friend iterator operator+(size_type o, iterator it) noexcept(true) {return it+=o;}
iterator& operator-=(size_type o) noexcept(true) {ptr = ptr->find_many_to(left, o); return *this;}
friend iterator operator-(iterator it, size_type o) noexcept(true) {return it-=o;}
difference_type operator-(const iterator& it) noexcept(true) {return ptr->get_index() - it.ptr->get_index();}
reference operator*() const noexcept(true) {return static_cast<payload*>(ptr)->data;}
pointer operator->() const noexcept(true) {return &static_cast<payload*>(ptr)->data;}
reference operator[](size_type o) const noexcept(true) {return static_cast<payload*>(ptr->find_many_to(right, o))->data;}
friend void swap(iterator& lhs, iterator& rhs) noexcept(true) {std::swap(lhs.ptr, rhs.ptr);}
private:
node* ptr;
friend track;
friend const_iterator;
iterator(node* p) noexcept(true) :ptr(p) {}
};
class const_iterator {
public:
typedef typename allocator_type::difference_type difference_type;
typedef typename allocator_type::value_type value_type;
typedef typename allocator_type::const_reference reference;
typedef typename allocator_type::const_pointer pointer;
typedef std::bidirectional_iterator_tag iterator_category;
const_iterator() noexcept(true) :ptr() {}
const_iterator(const const_iterator& rhs) noexcept(true) :ptr(rhs.ptr) {}
const_iterator(const iterator& rhs) noexcept(true) :ptr(rhs.ptr) {}
friend bool operator==(const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr==rhs.ptr;}
friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr!=rhs.ptr;}
friend bool operator< (const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr->get_index()< rhs.ptr->get_index();}
friend bool operator<=(const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr->get_index()<=rhs.ptr->get_index();}
friend bool operator> (const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr->get_index()> rhs.ptr->get_index();}
friend bool operator>=(const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr->get_index()>=rhs.ptr->get_index();}
const_iterator& operator++() noexcept(true) {ptr=ptr->find_one_to(right); return *this;}
const_iterator operator++(int) noexcept(true) {const_iterator t(*this); ++*this; return t;}
const_iterator& operator--() noexcept(true) {ptr=ptr->find_one_to(left); return *this;}
const_iterator operator--(int) noexcept(true) {const_iterator t(*this); --*this; return t;}
const_iterator& operator+=(size_type o) noexcept(true) {ptr = ptr->find_many_to(right, o); return *this;}
friend const_iterator operator+(const_iterator it, size_type o) noexcept(true) {return it+=o;}
friend const_iterator operator+(size_type o, const_iterator it) noexcept(true) {return it+=o;}
const_iterator& operator-=(size_type o) noexcept(true) {ptr = ptr->find_many_to(left, o); return *this;}
friend const_iterator operator-(const_iterator it, size_type o) noexcept(true) {return it-=o;}
friend difference_type operator-(const const_iterator& lhs, const const_iterator& rhs) noexcept(true) {return lhs.ptr->get_index() - rhs.ptr->get_index();}
reference operator*() const noexcept(true) {return static_cast<const payload*>(ptr)->data;}
pointer operator->() const noexcept(true) {return &static_cast<const payload*>(ptr)->data;}
reference operator[](size_type o) const noexcept(true) {return static_cast<const payload*>(ptr->find_many_to(right, o))->data;}
friend void swap(const_iterator& lhs, const_iterator& rhs) noexcept(true) {std::swap(lhs.ptr, rhs.ptr);}
private:
const node* ptr;
friend track;
const_iterator(const node* p) noexcept(true) :ptr(p) {}
iterator unconst() const noexcept(true) {return iterator(const_cast<node*>(ptr));}
};
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
track() : root() {}
track(const track& rhs) : root(rhs.root) {} //DARN YOU MSVC AND YOU'RE FAULURE OF IMPLICIT MOVE CONSTRUCTORS
track(track&& rhs) noexcept(true) :root() {swap(rhs);} //DARN YOU MSVC AND YOU'RE FAULURE OF IMPLICIT MOVE CONSTRUCTORS
explicit track(size_type n)
: root() {insert(end(), make_value_iterator(0, use_def_ctor()), make_value_iterator(n, use_def_ctor()));}
track(size_type n, const value_type& val, const allocator_type& alloc = allocator_type())
: root(alloc) {insert(end(), make_value_iterator(0, val), make_value_iterator(n, val));}
template <class input_iterator>
track(input_iterator first, input_iterator last, const allocator_type& alloc = allocator_type())
: root(alloc) {insert(end(), first, last);}
//track(std::initializer_list<T> init, const allocator_type& alloc = allocator_type())
//: allocator_type(alloc), root() {insert(end(), init.begin(), init.end());}
explicit track(const allocator_type& alloc) : root(alloc) {}
track(const track& rhs, const allocator_type& alloc) : root(rhs.root) {}
track(track&& rhs, const allocator_type& alloc) noexcept(true) :root(alloc) {swap(rhs);}
iterator begin() noexcept(true) {return iterator(root.down_to_far(left));}
iterator end() noexcept(true) {return iterator(&root);}
reverse_iterator rbegin() noexcept(true) {return reverse_iterator(iterator(root.down_to_far(left)));}
reverse_iterator rend() noexcept(true) {return reverse_iterator(iterator(&root));}
const_iterator begin() const noexcept(true) {return const_iterator(root.down_to_far(left));}
const_iterator end() const noexcept(true) {return const_iterator(&root);}
const_reverse_iterator rbegin() const noexcept(true) {return const_reverse_iterator(const_iterator(root.down_to_far(left)));}
const_reverse_iterator rend() const noexcept(true) {return const_reverse_iterator(const_iterator(&root));}
const_iterator cbegin() const noexcept(true) {return const_iterator(root.down_to_far(left));}
const_iterator cend() const noexcept(true) {return const_iterator(&root);}
const_reverse_iterator crbegin() const noexcept(true) {return const_reverse_iterator(const_iterator(root.down_to_far(left)));}
const_reverse_iterator crend() const noexcept(true) {return const_reverse_iterator(const_iterator(&root));}
size_type size() const noexcept(true) {return root.nodes_on_left;}
size_type max_size() const noexcept(noexcept(root.max_size())) {return root.max_size();}
void resize(size_type n) {
assert_valid_after_no_matter_what verify(&root);
if (n<root.nodes_on_left) {
erase(const_iterator(root.down_to_offset(n)), cend());
} else if (n>root.nodes_on_left)
insert(end(), make_value_iterator(root.nodes_on_left, use_def_ctor()), make_value_iterator(n, use_def_ctor()));
}
void resize(size_type n, value_type val) {
assert_valid_after_no_matter_what verify(&root);
if (n<root.nodes_on_left) {
erase(const_iterator(root.down_to_offset(n)), cend());
} else if (n>root.nodes_on_left)
insert(end(), make_value_iterator(root.nodes_on_left, val), make_value_iterator(n, val));
}
//size_type capacity() const noexcept;
bool empty() const noexcept(true) {return size()==0;}
//void reserve(size_type n);
//void shrink_to_fit();
reference operator[](size_type n) noexcept(true) {return static_cast<payload*>(root.down_to_offset(n))->data;}
const_reference operator[](size_type n) const noexcept(true) {return static_cast<const payload*>(root.down_to_offset(n))->data;}
const_reference at(size_type n) const {
if (n>=size()) throw std::out_of_range("invalid index");
return static_cast<const payload*>(root.down_to_offset(n))->data;
}
reference at(size_type n) {
if (n>=size()) throw std::out_of_range("invalid index");
return static_cast<payload*>(root.down_to_offset(n))->data;
}
reference front() noexcept(true) {return static_cast<payload*>(root.down_to_far(left))->data;}
const_reference front() const noexcept(true) {return static_cast<const payload*>(root.down_to_far(left))->data;}
reference back() noexcept(true) {return static_cast<payload*>(root.child[left]->down_to_far(right))->data;}
const_reference back() const noexcept(true) {return static_cast<const payload*>(root.child[left]->down_to_far(right))->data;}
//value_type* data() noexcept;
//const value_type* data() const noexcept;
template <class input_iterator>
void assign(input_iterator first, input_iterator last) {track(first, last).swap(*this);}
void assign(size_type n, const value_type& val) {track(value_iterator<value_type>(0, val), value_iterator<value_type>(n, val)).swap(*this);}
//void assign(std::initializer_list<value_type> il) {track(il.begin(), il.end().swap(*this);}
void push_back(value_type val) {insert(cend(), std::make_move_iterator(&val), std::make_move_iterator(&val + 1));}
void pop_back() {erase(cend()-1, cend());}
iterator insert(const_iterator position, size_type n, const value_type& val) {return insert(position, value_iterator<value_type>(0, val), value_iterator<value_type>(n, val));}
template <class input_iterator>
iterator insert(const_iterator position, input_iterator first, input_iterator last) {return parent::insert(position.unconst().ptr, first, last, root);}
iterator insert(const_iterator position, value_type val) {return insert(position.unconst().ptr, std::make_move_iterator(&val), std::make_move_iterator(&val + 1));}
//iterator insert(const_iterator position, std::initializer_list<value_type> il);
iterator erase(const_iterator position) {return parent::erase(position.unconst().ptr, root);}
iterator erase(const_iterator first, const_iterator last) {return parent::erase(first.unconst().ptr, last.unconst().ptr, root);}
void swap(track& rhs) {root.swap(rhs.root);}
void clear() {root.print_tree(); erase(cbegin(), cend()); root.print_tree();}
//template <class... Args>
//iterator emplace(const_iterator position, Args&&... args); //@@@TODO
template <class Args0>
iterator emplace(const_iterator position, Args0&& args) {return insert(position, std::make_move_iterator(&args), std::make_move_iterator(&args +1));}
template <class Args0>
iterator emplace(const_iterator position, const Args0& args) {return insert(position, &args, &args +1);}
//template <class... Args>
//void emplace_back(Args&&... args){emplace(cend(), std::forward<Args>(args)...);}
template <class Args0>
void emplace_back(Args0&& args) {insert(cend(), std::make_move_iterator(&args), std::make_move_iterator(&args +1));}
template <class Args0>
void emplace_back(const Args0& args) {insert(cend(), &args, &args +1);}
allocator_type get_allocator() const noexcept(true) {return root;}
friend bool operator==(const track& lhs, const track& rhs)
{return lhs.size()==rhs.size() && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());}
friend bool operator!=(const track& lhs, const track& rhs)
{return lhs.size()!=rhs.size() || !std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());}
friend bool operator< (const track& lhs, const track& rhs)
{return lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less<value_type>());}
friend bool operator<=(const track& lhs, const track& rhs)
{return lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::less_equal<value_type>());}
friend bool operator> (const track& lhs, const track& rhs)
{return lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater<value_type>());}
friend bool operator>=(const track& lhs, const track& rhs)
{return lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), std::greater_equal<value_type>());}
friend void swap(track& lhs, track& rhs) {lhs.root.swap(rhs.root);}
};
} //namespace mpd