16
16
17
17
#include < concepts>
18
18
19
+ #include " subspace/mem/copy.h"
20
+
19
21
namespace sus ::construct {
20
22
21
23
// / Specializing this class for `To` and `From` allows `To` to satisfy
22
- // / `ToBits <To, From>`.
24
+ // / `Transmogrify <To, From>`.
23
25
// /
24
26
// / # Examples
25
27
// /
26
28
// / To allow bitwise conversion to `Goat` from any type satisying a
27
29
// / concept `GoatLike`:
28
30
// / ```cpp
29
- // / // Satisfies ToBits <Goat, GoatLike>.
31
+ // / // Satisfies Transmogrify <Goat, GoatLike>.
30
32
// / template <class Goat, GoatLike G>
31
- // / struct ToBitsImpl <Goat, G> {
32
- // / constexpr static Goat from_bits (const G& g) noexcept { return ...; }
33
+ // / struct TransmogrifyImpl <Goat, G> {
34
+ // / constexpr static Goat mog_from (const G& g) noexcept { return ...; }
33
35
// / };
34
36
// / ```
35
37
// /
36
38
// / To receive something that can be bitwise converted to an `u32`.
37
39
// / ```cpp
38
- // / auto add = [](u32 a, const sus::construct::ToBits<u32> auto& b) -> u32 {
39
- // / return a.wrapping_add(sus::to_bits<u32>(b));
40
+ // / auto add = [](u32 a, const sus::construct::Transmogrify<u32> auto& b) -> u32
41
+ // / {
42
+ // / return a.wrapping_add(sus::mog<u32>(b));
40
43
// / };
41
44
// / sus::check(add(3_u32, -1_i32) == u32::MIN + 2);
42
45
// / ```
43
46
template <class To , class From >
44
- struct ToBitsImpl ;
47
+ struct TransmogrifyImpl ;
45
48
46
- // sus::construct::ToBits<T, T> trait for identity conversion.
47
- template <class T >
48
- struct ToBitsImpl <T, T> {
49
- constexpr static T from_bits (const T& from) noexcept { return from; }
49
+ // sus::construct::Transmogrify<T, T> trait for identity conversion when `T` is
50
+ // `Copy`.
51
+ template <::sus::mem::Copy T>
52
+ struct TransmogrifyImpl <T, T> {
53
+ constexpr static T mog_from (const T& from) noexcept { return from; }
50
54
};
51
55
52
- // / A type `T` that satisfies `ToBits<T, F>` can be constructed from `F` through
53
- // / a conversion that will always succeed in producing _some_ value, but may be
54
- // / lossy or produce a value with a different meaning. The conversion may
55
- // / truncate or extend `F` in order to do the conversion to `T`.
56
+ // / When a pair of types `T` and `F` satisfy `Transmogrify<T, F>`, it means that
57
+ // / `F` can be converted
58
+ // / ([transmogrified](https://calvinandhobbes.fandom.com/wiki/Transmogrifier))
59
+ // / to `T` through a conversion that will always succeed in producing _some_
60
+ // / value, but may be lossy or produce a value with a different meaning. The
61
+ // / conversion may truncate or extend `F` in order to do the conversion to `T`.
62
+ // /
63
+ // / This operation is also commonly known as type casting, or type coercion. The
64
+ // / conversion to `T` can be done by calling `sus::mog<T>(from)`.
56
65
// /
57
- // / For numeric and primitive types, this provides a mechanism like
58
- // / `static_cast<T>` but it is much safer than `static_cast<T>` as it has
59
- // / defined behaviour for all inputs:
66
+ // / The conversion is defined for the identity conversion where both the input
67
+ // / and output are the same type, if the type is `Copy`, in which case the input
68
+ // / is copied and returned. As Transmogrification is meant to be a cheap
69
+ // / conversion, primarily for primitive types, it does not support `Clone`
70
+ // / types, and `sus::construct::Into` should be used in more complex cases.
71
+ // /
72
+ // / For numeric and primitive types, `Transmogrify` is defined to provide a
73
+ // / mechanism like `static_cast<T>` but it is much safer than `static_cast<T>`
74
+ // / as it has defined behaviour for all inputs:
60
75
// /
61
76
// / * Casting from a float to an integer will perform a static_cast, which
62
77
// / rounds the float towards zero, except:
@@ -81,42 +96,62 @@ struct ToBitsImpl<T, T> {
81
96
// / from `u8`.
82
97
// /
83
98
// / These conversions are all defined in `subspace/num/types.h`.
99
+ // /
100
+ // / The transmogrifier is one of three of the most complicated inventions. The
101
+ // / other two are the [Cerebral
102
+ // / Enhance-O-Tron](https://calvinandhobbes.fandom.com/wiki/Cerebral_Enhance-O-Tron),
103
+ // / and the [Transmogrifier
104
+ // / Gun](https://calvinandhobbes.fandom.com/wiki/Transmogrifier_Gun).
105
+ // /
106
+ // / # Extending to other types
107
+ // /
108
+ // / Types can participate in defining their transmogrification strategy by
109
+ // / providing a specialization of `sus::convert::TransmogrifyImpl<To, From>`.
110
+ // / The conversions should always produce a value of type `T`, should not panic,
111
+ // / and should not cause Undefined Behaviour.
112
+ // /
113
+ // / The `Transmogrify` specialization needs a static method `mog_from()` that
114
+ // / receives `const From&` and returns `To`.
84
115
template <class To , class From >
85
- concept ToBits = requires(const From& from) {
116
+ concept Transmogrify = requires(const From& from) {
86
117
{
87
- ::sus::construct::ToBitsImpl <To, From>::from_bits (from)
118
+ ::sus::construct::TransmogrifyImpl <To, From>::mog_from (from)
88
119
} noexcept -> std::same_as<To>;
89
120
};
90
121
91
- // / An infallible conversion that may lose the original value in the process. If
92
- // / the input can not be represented in the output, some other value will be
93
- // / produced, which may lead to application bugs and memory unsafety if used
94
- // / incorrectly.
122
+ // / An infallible conversion (transmogrification) that may lose the original
123
+ // / value in the process. If the input can not be represented in the output,
124
+ // / some other value will be produced, which may lead to application bugs and
125
+ // / memory unsafety if used incorrectly. This behaves like `static_cast<To>()`
126
+ // / but without Undefined Behaviour.
127
+ // /
128
+ // / The `mog` operation is supported for types `To` and `From` that satisfy
129
+ // / `Transmogrify<To, From>`.
95
130
// /
96
131
// / To convert between types while ensuring the values are preserved, use
97
132
// / `sus::construct::Into` or `sus::construct::TryInto`. Usually prefer using
98
- // / `sus::into(x)` or `sus::try_into(x)` over `sus::to_bits <Y>(x)` as most code
133
+ // / `sus::into(x)` or `sus::try_into(x)` over `sus::mog <Y>(x)` as most code
99
134
// / should preserve values across type transitions.
100
135
// /
101
- // / See `AsBits ` for how numeric and primitive values are converted.
136
+ // / See `Transmogrify ` for how numeric and primitive values are converted.
102
137
// /
103
138
// / # Examples
104
139
// /
105
140
// / This converts `-1_i64` into a `u32`, which both changes its meaning,
106
141
// / becoming a large positive number, and truncates the high 32 bits, losing the
107
142
// / original.
108
143
// / ```cpp
109
- // / sus::check(u32::MAX == sus::to_bits <u32>(-1_i64));
144
+ // / sus::check(u32::MAX == sus::mog <u32>(-1_i64));
110
145
// / ```
111
146
template <class To , class From >
112
- requires (ToBits <To, From>)
113
- constexpr inline To to_bits (const From& from) {
114
- return ToBitsImpl <To, From>::from_bits (from);
147
+ requires (Transmogrify <To, From>)
148
+ constexpr inline To mog (const From& from) {
149
+ return TransmogrifyImpl <To, From>::mog_from (from);
115
150
}
116
151
117
152
} // namespace sus::construct
118
153
119
- // Bring the to_bits () function into the `sus` namespace.
154
+ // Bring the mog () function into the `sus` namespace.
120
155
namespace sus {
121
- using ::sus::construct::to_bits ;
156
+ using ::sus::construct::mog ;
122
157
}
0 commit comments