CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
sharing_node.h
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Sharing node
4
5Author: 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"
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{
71public:
73#if SN_SMALL_MAP == 1
75#else
76 typedef std::map<std::size_t, innert> to_mapt;
77#endif
78
80};
81
83{
84public:
86 typedef std::forward_list<leaft> leaf_listt;
87
89};
90
92{
93public:
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
107};
108
110{
111public:
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);
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 {
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
191 {
192 return !empty() && is_internal();
193 }
194
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
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
268 {
270
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
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
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
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
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>
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 {
431 }
432
433 mutator(data.template get_derived<1>()->v);
434
435 SN_ASSERT(data.use_count() == 1);
436 }
437
438protected:
440 {
442
443 if(!data)
444 {
446 }
447 else if(data.use_count() > 1)
448 {
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 {
464 }
465 else if(data.use_count() > 1)
466 {
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
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
sharing_nodet< keyT, valueT, equalT > leaft
leaf_listt con
std::forward_list< leaft > leaf_listt
sharing_nodet< keyT, valueT, equalT > innert
small_mapt< innert > to_mapt
d_leaft(const keyt &k, valueU &&v)
keyT keyt
valueT v
bool is_defined_container() const
void make_leaf(const keyT &k, valueU &&v)
d_internalt< keyT, valueT, equalT > d_it
leaft * find_leaf(const keyT &k)
small_shared_n_way_ptrt< d_containert< keyT, valueT, equalT >, d_leaft< keyT, valueT, equalT >, d_internalt< keyT, valueT, equalT > > datat
bool empty() const
void set_value(valueU &&v)
void remove_child(const std::size_t n)
d_it & write_internal()
bool is_defined_internal() const
void swap(sharing_nodet &other)
void place_leaf(const keyT &k, valueU &&v)
d_ct::leaf_listt leaf_listt
const leaf_listt & get_container() const
void mutate_value(std::function< void(valueT &)> mutator)
bool is_defined_leaf() const
const valueT & get_value() const
const d_it::innert * find_child(const std::size_t n) const
const d_it & read_internal() const
d_leaft< keyT, valueT, equalT > d_lt
use_countt use_count() const
const leaft * find_leaf(const keyT &k) const
d_ct::leaft leaft
d_ct & write_container()
bool shares_with(const sharing_nodet &other) const
d_it::innert & add_child(const std::size_t n)
sharing_nodet(const keyT &k, valueU &&v)
leaf_listt & get_container()
bool is_leaf() const
const to_mapt & get_to_map() const
d_containert< keyT, valueT, equalT > d_ct
datat::use_countt use_countt
bool is_container() const
const d_ct & read_container() const
void remove_leaf(const keyT &k)
const keyT & get_key() const
bool is_internal() const
const d_lt & read_leaf() const
d_it::to_mapt to_mapt
to_mapt & get_to_map()
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
STL namespace.
#define SN_ASSERT(b)
small_shared_n_way_pointee_baset< 3, unsigned > d_baset
#define SN_ASSERT_USE(v, b)
#define SN_TYPE_PAR_DECL
#define SN_TYPE_PAR_DEF
Small map.
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define PRECONDITION(CONDITION)
Definition invariant.h:463