using __maybe_const
= __conditional_t<formattable<const _Tp, _CharT>, const _Tp, _Tp>;
}
+
+ // [format.range], formatting of ranges
+ // [format.range.fmtkind], variable template format_kind
+ enum class range_format {
+ disabled,
+ map,
+ set,
+ sequence,
+ string,
+ debug_string
+ };
+
+ /** @brief A constant determining how a range should be formatted.
+ *
+ * The primary template of `std::format_kind` cannot be instantiated.
+ * There is a partial specialization for input ranges and you can
+ * specialize the variable template for your own cv-unqualified types
+ * that satisfy the `ranges::input_range` concept.
+ *
+ * @since C++23
+ */
+ template<typename _Rg>
+ constexpr auto format_kind = []{
+ static_assert(false, "cannot use primary template of 'std::format_kind'");
+ return type_identity<_Rg>{};
+ }();
#endif // format_ranges
_GLIBCXX_END_NAMESPACE_VERSION
};
};
+ftms = {
+ name = optional_range_support;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ };
+};
+
ftms = {
name = destroying_delete;
values = {
#endif /* !defined(__cpp_lib_optional) && defined(__glibcxx_want_optional) */
#undef __glibcxx_want_optional
+#if !defined(__cpp_lib_optional_range_support)
+# if (__cplusplus > 202302L)
+# define __glibcxx_optional_range_support 202406L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional_range_support)
+# define __cpp_lib_optional_range_support 202406L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_optional_range_support) && defined(__glibcxx_want_optional_range_support) */
+#undef __glibcxx_want_optional_range_support
+
#if !defined(__cpp_lib_destroying_delete)
# if (__cplusplus >= 202002L) && (__cpp_impl_destroying_delete)
# define __glibcxx_destroying_delete 201806L
#endif
#if __glibcxx_format_ranges // C++ >= 23 && HOSTED
- // [format.range], formatting of ranges
- // [format.range.fmtkind], variable template format_kind
- enum class range_format {
- disabled,
- map,
- set,
- sequence,
- string,
- debug_string
- };
-
- /** @brief A constant determining how a range should be formatted.
- *
- * The primary template of `std::format_kind` cannot be instantiated.
- * There is a partial specialization for input ranges and you can
- * specialize the variable template for your own cv-unqualified types
- * that satisfy the `ranges::input_range` concept.
- *
- * @since C++23
- */
- template<typename _Rg>
- constexpr auto format_kind = []{
- static_assert(false, "cannot use primary template of 'std::format_kind'");
- return type_identity<_Rg>{};
- }();
-
/// @cond undocumented
template<typename _Tp>
consteval range_format
#define __glibcxx_want_freestanding_optional
#define __glibcxx_want_optional
+#define __glibcxx_want_optional_range_support
#define __glibcxx_want_constrained_equality
#include <bits/version.h>
#if __cplusplus > 202002L
# include <concepts>
#endif
+#ifdef __cpp_lib_optional_range_support // C++ >= 26
+# include <bits/formatfwd.h>
+# include <bits/ranges_base.h>
+# include <bits/stl_iterator.h>
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
public:
using value_type = _Tp;
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>;
+ using const_iterator = __gnu_cxx::__normal_iterator<const _Tp*, optional>;
+#endif
constexpr optional() noexcept { }
}
}
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ // Iterator support.
+ constexpr iterator begin() noexcept
+ {
+ return iterator(
+ this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr
+ );
+ }
+
+ constexpr const_iterator begin() const noexcept
+ {
+ return const_iterator(
+ this->_M_is_engaged() ? std::addressof(this->_M_get()) : nullptr
+ );
+ }
+
+ constexpr iterator end() noexcept
+ {
+ return begin() + has_value();
+ }
+
+ constexpr const_iterator end() const noexcept
+ {
+ return begin() + has_value();
+ }
+#endif // __cpp_lib_optional_range_support
+
// Observers.
constexpr const _Tp*
operator->() const noexcept
template <typename _Tp> optional(_Tp) -> optional<_Tp>;
#endif
+#ifdef __cpp_lib_optional_range_support // >= C++26
+ template<typename _Tp>
+ inline constexpr bool
+ ranges::enable_view<optional<_Tp>> = true;
+
+ template<typename _Tp>
+ inline constexpr auto
+ format_kind<optional<_Tp>> = range_format::disabled;
+#endif // __cpp_lib_optional_range_support
+
#undef _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL
_GLIBCXX_END_NAMESPACE_VERSION
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <concepts>
+#include <format>
+#include <iterator>
+#include <optional>
+#include <ranges>
+#include <string_view>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<typename O>
+constexpr
+void
+test_range_concepts()
+{
+ static_assert(std::ranges::contiguous_range<O>);
+ static_assert(std::ranges::sized_range<O>);
+ static_assert(std::ranges::common_range<O>);
+ static_assert(!std::ranges::borrowed_range<O>);
+
+ // an optional<const T> is not assignable, and therefore does not satisfy ranges::view
+ using T = typename O::value_type;
+ constexpr bool is_const_opt = std::is_const_v<T>;
+ static_assert(std::ranges::view<O> == !is_const_opt);
+ static_assert(std::ranges::viewable_range<O> == !is_const_opt);
+}
+
+template<typename O>
+constexpr
+void
+test_iterator_concepts()
+{
+ using T = typename O::value_type;
+ using iterator = typename O::iterator;
+ static_assert(std::contiguous_iterator<iterator>);
+ static_assert(std::is_same_v<typename std::iterator_traits<iterator>::value_type, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<std::iter_value_t<iterator>, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<typename std::iterator_traits<iterator>::reference, T&>);
+ static_assert(std::is_same_v<std::iter_reference_t<iterator>, T&>);
+
+ using const_iterator = typename O::const_iterator;
+ static_assert(std::contiguous_iterator<const_iterator>);
+ static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::value_type, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<std::iter_value_t<const_iterator>, std::remove_cv_t<T>>);
+ static_assert(std::is_same_v<typename std::iterator_traits<const_iterator>::reference, const T&>);
+ static_assert(std::is_same_v<std::iter_reference_t<const_iterator>, const T&>);
+}
+
+template<typename O>
+constexpr
+void
+test_empty()
+{
+ O empty;
+ VERIFY(!empty);
+ VERIFY(empty.begin() == empty.end());
+ VERIFY(std::as_const(empty).begin() == std::as_const(empty).end());
+ VERIFY(std::ranges::empty(empty));
+ VERIFY(std::ranges::empty(std::as_const(empty)));
+ VERIFY(std::ranges::empty(empty | std::views::as_const));
+ VERIFY(std::ranges::size(empty) == 0);
+ VERIFY(std::ranges::size(std::as_const(empty)) == 0);
+
+ size_t count = 0;
+ for (const auto& x : empty)
+ ++count;
+ VERIFY(count == 0);
+}
+
+template<typename O, typename T>
+constexpr
+void
+test_non_empty(const T& value)
+{
+ O non_empty = std::make_optional(value);
+ VERIFY(non_empty);
+ VERIFY(*non_empty == value);
+ VERIFY(non_empty.begin() != non_empty.end());
+ VERIFY(non_empty.begin() < non_empty.end());
+ VERIFY(std::as_const(non_empty).begin() != std::as_const(non_empty).end());
+ VERIFY(std::as_const(non_empty).begin() < std::as_const(non_empty).end());
+ VERIFY(!std::ranges::empty(non_empty));
+ VERIFY(!std::ranges::empty(std::as_const(non_empty)));
+ VERIFY(!std::ranges::empty(non_empty | std::views::as_const));
+ VERIFY(std::ranges::size(non_empty) == 1);
+ VERIFY(std::ranges::size(std::as_const(non_empty)) == 1);
+
+ size_t count = 0;
+ for (const auto& x : non_empty)
+ ++count;
+ VERIFY(count == 1);
+
+ if constexpr (!std::is_const_v<typename O::value_type>) {
+ for (auto& x : non_empty)
+ x = T{};
+ VERIFY(non_empty);
+ VERIFY(*non_empty == T{});
+ }
+}
+
+template<typename T>
+constexpr
+void
+test(const T& value)
+{
+ using O = std::optional<T>;
+ test_range_concepts<O>();
+ test_iterator_concepts<O>();
+ test_empty<O>();
+ test_non_empty<O>(value);
+ static_assert(!std::formattable<O, char>);
+ static_assert(!std::formattable<O, wchar_t>);
+ static_assert(std::format_kind<O> == std::range_format::disabled);
+}
+
+constexpr
+void
+range_chain_example() // from P3168
+{
+ std::vector<int> v{2, 3, 4, 5, 6, 7, 8, 9, 1};
+ auto test = [](int i) -> std::optional<int> {
+ switch(i) {
+ case 1:
+ case 3:
+ case 7:
+ case 9:
+ return i * 2;
+ default:
+ return {};
+ }
+ };
+
+ auto result = v
+ | std::views::transform(test)
+ | std::views::filter([](auto x) { return bool(x); })
+ | std::views::transform([](auto x){ return *x; })
+ | std::ranges::to<std::vector>();
+
+ bool ok = result == std::vector<int>{6, 14, 18, 2};
+ VERIFY(ok);
+}
+
+constexpr
+bool
+all_tests()
+{
+ test(42);
+ int i = 42;
+ test(&i);
+ test(std::string_view("test"));
+ test(std::vector<int>{1, 2, 3, 4});
+ test(std::optional<int>(42));
+ test<const int>(42);
+
+ range_chain_example();
+
+ return true;
+}
+
+static_assert(all_tests());
+
#endif
#endif
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_optional_range_support
+# error "Feature test macro for optional range support is missing in <version>"
+# elif __cpp_lib_optional_range_support != 202406L
+# error "Feature test macro for optional range support has wrong value for C++26 in <version>"
+# endif
+#endif
+
#undef __cpp_lib_optional
#undef __cpp_lib_freestanding_optional
+#undef __cpp_lib_optional_range_support
#include <optional>
#if __cplusplus >= 202302L
# error "Feature test macro for freestanding std::optional has wrong value in <optional>"
#endif
#endif
+
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_optional_range_support
+# error "Feature test macro for optional range support is missing in <optional>"
+# endif
+# if __cpp_lib_optional_range_support != 202406L
+# error "Feature test macro for optional range support has wrong value for C++26 in <optional>"
+# endif
+#endif