2 // IWYU pragma: private, include "rlbox.hpp"
3 // IWYU pragma: friend "rlbox_.*\.hpp"
10 #include "rlbox_helpers.hpp"
11 #include "rlbox_type_traits.hpp"
12 #include "rlbox_types.hpp"
14 namespace rlbox::detail
{
16 template<typename T_To
, typename T_From
>
17 inline constexpr void convert_type_fundamental(T_To
& to
,
18 const volatile T_From
& from
)
22 if_constexpr_named(cond1
, !is_fundamental_or_enum_v
<T_To
>)
24 rlbox_detail_static_fail_because(
25 cond1
, "Conversion target should be fundamental or enum type");
27 else if_constexpr_named(cond2
, !is_fundamental_or_enum_v
<T_From
>)
29 rlbox_detail_static_fail_because(
30 cond2
, "Conversion source should be fundamental or enum type");
32 else if_constexpr_named(cond3
, is_enum_v
<T_To
> || is_enum_v
<T_From
>)
34 static_assert(std::is_same_v
<detail::remove_cv_ref_t
<T_To
>,
35 detail::remove_cv_ref_t
<T_From
>>);
38 else if_constexpr_named(
39 cond4
, is_floating_point_v
<T_To
> || is_floating_point_v
<T_From
>)
41 static_assert(is_floating_point_v
<T_To
> && is_floating_point_v
<T_From
>);
42 // language coerces different float types
45 else if_constexpr_named(cond5
, is_integral_v
<T_To
> || is_integral_v
<T_From
>)
47 static_assert(is_integral_v
<T_To
> && is_integral_v
<T_From
>);
50 "Over/Underflow when converting between integer types";
52 // Some branches don't use the param
53 RLBOX_UNUSED(err_msg
);
55 if constexpr (is_signed_v
<T_To
> == is_signed_v
<T_From
> &&
56 sizeof(T_To
) >= sizeof(T_From
)) {
57 // Eg: int64_t from int32_t, uint64_t from uint32_t
58 } else if constexpr (is_unsigned_v
<T_To
> && is_unsigned_v
<T_From
>) {
59 // Eg: uint32_t from uint64_t
60 dynamic_check(from
<= numeric_limits
<T_To
>::max(), err_msg
);
61 } else if constexpr (is_signed_v
<T_To
> && is_signed_v
<T_From
>) {
62 // Eg: int32_t from int64_t
63 dynamic_check(from
>= numeric_limits
<T_To
>::min(), err_msg
);
64 dynamic_check(from
<= numeric_limits
<T_To
>::max(), err_msg
);
65 } else if constexpr (is_unsigned_v
<T_To
> && is_signed_v
<T_From
>) {
66 if constexpr (sizeof(T_To
) < sizeof(T_From
)) {
67 // Eg: uint32_t from int64_t
68 dynamic_check(from
>= 0, err_msg
);
69 auto to_max
= numeric_limits
<T_To
>::max();
70 dynamic_check(from
<= static_cast<T_From
>(to_max
), err_msg
);
72 // Eg: uint32_t from int32_t, uint64_t from int32_t
73 dynamic_check(from
>= 0, err_msg
);
75 } else if constexpr (is_signed_v
<T_To
> && is_unsigned_v
<T_From
>) {
76 if constexpr (sizeof(T_To
) <= sizeof(T_From
)) {
77 // Eg: int32_t from uint32_t, int32_t from uint64_t
78 auto to_max
= numeric_limits
<T_To
>::max();
79 dynamic_check(from
<= static_cast<T_From
>(to_max
), err_msg
);
81 // Eg: int64_t from uint32_t
84 to
= static_cast<T_To
>(from
);
88 constexpr auto unknownCase
= !(cond1
|| cond2
|| cond3
|| cond4
|| cond5
);
89 rlbox_detail_static_fail_because(
90 unknownCase
, "Unexpected case for convert_type_fundamental");
94 template<typename T_To
, typename T_From
>
95 inline constexpr void convert_type_fundamental_or_array(T_To
& to
,
100 using T_To_C
= std_array_to_c_arr_t
<T_To
>;
101 using T_From_C
= std_array_to_c_arr_t
<T_From
>;
102 using T_To_El
= remove_all_extents_t
<T_To_C
>;
103 using T_From_El
= remove_all_extents_t
<T_From_C
>;
105 if_constexpr_named(cond1
, is_array_v
<T_To_C
> != is_array_v
<T_From_C
>)
107 rlbox_detail_static_fail_because(
108 cond1
, "Conversion should not go between array and non array types");
110 else if constexpr (!is_array_v
<T_To_C
>)
112 convert_type_fundamental(to
, from
);
114 else if_constexpr_named(cond2
, !all_extents_same
<T_To_C
, T_From_C
>)
116 rlbox_detail_static_fail_because(
117 cond2
, "Conversion between arrays should have same dimensions");
119 else if_constexpr_named(cond3
,
120 is_pointer_v
<T_To_El
> || is_pointer_v
<T_From_El
>)
122 rlbox_detail_static_fail_because(cond3
,
123 "convert_type_fundamental_or_array "
124 "does not allow arrays of pointers");
128 // Explicitly using size to check for element type as we may be going across
129 // different types of the same width such as void* and uintptr_t
130 if constexpr (sizeof(T_To_El
) == sizeof(T_From_El
) &&
131 is_signed_v
<T_To_El
> == is_signed_v
<T_From_El
>) {
132 // Sanity check - this should definitely be true
133 static_assert(sizeof(T_From_C
) == sizeof(T_To_C
));
134 std::memcpy(&to
, &from
, sizeof(T_To_C
));
136 for (size_t i
= 0; i
< std::extent_v
<T_To_C
>; i
++) {
137 convert_type_fundamental_or_array(to
[i
], from
[i
]);
143 enum class adjust_type_direction
150 enum class adjust_type_context
156 template<typename T_Sbx
,
157 adjust_type_direction Direction
,
158 adjust_type_context Context
,
161 inline constexpr void convert_type_non_class(
164 const void* example_unsandboxed_ptr
,
165 rlbox_sandbox
<T_Sbx
>* sandbox_ptr
)
169 // Some branches don't use the param
170 RLBOX_UNUSED(example_unsandboxed_ptr
);
171 RLBOX_UNUSED(sandbox_ptr
);
173 using T_To_C
= std_array_to_c_arr_t
<T_To
>;
174 using T_From_C
= std_array_to_c_arr_t
<T_From
>;
175 using T_To_El
= remove_all_extents_t
<T_To_C
>;
176 using T_From_El
= remove_all_extents_t
<T_From_C
>;
178 if constexpr (is_pointer_v
<T_To_C
> || is_pointer_v
<T_From_C
>) {
180 if constexpr (Direction
== adjust_type_direction::NO_CHANGE
) {
182 static_assert(is_pointer_v
<T_To_C
> && is_pointer_v
<T_From_C
> &&
183 sizeof(T_To_C
) == sizeof(T_From_C
));
186 } else if constexpr (Direction
== adjust_type_direction::TO_SANDBOX
) {
188 static_assert(is_pointer_v
<T_From_C
>);
189 // Maybe a function pointer, so convert
190 auto from_c
= reinterpret_cast<const void*>(from
);
191 if constexpr (Context
== adjust_type_context::SANDBOX
) {
192 RLBOX_DEBUG_ASSERT(sandbox_ptr
!= nullptr);
193 to
= sandbox_ptr
->template get_sandboxed_pointer
<T_From_C
>(from_c
);
195 RLBOX_DEBUG_ASSERT(from_c
== nullptr ||
196 example_unsandboxed_ptr
!= nullptr);
198 rlbox_sandbox
<T_Sbx
>::template get_sandboxed_pointer_no_ctx
<T_From_C
>(
199 from_c
, example_unsandboxed_ptr
);
202 } else if constexpr (Direction
== adjust_type_direction::TO_APPLICATION
) {
204 static_assert(is_pointer_v
<T_To_C
>);
205 if constexpr (Context
== adjust_type_context::SANDBOX
) {
206 RLBOX_DEBUG_ASSERT(sandbox_ptr
!= nullptr);
207 to
= sandbox_ptr
->template get_unsandboxed_pointer
<T_To_C
>(from
);
209 RLBOX_DEBUG_ASSERT(from
== 0 || example_unsandboxed_ptr
!= nullptr);
211 rlbox_sandbox
<T_Sbx
>::template get_unsandboxed_pointer_no_ctx
<T_To_C
>(
212 from
, example_unsandboxed_ptr
);
216 } else if constexpr (is_pointer_v
<T_To_El
> || is_pointer_v
<T_From_El
>) {
218 if constexpr (Direction
== adjust_type_direction::NO_CHANGE
) {
219 // Sanity check - this should definitely be true
220 static_assert(sizeof(T_To_El
) == sizeof(T_From_El
) &&
221 sizeof(T_From_C
) == sizeof(T_To_C
));
222 memcpy(&to
, &from
, sizeof(T_To_C
));
224 for (size_t i
= 0; i
< std::extent_v
<T_To_C
>; i
++) {
225 convert_type_non_class
<T_Sbx
, Direction
, Context
>(
226 to
[i
], from
[i
], example_unsandboxed_ptr
, sandbox_ptr
);
231 convert_type_fundamental_or_array(to
, from
);
235 // Structs implement their own convert_type by specializing this class
236 // Have to do this via a class, as functions can't be partially specialized
237 template<typename T_Sbx
,
238 adjust_type_direction Direction
,
239 adjust_type_context Context
,
242 class convert_type_class
;
243 // The specialization implements the following
245 // static inline void run(T_To& to,
246 // const T_From& from,
247 // const void* example_unsandboxed_ptr);
250 template<typename T_Sbx
,
251 adjust_type_direction Direction
,
252 adjust_type_context Context
,
255 inline void convert_type(T_To
& to
,
257 const void* example_unsandboxed_ptr
,
258 rlbox_sandbox
<T_Sbx
>* sandbox_ptr
)
260 if constexpr ((std::is_class_v
<T_To
> ||
261 std::is_class_v
<T_From
>)&&!detail::is_std_array_v
<T_To
> &&
262 !detail::is_std_array_v
<T_From
>) {
264 static_assert(std::is_class_v
<T_From
> && std::is_class_v
<T_To
>);
265 convert_type_class
<T_Sbx
, Direction
, Context
, T_To
, T_From
>::run(
266 to
, from
, example_unsandboxed_ptr
, sandbox_ptr
);
268 convert_type_non_class
<T_Sbx
, Direction
, Context
>(
269 to
, from
, example_unsandboxed_ptr
, sandbox_ptr
);