77#include < linyaps_box/utils/span.h>
88
99#include < array>
10+ #include < cstring>
1011#include < vector>
1112
1213namespace utils = linyaps_box::utils;
@@ -28,7 +29,6 @@ TEST(SpanAt, OutOfRangeThrows)
2829 const utils::span<int > s (arr);
2930
3031 EXPECT_THROW (std::ignore = s.at (3 ), std::out_of_range);
31- EXPECT_THROW (std::ignore = s.at (100 ), std::out_of_range);
3232}
3333
3434TEST (SpanAt, EmptySpanThrows)
@@ -55,16 +55,7 @@ TEST(SpanAt, ConstSpanReadsCorrectly)
5555 EXPECT_EQ (s.at (1 ), 6 );
5656}
5757
58- TEST (SpanAt, BoundaryIndex)
59- {
60- std::array arr = { 99 };
61- const utils::span<int > s (arr);
62-
63- EXPECT_EQ (s.at (0 ), 99 );
64- EXPECT_THROW (std::ignore = s.at (1 ), std::out_of_range);
65- }
66-
67- TEST (SpanAt, SubspanAt)
58+ TEST (Subspan, Offset)
6859{
6960 std::array raw{ 0 , 1 , 2 , 3 , 4 };
7061 auto s = utils::span<int >(raw).subspan (1 , 3 );
@@ -73,3 +64,209 @@ TEST(SpanAt, SubspanAt)
7364 EXPECT_EQ (s.at (2 ), 3 );
7465 EXPECT_THROW (std::ignore = s.at (3 ), std::out_of_range);
7566}
67+
68+ // P1976R2: fixed-size span construction from dynamic-size range should be explicit.
69+ // Single-argument constructors are tested via is_convertible_v (which requires implicit
70+ // conversion). Two-argument constructors (ptr,count) and (first,last) are tested via runtime
71+ // positive tests.
72+ static_assert (std::is_convertible_v<std::vector<int > &, utils::span<int >>,
73+ " dynamic span from container should be implicit" );
74+ static_assert (!std::is_convertible_v<std::vector<int > &, utils::span<int , 3 >>,
75+ " fixed span from container should be explicit" );
76+
77+ static_assert (std::is_convertible_v<utils::span<int > &, utils::span<const int >>,
78+ " dynamic→dynamic span should be implicit" );
79+ static_assert (!std::is_convertible_v<utils::span<int > &, utils::span<const int , 5 >>,
80+ " dynamic→fixed span should be explicit" );
81+ static_assert (std::is_convertible_v<utils::span<int , 5 > &, utils::span<const int , 5 >>,
82+ " fixed→fixed (matching) span should be implicit" );
83+ static_assert (std::is_convertible_v<utils::span<int , 5 > &, utils::span<const int >>,
84+ " fixed→dynamic span should be implicit" );
85+
86+ static_assert (std::is_convertible_v<int (&)[5 ], utils::span<int >>,
87+ " dynamic span from c-array should be implicit" );
88+ static_assert (std::is_convertible_v<int (&)[5 ], utils::span<int , 5 >>,
89+ " fixed span from c-array (matching extent) should be implicit" );
90+ static_assert (std::is_convertible_v<std::array<int , 5 > &, utils::span<int , 5 >>,
91+ " fixed span from std::array (matching extent) should be implicit" );
92+ static_assert (std::is_convertible_v<const std::array<int , 5 > &, utils::span<const int , 5 >>,
93+ " fixed span from const std::array (matching extent) should be implicit" );
94+
95+ static_assert (std::is_default_constructible_v<utils::span<int >>,
96+ " dynamic span should be default-constructible" );
97+ static_assert (!std::is_default_constructible_v<utils::span<int , 5 >>,
98+ " fixed non-zero span should NOT be default-constructible" );
99+
100+ TEST (SpanConstructorExplicit, PtrCountDynamic)
101+ {
102+ const std::vector<int > data{ 1 , 2 , 3 };
103+ const utils::span<const int > s (data.data (), 3 );
104+ EXPECT_EQ (s.size (), 3 );
105+ EXPECT_EQ (s[0 ], 1 );
106+ EXPECT_EQ (s[2 ], 3 );
107+ }
108+
109+ TEST (SpanConstructorExplicit, FirstLastDynamic)
110+ {
111+ const std::vector<int > data{ 1 , 2 , 3 , 4 };
112+ const utils::span<const int > s (data.cbegin (), data.cend ());
113+ EXPECT_EQ (s.size (), 4 );
114+ EXPECT_EQ (s[0 ], 1 );
115+ EXPECT_EQ (s[3 ], 4 );
116+ }
117+
118+ TEST (SpanConstructorExplicit, ContainerFixedExplicit)
119+ {
120+ const std::vector<int > v{ 1 , 2 , 3 };
121+ auto s = utils::span<const int , 3 >(v);
122+ EXPECT_EQ (s.size (), 3 );
123+ EXPECT_EQ (s[0 ], 1 );
124+ EXPECT_EQ (s[2 ], 3 );
125+ }
126+
127+ TEST (SpanConstructorExplicit, ConvertingSpanFixedToDynamic)
128+ {
129+ std::array arr{ 1 , 2 , 3 };
130+ const utils::span<const int , 3 > fixed (arr);
131+ const utils::span<const int > dyn (fixed);
132+ EXPECT_EQ (dyn.size (), 3 );
133+ EXPECT_EQ (dyn[0 ], 1 );
134+ }
135+
136+ TEST (SpanConstructorExplicit, ConvertingSpanDynamicToFixed)
137+ {
138+ std::vector<int > arr{ 1 , 2 , 3 };
139+ const utils::span<const int > dyn (arr);
140+ auto fixed = utils::span<const int , 3 >(dyn);
141+ EXPECT_EQ (fixed.size (), 3 );
142+ EXPECT_EQ (fixed[0 ], 1 );
143+ }
144+
145+ TEST (SpanConstructorExplicit, ItCountDynamic)
146+ {
147+ const std::vector<int > data{ 10 , 20 , 30 };
148+ const utils::span<const int > s (data.cbegin (), 2 );
149+ EXPECT_EQ (s.size (), 2 );
150+ EXPECT_EQ (s[0 ], 10 );
151+ EXPECT_EQ (s[1 ], 20 );
152+ }
153+
154+ TEST (SpanConstructorExplicit, ItEndFixedExplicit)
155+ {
156+ const std::vector<int > data{ 1 , 2 , 3 };
157+ const utils::span<const int , 3 > s (data.cbegin (), data.cend ());
158+ EXPECT_EQ (s.size (), 3 );
159+ EXPECT_EQ (s[0 ], 1 );
160+ EXPECT_EQ (s[2 ], 3 );
161+ }
162+
163+ TEST (SpanConstructorExplicit, ItCountFixedExplicit)
164+ {
165+ const std::vector<int > data{ 5 , 6 , 7 };
166+ const utils::span<const int , 3 > s (data.cbegin (), 3 );
167+ EXPECT_EQ (s.size (), 3 );
168+ EXPECT_EQ (s[0 ], 5 );
169+ EXPECT_EQ (s[2 ], 7 );
170+ }
171+
172+ TEST (SpanCTAD, CArray)
173+ {
174+ int arr[] = { 1 , 2 , 3 }; // NOLINT
175+ const utils::span s (arr);
176+ EXPECT_EQ (s.size (), 3 );
177+ EXPECT_EQ (s[0 ], 1 );
178+ EXPECT_EQ (s[2 ], 3 );
179+ static_assert (decltype (s)::extent == 3 );
180+ }
181+
182+ TEST (SpanCTAD, StdArray)
183+ {
184+ std::array arr{ 10 , 20 };
185+ const utils::span s (arr);
186+ EXPECT_EQ (s.size (), 2 );
187+ EXPECT_EQ (s[0 ], 10 );
188+ static_assert (decltype (s)::extent == 2 );
189+ }
190+
191+ TEST (SpanCTAD, ConstStdArray)
192+ {
193+ const std::array arr{ 1 , 2 , 3 , 4 };
194+ const utils::span s (arr);
195+ EXPECT_EQ (s.size (), 4 );
196+ EXPECT_EQ (s[3 ], 4 );
197+ static_assert (decltype (s)::extent == 4 );
198+ }
199+
200+ TEST (SpanCTAD, ItCount)
201+ {
202+ std::vector<int > v{ 5 , 5 , 5 };
203+ const utils::span s (v.begin (), 2 );
204+ EXPECT_EQ (s.size (), 2 );
205+ EXPECT_EQ (s[0 ], 5 );
206+ static_assert (decltype (s)::extent == utils::dynamic_extent);
207+ }
208+
209+ TEST (SpanCTAD, ItEnd)
210+ {
211+ const std::vector<int > v{ 7 , 8 , 9 };
212+ const utils::span s (v.cbegin (), v.cend ());
213+ EXPECT_EQ (s.size (), 3 );
214+ EXPECT_EQ (s[2 ], 9 );
215+ static_assert (decltype (s)::extent == utils::dynamic_extent);
216+ }
217+
218+ namespace {
219+
220+ template <typename T, typename = void >
221+ struct has_as_bytes : std::false_type
222+ {
223+ };
224+
225+ template <typename T>
226+ struct has_as_bytes <T, std::void_t <decltype (utils::as_bytes(std::declval<utils::span<T>>()))>>
227+ : std::true_type
228+ {
229+ };
230+
231+ template <typename T, typename = void >
232+ struct has_as_writable_bytes : std::false_type
233+ {
234+ };
235+
236+ template <typename T>
237+ struct has_as_writable_bytes <
238+ T,
239+ std::void_t <decltype (utils::as_writable_bytes(std::declval<utils::span<T>>()))>> : std::true_type
240+ {
241+ };
242+
243+ } // anonymous namespace
244+
245+ static_assert (has_as_bytes<int >::value, " as_bytes should accept int" );
246+ static_assert (has_as_bytes<const int >::value, " as_bytes should accept const int" );
247+ static_assert (!has_as_bytes<volatile int >::value, " as_bytes should reject volatile" );
248+ static_assert (has_as_writable_bytes<int >::value, " as_writable_bytes should accept int" );
249+ static_assert (!has_as_writable_bytes<const int >::value, " as_writable_bytes should reject const" );
250+ static_assert (!has_as_writable_bytes<volatile int >::value,
251+ " as_writable_bytes should reject volatile" );
252+
253+ TEST (SpanBytes, AsBytes)
254+ {
255+ const std::array arr{ 0x01020304 , 0x05060708 };
256+ const utils::span s (arr);
257+ auto bytes = utils::as_bytes (s);
258+ EXPECT_EQ (bytes.size (), sizeof (arr));
259+ EXPECT_EQ (bytes.data (), reinterpret_cast <const std::byte *>(s.data ()));
260+ }
261+
262+ TEST (SpanBytes, AsWritableBytes)
263+ {
264+ std::array arr{ 0x01020304 };
265+ const utils::span s (arr);
266+ auto bytes = utils::as_writable_bytes (s);
267+ EXPECT_EQ (bytes.size (), sizeof (int ));
268+ memset (bytes.data (), 0 , sizeof (int ));
269+ EXPECT_EQ (arr[0 ], 0 );
270+ bytes[0 ] = std::byte (1 );
271+ EXPECT_EQ (arr[0 ], 1 );
272+ }
0 commit comments