Skip to content

Commit 717cf00

Browse files
committed
fix: Use static_cast instead of reinterpret_cast
1 parent e2ce880 commit 717cf00

2 files changed

Lines changed: 85 additions & 12 deletions

File tree

include/byte_span/byte_span.hpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ constexpr auto calculate_size(size_t count) noexcept -> size_t {
5959
}
6060
}
6161

62+
template <typename T>
63+
using void_pointer_for =
64+
std::conditional_t<std::is_const_v<T>, const void*, void*>;
65+
66+
template <typename To, typename From>
67+
constexpr auto pointer_cast(From* p) noexcept -> To* {
68+
return static_cast<To*>(static_cast<void_pointer_for<From>>(p));
69+
}
70+
6271
} // namespace detail
6372

6473
template <typename B, size_t Extent = dynamic_extent>
@@ -102,7 +111,7 @@ class byte_span {
102111
constexpr explicit(Extent != dynamic_extent
103112
|| !detail::byte_like<std::iter_value_t<It>>)
104113
byte_span(It first, End last) noexcept(noexcept(last - first))
105-
: span_{reinterpret_cast<pointer>(std::to_address(first)),
114+
: span_{detail::pointer_cast<element_type>(std::to_address(first)),
106115
detail::calculate_size<std::iter_value_t<It>>(
107116
static_cast<size_type>(last - first))} {}
108117

@@ -113,7 +122,7 @@ class byte_span {
113122
constexpr explicit(Extent != dynamic_extent
114123
|| !detail::byte_like<std::iter_value_t<It>>)
115124
byte_span(It first, size_type count) noexcept
116-
: span_{reinterpret_cast<pointer>(std::to_address(first)),
125+
: span_{detail::pointer_cast<element_type>(std::to_address(first)),
117126
detail::calculate_size<std::iter_value_t<It>>(count)} {}
118127

119128
// From void* - always explicit
@@ -122,7 +131,7 @@ class byte_span {
122131
requires std::is_void_v<VoidType>
123132
&& detail::const_convertible<VoidType, element_type>
124133
constexpr explicit byte_span(VoidType* data, size_type size) noexcept
125-
: span_{reinterpret_cast<pointer>(data), size} {}
134+
: span_{detail::pointer_cast<element_type>(data), size} {}
126135

127136
// From c-style arrays
128137
template <typename T, size_t ArrayExtent>
@@ -132,7 +141,7 @@ class byte_span {
132141
constexpr explicit(!detail::byte_like<T>)
133142
// NOLINTNEXTLINE
134143
byte_span(T (&arr)[ArrayExtent]) noexcept
135-
: span_{reinterpret_cast<pointer>(arr),
144+
: span_{detail::pointer_cast<element_type>(std::data(arr)),
136145
detail::calculate_size<T>(ArrayExtent)} {}
137146

138147
// From std::array
@@ -143,7 +152,7 @@ class byte_span {
143152
constexpr explicit(!detail::byte_like<T>)
144153
// NOLINTNEXTLINE
145154
byte_span(std::array<T, ArrayExtent>& arr) noexcept
146-
: span_{reinterpret_cast<pointer>(arr.data()),
155+
: span_{detail::pointer_cast<element_type>(arr.data()),
147156
detail::calculate_size<T>(ArrayExtent)} {}
148157

149158
// From const std::array
@@ -154,7 +163,7 @@ class byte_span {
154163
constexpr explicit(!detail::byte_like<T>)
155164
// NOLINTNEXTLINE
156165
byte_span(const std::array<T, ArrayExtent>& arr) noexcept
157-
: span_{reinterpret_cast<pointer>(arr.data()),
166+
: span_{detail::pointer_cast<element_type>(arr.data()),
158167
detail::calculate_size<T>(ArrayExtent)} {}
159168

160169
// From Ranges
@@ -175,7 +184,7 @@ class byte_span {
175184
// NOLINTNEXTLINE
176185
byte_span(Range&& range) noexcept(noexcept(std::ranges::data(range))
177186
&& noexcept(std::ranges::size(range)))
178-
: span_{reinterpret_cast<pointer>(std::ranges::data(range)),
187+
: span_{detail::pointer_cast<element_type>(std::ranges::data(range)),
179188
detail::calculate_size<std::ranges::range_value_t<Range>>(
180189
std::ranges::size(range))} {
181190
if constexpr (Extent != dynamic_extent) {
@@ -196,7 +205,7 @@ class byte_span {
196205
|| Extent != dynamic_extent)
197206
// NOLINTNEXTLINE
198207
byte_span(const std::span<OtherElementType, OtherExtent>& s) noexcept
199-
: span_{reinterpret_cast<pointer>(s.data()),
208+
: span_{detail::pointer_cast<element_type>(s.data()),
200209
detail::calculate_size<OtherElementType>(s.size())} {
201210
if constexpr (Extent != dynamic_extent) {
202211
assert(detail::calculate_size<OtherElementType>(s.size()) == Extent);
@@ -349,15 +358,15 @@ constexpr void swap(byte_span<B, Extent>& lhs,
349358

350359
template <typename B, size_t N>
351360
constexpr auto as_sv(byte_span<B, N> bytes) noexcept -> std::string_view {
352-
return {reinterpret_cast<const char*>(bytes.data()), bytes.size()};
361+
return {detail::pointer_cast<const char>(bytes.data()), bytes.size()};
353362
}
354363

355364
template <typename T, typename B, size_t N>
356365
requires std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>
357366
&& (!std::is_void_v<T>) && (N == dynamic_extent || N >= sizeof(T))
358367
constexpr auto as_value(byte_span<B, N> bytes) noexcept -> const T& {
359368
assert(bytes.size() >= sizeof(T));
360-
return *std::launder(reinterpret_cast<const T*>(bytes.data()));
369+
return *std::launder(detail::pointer_cast<const T>(bytes.data()));
361370
}
362371

363372
// byte_span -> std::span<std::byte>
@@ -385,7 +394,7 @@ constexpr auto as_writable_span(byte_span<B, N> bytes) noexcept
385394
-> std::span<T, N == dynamic_extent ? dynamic_extent : N / sizeof(T)> {
386395
assert(bytes.size() % sizeof(T) == 0);
387396
return std::span<T, (N == dynamic_extent ? dynamic_extent : N / sizeof(T))>{
388-
std::launder(reinterpret_cast<T*>(bytes.data())),
397+
std::launder(detail::pointer_cast<T>(bytes.data())),
389398
bytes.size() / sizeof(T)};
390399
}
391400

@@ -399,7 +408,7 @@ constexpr auto as_span(byte_span<B, N> bytes) noexcept
399408
assert(bytes.size() % sizeof(T) == 0);
400409
return std::span<const T,
401410
(N == dynamic_extent ? dynamic_extent : N / sizeof(T))>{
402-
std::launder(reinterpret_cast<const T*>(bytes.data())),
411+
std::launder(detail::pointer_cast<const T>(bytes.data())),
403412
bytes.size() / sizeof(T)};
404413
}
405414

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// NOLINTBEGIN(misc-const-correctness,clang-analyzer-deadcode.DeadStores,unused-includes)
2+
#if defined(__cpp_constexpr) && __cpp_constexpr >= 202207L // C++26
3+
#include <algorithm>
4+
#include <array>
5+
#include <cstddef>
6+
#include <cstdint>
7+
#include <span>
8+
#include <string_view>
9+
#include <type_traits>
10+
#include <vector>
11+
12+
#include <catch2/catch_approx.hpp>
13+
#include <catch2/catch_template_test_macros.hpp>
14+
#include <catch2/catch_test_macros.hpp>
15+
16+
#include "byte_span/byte_span.hpp"
17+
18+
19+
using range3::as_bytes;
20+
using range3::as_span;
21+
using range3::as_sv;
22+
using range3::as_writable_bytes;
23+
using range3::as_writable_span;
24+
using range3::byte_span;
25+
using range3::byte_view;
26+
using range3::cbyte_view;
27+
using range3::detail::byte_like;
28+
using range3::detail::const_convertible;
29+
using namespace std::string_view_literals;
30+
31+
#pragma GCC diagnostic push
32+
#pragma GCC diagnostic ignored "-Wunused-variable"
33+
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
34+
35+
36+
37+
TEST_CASE("byte_span compile-time construction", "[byte_span]") {
38+
SECTION("from iterator and sentinel") {
39+
constexpr std::array<char, 4> arr = {'a', 'b', 'c', 'd'};
40+
constexpr byte_span view(arr.begin(), arr.end());
41+
STATIC_REQUIRE(view.size() == 4);
42+
REQUIRE(view.size() == 4);
43+
}
44+
45+
SECTION("from iterator and count") {
46+
constexpr std::array<char, 4> arr = {'a', 'b', 'c', 'd'};
47+
constexpr byte_span view(arr.begin(), 4);
48+
STATIC_REQUIRE(view.size() == 4);
49+
REQUIRE(view.size() == 4);
50+
}
51+
52+
/*
53+
SECTION("from std::array") {}
54+
SECTION("from C array") {}
55+
SECTION("from std::span") {}
56+
*/
57+
}
58+
59+
60+
61+
#pragma GCC diagnostic pop
62+
63+
#endif
64+
// NOLINTEND(misc-const-correctness,clang-analyzer-deadcode.DeadStores)

0 commit comments

Comments
 (0)