Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<iterator>: Modernize and deprecate (un)checked_array_iterator #3818

Merged
merged 10 commits into from
Jul 14, 2023
95 changes: 71 additions & 24 deletions stl/inc/iterator
Original file line number Diff line number Diff line change
Expand Up @@ -1467,27 +1467,39 @@ struct iterator_traits<counted_iterator<_Iter>> : iterator_traits<_Iter> {
_STD_END

_STDEXT_BEGIN
using _STD iterator_traits;
using _STD size_t;

template <class _Ptr>
class checked_array_iterator { // wrap a pointer with checking
static_assert(_STD is_pointer_v<_Ptr>, "checked_array_iterator requires pointers");
class _DEPRECATE_STDEXT_ARR_ITERS checked_array_iterator { // wrap a pointer with checking
private:
using _Pointee_type = _STD remove_pointer_t<_Ptr>;
static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>,
"checked_array_iterator requires pointers to objects");

public:
using iterator_category = typename iterator_traits<_Ptr>::iterator_category;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
using value_type = typename iterator_traits<_Ptr>::value_type;
using difference_type = typename iterator_traits<_Ptr>::difference_type;
using pointer = typename iterator_traits<_Ptr>::pointer;
using reference = typename iterator_traits<_Ptr>::reference;
using iterator_category = _STD random_access_iterator_tag;
using value_type = _STD remove_cv_t<_Pointee_type>;
using difference_type = _STD ptrdiff_t;
using pointer = _Ptr;
using reference = _Pointee_type&;
#ifdef __cpp_lib_concepts
using iterator_concept = _STD contiguous_iterator_tag;
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
#endif // __cpp_lib_concepts

constexpr checked_array_iterator() noexcept : _Myarray(nullptr), _Mysize(0), _Myindex(0) {}
constexpr checked_array_iterator() = default;

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

_STL_DISABLE_DEPRECATED_WARNING
template <class _Ty = _Pointee_type, _STD enable_if_t<!_STD is_const_v<_Ty>, int> = 0>
constexpr operator checked_array_iterator<const _Ty*>() const noexcept {
return checked_array_iterator<const _Ty*>{_Myarray, _Mysize, _Myindex};
}
_STL_RESTORE_DEPRECATED_WARNING

_NODISCARD constexpr _Ptr base() const noexcept {
return _Myarray + _Myindex;
}
Expand Down Expand Up @@ -1658,32 +1670,47 @@ public:
}

private:
_Ptr _Myarray; // beginning of array
size_t _Mysize; // size of array
size_t _Myindex; // offset into array
_Ptr _Myarray = nullptr; // beginning of array
size_t _Mysize = 0; // size of array
size_t _Myindex = 0; // offset into array
};

