[libc++][format] Adds range-default-formatter.
This adds an incomplete version where the specializations for the format_kinds are disabled dummy formatters. Implements part of - P2585R0 Improving default container formatting Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D137271
This commit is contained in:
@@ -310,6 +310,7 @@ set(files
|
||||
__format/formatter_pointer.h
|
||||
__format/formatter_string.h
|
||||
__format/parser_std_format_spec.h
|
||||
__format/range_default_formatter.h
|
||||
__format/unicode.h
|
||||
__functional/binary_function.h
|
||||
__functional/binary_negate.h
|
||||
@@ -626,6 +627,7 @@ set(files
|
||||
__type_traits/is_scoped_enum.h
|
||||
__type_traits/is_signed.h
|
||||
__type_traits/is_signed_integer.h
|
||||
__type_traits/is_specialization.h
|
||||
__type_traits/is_standard_layout.h
|
||||
__type_traits/is_swappable.h
|
||||
__type_traits/is_trivial.h
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <__config>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__type_traits/is_specialization.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
@@ -56,6 +59,17 @@ concept __formattable =
|
||||
# if _LIBCPP_STD_VER > 20
|
||||
template <class _Tp, class _CharT>
|
||||
concept formattable = __formattable<_Tp, _CharT>;
|
||||
|
||||
// [tuple.like] defines a tuple-like exposition only concept. This concept is
|
||||
// not related to that. Therefore it uses a different name for the concept.
|
||||
//
|
||||
// TODO FMT Add a test to validate we fail when using that concept after P2165
|
||||
// has been implemented.
|
||||
template <class _Tp>
|
||||
concept __fmt_pair_like = __is_specialization_v<_Tp, pair> ||
|
||||
// Use a requires since tuple_size_v may fail to instantiate,
|
||||
(__is_specialization_v<_Tp, tuple> && requires { tuple_size_v<_Tp> == 2; });
|
||||
|
||||
# endif //_LIBCPP_STD_VER > 20
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
||||
|
||||
137
libcxx/include/__format/range_default_formatter.h
Normal file
137
libcxx/include/__format/range_default_formatter.h
Normal file
@@ -0,0 +1,137 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
||||
#define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <__availability>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <tuple>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
|
||||
template <class _Rp, class _CharT>
|
||||
concept __const_formattable_range =
|
||||
ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>;
|
||||
|
||||
template <class _Rp, class _CharT>
|
||||
using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>;
|
||||
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow")
|
||||
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow")
|
||||
// This shadows map, set, and string.
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
|
||||
// There is no definition of this struct, it's purely intended to be used to
|
||||
// generate diagnostics.
|
||||
template <class _Rp>
|
||||
struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind;
|
||||
|
||||
template <class _Rp>
|
||||
constexpr range_format format_kind = [] {
|
||||
// [format.range.fmtkind]/1
|
||||
// A program that instantiates the primary template of format_kind is ill-formed.
|
||||
static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type");
|
||||
return range_format::disabled;
|
||||
}();
|
||||
|
||||
template <ranges::input_range _Rp>
|
||||
requires same_as<_Rp, remove_cvref_t<_Rp>>
|
||||
inline constexpr range_format format_kind<_Rp> = [] {
|
||||
// [format.range.fmtkind]/2
|
||||
|
||||
// 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true,
|
||||
// Otherwise format_kind<R> is range_format::disabled.
|
||||
if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>)
|
||||
return range_format::disabled;
|
||||
// 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type:
|
||||
else if constexpr (requires { typename _Rp::key_type; }) {
|
||||
// 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ...
|
||||
if constexpr (requires { typename _Rp::mapped_type; } &&
|
||||
// 2.2.1 ... If either U is a specialization of pair or U is a specialization
|
||||
// of tuple and tuple_size_v<U> == 2
|
||||
__fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>)
|
||||
return range_format::map;
|
||||
else
|
||||
// 2.2.2 Otherwise format_kind<R> is range_format::set.
|
||||
return range_format::set;
|
||||
} else
|
||||
// 2.3 Otherwise, format_kind<R> is range_format::sequence.
|
||||
return range_format::sequence;
|
||||
}();
|
||||
|
||||
// This is a non-standard work-around to fix instantiation of
|
||||
// formatter<const _CharT[N], _CharT>
|
||||
// const _CharT[N] satisfies the ranges::input_range concept.
|
||||
// remove_cvref_t<const _CharT[N]> is _CharT[N] so it does not satisfy the
|
||||
// requirement of the above specialization. Instead it will instantiate the
|
||||
// primary template, which is ill-formed.
|
||||
//
|
||||
// An alternative solution is to remove the offending formatter.
|
||||
//
|
||||
// https://godbolt.org/z/bqjhhaexx
|
||||
//
|
||||
// The removal is proposed in LWG3833, but use the work-around until the issue
|
||||
// has been adopted.
|
||||
// TODO FMT Implement LWG3833.
|
||||
template <class _CharT, size_t N>
|
||||
inline constexpr range_format format_kind<const _CharT[N]> = range_format::disabled;
|
||||
|
||||
template <range_format _Kp, ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter;
|
||||
|
||||
// Required specializations
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::sequence, _Rp, _CharT> {
|
||||
__range_default_formatter() = delete; // TODO FMT Implement
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::map, _Rp, _CharT> {
|
||||
__range_default_formatter() = delete; // TODO FMT Implement
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::set, _Rp, _CharT> {
|
||||
__range_default_formatter() = delete; // TODO FMT Implement
|
||||
};
|
||||
|
||||
template <range_format _Kp, ranges::input_range _Rp, class _CharT>
|
||||
requires(_Kp == range_format::string || _Kp == range_format::debug_string)
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<_Kp, _Rp, _CharT> {
|
||||
__range_default_formatter() = delete; // TODO FMT Implement
|
||||
};
|
||||
|
||||
// Dispatcher to select the specialization based on the type of the range.
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>)
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_Rp, _CharT>
|
||||
: __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
||||
45
libcxx/include/__type_traits/is_specialization.h
Normal file
45
libcxx/include/__type_traits/is_specialization.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___TYPE_TRAITS_IS_SPECIALIZATION
|
||||
#define _LIBCPP___TYPE_TRAITS_IS_SPECIALIZATION
|
||||
|
||||
// This contains parts of P2098R1 but is based on MSVC STL's implementation.
|
||||
//
|
||||
// The paper has been rejected
|
||||
// We will not pursue P2098R0 (std::is_specialization_of) at this time; we'd
|
||||
// like to see a solution to this problem, but it requires language evolution
|
||||
// too.
|
||||
//
|
||||
// Since it is expected a real solution will be provided in the future only the
|
||||
// minimal part is implemented.
|
||||
//
|
||||
// Note a cvref qualified _Tp is never considered a specialization.
|
||||
|
||||
#include <__config>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
template <class _Tp, template <class...> class _Template>
|
||||
inline constexpr bool __is_specialization_v = false; // true if and only if _Tp is a specialization of _Template
|
||||
|
||||
template <template <class...> class _Template, class... _Args>
|
||||
inline constexpr bool __is_specialization_v<_Template<_Args...>, _Template> = true;
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 14
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___TYPE_TRAITS_IS_SPECIALIZATION
|
||||
@@ -112,6 +112,35 @@ namespace std {
|
||||
using format_parse_context = basic_format_parse_context<char>;
|
||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||
|
||||
// [format.range], formatting of ranges
|
||||
// [format.range.fmtkind], variable template format_kind
|
||||
enum class range_format { // since C++23
|
||||
disabled,
|
||||
map,
|
||||
set,
|
||||
sequence,
|
||||
string,
|
||||
debug_string
|
||||
};
|
||||
|
||||
template<class R>
|
||||
constexpr unspecified format_kind = unspecified; // since C++23
|
||||
|
||||
template<ranges::input_range R>
|
||||
requires same_as<R, remove_cvref_t<R>>
|
||||
constexpr range_format format_kind<R> = see below; // since C++23
|
||||
|
||||
// [format.range.fmtdef], class template range-default-formatter
|
||||
template<range_format K, ranges::input_range R, class charT>
|
||||
struct range-default-formatter; // exposition only, since C++23
|
||||
|
||||
// [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
|
||||
// specializations for maps, sets, and strings
|
||||
template<ranges::input_range R, class charT>
|
||||
requires (format_kind<R> != range_format::disabled) &&
|
||||
formattable<ranges::range_reference_t<R>, charT>
|
||||
struct formatter<R, charT> : range-default-formatter<format_kind<R>, R, charT> { }; // since C++23
|
||||
|
||||
// [format.arguments], arguments
|
||||
// [format.arg], class template basic_format_arg
|
||||
template<class Context> class basic_format_arg;
|
||||
@@ -163,6 +192,7 @@ namespace std {
|
||||
#include <__format/formatter_pointer.h>
|
||||
#include <__format/formatter_string.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__format/range_default_formatter.h>
|
||||
#include <__format/unicode.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
||||
@@ -846,6 +846,7 @@ module std [system] {
|
||||
module formatter_pointer { private header "__format/formatter_pointer.h" }
|
||||
module formatter_string { private header "__format/formatter_string.h" }
|
||||
module parser_std_format_spec { private header "__format/parser_std_format_spec.h" }
|
||||
module range_default_formatter { private header "__format/range_default_formatter.h" }
|
||||
module unicode { private header "__format/unicode.h" }
|
||||
}
|
||||
}
|
||||
@@ -1429,6 +1430,7 @@ module std [system] {
|
||||
module is_scoped_enum { private header "__type_traits/is_scoped_enum.h" }
|
||||
module is_signed { private header "__type_traits/is_signed.h" }
|
||||
module is_signed_integer { private header "__type_traits/is_signed_integer.h" }
|
||||
module is_specialization { private header "__type_traits/is_specialization.h" }
|
||||
module is_standard_layout { private header "__type_traits/is_standard_layout.h" }
|
||||
module is_swappable { private header "__type_traits/is_swappable.h" }
|
||||
module is_trivial { private header "__type_traits/is_trivial.h" }
|
||||
|
||||
@@ -497,6 +497,7 @@ namespace std
|
||||
#include <__type_traits/is_scalar.h>
|
||||
#include <__type_traits/is_scoped_enum.h>
|
||||
#include <__type_traits/is_signed.h>
|
||||
#include <__type_traits/is_specialization.h>
|
||||
#include <__type_traits/is_standard_layout.h>
|
||||
#include <__type_traits/is_swappable.h>
|
||||
#include <__type_traits/is_trivial.h>
|
||||
|
||||
@@ -342,6 +342,7 @@ END-SCRIPT
|
||||
#include <__format/formatter_pointer.h> // expected-error@*:* {{use of private header from outside its module: '__format/formatter_pointer.h'}}
|
||||
#include <__format/formatter_string.h> // expected-error@*:* {{use of private header from outside its module: '__format/formatter_string.h'}}
|
||||
#include <__format/parser_std_format_spec.h> // expected-error@*:* {{use of private header from outside its module: '__format/parser_std_format_spec.h'}}
|
||||
#include <__format/range_default_formatter.h> // expected-error@*:* {{use of private header from outside its module: '__format/range_default_formatter.h'}}
|
||||
#include <__format/unicode.h> // expected-error@*:* {{use of private header from outside its module: '__format/unicode.h'}}
|
||||
#include <__functional/binary_function.h> // expected-error@*:* {{use of private header from outside its module: '__functional/binary_function.h'}}
|
||||
#include <__functional/binary_negate.h> // expected-error@*:* {{use of private header from outside its module: '__functional/binary_negate.h'}}
|
||||
@@ -639,6 +640,7 @@ END-SCRIPT
|
||||
#include <__type_traits/is_scoped_enum.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_scoped_enum.h'}}
|
||||
#include <__type_traits/is_signed.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_signed.h'}}
|
||||
#include <__type_traits/is_signed_integer.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_signed_integer.h'}}
|
||||
#include <__type_traits/is_specialization.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_specialization.h'}}
|
||||
#include <__type_traits/is_standard_layout.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_standard_layout.h'}}
|
||||
#include <__type_traits/is_swappable.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_swappable.h'}}
|
||||
#include <__type_traits/is_trivial.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_trivial.h'}}
|
||||
|
||||
@@ -347,6 +347,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list algorithm
|
||||
|
||||
|
@@ -347,6 +347,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list algorithm
|
||||
|
||||
|
@@ -349,6 +349,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list algorithm
|
||||
|
||||
|
@@ -349,6 +349,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list algorithm
|
||||
|
||||
|
@@ -123,6 +123,7 @@ chrono sstream
|
||||
chrono stdexcept
|
||||
chrono string
|
||||
chrono string_view
|
||||
chrono tuple
|
||||
chrono type_traits
|
||||
chrono version
|
||||
cinttypes cstdint
|
||||
@@ -360,6 +361,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list algorithm
|
||||
|
||||
|
@@ -96,6 +96,7 @@ chrono sstream
|
||||
chrono stdexcept
|
||||
chrono string
|
||||
chrono string_view
|
||||
chrono tuple
|
||||
chrono type_traits
|
||||
chrono version
|
||||
cinttypes cstdint
|
||||
@@ -277,6 +278,7 @@ format optional
|
||||
format stdexcept
|
||||
format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format version
|
||||
forward_list compare
|
||||
|
||||
|
@@ -0,0 +1,58 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// template <class _Tp, template <class...> class _Template>
|
||||
// inline constexpr bool __is_specialization_v = true if and only if _Tp is a specialization of _Template
|
||||
//
|
||||
// Note instantiation for certain type combinations are ill-formed. These are
|
||||
// tested in is_specialization.verify.cpp.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// Simple types
|
||||
static_assert(std::__is_specialization_v<std::pair<int, int>, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<std::pair<int, int>, std::tuple>);
|
||||
static_assert(!std::__is_specialization_v<std::pair<int, int>, std::basic_string_view>);
|
||||
|
||||
static_assert(std::__is_specialization_v<std::tuple<int>, std::tuple>);
|
||||
static_assert(std::__is_specialization_v<std::tuple<int, float>, std::tuple>);
|
||||
static_assert(std::__is_specialization_v<std::tuple<int, float, void*>, std::tuple>);
|
||||
|
||||
static_assert(std::__is_specialization_v<std::string_view, std::basic_string_view>);
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
static_assert(std::__is_specialization_v<std::wstring_view, std::basic_string_view>);
|
||||
#endif
|
||||
|
||||
// Nested types
|
||||
static_assert(std::__is_specialization_v<std::pair<std::tuple<int>, int>, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<std::pair<std::tuple<int>, int>, std::tuple>);
|
||||
|
||||
// cvref _Tp is not a specialization.
|
||||
static_assert(!std::__is_specialization_v<const std::pair<int, int>, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<volatile std::pair<int, int>, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<const volatile std::pair<int, int>, std::pair>);
|
||||
|
||||
static_assert(!std::__is_specialization_v<std::pair<int, int>&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<const std::pair<int, int>&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<volatile std::pair<int, int>&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<const volatile std::pair<int, int>&, std::pair>);
|
||||
|
||||
static_assert(!std::__is_specialization_v<std::pair<int, int>&&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<const std::pair<int, int>&&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<volatile std::pair<int, int>&&, std::pair>);
|
||||
static_assert(!std::__is_specialization_v<const volatile std::pair<int, int>&&, std::pair>);
|
||||
22
libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
Normal file
22
libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// template <class _Tp, template <class...> class _Template>
|
||||
// inline constexpr bool __is_specialization_v = true if and only if _Tp is a specialization of _Template
|
||||
//
|
||||
// Tests the ill-formed instantiations.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
// expected-error@+1 {{template template argument has different template parameters than its corresponding template template parameter}}
|
||||
static_assert(!std::__is_specialization_v<std::pair<int, size_t>, std::array>);
|
||||
@@ -185,7 +185,8 @@ void test_P1636() {
|
||||
#endif
|
||||
assert_is_not_formattable<std::shared_ptr<int>, CharT>();
|
||||
#ifndef TEST_HAS_NO_LOCALIZATION
|
||||
assert_is_not_formattable<std::sub_match<CharT*>, CharT>();
|
||||
if constexpr (!std::same_as<CharT, int>) // sub_match only works with proper character types
|
||||
assert_is_not_formattable<std::sub_match<CharT*>, CharT>();
|
||||
#endif
|
||||
#ifndef TEST_HAS_NO_THREADS
|
||||
assert_is_not_formattable<std::thread::id, CharT>();
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// <format>
|
||||
|
||||
// template<ranges::input_range R>
|
||||
// requires same_as<R, remove_cvref_t<R>>
|
||||
// constexpr range_format format_kind<R> = see below;
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <format>
|
||||
#include <forward_list>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <valarray>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
#ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY
|
||||
# include <filesystem>
|
||||
#endif
|
||||
|
||||
// [format.range.fmtkind]
|
||||
// If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true,
|
||||
// format_kind<R> is range_format::disabled.
|
||||
// [Note 1: This prevents constraint recursion for ranges whose reference type
|
||||
// is the same range type. For example, std::filesystem::path is a range of
|
||||
// std::filesystem::path. - end note]
|
||||
struct recursive_range {
|
||||
struct iterator {
|
||||
using iterator_concept = std::input_iterator_tag;
|
||||
using value_type = recursive_range;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = recursive_range;
|
||||
|
||||
reference operator*() const;
|
||||
|
||||
iterator& operator++();
|
||||
iterator operator++(int);
|
||||
|
||||
friend bool operator==(const iterator&, const iterator&);
|
||||
};
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
};
|
||||
|
||||
static_assert(std::ranges::input_range<recursive_range>, "format_kind requires an input range");
|
||||
static_assert(std::format_kind<recursive_range> == std::range_format::disabled);
|
||||
|
||||
#ifndef TEST_HAS_NO_FILESYSTEM_LIBRARY
|
||||
static_assert(std::format_kind<std::filesystem::path> == std::range_format::disabled);
|
||||
#endif
|
||||
|
||||
static_assert(std::format_kind<std::map<int, int>> == std::range_format::map);
|
||||
static_assert(std::format_kind<std::multimap<int, int>> == std::range_format::map);
|
||||
static_assert(std::format_kind<std::unordered_map<int, int>> == std::range_format::map);
|
||||
static_assert(std::format_kind<std::unordered_multimap<int, int>> == std::range_format::map);
|
||||
|
||||
static_assert(std::format_kind<std::set<int>> == std::range_format::set);
|
||||
static_assert(std::format_kind<std::multiset<int>> == std::range_format::set);
|
||||
static_assert(std::format_kind<std::unordered_set<int>> == std::range_format::set);
|
||||
static_assert(std::format_kind<std::unordered_multiset<int>> == std::range_format::set);
|
||||
|
||||
static_assert(std::format_kind<std::array<int, 1>> == std::range_format::sequence);
|
||||
static_assert(std::format_kind<std::vector<int>> == std::range_format::sequence);
|
||||
static_assert(std::format_kind<std::deque<int>> == std::range_format::sequence);
|
||||
static_assert(std::format_kind<std::forward_list<int>> == std::range_format::sequence);
|
||||
static_assert(std::format_kind<std::list<int>> == std::range_format::sequence);
|
||||
|
||||
static_assert(std::format_kind<std::span<int>> == std::range_format::sequence);
|
||||
|
||||
static_assert(std::format_kind<std::valarray<int>> == std::range_format::sequence);
|
||||
|
||||
// [format.range.fmtkind]/3
|
||||
// Remarks: Pursuant to [namespace.std], users may specialize format_kind for
|
||||
// cv-unqualified program-defined types that model ranges::input_range. Such
|
||||
// specializations shall be usable in constant expressions ([expr.const]) and
|
||||
// have type const range_format.
|
||||
// Note only test the specializing, not all constraints.
|
||||
struct no_specialization : std::ranges::view_base {
|
||||
using key_type = void;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(std::format_kind<no_specialization> == std::range_format::set);
|
||||
|
||||
// The struct's "contents" are the same as no_specialization.
|
||||
struct specialized : std::ranges::view_base {
|
||||
using key_type = void;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr std::range_format std::format_kind<specialized> = std::range_format::sequence;
|
||||
static_assert(std::format_kind<specialized> == std::range_format::sequence);
|
||||
@@ -0,0 +1,60 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// <format>
|
||||
|
||||
// template<ranges::input_range R>
|
||||
// requires same_as<R, remove_cvref_t<R>>
|
||||
// constexpr range_format format_kind<R> = see below;
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <array>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
constexpr std::range_format valid = std::format_kind<std::array<int, 1>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format invalid_due_to_const = std::format_kind<const std::array<int, 1>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format invalid_due_to_volatile = std::format_kind<volatile std::array<int, 1>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format invalid_due_to_reference = std::format_kind<std::array<int, 1>&>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format invalid_no_input_range = std::format_kind<int>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_stack = std::format_kind<std::stack<int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_queue = std::format_kind<std::queue<int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_priority_queue = std::format_kind<std::priority_queue<int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_pair = std::format_kind<std::pair<int, int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_tuple_1 = std::format_kind<std::tuple<int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_tuple_2 = std::format_kind<std::tuple<int, int>>;
|
||||
|
||||
// expected-error@*:* {{create a template specialization of format_kind for your type}}
|
||||
constexpr std::range_format not_a_range_tuple_3 = std::format_kind<std::tuple<int, int, int>>;
|
||||
@@ -0,0 +1,30 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// <format>
|
||||
|
||||
// enum class range_format {
|
||||
// disabled,
|
||||
// map,
|
||||
// set,
|
||||
// sequence,
|
||||
// string,
|
||||
// debug_string
|
||||
// };
|
||||
|
||||
#include <format>
|
||||
|
||||
// test that the enumeration values exist
|
||||
static_assert(requires { std::range_format::disabled; });
|
||||
static_assert(requires { std::range_format::map; });
|
||||
static_assert(requires { std::range_format::set; });
|
||||
static_assert(requires { std::range_format::sequence; });
|
||||
static_assert(requires { std::range_format::string; });
|
||||
static_assert(requires { std::range_format::debug_string; });
|
||||
Reference in New Issue
Block a user