Co-authored-by: S. B. Tam <cpplearner@outlook.com>
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
Co-authored-by: Casey Carter <Casey@Carter.net>
This commit is contained in:
Michael Schellenberger Costa 2020-08-14 23:27:53 +02:00 коммит произвёл GitHub
Родитель 87dc1d3383
Коммит 1e42166b78
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 1024 добавлений и 1 удалений

Просмотреть файл

@ -511,6 +511,311 @@ private:
bool _Failed; // true if any stores have failed
streambuf_type* _Strbuf; // the wrapped stream buffer
};
#ifdef __cpp_lib_concepts
// CLASS TEMPLATE counted_iterator
template <input_or_output_iterator _Iter>
class counted_iterator {
public:
using iterator_type = _Iter;
// [counted.iter.const]
constexpr counted_iterator() = default;
constexpr counted_iterator(_Iter _Right, const iter_difference_t<_Iter> _Diff) noexcept(
is_nothrow_move_constructible_v<_Iter>) // strengthened
: _Current(_STD move(_Right)), _Length(_Diff) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Diff >= 0, "counted_iterator requires non-negative length n");
#endif // _ITERATOR_DEBUG_LEVEL != 0
}
// clang-format off
template <class _Other>
requires convertible_to<const _Other&, _Iter>
constexpr counted_iterator(const counted_iterator<_Other>& _Right) noexcept(
is_nothrow_constructible_v<_Iter, const _Other&>) // strengthened
: _Current(_Right._Current), _Length(_Right._Length) {}
template <class _Other>
requires assignable_from<_Iter&, const _Other&>
constexpr counted_iterator& operator=(const counted_iterator<_Other>& _Right) noexcept(
is_nothrow_assignable_v<_Iter&, const _Other&>) /* strengthened */ {
// clang-format on
_Current = _Right._Current;
_Length = _Right._Length;
return *this;
}
// [counted.iter.access]
_NODISCARD constexpr _Iter base() const& noexcept(is_nothrow_copy_constructible_v<_Iter>) /* strengthened */
requires copy_constructible<_Iter> {
return _Current;
}
_NODISCARD constexpr _Iter base() && noexcept(is_nothrow_move_constructible_v<_Iter>) /* strengthened */ {
return _STD move(_Current);
}
_NODISCARD constexpr iter_difference_t<_Iter> count() const noexcept {
return _Length;
}
// [counted.iter.elem]
_NODISCARD constexpr decltype(auto) operator*() noexcept(noexcept(*_Current)) /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per proposed resolution of LWG-3472
_STL_VERIFY(_Length > 0, "counted_iterator dereference beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Current;
}
_NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(*_Current)) /* strengthened */
requires _Dereferenceable<const _Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
// Per proposed resolution of LWG-3472
_STL_VERIFY(_Length > 0, "counted_iterator dereference beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Current;
}
_NODISCARD constexpr decltype(auto) operator[](const iter_difference_t<_Iter> _Diff) const
requires random_access_iterator<_Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Diff < _Length, "counted_iterator index out of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Current[_Diff];
}
// [counted.iter.nav]
constexpr counted_iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
++_Current;
--_Length;
return *this;
}
constexpr decltype(auto) operator++(int) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
--_Length;
_TRY_BEGIN
return _Current++;
_CATCH_ALL
++_Length;
_RERAISE;
_CATCH_END
}
constexpr counted_iterator operator++(int) requires forward_iterator<_Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
counted_iterator _Tmp = *this;
++_Current;
--_Length;
return _Tmp;
}
constexpr counted_iterator& operator--() requires bidirectional_iterator<_Iter> {
--_Current;
++_Length;
return *this;
}
constexpr counted_iterator operator--(int) requires bidirectional_iterator<_Iter> {
counted_iterator _Tmp = *this;
--_Current;
++_Length;
return _Tmp;
}
_NODISCARD constexpr counted_iterator operator+(const iter_difference_t<_Iter> _Diff) const
requires random_access_iterator<_Iter> {
return counted_iterator{_Current + _Diff, static_cast<iter_difference_t<_Iter>>(_Length - _Diff)};
}
_NODISCARD friend constexpr counted_iterator operator+(
const iter_difference_t<_Iter> _Diff, const counted_iterator& _Right) requires random_access_iterator<_Iter> {
return counted_iterator{_Right._Current + _Diff, static_cast<iter_difference_t<_Iter>>(_Right._Length - _Diff)};
}
constexpr counted_iterator& operator+=(
const iter_difference_t<_Iter> _Diff) requires random_access_iterator<_Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Diff <= _Length, "counted_iterator seek beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current += _Diff;
_Length -= _Diff;
return *this;
}
_NODISCARD constexpr counted_iterator operator-(const iter_difference_t<_Iter> _Diff) const
requires random_access_iterator<_Iter> {
return counted_iterator{_Current - _Diff, static_cast<iter_difference_t<_Iter>>(_Length + _Diff)};
}
template <common_with<_Iter> _Other>
_NODISCARD friend constexpr iter_difference_t<_Other> operator-(
const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_Same_sequence(_Left, _Right);
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Right.count() - _Left._Length;
}
_NODISCARD friend constexpr iter_difference_t<_Iter> operator-(
const counted_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ {
return -_Left._Length;
}
_NODISCARD friend constexpr iter_difference_t<_Iter> operator-(
default_sentinel_t, const counted_iterator& _Right) noexcept /* strengthened */ {
return _Right._Length;
}
constexpr counted_iterator& operator-=(
const iter_difference_t<_Iter> _Diff) requires random_access_iterator<_Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(-_Diff <= _Length, "counted_iterator decrement beyond end of range");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Current -= _Diff;
_Length += _Diff;
return *this;
}
// [counted.iter.cmp]
template <common_with<_Iter> _Other>
_NODISCARD friend constexpr bool operator==(
const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_Same_sequence(_Left, _Right);
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Left._Length == _Right.count();
}
_NODISCARD friend constexpr bool operator==(const counted_iterator& _Left, default_sentinel_t) noexcept
/* strengthened */ {
return _Left._Length == 0;
}
template <common_with<_Iter> _Other>
_NODISCARD friend constexpr strong_ordering operator<=>(
const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ {
#if _ITERATOR_DEBUG_LEVEL != 0
_Same_sequence(_Left, _Right);
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Right.count() <=> _Left._Length;
}
// [counted.iter.cust]
_NODISCARD friend constexpr iter_rvalue_reference_t<_Iter> iter_move(const counted_iterator& _Right) noexcept(
noexcept(_RANGES iter_move(_Right._Current))) requires input_iterator<_Iter> {
return _RANGES iter_move(_Right._Current);
}
template <indirectly_swappable<_Iter> _Other>
friend constexpr void iter_swap(const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept(
noexcept(_RANGES iter_swap(_Left._Current, _Right._Current))) {
_RANGES iter_swap(_Left._Current, _Right._Current);
}
template <common_with<_Iter> _Other>
friend constexpr void _Same_sequence(
const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept {
// Per N4861 [counted.iterator]/2, two counted_iterators x and y refer to elements of the same sequence iff
// next(x.base(), x.count()) and next(y.base(), y.count()) "refer to the same element." Iterator equality is a
// fair proxy for this condition.
if constexpr (forward_iterator<_Iter> && forward_iterator<_Other>) {
using _CIter = common_type_t<_Iter, _Other>;
using _CDiff = common_type_t<iter_difference_t<_Iter>, iter_difference_t<_Other>>;
const _CDiff _Diff = static_cast<_CDiff>(_Left._Length) - static_cast<_CDiff>(_Right.count());
if (_Diff < 0) {
_STL_VERIFY(
static_cast<_CIter>(_Left._Current) == _RANGES next(static_cast<_CIter>(_Right.base()), -_Diff),
"counted_iterators from different ranges");
} else {
_STL_VERIFY(
_RANGES next(static_cast<_CIter>(_Left._Current), _Diff) == static_cast<_CIter>(_Right.base()),
"counted_iterators from different ranges");
}
}
}
template <common_with<_Iter> _Other>
friend constexpr void _Verify_range(const counted_iterator& _Left, const counted_iterator<_Other>& _Right) {
if constexpr (_Range_verifiable_v<_Iter, _Other>) {
_Verify_range(_Left._Current, _Right._Current);
}
#if _ITERATOR_DEBUG_LEVEL != 0
_Same_sequence(_Left, _Right);
#endif // _ITERATOR_DEBUG_LEVEL != 0
}
constexpr void _Verify_offset(const iter_difference_t<_Iter> _Off) const {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off <= _Length, "Offset larger than counted_iterator length");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (_Offset_verifiable_v<_Iter>) {
_Current._Verify_offset(_Off);
}
}
using _Prevent_inheriting_unwrap = counted_iterator;
_NODISCARD constexpr counted_iterator<_Unwrapped_t<const _Iter&>>
_Unwrapped() const& requires _Unwrappable_v<const _Iter&> {
return static_cast<counted_iterator<_Unwrapped_t<const _Iter&>>>(_Current._Unwrapped());
}
_NODISCARD constexpr counted_iterator<_Unwrapped_t<_Iter>> _Unwrapped() && requires _Unwrappable_v<const _Iter&> {
return static_cast<counted_iterator<_Unwrapped_t<_Iter>>>(_STD move(_Current)._Unwrapped());
}
static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<_Iter>;
// clang-format off
template <class _Other>
requires _Wrapped_seekable_v<_Iter, const _Other&>
constexpr void _Seek_to(const counted_iterator<_Other>& _It) {
// clang-format on
_Current._Seek_to(_It._Current);
_Length = _It._Length;
}
// clang-format off
template <class _Other>
requires _Wrapped_seekable_v<_Iter, _Other>
constexpr void _Seek_to(counted_iterator<_Other>&& _It) {
// clang-format on
_Current._Seek_to(_STD move(_It)._Current);
_Length = _It._Length;
}
private:
template <input_or_output_iterator>
friend class counted_iterator;
_Iter _Current{};
iter_difference_t<_Iter> _Length = 0;
};
template <class _Iter>
struct incrementable_traits<counted_iterator<_Iter>> {
using difference_type = iter_difference_t<_Iter>;
};
template <input_iterator _Iter>
struct iterator_traits<counted_iterator<_Iter>> : iterator_traits<_Iter> {
using pointer = void;
};
#endif // __cpp_lib_concepts
_STD_END
_STDEXT_BEGIN

Просмотреть файл

@ -340,8 +340,9 @@ namespace test {
static constexpr bool at_least = derived_from<Category, T>;
using ReferenceType = conditional_t<to_bool(Proxy), proxy_reference<Category, Element>, Element&>;
public:
using Consterator = iterator<Category, const Element, Diff, Eq, Proxy, Wrapped>;
// output iterator operations
iterator() = default;
@ -353,6 +354,10 @@ namespace test {
return *this;
}
constexpr operator Consterator() && noexcept {
return Consterator{exchange(ptr_, nullptr)};
}
[[nodiscard]] constexpr Element* peek() const noexcept {
return ptr_;
}
@ -426,6 +431,12 @@ namespace test {
// sentinel operations (implied by forward iterator):
iterator(iterator const&) requires (to_bool(Eq)) = default;
iterator& operator=(iterator const&) requires (to_bool(Eq)) = default;
constexpr operator Consterator() const& noexcept
requires (to_bool(Eq)) {
return Consterator{ptr_};
}
[[nodiscard]] constexpr boolish operator==(iterator const& that) const noexcept requires (to_bool(Eq)) {
return {ptr_ == that.ptr_};
}

Просмотреть файл

@ -240,6 +240,8 @@ tests\P0768R1_spaceship_operator
tests\P0769R2_shift_left_shift_right
tests\P0784R7_library_support_for_more_constexpr_containers
tests\P0811R3_midpoint_lerp
tests\P0896R4_counted_iterator
tests\P0896R4_counted_iterator_death
tests\P0896R4_P1614R2_comparisons
tests\P0896R4_ranges_alg_adjacent_find
tests\P0896R4_ranges_alg_all_of

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\strict_concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,307 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <concepts>
#include <iterator>
#include <memory>
#include <type_traits>
#include <range_algorithm_support.hpp>
using namespace std;
template <class>
inline constexpr void* must_be_countable = nullptr;
// clang-format off
template <input_or_output_iterator I>
requires requires { typename counted_iterator<I>; }
inline constexpr bool must_be_countable<I> = true;
template <class... Is>
concept Counted = (must_be_countable<Is> && ...);
template <class I1, class I2>
concept CountedCompare = Counted<I1, I2>
&& requires(const counted_iterator<I1>& c1, const counted_iterator<I2>& c2) {
c1 == c2;
c1 != c2;
c1 < c2;
c1 > c2;
c1 <= c2;
c1 >= c2;
c1 <=> c2;
c1 - c2;
c2 == c1;
c2 != c1;
c2 < c1;
c2 > c1;
c2 <= c1;
c2 >= c1;
c2 <=> c1;
c2 - c1;
};
// clang-format on
struct instantiator {
template <input_or_output_iterator Iter>
static constexpr void call() {
using ConstIter = typename Iter::Consterator;
int input[5] = {1, 2, 3, 4, 5};
// [counted.iter.const]
{
[[maybe_unused]] counted_iterator<Iter> defaultConstructed{};
counted_iterator<Iter> constructed(Iter{input}, iter_difference_t<Iter>{2});
counted_iterator<Iter> constructedEmpty{Iter{input}, iter_difference_t<Iter>{0}};
if constexpr (copyable<Iter>) { // counted_iterator only has const lvalue conversions
counted_iterator<ConstIter> constructedConversion{constructed};
constructedConversion = constructedEmpty;
}
}
// [counted.iter.access]
{
if constexpr (copy_constructible<Iter>) {
const counted_iterator<Iter> lvalueBase{Iter{input}, 2};
const same_as<Iter> auto base1 = lvalueBase.base();
assert(base1.peek() == input);
}
const same_as<Iter> auto base2 = counted_iterator<Iter>{Iter{input}, 2}.base();
assert(base2.peek() == input);
const same_as<iter_difference_t<Iter>> auto length = counted_iterator<Iter>{Iter{input}, 2}.count();
assert(length == 2);
}
// [counted.iter.elem]
{
counted_iterator<Iter> iter{Iter{input}, 2};
assert(*iter == 1);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*iter) == input);
}
const counted_iterator<Iter> constIter{Iter{input}, 2};
assert(*constIter == 1);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*constIter) == input);
}
if constexpr (random_access_iterator<Iter>) {
assert(iter[1] == 2);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(iter[1]) == input + 1);
}
}
}
// [counted.iter.nav]
{
{ // pre increment
counted_iterator<Iter> iter{Iter{input}, 2};
assert(addressof(++iter) == addressof(iter));
assert(iter.count() == 1);
assert(*iter == 2);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*iter) == input + 1);
}
}
if constexpr (forward_iterator<Iter>) { // post increment
counted_iterator<Iter> iter{Iter{input}, 2};
auto ref_iter = iter;
auto iter2 = iter++;
assert(iter2 == ref_iter);
assert(iter.count() == 1);
assert(*iter == 2);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*iter) == input + 1);
}
}
if constexpr (bidirectional_iterator<Iter>) {
{
// pre decrement
counted_iterator<Iter> iter{Iter{input + 2}, 3};
assert(addressof(--iter) == addressof(iter));
assert(iter.count() == 4);
assert(*iter == 2);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*iter) == input + 1);
}
}
{ // post decrement
counted_iterator<Iter> iter{Iter{begin(input) + 2}, 3};
auto ref_iter = iter;
auto iter2 = iter--;
assert(iter2 == ref_iter);
assert(iter.count() == 4);
assert(*iter == 2);
if constexpr (is_reference_v<iter_reference_t<Iter>>) {
assert(addressof(*iter) == input + 1);
}
}
}
if constexpr (random_access_iterator<Iter>) {
{ // increment by n lhs
counted_iterator<Iter> iter{Iter{input}, 5};
auto ref_iter = iter + 3;
assert(iter.count() == 5);
assert(*iter == 1);
assert(iter.count() == ref_iter.count() + 3);
assert(iter.base().peek() == prev(ref_iter.base().peek(), 3));
}
{ // increment by n rhs
counted_iterator<Iter> iter{Iter{input}, 5};
auto ref_iter = 3 + iter;
assert(iter.count() == 5);
assert(*iter == 1);
assert(iter.count() == ref_iter.count() + 3);
assert(iter.base().peek() == prev(ref_iter.base().peek(), 3));
}
{ // increment value-initialized by 0
counted_iterator<Iter> iter;
auto ref_iter = 0 + iter;
assert(iter == ref_iter);
}
{ // increment assign
counted_iterator<Iter> iter{Iter{input}, 5};
auto ref_iter = iter;
assert(addressof(iter += 3) == addressof(iter));
assert(iter.count() == 2);
assert(*iter == 4);
assert(iter.count() == ref_iter.count() - 3);
assert(iter.base().peek() == next(ref_iter.base().peek(), 3));
}
{ // decrement by n
counted_iterator<Iter> iter{Iter{begin(input) + 2}, 3};
auto ref_iter = iter - 2;
assert(iter.count() == 3);
assert(*iter == 3);
assert(iter.count() == ref_iter.count() - 2);
assert(iter.base().peek() == next(ref_iter.base().peek(), 2));
}
}
{ // difference
counted_iterator<Iter> iter1{Iter{input + 1}, 2};
counted_iterator<Iter> iter2{Iter{input}, 3};
const same_as<iter_difference_t<Iter>> auto diff1 = iter1 - iter2;
assert(diff1 == 1);
const same_as<iter_difference_t<Iter>> auto diff2 = iter2 - iter1;
assert(diff2 == -1);
}
{ // difference value-initialized
const same_as<iter_difference_t<Iter>> auto diff1 = counted_iterator<Iter>{} - counted_iterator<Iter>{};
assert(diff1 == 0);
}
STATIC_ASSERT(CountedCompare<Iter, ConstIter> == common_with<Iter, ConstIter>);
STATIC_ASSERT(CountedCompare<ConstIter, Iter> == common_with<Iter, ConstIter>);
if constexpr (common_with<Iter, ConstIter>) { // cross-type difference
counted_iterator<Iter> iter1{Iter{input + 1}, 2};
counted_iterator<ConstIter> iter2{ConstIter{input}, 3};
const same_as<iter_difference_t<Iter>> auto diff1 = iter1 - iter2;
assert(diff1 == 1);
const same_as<iter_difference_t<ConstIter>> auto diff2 = iter2 - iter1;
assert(diff2 == -1);
}
{ // difference default sentinel
counted_iterator<Iter> iter1{Iter{input}, 2};
const same_as<iter_difference_t<Iter>> auto diff1 = iter1 - default_sentinel;
assert(diff1 == -2);
const same_as<iter_difference_t<Iter>> auto diff2 = default_sentinel - iter1;
assert(diff2 == 2);
}
if constexpr (random_access_iterator<Iter>) { // decrement assign
counted_iterator<Iter> iter{Iter{end(input)}, 0};
auto ref_iter = iter;
assert(addressof(iter -= 3) == addressof(iter));
assert(iter.count() == 3);
assert(*iter == 3);
assert(iter.count() == ref_iter.count() + 3);
assert(iter.base().peek() == prev(ref_iter.base().peek(), 3));
}
}
// [counted.iter.cmp]
{
{ // equality
counted_iterator<Iter> iter1{Iter{input}, 2};
counted_iterator<Iter> iter2{Iter{input}, 2};
counted_iterator<Iter> iter3{Iter{input + 1}, 1};
assert(iter1 == iter2);
assert(!(iter1 == iter3));
}
{ // inequality
counted_iterator<Iter> iter1{Iter{input + 1}, 2};
counted_iterator<Iter> iter2{Iter{input}, 3};
counted_iterator<Iter> iter3{Iter{input}, 3};
assert(iter1 != iter2);
assert(!(iter2 != iter3));
}
{ // equality default sentinel
counted_iterator<Iter> iter1{Iter{input}, 2};
counted_iterator<Iter> iter2{Iter{input}, 0};
assert(iter1 != default_sentinel);
assert(default_sentinel != iter1);
assert(iter2 == default_sentinel);
assert(default_sentinel == iter2);
}
{ // spaceship
counted_iterator<Iter> iter1{Iter{input}, 2};
counted_iterator<Iter> iter2{Iter{input + 2}, 0};
const same_as<strong_ordering> auto result = iter1 <=> iter2;
assert(result == strong_ordering::less);
assert(iter2 <=> iter1 == strong_ordering::greater);
assert(iter1 <=> iter1 == strong_ordering::equal);
assert(iter1 <=> iter1 == strong_ordering::equivalent);
}
{ // spaceship value-initialized
assert(counted_iterator<Iter>{} <=> counted_iterator<Iter>{} == strong_ordering::equal);
assert(counted_iterator<Iter>{} <=> counted_iterator<Iter>{} == strong_ordering::equivalent);
}
if constexpr (common_with<Iter, ConstIter>) {
{ // equality converting
counted_iterator<ConstIter> const_iter1{ConstIter{input}, 2};
counted_iterator<Iter> iter2{Iter{input}, 2};
counted_iterator<Iter> iter3{Iter{input + 1}, 1};
assert(const_iter1 == iter2);
assert(!(const_iter1 == iter3));
}
{ // inequality converting
counted_iterator<Iter> iter1{Iter{input + 1}, 2};
counted_iterator<ConstIter> const_iter1{ConstIter{input}, 3};
counted_iterator<Iter> iter3{Iter{input}, 3};
assert(iter1 != const_iter1);
assert(!(const_iter1 != iter3));
}
{ // spaceship converting
counted_iterator<Iter> iter{Iter{input}, 2};
counted_iterator<ConstIter> const_iter{ConstIter{input + 2}, 0};
const same_as<strong_ordering> auto result = iter <=> const_iter;
assert(result == strong_ordering::less);
assert(const_iter <=> iter == strong_ordering::greater);
assert(iter <=> iter == strong_ordering::equal);
assert(iter <=> iter == strong_ordering::equivalent);
}
}
}
}
};
int main() {
STATIC_ASSERT((with_writable_iterators<instantiator, int>::call(), true));
with_writable_iterators<instantiator, int>::call();
}

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\strict_winsdk_concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,249 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#define _CONTAINER_DEBUG_LEVEL 1
#include <cassert>
#include <concepts>
#include <cstddef>
#include <iterator>
#include <vector>
#include <test_death.hpp>
using namespace std;
int globalArray[5]{10, 20, 30, 40, 50};
int otherArray[5]{10, 20, 30, 40, 50};
vector<int> checkedArray{10, 20, 30, 40, 50};
using vit = vector<int>::iterator;
struct simple_input_iter {
using value_type = int;
using difference_type = ptrdiff_t;
value_type operator*() const {
return *_ptr;
}
simple_input_iter& operator++() {
++_ptr;
return *this;
}
simple_input_iter operator++(int) {
simple_input_iter _tmp = *this;
++_ptr;
return _tmp;
}
bool operator==(simple_input_iter const&) const = default;
int* _ptr = nullptr;
};
void test_case_construction_negative_length() {
counted_iterator<int*> cit{globalArray, -1}; // counted_iterator requires non-negative length n
(void) cit;
}
void test_case_operator_dereference_value_initialized_iterator() {
counted_iterator<int*> cit{}; // note: for IDL to work correctly, default-init and value-init are equivalent
(void) (*cit); // cannot dereference value-initialized counted_iterator
}
void test_case_operator_dereference_end_iterator() {
counted_iterator<int*> cit{globalArray, 0};
(void) (*cit); // cannot dereference end counted_iterator (per proposed resolution of LWG-3472)
}
void test_case_operator_preincrement_value_initialized_iterator() {
counted_iterator<int*> cit{};
++cit; // cannot increment value-initialized counted_iterator
}
void test_case_operator_preincrement_value_initialized_input_iterator() {
counted_iterator<simple_input_iter> cit{};
++cit; // cannot increment value-initialized counted_iterator
}
void test_case_operator_preincrement_after_end() {
counted_iterator<int*> cit{globalArray, 0};
++cit; // cannot increment counted_iterator past end
}
void test_case_operator_preincrement_after_end_input_iterator() {
counted_iterator<simple_input_iter> cit{simple_input_iter{globalArray}, 0};
++cit; // cannot increment counted_iterator past end
}
void test_case_operator_postincrement_value_initialized_iterator() {
counted_iterator<int*> cit{};
cit++; // cannot increment value-initialized counted_iterator
}
void test_case_operator_postincrement_value_initialized_input_iterator() {
counted_iterator<simple_input_iter> cit{};
cit++; // cannot increment value-initialized counted_iterator
}
void test_case_operator_postincrement_after_end() {
counted_iterator<int*> cit{globalArray, 0};
cit++; // cannot increment counted_iterator past end
}
void test_case_operator_postincrement_after_end_input_iterator() {
counted_iterator<simple_input_iter> cit{simple_input_iter{globalArray}, 0};
cit++; // cannot increment value-initialized counted_iterator
}
void test_case_operator_predecrement_before_begin() {
counted_iterator<vit> cit{begin(checkedArray), 5};
--cit; // cannot decrement counted_iterator before begin
}
void test_case_operator_decrement_before_begin() {
counted_iterator<vit> cit{begin(checkedArray), 5};
cit--; // cannot decrement counted_iterator before begin
}
void test_case_operator_advance_value_initialized_iterator() {
counted_iterator<int*> cit{};
cit += 1; // cannot seek value-initialized counted_iterator
}
void test_case_operator_advance_after_end() {
counted_iterator<int*> cit{globalArray, 2};
cit += 3; // cannot seek counted_iterator after end
}
void test_case_operator_advance_copy_value_initialized_iterator() {
counted_iterator<int*> cit{};
(void) (cit + 1); // cannot seek value-initialized counted_iterator
}
void test_case_operator_advance_copy_after_end() {
counted_iterator<int*> cit{globalArray, 2};
(void) (cit + 3); // cannot seek counted_iterator after end
}
void test_case_operator_advance_copy_2_value_initialized_iterator() {
counted_iterator<int*> cit{};
(void) (1 + cit); // cannot seek value-initialized counted_iterator
}
void test_case_operator_advance_copy_2_after_end() {
counted_iterator<int*> cit{globalArray, 2};
(void) (3 + cit); // cannot seek counted_iterator after end
}
void test_case_operator_retreat_before_begin() {
counted_iterator<vit> cit{begin(checkedArray), 5};
cit -= 1; // cannot seek counted_iterator before begin
}
void test_case_operator_retreat_negative_after_end() {
counted_iterator<int*> cit{globalArray, 0};
cit -= -1; // cannot seek counted_iterator after end
}
void test_case_operator_retreat_copy_before_begin() {
counted_iterator<vit> cit{begin(checkedArray), 5};
(void) (cit - 1); // cannot seek counted_iterator before begin
}
void test_case_operator_retreat_copy_after_end() {
counted_iterator<int*> cit{globalArray, 0};
(void) (cit - -1); // cannot seek counted_iterator after end
}
void test_case_operator_subtract_incompatible_different_data() {
counted_iterator<int*> cit1(globalArray, 2);
counted_iterator<int*> cit2(otherArray, 2);
(void) (cit1 - cit2); // cannot subtract incompatible counted_iterators
}
void test_case_operator_subtract_incompatible_different_size() {
counted_iterator<int*> cit1(globalArray, 3);
counted_iterator<int*> cit2(globalArray, 4);
(void) (cit1 - cit2); // cannot subtract incompatible counted_iterators
}
void test_case_operator_subtract_incompatible_value_initialized() {
counted_iterator<int*> cit{globalArray, 0};
(void) (cit - counted_iterator<int*>{}); // cannot subtract incompatible counted_iterators
}
void test_case_operator_equal_incompatible_different_data() {
counted_iterator<int*> cit1(globalArray, 2);
counted_iterator<int*> cit2(otherArray, 2);
(void) (cit1 == cit2); // cannot compare incompatible counted_iterators for equality
}
void test_case_operator_equal_incompatible_different_size() {
counted_iterator<int*> cit1(globalArray, 3);
counted_iterator<int*> cit2(globalArray, 4);
(void) (cit1 == cit2); // cannot compare incompatible counted_iterators for equality
}
void test_case_operator_equal_incompatible_value_initialized() {
counted_iterator<int*> cit{globalArray, 0};
(void) (cit == counted_iterator<int*>{}); // cannot compare incompatible counted_iterators for equality
}
void test_case_operator_spaceship_incompatible_different_data() {
counted_iterator<int*> cit1(globalArray, 3);
counted_iterator<int*> cit2(otherArray, 3);
(void) (cit1 <=> cit2); // cannot compare incompatible counted_iterators
}
void test_case_operator_spaceship_incompatible_different_size() {
counted_iterator<int*> cit1(globalArray, 3);
counted_iterator<int*> cit2(globalArray, 4);
(void) (cit1 <=> cit2); // cannot compare incompatible counted_iterators
}
void test_case_operator_spaceship_incompatible_value_initialized() {
counted_iterator<int*> cit{globalArray, 0};
(void) (cit <=> counted_iterator<int*>{}); // cannot compare incompatible counted_iterators
}
int main(int argc, char* argv[]) {
std_testing::death_test_executive exec([] {});
#if _ITERATOR_DEBUG_LEVEL != 0
exec.add_death_tests({
test_case_construction_negative_length,
test_case_operator_dereference_value_initialized_iterator,
test_case_operator_dereference_end_iterator,
test_case_operator_preincrement_value_initialized_iterator,
test_case_operator_preincrement_value_initialized_input_iterator,
test_case_operator_preincrement_after_end,
test_case_operator_preincrement_after_end_input_iterator,
test_case_operator_postincrement_value_initialized_iterator,
test_case_operator_postincrement_value_initialized_input_iterator,
test_case_operator_postincrement_after_end,
test_case_operator_postincrement_after_end_input_iterator,
test_case_operator_predecrement_before_begin,
test_case_operator_decrement_before_begin,
test_case_operator_advance_value_initialized_iterator,
test_case_operator_advance_after_end,
test_case_operator_advance_copy_value_initialized_iterator,
test_case_operator_advance_copy_after_end,
test_case_operator_advance_copy_2_value_initialized_iterator,
test_case_operator_advance_copy_2_after_end,
test_case_operator_retreat_before_begin,
test_case_operator_retreat_negative_after_end,
test_case_operator_retreat_copy_before_begin,
test_case_operator_retreat_copy_after_end,
test_case_operator_subtract_incompatible_different_data,
test_case_operator_subtract_incompatible_different_size,
test_case_operator_subtract_incompatible_value_initialized,
test_case_operator_equal_incompatible_different_data,
test_case_operator_equal_incompatible_different_size,
test_case_operator_equal_incompatible_value_initialized,
test_case_operator_spaceship_incompatible_different_data,
test_case_operator_spaceship_incompatible_different_size,
test_case_operator_spaceship_incompatible_value_initialized,
});
#endif // _ITERATOR_DEBUG_LEVEL != 0
return exec.run(argc, argv);
}

