CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
small_map.h
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Small map
4
5Author: Daniel Poetzl
6
7\*******************************************************************/
8
11
12#ifndef CPROVER_UTIL_SMALL_MAP_H
13#define CPROVER_UTIL_SMALL_MAP_H
14
15#include <bitset>
16#include <cstdint>
17#include <cstring>
18#include <limits>
19#include <memory>
20#include <new>
21#include <type_traits>
22#include <utility>
23
24#include "invariant.h"
25
26//#define _SMALL_MAP_REALLOC_STATS
27
67template <typename T, typename Ind = uint32_t, std::size_t Num = 8>
69{
70public:
72 {
73 }
74
75private:
76 static_assert(std::is_unsigned<Ind>::value, "Ind should be an unsigned type");
77
79
80 friend void small_map_test();
81
82 // Memory
83
84 void copy(T *dest, const T *src, std::size_t n) const
85 {
86 for(std::size_t i = 0; i < n; i++)
87 {
88 new(dest + i) T(*(src + i));
89 }
90 }
91
92 T *allocate(std::size_t n) const
93 {
94 if(n == 0)
95 return nullptr;
96
97 T *mem = (T *)malloc(sizeof(T) * n);
98
99 if(!mem)
100 throw std::bad_alloc();
101
102 return mem;
103 }
104
105 T *allocate(T *ptr, std::size_t n) const
106 {
107 if(n == 0)
108 return nullptr;
109
110 // explicitly cast to char * as GCC 8 warns about not using new/delete for
111 // class sharing_node_innert<dstringt, std::basic_string<char>,
112 // std::equal_to<dstringt> >
113 T *mem = (T *)realloc((char *)ptr, sizeof(T) * n);
114
115 if(!mem)
116 throw std::bad_alloc();
117
118#ifdef _SMALL_MAP_REALLOC_STATS
119 if(ptr == mem)
120 {
122 }
123 else if(ptr != nullptr)
124 {
126 }
127#endif
128
129 return mem;
130 }
131
132public:
133 small_mapt(const small_mapt &m) : ind(m.ind), p(m.p)
134 {
135 if(m.p == nullptr)
136 {
137 return;
138 }
139
140 const std::size_t n = m.size();
141 INVARIANT(n > 0, "size is > 0 if data pointer is non-null");
142
143 p = allocate(n);
144
145 copy(p, m.p, n);
146 }
147
149 {
150 if(p)
151 {
152 std::size_t n = size();
153
154 for(std::size_t i = 0; i < n; i++)
155 {
156 (p + i)->~T();
157 }
158
159 free(p);
160 }
161 }
162
163private:
164 // Derived config
165
166 static const std::size_t N_BITS = std::numeric_limits<index_fieldt>::digits;
167
168 static const std::size_t NUM = Num;
169
170 static_assert(NUM >= 2, "NUM should be at least 2");
171
172 static constexpr std::size_t num_bits(const std::size_t n)
173 {
174 return n < 2 ? 1 : 1 + num_bits(n >> 1);
175 }
176
177 static constexpr std::size_t S_BITS = NUM * num_bits(NUM - 1) + NUM;
178
179 static const std::size_t BITS = num_bits(NUM - 1) + 1;
180
181 static constexpr index_fieldt indicator_mask(const index_fieldt digit = 1)
182 {
183 return !digit ? 0 : digit | indicator_mask(digit << BITS);
184 }
185
187
188 static const index_fieldt MASK = ((index_fieldt)1 << BITS) - 1;
189
190 static_assert(S_BITS <= N_BITS, "S_BITS should be no larger than N_BITS");
191
192 static_assert(
193 std::numeric_limits<std::size_t>::digits >= BITS,
194 "BITS must fit into an unsigned");
195
196 // Internal
197
198 std::size_t get_field(std::size_t field) const
199 {
201
202 std::size_t shift = field * BITS;
203 return (ind & (MASK << shift)) >> shift;
204 }
205
206 void set_field(std::size_t field, std::size_t v)
207 {
209 PRECONDITION((std::size_t)(v >> 1) < NUM);
210
211 std::size_t shift = field * BITS;
212
213 ind &= ~((index_fieldt)MASK << shift);
214 ind |= (index_fieldt)v << shift;
215 }
216
217 void shift_indices(std::size_t ii)
218 {
219 for(std::size_t idx = 0; idx < S_BITS / BITS; idx++)
220 {
221 std::size_t v = get_field(idx);
222 if(v & 1)
223 {
224 v >>= 1;
225 if(v > ii)
226 {
227 v = ((v - 1) << 1) | 1;
228 set_field(idx, v);
229 }
230 }
231 }
232 }
233
234public:
235 // Standard const iterator
236
237 typedef std::pair<const std::size_t, const T &> valuet;
238
243 {
244 public:
245 explicit const_iterator(const small_mapt &m) : m(m), idx(0), ii(0)
246 {
247 find_next();
248 }
249
251 const small_mapt &m,
252 const std::size_t idx,
253 const std::size_t ii)
254 : m(m), idx(idx), ii(ii)
255 {
256 }
257
258 const valuet operator*() const
259 {
260 return valuet(idx, *(m.p + ii));
261 }
262
263 const std::shared_ptr<valuet> operator->() const
264 {
265 return std::make_shared<valuet>(idx, *(m.p + ii));
266 }
267
272 const T &get_value() const
273 {
274 return *(m.p + ii);
275 }
276
278 {
279 idx++;
280 find_next();
281
282 return *this;
283 }
284
286 {
287 std::size_t old_idx = idx;
288 std::size_t old_ii = ii;
289
290 idx++;
291 find_next();
292
293 return const_iterator(m, old_idx, old_ii);
294 }
295
296 bool operator==(const const_iterator &other) const
297 {
298 return idx == other.idx;
299 }
300
301 bool operator!=(const const_iterator &other) const
302 {
303 return idx != other.idx;
304 }
305
306 private:
308 {
309 while(idx < NUM)
310 {
311 std::size_t v = m.get_field(idx);
312 if(v & 1)
313 {
314 ii = v >> 1;
315 break;
316 }
317
318 idx++;
319 }
320 }
321
322 const small_mapt &m;
323 std::size_t idx;
324 std::size_t ii;
325 };
326
328 {
329 return const_iterator(*this);
330 }
331
333 {
334 return const_iterator(*this, NUM, 0);
335 }
336
343 {
344 public:
345 const_value_iterator(const small_mapt &m, const int ii) : m(m), ii(ii)
346 {
347 }
348
349 const T &operator*() const
350 {
351 return *(m.p + ii);
352 }
353
354 const T *operator->() const
355 {
356 return m.p + ii;
357 }
358
360 {
361 ii--;
362
363 return *this;
364 }
365
367 {
368 int old_ii = ii;
369
370 ii--;
371
373 }
374
375 bool operator==(const const_value_iterator &other) const
376 {
377 return ii == other.ii;
378 }
379
380 bool operator!=(const const_value_iterator &other) const
381 {
382 return ii != other.ii;
383 }
384
385 private:
386 const small_mapt &m;
387 int ii;
388 };
389
391 {
392 return const_value_iterator(*this, size() - 1);
393 }
394
396 {
397 return const_value_iterator(*this, -1);
398 }
399
400 // Interface
401
402 T &operator[](std::size_t idx)
403 {
404 PRECONDITION(idx < NUM);
405
406 std::size_t v = get_field(idx);
407 if(v & 1)
408 {
409 std::size_t ii = v >> 1;
410 return *(p + ii);
411 }
412
413 std::size_t ii = size();
414 p = allocate(p, ii + 1);
415 new(p + ii) T();
416
417 v = (ii << 1) | 1;
418 set_field(idx, v);
419
420 return *(p + ii);
421 }
422
423 const_iterator find(std::size_t idx) const
424 {
425 PRECONDITION(idx < NUM);
426
427 std::size_t v = get_field(idx);
428 if(v & 1)
429 {
430 std::size_t ii = v >> 1;
431 return const_iterator(*this, idx, ii);
432 }
433
434 return end();
435 }
436
437 std::size_t erase(std::size_t idx)
438 {
439 PRECONDITION(idx < NUM);
440
441 std::size_t v = get_field(idx);
442
443 if(v & 1)
444 {
445 std::size_t ii = v >> 1;
446
447 (p + ii)->~T();
448 std::size_t n = size();
449 if(ii < n - 1)
450 {
451 // explicitly cast to char * as GCC 8 warns about not using new/delete
452 // for
453 // class sharing_node_innert<dstringt, std::basic_string<char>,
454 // std::equal_to<dstringt> >
455 memmove((char *)(p + ii), p + ii + 1, sizeof(T) * (n - ii - 1));
456 }
457
458 p = allocate(p, n - 1);
459
460 if(n == 1)
461 {
462 p = nullptr;
463 }
464
465 set_field(idx, 0);
466 shift_indices(ii);
467
468 return 1;
469 }
470
471 return 0;
472 }
473
474 small_mapt *copy_and_erase(std::size_t idx) const
475 {
476 PRECONDITION(idx < NUM);
477
478 std::size_t v = get_field(idx);
479 INVARIANT(v & 1, "element must be in map");
480
481 std::size_t ii = v >> 1;
482 std::size_t n = size();
483
484 // new map
485
486 small_mapt *m = new small_mapt();
487
488 if(n == 1)
489 {
490 return m;
491 }
492
493 m->p = allocate(n - 1);
494
495 // copy part before erased element
496 copy(m->p, p, ii);
497
498 // copy part after erased element
499 copy(m->p + ii, p + ii + 1, n - ii - 1);
500
501 m->ind = ind;
502 m->set_field(idx, 0);
503 m->shift_indices(ii);
504
505 return m;
506 }
507
508 small_mapt *copy_and_insert(std::size_t idx, const T &value) const
509 {
510 PRECONDITION(idx < NUM);
511
512 std::size_t v = get_field(idx);
513 INVARIANT(!(v & 1), "element must not be in map");
514
515 std::size_t n = size();
516 std::size_t ii = n;
517
518 small_mapt *m = new small_mapt();
519
520 m->p = allocate(n + 1);
521
522 // copy old elements
523 copy(m->p, p, n);
524
525 // new element
526 new(m->p + ii) T(value);
527
528 m->ind = ind;
529 v = (ii << 1) | 1;
530 m->set_field(idx, v);
531
532 return m;
533 }
534
535 std::size_t size() const
536 {
537 std::bitset<N_BITS> bs(ind & IND);
538 return bs.count();
539 }
540
541 bool empty() const
542 {
543 return !ind;
544 }
545
546#ifdef _SMALL_MAP_REALLOC_STATS
547 mutable std::size_t realloc_failure = 0;
548 mutable std::size_t realloc_success = 0;
549#endif
550
551private:
553 T *p;
554};
555
556#endif
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
bool operator==(const const_iterator &other) const
Definition small_map.h:296
const_iterator(const small_mapt &m, const std::size_t idx, const std::size_t ii)
Definition small_map.h:250
const_iterator operator++()
Definition small_map.h:277
bool operator!=(const const_iterator &other) const
Definition small_map.h:301
const std::shared_ptr< valuet > operator->() const
Definition small_map.h:263
const T & get_value() const
Non-standard direct access to the underlying value instead of creating a valuet object.
Definition small_map.h:272
const valuet operator*() const
Definition small_map.h:258
const_iterator(const small_mapt &m)
Definition small_map.h:245
const_iterator operator++(int)
Definition small_map.h:285
const small_mapt & m
Definition small_map.h:322
Const value iterator.
Definition small_map.h:343
const_value_iterator operator++(int)
Definition small_map.h:366
const_value_iterator(const small_mapt &m, const int ii)
Definition small_map.h:345
const_value_iterator operator++()
Definition small_map.h:359
bool operator!=(const const_value_iterator &other) const
Definition small_map.h:380
bool operator==(const const_value_iterator &other) const
Definition small_map.h:375
Map from small integers to values.
Definition small_map.h:69
small_mapt * copy_and_insert(std::size_t idx, const T &value) const
Definition small_map.h:508
static const std::size_t BITS
Definition small_map.h:179
static constexpr std::size_t S_BITS
Definition small_map.h:177
static const std::size_t N_BITS
Definition small_map.h:166
std::size_t size() const
Definition small_map.h:535
small_mapt(const small_mapt &m)
Definition small_map.h:133
T * allocate(T *ptr, std::size_t n) const
Definition small_map.h:105
const_iterator find(std::size_t idx) const
Definition small_map.h:423
const_value_iterator value_begin() const
Definition small_map.h:390
bool empty() const
Definition small_map.h:541
static const index_fieldt IND
Definition small_map.h:186
const_iterator end() const
Definition small_map.h:332
void shift_indices(std::size_t ii)
Definition small_map.h:217
const_iterator begin() const
Definition small_map.h:327
T * allocate(std::size_t n) const
Definition small_map.h:92
index_fieldt ind
Definition small_map.h:552
static constexpr index_fieldt indicator_mask(const index_fieldt digit=1)
Definition small_map.h:181
std::size_t erase(std::size_t idx)
Definition small_map.h:437
const_value_iterator value_end() const
Definition small_map.h:395
static constexpr std::size_t num_bits(const std::size_t n)
Definition small_map.h:172
void set_field(std::size_t field, std::size_t v)
Definition small_map.h:206
static const index_fieldt MASK
Definition small_map.h:188
static const std::size_t NUM
Definition small_map.h:168
T & operator[](std::size_t idx)
Definition small_map.h:402
std::pair< const std::size_t, const T & > valuet
Definition small_map.h:237
std::size_t get_field(std::size_t field) const
Definition small_map.h:198
friend void small_map_test()
void copy(T *dest, const T *src, std::size_t n) const
Definition small_map.h:84
Ind index_fieldt
Definition small_map.h:78
small_mapt * copy_and_erase(std::size_t idx) const
Definition small_map.h:474
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
void * malloc(__CPROVER_size_t malloc_size)
Definition stdlib.c:212
void * realloc(void *ptr, __CPROVER_size_t malloc_size)
Definition stdlib.c:542
void free(void *ptr)
Definition stdlib.c:317
void * memmove(void *dest, const void *src, size_t n)
Definition string.c:837