зеркало из https://github.com/microsoft/STL.git
Implement counted_iterator (#1083)
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:
Родитель
87dc1d3383
Коммит
1e42166b78
305
stl/inc/iterator
305
stl/inc/iterator
|
@ -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"
|
Загрузка…
Ссылка в новой задаче