CBMC
small_shared_n_way_ptr.h
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Small shared n-way pointer
4 
5 Author: Daniel Poetzl
6 
7 \*******************************************************************/
8 
9 #ifndef CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H
10 #define CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H
11 
12 #include <limits>
13 #include <tuple>
14 #include <type_traits>
15 #include <utility>
16 
17 #include "invariant.h"
18 
20 template <std::size_t I, typename... Ts>
21 struct get_typet
22 {
23  // NOLINTNEXTLINE(readability/identifiers)
24  typedef typename std::tuple_element<I, std::tuple<Ts...>>::type type;
25 };
26 
27 template <std::size_t N, typename Num>
29 
30 // Struct to hold the static method destruct() to destruct the pointee of a
31 // small shared n-way pointer.
32 //
33 // Note: This functionality should ideally be in a private static method of
34 // small_shared_n_way_ptrt, but partial template specializations are not allowed
35 // within other templates, hence it is defined at global scope.
36 template <std::size_t I, typename pointee_baset, typename... Ts>
37 struct destructt
38 {
39  static void destruct(pointee_baset *p)
40  {
41  if(p->template is_derived<I>())
42  {
43  typedef typename get_typet<I, Ts...>::type pointeet;
44  static_assert(
45  std::is_base_of<pointee_baset, pointeet>::value,
46  "indexed pointee type must be a subclass of the pointee base");
47 
48  delete static_cast<pointeet *>(p);
49  }
50  else
51  {
53  }
54  }
55 };
56 
57 template <typename pointee_baset, typename... Ts>
58 struct destructt<0, pointee_baset, Ts...>
59 {
60  static void destruct(pointee_baset *p)
61  {
62  PRECONDITION(p->template is_derived<0>());
63 
64  typedef typename get_typet<0, Ts...>::type pointeet;
65  static_assert(
66  std::is_base_of<pointee_baset, pointeet>::value,
67  "indexed pointee type must be a subclass of the pointee base");
68 
69  delete static_cast<pointeet *>(p);
70  }
71 };
72 
89 template <typename... Ts>
91 {
92 public:
93  static const std::size_t num_types =
94  std::tuple_size<std::tuple<Ts...>>::value;
95 
96  static_assert(
97  num_types >= 2,
98  "parameter pack should contain at least two types");
99 
100  typedef decltype(std::declval<typename get_typet<0, Ts...>::type>()
101  .get_use_count()) use_countt;
102 
104 
106 
114  template <std::size_t I>
115  static small_shared_n_way_ptrt<Ts...>
116  create_small_shared_n_way_ptr(typename get_typet<I, Ts...>::type *p)
117  {
118  PRECONDITION(p != nullptr);
119  PRECONDITION(p->get_use_count() == 0);
120 
121  p->template set_derived<I>();
123 
124  return small_shared_n_way_ptrt<Ts...>(p);
125  }
126 
128  {
130 
131  if(p)
132  {
134  }
135  }
136 
138  {
140 
141  swap(rhs);
142  }
143 
145  {
147 
148  small_shared_n_way_ptrt copy(rhs);
149  swap(copy);
150  return *this;
151  }
152 
154  {
156 
157  swap(rhs);
158  return *this;
159  }
160 
162  {
163  destruct();
164  }
165 
168  void reset()
169  {
170  destruct();
171  p = nullptr;
172  }
173 
175  {
177 
178  std::swap(p, rhs.p);
179  }
180 
185  {
186  return p ? p->get_use_count() : 0;
187  }
188 
192  template <std::size_t I>
193  bool is_derived() const
194  {
195  return p == nullptr || p->template is_derived<I>();
196  }
197 
204  {
205  return p;
206  }
207 
211  template <std::size_t I>
212  typename get_typet<I, Ts...>::type *get_derived() const
213  {
214  PRECONDITION(is_derived<I>());
215 
216  return static_cast<typename get_typet<I, Ts...>::type *>(p);
217  }
218 
222  bool is_same_type(const small_shared_n_way_ptrt &other) const
223  {
224  if(p == nullptr || other.p == nullptr)
225  return true;
226 
227  return p->is_same_type(*other.p);
228  }
229 
230  explicit operator bool() const
231  {
232  return p != nullptr;
233  }
234 
235 private:
236  template <typename T>
237  explicit small_shared_n_way_ptrt(T *p) : p(p)
238  {
239  }
240 
241  void destruct()
242  {
243  if(!p)
244  {
245  return;
246  }
247 
248  if(p->get_use_count() > 1)
249  {
251  return;
252  }
253 
255  }
256 
257  pointee_baset *p = nullptr;
258 };
259 
271 template <std::size_t I, typename U, typename V, typename... Ts>
273 {
274  return small_shared_n_way_ptrt<U, V>::template create_small_shared_n_way_ptr<
275  I>(new typename get_typet<I, U, V>::type(std::forward<Ts>(ts)...));
276 }
277 
290 template <std::size_t I, typename U, typename V, typename W, typename... Ts>
292 {
294  template create_small_shared_n_way_ptr<I>(
295  new typename get_typet<I, U, V, W>::type(std::forward<Ts>(ts)...));
296 }
297 
298 template <typename... Ts>
302 {
303  return lhs.get() == rhs.get();
304 }
305 
306 template <typename... Ts>
310 {
311  return lhs.get() != rhs.get();
312 }
313 
314 template <std::size_t N, typename Num>
316 {
317 public:
318  static_assert(std::is_unsigned<Num>::value, "Num must be an unsigned type");
319 
321 
322  // The use count shall be unaffected
324  {
325  }
326 
327  // The use count shall be unaffected
330  {
331  return *this;
332  }
333 
334  Num get_use_count() const
335  {
336  return use_count & use_count_mask;
337  }
338 
340  {
342 
343  ++use_count;
344  }
345 
347  {
349 
350  --use_count;
351  }
352 
353  template <std::size_t I>
354  void set_derived()
355  {
356  static_assert(I < N, "type index shall be within bounds");
357 
360  }
361 
362  template <std::size_t I>
363  bool is_derived() const
364  {
365  static_assert(I < N, "type index shall be within bounds");
366 
367  return ((use_count & ~use_count_mask) >> use_count_bit_width) == I;
368  }
369 
371  {
372  return !((use_count ^ other.use_count) & ~use_count_mask);
373  }
374 
375 private:
376  Num use_count = 0;
377 
378  static const int bit_width = std::numeric_limits<Num>::digits;
379 
380  static constexpr std::size_t num_bits(const std::size_t n)
381  {
382  return n < 2 ? 1 : 1 + num_bits(n >> 1);
383  }
384 
385  static const std::size_t type_bit_width = num_bits(N);
386 
387  static const std::size_t use_count_bit_width =
388  (std::size_t)bit_width - type_bit_width;
389 
390  static const Num use_count_mask = ((Num)1 << use_count_bit_width) - 1;
391 };
392 
393 #endif // CPROVER_UTIL_SMALL_SHARED_N_WAY_PTR_H
static const std::size_t type_bit_width
static const std::size_t use_count_bit_width
small_shared_n_way_pointee_baset & operator=(const small_shared_n_way_pointee_baset &)
small_shared_n_way_pointee_baset(const small_shared_n_way_pointee_baset &)
static constexpr std::size_t num_bits(const std::size_t n)
bool is_same_type(const small_shared_n_way_pointee_baset &other) const
This class is similar to small_shared_ptrt and boost's intrusive_ptr.
void reset()
Clears this shared pointer.
static const std::size_t num_types
small_shared_n_way_ptrt & operator=(const small_shared_n_way_ptrt &rhs)
get_typet< I, Ts... >::type * get_derived() const
Get pointer to the managed object.
small_shared_n_way_ptrt & operator=(small_shared_n_way_ptrt &&rhs)
use_countt use_count() const
Get the use count of the pointed-to object.
bool is_same_type(const small_shared_n_way_ptrt &other) const
Checks if the raw pointers held by *this and other both can be converted to a pointer to the same typ...
static small_shared_n_way_ptrt< Ts... > create_small_shared_n_way_ptr(typename get_typet< I, Ts... >::type *p)
Static factory method to construct a small shared n-way pointer, pointing to the given object *p of t...
pointee_baset * get() const
Get base type pointer to the managed object.
small_shared_n_way_ptrt(small_shared_n_way_ptrt &&rhs)
small_shared_n_way_ptrt(const small_shared_n_way_ptrt &rhs)
bool is_derived() const
Check if converting the held raw pointer to type Ts[I] is valid.
decltype(std::declval< typename get_typet< 0, Ts... >::type >() .get_use_count()) typedef use_countt
void swap(small_shared_n_way_ptrt &rhs)
bool operator==(const small_shared_n_way_ptrt< Ts... > &lhs, const small_shared_n_way_ptrt< Ts... > &rhs)
small_shared_n_way_ptrt< U, V, W > make_shared_3(Ts &&... ts)
Constructs a small shared n-way pointer, with three possible pointee types (i.e., n = 3),...
bool operator!=(const small_shared_n_way_ptrt< Ts... > &lhs, const small_shared_n_way_ptrt< Ts... > &rhs)
small_shared_n_way_ptrt< U, V > make_shared_2(Ts &&... ts)
Constructs a small shared n-way pointer, with two possible pointee types (i.e., n = 2),...
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
static void destruct(pointee_baset *p)
static void destruct(pointee_baset *p)
Get the type with the given index in the parameter pack.
std::tuple_element< I, std::tuple< Ts... > >::type type