_STL_DISABLE_DEPRECATED_WARNING
template <class _Ptr>
_NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator(
const _Ptr _Array, const size_t _Size, const size_t _Index = 0) {
_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator(
const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept {
return checked_array_iterator<_Ptr>(_Array, _Size, _Index);
}
_STL_RESTORE_DEPRECATED_WARNING

template <class _Ptr>
class unchecked_array_iterator { // wrap a pointer without checking, to silence warnings
static_assert(_STD is_pointer_v<_Ptr>, "unchecked_array_iterator requires pointers");
class _DEPRECATE_STDEXT_ARR_ITERS unchecked_array_iterator { // wrap a pointer without checking, to silence warnings
private:
using _Pointee_type = _STD remove_pointer_t<_Ptr>;
static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>,
"unchecked_array_iterator requires pointers to objects");

public:
using iterator_category = typename iterator_traits<_Ptr>::iterator_category;
using value_type = typename iterator_traits<_Ptr>::value_type;
using difference_type = typename iterator_traits<_Ptr>::difference_type;
using pointer = typename iterator_traits<_Ptr>::pointer;
using reference = typename iterator_traits<_Ptr>::reference;
using iterator_category = _STD random_access_iterator_tag;
using value_type = _STD remove_cv_t<_Pointee_type>;
using difference_type = _STD ptrdiff_t;
using pointer = _Ptr;
using reference = _Pointee_type&;
#ifdef __cpp_lib_concepts
using iterator_concept = _STD contiguous_iterator_tag;
#endif // __cpp_lib_concepts

constexpr unchecked_array_iterator() noexcept : _Myptr(nullptr) {}
constexpr unchecked_array_iterator() = default;

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

_STL_DISABLE_DEPRECATED_WARNING
template <class _Ty = _Pointee_type, _STD enable_if_t<!_STD is_const_v<_Ty>, int> = 0>
constexpr operator unchecked_array_iterator<const _Ty*>() const noexcept {
return unchecked_array_iterator<const _Ty*>{_Myptr};
}
_STL_RESTORE_DEPRECATED_WARNING

_NODISCARD constexpr _Ptr base() const noexcept {
return _Myptr;
}
Expand Down Expand Up @@ -1802,15 +1829,35 @@ public:
}

private:
_Ptr _Myptr; // underlying pointer
_Ptr _Myptr = nullptr; // underlying pointer
};

_STL_DISABLE_DEPRECATED_WARNING
template <class _Ptr>
_NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator(const _Ptr _It) noexcept {
_DEPRECATE_STDEXT_ARR_ITERS _NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator(
const _Ptr _It) noexcept {
return unchecked_array_iterator<_Ptr>(_It);
}
_STL_RESTORE_DEPRECATED_WARNING
_STDEXT_END

#if _HAS_CXX20
_STD_BEGIN
_STL_DISABLE_DEPRECATED_WARNING
template <class _Ty>
struct pointer_traits<_STDEXT checked_array_iterator<_Ty*>> {
using pointer = _STDEXT checked_array_iterator<_Ty*>;
using element_type = _Ty;
using difference_type = ptrdiff_t;

_NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept {
return _Iter._Unwrapped();
}
};
_STL_RESTORE_DEPRECATED_WARNING
_STD_END
#endif // _HAS_CXX20

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
Expand Down
14 changes: 13 additions & 1 deletion stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,19 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
#define _CXX23_DEPRECATE_DENORM
#endif // ^^^ warning disabled ^^^

// next warning number: STL4043
#if _HAS_CXX17 && !defined(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) \
&& !defined(_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS)
#define _DEPRECATE_STDEXT_ARR_ITERS \
[[deprecated( \
"warning STL4043: stdext::checked_array_iterator, stdext::unchecked_array_iterator, and related factory " \
"functions are non-Standard extensions and will be removed in the future. std::span (since C++20) " \
"and gsl::span can be used instead. You can define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING or " \
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to suppress this warning.")]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is debatable whether this should be controlled by the coarse-grained _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS as this is a Microsoft deprecation, not an ISO deprecation. On the other hand, guarding this with _HAS_CXX17 will significantly limit the impact on legacy code (which is good). I suppose I am fine with this; the precedent doesn't even really matter since we are running out of unwise Microsoft extensions to deprecate.

#else // ^^^ warning enabled / warning disabled vvv
#define _DEPRECATE_STDEXT_ARR_ITERS
#endif // ^^^ warning disabled ^^^

// next warning number: STL4044

// next error number: STL1006

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS

#include <array>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,74 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template <class T>
void check_checked_array_iterator_category_and_convertibility() {
STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::iterator_category,
std::random_access_iterator_tag>);

STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::value_type, std::remove_cv_t<T>>);

STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::difference_type, std::ptrdiff_t>);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::pointer, T*>);

STATIC_ASSERT(std::is_same_v<typename stdext::checked_array_iterator<T*>::reference, T&>);

STATIC_ASSERT(std::is_convertible_v<stdext::checked_array_iterator<T*>, stdext::checked_array_iterator<const T*>>);

#ifdef __cpp_lib_concepts
STATIC_ASSERT(
std::is_same_v<typename stdext::checked_array_iterator<T*>::iterator_concept, std::contiguous_iterator_tag>);

STATIC_ASSERT(std::contiguous_iterator<stdext::checked_array_iterator<T*>>);
#endif // __cpp_lib_concepts
}

template <class T>
void check_unchecked_array_iterator_category_and_convertibility() {
STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::iterator_category,
std::random_access_iterator_tag>);

STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::value_type, std::remove_cv_t<T>>);

STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::difference_type, std::ptrdiff_t>);

STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::pointer, T*>);

STATIC_ASSERT(std::is_same_v<typename stdext::unchecked_array_iterator<T*>::reference, T&>);

STATIC_ASSERT(
std::is_convertible_v<stdext::unchecked_array_iterator<T*>, stdext::unchecked_array_iterator<const T*>>);

#ifdef __cpp_lib_concepts
STATIC_ASSERT(
std::is_same_v<typename stdext::unchecked_array_iterator<T*>::iterator_concept, std::contiguous_iterator_tag>);

STATIC_ASSERT(std::contiguous_iterator<stdext::unchecked_array_iterator<T*>>);
#endif // __cpp_lib_concepts
}

