Caffe2 - C++ API
A deep learning, cross platform ML framework
Casting.h
1 //===- nomnigraph/Support/Casting.h - Allow casting checks ------*- C++ -*-===//
2 //
3 // This is taken directly from LLVM's source code.
4 //
5 // The original file is distributed under the University of Illinois Open Source
6 // License.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the isa<X>() function for checking downcastibility.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef NOM_SUPPORT_CASTING_H
15 #define NOM_SUPPORT_CASTING_H
16 
17 #include <memory>
18 #include <assert.h>
19 
20 //===----------------------------------------------------------------------===//
21 // isa<x> Support Templates
22 //===----------------------------------------------------------------------===//
23 
25 #define NOMNIGRAPH_NODISCARD
26 #if __cplusplus > 201402L && defined(__has_cpp_attribute)
27  #if __has_cpp_attribute(nodiscard)
28  #undef NOMNIGRAPH_NODISCARD
29  #define NOMNIGRAPH_NODISCARD [[nodiscard]]
30  #endif
31 // Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
32 // error when __has_cpp_attribute is given a scoped attribute in C mode.
33 #elif __cplusplus && defined(__has_cpp_attribute)
34  #if __has_cpp_attribute(clang::warn_unused_result)
35  #undef NOMNIGRAPH_NODISCARD
36  #define NOMNIGRAPH_NODISCARD [[clang::warn_unused_result]]
37  #endif
38 #endif
39 
41 template <typename T, typename Enable = void>
43  using type = T &;
44 };
45 
48 template <typename T, typename Enable = void> struct add_const_past_pointer {
49  using type = const T;
50 };
51 
52 // Define a template that can be specialized by smart pointers to reflect the
53 // fact that they are automatically dereferenced, and are not involved with the
54 // template selection process... the default implementation is a noop.
55 //
56 template <typename From> struct simplify_type {
57  using SimpleType = From; // The real type this represents...
58 
59  // An accessor to get the real value...
60  static SimpleType &getSimplifiedValue(From &Val) { return Val; }
61 };
62 
63 template <typename From> struct simplify_type<const From> {
64  using NonConstSimpleType = typename simplify_type<From>::SimpleType;
65  using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type;
66  using RetType =
67  typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
68 
69  static RetType getSimplifiedValue(const From &Val) {
70  return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val));
71  }
72 };
73 
74 // The core of the implementation of isa<X> is here; To and From should be
75 // the names of classes. This template can be specialized to customize the
76 // implementation of isa<> without rewriting it from scratch.
77 template <typename To, typename From, typename Enabler = void> struct isa_impl {
78  static inline bool doit(const From &Val) { return To::classof(&Val); }
79 };
80 
82 template <typename To, typename From>
83 struct isa_impl<
84  To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> {
85  static inline bool doit(const From &) { return true; }
86 };
87 
88 template <typename To, typename From> struct isa_impl_cl {
89  static inline bool doit(const From &Val) {
90  return isa_impl<To, From>::doit(Val);
91  }
92 };
93 
94 template <typename To, typename From> struct isa_impl_cl<To, const From> {
95  static inline bool doit(const From &Val) {
96  return isa_impl<To, From>::doit(Val);
97  }
98 };
99 
100 template <typename To, typename From>
101 struct isa_impl_cl<To, const std::unique_ptr<From>> {
102  static inline bool doit(const std::unique_ptr<From> &Val) {
103  assert(Val && "isa<> used on a null pointer");
104  return isa_impl_cl<To, From>::doit(*Val);
105  }
106 };
107 
108 template <typename To, typename From> struct isa_impl_cl<To, From *> {
109  static inline bool doit(const From *Val) {
110  assert(Val && "isa<> used on a null pointer");
111  return isa_impl<To, From>::doit(*Val);
112  }
113 };
114 
115 template <typename To, typename From> struct isa_impl_cl<To, From *const> {
116  static inline bool doit(const From *Val) {
117  assert(Val && "isa<> used on a null pointer");
118  return isa_impl<To, From>::doit(*Val);
119  }
120 };
121 
122 template <typename To, typename From> struct isa_impl_cl<To, const From *> {
123  static inline bool doit(const From *Val) {
124  assert(Val && "isa<> used on a null pointer");
125  return isa_impl<To, From>::doit(*Val);
126  }
127 };
128 
129 template <typename To, typename From>
130 struct isa_impl_cl<To, const From *const> {
131  static inline bool doit(const From *Val) {
132  assert(Val && "isa<> used on a null pointer");
133  return isa_impl<To, From>::doit(*Val);
134  }
135 };
136 
137 template <typename To, typename From, typename SimpleFrom>
139  // When From != SimplifiedType, we can simplify the type some more by using
140  // the simplify_type template.
141  static bool doit(const From &Val) {
142  return isa_impl_wrap<To, SimpleFrom,
143  typename simplify_type<SimpleFrom>::SimpleType>::
145  }
146 };
147 
148 template <typename To, typename FromTy>
149 struct isa_impl_wrap<To, FromTy, FromTy> {
150  // When From == SimpleType, we are as simple as we are going to get.
151  static bool doit(const FromTy &Val) {
152  return isa_impl_cl<To, FromTy>::doit(Val);
153  }
154 };
155 
156 // isa<X> - Return true if the parameter to the template is an instance of the
157 // template type argument. Used like this:
158 //
159 // if (isa<Type>(myVal)) { ... }
160 //
161 template <class X, class Y> NOMNIGRAPH_NODISCARD inline bool isa(const Y &Val) {
162  return isa_impl_wrap<X, const Y,
163  typename simplify_type<const Y>::SimpleType>::doit(Val);
164 }
165 
166 //===----------------------------------------------------------------------===//
167 // cast<x> Support Templates
168 //===----------------------------------------------------------------------===//
169 
170 template <class To, class From> struct cast_retty;
171 
172 // Calculate what type the 'cast' function should return, based on a requested
173 // type of To and a source type of From.
174 template <class To, class From> struct cast_retty_impl {
175  using ret_type = To &; // Normal case, return Ty&
176 };
177 template <class To, class From> struct cast_retty_impl<To, const From> {
178  using ret_type = const To &; // Normal case, return Ty&
179 };
180 
181 template <class To, class From> struct cast_retty_impl<To, From *> {
182  using ret_type = To *; // Pointer arg case, return Ty*
183 };
184 
185 template <class To, class From> struct cast_retty_impl<To, const From *> {
186  using ret_type = const To *; // Constant pointer arg case, return const Ty*
187 };
188 
189 template <class To, class From> struct cast_retty_impl<To, const From *const> {
190  using ret_type = const To *; // Constant pointer arg case, return const Ty*
191 };
192 
193 template <class To, class From>
194 struct cast_retty_impl<To, std::unique_ptr<From>> {
195 private:
196  using PointerType = typename cast_retty_impl<To, From *>::ret_type;
197  using ResultType = typename std::remove_pointer<PointerType>::type;
198 
199 public:
200  using ret_type = std::unique_ptr<ResultType>;
201 };
202 
203 template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
204  // When the simplified type and the from type are not the same, use the type
205  // simplifier to reduce the type, then reuse cast_retty_impl to get the
206  // resultant type.
207  using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
208 };
209 
210 template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
211  // When the simplified type is equal to the from type, use it directly.
212  using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
213 };
214 
215 template <class To, class From> struct cast_retty {
216  using ret_type = typename cast_retty_wrap<
217  To, From, typename simplify_type<From>::SimpleType>::ret_type;
218 };
219 
220 // Ensure the non-simple values are converted using the simplify_type template
221 // that may be specialized by smart pointers...
222 //
223 template <class To, class From, class SimpleFrom> struct cast_convert_val {
224  // This is not a simple type, use the template to simplify it...
225  static typename cast_retty<To, From>::ret_type doit(From &Val) {
226  return cast_convert_val<To, SimpleFrom,
227  typename simplify_type<SimpleFrom>::SimpleType>::
229  }
230 };
231 
232 template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
233  // This _is_ a simple type, just cast it.
234  static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
235  typename cast_retty<To, FromTy>::ret_type Res2 =
236  (typename cast_retty<To, FromTy>::ret_type) const_cast<FromTy &>(Val);
237  return Res2;
238  }
239 };
240 
241 template <class X> struct is_simple_type {
242  static const bool value =
243  std::is_same<X, typename simplify_type<X>::SimpleType>::value;
244 };
245 
246 // cast<X> - Return the argument parameter cast to the specified type. This
247 // casting operator asserts that the type is correct, so it does not return null
248 // on failure. It does not allow a null argument (use cast_or_null for that).
249 // It is typically used like this:
250 //
251 // cast<Instruction>(myVal)->getParent()
252 //
253 template <class X, class Y>
254 inline typename std::enable_if<!is_simple_type<Y>::value,
255  typename cast_retty<X, const Y>::ret_type>::type
256 cast(const Y &Val) {
257  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
258  return cast_convert_val<
259  X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val);
260 }
261 
262 template <class X, class Y>
263 inline typename cast_retty<X, Y>::ret_type cast(Y &Val) {
264  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
266  Val);
267 }
268 
269 template <class X, class Y>
270 inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) {
271  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
272  return cast_convert_val<X, Y *,
273  typename simplify_type<Y *>::SimpleType>::doit(Val);
274 }
275 
276 template <class X, class Y>
277 inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
278 cast(std::unique_ptr<Y> &&Val) {
279  assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!");
280  using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type;
281  return ret_type(
282  cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit(
283  Val.release()));
284 }
285 
286 // cast_or_null<X> - Functionally identical to cast, except that a null value is
287 // accepted.
288 //
289 template <class X, class Y>
290 NOMNIGRAPH_NODISCARD inline
291  typename std::enable_if<!is_simple_type<Y>::value,
292  typename cast_retty<X, const Y>::ret_type>::type
293  cast_or_null(const Y &Val) {
294  if (!Val)
295  return nullptr;
296  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
297  return cast<X>(Val);
298 }
299 
300 template <class X, class Y>
301 NOMNIGRAPH_NODISCARD inline
302  typename std::enable_if<!is_simple_type<Y>::value,
303  typename cast_retty<X, Y>::ret_type>::type
304  cast_or_null(Y &Val) {
305  if (!Val)
306  return nullptr;
307  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
308  return cast<X>(Val);
309 }
310 
311 template <class X, class Y>
312 NOMNIGRAPH_NODISCARD inline typename cast_retty<X, Y *>::ret_type
313 cast_or_null(Y *Val) {
314  if (!Val)
315  return nullptr;
316  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
317  return cast<X>(Val);
318 }
319 
320 template <class X, class Y>
321 inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
322 cast_or_null(std::unique_ptr<Y> &&Val) {
323  if (!Val)
324  return nullptr;
325  return cast<X>(std::move(Val));
326 }
327 
328 // dyn_cast<X> - Return the argument parameter cast to the specified type. This
329 // casting operator returns null if the argument is of the wrong type, so it can
330 // be used to test for a type as well as cast if successful. This should be
331 // used in the context of an if statement like this:
332 //
333 // if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
334 //
335 
336 template <class X, class Y>
337 NOMNIGRAPH_NODISCARD inline
338  typename std::enable_if<!is_simple_type<Y>::value,
339  typename cast_retty<X, const Y>::ret_type>::type
340  dyn_cast(const Y &Val) {
341  return isa<X>(Val) ? cast<X>(Val) : nullptr;
342 }
343 
344 template <class X, class Y>
345 NOMNIGRAPH_NODISCARD inline typename cast_retty<X, Y>::ret_type
346 dyn_cast(Y &Val) {
347  return isa<X>(Val) ? cast<X>(Val) : nullptr;
348 }
349 
350 template <class X, class Y>
351 NOMNIGRAPH_NODISCARD inline typename cast_retty<X, Y *>::ret_type
352 dyn_cast(Y *Val) {
353  return isa<X>(Val) ? cast<X>(Val) : nullptr;
354 }
355 
356 // dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null
357 // value is accepted.
358 //
359 template <class X, class Y>
360 NOMNIGRAPH_NODISCARD inline
361  typename std::enable_if<!is_simple_type<Y>::value,
362  typename cast_retty<X, const Y>::ret_type>::type
363  dyn_cast_or_null(const Y &Val) {
364  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
365 }
366 
367 template <class X, class Y>
368 NOMNIGRAPH_NODISCARD inline
369  typename std::enable_if<!is_simple_type<Y>::value,
370  typename cast_retty<X, Y>::ret_type>::type
371  dyn_cast_or_null(Y &Val) {
372  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
373 }
374 
375 template <class X, class Y>
376 NOMNIGRAPH_NODISCARD inline typename cast_retty<X, Y *>::ret_type
377 dyn_cast_or_null(Y *Val) {
378  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
379 }
380 
381 // unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
382 // taking ownership of the input pointer iff isa<X>(Val) is true. If the
383 // cast is successful, From refers to nullptr on exit and the casted value
384 // is returned. If the cast is unsuccessful, the function returns nullptr
385 // and From is unchanged.
386 template <class X, class Y>
387 NOMNIGRAPH_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val)
388  -> decltype(cast<X>(Val)) {
389  if (!isa<X>(Val))
390  return nullptr;
391  return cast<X>(std::move(Val));
392 }
393 
394 template <class X, class Y>
395 NOMNIGRAPH_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val)
396  -> decltype(cast<X>(Val)) {
397  return unique_dyn_cast<X, Y>(Val);
398 }
399 
400 // dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that
401 // a null value is accepted.
402 template <class X, class Y>
403 NOMNIGRAPH_NODISCARD inline auto
404 unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) -> decltype(cast<X>(Val)) {
405  if (!Val)
406  return nullptr;
407  return unique_dyn_cast<X, Y>(Val);
408 }
409 
410 template <class X, class Y>
411 NOMNIGRAPH_NODISCARD inline auto
412 unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) -> decltype(cast<X>(Val)) {
413  return unique_dyn_cast_or_null<X, Y>(Val);
414 }
415 
416 #endif // NOM_SUPPORT_CASTING_H
If T is a pointer, just return it. If it is not, return T&.
Definition: Casting.h:42
If T is a pointer to X, return a pointer to const X.
Definition: Casting.h:48
Definition: types.h:72