//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // REQUIRES: std-at-least-c++26 // UNSUPPORTED: libcpp-has-no-experimental-optional-iterator // // template class optional::iterator; // template class optional::const_iterator; #include #include #include #include #include template concept has_iterator = requires { typename T::iterator; }; template concept has_const_iterator = requires { typename T::const_iterator; }; template concept has_both_iterators = has_iterator && has_const_iterator; template concept only_has_iterator = has_iterator && !has_const_iterator; template concept has_no_iterators = !has_iterator && !has_const_iterator; template constexpr void test(std::decay_t v) { std::optional opt{v}; { static_assert(std::ranges::range); } { // Dereferencing an iterator of an engaged optional will return the same value that the optional holds. auto it = opt.begin(); auto it2 = std::as_const(opt).begin(); assert(*it == *opt); assert(*it2 == *std::as_const(opt)); } { // optional::iterator and optional::const_iterator satisfy the Cpp17RandomAccessIterator and contiguous iterator. auto it = opt.begin(); auto it2 = std::as_const(opt).begin(); static_assert(std::contiguous_iterator); static_assert(std::contiguous_iterator); static_assert(std::random_access_iterator); static_assert(std::random_access_iterator); } { // const_iterator::value_type == std::remove_cvref_t, const_iterator::reference == const T&, iterator::value_type = std::remove_cvref_t, iterator::reference == T& // std::remove_cv_t is impossible for optional auto it = opt.begin(); auto it2 = std::as_const(opt).begin(); static_assert(std::is_same_v>); static_assert(std::is_same_v&>); static_assert(std::is_same_v>); // optional doesn't have const_iterator if constexpr (!std::is_lvalue_reference_v) { static_assert(std::is_same_v&>); } } { // std::ranges::size for an engaged optional == 1, disengaged optional == 0 const std::optional disengaged{std::nullopt}; std::optional disengaged2{std::nullopt}; assert(std::ranges::size(opt) == 1); assert(std::ranges::size(std::as_const(opt)) == 1); assert(std::ranges::size(disengaged) == 0); assert(std::ranges::size(disengaged2) == 0); } { // std::ranges::enable_view> == true, and std::format_kind> == std::range_format::disabled static_assert(std::ranges::enable_view> == true); static_assert(std::format_kind> == std::range_format::disabled); } // An optional with value that is reset will have a begin() == end(), then when it is reassigned a value, // begin() != end(), and *begin() will contain the new value. { std::optional val{v}; assert(val.begin() != val.end()); val.reset(); assert(val.begin() == val.end()); val.emplace(v); assert(val.begin() != val.end()); assert(*(val.begin()) == v); } // [container.reqmts] operator- { std::optional val(v); auto it1 = val.begin(); auto it2 = val.begin(); auto it3 = val.end(); auto cit1 = std::as_const(val).begin(); auto cit2 = std::as_const(val).begin(); auto cit3 = std::as_const(val).end(); assert(it1 - it2 == 0); assert(cit1 - cit2 == 0); assert(it1 - cit1 == 0); assert(it3 - it1 == 1); assert(it1 - it3 == -1); assert(cit3 - cit1 == 1); assert(cit1 - cit3 == -1); assert(cit3 - cit3 == 0); assert(cit3 - it1 == 1); assert(it1 - cit3 == -1); } } constexpr bool test() { // Verify that iterator and const_iterator are present for object type T, but for T&, // that only iterator is available iff T is an object type and is not an unbounded array. static_assert(has_both_iterators>); static_assert(has_both_iterators>); static_assert(only_has_iterator>); static_assert(only_has_iterator>); static_assert(only_has_iterator>); static_assert(has_no_iterators>); static_assert(has_no_iterators>); test(1); test('a'); test(true); test(2); test('b'); test(1); test('a'); test(true); test(2); test('b'); static_assert(!std::ranges::range>); static_assert(!std::ranges::range>); static_assert(std::ranges::range>); return true; } int main(int, char**) { assert(test()); static_assert(test()); return 0; }