Photon Common Library 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
utility.ipp
Go to the documentation of this file.
1#pragma once
2
3#include "Common/utility.h"
4#include "Common/assertion.h"
5#include "Common/exceptions.h"
6
7#include <utility>
8#include <climits>
9#include <limits>
10
11namespace ph
12{
13
14namespace detail
15{
16
17template<typename T, std::size_t... Is>
18inline constexpr std::array<T, sizeof...(Is)> make_array(
19 T element,
20 std::index_sequence<Is...>)
21{
22 // Use sequence as pattern to repeat `element`, also to avoid unused warnings
23 return {(static_cast<void>(Is), element)...};
24}
25
26}// end namespace detail
27
28template<typename T>
29inline consteval std::size_t sizeof_in_bits()
30{
31 return CHAR_BIT * sizeof(T);
32}
33
34template<typename T, std::size_t N>
35inline constexpr std::array<T, N> make_array(const T& element)
36{
37 return detail::make_array(element, std::make_index_sequence<N>());
38}
39
40template<std::integral DstType, std::integral SrcType>
41inline DstType lossless_integer_cast(const SrcType& src)
42{
43 using SrcLimits = std::numeric_limits<SrcType>;
44 using DstLimits = std::numeric_limits<DstType>;
45
46 // Note that the use of `std::cmp_<X>` functions are important as the comparisons
47 // may be signed <-> unsigned comparisons, which may cause signed limits to overflow
48
49 // TODO: we may need to cast src to some integer first to support char and bool types (they are not supported by cmp functions)
50
51 constexpr bool mayHavePositiveOverflow = std::cmp_greater(SrcLimits::max(), DstLimits::max());
52 constexpr bool mayHaveNegativeOverflow = std::cmp_less(SrcLimits::lowest(), DstLimits::lowest());
53
54 if constexpr(mayHavePositiveOverflow)
55 {
56 if(std::cmp_greater(src, DstLimits::max()))
57 {
58 throw_formatted<OverflowException>("cast results in positive overflow: {} exceeds the limit {}",
59 src, DstLimits::max());
60 }
61 }
62
63 if constexpr(mayHaveNegativeOverflow)
64 {
65 if(std::cmp_less(src, DstLimits::lowest()))
66 {
67 throw_formatted<OverflowException>("cast results in negative overflow: {} exceeds the limit {}",
68 src, DstLimits::lowest());
69 }
70 }
71
72 // All possible integer overflow scenarios are checked so it is safe to cast now
73 return static_cast<DstType>(src);
74}
75
76template<std::floating_point DstType, std::floating_point SrcType>
77inline DstType lossless_float_cast(const SrcType& src)
78{
79 // Nothing to do if both types are the same
80 if constexpr(std::is_same_v<SrcType, DstType>)
81 {
82 return src;
83 }
84 // If we are converting to a wider floating-point type, generally it will be lossless
85 else if constexpr(sizeof(DstType) > sizeof(SrcType))
86 {
87 // We need both types to be IEEE-754
88 static_assert(std::numeric_limits<SrcType>::is_iec559);
89 static_assert(std::numeric_limits<DstType>::is_iec559);
90
91 return static_cast<DstType>(src);
92 }
93 // Otherwise, cast to `DstType` then back to `SrcType` and see if there is any difference
94 else
95 {
96 const auto dst = static_cast<DstType>(src);
97 const auto dstBackToSrc = static_cast<SrcType>(dst);
98 if(src != dstBackToSrc)
99 {
100 throw_formatted<NumericException>("cast results in numeric precision loss: {} -> {}",
101 src, dstBackToSrc);
102 }
103
104 return dst;
105 }
106}
107
108template<typename DstType, typename SrcType>
109inline DstType lossless_cast(const SrcType& src)
110{
111 // Integer -> Integer
112 if constexpr(std::is_integral_v<SrcType> && std::is_integral_v<DstType>)
113 {
115 }
116 // Integer -> Floating-point
117 else if constexpr(std::is_integral_v<SrcType> && std::is_floating_point_v<DstType>)
118 {
119 // TODO
121 return 0;
122 }
123 // Floating-point -> Integer
124 else if constexpr(std::is_floating_point_v<SrcType> && std::is_integral_v<DstType>)
125 {
126 // TODO
128 return 0;
129 }
130 // Floating-point -> Floating-point
131 else
132 {
133 static_assert(std::is_floating_point_v<SrcType> && std::is_floating_point_v<DstType>);
134
136 }
137}
138
139template<typename DstType, typename SrcType>
140inline DstType lossless_cast(const SrcType& src, DstType* const out_dst)
141{
142 PH_ASSERT(out_dst);
143
144 *out_dst = lossless_cast<DstType>(src);
145 return *out_dst;
146}
147
148}// end namespace ph
#define PH_ASSERT(condition)
Definition assertion.h:49
#define PH_ASSERT_UNREACHABLE_SECTION()
Definition assertion.h:52
constexpr std::array< T, sizeof...(Is)> make_array(T element, std::index_sequence< Is... >)
Definition utility.ipp:18
The root for all renderer implementations.
Definition assertion.h:9
DstType lossless_integer_cast(const SrcType &src)
Definition utility.ipp:41
void throw_formatted(const std::format_string< Args... > msgFormat, Args &&... args)
Definition exceptions.h:85
constexpr std::array< T, N > make_array(const T &element)
Creates an std::array filled with the same element.
Definition utility.ipp:35
DstType lossless_cast(const SrcType &src)
Cast numeric value to another type without any loss of information. If there is any possible overflow...
Definition utility.ipp:109
DstType lossless_float_cast(const SrcType &src)
Definition utility.ipp:77
consteval std::size_t sizeof_in_bits()
Calculates number of bits an instance of type T occupies.
Definition utility.ipp:29