Lumiera  0.pre.03
»edityourfreedom«
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
access-casted.hpp
Go to the documentation of this file.
1 /*
2  ACCESS-CASTED.hpp - util template to access a value using conversion or cast as appropriate
3 
4  Copyright (C) Lumiera.org
5  2008, 2015 Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
50 #ifndef UTIL_ACCESS_CASTED_H
51 #define UTIL_ACCESS_CASTED_H
52 
53 #include "lib/error.hpp"
54 
55 #include <type_traits>
56 #include <utility>
57 
58 
59 
60 namespace util {
61 
62  namespace error = lumiera::error;
63 
64  namespace { // implementation helper traits....
65 
66  using std::remove_pointer;
67  using std::remove_reference;
68 
69 
70  template <typename T>
71  using PlainType = typename remove_pointer<
72  typename remove_reference<T>::type>::type;
73 
74  template <typename T>
75  struct has_RTTI
76  {
77  static constexpr bool value = std::is_polymorphic<PlainType<T>>::value;
78  };
79 
80  template <typename SRC, typename TAR>
81  struct can_downcast
82  {
83  static constexpr bool value = std::is_base_of<PlainType<SRC>, PlainType<TAR>>::value
84  && ( ( std::is_pointer<typename remove_reference<SRC>::type>::value
85  && std::is_pointer<typename remove_reference<TAR>::type>::value
86  )
87  ||( !std::is_pointer<typename remove_reference<SRC>::type>::value
88  && !std::is_pointer<typename remove_reference<TAR>::type>::value
89  ));
90  };
91 
92  template <typename SRC, typename TAR>
93  struct can_use_dynamic_downcast
94  {
95  static constexpr bool value = !std::is_convertible<SRC,TAR>::value
96  && can_downcast<SRC,TAR>::value
97  && has_RTTI<SRC>::value
98  && has_RTTI<TAR>::value;
99  };
100 
101  template <typename SRC, typename TAR>
102  struct can_use_conversion
103  : std::is_convertible<SRC,TAR>
104  { };
105 
106  template <typename SRC, typename TAR>
107  struct can_take_address
108  {
109  static constexpr bool value = !std::is_rvalue_reference<SRC>::value // considered dangerous
110  && !std::is_pointer<typename remove_reference<SRC>::type>::value
111  && std::is_pointer<typename remove_reference<TAR>::type>::value;
112  };
113 
114  template <typename SRC, typename TAR>
115  struct can_dereference
116  {
117  static constexpr bool value = !std::is_pointer<typename remove_reference<TAR>::type>::value
118  && std::is_pointer<typename remove_reference<SRC>::type>::value;
119  };
120 
121 
122  template <typename SRC, typename TAR>
123  struct if_can_use_dynamic_downcast
124  : std::enable_if< can_use_dynamic_downcast<SRC,TAR>::value, TAR>
125  { };
126 
127  template <typename SRC, typename TAR>
128  struct if_can_use_conversion
129  : std::enable_if< can_use_conversion<SRC,TAR>::value, TAR>
130  { };
131 
132  template <typename SRC, typename TAR>
133  struct if_can_take_address
134  : std::enable_if< can_take_address<SRC,TAR>::value, TAR>
135  { };
136 
137  template <typename SRC, typename TAR>
138  struct if_can_dereference
139  : std::enable_if< can_dereference<SRC,TAR>::value, TAR>
140  { };
141 
142  }//(End)helper traits
143 
144 
145 
146 
151  template<typename TAR>
153  {
154  typedef TAR Ret;
155 
156 
157  template<typename SRC>
158  static typename if_can_use_dynamic_downcast<SRC&&,TAR>::type
159  access (SRC&& elem)
160  {
161  try
162  {
163  return dynamic_cast<TAR> (std::forward<SRC>(elem));
164  }
165  catch (std::bad_cast& castError)
166  {
167  throw error::Invalid(castError
168  ,"AccessCasted: not the expected runtime type; downcast failed"
169  ,error::LUMIERA_ERROR_WRONG_TYPE);
170  }
171  }
172 
173 
174  template<typename SRC>
175  static typename if_can_use_conversion<SRC&&,TAR>::type
176  access (SRC&& elem)
177  {
178  return std::forward<SRC> (elem);
179  }
180 
181 
182  template<typename SRC>
183  static typename if_can_take_address<SRC&&,TAR>::type
184  access (SRC&& elem)
185  {
186  return AccessCasted<TAR>::access (&elem);
187  }
188 
189 
190  template<typename SRC>
191  static typename if_can_dereference<SRC&&,TAR>::type
192  access (SRC&& elem)
193  {
194  if (!elem)
195  throw error::Invalid("AccessCasted: attempt to build a value or reference from a NULL pointer"
196  ,error::LUMIERA_ERROR_BOTTOM_VALUE);
197 
198  return AccessCasted<TAR>::access (*elem);
199  }
200 
201 
203  static TAR
204  access (...)
205  {
206  // NOTE: if you see this assertion failure, none of the above predicates were true.
207  // Chances are that you requested a conversion that is logically impossible or dangerous,
208  // like e.g. taking a reference from an anonymous value parameter
209  static_assert (!sizeof(TAR), "AccessCasted: No valid conversion or cast supported for these types.");
210  throw error::Invalid("impossible or unsafe type conversion requested");
211  }
212  };
213 
214 
215 
216 } // namespace util
217 #endif
static if_can_take_address< SRC &&, TAR >::type access(SRC &&elem)
Helper template to access a given value, possibly converted or casted in a safe way.
LumieraError< LERR_(INVALID)> Invalid
Definition: error.hpp:216
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:91
static if_can_use_dynamic_downcast< SRC &&, TAR >::type access(SRC &&elem)
static if_can_use_conversion< SRC &&, TAR >::type access(SRC &&elem)
static TAR access(...)
catch-all to signal failure of conversion
Lumiera error handling (C++ interface).
static if_can_dereference< SRC &&, TAR >::type access(SRC &&elem)