blob: 5128e2b22683191edec45ee9c40093e6c18f22cd [file] [log] [blame]
#pragma once
// implicit_cast<T>() is a weaker form of static_cast<T>() that only works
// where the C++ language would allow you to implcitly cast its argument to T.
//
// This is most valuable where you are casting between primitive types with
// different ranges, e.g float -> int or int -> uint8_t.
//
// A stronger cast (static_cast, reinterpret_cast, C-style) would supress
// -fsanitize=integer's checks that the runtime values actually fit in range,
// but implicit_cast preserves them.
namespace eskia {
// This raw_implicit_cast is the basic implicit_cast, but we have a slight twist.
// (Ordinarily we'd do roundabout things to prevent type deduction of T here,
// but we don't need that when implicit_cast is the only caller of raw_implicit_cast.)
template <typename T>
static constexpr T raw_implicit_cast(T v) { return v; }
// We take one extra indirection to make implicit_cast more compatible with
// Clang's -Wconversion warnings, delaying the implicit cast to here where we
// can disable -Wconversion just for the one raw_implicit_cast() call.
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#endif
template <typename T, typename Arg>
static constexpr T implicit_cast(Arg&& v) { return raw_implicit_cast<T>(v); }
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
}