Program Listing for File safe_cast.hpp

Return to documentation for file (include/uitsl/debug/safe_cast.hpp)

#pragma once
#ifndef UITSL_DEBUG_SAFE_CAST_HPP_INCLUDE
#define UITSL_DEBUG_SAFE_CAST_HPP_INCLUDE

#include <limits>
#include <stddef.h>
#include <stdexcept>

#include "safe_compare.hpp"

namespace uitsl {

// adapted from https://stackoverflow.com/a/49658950
template<typename Dst, typename Src>
inline Dst safe_cast(const Src value)
{
  typedef std::numeric_limits<Dst> DstLim;
  typedef std::numeric_limits<Src> SrcLim;

  const bool positive_overflow_possible = safe_less(
    DstLim::max(),
    SrcLim::max()
  );
  const bool negative_overflow_possible =
      SrcLim::is_signed
      or
      safe_greater(DstLim::lowest(), SrcLim::lowest());

  // unsigned <-- unsigned
  if((not DstLim::is_signed) and (not SrcLim::is_signed)) {
    if(positive_overflow_possible and (value > DstLim::max())) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": positive overflow"));
    }
  }
  // unsigned <-- signed
  else if((not DstLim::is_signed) and SrcLim::is_signed) {
    if(positive_overflow_possible and safe_greater(value, DstLim::max())) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": positive overflow"));
    }
    else if(negative_overflow_possible and (value < 0)) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": negative overflow"));
    }

  }
  // signed <-- unsigned
  else if(DstLim::is_signed and (not SrcLim::is_signed)) {
    if(positive_overflow_possible and safe_greater(value, DstLim::max())) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": positive overflow"));
    }
  }
  // signed <-- signed
  else if(DstLim::is_signed and SrcLim::is_signed) {
    if(positive_overflow_possible and safe_greater(value, DstLim::max())) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": positive overflow"));
    } else if(negative_overflow_possible and safe_less(value, DstLim::lowest())) {
      throw std::overflow_error(__PRETTY_FUNCTION__ +
                    std::string(": negative overflow"));
    }
  }

  // limits have been checked, therefore safe to cast
  return static_cast<Dst>(value);
}

} // namespace uitsl

#endif // #ifndef UITSL_DEBUG_SAFE_CAST_HPP_INCLUDE