GTIRB  v2.2.0
GrammaTech Intermediate Representation for Binaries: C++ API
Casting.hpp
Go to the documentation of this file.
1 //===- Casting.hpp ----------------------------------------------*- C++ -*-===//
2 //
3 // Copyright (C) 2020 GrammaTech, Inc.
4 //
5 // This code is licensed under the MIT license. See the LICENSE file in the
6 // project root for license terms.
7 //
8 // This project is sponsored by the Office of Naval Research, One Liberty
9 // Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #
10 // N68335-17-C-0700. The content of the information does not necessarily
11 // reflect the position or policy of the Government and no official
12 // endorsement should be inferred.
13 //
14 //===-Addition License Information-----------------------------------------===//
15 //
16 // This file was initially written for the LLVM Compiler Infrastructure
17 // project where it is distributed under the University of Illinois Open Source
18 // License. See the LICENSE file in the project root for license terms.
19 //
20 //===----------------------------------------------------------------------===//
21 #ifndef GTIRB_CASTING_H
22 #define GTIRB_CASTING_H
23 
24 #include <cassert>
25 #include <type_traits>
26 
28 #ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE
29 #define GTIRB_DEPRECATED_UTILS \
30  [[deprecated("Define GTIRB_WRAP_UTILS_IN_NAMESPACE and access via the " \
31  "gtirb namespace to suppress this error.")]]
32 #else
33 #define GTIRB_DEPRECATED_UTILS
34 #endif
35 
37 namespace gtirb {
38 
39 // We want clients to use the names in the gtirb namespace, so we exclude
40 // the allocator namespace when generating documentation.
42 namespace casting {
44 
51 
189 
192 
195 
198 
201 
204 
207 
210 
213 
216 
219 
222 
225 
228 
229 //===----------------------------------------------------------------------===//
230 // isa<x> Support Templates
231 //===----------------------------------------------------------------------===//
232 
234 // Define a template that can be specialized by smart pointers to reflect the
235 // fact that they are automatically dereferenced, and are not involved with the
236 // template selection process... the default implementation is a noop.
237 //
238 template <typename From> struct simplify_type {
239  using SimpleType = From; // The real type this represents...
240 
241  // An accessor to get the real value...
242  static SimpleType& getSimplifiedValue(From& Val) { return Val; }
243 };
245 
247 // The core of the implementation of isa<X> is here; To and From should be
248 // the names of classes. This template can be specialized to customize the
249 // implementation of isa<> without rewriting it from scratch.
250 template <typename To, typename From, typename Enabler = void> struct isa_impl {
251  static inline bool doit(const From& Val) { return To::classof(&Val); }
252 };
254 
256 // Always allow upcasts, and perform no dynamic check for them.
257 template <typename To, typename From>
258 struct isa_impl<
259  To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> {
260  static inline bool doit(const From&) { return true; }
261 };
263 
265 template <typename To, typename From> struct isa_impl_cl {
266  static inline bool doit(const From& Val) {
267  return isa_impl<To, From>::doit(Val);
268  }
269 };
271 
273 template <typename To, typename From> struct isa_impl_cl<To, const From> {
274  static inline bool doit(const From& Val) {
275  return isa_impl<To, From>::doit(Val);
276  }
277 };
279 
281 template <typename To, typename From> struct isa_impl_cl<To, From*> {
282  static inline bool doit(const From* Val) {
283  assert(Val && "isa<> used on a null pointer");
284  return isa_impl<To, From>::doit(*Val);
285  }
286 };
288 
290 template <typename To, typename From> struct isa_impl_cl<To, From* const> {
291  static inline bool doit(const From* Val) {
292  assert(Val && "isa<> used on a null pointer");
293  return isa_impl<To, From>::doit(*Val);
294  }
295 };
297 
299 template <typename To, typename From> struct isa_impl_cl<To, const From*> {
300  static inline bool doit(const From* Val) {
301  assert(Val && "isa<> used on a null pointer");
302  return isa_impl<To, From>::doit(*Val);
303  }
304 };
306 
308 template <typename To, typename From>
309 struct isa_impl_cl<To, const From* const> {
310  static inline bool doit(const From* Val) {
311  assert(Val && "isa<> used on a null pointer");
312  return isa_impl<To, From>::doit(*Val);
313  }
314 };
316 
318 template <typename To, typename From, typename SimpleFrom>
319 struct isa_impl_wrap {
320  // When From != SimplifiedType, we can simplify the type some more by using
321  // the simplify_type template.
322  static bool doit(const From& Val) {
323  return isa_impl_wrap<To, SimpleFrom,
324  typename simplify_type<SimpleFrom>::SimpleType>::
325  doit(simplify_type<const From>::getSimplifiedValue(Val));
326  }
327 };
329 
331 template <typename To, typename FromTy>
332 struct isa_impl_wrap<To, FromTy, FromTy> {
333  // When From == SimpleType, we are as simple as we are going to get.
334  static bool doit(const FromTy& Val) {
335  return isa_impl_cl<To, FromTy>::doit(Val);
336  }
337 };
339 
340 // isa<X> - Return true if the parameter to the template is an instance of the
341 // template type argument. Used like this:
342 //
343 // if (isa<Type>(myVal)) { ... }
344 //
345 template <class X, class Y>
346 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline bool isa(const Y& Val) {
347  return isa_impl_wrap<X, const Y,
348  typename simplify_type<const Y>::SimpleType>::doit(Val);
349 }
350 
351 //===----------------------------------------------------------------------===//
352 // cast<x> Support Templates
353 //===----------------------------------------------------------------------===//
355 template <class To, class From> struct cast_retty;
357 
359 // Calculate what type the 'cast' function should return, based on a requested
360 // type of To and a source type of From.
361 template <class To, class From> struct cast_retty_impl {
362  using ret_type = To&; // Normal case, return Ty&
363 };
364 template <class To, class From> struct cast_retty_impl<To, const From> {
365  using ret_type = const To&; // Normal case, return Ty&
366 };
367 
368 template <class To, class From> struct cast_retty_impl<To, From*> {
369  using ret_type = To*; // Pointer arg case, return Ty*
370 };
371 
372 template <class To, class From> struct cast_retty_impl<To, const From*> {
373  using ret_type = const To*; // Constant pointer arg case, return const Ty*
374 };
375 
376 template <class To, class From> struct cast_retty_impl<To, const From* const> {
377  using ret_type = const To*; // Constant pointer arg case, return const Ty*
378 };
380 
382 template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
383  // When the simplified type and the from type are not the same, use the type
384  // simplifier to reduce the type, then reuse cast_retty_impl to get the
385  // resultant type.
386  using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
387 };
388 
389 template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
390  // When the simplified type is equal to the from type, use it directly.
391  using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
392 };
393 
394 template <class To, class From> struct cast_retty {
395  using ret_type = typename cast_retty_wrap<
396  To, From, typename simplify_type<From>::SimpleType>::ret_type;
397 };
399 
401 // Ensure the non-simple values are converted using the simplify_type template
402 // that may be specialized by smart pointers...
403 //
404 template <class To, class From, class SimpleFrom> struct cast_convert_val {
405  // This is not a simple type, use the template to simplify it...
406  static typename cast_retty<To, From>::ret_type doit(From& Val) {
407  return cast_convert_val<To, SimpleFrom,
408  typename simplify_type<SimpleFrom>::SimpleType>::
409  doit(simplify_type<From>::getSimplifiedValue(Val));
410  }
411 };
412 
413 template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
414  // This _is_ a simple type, just cast it.
415  static typename cast_retty<To, FromTy>::ret_type doit(const FromTy& Val) {
416  typename cast_retty<To, FromTy>::ret_type Res2 =
417  (typename cast_retty<To, FromTy>::ret_type) const_cast<FromTy&>(Val);
418  return Res2;
419  }
420 };
422 
424 template <class X> struct is_simple_type {
425  static const bool value =
426  std::is_same<X, typename simplify_type<X>::SimpleType>::value;
427 };
429 
430 // cast<X> - Return the argument parameter cast to the specified type. This
431 // casting operator asserts that the type is correct, so it does not return null
432 // on failure. It does not allow a null argument (use cast_or_null for that).
433 // It is typically used like this:
434 //
435 // cast<Instruction>(myVal)->getParent()
436 //
437 template <class X, class Y>
438 GTIRB_DEPRECATED_UTILS inline
439  typename std::enable_if<!is_simple_type<Y>::value,
440  typename cast_retty<X, const Y>::ret_type>::type
441  cast(const Y& Val) {
442  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
443  return cast_convert_val<
444  X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val);
445 }
446 
447 template <class X, class Y>
448 GTIRB_DEPRECATED_UTILS inline typename cast_retty<X, Y>::ret_type cast(Y& Val) {
449  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
450  return cast_convert_val<X, Y, typename simplify_type<Y>::SimpleType>::doit(
451  Val);
452 }
453 
454 template <class X, class Y>
455 GTIRB_DEPRECATED_UTILS inline typename cast_retty<X, Y*>::ret_type
456 cast(Y* Val) {
457  assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!");
458  return cast_convert_val<X, Y*, typename simplify_type<Y*>::SimpleType>::doit(
459  Val);
460 }
461 
462 // cast_or_null<X> - Functionally identical to cast, except that a null value is
463 // accepted.
464 //
465 template <class X, class Y>
466 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline
467  typename std::enable_if<!is_simple_type<Y>::value,
468  typename cast_retty<X, const Y>::ret_type>::type
469  cast_or_null(const Y& Val) {
470  if (!Val)
471  return nullptr;
472  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
473  return cast<X>(Val);
474 }
475 
476 template <class X, class Y>
477 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline
478  typename std::enable_if<!is_simple_type<Y>::value,
479  typename cast_retty<X, Y>::ret_type>::type
480  cast_or_null(Y& Val) {
481  if (!Val)
482  return nullptr;
483  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
484  return cast<X>(Val);
485 }
486 
487 template <class X, class Y>
488 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type
489 cast_or_null(Y* Val) {
490  if (!Val)
491  return nullptr;
492  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
493  return cast<X>(Val);
494 }
495 
496 // dyn_cast<X> - Return the argument parameter cast to the specified type. This
497 // casting operator returns null if the argument is of the wrong type, so it can
498 // be used to test for a type as well as cast if successful. This should be
499 // used in the context of an if statement like this:
500 //
501 // if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
502 //
503 
504 template <class X, class Y>
505 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline
506  typename std::enable_if<!is_simple_type<Y>::value,
507  typename cast_retty<X, const Y>::ret_type>::type
508  dyn_cast(const Y& Val) {
509  return isa<X>(Val) ? cast<X>(Val) : nullptr;
510 }
511 
512 template <class X, class Y>
513 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y>::ret_type
514 dyn_cast(Y& Val) {
515  return isa<X>(Val) ? cast<X>(Val) : nullptr;
516 }
517 
518 template <class X, class Y>
519 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type
520 dyn_cast(Y* Val) {
521  return isa<X>(Val) ? cast<X>(Val) : nullptr;
522 }
523 
524 // dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null
525 // value is accepted.
526 //
527 template <class X, class Y>
528 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline
529  typename std::enable_if<!is_simple_type<Y>::value,
530  typename cast_retty<X, const Y>::ret_type>::type
531  dyn_cast_or_null(const Y& Val) {
532  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
533 }
534 
535 template <class X, class Y>
536 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline
537  typename std::enable_if<!is_simple_type<Y>::value,
538  typename cast_retty<X, Y>::ret_type>::type
540  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
541 }
542 
543 template <class X, class Y>
544 GTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type
546  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
547 }
548 
550 } // namespace casting
552 
553 #ifdef GTIRB_WRAP_UTILS_IN_NAMESPACE
554 
555 using casting::cast;
557 using casting::dyn_cast;
559 using casting::isa;
560 
561 #endif // GTIRB_WRAP_UTILS_IN_NAMESPACE
562 
563 } // namespace gtirb
564 
565 #ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE
566 
571 using gtirb::casting::isa;
572 
573 #endif // GTIRB_WRAP_UTILS_IN_NAMESPACE
574 
575 #endif // GTIRB_CASTING_H
gtirb::cast_or_null
cast_retty< X, Y * >::ret_type cast_or_null(Y *Val)
Definition: Casting.hpp:489
gtirb::dyn_cast
cast_retty< X, Y * >::ret_type dyn_cast(Y *Val)
Definition: Casting.hpp:520
gtirb::cast
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type cast(const Y &Val)
Definition: Casting.hpp:441
gtirb::dyn_cast_or_null
cast_retty< X, Y * >::ret_type dyn_cast_or_null(Y *Val)
Definition: Casting.hpp:545
gtirb::cast
cast_retty< X, Y * >::ret_type cast(Y *Val)
Definition: Casting.hpp:456
gtirb
Main namespace for the GTIRB API.
Definition: Addr.hpp:28
gtirb::dyn_cast
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.hpp:508
gtirb::cast_or_null
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type cast_or_null(const Y &Val)
Definition: Casting.hpp:469
gtirb::dyn_cast_or_null
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast_or_null(const Y &Val)
Definition: Casting.hpp:531
std
Definition: Addr.hpp:359
gtirb::isa
bool isa(const Y &Val)
Definition: Casting.hpp:346