CBMC
sharing_node.h
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Sharing node
4 
5 Author: Daniel Poetzl
6 
7 \*******************************************************************/
8 
11 
12 #ifndef CPROVER_UTIL_SHARING_NODE_H
13 #define CPROVER_UTIL_SHARING_NODE_H
14 
15 #ifdef SN_DEBUG
16 #include <iostream>
17 #endif
18 
19 #include <forward_list>
20 #include <functional>
21 #include <type_traits>
22 
23 #ifndef SN_SMALL_MAP
24 #define SN_SMALL_MAP 1
25 #endif
26 
27 #ifndef SN_SHARE_KEYS
28 #define SN_SHARE_KEYS 0
29 #endif
30 
31 #if SN_SMALL_MAP == 1
32 #include "small_map.h"
33 #else
34 #include <map>
35 #endif
36 
37 #include "as_const.h"
38 #include "invariant.h"
39 #include "small_shared_n_way_ptr.h"
40 #include "small_shared_ptr.h"
41 
42 #ifdef SN_INTERNAL_CHECKS
43 #define SN_ASSERT(b) INVARIANT(b, "Sharing node internal invariant")
44 #define SN_ASSERT_USE(v, b) SN_ASSERT(b)
45 #else
46 #define SN_ASSERT(b)
47 #define SN_ASSERT_USE(v, b) static_cast<void>(v);
48 #endif
49 
50 // clang-format off
51 #define SN_TYPE_PAR_DECL \
52  template <typename keyT, \
53  typename valueT, \
54  typename equalT = std::equal_to<keyT>>
55 
56 #define SN_TYPE_PAR_DEF \
57  template <typename keyT, typename valueT, typename equalT>
58 
59 #define SN_TYPE_ARGS keyT, valueT, equalT
60 
61 #define SN_PTR_TYPE_ARGS \
62  d_containert<SN_TYPE_ARGS>, d_leaft<SN_TYPE_ARGS>, d_internalt<SN_TYPE_ARGS>
63 // clang-format on
64 
66 
68 
70 {
71 public:
73 #if SN_SMALL_MAP == 1
75 #else
76  typedef std::map<std::size_t, innert> to_mapt;
77 #endif
78 
80 };
81 
83 {
84 public:
86  typedef std::forward_list<leaft> leaf_listt;
87 
89 };
90 
92 {
93 public:
94 #if SN_SHARE_KEYS == 1
95  typedef std::shared_ptr<keyT> keyt;
96 #else
97  typedef keyT keyt;
98 #endif
99 
100  template <class valueU>
101  d_leaft(const keyt &k, valueU &&v) : k(k), v(std::forward<valueU>(v))
102  {
103  }
105 
106  valueT v;
107 };
108 
110 {
111 public:
113  typedef typename datat::use_countt use_countt;
114 
118 
119  typedef typename d_it::to_mapt to_mapt;
120 
121  typedef typename d_ct::leaft leaft;
122  typedef typename d_ct::leaf_listt leaf_listt;
123 
125  {
126  }
127 
128  template <class valueU>
129  sharing_nodet(const keyT &k, valueU &&v)
130  {
131  SN_ASSERT(!data);
132 
133 #if SN_SHARE_KEYS == 1
134  SN_ASSERT(d.k == nullptr);
135  data = make_shared_3<1, SN_PTR_TYPE_ARGS>(
136  std::make_shared<keyT>(k), std::forward<valueU>(v));
137 #else
138  data = make_shared_3<1, SN_PTR_TYPE_ARGS>(k, std::forward<valueU>(v));
139 #endif
140  }
141 
142  bool empty() const
143  {
144  return !data;
145  }
146 
147  void clear()
148  {
149  // only the root node may be cleared which is an internal node
151 
152  data.reset();
153  }
154 
155  bool shares_with(const sharing_nodet &other) const
156  {
157  SN_ASSERT(data);
158  SN_ASSERT(other.data);
159 
160  return data == other.data;
161  }
162 
164  {
165  return data.use_count();
166  }
167 
168  void swap(sharing_nodet &other)
169  {
170  data.swap(other.data);
171  }
172 
173  // Types
174 
175  bool is_internal() const
176  {
177  return data.template is_derived<2>();
178  }
179 
180  bool is_container() const
181  {
182  return data.template is_derived<0>();
183  }
184 
185  bool is_leaf() const
186  {
187  return data.template is_derived<1>();
188  }
189 
190  bool is_defined_internal() const
191  {
192  return !empty() && is_internal();
193  }
194 
195  bool is_defined_container() const
196  {
197  return !empty() && is_container();
198  }
199 
200  bool is_defined_leaf() const
201  {
202  return !empty() && is_leaf();
203  }
204 
205  const d_it &read_internal() const
206  {
207  SN_ASSERT(!empty());
208 
209  return *data.template get_derived<2>();
210  }
211 
212  const d_ct &read_container() const
213  {
214  SN_ASSERT(!empty());
215 
216  return *data.template get_derived<0>();
217  }
218 
219  const d_lt &read_leaf() const
220  {
221  SN_ASSERT(!empty());
222 
223  return *data.template get_derived<1>();
224  }
225 
226  // Accessors
227 
228  const to_mapt &get_to_map() const
229  {
230  return read_internal().m;
231  }
232 
234  {
235  return write_internal().m;
236  }
237 
238  const leaf_listt &get_container() const
239  {
240  return read_container().con;
241  }
242 
244  {
245  return write_container().con;
246  }
247 
248  // Containers
249 
250  const leaft *find_leaf(const keyT &k) const
251  {
253 
254  const leaf_listt &c = get_container();
255 
256  for(const auto &n : c)
257  {
258  SN_ASSERT(n.is_leaf());
259 
260  if(equalT()(n.get_key(), k))
261  return &n;
262  }
263 
264  return nullptr;
265  }
266 
267  leaft *find_leaf(const keyT &k)
268  {
270 
271  leaf_listt &c = get_container();
272 
273  for(auto &n : c)
274  {
275  SN_ASSERT(n.is_leaf());
276 
277  if(equalT()(n.get_key(), k))
278  return &n;
279  }
280 
281  UNREACHABLE;
282  return nullptr;
283  }
284 
285  // add leaf, key must not exist yet
286  template <class valueU>
287  void place_leaf(const keyT &k, valueU &&v)
288  {
289  SN_ASSERT(is_container()); // empty() is allowed
290 
291  // we need to check empty() first as the const version of find_leaf() must
292  // not be called on an empty node
293  PRECONDITION(empty() || as_const_ptr(this)->find_leaf(k) == nullptr);
294 
295  leaf_listt &c = get_container();
296  c.emplace_front(k, std::forward<valueU>(v));
297  SN_ASSERT(c.front().is_defined_leaf());
298  }
299 
300  // remove leaf, key must exist
301  void remove_leaf(const keyT &k)
302  {
304 
305  leaf_listt &c = get_container();
306 
307  SN_ASSERT(!c.empty());
308 
309  const leaft &first = c.front();
310 
311  if(equalT()(first.get_key(), k))
312  {
313  c.pop_front();
314  return;
315  }
316 
317  typename leaf_listt::const_iterator last_it = c.begin();
318 
319  typename leaf_listt::const_iterator it = c.begin();
320  it++;
321 
322  for(; it != c.end(); it++)
323  {
324  const leaft &leaf = *it;
325 
326  SN_ASSERT(leaf.is_defined_leaf());
327 
328  if(equalT()(leaf.get_key(), k))
329  {
330  c.erase_after(last_it);
331  return;
332  }
333 
334  last_it = it;
335  }
336 
337  UNREACHABLE;
338  }
339 
340  // Inner nodes
341 
342  const typename d_it::innert *find_child(const std::size_t n) const
343  {
345 
346  const to_mapt &m = get_to_map();
347  typename to_mapt::const_iterator it = m.find(n);
348 
349 #if SN_SMALL_MAP == 1
350  if(it != m.end())
351  return &it.get_value();
352 #else
353  if(it != m.end())
354  return &it->second;
355 #endif
356 
357  return nullptr;
358  }
359 
360  typename d_it::innert &add_child(const std::size_t n)
361  {
362  SN_ASSERT(is_internal()); // empty() is allowed
363 
364  to_mapt &m = get_to_map();
365  return m[n];
366  }
367 
368  void remove_child(const std::size_t n)
369  {
371 
372  to_mapt &m = get_to_map();
373  std::size_t r = m.erase(n);
374 
375  SN_ASSERT_USE(r, r == 1);
376  }
377 
378  // Leafs
379 
380  const keyT &get_key() const
381  {
383 
384 #if SN_SHARE_KEYS == 1
385  return *read_leaf().k;
386 #else
387  return read_leaf().k;
388 #endif
389  }
390 
391  const valueT &get_value() const
392  {
394 
395  return read_leaf().v;
396  }
397 
398  template <class valueU>
399  void make_leaf(const keyT &k, valueU &&v)
400  {
401  SN_ASSERT(!data);
402 
403  data = make_shared_3<1, SN_PTR_TYPE_ARGS>(k, std::forward<valueU>(v));
404  }
405 
406  template <class valueU>
407  void set_value(valueU &&v)
408  {
410 
411  if(data.use_count() > 1)
412  {
413  data =
414  make_shared_3<1, SN_PTR_TYPE_ARGS>(get_key(), std::forward<valueU>(v));
415  }
416  else
417  {
418  data.template get_derived<1>()->v = std::forward<valueU>(v);
419  }
420 
421  SN_ASSERT(data.use_count() == 1);
422  }
423 
424  void mutate_value(std::function<void(valueT &)> mutator)
425  {
427 
428  if(data.use_count() > 1)
429  {
430  data = make_shared_3<1, SN_PTR_TYPE_ARGS>(read_leaf());
431  }
432 
433  mutator(data.template get_derived<1>()->v);
434 
435  SN_ASSERT(data.use_count() == 1);
436  }
437 
438 protected:
440  {
442 
443  if(!data)
444  {
445  data = make_shared_3<2, SN_PTR_TYPE_ARGS>();
446  }
447  else if(data.use_count() > 1)
448  {
449  data = make_shared_3<2, SN_PTR_TYPE_ARGS>(read_internal());
450  }
451 
452  SN_ASSERT(data.use_count() == 1);
453 
454  return *data.template get_derived<2>();
455  }
456 
458  {
460 
461  if(!data)
462  {
463  data = make_shared_3<0, SN_PTR_TYPE_ARGS>();
464  }
465  else if(data.use_count() > 1)
466  {
467  data = make_shared_3<0, SN_PTR_TYPE_ARGS>(read_container());
468  }
469 
470  SN_ASSERT(data.use_count() == 1);
471 
472  return *data.template get_derived<0>();
473  }
474 
476 };
477 
478 #endif
const T * as_const_ptr(T *t)
Return a pointer to the same object but ensures the type is pointer to const.
Definition: as_const.h:21
sharing_nodet< keyT, valueT, equalT > leaft
Definition: sharing_node.h:85
leaf_listt con
Definition: sharing_node.h:88
std::forward_list< leaft > leaf_listt
Definition: sharing_node.h:86
sharing_nodet< keyT, valueT, equalT > innert
Definition: sharing_node.h:72
small_mapt< innert > to_mapt
Definition: sharing_node.h:74
to_mapt m
Definition: sharing_node.h:79
d_leaft(const keyt &k, valueU &&v)
Definition: sharing_node.h:101
keyT keyt
Definition: sharing_node.h:97
valueT v
Definition: sharing_node.h:106
bool is_defined_container() const
Definition: sharing_node.h:195
d_ct & write_container()
Definition: sharing_node.h:457
void make_leaf(const keyT &k, valueU &&v)
Definition: sharing_node.h:399
d_internalt< keyT, valueT, equalT > d_it
Definition: sharing_node.h:115
small_shared_n_way_ptrt< d_containert< keyT, valueT, equalT >, d_leaft< keyT, valueT, equalT >, d_internalt< keyT, valueT, equalT > > datat
Definition: sharing_node.h:112
bool empty() const
Definition: sharing_node.h:142
void set_value(valueU &&v)
Definition: sharing_node.h:407
void remove_child(const std::size_t n)
Definition: sharing_node.h:368
const d_lt & read_leaf() const
Definition: sharing_node.h:219
bool is_defined_internal() const
Definition: sharing_node.h:190
void swap(sharing_nodet &other)
Definition: sharing_node.h:168
void place_leaf(const keyT &k, valueU &&v)
Definition: sharing_node.h:287
const leaf_listt & get_container() const
Definition: sharing_node.h:238
d_ct::leaf_listt leaf_listt
Definition: sharing_node.h:122
void mutate_value(std::function< void(valueT &)> mutator)
Definition: sharing_node.h:424
d_it::innert & add_child(const std::size_t n)
Definition: sharing_node.h:360
bool is_defined_leaf() const
Definition: sharing_node.h:200
to_mapt & get_to_map()
Definition: sharing_node.h:233
leaf_listt & get_container()
Definition: sharing_node.h:243
const d_it & read_internal() const
Definition: sharing_node.h:205
d_leaft< keyT, valueT, equalT > d_lt
Definition: sharing_node.h:117
use_countt use_count() const
Definition: sharing_node.h:163
d_ct::leaft leaft
Definition: sharing_node.h:121
const d_it::innert * find_child(const std::size_t n) const
Definition: sharing_node.h:342
bool shares_with(const sharing_nodet &other) const
Definition: sharing_node.h:155
const to_mapt & get_to_map() const
Definition: sharing_node.h:228
d_it & write_internal()
Definition: sharing_node.h:439
sharing_nodet(const keyT &k, valueU &&v)
Definition: sharing_node.h:129
bool is_leaf() const
Definition: sharing_node.h:185
const keyT & get_key() const
Definition: sharing_node.h:380
d_containert< keyT, valueT, equalT > d_ct
Definition: sharing_node.h:116
const d_ct & read_container() const
Definition: sharing_node.h:212
datat::use_countt use_countt
Definition: sharing_node.h:113
bool is_container() const
Definition: sharing_node.h:180
leaft * find_leaf(const keyT &k)
Definition: sharing_node.h:267
void remove_leaf(const keyT &k)
Definition: sharing_node.h:301
bool is_internal() const
Definition: sharing_node.h:175
const valueT & get_value() const
Definition: sharing_node.h:391
d_it::to_mapt to_mapt
Definition: sharing_node.h:119
const leaft * find_leaf(const keyT &k) const
Definition: sharing_node.h:250
const_iterator find(std::size_t idx) const
Definition: small_map.h:423
const_iterator end() const
Definition: small_map.h:332
std::size_t erase(std::size_t idx)
Definition: small_map.h:437
This class is similar to small_shared_ptrt and boost's intrusive_ptr.
void reset()
Clears this shared pointer.
use_countt use_count() const
Get the use count of the pointed-to object.
void swap(small_shared_n_way_ptrt &rhs)
static int8_t r
Definition: irep_hash.h:60
#define SN_ASSERT(b)
Definition: sharing_node.h:46
small_shared_n_way_pointee_baset< 3, unsigned > d_baset
Definition: sharing_node.h:65
#define SN_ASSERT_USE(v, b)
Definition: sharing_node.h:47
#define SN_TYPE_PAR_DECL
Definition: sharing_node.h:51
#define SN_TYPE_PAR_DEF
Definition: sharing_node.h:56
Small map.
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463