LCOV - code coverage report
Current view: top level - core/Utilities - TypeCasts.hpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 5 38 13.2 %
Date: 2022-08-04 03:43:28 Functions: 2 546 0.4 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <type_traits>
       4             : #include <limits>
       5             : #include <cassert>
       6             : #include <memory>
       7             : 
       8             : #include "elsaDefines.h"
       9             : #include "Error.h"
      10             : 
      11             : namespace elsa
      12             : {
      13             :     namespace detail
      14             :     {
      15             :         /// Type of CopyConst_t is 'const Dst' if Src is 'const Type', else it's 'Dst'
      16             :         template <typename Src, typename Dst>
      17             :         using CopyConst_t =
      18             :             typename std::conditional_t<std::is_const_v<Src>, std::add_const_t<Dst>, Dst>;
      19             :     } // namespace detail
      20             : 
      21             :     /// Check if a type can be dynamically casted to another
      22             :     template <typename Derived, typename Base>
      23         472 :     bool is(Base& input)
      24             :     {
      25         472 :         return dynamic_cast<detail::CopyConst_t<Base, Derived>*>(&input);
      26             :     }
      27             : 
      28             :     /// Overload to check for pointer types directly
      29             :     template <typename Derived, typename Base>
      30           0 :     bool is(Base* input)
      31             :     {
      32           0 :         return input && is<Derived>(*input);
      33             :     }
      34             : 
      35             :     /// Overload to check for unique_ptr directly.
      36             :     /// Usually passing a const reference to a unique_ptr is really dumb, but for this case it's
      37             :     /// what is needed.
      38             :     template <typename Derived, typename Base, typename Deleter>
      39           0 :     bool is(std::unique_ptr<Base, Deleter>& input)
      40             :     {
      41           0 :         return input && is<Derived>(*input);
      42             :     }
      43             : 
      44             :     /// Downcast pointer, assumes that type is known (i.e. checked by is(...))
      45             :     template <typename Derived, typename Base>
      46           0 :     auto downcast(Base* input) -> detail::CopyConst_t<Base, Derived>*
      47             :     {
      48             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
      49             : 
      50           0 :         assert(!input || is<Derived>(*input));
      51             : 
      52           0 :         return static_cast<detail::CopyConst_t<Base, Derived>*>(input);
      53             :     }
      54             : 
      55             :     /// Downcast reference, assumes that type is known (i.e. checked by is(...))
      56             :     template <typename Derived, typename Base>
      57         214 :     auto downcast(Base& input) -> detail::CopyConst_t<Base, Derived>&
      58             :     {
      59             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
      60             : 
      61         214 :         assert(is<Derived>(input));
      62             : 
      63         214 :         return static_cast<detail::CopyConst_t<Base, Derived>&>(input);
      64             :     }
      65             : 
      66             :     /// Downcast reference, assumes that type is known (i.e. checked by is(...))
      67             :     /// Note: This version only works with the default deleter, if you need a fancy deleter,
      68             :     /// this function might need's some overloading and SFINAE to get it working
      69             :     template <typename Derived, typename Base>
      70           0 :     std::unique_ptr<Derived> downcast(std::unique_ptr<Base>&& input)
      71             :     {
      72             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
      73             : 
      74           0 :         assert(is<Derived>(input));
      75             : 
      76           0 :         auto d = static_cast<Derived*>(input.release());
      77           0 :         return std::unique_ptr<Derived>(d);
      78             :     }
      79             : 
      80             :     /// Try to downcast pointer to Base to Derived, return a nullptr if it fails
      81             :     template <typename Derived, typename Base>
      82           0 :     auto downcast_safe(Base* input) -> detail::CopyConst_t<Base, Derived>*
      83             :     {
      84             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
      85             : 
      86           0 :         if (is<Derived>(input)) {
      87           0 :             return downcast<Derived>(input);
      88             :         }
      89             : 
      90           0 :         return nullptr;
      91             :     }
      92             : 
      93             :     /// Try to downcast reference to Base to Derived, Will throw std::bad_cast if it can't
      94             :     /// dynamically cast to Derived
      95             :     template <typename Derived, typename Base>
      96           0 :     auto downcast_safe(Base& input) -> detail::CopyConst_t<Base, Derived>&
      97             :     {
      98             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
      99             : 
     100           0 :         if (is<Derived>(input)) {
     101           0 :             return downcast<Derived>(input);
     102             :         }
     103             : 
     104           0 :         throw BadCastError("Could not cast given reference to wanted type");
     105             :     }
     106             : 
     107             :     /// Try to downcast a unique_ptr to Base to Derived, return a nullptr if it fails
     108             :     /// Note: that if the downcast can't be performed the callees unique_ptr is not touched
     109             :     /// But once the cast is done, the callees unique_ptr is not safe to use anymore
     110             :     /// Also This version only works with the default deleter, if you need a fancy deleter,
     111             :     /// this function might need's some overloading and SFINAE to get it working
     112             :     template <typename Derived, typename Base>
     113           0 :     std::unique_ptr<Derived> downcast_safe(std::unique_ptr<Base>&& input)
     114             :     {
     115             :         static_assert(std::is_base_of_v<Base, Derived>, "To downcast, types needs to be derived");
     116             : 
     117           0 :         if (Derived* result = downcast_safe<Derived>(input.get())) {
     118           0 :             input.release();
     119           0 :             return std::unique_ptr<Derived>(result);
     120             :         }
     121             : 
     122           0 :         return std::unique_ptr<Derived>(nullptr);
     123             :     }
     124             : 
     125             :     namespace detail
     126             :     {
     127             :         /// Alias to remove const, volatile and reference qualifiers of type
     128             :         template <typename T>
     129             :         using remove_crv_t = std::remove_reference_t<std::remove_cv_t<T>>;
     130             :     } // namespace detail
     131             : 
     132             :     /// Cast from one type to another without any checks, use with care
     133             :     template <typename To, typename From>
     134           0 :     auto as(From&& from) noexcept
     135             :     {
     136           0 :         return static_cast<To>(std::forward<From>(from));
     137             :     }
     138             : 
     139             :     /// Convert a signed value to an unsigned. Check for underflow only
     140             :     template <typename From>
     141           0 :     auto asUnsigned(From&& v) noexcept
     142             :     {
     143             :         static_assert(std::is_arithmetic_v<detail::remove_crv_t<From>>,
     144             :                       "Expect arithmetic type (use as() instead)");
     145             : 
     146             :         if constexpr (std::is_unsigned_v<From>) {
     147           0 :             return std::forward<From>(v);
     148             :         }
     149             : 
     150             :         using To = std::make_unsigned_t<detail::remove_crv_t<From>>;
     151             : 
     152           0 :         assert(v >= 0 && "Only convert positive numbers to an unsigned");
     153           0 :         return as<To>(std::forward<From>(v));
     154             :     }
     155             : 
     156             :     /// Convert an unsigned value to an signed. Check for overflow only
     157             :     template <typename From>
     158           0 :     auto asSigned(From&& v) noexcept
     159             :     {
     160             :         static_assert(std::is_arithmetic_v<detail::remove_crv_t<From>>,
     161             :                       "Expect arithmetic type (use as() instead)");
     162             : 
     163             :         if constexpr (std::is_signed_v<From>) {
     164             :             return std::forward<From>(v);
     165             :         }
     166             : 
     167             :         using To = std::make_signed_t<detail::remove_crv_t<From>>;
     168             : 
     169           0 :         assert(v <= std::numeric_limits<To>::max() && "Converted value is overflown");
     170           0 :         return as<To>(std::forward<From>(v));
     171             :     }
     172             : } // namespace elsa

Generated by: LCOV version 1.14