list-composition.cpp (3783B)
1 #include <utility> 2 #include <iostream> 3 4 template <typename T, T* T::*link> 5 struct list_adapter 6 { 7 using element_type = T; 8 using iterator_type = T*; 9 10 static void insert_front(T*& head, T* x) 11 { 12 x->*link = std::exchange(head, x); 13 } 14 15 static void insert_after(T* prev, T* x) 16 { 17 insert_front(prev->*link, x); 18 } 19 20 static T* split_front(T*& head) 21 { 22 return std::exchange(head, nullptr); 23 } 24 25 static T* split_after(T* prev) 26 { 27 return split_front(prev->*link); 28 } 29 30 static T* extract_front(T*& head) 31 { 32 auto node = split_front(head); 33 head = split_after(node); 34 return node; 35 } 36 37 static T* extract_after(T& prev) 38 { 39 return extract_front(prev.*link); 40 } 41 42 static T* tail(T* head) 43 { 44 while (head->*link) 45 head = head->*link; 46 return head; 47 } 48 49 static T* index(T* head, unsigned i) 50 { 51 while(i--) 52 head = head->*link; 53 return head; 54 } 55 56 static unsigned count_list(T const* head) 57 { 58 unsigned n = 0; 59 while (head) 60 { 61 head = head->*link; 62 ++n; 63 } 64 return n; 65 } 66 67 template <typename P> 68 static T*& find_before(T*& head, P predicate) 69 { 70 T** p = &head; 71 while (*p and not predicate(*p)) 72 p = &((*p)->*link); 73 return *p; 74 } 75 76 template <typename U> 77 static void insert_sorted(T*& head, U T::*field, T* x) 78 { 79 //T** p = &head; 80 // while (*p and xx->*field > (*p)->*field) 81 // p = &((*p)->*link); 82 auto l = [x, field](T* y) { 83 return x->*field < y->*field; 84 }; 85 T*& p = find_before(head, l); 86 insert_front(p, x); 87 } 88 89 }; 90 91 template <typename T> 92 struct list_head : private T 93 { 94 using typename T::iterator_type; 95 iterator_type head = nullptr; 96 97 unsigned count() const 98 { 99 return T::count_list(head); 100 } 101 102 template <typename U> 103 void insert_sorted(U T::element_type::*field, iterator_type x) 104 { 105 //T** p = &head; 106 // while (*p and xx->*field > (*p)->*field) 107 // p = &((*p)->*link); 108 auto l = [x, field](iterator_type y) { 109 return x->*field < y->*field; 110 }; 111 iterator_type& p = T::find_before(head, l); 112 T::insert_front(p, x); 113 } 114 }; 115 116 117 struct treenode 118 { 119 std::string_view name; 120 121 using link = treenode*; 122 link first_child = nullptr; 123 link next_sibling = nullptr; 124 link next_sorted = nullptr; 125 126 using child_list = list_adapter<treenode, &treenode::first_child>; 127 using sibling_list = list_adapter<treenode, &treenode::next_sibling>; 128 using sorted_list = list_adapter<treenode, &treenode::next_sorted>; 129 }; 130 131 void add_child(treenode& parent, treenode& child) 132 { 133 treenode::sibling_list::insert_front(parent.first_child, &child); 134 } 135 136 void insert_sorted(list_head<treenode::sorted_list>& head, treenode& x) 137 { 138 head.insert_sorted(&treenode::name, &x); 139 } 140 141 struct list_printer 142 { 143 treenode const* head; 144 treenode* treenode::*link; 145 }; 146 147 std::ostream& operator <<(std::ostream& out, list_printer const& lp) 148 { 149 out << "[ "; 150 for (auto p = lp.head; p; p = p->*lp.link) 151 std::cout << p->name << ' '; 152 return out << ']'; 153 } 154 155 int main() 156 { 157 using std::cout, std::endl; 158 treenode a{"Alice"}, b{"Bob"}, c{"Charlie"}, d{"Douglas"}, e{"Edward"}, f{"Fogarty"}; 159 160 add_child(a, d); 161 add_child(d, f); 162 add_child(a, b); 163 add_child(b, c); 164 add_child(b, e); 165 166 list_head<treenode::sorted_list> name_order; 167 168 insert_sorted(name_order, b); 169 insert_sorted(name_order, d); 170 insert_sorted(name_order, c); 171 insert_sorted(name_order, f); 172 insert_sorted(name_order, a); 173 insert_sorted(name_order, e); 174 175 cout << "Alice & lastborn descendents: " << list_printer{&a, &treenode::first_child} << endl; 176 cout << "Bob & siblings: " << list_printer{&b, &treenode::next_sibling} << endl; 177 cout << "All " << name_order.count() << " sorted by name: " << list_printer(name_order.head, &treenode::next_sorted) << endl; 178 179 treenode::sorted_list::extract_after(b); 180 cout << "Extract Charlie: " << list_printer{&c, &treenode::next_sorted} << list_printer{name_order.head, &treenode::next_sorted} << endl; 181 }