mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-30 09:01:19 +00:00
[libc++][format] Implements range_formatter
Implements parts of - P2286R8 Formatting Ranges - P2585R0 Improving default container formatting Depends on D140651 Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D140653
This commit is contained in:
parent
72dc033fa6
commit
22e8525dfd
@ -30,7 +30,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
|
||||
`P2286R8 <https://wg21.link/P2286R8>`__,"Formatting ranges"
|
||||
`[format.syn] <https://wg21.link/format.syn>`_,"Concept ``formattable``",,Mark de Wever,|Complete|, Clang 16
|
||||
`[format.string.std] <https://wg21.link/format.string.std>`_,"std-format-spec ``type`` debug",,Mark de Wever,|Complete|,Clang 16
|
||||
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: sequences",,Mark de Wever,|In Progress|,
|
||||
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: sequences",,Mark de Wever,|Complete|,Clang 16
|
||||
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: associative",,Mark de Wever,,
|
||||
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: container adaptors",,Mark de Wever,,
|
||||
`[format.range] <https://wg21.link/format.range>`_,"Formatting for ranges: ``pair`` and ``tuple``",,Mark de Wever,|Complete|,Clang 16
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -327,6 +327,7 @@ set(files
|
||||
__format/formatter_tuple.h
|
||||
__format/parser_std_format_spec.h
|
||||
__format/range_default_formatter.h
|
||||
__format/range_formatter.h
|
||||
__format/unicode.h
|
||||
__functional/binary_function.h
|
||||
__functional/binary_negate.h
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@ -493,6 +494,74 @@ public:
|
||||
return {_VSTD::move(this->__writer_).__out_it(), this->__size_};
|
||||
}
|
||||
};
|
||||
|
||||
// A dynamically growing buffer intended to be used for retargeting a context.
|
||||
//
|
||||
// P2286 Formatting ranges adds range formatting support. It allows the user to
|
||||
// specify the minimum width for the entire formatted range. The width of the
|
||||
// range is not known until the range is formatted. Formatting is done to an
|
||||
// output_iterator so there's no guarantee it would be possible to add the fill
|
||||
// to the front of the output. Instead the range is formatted to a temporary
|
||||
// buffer and that buffer is formatted as a string.
|
||||
//
|
||||
// There is an issue with that approach, the format context used in
|
||||
// std::formatter<T>::format contains the output iterator used as part of its
|
||||
// type. So using this output iterator means there needs to be a new format
|
||||
// context and the format arguments need to be retargeted to the new context.
|
||||
// This retargeting is done by a basic_format_context specialized for the
|
||||
// __iterator of this container.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
|
||||
public:
|
||||
using value_type = _CharT;
|
||||
|
||||
struct __iterator {
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
|
||||
: __buffer_(std::addressof(__buffer)) {}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
|
||||
__buffer_->push_back(__c);
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
|
||||
__buffer_->push_back(__c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
|
||||
__retarget_buffer* __buffer_;
|
||||
};
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) { __buffer_.reserve(__size_hint); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { __buffer_.push_back(__c); }
|
||||
|
||||
template <__fmt_char_type _InCharT>
|
||||
_LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
|
||||
__buffer_.insert(__buffer_.end(), __str.begin(), __str.end());
|
||||
}
|
||||
|
||||
template <__fmt_char_type _InCharT, class _UnaryOperation>
|
||||
_LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
|
||||
_LIBCPP_ASSERT(__first <= __last, "not a valid range");
|
||||
std::transform(__first, __last, std::back_inserter(__buffer_), std::move(__operation));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { __buffer_.insert(__buffer_.end(), __n, __value); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__buffer_.data(), __buffer_.size()}; }
|
||||
|
||||
private:
|
||||
// Use vector instead of string to avoid adding zeros after every append
|
||||
// operation. The buffer is exposed as a string_view and not as a c-string.
|
||||
vector<_CharT> __buffer_;
|
||||
};
|
||||
|
||||
} // namespace __format
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
@ -11,13 +11,19 @@
|
||||
#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/buffer.h>
|
||||
#include <__format/format_arg.h>
|
||||
#include <__format/format_arg_store.h>
|
||||
#include <__format/format_args.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__variant/monostate.h>
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
@ -138,8 +144,78 @@ private:
|
||||
: __out_it_(_VSTD::move(__out_it)), __args_(__args) {}
|
||||
#endif
|
||||
};
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
|
||||
|
||||
// A specialization for __retarget_buffer
|
||||
//
|
||||
// See __retarget_buffer for the motivation for this specialization.
|
||||
//
|
||||
// This context holds a reference to the instance of the basic_format_context
|
||||
// that is retargeted. It converts a formatting argument when it is requested
|
||||
// during formatting. It is expected that the usage of the arguments is rare so
|
||||
// the lookups are not expected to be used often. An alternative would be to
|
||||
// convert all elements during construction.
|
||||
//
|
||||
// The elements of the retargets context are only used when an underlying
|
||||
// formatter uses a locale specific formatting or an formatting argument is
|
||||
// part for the format spec. For example
|
||||
// format("{:256:{}}", input, 8);
|
||||
// Here the width of an element in input is determined dynamically.
|
||||
// Note when the top-level element has no width the retargeting is not needed.
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
|
||||
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
|
||||
public:
|
||||
using iterator = typename __format::__retarget_buffer<_CharT>::__iterator;
|
||||
using char_type = _CharT;
|
||||
template <class _Tp>
|
||||
using formatter_type = formatter<_Tp, _CharT>;
|
||||
|
||||
template <class _Context>
|
||||
_LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx)
|
||||
: __out_it_(std::move(__out_it)),
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
__loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }),
|
||||
# endif
|
||||
__ctx_(std::addressof(__ctx)),
|
||||
__arg_([](void* __c, size_t __id) {
|
||||
return std::visit_format_arg(
|
||||
[&](auto __arg) -> basic_format_arg<basic_format_context> {
|
||||
if constexpr (same_as<decltype(__arg), monostate>)
|
||||
return {};
|
||||
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
|
||||
// At the moment it's not possible for formatting to use a re-targeted handle.
|
||||
// TODO FMT add this when support is needed.
|
||||
std::__throw_format_error("Re-targeting handle not supported");
|
||||
else
|
||||
return basic_format_arg<basic_format_context>{
|
||||
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
|
||||
__basic_format_arg_value<basic_format_context>(__arg)};
|
||||
},
|
||||
static_cast<_Context*>(__c)->arg(__id));
|
||||
}) {
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
|
||||
return __arg_(__ctx_, __id);
|
||||
}
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
_LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); }
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
|
||||
_LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
|
||||
|
||||
private:
|
||||
iterator __out_it_;
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
std::locale (*__loc_)(void* __ctx);
|
||||
# endif
|
||||
|
||||
void* __ctx_;
|
||||
basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id);
|
||||
};
|
||||
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
@ -102,6 +102,10 @@ _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterat
|
||||
if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
|
||||
__out_it.__get_container()->__copy(__str);
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it),
|
||||
typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
|
||||
__out_it.__buffer_->__copy(__str);
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::copy(__str, _VSTD::move(__out_it)).out;
|
||||
}
|
||||
@ -132,6 +136,10 @@ __transform(const _CharT* __first,
|
||||
if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
|
||||
__out_it.__get_container()->__transform(__first, __last, _VSTD::move(__operation));
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it),
|
||||
typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
|
||||
__out_it.__buffer_->__transform(__first, __last, _VSTD::move(__operation));
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out;
|
||||
}
|
||||
@ -145,6 +153,9 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value)
|
||||
if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_CharT>>>) {
|
||||
__out_it.__get_container()->__fill(__n, __value);
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) {
|
||||
__out_it.__buffer_->__fill(__n, __value);
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::fill_n(_VSTD::move(__out_it), __n, __value);
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ inline constexpr __fields __fields_pointer{.__type_ = true};
|
||||
|
||||
# if _LIBCPP_STD_VER > 20
|
||||
inline constexpr __fields __fields_tuple{.__type_ = false, .__allow_colon_in_fill_ = true};
|
||||
inline constexpr __fields __fields_range{.__type_ = false, .__allow_colon_in_fill_ = true};
|
||||
# endif
|
||||
|
||||
enum class _LIBCPP_ENUM_VIS __alignment : uint8_t {
|
||||
|
@ -19,9 +19,11 @@
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/range_formatter.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
@ -104,7 +106,28 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatte
|
||||
|
||||
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
|
||||
private:
|
||||
using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>;
|
||||
range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) {
|
||||
__underlying_.set_separator(__separator);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void
|
||||
set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) {
|
||||
__underlying_.set_brackets(__opening_bracket, __closing_bracket);
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return __underlying_.parse(__ctx);
|
||||
}
|
||||
|
||||
template <class FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename FormatContext::iterator format(__maybe_const_r& __range, FormatContext& __ctx) const {
|
||||
return __underlying_.format(__range, __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
|
245
libcxx/include/__format/range_formatter.h
Normal file
245
libcxx/include/__format/range_formatter.h
Normal file
@ -0,0 +1,245 @@
|
||||
// -*- 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_FORMATTER_H
|
||||
#define _LIBCPP___FORMAT_RANGE_FORMATTER_H
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__availability>
|
||||
#include <__chrono/statically_widen.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/buffer.h>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_args.h>
|
||||
#include <__format/format_context.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
#include <string_view>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 20
|
||||
|
||||
template <class _Tp, class _CharT = char>
|
||||
requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT range_formatter {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) {
|
||||
__separator_ = __separator;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void
|
||||
set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) {
|
||||
__opening_bracket_ = __opening_bracket;
|
||||
__closing_bracket_ = __closing_bracket;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() { return __underlying_; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const { return __underlying_; }
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __parse_ctx) {
|
||||
const _CharT* __begin = __parser_.__parse(__parse_ctx, __format_spec::__fields_range);
|
||||
const _CharT* __end = __parse_ctx.end();
|
||||
if (__begin == __end)
|
||||
return __begin;
|
||||
|
||||
// The n field overrides a possible m type, therefore delay applying the
|
||||
// effect of n until the type has been procesed.
|
||||
bool __clear_brackets = (*__begin == _CharT('n'));
|
||||
if (__clear_brackets) {
|
||||
++__begin;
|
||||
if (__begin == __end) {
|
||||
// Since there is no more data, clear the brackets before returning.
|
||||
set_brackets({}, {});
|
||||
return __begin;
|
||||
}
|
||||
}
|
||||
|
||||
__parse_type(__begin, __end);
|
||||
if (__clear_brackets)
|
||||
set_brackets({}, {});
|
||||
if (__begin == __end)
|
||||
return __begin;
|
||||
|
||||
bool __has_range_underlying_spec = *__begin == _CharT(':');
|
||||
if (__parser_.__type_ != __format_spec::__type::__default) {
|
||||
// [format.range.formatter]/6
|
||||
// If the range-type is s or ?s, then there shall be no n option and no
|
||||
// range-underlying-spec.
|
||||
if (__clear_brackets) {
|
||||
if (__parser_.__type_ == __format_spec::__type::__string)
|
||||
std::__throw_format_error("The n option and type s can't be used together");
|
||||
std::__throw_format_error("The n option and type ?s can't be used together");
|
||||
}
|
||||
if (__has_range_underlying_spec) {
|
||||
if (__parser_.__type_ == __format_spec::__type::__string)
|
||||
std::__throw_format_error("Type s and an underlying format specification can't be used together");
|
||||
std::__throw_format_error("Type ?s and an underlying format specification can't be used together");
|
||||
}
|
||||
} else if (!__has_range_underlying_spec)
|
||||
std::__set_debug_format(__underlying_);
|
||||
|
||||
if (__has_range_underlying_spec) {
|
||||
// range-underlying-spec:
|
||||
// : format-spec
|
||||
++__begin;
|
||||
if (__begin == __end)
|
||||
return __begin;
|
||||
|
||||
__parse_ctx.advance_to(__begin);
|
||||
__begin = __underlying_.parse(__parse_ctx);
|
||||
}
|
||||
|
||||
if (__begin != __end && *__begin != _CharT('}'))
|
||||
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
|
||||
|
||||
return __begin;
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
requires formattable<ranges::range_reference_t<_Rp>, _CharT> &&
|
||||
same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Rp&& __range, _FormatContext& __ctx) const {
|
||||
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
|
||||
|
||||
if (!__specs.__has_width())
|
||||
return __format_range(__range, __ctx, __specs);
|
||||
|
||||
// The size of the buffer needed is:
|
||||
// - open bracket characters
|
||||
// - close bracket character
|
||||
// - n elements where every element may have a different size
|
||||
// - (n -1) separators
|
||||
// The size of the element is hard to predict, knowing the type helps but
|
||||
// it depends on the format-spec. As an initial estimate we guess 6
|
||||
// characters.
|
||||
// Typically both brackets are 1 character and the separator is 2
|
||||
// characters. Which means there will be
|
||||
// (n - 1) * 2 + 1 + 1 = n * 2 character
|
||||
// So estimate 8 times the range size as buffer.
|
||||
__format::__retarget_buffer<_CharT> __buffer{8 * ranges::size(__range)};
|
||||
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{
|
||||
__buffer.__make_output_iterator(), __ctx};
|
||||
|
||||
__format_range(__range, __c, __specs);
|
||||
|
||||
return __formatter::__write_string_no_precision(__buffer.__view(), __ctx.out(), __specs);
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI
|
||||
__format_range(_Rp&& __range, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) const {
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
switch (__specs.__std_.__type_) {
|
||||
case __format_spec::__type::__string:
|
||||
case __format_spec::__type::__debug:
|
||||
return __format_as_string(__range, __ctx, __specs.__std_.__type_ == __format_spec::__type::__debug);
|
||||
default:
|
||||
return __format_as_sequence(__range, __ctx);
|
||||
}
|
||||
} else
|
||||
return __format_as_sequence(__range, __ctx);
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_as_string(_Rp&& __range, _FormatContext& __ctx, bool __debug_format) const {
|
||||
// When the range is contiguous use a basic_string_view instead to avoid a
|
||||
// copy of the underlying data. The basic_string_view formatter
|
||||
// specialization is the "basic" string formatter in libc++.
|
||||
if constexpr (ranges::contiguous_range<_Rp>) {
|
||||
std::formatter<basic_string_view<_CharT>, _CharT> __formatter;
|
||||
if (__debug_format)
|
||||
__formatter.set_debug_format();
|
||||
return __formatter.format(basic_string_view<_CharT>{__range.data(), __range.size()}, __ctx);
|
||||
} else {
|
||||
std::formatter<basic_string<_CharT>, _CharT> __formatter;
|
||||
if (__debug_format)
|
||||
__formatter.set_debug_format();
|
||||
// P2106's from_range has not been implemented yet. Instead use a simple
|
||||
// copy operation.
|
||||
// TODO FMT use basic_string's "from_range" constructor.
|
||||
// return std::formatter<basic_string<_CharT>, _CharT>{}.format(basic_string<_CharT>{from_range, __range}, __ctx);
|
||||
basic_string<_CharT> __str;
|
||||
ranges::copy(__range, back_insert_iterator{__str});
|
||||
return __formatter.format(__str, __ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_as_sequence(_Rp&& __range, _FormatContext& __ctx) const {
|
||||
__ctx.advance_to(ranges::copy(__opening_bracket_, __ctx.out()).out);
|
||||
bool __use_separator = false;
|
||||
for (auto&& __e : __range) {
|
||||
if (__use_separator)
|
||||
__ctx.advance_to(ranges::copy(__separator_, __ctx.out()).out);
|
||||
else
|
||||
__use_separator = true;
|
||||
|
||||
__ctx.advance_to(__underlying_.format(__e, __ctx));
|
||||
}
|
||||
|
||||
return ranges::copy(__closing_bracket_, __ctx.out()).out;
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left};
|
||||
|
||||
private:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(const _CharT*& __begin, const _CharT* __end) {
|
||||
switch (*__begin) {
|
||||
case _CharT('m'):
|
||||
if constexpr (__fmt_pair_like<_Tp>) {
|
||||
set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
|
||||
set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", "));
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type m requires two elements for a pair or tuple");
|
||||
break;
|
||||
|
||||
case _CharT('s'):
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
__parser_.__type_ = __format_spec::__type::__string;
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type s requires formatting a character type");
|
||||
break;
|
||||
|
||||
case _CharT('?'):
|
||||
++__begin;
|
||||
if (__begin == __end || *__begin != _CharT('s'))
|
||||
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
__parser_.__type_ = __format_spec::__type::__debug;
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type ?s requires formatting a character type");
|
||||
}
|
||||
}
|
||||
|
||||
formatter<_Tp, _CharT> __underlying_;
|
||||
basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", ");
|
||||
basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "[");
|
||||
basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "]");
|
||||
};
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_RANGE_FORMATTER_H
|
@ -25,6 +25,7 @@ struct allocation_result {
|
||||
_Pointer ptr;
|
||||
size_t count;
|
||||
};
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(allocation_result);
|
||||
|
||||
template <class _Alloc>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
|
@ -130,6 +130,11 @@ namespace std {
|
||||
requires same_as<R, remove_cvref_t<R>>
|
||||
constexpr range_format format_kind<R> = see below; // since C++23
|
||||
|
||||
// [format.range.formatter], class template range_formatter
|
||||
template<class T, class charT = char>
|
||||
requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
class range_formatter; // 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
|
||||
@ -194,6 +199,7 @@ namespace std {
|
||||
#include <__format/formatter_tuple.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__format/range_default_formatter.h>
|
||||
#include <__format/range_formatter.h>
|
||||
#include <__format/unicode.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -871,6 +871,7 @@ module std [system] {
|
||||
module formatter_tuple { private header "__format/formatter_tuple.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 range_formatter { private header "__format/range_formatter.h" }
|
||||
module unicode { private header "__format/unicode.h" }
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +359,7 @@ END-SCRIPT
|
||||
#include <__format/formatter_tuple.h> // expected-error@*:* {{use of private header from outside its module: '__format/formatter_tuple.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/range_formatter.h> // expected-error@*:* {{use of private header from outside its module: '__format/range_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'}}
|
||||
|
@ -359,6 +359,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list algorithm
|
||||
forward_list atomic
|
||||
|
|
@ -359,6 +359,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list algorithm
|
||||
forward_list atomic
|
||||
|
|
@ -361,6 +361,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list algorithm
|
||||
forward_list atomic
|
||||
|
|
@ -361,6 +361,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list algorithm
|
||||
forward_list atomic
|
||||
|
|
@ -125,6 +125,7 @@ chrono string
|
||||
chrono string_view
|
||||
chrono tuple
|
||||
chrono type_traits
|
||||
chrono vector
|
||||
chrono version
|
||||
cinttypes cstdint
|
||||
cmath type_traits
|
||||
@ -369,6 +370,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list algorithm
|
||||
forward_list atomic
|
||||
|
|
@ -95,6 +95,7 @@ chrono string
|
||||
chrono string_view
|
||||
chrono tuple
|
||||
chrono type_traits
|
||||
chrono vector
|
||||
chrono version
|
||||
cinttypes cstdint
|
||||
cmath version
|
||||
@ -277,6 +278,7 @@ format string
|
||||
format string_view
|
||||
format tuple
|
||||
format type_traits
|
||||
format vector
|
||||
format version
|
||||
forward_list compare
|
||||
forward_list cstddef
|
||||
|
|
@ -200,11 +200,11 @@ void test_P1636() {
|
||||
// TODO validate whether the test is correct after the paper has been accepted.
|
||||
template <class CharT>
|
||||
void test_P2286() {
|
||||
assert_is_not_formattable<std::array<int, 42>, CharT>();
|
||||
assert_is_not_formattable<std::vector<int>, CharT>();
|
||||
assert_is_not_formattable<std::deque<int>, CharT>();
|
||||
assert_is_not_formattable<std::forward_list<int>, CharT>();
|
||||
assert_is_not_formattable<std::list<int>, CharT>();
|
||||
assert_is_formattable<std::array<int, 42>, CharT>();
|
||||
assert_is_formattable<std::vector<int>, CharT>();
|
||||
assert_is_formattable<std::deque<int>, CharT>();
|
||||
assert_is_formattable<std::forward_list<int>, CharT>();
|
||||
assert_is_formattable<std::list<int>, CharT>();
|
||||
|
||||
assert_is_not_formattable<std::set<int>, CharT>();
|
||||
assert_is_not_formattable<std::map<int, int>, CharT>();
|
||||
@ -220,9 +220,9 @@ void test_P2286() {
|
||||
assert_is_not_formattable<std::queue<int>, CharT>();
|
||||
assert_is_not_formattable<std::priority_queue<int>, CharT>();
|
||||
|
||||
assert_is_not_formattable<std::span<int>, CharT>();
|
||||
assert_is_formattable<std::span<int>, CharT>();
|
||||
|
||||
assert_is_not_formattable<std::valarray<int>, CharT>();
|
||||
assert_is_formattable<std::valarray<int>, CharT>();
|
||||
|
||||
assert_is_formattable<std::pair<int, int>, CharT>();
|
||||
assert_is_formattable<std::tuple<int>, CharT>();
|
||||
|
@ -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, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter;
|
||||
|
||||
// template<class... Args>
|
||||
// string format(format_string<Args...> fmt, Args&&... args);
|
||||
// template<class... Args>
|
||||
// wstring format(wformat_string<Args...> fmt, Args&&... args);
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "format.functions.tests.h"
|
||||
#include "test_format_string.h"
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
|
||||
auto test = []<class CharT, class... Args>(
|
||||
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
|
||||
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
|
||||
TEST_REQUIRE(
|
||||
out == expected,
|
||||
test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
|
||||
};
|
||||
|
||||
auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, Args&&...) {
|
||||
// After P2216 most exceptions thrown by std::format become ill-formed.
|
||||
// Therefore this tests does nothing.
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
format_tests<char>(test, test_exception);
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
format_tests<wchar_t>(test, test_exception);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter;
|
||||
|
||||
// string vformat(string_view fmt, format_args args);
|
||||
// wstring vformat(wstring_view fmt, wformat_args args);
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "format.functions.tests.h"
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
|
||||
auto test = []<class CharT, class... Args>(
|
||||
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) {
|
||||
std::basic_string<CharT> out = std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
|
||||
TEST_REQUIRE(
|
||||
out == expected,
|
||||
test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
|
||||
};
|
||||
|
||||
auto test_exception =
|
||||
[]<class CharT, class... Args>(
|
||||
[[maybe_unused]] std::string_view what,
|
||||
[[maybe_unused]] std::basic_string_view<CharT> fmt,
|
||||
[[maybe_unused]] Args&&... args) {
|
||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||
try {
|
||||
TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
|
||||
TEST_FAIL(test_concat_message("\nFormat string ", fmt, "\nDidn't throw an exception.\n"));
|
||||
} catch (const std::format_error& e) {
|
||||
TEST_LIBCPP_REQUIRE(
|
||||
e.what() == what,
|
||||
test_concat_message(
|
||||
"\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||
|
||||
return;
|
||||
}
|
||||
assert(false);
|
||||
#endif
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
format_tests<char>(test, test_exception);
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
format_tests<wchar_t>(test, test_exception);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter
|
||||
|
||||
// template<class FormatContext>
|
||||
// typename FormatContext::iterator
|
||||
// format(const T& ref, FormatContext& ctx) const;
|
||||
|
||||
// Note this tests the basics of this function. It's tested in more detail in
|
||||
// the format functions test.
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <format>
|
||||
#include <vector>
|
||||
|
||||
#include "test_format_context.h"
|
||||
#include "test_macros.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class StringViewT>
|
||||
void test_format(StringViewT expected, std::vector<int> arg) {
|
||||
using CharT = typename StringViewT::value_type;
|
||||
using String = std::basic_string<CharT>;
|
||||
using OutIt = std::back_insert_iterator<String>;
|
||||
using FormatCtxT = std::basic_format_context<OutIt, CharT>;
|
||||
|
||||
const std::range_formatter<int, CharT> formatter;
|
||||
|
||||
String result;
|
||||
OutIt out = std::back_inserter(result);
|
||||
FormatCtxT format_ctx = test_format_context_create<OutIt, CharT>(out, std::make_format_args<FormatCtxT>(arg));
|
||||
formatter.format(arg, format_ctx);
|
||||
assert(result == expected);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void test_fmt() {
|
||||
test_format(SV("[1]"), std::vector<int>{1});
|
||||
test_format(SV("[0]"), std::vector<int>{0});
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_fmt<char>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test_fmt<wchar_t>();
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter
|
||||
|
||||
// template<class ParseContext>
|
||||
// constexpr typename ParseContext::iterator
|
||||
// parse(ParseContext& ctx);
|
||||
|
||||
// Note this tests the basics of this function. It's tested in more detail in
|
||||
// the format functions test.
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <format>
|
||||
|
||||
#include "test_format_context.h"
|
||||
#include "test_macros.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class StringViewT>
|
||||
constexpr void test_parse(StringViewT fmt) {
|
||||
using CharT = typename StringViewT::value_type;
|
||||
auto parse_ctx = std::basic_format_parse_context<CharT>(fmt);
|
||||
std::range_formatter<int, CharT> formatter;
|
||||
static_assert(std::semiregular<decltype(formatter)>);
|
||||
|
||||
std::same_as<typename StringViewT::iterator> auto it = formatter.parse(parse_ctx);
|
||||
assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}'));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_fmt() {
|
||||
test_parse(SV(""));
|
||||
test_parse(SV(":d"));
|
||||
|
||||
test_parse(SV("}"));
|
||||
test_parse(SV(":d}"));
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_fmt<char>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test_fmt<wchar_t>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter
|
||||
|
||||
// constexpr void constexpr void set_brackets(basic_string_view<charT> opening,
|
||||
// basic_string_view<charT> closing);
|
||||
|
||||
// Note this tests the basics of this function. It's tested in more detail in
|
||||
// the format functions test.
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "make_string.h"
|
||||
#include "test_format_context.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_setter() {
|
||||
std::range_formatter<int, CharT> formatter;
|
||||
formatter.set_brackets(SV("open"), SV("close"));
|
||||
|
||||
// Note there is no direct way to validate this function modified the object.
|
||||
if (!std::is_constant_evaluated()) {
|
||||
using String = std::basic_string<CharT>;
|
||||
using OutIt = std::back_insert_iterator<String>;
|
||||
using FormatCtxT = std::basic_format_context<OutIt, CharT>;
|
||||
|
||||
String result;
|
||||
OutIt out = std::back_inserter(result);
|
||||
FormatCtxT format_ctx = test_format_context_create<OutIt, CharT>(out, std::make_format_args<FormatCtxT>());
|
||||
formatter.format(std::vector<int>{0, 42, 99}, format_ctx);
|
||||
assert(result == SV("open0, 42, 99close"));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_setter<char>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test_setter<wchar_t>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter
|
||||
|
||||
// constexpr void set_separator(basic_string_view<charT> sep);
|
||||
|
||||
// Note this tests the basics of this function. It's tested in more detail in
|
||||
// the format functions test.
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "make_string.h"
|
||||
#include "test_format_context.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_setter() {
|
||||
std::range_formatter<int, CharT> formatter;
|
||||
formatter.set_separator(SV("sep"));
|
||||
|
||||
// Note there is no direct way to validate this function modified the object.
|
||||
if (!std::is_constant_evaluated()) {
|
||||
using String = std::basic_string<CharT>;
|
||||
using OutIt = std::back_insert_iterator<String>;
|
||||
using FormatCtxT = std::basic_format_context<OutIt, CharT>;
|
||||
|
||||
String result;
|
||||
OutIt out = std::back_inserter(result);
|
||||
FormatCtxT format_ctx = test_format_context_create<OutIt, CharT>(out, std::make_format_args<FormatCtxT>());
|
||||
formatter.format(std::vector<int>{0, 42, 99}, format_ctx);
|
||||
assert(result == SV("[0sep42sep99]"));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_setter<char>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test_setter<wchar_t>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -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, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class T, class charT = char>
|
||||
// requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
|
||||
// class range_formatter
|
||||
|
||||
// constexpr formatter<T, charT>& underlying();
|
||||
// constexpr const formatter<T, charT>& underlying() const;
|
||||
|
||||
#include <concepts>
|
||||
#include <format>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test_underlying() {
|
||||
{
|
||||
std::range_formatter<int, CharT> formatter;
|
||||
[[maybe_unused]] std::same_as<std::formatter<int, CharT>&> decltype(auto) underlying = formatter.underlying();
|
||||
}
|
||||
{
|
||||
const std::range_formatter<int, CharT> formatter;
|
||||
[[maybe_unused]] std::same_as<const std::formatter<int, CharT>&> decltype(auto) underlying = formatter.underlying();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_underlying<char>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test_underlying<wchar_t>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -8,6 +8,9 @@
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-format
|
||||
|
||||
// TODO FMT Fix this test using GCC, it currently times out.
|
||||
// UNSUPPORTED: gcc-12
|
||||
|
||||
// This test requires the dylib support introduced in D92214.
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}}
|
||||
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}}
|
||||
|
@ -279,7 +279,7 @@ template <class CharT, class TestFunction, class ExceptionTest, class Nested>
|
||||
void test_nested(TestFunction check, ExceptionTest check_exception, Nested&& input) {
|
||||
// [format.formatter.spec]/2
|
||||
// A debug-enabled specialization of formatter additionally provides a
|
||||
// public, constexpr, non-static member function set_debug_format()
|
||||
// public, constexpr, non-static member function set_debug_format()
|
||||
// which modifies the state of the formatter to be as if the type of the
|
||||
// std-format-spec parsed by the last call to parse were ?.
|
||||
// pair and tuple are not debug-enabled specializations to the
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
|
||||
#include "make_string.h"
|
||||
|
||||
@ -129,4 +130,57 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// Creates format string for the invalid types.
|
||||
//
|
||||
// valid contains a list of types that are valid.
|
||||
// - The type ?s is the only type requiring 2 characters, use S for that type.
|
||||
// - Whether n is a type or not depends on the context, is is always used.
|
||||
//
|
||||
// The return value is a collection of basic_strings, instead of
|
||||
// basic_string_views since the values are temporaries.
|
||||
namespace detail {
|
||||
template <class CharT, size_t N>
|
||||
std::basic_string<CharT> get_colons() {
|
||||
static std::basic_string<CharT> result(N, CharT(':'));
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr std::string_view get_format_types() {
|
||||
return "aAbBcdeEfFgGopsxX"
|
||||
#if TEST_STD_VER > 20
|
||||
"?"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
template <class CharT, /*format_types types,*/ size_t N>
|
||||
std::vector<std::basic_string<CharT>> fmt_invalid_types(std::string_view valid) {
|
||||
// std::ranges::to is not available in C++20.
|
||||
std::vector<std::basic_string<CharT>> result;
|
||||
std::ranges::copy(
|
||||
get_format_types() | std::views::filter([&](char type) { return valid.find(type) == std::string_view::npos; }) |
|
||||
std::views::transform([&](char type) { return std::format(SV("{{{}{}}}"), get_colons<CharT, N>(), type); }),
|
||||
std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Creates format string for the invalid types.
|
||||
//
|
||||
// valid contains a list of types that are valid.
|
||||
//
|
||||
// The return value is a collection of basic_strings, instead of
|
||||
// basic_string_views since the values are temporaries.
|
||||
template <class CharT>
|
||||
std::vector<std::basic_string<CharT>> fmt_invalid_types(std::string_view valid) {
|
||||
return detail::fmt_invalid_types<CharT, 1>(valid);
|
||||
}
|
||||
|
||||
// Like fmt_invalid_types but when the format spec is for an underlying formatter.
|
||||
template <class CharT>
|
||||
std::vector<std::basic_string<CharT>> fmt_invalid_nested_types(std::string_view valid) {
|
||||
return detail::fmt_invalid_types<CharT, 2>(valid);
|
||||
}
|
||||
|
||||
#endif // TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
|
||||
|
Loading…
Reference in New Issue
Block a user