Skip to content

Commit 90dcf26

Browse files
<iterator>: Modernize and deprecate (un)checked_array_iterator (#3818)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 23a5a53 commit 90dcf26

File tree

10 files changed

+193
-65
lines changed

10 files changed

+193
-65
lines changed

stl/inc/iterator

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,27 +1467,39 @@ struct iterator_traits<counted_iterator<_Iter>> : iterator_traits<_Iter> {
14671467
_STD_END
14681468

14691469
_STDEXT_BEGIN
1470-
using _STD iterator_traits;
14711470
using _STD size_t;
14721471

14731472
template <class _Ptr>
1474-
class checked_array_iterator { // wrap a pointer with checking
1475-
static_assert(_STD is_pointer_v<_Ptr>, "checked_array_iterator requires pointers");
1473+
class _DEPRECATE_STDEXT_ARR_ITERS checked_array_iterator { // wrap a pointer with checking
1474+
private:
1475+
using _Pointee_type = _STD remove_pointer_t<_Ptr>;
1476+
static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>,
1477+
"checked_array_iterator requires pointers to objects");
14761478

14771479
public:
1478-
using iterator_category = typename iterator_traits<_Ptr>::iterator_category;
1479-
using value_type = typename iterator_traits<_Ptr>::value_type;
1480-
using difference_type = typename iterator_traits<_Ptr>::difference_type;
1481-
using pointer = typename iterator_traits<_Ptr>::pointer;
1482-
using reference = typename iterator_traits<_Ptr>::reference;
1480+
using iterator_category = _STD random_access_iterator_tag;
1481+
using value_type = _STD remove_cv_t<_Pointee_type>;
1482+
using difference_type = _STD ptrdiff_t;
1483+
using pointer = _Ptr;
1484+
using reference = _Pointee_type&;
1485+
#ifdef __cpp_lib_concepts
1486+
using iterator_concept = _STD contiguous_iterator_tag;
1487+
#endif // __cpp_lib_concepts
14831488

1484-
constexpr checked_array_iterator() noexcept : _Myarray(nullptr), _Mysize(0), _Myindex(0) {}
1489+
constexpr checked_array_iterator() = default;
14851490

14861491
constexpr checked_array_iterator(const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept
14871492
: _Myarray(_Array), _Mysize(_Size), _Myindex(_Index) {
14881493
_STL_VERIFY(_Index <= _Size, "checked_array_iterator construction index out of range");
14891494
}
14901495

1496+
_STL_DISABLE_DEPRECATED_WARNING
1497+
template <class _Ty = _Pointee_type, _STD enable_if_t<!_STD is_const_v<_Ty>, int> = 0>
1498+
constexpr operator checked_array_iterator<const _Ty*>() const noexcept {
1499+
return checked_array_iterator<const _Ty*>{_Myarray, _Mysize, _Myindex};
1500+
}
1501+
_STL_RESTORE_DEPRECATED_WARNING
1502+
14911503
_NODISCARD constexpr _Ptr base() const noexcept {
14921504
return _Myarray + _Myindex;
14931505
}
@@ -1658,32 +1670,47 @@ public:
16581670
}
16591671

16601672
private:
1661-
_Ptr _Myarray; // beginning of array
1662-
size_t _Mysize; // size of array
1663-
size_t _Myindex; // offset into array
1673+
_Ptr _Myarray = nullptr; // beginning of array
1674+
size_t _Mysize = 0; // size of array
1675+
size_t _Myindex = 0; // offset into array
16641676
};
16651677

1678+
_STL_DISABLE_DEPRECATED_WARNING
16661679
template <class _Ptr>
1667-
_NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator(
1668-
const _Ptr _Array, const size_t _Size, const size_t _Index = 0) {
1680+
_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator(
1681+
const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept {
16691682
return checked_array_iterator<_Ptr>(_Array, _Size, _Index);
16701683
}
1684+
_STL_RESTORE_DEPRECATED_WARNING
16711685

16721686
template <class _Ptr>
1673-
class unchecked_array_iterator { // wrap a pointer without checking, to silence warnings
1674-
static_assert(_STD is_pointer_v<_Ptr>, "unchecked_array_iterator requires pointers");
1687+
class _DEPRECATE_STDEXT_ARR_ITERS unchecked_array_iterator { // wrap a pointer without checking, to silence warnings
1688+
private:
1689+
using _Pointee_type = _STD remove_pointer_t<_Ptr>;
1690+
static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>,
1691+
"unchecked_array_iterator requires pointers to objects");
16751692

16761693
public:
1677-
using iterator_category = typename iterator_traits<_Ptr>::iterator_category;
1678-
using value_type = typename iterator_traits<_Ptr>::value_type;
1679-
using difference_type = typename iterator_traits<_Ptr>::difference_type;
1680-
using pointer = typename iterator_traits<_Ptr>::pointer;
1681-
using reference = typename iterator_traits<_Ptr>::reference;
1694+
using iterator_category = _STD random_access_iterator_tag;
1695+
using value_type = _STD remove_cv_t<_Pointee_type>;
1696+
using difference_type = _STD ptrdiff_t;
1697+
using pointer = _Ptr;
1698+
using reference = _Pointee_type&;
1699+
#ifdef __cpp_lib_concepts
1700+
using iterator_concept = _STD contiguous_iterator_tag;
1701+
#endif // __cpp_lib_concepts
16821702

1683-
constexpr unchecked_array_iterator() noexcept : _Myptr(nullptr) {}
1703+
constexpr unchecked_array_iterator() = default;
16841704

16851705
constexpr explicit unchecked_array_iterator(const _Ptr _Src) noexcept : _Myptr(_Src) {}
16861706

1707+
_STL_DISABLE_DEPRECATED_WARNING
1708+
template <class _Ty = _Pointee_type, _STD enable_if_t<!_STD is_const_v<_Ty>, int> = 0>
1709+
constexpr operator unchecked_array_iterator<const _Ty*>() const noexcept {
1710+
return unchecked_array_iterator<const _Ty*>{_Myptr};
1711+
}
1712+
_STL_RESTORE_DEPRECATED_WARNING
1713+
16871714
_NODISCARD constexpr _Ptr base() const noexcept {
16881715
return _Myptr;
16891716
}
@@ -1802,15 +1829,35 @@ public:
18021829
}
18031830

18041831
private:
1805-
_Ptr _Myptr; // underlying pointer
1832+
_Ptr _Myptr = nullptr; // underlying pointer
18061833
};
18071834

1835+
_STL_DISABLE_DEPRECATED_WARNING
18081836
template <class _Ptr>
1809-
_NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator(const _Ptr _It) noexcept {
1837+
_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator(
1838+
const _Ptr _It) noexcept {
18101839
return unchecked_array_iterator<_Ptr>(_It);
18111840
}
1841+
_STL_RESTORE_DEPRECATED_WARNING
18121842
_STDEXT_END
18131843

1844+
#if _HAS_CXX20
1845+
_STD_BEGIN
1846+
_STL_DISABLE_DEPRECATED_WARNING
1847+
template <class _Ty>
1848+
struct pointer_traits<_STDEXT checked_array_iterator<_Ty*>> {
1849+
using pointer = _STDEXT checked_array_iterator<_Ty*>;
1850+
using element_type = _Ty;
1851+
using difference_type = ptrdiff_t;
1852+
1853+
_NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept {
1854+
return _Iter._Unwrapped();
1855+
}
1856+
};
1857+
_STL_RESTORE_DEPRECATED_WARNING
1858+
_STD_END
1859+
#endif // _HAS_CXX20
1860+
18141861
#pragma pop_macro("new")
18151862
_STL_RESTORE_CLANG_WARNINGS
18161863
#pragma warning(pop)

stl/inc/yvals_core.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1445,7 +1445,19 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
14451445
#define _CXX23_DEPRECATE_DENORM
14461446
#endif // ^^^ warning disabled ^^^
14471447

1448-
// next warning number: STL4043
1448+
#if _HAS_CXX17 && !defined(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) \
1449+
&& !defined(_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS)
1450+
#define _DEPRECATE_STDEXT_ARR_ITERS \
1451+
[[deprecated( \
1452+
"warning STL4043: stdext::checked_array_iterator, stdext::unchecked_array_iterator, and related factory " \
1453+
"functions are non-Standard extensions and will be removed in the future. std::span (since C++20) " \
1454+
"and gsl::span can be used instead. You can define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING or " \
1455+
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to suppress this warning.")]]
1456+
#else // ^^^ warning enabled / warning disabled vvv
1457+
#define _DEPRECATE_STDEXT_ARR_ITERS
1458+
#endif // ^^^ warning disabled ^^^
1459+
1460+
// next warning number: STL4044
14491461

14501462
// next error number: STL1006
14511463

tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
45
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
56

67
#include <array>

tests/std/tests/Dev10_709166_checked_and_unchecked_array_iterator/test.cpp

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,74 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
5+
46
#include <algorithm>
57
#include <cassert>
8+
#include <cstddef>
69
#include <iterator>
10+
#include <memory>
11+
#include <tuple>
712
#include <type_traits>
813
#include <utility>
914
#include <vector>
1015

16+
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
17+
18+
template <class T>
19+
void check_checked_array_iterator_category_and_convertibility() {
20+
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::iterator_category,
21+
std::random_access_iterator_tag>);
22+
23+
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::value_type, std::remove_cv_t<T>>);
24+
25+
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::difference_type, std::ptrdiff_t>);
26+
27+
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::pointer, T*>);
28+
29+
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::reference, T&>);
30+
31+
STATIC_ASSERT(std::is_convertible_v<stdext::checked_array_iterator<T*>, stdext::checked_array_iterator<const T*>>);
32+
33+
#ifdef __cpp_lib_concepts
34+
STATIC_ASSERT(
35+
std::is_same_v<typename stdext::checked_array_iterator<T*>::iterator_concept, std::contiguous_iterator_tag>);
36+
37+
STATIC_ASSERT(std::contiguous_iterator<stdext::checked_array_iterator<T*>>);
38+
#endif // __cpp_lib_concepts
39+
}
40+
41+
template <class T>
42+
void check_unchecked_array_iterator_category_and_convertibility() {
43+
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::iterator_category,
44+
std::random_access_iterator_tag>);
45+
46+
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::value_type, std::remove_cv_t<T>>);
47+
48+
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::difference_type, std::ptrdiff_t>);
49+
50+
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::pointer, T*>);
51+
52+
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::reference, T&>);
53+
54+
STATIC_ASSERT(
55+
std::is_convertible_v<stdext::unchecked_array_iterator<T*>, stdext::unchecked_array_iterator<const T*>>);
56+
57+
#ifdef __cpp_lib_concepts
58+
STATIC_ASSERT(
59+
std::is_same_v<typename stdext::unchecked_array_iterator<T*>::iterator_concept, std::contiguous_iterator_tag>);
60+
61+
STATIC_ASSERT(std::contiguous_iterator<stdext::unchecked_array_iterator<T*>>);
62+
#endif // __cpp_lib_concepts
63+
}
64+
1165
int main() {
1266
{
67+
check_checked_array_iterator_category_and_convertibility<int>();
68+
check_checked_array_iterator_category_and_convertibility<const int>();
69+
check_checked_array_iterator_category_and_convertibility<std::tuple<const char*>>();
70+
71+
1372
int* const p = new int[9];
1473

1574
for (int i = 0; i < 9; ++i) {
@@ -19,31 +78,28 @@ int main() {
1978

2079
auto cat = stdext::make_checked_array_iterator(p, 9);
2180

22-
static_assert(std::is_same_v<decltype(cat), stdext::checked_array_iterator<int*>>,
23-
"stdext::make_checked_array_iterator(p, 9)'s return type is wrong!");
24-
25-
26-
auto dog = stdext::make_checked_array_iterator(p, 9, 3);
27-
28-
static_assert(std::is_same_v<decltype(dog), stdext::checked_array_iterator<int*>>,
29-
"stdext::make_checked_array_iterator(p, 9, 3)'s return type is wrong!");
30-
81+
STATIC_ASSERT(std::is_same_v<decltype(cat), stdext::checked_array_iterator<int*>>);
3182

32-
static_assert(
33-
std::is_same_v<stdext::checked_array_iterator<int*>::iterator_category, std::random_access_iterator_tag>,
34-
"stdext::checked_array_iterator<int *>::iterator_category is wrong!");
83+
#if _HAS_CXX20
84+
assert(std::to_address(cat) == &*cat);
85+
assert(std::to_address(cat + 8) == &*cat + 8);
86+
assert(std::to_address(cat + 8) == std::to_address(cat) + 8);
87+
assert(std::to_address(cat + 9) == std::to_address(cat) + 9);
88+
#endif // _HAS_CXX20
3589

36-
static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::value_type, int>,
37-
"stdext::checked_array_iterator<int *>::value_type is wrong!");
3890

39-
static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::difference_type, ptrdiff_t>,
40-
"stdext::checked_array_iterator<int *>::difference_type is wrong!");
91+
auto dog = stdext::make_checked_array_iterator(p, 9, 3);
4192

42-
static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::pointer, int*>,
43-
"stdext::checked_array_iterator<int *>::pointer is wrong!");
93+
STATIC_ASSERT(std::is_same_v<decltype(dog), stdext::checked_array_iterator<int*>>);
4494

45-
static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::reference, int&>,
46-
"stdext::checked_array_iterator<int *>::reference is wrong!");
95+
#if _HAS_CXX20
96+
assert(std::to_address(dog) == &*dog);
97+
assert(std::to_address(dog + 5) == &*dog + 5);
98+
assert(std::to_address(dog + 5) == std::to_address(dog) + 5);
99+
assert(std::to_address(dog - 3) == &*dog - 3);
100+
assert(std::to_address(dog - 3) == std::to_address(dog) - 3);
101+
assert(std::to_address(dog + 6) == std::to_address(dog) + 6);
102+
#endif // _HAS_CXX20
47103

