joque
task orchestration library
list.hpp
Go to the documentation of this file.
1 #pragma once
23 
24 #include "joque/bits/list_ptr.hpp"
25 
26 #include <cstddef>
27 #include <type_traits>
28 #include <utility>
29 
30 namespace joque::bits
31 {
32 
33 template < typename Node, typename Accessor >
34 struct list_header;
35 
39 template < typename T, typename Node >
40 concept header_accessor = requires( Node& n, const Node& cn ) {
41  { T::get( n ) } -> std::convertible_to< list_header< Node, T >& >;
42  { T::get( cn ) } -> std::convertible_to< const list_header< Node, T >& >;
43 };
44 
45 // \brief List header (next/prev pointer) for double linked list node.
46 //
47 // Stores next/prev pointers for list node. Models a pattern where header stores
48 // pointers to the type of the node and has static accessor to get appropiate
49 // header from next/prev node. This makes it possible to have multiple different
50 // headers per node. (And hence each node can be part of multiple linked lists)
51 //
52 // \tparam Node type of nodes in the linked list
53 // \tparam Accessor
54 template < typename Node, typename Accessor >
56 {
57 
58  using node_type = Node;
59  using accessor_type = Accessor;
61 
62  ptr_type next = nullptr;
63  ptr_type prev = nullptr;
64 
65  list_header() = default;
66 
67  list_header( const list_header& ) = delete;
68  list_header& operator=( const list_header& ) = delete;
69 
70  list_header( list_header&& other ) noexcept
71  {
72  *this = std::move( other );
73  }
74 
75  list_header& operator=( list_header&& other ) noexcept
76  {
77  if ( this == &other )
78  return *this;
79 
80  next = std::exchange( other.next, nullptr );
81  prev = std::exchange( other.prev, nullptr );
82  if ( auto* h = next.find_header() )
83  h->prev = this;
84  if ( auto* h = prev.find_header() )
85  h->next = next;
86 
87  return *this;
88  }
89 
91 };
92 
93 template < typename Accessor, typename Node >
94 void list_unlink( Node& node );
95 
96 template < typename Ptr, typename... Args >
97 auto& list_emplace_next( Ptr ptr, Args&&... args );
98 
99 template < typename Ptr, typename Node >
100 void list_link_next( Ptr ptr, Node& next );
101 
102 template < typename Header >
103 void list_delete_all_next( Header& header );
104 
105 template < typename ListHeader >
107 {
108 public:
109  static constexpr bool is_const = std::is_const_v< ListHeader >;
110 
111  using header_type = ListHeader;
112  using difference_type = std::ptrdiff_t;
113  using value_type = std::conditional_t<
114  is_const,
115  const typename header_type::node_type,
116  typename header_type::node_type >;
117  using accessor_type = typename header_type::accessor_type;
118 
119  list_iterator() = default;
120 
121  list_iterator( value_type* node );
122 
124 
125  value_type& operator*() const;
126 
128 
129  value_type* operator->() const;
130 
132 
134 
135  list_iterator operator++( int );
136 
137  list_iterator operator--( int );
138 
139  auto operator<=>( const list_iterator& ) const = default;
140 
141 private:
143  {
144  return accessor_type::get( *node_ );
145  }
146 
147  value_type* node_ = nullptr;
148 };
149 
150 template < typename ListHeader >
151 class list
152 {
153 public:
154  using header_type = ListHeader;
155  using node_type = typename header_type::node_type;
156  using accessor_type = typename header_type::accessor_type;
160 
161  list() = default;
162  list( const list& ) = delete;
163  list( list&& ) = default;
164  list& operator=( const list& ) = delete;
165  list& operator=( list&& ) = default;
166 
167  [[nodiscard]] iterator begin();
168  [[nodiscard]] const_iterator begin() const;
169 
170  [[nodiscard]] iterator end();
171  [[nodiscard]] const_iterator end() const;
172 
173  [[nodiscard]] node_type& front()
174  {
175  return *begin();
176  }
177 
178  [[nodiscard]] const node_type& front() const
179  {
180  return *begin();
181  };
182 
183  [[nodiscard]] node_type& back()
184  {
185  return *++end();
186  }
187 
188  [[nodiscard]] const node_type& back() const
189  {
190  return *++end();
191  };
192 
193  template < typename... Args >
194  node_type& emplace_front( Args&&... args );
195 
196  void link_front( node_type& node );
197 
198  [[nodiscard]] bool empty() const;
199 
200  void clear_if( auto&& f );
201 
202  ~list();
203 
204 private:
205  header_type header_;
206 };
207 
208 template < typename Node, typename Accessor >
210 {
211  static_assert( header_accessor< Accessor, Node > );
212 
213  if ( auto* h = next.find_header() )
214  h->prev = prev;
215 
216  if ( auto* h = prev.find_header() )
217  h->next = next;
218 }
219 
220 template < typename Accessor, typename Node >
221 void list_unlink( Node& node )
222 {
223  auto& lnode = Accessor::get( node );
224 
225  if ( lnode.next != nullptr )
226  Accessor::get( *lnode.next ).prev = lnode.prev;
227  if ( lnode.prev != nullptr )
228  Accessor::get( *lnode.prev ).next = lnode.next;
229 
230  lnode.prev = nullptr;
231  lnode.next = nullptr;
232 }
233 
234 template < typename Ptr, typename... Args >
235 auto& list_emplace_next( Ptr ptr, Args&&... args )
236 {
237  using Node = typename Ptr::node_type;
238 
239  Node* nnode = new Node{ std::forward< Args >( args )... };
240  list_link_next( ptr, *nnode );
241  return *nnode;
242 }
243 
244 template < typename Ptr, typename Node >
245 void list_link_next( Ptr ptr, Node& next )
246 {
247  static_assert( std::same_as< typename Ptr::node_type, Node > );
248  using Accessor = typename Ptr::accessor_type;
249  using Header = typename Ptr::header_type;
250 
251  Header& nnode = Accessor::get( next );
252 
253  nnode.next = ptr.find_header()->next;
254  if ( nnode.next != nullptr )
255  nnode.next.find_header()->prev = &next;
256 
257  ptr.find_header()->next = &next;
258  nnode.prev = ptr;
259 }
260 
261 template < typename Header >
262 void list_delete_all_next( Header& header )
263 {
264  while ( auto* node = header.next.get_node() )
265  delete node;
266 }
267 
268 template < typename ListHeader >
270  : node_( node )
271 {
272 }
273 
274 template < typename ListHeader >
276 {
277  return *node_;
278 }
279 
280 template < typename ListHeader >
282 {
283  return *node_;
284 }
285 
286 template < typename ListHeader >
288 {
289  return node_;
290 }
291 
292 template < typename ListHeader >
294 {
295  return node_;
296 }
297 
298 template < typename ListHeader >
300 {
301  node_ = list_header().next.get_node();
302  return *this;
303 }
304 
305 template < typename ListHeader >
307 {
308  node_ = list_header().prev.get_node();
309  return *this;
310 }
311 
312 template < typename ListHeader >
314 {
315  list_iterator res{ *this };
316  ++( *this );
317  return res;
318 }
319 
320 template < typename ListHeader >
322 {
323  list_iterator res{ *this };
324  --( *this );
325  return res;
326 }
327 
328 template < typename ListHeader >
330 {
331  iterator res{ header_.next.get_node() };
332  return res;
333 }
334 
335 template < typename ListHeader >
337 {
338  const_iterator res{ header_.next.get_node() };
339  return res;
340 }
341 
342 template < typename ListHeader >
344 {
345  return iterator{ nullptr };
346 }
347 
348 template < typename ListHeader >
350 {
351  return const_iterator{ nullptr };
352 }
353 
354 template < typename ListHeader >
355 template < typename... Args >
357 {
358  return list_emplace_next( ptr_type{ &header_ }, std::forward< Args >( args )... );
359 }
360 
361 template < typename ListHeader >
363 {
364  list_link_next( ptr_type{ &header_ }, node );
365 }
366 
367 template < typename ListHeader >
369 {
370  return header_.next == nullptr;
371 }
372 
373 template < typename ListHeader >
375 {
376  for ( auto iter = begin(); iter != end(); ) {
377  auto* node = &*( iter++ );
378  if ( f( *node ) )
379  delete node;
380  }
381 }
382 
383 template < typename ListHeader >
385 {
386  list_delete_all_next( header_ );
387 }
388 
389 } // namespace joque::bits
Definition: list.hpp:107
static constexpr bool is_const
Definition: list.hpp:109
list_iterator & operator--()
Definition: list.hpp:306
value_type & operator*()
Definition: list.hpp:275
std::conditional_t< is_const, const typename header_type::node_type, typename header_type::node_type > value_type
Definition: list.hpp:116
auto operator<=>(const list_iterator &) const =default
std::ptrdiff_t difference_type
Definition: list.hpp:112
ListHeader header_type
Definition: list.hpp:111
list_iterator & operator++()
Definition: list.hpp:299
value_type * operator->()
Definition: list.hpp:287
typename header_type::accessor_type accessor_type
Definition: list.hpp:117
Node * get_node()
Definition: list_ptr.hpp:87
Header * find_header()
Definition: list_ptr.hpp:97
Definition: list.hpp:152
ListHeader header_type
Definition: list.hpp:154
bool empty() const
Definition: list.hpp:368
list & operator=(const list &)=delete
node_type & back()
Definition: list.hpp:183
~list()
Definition: list.hpp:384
void link_front(node_type &node)
Definition: list.hpp:362
list(const list &)=delete
typename header_type::accessor_type accessor_type
Definition: list.hpp:156
void clear_if(auto &&f)
Definition: list.hpp:374
node_type & front()
Definition: list.hpp:173
const node_type & back() const
Definition: list.hpp:188
iterator end()
Definition: list.hpp:343
node_type & emplace_front(Args &&... args)
Definition: list.hpp:356
list(list &&)=default
iterator begin()
Definition: list.hpp:329
typename header_type::node_type node_type
Definition: list.hpp:155
list & operator=(list &&)=default
const node_type & front() const
Definition: list.hpp:178
MIT License.
Definition: dag.hpp:27
auto & list_emplace_next(Ptr ptr, Args &&... args)
Definition: list.hpp:235
void list_delete_all_next(Header &header)
Definition: list.hpp:262
void list_unlink(Node &node)
Definition: list.hpp:221
concept header_accessor
Header accessor is a type that has static member function get(n) which returns reference to list head...
Definition: list.hpp:40
void list_link_next(Ptr ptr, Node &next)
Definition: list.hpp:245
Fun && f
Definition: task.hpp:93
requires(std::same_as< std::remove_cvref_t< T >, task_set >) void for_each_task(T &ts
Recursively executes function f for each task in set ts.
Definition: list.hpp:56
Accessor accessor_type
Definition: list.hpp:59
list_header & operator=(list_header &&other) noexcept
Definition: list.hpp:75
list_header(const list_header &)=delete
~list_header()
Definition: list.hpp:209
Node node_type
Definition: list.hpp:58
ptr_type prev
Definition: list.hpp:63
list_header & operator=(const list_header &)=delete
ptr_type next
Definition: list.hpp:62
list_header(list_header &&other) noexcept
Definition: list.hpp:70