Skip to content

Commit 36f70ff

Browse files
committed
add safe_cast
1 parent 57a9b32 commit 36f70ff

File tree

8 files changed

+82
-2
lines changed

8 files changed

+82
-2
lines changed

include/safe.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
#include <safe/int.hpp>
99
#include <safe/match.hpp>
1010
#include <safe/object.hpp>
11+
#include <safe/safe_cast.hpp>
1112
#include <safe/value.hpp>
1213
#include <safe/var.hpp>

include/safe/detail/fwd.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ template <typename T> struct unsafe_cast_ferry {
3737

3838
template <typename T>
3939
requires(safe::Var<T>)
40-
[[nodiscard]] constexpr auto unsafe_cast(auto const &src) {
40+
[[nodiscard]] SAFE_INLINE constexpr auto unsafe_cast(auto const &src) {
4141
return T{safe::unsafe_cast_ferry{src}};
4242
}
4343

4444
template <typename T>
4545
requires(!safe::Var<T>)
46-
[[nodiscard]] constexpr auto unsafe_cast(auto const &src) {
46+
[[nodiscard]] SAFE_INLINE constexpr auto unsafe_cast(auto const &src) {
4747
return src;
4848
}

include/safe/safe_cast.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
3+
#include <safe/detail/concepts.hpp>
4+
#include <safe/detail/fwd.hpp>
5+
#include <safe/var.hpp>
6+
7+
#include <concepts>
8+
9+
template <typename To, safe::Var From>
10+
requires(std::is_convertible_v<typename From::value_type, To>)
11+
[[nodiscard]] SAFE_INLINE constexpr To safe_cast(From const &src) {
12+
static_assert(safe::detail::integral_type<To>::requirement >=
13+
From::requirement,
14+
"The safe value must fit within the target value type.");
15+
16+
return static_cast<To>(src.unsafe_value_);
17+
}

test/safe/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_subdirectory(array)
22
add_subdirectory(var)
3+
add_subdirectory(safe_cast)
34

45
function(add_test_suites)
56
foreach(test_file ${ARGN})
@@ -34,6 +35,7 @@ add_test_suites(
3435
var.cpp
3536
match.cpp
3637
array.cpp
38+
safe_cast.cpp
3739
dsl/add.cpp
3840
dsl/divide.cpp
3941
dsl/intersection.cpp

test/safe/safe_cast.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "gmock/gmock.h"
2+
#include "gtest/gtest.h"
3+
4+
#include <cstdint>
5+
#include <type_traits>
6+
7+
#include <safe.hpp>
8+
9+
using ::testing::_;
10+
using ::testing::InSequence;
11+
using ::testing::Return;
12+
13+
using namespace safe::interval_types;
14+
using namespace safe::int_types;
15+
using namespace safe::literals;
16+
17+
TEST(safe_cast_test, cast_same_type) {
18+
auto v = safe_cast<std::int32_t>(42_s32);
19+
EXPECT_EQ(v, 42);
20+
static_assert(std::is_same_v<std::int32_t, decltype(v)>);
21+
}
22+
23+
TEST(safe_cast_test, cast_narrower_type) {
24+
auto v = safe_cast<std::uint8_t>(42_s32);
25+
EXPECT_EQ(v, 42);
26+
static_assert(std::is_same_v<std::uint8_t, decltype(v)>);
27+
}
28+
29+
TEST(safe_cast_test, cast_different_sign) {
30+
auto v = safe_cast<std::uint32_t>(99_s32);
31+
EXPECT_EQ(v, 99);
32+
static_assert(std::is_same_v<std::uint32_t, decltype(v)>);
33+
}

test/safe/safe_cast/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function(add_fail_tests)
2+
foreach(name ${ARGN})
3+
add_compile_fail_test("${name}.cpp" LIBRARIES safe_arithmetic)
4+
endforeach()
5+
endfunction()
6+
7+
add_fail_tests(
8+
incompatible_sign_cast
9+
incompatible_range_cast)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <cstdint>
2+
3+
#include <safe.hpp>
4+
5+
using namespace safe::interval_types;
6+
using namespace safe::int_types;
7+
using namespace safe::literals;
8+
9+
auto main() -> int { auto v = safe_cast<std::uint8_t>(420_u32); }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <cstdint>
2+
3+
#include <safe.hpp>
4+
5+
using namespace safe::interval_types;
6+
using namespace safe::int_types;
7+
using namespace safe::literals;
8+
9+
auto main() -> int { auto v = safe_cast<std::uint32_t>(-99_s32); }

0 commit comments

Comments
 (0)