Просмотреть файл

@ -147,7 +147,9 @@ struct test_vector {
};
int main() {
#ifndef _PREFAST_ // TRANSITION, GH-1030
STATIC_ASSERT((test_bidi_write<instantiator, const nontrivial_int, nontrivial_int>(), true));
#endif // TRANSITION, GH-1030
test_bidi_write<instantiator, const nontrivial_int, nontrivial_int>();
STATIC_ASSERT((test_contiguous_write<test_vector, const bytes<1>, bytes<1>>(), true));

Просмотреть файл

@ -3266,6 +3266,81 @@ namespace move_iterator_test {
STATIC_ASSERT(test());
} // namespace move_iterator_test
namespace counted_iterator_test {
using std::bidirectional_iterator_tag, std::default_sentinel_t, std::forward_iterator_tag, std::input_iterator_tag,
std::iterator_traits, std::counted_iterator, std::random_access_iterator_tag, std::same_as, std::string,
std::three_way_comparable, std::three_way_comparable_with;
// Validate the iterator_concept/iterator_category metaprogramming
STATIC_ASSERT(same_as<iterator_traits<counted_iterator<simple_contiguous_iter<>>>::iterator_category,
random_access_iterator_tag>);
STATIC_ASSERT(same_as<iterator_traits<counted_iterator<simple_random_iter<>>>::iterator_category,
random_access_iterator_tag>);
STATIC_ASSERT(
same_as<iterator_traits<counted_iterator<simple_bidi_iter<>>>::iterator_category, bidirectional_iterator_tag>);
STATIC_ASSERT(
same_as<iterator_traits<counted_iterator<simple_forward_iter<>>>::iterator_category, forward_iterator_tag>);
STATIC_ASSERT(same_as<iterator_traits<counted_iterator<simple_input_iter>>::iterator_category, input_iterator_tag>);
// Validate that postincrement returns counted_iterator<simple_input_iter> for single-pass adaptees
STATIC_ASSERT(same_as<decltype(counted_iterator<simple_input_iter> {} ++), counted_iterator<simple_input_iter>>);
STATIC_ASSERT(
same_as<decltype(counted_iterator<simple_forward_iter<>> {} ++), counted_iterator<simple_forward_iter<>>>);
// Validate comparison constraints
STATIC_ASSERT(has_eq<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_neq<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_less<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_greater<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_less_eq<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_greater_eq<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(three_way_comparable<counted_iterator<simple_input_iter>>);
STATIC_ASSERT(has_eq<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_neq<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_less<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_greater<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_less_eq<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_greater_eq<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(three_way_comparable<counted_iterator<simple_forward_iter<>>>);
STATIC_ASSERT(has_eq<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(has_neq<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(has_less<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(has_greater<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(has_less_eq<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(has_greater_eq<counted_iterator<simple_random_iter<>>>);
STATIC_ASSERT(three_way_comparable<counted_iterator<simple_random_iter<>>, std::strong_ordering>);
STATIC_ASSERT(has_eq<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(has_neq<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(has_less<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(has_greater<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(has_less_eq<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(has_greater_eq<counted_iterator<int*>, counted_iterator<int const*>>);
STATIC_ASSERT(
three_way_comparable_with<counted_iterator<int*>, counted_iterator<int const*>, std::strong_ordering>);
STATIC_ASSERT(!has_eq<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!has_neq<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!has_less<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!has_greater<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!has_less_eq<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!has_greater_eq<counted_iterator<int*>, counted_iterator<string*>>);
STATIC_ASSERT(!three_way_comparable_with<counted_iterator<int*>, counted_iterator<string*>>);
// Validate default_sentinel_t comparisons and difference
STATIC_ASSERT(has_eq<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(has_neq<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(!has_less<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(!has_greater<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(!has_less_eq<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(!has_greater_eq<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(!three_way_comparable_with<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(has_difference<counted_iterator<simple_input_iter>, default_sentinel_t>);
STATIC_ASSERT(has_difference<default_sentinel_t, counted_iterator<simple_input_iter>>);
} // namespace counted_iterator_test
namespace lwg3420 {
// Validate that we can ask for the iterator_traits of a type with no operator* for which checking copyability
// results in constraint recursion.

Просмотреть файл

@ -51,6 +51,9 @@ constexpr bool iter_test() {
STATIC_ASSERT(same_as<_Unwrapped_t<S>, sentinel<Element, IsWrapped::no>>);
}
STATIC_ASSERT(convertible_to<I, typename I::Consterator>);
STATIC_ASSERT(!to_bool(Eq) || convertible_to<const I&, typename I::Consterator>);
return true;
}

Просмотреть файл

@ -0,0 +1,28 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# This file is identical to concepts_matrix.lst, except that all configurations include /permissive-.
RUNALL_INCLUDE .\prefix.lst
RUNALL_CROSSLIST
PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /std:c++latest /permissive-"
RUNALL_CROSSLIST
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /Zc:noexceptTypes-"
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /Zc:char8_t- /Zc:preprocessor"
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /Zc:wchar_t-"
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /fp:except /Zc:preprocessor"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /await"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /analyze:only"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /fp:strict"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /await"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /analyze:only"
PM_CL="/Za /MD"
PM_CL="/Za /MDd"
# PM_CL="/BE /c /MD"
# PM_CL="/BE /c /MTd"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /MD"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /MTd /fp:strict"

Просмотреть файл

@ -0,0 +1,33 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# This file is identical to concepts_matrix.lst, except that:
# * all configurations include /permissive-,
# * /Za configurations are excluded since they can't deal with Windows.h,
# * /Zc:preprocessor configurations additionally have /wd5105 to cope with Windows.h
RUNALL_INCLUDE .\prefix.lst
RUNALL_CROSSLIST
PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /std:c++latest /permissive-"
RUNALL_CROSSLIST
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /Zc:noexceptTypes-"
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=1"
# TRANSITION, GH-854
PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /Zc:char8_t- /Zc:preprocessor /wd5105"
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /Zc:wchar_t-"
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1"
# TRANSITION, GH-854
PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /fp:except /Zc:preprocessor /wd5105"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /await"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /analyze:only"
PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /fp:strict"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /await"
PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /analyze:only"
# PM_CL="/Za /MD"
# PM_CL="/Za /MDd"
# PM_CL="/BE /c /MD"
# PM_CL="/BE /c /MTd"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /MD"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /MTd /fp:strict"