ARB
downcast.h
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : downcast.h //
4 // Purpose : safely cast from base class to derived class //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in October 2009 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #ifndef DOWNCAST_H
13 #define DOWNCAST_H
14 
15 #ifndef ARB_ASSERT_H
16 #include <arb_assert.h>
17 #endif
18 #ifndef STATIC_ASSERT_H
19 #include "static_assert.h"
20 #endif
21 
22 #if defined(DEBUG)
23 #define SAFE_DOWNCASTS
24 #endif // DEBUG
25 
26 // --------------------
27 
28 namespace ARB_type_traits { // according to boost-type_traits or std-type_traits
29  // (remove when available in std for lowest supported gcc-version)
30  typedef char (&yes)[1];
31  typedef char (&no)[2];
32 
33  template< class T > struct remove_const { typedef T type; };
34  template< class T > struct remove_const<const T> { typedef T type; };
35 
36  template< class T > struct remove_volatile { typedef T type; };
37  template< class T > struct remove_volatile<volatile T> { typedef T type; };
38 
39  template< class T > struct remove_cv { typedef typename remove_volatile<typename remove_const<T>::type>::type type; };
40 
41  template <typename B, typename D>
42  struct Host {
43  operator B*() const;
44  operator D*();
45  };
46 
47  template <typename B, typename D>
48  struct is_base_of {
49  typedef const volatile B CVB;
50  typedef const volatile D CVD;
51 
52  template <typename T> static yes check(CVD*, T);
53  static no check(CVB*, int);
54 
55  static const bool value = sizeof(check(Host<CVB,CVD>(), int())) == sizeof(yes);
56  };
57 
58  template <typename T, typename U>
59  struct is_same {
60  static T *t;
61  static U *u;
62 
63  static yes check1(T*, T*);
64  static no check1(...);
65 
66  static yes check2(U*, U*);
67  static no check2(...);
68 
69  static const bool value = (sizeof(check1(t, u)) == sizeof(yes)) && (sizeof(check2(t, u)) == sizeof(yes));
70  };
71  // Note: test-code for ARB_type_traits was removed by [13300]
72 };
73 
74 // -----------------------------------------
75 // detect and deref pointer-types:
76 
77 
78 template<typename> struct dereference {
79  static const bool possible = false;
80 };
81 template<typename T> struct dereference<T*> {
82  static const bool possible = true;
83  typedef T type;
84 };
85 template<typename T> struct dereference<T*const> {
86  static const bool possible = true;
87  typedef T type;
88 };
89 
90 // ----------------------------------------------
91 // DOWNCAST from BASE* to DERIVED*
92 // - uses dynamic_cast in DEBUG mode and checks for failure
93 // - uses plain old cast in NDEBUG mode
94 
95 #if defined(SAFE_DOWNCASTS)
96 
97 template<class DERIVED>
98 inline DERIVED assert_downcasted(DERIVED expr) {
99  arb_assert(expr); // impossible DOWNCAST (expr is not of type DERIVED)
100  return expr;
101 }
102 
103 template<class DERIVED, class BASE>
104 inline DERIVED *safe_pointer_downcast(BASE *expr) {
105  STATIC_ASSERT_ANNOTATED(dereference<BASE >::possible == false, "got BASE** (expected BASE*)");
106  STATIC_ASSERT_ANNOTATED(dereference<DERIVED>::possible == false, "got DERIVED** (expected DERIVED*)");
107 
108  typedef typename ARB_type_traits::remove_cv<BASE >::type NCV_BASE;
109  typedef typename ARB_type_traits::remove_cv<DERIVED>::type NCV_DERIVED;
110 
111  STATIC_ASSERT_ANNOTATED((ARB_type_traits::is_same<NCV_BASE, NCV_DERIVED>::value == false), "useless downcast (BASE==DERIVED)");
112  STATIC_ASSERT_ANNOTATED((ARB_type_traits::is_base_of<BASE,DERIVED>::value), "downcast only allowed from base type to derived type");
113 
114  return expr
115  ? assert_downcasted<DERIVED*>(dynamic_cast<DERIVED*>(expr))
116  : NULp;
117 }
118 
119 template<class DERIVED_PTR, class BASE_PTR>
120 inline DERIVED_PTR safe_downcast(BASE_PTR expr) {
121  STATIC_ASSERT_ANNOTATED(dereference<BASE_PTR >::possible == true, "expected 'BASE*' as source type");
122  STATIC_ASSERT_ANNOTATED(dereference<DERIVED_PTR>::possible == true, "expected 'DERIVED*' as target type");
123 
124  typedef typename dereference<BASE_PTR >::type BASE;
125  typedef typename dereference<DERIVED_PTR>::type DERIVED;
126 
127  return safe_pointer_downcast<DERIVED,BASE>(expr);
128 }
129 
130 #define DOWNCAST(totype,expr) safe_downcast<totype,typeof(expr)>(expr)
131 
132 #else
133 
134 template<class DERIVED_PTR, class BASE_PTR>
135 inline DERIVED_PTR static_downcast(BASE_PTR expr) {
136  // Note: using this template delays the instantiation of the static_cast (until DERIVED is defined)
137  // (opposed to directly using static_cast in define of DOWNCAST below)
138  return static_cast<DERIVED_PTR>(expr);
139 }
140 
141 #define DOWNCAST(totype,expr) static_downcast<totype,typeof(expr)>(expr) // fixes undefined behavior
142 
143 #endif // SAFE_DOWNCASTS
144 
145 
146 // helper macro to overwrite accessor functions in derived classes
147 #define DEFINE_DOWNCAST_ACCESSORS(CLASS, NAME, VALUE) \
148  CLASS *NAME() { return DOWNCAST(CLASS*, VALUE); } \
149  const CLASS *NAME() const { return DOWNCAST(const CLASS*, VALUE); }
150 
151 // helper macro to cast references into 'totype'
152 #define DOWNCAST_REFERENCE(totype,expr) (*DOWNCAST(totype*, &(expr)))
153 
154 #else
155 #error downcast.h included twice
156 #endif // DOWNCAST_H
#define arb_assert(cond)
Definition: arb_assert.h:245
static const bool possible
Definition: downcast.h:79
const volatile B CVB
Definition: downcast.h:49
#define STATIC_ASSERT_ANNOTATED(const_expression, annotation)
Definition: static_assert.h:38
static yes check1(T *, T *)
const volatile D CVD
Definition: downcast.h:50
char(& yes)[1]
Definition: downcast.h:30
static void * D
Definition: mem.cxx:18
remove_volatile< typename remove_const< T >::type >::type type
Definition: downcast.h:39
DERIVED_PTR static_downcast(BASE_PTR expr)
Definition: downcast.h:135
static const bool value
Definition: downcast.h:55
char(& no)[2]
Definition: downcast.h:31
#define NULp
Definition: cxxforward.h:116
Definition: trnsprob.h:20
static yes check2(U *, U *)
static yes check(CVD *, T)
static Score ** U
Definition: align.cxx:67