int main() {
{
check_checked_array_iterator_category_and_convertibility<int>();
check_checked_array_iterator_category_and_convertibility<const int>();
check_checked_array_iterator_category_and_convertibility<std::tuple<const char*>>();
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved


int* const p = new int[9];

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

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

static_assert(std::is_same_v<decltype(cat), stdext::checked_array_iterator<int*>>,
"stdext::make_checked_array_iterator(p, 9)'s return type is wrong!");


auto dog = stdext::make_checked_array_iterator(p, 9, 3);

static_assert(std::is_same_v<decltype(dog), stdext::checked_array_iterator<int*>>,
"stdext::make_checked_array_iterator(p, 9, 3)'s return type is wrong!");

STATIC_ASSERT(std::is_same_v<decltype(cat), stdext::checked_array_iterator<int*>>);

static_assert(
std::is_same_v<stdext::checked_array_iterator<int*>::iterator_category, std::random_access_iterator_tag>,
"stdext::checked_array_iterator<int *>::iterator_category is wrong!");
#if _HAS_CXX20
assert(std::to_address(cat) == &*cat);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
assert(std::to_address(cat + 8) == &*cat + 8);
assert(std::to_address(cat + 8) == std::to_address(cat) + 8);
assert(std::to_address(cat + 9) == std::to_address(cat) + 9);
#endif // _HAS_CXX20

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

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

static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::pointer, int*>,
"stdext::checked_array_iterator<int *>::pointer is wrong!");
STATIC_ASSERT(std::is_same_v<decltype(dog), stdext::checked_array_iterator<int*>>);

static_assert(std::is_same_v<stdext::checked_array_iterator<int*>::reference, int&>,
"stdext::checked_array_iterator<int *>::reference is wrong!");
#if _HAS_CXX20
assert(std::to_address(dog) == &*dog);
assert(std::to_address(dog + 5) == &*dog + 5);
assert(std::to_address(dog + 5) == std::to_address(dog) + 5);
assert(std::to_address(dog - 3) == &*dog - 3);
assert(std::to_address(dog - 3) == std::to_address(dog) - 3);
assert(std::to_address(dog + 6) == std::to_address(dog) + 6);
#endif // _HAS_CXX20


{
Expand Down Expand Up @@ -184,6 +240,11 @@ int main() {
}

{
check_unchecked_array_iterator_category_and_convertibility<int>();
check_unchecked_array_iterator_category_and_convertibility<const int>();
check_unchecked_array_iterator_category_and_convertibility<std::tuple<const char*>>();


int* const p = new int[9];

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

auto cat = stdext::make_unchecked_array_iterator(p);

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

#if _HAS_CXX20
assert(std::to_address(cat) == &*cat);
assert(std::to_address(cat + 8) == &*cat + 8);
assert(std::to_address(cat + 8) == std::to_address(cat) + 8);
assert(std::to_address(cat + 9) == std::to_address(cat) + 9);
#endif // _HAS_CXX20

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

static_assert(std::is_same_v<decltype(dog), stdext::unchecked_array_iterator<int*>>,
"stdext::make_unchecked_array_iterator(p + 3)'s return type is wrong!");

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

static_assert(
std::is_same_v<stdext::unchecked_array_iterator<int*>::iterator_category, std::random_access_iterator_tag>,
"stdext::unchecked_array_iterator<int *>::iterator_category is wrong!");

static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::value_type, int>,
"stdext::unchecked_array_iterator<int *>::value_type is wrong!");

static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::difference_type, ptrdiff_t>,
"stdext::unchecked_array_iterator<int *>::difference_type is wrong!");

static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::pointer, int*>,
"stdext::unchecked_array_iterator<int *>::pointer is wrong!");
STATIC_ASSERT(std::is_same_v<decltype(dog), stdext::unchecked_array_iterator<int*>>);

static_assert(std::is_same_v<stdext::unchecked_array_iterator<int*>::reference, int&>,
"stdext::unchecked_array_iterator<int *>::reference is wrong!");
#if _HAS_CXX20
assert(std::to_address(dog) == &*dog);
assert(std::to_address(dog + 5) == &*dog + 5);
assert(std::to_address(dog + 5) == std::to_address(dog) + 5);
assert(std::to_address(dog - 3) == &*dog - 3);
assert(std::to_address(dog - 3) == std::to_address(dog) - 3);
assert(std::to_address(dog + 6) == std::to_address(dog) + 6);
#endif // _HAS_CXX20


{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING

#include <array>
#include <cstddef>
#include <deque>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define _SILENCE_CXX23_ALIGNED_UNION_DEPRECATION_WARNING
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING

#include <array>
#include <cassert>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING

#include <algorithm>
#include <cassert>
#include <iterator>
Expand Down
2 changes: 2 additions & 0 deletions tests/std/tests/P1614R2_spaceship/test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING

#include <array>
#include <cassert>
#include <charconv>
Expand Down
Loading