OXYGENHUB
◆ main openmsx / src / utils / narrow.hh
1.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef NARROW_HH
2
#define NARROW_HH
3
4
#include "inline.hh"
5
#include <cassert>
6
#include <type_traits>
7
#include <utility>
8
9
// Inspired by GSL narrow
10
//     https://github.com/microsoft/GSL/blob/main/include/gsl/narrow
11
//
12
// narrow_cast(): a searchable way to do narrowing casts of values
13
// narrow(): a checked version of narrow_cast(), asserts that the
14
//           numerical value remains unchanged
15
//
16
// The main difference between this version and the GSL version is that we
17
// assert (we don't want any overhead in non-assert build), while GSL throws an
18
// exception.
19
20
template<typename To, typename From>
21
constexpr To narrow_cast(From&& from) noexcept
22
{
23
	return static_cast<To>(std::forward<From>(from));
24
}
25
26
ALWAYS_INLINE constexpr void narrow_assert(bool ok)
27
{
28
	if (!ok) {
29
#ifdef UNITTEST
30
		throw "narrow() error";
31
#else
32
		assert(false && "narrow() error");
33
#endif
34
	}
35
}
36
37
template<typename To, typename From> constexpr To narrow(From from)
38
#ifndef UNITTEST
39
	noexcept
40
#endif
41
{
42
	static_assert(std::is_arithmetic_v<From>);
43
	static_assert(std::is_arithmetic_v<To>);
44
45
	const To to = narrow_cast<To>(from);
46
47
	narrow_assert(static_cast<From>(to) == from);
48
	if constexpr (std::is_signed_v<From> != std::is_signed_v<To>) {
49
		narrow_assert((to < To{}) == (from < From{}));
50
	}
51
52
	return to;
53
}
54
55
#endif