48104

49105
{
@@ -184,6 +240,11 @@ int main() {
184240
}
185241

186242
{
243+
check_unchecked_array_iterator_category_and_convertibility<int>();
244+
check_unchecked_array_iterator_category_and_convertibility<const int>();
245+
check_unchecked_array_iterator_category_and_convertibility<std::tuple<const char*>>();
246+
247+
187248
int* const p = new int[9];
188249

189250
for (int i = 0; i < 9; ++i) {
@@ -193,31 +254,28 @@ int main() {
193254

194255
auto cat = stdext::make_unchecked_array_iterator(p);
195256

196-
static_assert(std::is_same_v<decltype(cat), stdext::unchecked_array_iterator<int*>>,
197-
"stdext::make_unchecked_array_iterator(p)'s return type is wrong!");
257+
STATIC_ASSERT(std::is_same_v<decltype(cat), stdext::unchecked_array_iterator<int*>>);
198258

259+
#if _HAS_CXX20
260+
assert(std::to_address(cat) == &*cat);
261+
assert(std::to_address(cat + 8) == &*cat + 8);
262+
assert(std::to_address(cat + 8) == std::to_address(cat) + 8);
263+
assert(std::to_address(cat + 9) == std::to_address(cat) + 9);
264+
#endif // _HAS_CXX20
199265

200-
auto dog = stdext::make_unchecked_array_iterator(p + 3);
201-
202-
static_assert(std::is_same_v<decltype(dog), stdext::unchecked_array_iterator<int*>>,
203-
"stdext::make_unchecked_array_iterator(p + 3)'s return type is wrong!");
204266

267+
auto dog = stdext::make_unchecked_array_iterator(p + 3);
205268

206-
static_assert(
207-
std::is_same_v<stdext::unchecked_array_iterator<int*>::iterator_category, std::random_access_iterator_tag>,
208-
"stdext::unchecked_array_iterator<int *>::iterator_category is wrong!");
209-
210-
static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::value_type, int>,
211-
"stdext::unchecked_array_iterator<int *>::value_type is wrong!");
212-
213-
static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::difference_type, ptrdiff_t>,
214-
"stdext::unchecked_array_iterator<int *>::difference_type is wrong!");
215-
216-
static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::pointer, int*>,
217-
"stdext::unchecked_array_iterator<int *>::pointer is wrong!");
269+
STATIC_ASSERT(std::is_same_v<decltype(dog), stdext::unchecked_array_iterator<int*>>);
218270

219-
static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::reference, int&>,
220-
"stdext::unchecked_array_iterator<int *>::reference is wrong!");
271+
#if _HAS_CXX20
272+
assert(std::to_address(dog) == &*dog);
273+
assert(std::to_address(dog + 5) == &*dog + 5);
274+
assert(std::to_address(dog + 5) == std::to_address(dog) + 5);
275+
assert(std::to_address(dog - 3) == &*dog - 3);
276+
assert(std::to_address(dog - 3) == std::to_address(dog) - 3);
277+
assert(std::to_address(dog + 6) == std::to_address(dog) + 6);
278+
#endif // _HAS_CXX20
221279

222280

223281
{

tests/std/tests/Dev10_709168_marking_iterators_as_checked/test.compile.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
5+
46
#include <array>
57
#include <cstddef>
68
#include <deque>

tests/std/tests/Dev11_0000000_null_forward_iterators/test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#define _SILENCE_CXX23_ALIGNED_UNION_DEPRECATION_WARNING
55
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
6+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
67

78
#include <array>
89
#include <cassert>

tests/std/tests/P0040R3_extending_memory_management_tools/test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
5+
46
#include <algorithm>
57
#include <cassert>
68
#include <iterator>

tests/std/tests/P1614R2_spaceship/test.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
5+
46
#include <array>
57
#include <cassert>
68
#include <charconv>

0 commit comments

Comments
 (0)