source: branches/alilink/TEMPLATES/downcast.h

Last change on this file was 16768, checked in by westram, 7 years ago
File size: 5.5 KB
Line 
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
28namespace 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
78template<typename> struct dereference {
79    static const bool possible = false;
80};
81template<typename T> struct dereference<T*> {
82    static const bool possible = true;
83    typedef T type;
84};
85template<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
97template<class DERIVED>
98inline DERIVED assert_downcasted(DERIVED expr) {
99    arb_assert(expr); // impossible DOWNCAST (expr is not of type DERIVED)
100    return expr;
101}
102
103template<class DERIVED, class BASE>
104inline 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
119template<class DERIVED_PTR, class BASE_PTR>
120inline 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
134template<class DERIVED_PTR, class BASE_PTR>
135inline 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
Note: See TracBrowser for help on using the repository browser.