emlabcpp
modern opinionated embedded C++ library
tree.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../../match.h"
27 #include "../../pmr/aliases.h"
28 #include "../../pmr/pool_resource.h"
29 #include "../../static_vector.h"
30 #include "./base.h"
31 
32 #include <map>
33 
34 namespace emlabcpp
35 {
36 template < typename ObjectType >
38 {
39  static constexpr bool is_const = std::is_const_v< ObjectType >;
40 
41  using object_type = ObjectType;
42  using child_id = uint32_t;
43  using node_id = std::tuple_element_t< 1, typename object_type::value_type >;
44  using key_type = typename object_type::key_type;
45  using const_iterator = typename object_type::const_iterator;
46  using iterator =
47  std::conditional_t< is_const, const_iterator, typename object_type::iterator >;
48 
49 public:
50  using node_type = typename object_type::node_type;
51 
52  explicit contiguous_object_handle( object_type* obj )
53  : obj_( obj )
54  {
55  }
56 
57  [[nodiscard]] iterator begin()
58  {
59  return obj_->begin();
60  }
61 
62  [[nodiscard]] iterator end()
63  {
64  return obj_->end();
65  }
66 
67  [[nodiscard]] const_iterator begin() const
68  {
69  return obj_->begin();
70  }
71 
72  [[nodiscard]] const_iterator end() const
73  {
74  return obj_->end();
75  }
76 
77  [[nodiscard]] std::optional< node_id > get_child( child_id chid ) const
78  {
79  if ( obj_->size() < chid )
80  return std::nullopt;
81  auto iter = obj_->begin();
82  std::advance( iter, chid );
83  return iter->second;
84  }
85 
86  [[nodiscard]] std::optional< node_id > get_child( key_type k ) const
87  {
88  auto iter = obj_->find( k );
89  if ( iter == obj_->end() )
90  return std::nullopt;
91  return iter->second;
92  }
93 
94  [[nodiscard]] uint32_t size() const
95  {
96  return static_cast< uint32_t >( obj_->size() );
97  }
98 
99  [[nodiscard]] key_type const* get_key( child_id chid ) const
100  {
101  if ( chid >= obj_->size() )
102  return nullptr;
103 
104  auto iter = obj_->begin();
105  std::advance( iter, chid );
106  return &iter->first;
107  }
108 
109  void set( key_type const& k, node_id nid )
110  {
111  obj_->emplace( k, nid );
112  }
113 
114 private:
115  object_type* obj_;
116 };
117 
118 #ifdef EMLABCPP_USE_OSTREAM
119 template < typename ObjectType >
120 std::ostream& operator<<( std::ostream& os, contiguous_object_handle< ObjectType > const& oh )
121 {
122  for ( auto const& [key, nid] : oh )
123  os << key << ":" << nid << ",";
124  return os;
125 }
126 #endif
127 
128 template < typename ArrayType >
130 {
131  static constexpr bool is_const = std::is_const_v< ArrayType >;
132 
133  using array_type = ArrayType;
134  using child_id = uint32_t;
135  using node_id = std::tuple_element_t< 1, typename array_type::value_type >;
136  using const_iterator = typename array_type::const_iterator;
137  using iterator =
138  std::conditional_t< is_const, const_iterator, typename array_type::iterator >;
139 
140 public:
141  using node_type = typename array_type::node_type;
142 
143  explicit contiguous_array_handle( array_type* arr )
144  : arr_( arr )
145  {
146  }
147 
148  [[nodiscard]] iterator begin()
149  {
150  return arr_->begin();
151  }
152 
153  [[nodiscard]] iterator end()
154  {
155  return arr_->end();
156  }
157 
158  [[nodiscard]] const_iterator begin() const
159  {
160  return arr_->begin();
161  }
162 
163  [[nodiscard]] const_iterator end() const
164  {
165  return arr_->end();
166  }
167 
168  [[nodiscard]] std::optional< node_id > get_child( child_id chid ) const
169  {
170  auto iter = arr_->find( chid );
171  if ( iter == arr_->end() )
172  return std::nullopt;
173  return iter->second;
174  }
175 
176  [[nodiscard]] uint32_t size() const
177  {
178  return static_cast< uint32_t >( arr_->size() );
179  }
180 
181  void append( node_id nid )
182  {
183  arr_->emplace( arr_->size(), nid );
184  }
185 
186 private:
187  array_type* arr_;
188 };
189 
190 #ifdef EMLABCPP_USE_OSTREAM
191 template < typename ArrayType >
192 std::ostream& operator<<( std::ostream& os, contiguous_array_handle< ArrayType > const& ah )
193 {
194  for ( auto const& [chid, nid] : ah )
195  os << chid << ":" << nid << ",";
196  return os;
197 }
198 #endif
199 
200 template < typename Key, typename Value >
202 {
203 public:
204  using key_type = Key;
205  using value_type = Value;
206  using node_id = uint32_t;
207  using child_id = uint32_t;
210  using content_type = std::variant< Value, array_type, object_type >;
215 
216  explicit contiguous_node( content_type cont )
217  : content_( std::move( cont ) )
218  {
219  }
220 
221  [[nodiscard]] Value const* get_value() const
222  {
223  return std::get_if< Value >( &content_ );
224  }
225 
226  [[nodiscard]] Value* get_value()
227  {
228  return std::get_if< Value >( &content_ );
229  }
230 
231  [[nodiscard]] std::
232  variant< std::reference_wrapper< Value const >, object_handle, array_handle >
234  {
235  if ( std::holds_alternative< array_type >( content_ ) )
236  return array_handle{ std::get_if< array_type >( &content_ ) };
237  if ( std::holds_alternative< object_type >( content_ ) )
238  return object_handle{ std::get_if< object_type >( &content_ ) };
239  return std::ref( *std::get_if< Value >( &content_ ) );
240  }
241 
242  [[nodiscard]] std::variant<
243  std::reference_wrapper< Value const >,
247  {
248  if ( std::holds_alternative< array_type >( content_ ) )
249  return const_array_handle{ std::get_if< array_type >( &content_ ) };
250  if ( std::holds_alternative< object_type >( content_ ) )
251  return const_object_handle{ std::get_if< object_type >( &content_ ) };
252  return std::ref( *std::get_if< Value >( &content_ ) );
253  }
254 
255  [[nodiscard]] contiguous_tree_type get_type() const
256  {
257  return match(
258  content_,
259  []( Value const& ) {
261  },
262  []( array_type const& ) {
264  },
265  []( object_type const& ) {
267  } );
268  }
269 
270 private:
271  content_type content_;
272 };
273 
274 #ifdef EMLABCPP_USE_OSTREAM
275 template < typename Key, typename Value >
276 std::ostream& operator<<( std::ostream& os, contiguous_node< Key, Value > const& node )
277 {
278  visit(
279  [&os]( auto const& val ) {
280  os << val;
281  },
282  node.get_container_handle() );
283  return os;
284 }
285 #endif
286 
287 template < typename Key, typename Value >
289 {
290 public:
291  using key_type = Key;
292  using value_type = Value;
293  using node_id = uint32_t;
294  using child_id = uint32_t;
304 
305  using iterator = typename container::iterator;
306  using const_iterator = typename container::const_iterator;
307 
308  // TODO: find better way to decided this
309  static constexpr std::size_t required_pool_size = 110;
310 
311  template < uint16_t Count >
313 
315  : data_( mem_res )
316  , mem_res_( mem_res )
317  {
318  }
319 
320  void clear()
321  {
322  data_.clear();
323  }
324 
325  [[nodiscard]] node_type const* get_node( node_id nid ) const
326  {
327  auto iter = data_.find( nid );
328  if ( iter == data_.end() )
329  return nullptr;
330  return &iter->second;
331  }
332 
333  [[nodiscard]] node_type* get_node( node_id nid )
334  {
335  auto iter = data_.find( nid );
336  if ( iter == data_.end() )
337  return nullptr;
338  return &iter->second;
339  }
340 
341  [[nodiscard]] iterator begin()
342  {
343  return data_.begin();
344  }
345 
346  [[nodiscard]] iterator end()
347  {
348  return data_.end();
349  }
350 
351  [[nodiscard]] const_iterator begin() const
352  {
353  return data_.begin();
354  }
355 
356  [[nodiscard]] const_iterator end() const
357  {
358  return data_.end();
359  }
360 
361  [[nodiscard]] std::size_t size() const
362  {
363  return data_.size();
364  }
365 
366  [[nodiscard]] bool empty() const
367  {
368  return data_.empty();
369  }
370 
371  std::optional< node_id > make_value_node( value_type val )
372  {
373  std::optional opt_val = make_node( std::move( val ) );
374  if ( !opt_val )
375  return std::nullopt;
376  auto [nid, iter] = *opt_val;
377  return nid;
378  }
379 
380  std::optional< std::pair< node_id, array_handle > > make_array_node()
381  {
382  std::optional opt_val = make_node( array_type{ mem_res_.get() } );
383  if ( !opt_val )
384  return std::nullopt;
385  auto [nid, iter] = *opt_val;
386  auto var = iter->second.get_container_handle();
387  return std::make_pair( nid, *std::get_if< array_handle >( &var ) );
388  }
389 
390  std::optional< std::pair< node_id, object_handle > > make_object_node()
391  {
392  std::optional opt_val = make_node( object_type{ mem_res_.get() } );
393  if ( !opt_val )
394  return std::nullopt;
395  auto [nid, iter] = *opt_val;
396  auto var = iter->second.get_container_handle();
397  return std::make_pair( nid, *std::get_if< object_handle >( &var ) );
398  }
399 
400 private:
401  std::optional< std::pair< node_id, iterator > > make_node( content_type cont )
402  {
403  if ( mem_res_.get().is_full() )
404  return std::nullopt;
405  auto nid = static_cast< node_id >( data_.size() );
406  auto [iter, inserted] = data_.emplace( nid, node_type{ std::move( cont ) } );
407  return std::make_pair( nid, iter );
408  }
409 
410  container data_;
411  std::reference_wrapper< pmr::memory_resource > mem_res_;
412 };
413 
414 #ifdef EMLABCPP_USE_OSTREAM
415 template < typename Key, typename Value >
416 std::ostream& operator<<( std::ostream& os, contiguous_tree< Key, Value > const& tree )
417 {
418  for ( auto const& [nid, node] : tree )
419  os << nid << ":" << node << "\n";
420  return os;
421 }
422 #endif
423 
424 } // namespace emlabcpp
Definition: tree.h:130
const_iterator begin() const
Definition: tree.h:158
std::optional< node_id > get_child(child_id chid) const
Definition: tree.h:168
contiguous_array_handle(array_type *arr)
Definition: tree.h:143
iterator begin()
Definition: tree.h:148
void append(node_id nid)
Definition: tree.h:181
const_iterator end() const
Definition: tree.h:163
uint32_t size() const
Definition: tree.h:176
typename array_type::node_type node_type
Definition: tree.h:141
iterator end()
Definition: tree.h:153
Definition: tree.h:202
contiguous_object_handle< object_type const > const_object_handle
Definition: tree.h:212
Value value_type
Definition: tree.h:205
contiguous_array_handle< array_type > array_handle
Definition: tree.h:213
pmr::map< key_type, node_id > object_type
Definition: tree.h:209
uint32_t child_id
Definition: tree.h:207
Value const * get_value() const
Definition: tree.h:221
Value * get_value()
Definition: tree.h:226
contiguous_array_handle< array_type const > const_array_handle
Definition: tree.h:214
std::variant< std::reference_wrapper< Value const >, object_handle, array_handle > get_container_handle()
Definition: tree.h:233
std::variant< Value, array_type, object_type > content_type
Definition: tree.h:210
pmr::map< child_id, node_id > array_type
Definition: tree.h:208
contiguous_node(content_type cont)
Definition: tree.h:216
contiguous_tree_type get_type() const
Definition: tree.h:255
uint32_t node_id
Definition: tree.h:206
Key key_type
Definition: tree.h:204
contiguous_object_handle< object_type > object_handle
Definition: tree.h:211
std::variant< std::reference_wrapper< Value const >, const_object_handle, const_array_handle > get_container_handle() const
Definition: tree.h:246
uint32_t size() const
Definition: tree.h:94
key_type const * get_key(child_id chid) const
Definition: tree.h:99
const_iterator begin() const
Definition: tree.h:67
typename object_type::node_type node_type
Definition: tree.h:50
iterator begin()
Definition: tree.h:57
std::optional< node_id > get_child(child_id chid) const
Definition: tree.h:77
const_iterator end() const
Definition: tree.h:72
contiguous_object_handle(object_type *obj)
Definition: tree.h:52
std::optional< node_id > get_child(key_type k) const
Definition: tree.h:86
void set(key_type const &k, node_id nid)
Definition: tree.h:109
iterator end()
Definition: tree.h:62
Definition: tree.h:289
std::optional< std::pair< node_id, array_handle > > make_array_node()
Definition: tree.h:380
const_iterator end() const
Definition: tree.h:356
Key key_type
Definition: tree.h:291
Value value_type
Definition: tree.h:292
bool empty() const
Definition: tree.h:366
node_type * get_node(node_id nid)
Definition: tree.h:333
pmr::map< key_type, node_id > object_type
Definition: tree.h:296
typename container::iterator iterator
Definition: tree.h:305
uint32_t child_id
Definition: tree.h:294
contiguous_node< Key, Value > node_type
Definition: tree.h:297
typename node_type::object_handle object_handle
Definition: tree.h:300
typename container::const_iterator const_iterator
Definition: tree.h:306
std::optional< std::pair< node_id, object_handle > > make_object_node()
Definition: tree.h:390
typename node_type::array_handle array_handle
Definition: tree.h:302
void clear()
Definition: tree.h:320
static constexpr std::size_t required_pool_size
Definition: tree.h:309
pmr::map< child_id, node_id > array_type
Definition: tree.h:295
pmr::map< node_id, node_type > container
Definition: tree.h:298
iterator begin()
Definition: tree.h:341
node_type const * get_node(node_id nid) const
Definition: tree.h:325
typename node_type::const_array_handle const_array_handle
Definition: tree.h:303
uint32_t node_id
Definition: tree.h:293
contiguous_tree(pmr::memory_resource &mem_res)
Definition: tree.h:314
std::optional< node_id > make_value_node(value_type val)
Definition: tree.h:371
std::size_t size() const
Definition: tree.h:361
const_iterator begin() const
Definition: tree.h:351
typename node_type::const_object_handle const_object_handle
Definition: tree.h:301
typename node_type::content_type content_type
Definition: tree.h:299
iterator end()
Definition: tree.h:346
Definition: memory_resource.h:33
Definition: pool_resource.h:36
std::map< Key, T, std::less< Key >, allocator< std::pair< Key const, T > > > map
Definition: aliases.h:62
key_type_buffer key_type
Definition: base.h:47
MIT License.
Definition: impl.h:31
decltype(auto) match(Variant &&var, Callables &&... cals)
Definition: match.h:55
decltype(auto) visit(Visitor &&vis, Variant &&var)
Reimplementation of std::visit.
Definition: visit.h:44
contiguous_tree_type
Definition: base.h:33
std::ostream & operator<<(std::ostream &os, string_buffer< N > const &sb)
Definition: string_buffer.h:112