1 // Copyright 2025 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include "pw_bytes/alignment.h"
17 #include "pw_span/internal/config.h"
18 #include "pw_span/span.h"
19
20 namespace pw {
21 namespace internal {
22
23 template <class ResultT, size_t kSourceExtentBytes>
24 using SpanFromBytes = span<ResultT,
25 (kSourceExtentBytes == dynamic_extent
26 ? dynamic_extent
27 : kSourceExtentBytes / sizeof(ResultT))>;
28
29 } // namespace internal
30
31 /// @defgroup pw_span_cast
32 /// @{
33
34 /// Casts a `pw::span<std::byte>` (`ByteSpan`) to a span of a different type.
35 ///
36 /// This function is only safe to use if the underlying data is actually of the
37 /// specified type. You cannot safely use this function to reinterpret e.g. a
38 /// raw byte array from `malloc()` as a span of integers.
39 ///
40 /// This function is essentially the inverse of `pw::as_writable_bytes`.
41 ///
42 /// If `kSourceExtentBytes` is `dynamic_extent`, the returned span also has a
43 /// dynamic extent. Otherwise, the returned span has a static extent of
44 /// `kSourceExtentBytes / sizeof(ResultT)`.
45 ///
46 /// @tparam ResultT The type of the returned span.
47 /// Must be one byte to avoid misuse and violation
48 /// of the strict aliasing rule. This restriction
49 /// might be lifted in the future.
50 /// @tparam kSourceExtentBytes The extent of the source byte span. This is
51 /// normally inferred and need not be explicitly
52 /// provided.
53 template <class ResultT, size_t kSourceExtentBytes>
span_cast(span<std::byte,kSourceExtentBytes> bytes)54 internal::SpanFromBytes<ResultT, kSourceExtentBytes> span_cast(
55 span<std::byte, kSourceExtentBytes> bytes) {
56 static_assert(sizeof(ResultT) == 1);
57
58 ResultT* const ptr = reinterpret_cast<ResultT*>(bytes.data());
59 const size_t count = bytes.size() / sizeof(ResultT);
60
61 auto result =
62 internal::SpanFromBytes<ResultT, kSourceExtentBytes>{ptr, count};
63
64 _PW_SPAN_ASSERT(IsAlignedAs<ResultT>(result.data()));
65 _PW_SPAN_ASSERT(result.size_bytes() == bytes.size_bytes());
66
67 return result;
68 }
69
70 // TODO: https://pwbug.dev/396493663 - Doxygen thinks this is the same function
71 // as the non-const version above, and merges the docs together.
72
73 /// Casts a `pw::span<const std::byte>` (`ConstByteSpan`) to a span of a
74 /// different const type.
75 ///
76 /// This function is only safe to use if the underlying data is actually of the
77 /// specified type. You cannot safely use this function to reinterpret e.g. a
78 /// raw byte array from `malloc()` as a span of integers.
79 ///
80 /// This function is essentially the inverse of `pw::as_bytes`.
81 ///
82 /// If `kSourceExtentBytes` is `dynamic_extent`, the returned span also has a
83 /// dynamic extent. Otherwise, the returned span has a static extent of
84 /// `kSourceExtentBytes / sizeof(ResultT)`.
85 ///
86 /// @tparam ResultT The type of the returned span.
87 /// Must be one byte to avoid misuse and violation
88 /// of the strict aliasing rule. This restriction
89 /// might be lifted in the future.
90 /// @tparam kSourceExtentBytes The extent of the source byte span. This is
91 /// normally inferred and need not be explicitly
92 /// provided.
93 template <class ResultT, size_t kSourceExtentBytes>
span_cast(span<const std::byte,kSourceExtentBytes> bytes)94 internal::SpanFromBytes<const ResultT, kSourceExtentBytes> span_cast(
95 span<const std::byte, kSourceExtentBytes> bytes) {
96 static_assert(sizeof(ResultT) == 1);
97
98 const ResultT* const ptr = reinterpret_cast<const ResultT*>(bytes.data());
99 const size_t count = bytes.size() / sizeof(ResultT);
100
101 auto result =
102 internal::SpanFromBytes<const ResultT, kSourceExtentBytes>{ptr, count};
103
104 _PW_SPAN_ASSERT(IsAlignedAs<const ResultT>(result.data()));
105 _PW_SPAN_ASSERT(result.size_bytes() == bytes.size_bytes());
106
107 return result;
108 }
109
110 /// @}
111
112 } // namespace pw
113