Release Cosmopolitan v3.6.0

This release is an atomic upgrade to GCC 14.1.0 with C23 and C++23
This commit is contained in:
Justine Tunney 2024-07-23 03:16:17 -07:00
parent 62ace3623a
commit 5660ec4741
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
1585 changed files with 117353 additions and 271644 deletions

View file

@ -71,7 +71,7 @@ public:
__obj_(__obj) {}
_LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
__ptr_ = __ptr;
__ptr_ = __ptr;
__capacity_ = __capacity;
}
@ -95,7 +95,7 @@ public:
_LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
// When the underlying iterator is a simple iterator the __capacity_ is
// infinite. For a string or container back_inserter it isn't. This means
// adding a large string the the buffer can cause some overhead. In that
// that adding a large string to the buffer can cause some overhead. In that
// case a better approach could be:
// - flush the buffer
// - container.append(__str.begin(), __str.end());
@ -107,19 +107,19 @@ public:
size_t __n = __str.size();
__flush_on_overflow(__n);
if (__n <= __capacity_) {
_VSTD::copy_n(__str.data(), __n, _VSTD::addressof(__ptr_[__size_]));
if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
__size_ += __n;
return;
}
// The output doesn't fit in the internal buffer.
// Copy the data in "__capacity_" sized chunks.
_LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
const _InCharT* __first = __str.data();
do {
size_t __chunk = _VSTD::min(__n, __capacity_);
_VSTD::copy_n(__first, __chunk, _VSTD::addressof(__ptr_[__size_]));
size_t __chunk = std::min(__n, __capacity_);
std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
__size_ = __chunk;
__first += __chunk;
__n -= __chunk;
@ -130,24 +130,26 @@ public:
/// A std::transform wrapper.
///
/// Like @ref __copy it may need to do type conversion.
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");
template <contiguous_iterator _Iterator,
class _UnaryOperation,
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
__flush_on_overflow(__n);
if (__n <= __capacity_) {
_VSTD::transform(__first, __last, _VSTD::addressof(__ptr_[__size_]), _VSTD::move(__operation));
if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));
__size_ += __n;
return;
}
// The output doesn't fit in the internal buffer.
// Transform the data in "__capacity_" sized chunks.
_LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
do {
size_t __chunk = _VSTD::min(__n, __capacity_);
_VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation);
size_t __chunk = std::min(__n, __capacity_);
std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
__size_ = __chunk;
__first += __chunk;
__n -= __chunk;
@ -158,18 +160,18 @@ public:
/// A \c fill_n wrapper.
_LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
__flush_on_overflow(__n);
if (__n <= __capacity_) {
_VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __n, __value);
if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);
__size_ += __n;
return;
}
// The output doesn't fit in the internal buffer.
// Fill the buffer in "__capacity_" sized chunks.
_LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
do {
size_t __chunk = _VSTD::min(__n, __capacity_);
_VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value);
size_t __chunk = std::min(__n, __capacity_);
std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
__size_ = __chunk;
__n -= __chunk;
__flush();
@ -251,19 +253,18 @@ template <__fmt_char_type _CharT>
class _LIBCPP_TEMPLATE_VIS __direct_storage {};
template <class _OutIt, class _CharT>
concept __enable_direct_output = __fmt_char_type<_CharT> &&
concept __enable_direct_output =
__fmt_char_type<_CharT> &&
(same_as<_OutIt, _CharT*>
#ifndef _LIBCPP_ENABLE_DEBUG_MODE
|| same_as<_OutIt, __wrap_iter<_CharT*>>
#endif
);
// TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
// `#ifdef`.
|| same_as<_OutIt, __wrap_iter<_CharT*>>);
/// Write policy for directly writing to the underlying output.
template <class _OutIt, __fmt_char_type _CharT>
class _LIBCPP_TEMPLATE_VIS __writer_direct {
public:
_LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it)
: __out_it_(__out_it) {}
_LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}
_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
@ -281,8 +282,7 @@ private:
template <class _OutIt, __fmt_char_type _CharT>
class _LIBCPP_TEMPLATE_VIS __writer_iterator {
public:
_LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it)
: __out_it_{_VSTD::move(__out_it)} {}
_LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {}
_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
@ -304,7 +304,8 @@ private:
template <class _Container>
concept __insertable =
__enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
requires(_Container& __t, add_pointer_t<typename _Container::value_type> __first,
requires(_Container& __t,
add_pointer_t<typename _Container::value_type> __first,
add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
/// Extract the container type of a \ref back_insert_iterator.
@ -343,28 +344,29 @@ class _LIBCPP_TEMPLATE_VIS __writer_selector {
using _Container = typename __back_insert_iterator_container<_OutIt>::type;
public:
using type = conditional_t<!same_as<_Container, void>, __writer_container<_Container>,
conditional_t<__enable_direct_output<_OutIt, _CharT>, __writer_direct<_OutIt, _CharT>,
__writer_iterator<_OutIt, _CharT>>>;
using type =
conditional_t<!same_as<_Container, void>,
__writer_container<_Container>,
conditional_t<__enable_direct_output<_OutIt, _CharT>,
__writer_direct<_OutIt, _CharT>,
__writer_iterator<_OutIt, _CharT>>>;
};
/// The generic formatting buffer.
template <class _OutIt, __fmt_char_type _CharT>
requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS
__format_buffer {
requires(output_iterator<_OutIt, const _CharT&>)
class _LIBCPP_TEMPLATE_VIS __format_buffer {
using _Storage =
conditional_t<__enable_direct_output<_OutIt, _CharT>,
__direct_storage<_CharT>, __internal_storage<_CharT>>;
conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;
public:
_LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
requires(same_as<_Storage, __internal_storage<_CharT>>)
: __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(_VSTD::move(__out_it)) {}
: __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}
_LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires(
same_as<_Storage, __direct_storage<_CharT>>)
: __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this),
__writer_(_VSTD::move(__out_it)) {}
_LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
requires(same_as<_Storage, __direct_storage<_CharT>>)
: __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
@ -372,7 +374,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
__output_.__flush();
return _VSTD::move(__writer_).__out_it();
return std::move(__writer_).__out_it();
}
private:
@ -411,11 +413,11 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
public:
_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
: __writer_(_VSTD::move(__out_it)), __max_size_(_VSTD::max(_Size(0), __max_size)) {}
: __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
if (_Size(__size_) <= __max_size_)
__writer_.__flush(__ptr, _VSTD::min(_Size(__n), __max_size_ - __size_));
__writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));
__size_ += __n;
}
@ -441,8 +443,8 @@ class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
public:
_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
: __output_(_VSTD::__unwrap_iter(__out_it), __max_size, this),
__writer_(_VSTD::move(__out_it)),
: __output_(std::__unwrap_iter(__out_it), __max_size, this),
__writer_(std::move(__out_it)),
__max_size_(__max_size) {
if (__max_size <= 0) [[unlikely]]
__output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
@ -466,7 +468,7 @@ public:
} else if (__size_ < __max_size_) {
// Copies a part of the internal buffer to the output up to n characters.
// See __output_buffer<_CharT>::__flush_on_overflow for more information.
_Size __s = _VSTD::min(_Size(__n), __max_size_ - __size_);
_Size __s = std::min(_Size(__n), __max_size_ - __size_);
std::copy_n(__ptr, __s, __writer_.__out_it());
__writer_.__flush(__ptr, __s);
}
@ -493,12 +495,12 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
public:
_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
: _Base(_VSTD::move(__out_it), __max_size) {}
: _Base(std::move(__out_it), __max_size) {}
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
this->__output_.__flush();
return {_VSTD::move(this->__writer_).__out_it(), this->__size_};
return {std::move(this->__writer_).__out_it(), this->__size_};
}
};
@ -529,6 +531,7 @@ public:
struct __iterator {
using difference_type = ptrdiff_t;
using value_type = _CharT;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
: __buffer_(std::addressof(__buffer)) {}
@ -551,7 +554,14 @@ public:
__retarget_buffer& operator=(const __retarget_buffer&) = delete;
_LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
auto __result = std::__allocate_at_least(__alloc_, __size_hint ? __size_hint : 256 / sizeof(_CharT));
// When the initial size is very small a lot of resizes happen
// when elements added. So use a hard-coded minimum size.
//
// Note a size < 2 will not work
// - 0 there is no buffer, while push_back requires 1 empty element.
// - 1 multiplied by the grow factor is 1 and thus the buffer never
// grows.
auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
__ptr_ = __result.ptr;
__capacity_ = __result.count;
}
@ -582,9 +592,11 @@ public:
__size_ += __n;
}
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");
template <contiguous_iterator _Iterator,
class _UnaryOperation,
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
size_t __n = static_cast<size_t>(__last - __first);
if (__size_ + __n >= __capacity_)
@ -611,12 +623,12 @@ private:
_LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
_LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
_LIBCPP_ASSERT(__capacity > __capacity_, "the buffer must grow");
_LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
auto __result = std::__allocate_at_least(__alloc_, __capacity);
auto __guard = std::__make_exception_guard([&] {
allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
});
// This shouldn't throw, but just to be safe. Not that at -O1 this
// This shouldn't throw, but just to be safe. Note that at -O1 this
// guard is optimized away so there is no runtime overhead.
std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
__guard.__complete();

View file

@ -13,11 +13,14 @@
#include <__concepts/same_as.h>
#include <__concepts/semiregular.h>
#include <__config>
#include <__format/format_fwd.h>
#include <__format/format_parse_context.h>
#include <__fwd/format.h>
#include <__fwd/tuple.h>
#include <__tuple/tuple_size.h>
#include <__type_traits/is_specialization.h>
#include <__type_traits/remove_const.h>
#include <__type_traits/remove_reference.h>
#include <__utility/pair.h>
#include <tuple>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -43,17 +46,21 @@ concept __fmt_char_type =
template <class _CharT>
using __fmt_iter_for = _CharT*;
template <class _Tp, class _Context, class _Formatter = typename _Context::template formatter_type<remove_const_t<_Tp>>>
concept __formattable_with =
semiregular<_Formatter> &&
requires(_Formatter& __f,
const _Formatter& __cf,
_Tp&& __t,
_Context __fc,
basic_format_parse_context<typename _Context::char_type> __pc) {
{ __f.parse(__pc) } -> same_as<typename decltype(__pc)::iterator>;
{ __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
};
template <class _Tp, class _CharT>
concept __formattable =
(semiregular<formatter<remove_cvref_t<_Tp>, _CharT>>) &&
requires(formatter<remove_cvref_t<_Tp>, _CharT> __f,
const formatter<remove_cvref_t<_Tp>, _CharT> __cf,
_Tp __t,
basic_format_context<__fmt_iter_for<_CharT>, _CharT> __fc,
basic_format_parse_context<_CharT> __pc) {
{ __f.parse(__pc) } -> same_as<typename basic_format_parse_context<_CharT>::iterator>;
{ __cf.format(__t, __fc) } -> same_as<__fmt_iter_for<_CharT>>;
};
__formattable_with<remove_reference_t<_Tp>, basic_format_context<__fmt_iter_for<_CharT>, _CharT>>;
# if _LIBCPP_STD_VER >= 23
template <class _Tp, class _CharT>
@ -69,7 +76,7 @@ concept __fmt_pair_like =
__is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2);
# endif //_LIBCPP_STD_VER >= 23
#endif //_LIBCPP_STD_VER >= 20
#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD

View file

@ -10,17 +10,19 @@
#ifndef _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H
#define _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H
#include <__availability>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
#include <__config>
#include <__format/concepts.h>
#include <__format/formatter.h>
#include <__format/range_default_formatter.h>
#include <__ranges/all.h>
#include <__fwd/queue.h>
#include <__fwd/stack.h>
#include <__ranges/ref_view.h>
#include <__type_traits/is_const.h>
#include <__type_traits/maybe_const.h>
#include <queue>
#include <stack>
_LIBCPP_BEGIN_NAMESPACE_STD

File diff suppressed because it is too large Load diff

View file

@ -124,7 +124,8 @@ enum class __property : uint8_t {
/// this approach uses less space for the data and is about 4% faster in the
/// following benchmark.
/// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp
inline constexpr uint32_t __entries[1496] = {
// clang-format off
_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = {
0x00000091,
0x00005005,
0x00005811,
@ -1621,6 +1622,7 @@ inline constexpr uint32_t __entries[1496] = {
0x707787f1,
0x707b87f1,
0x707f80f1};
// clang-format on
/// Returns the extended grapheme cluster bondary property of a code point.
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept {

View file

@ -13,24 +13,27 @@
#include <__assert>
#include <__concepts/arithmetic.h>
#include <__config>
#include <__format/format_error.h>
#include <__format/format_fwd.h>
#include <__format/concepts.h>
#include <__format/format_parse_context.h>
#include <__functional/invoke.h>
#include <__fwd/format.h>
#include <__memory/addressof.h>
#include <__type_traits/conditional.h>
#include <__type_traits/is_const.h>
#include <__utility/declval.h>
#include <__type_traits/remove_const.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <__variant/monostate.h>
#include <string>
#include <cstdint>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
@ -54,7 +57,7 @@ namespace __format {
/// handle to satisfy the user observable behaviour. The internal function
/// __visit_format_arg doesn't do this wrapping. So in the format functions
/// this function is used to avoid unneeded overhead.
enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t {
enum class __arg_t : uint8_t {
__none,
__boolean,
__char_type,
@ -74,17 +77,17 @@ enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t {
};
inline constexpr unsigned __packed_arg_t_bits = 5;
inline constexpr uint8_t __packed_arg_t_mask = 0x1f;
inline constexpr uint8_t __packed_arg_t_mask = 0x1f;
inline constexpr unsigned __packed_types_storage_bits = 64;
inline constexpr unsigned __packed_types_max = __packed_types_storage_bits / __packed_arg_t_bits;
inline constexpr unsigned __packed_types_max = __packed_types_storage_bits / __packed_arg_t_bits;
_LIBCPP_HIDE_FROM_ABI
constexpr bool __use_packed_format_arg_store(size_t __size) { return __size <= __packed_types_max; }
_LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size) {
return __size <= __packed_types_max;
}
_LIBCPP_HIDE_FROM_ABI
constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
_LIBCPP_ASSERT(__id <= __packed_types_max, "");
_LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
_LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, "");
if (__id > 0)
__types >>= __id * __packed_arg_t_bits;
@ -94,58 +97,110 @@ constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
} // namespace __format
// This function is not user obervable, so it can directly use the non-standard
// This function is not user observable, so it can directly use the non-standard
// types of the "variant". See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto)
__visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
_LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
case __format::__arg_t::__none:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
case __format::__arg_t::__boolean:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
case __format::__arg_t::__char_type:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
case __format::__arg_t::__int:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__int_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
case __format::__arg_t::__long_long:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
case __format::__arg_t::__i128:
# ifndef _LIBCPP_HAS_NO_INT128
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__i128_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__unsigned:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
case __format::__arg_t::__unsigned_long_long:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
case __format::__arg_t::__u128:
# ifndef _LIBCPP_HAS_NO_INT128
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__u128_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__float:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__float_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
case __format::__arg_t::__double:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__double_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
case __format::__arg_t::__long_double:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
case __format::__arg_t::__const_char_type_ptr:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
case __format::__arg_t::__string_view:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
case __format::__arg_t::__ptr:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
case __format::__arg_t::__handle:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis),
typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
return std::invoke(
std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
}
__libcpp_unreachable();
}
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
template <class _Rp, class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
case __format::__arg_t::__none:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
case __format::__arg_t::__boolean:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
case __format::__arg_t::__char_type:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
case __format::__arg_t::__int:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
case __format::__arg_t::__long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
case __format::__arg_t::__i128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__unsigned:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
case __format::__arg_t::__unsigned_long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
case __format::__arg_t::__u128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__float:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
case __format::__arg_t::__double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
case __format::__arg_t::__long_double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
case __format::__arg_t::__const_char_type_ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
case __format::__arg_t::__string_view:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
case __format::__arg_t::__ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
case __format::__arg_t::__handle:
return std::invoke_r<_Rp>(
std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
}
__libcpp_unreachable();
}
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
/// Contains the values used in basic_format_arg.
///
/// This is a separate type so it's possible to store the values and types in
@ -158,18 +213,14 @@ public:
/// Contains the implementation for basic_format_arg::handle.
struct __handle {
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI explicit __handle(_Tp&& __v) noexcept
: __ptr_(_VSTD::addressof(__v)),
_LIBCPP_HIDE_FROM_ABI explicit __handle(_Tp& __v) noexcept
: __ptr_(std::addressof(__v)),
__format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) {
using _Dp = remove_cvref_t<_Tp>;
using _Formatter = typename _Context::template formatter_type<_Dp>;
constexpr bool __const_formattable =
requires { _Formatter().format(std::declval<const _Dp&>(), std::declval<_Context&>()); };
using _Qp = conditional_t<__const_formattable, const _Dp, _Dp>;
using _Dp = remove_const_t<_Tp>;
using _Qp = conditional_t<__formattable_with<const _Dp, _Context>, const _Dp, _Dp>;
static_assert(__formattable_with<_Qp, _Context>, "Mandated by [format.arg]/10");
static_assert(__const_formattable || !is_const_v<remove_reference_t<_Tp>>, "Mandated by [format.arg]/18");
_Formatter __f;
typename _Context::template formatter_type<_Dp> __f;
__parse_ctx.advance_to(__f.parse(__parse_ctx));
__ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Dp*>(__ptr)), __ctx));
}) {}
@ -221,9 +272,7 @@ public:
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(basic_string_view<_CharT> __value) noexcept
: __string_view_(__value) {}
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const void* __value) noexcept : __ptr_(__value) {}
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle __value) noexcept
// TODO FMT Investigate why it doesn't work without the forward.
: __handle_(std::forward<__handle>(__value)) {}
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle&& __value) noexcept : __handle_(std::move(__value)) {}
};
template <class _Context>
@ -231,13 +280,56 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg {
public:
class _LIBCPP_TEMPLATE_VIS handle;
_LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept
: __type_{__format::__arg_t::__none} {}
_LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept : __type_{__format::__arg_t::__none} {}
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept {
return __type_ != __format::__arg_t::__none;
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; }
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor>
_LIBCPP_HIDE_FROM_ABI decltype(auto) visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
}
// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Rp, class _Visitor>
_LIBCPP_HIDE_FROM_ABI _Rp visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg<_Rp>(std::forward<_Visitor>(__vis), __arg);
}
}
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
private:
using char_type = typename _Context::char_type;
@ -264,8 +356,7 @@ public:
template <class _Context>
class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle {
public:
_LIBCPP_HIDE_FROM_ABI
void format(basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx) const {
_LIBCPP_HIDE_FROM_ABI void format(basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx) const {
__handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_);
}
@ -279,22 +370,25 @@ private:
// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto)
visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
_LIBCPP_DEPRECATED_IN_CXX26
# endif
_LIBCPP_HIDE_FROM_ABI decltype(auto)
visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
default:
return _VSTD::__visit_format_arg(_VSTD::forward<_Visitor>(__vis), __arg);
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
}
@ -302,4 +396,6 @@ visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_ARG_H

View file

@ -10,6 +10,10 @@
#ifndef _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
#define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.h>
#include <__config>
@ -17,8 +21,7 @@
#include <__format/format_arg.h>
#include <__type_traits/conditional.h>
#include <__type_traits/extent.h>
#include <__type_traits/is_same.h>
#include <__utility/forward.h>
#include <__type_traits/remove_const.h>
#include <string>
#include <string_view>
@ -148,23 +151,33 @@ consteval __arg_t __determine_arg_t() {
// The overload for not formattable types allows triggering the static
// assertion below.
template <class _Context, class _Tp>
requires(!__formattable<_Tp, typename _Context::char_type>)
requires(!__formattable_with<_Tp, _Context>)
consteval __arg_t __determine_arg_t() {
return __arg_t::__none;
}
// Pseudo constuctor for basic_format_arg
//
// Modeled after template<class T> explicit basic_format_arg(T& v) noexcept;
// [format.arg]/4-6
template <class _Context, class _Tp>
_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp&& __value) noexcept {
constexpr __arg_t __arg = __determine_arg_t<_Context, remove_cvref_t<_Tp>>();
_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __value) noexcept {
using _Dp = remove_const_t<_Tp>;
constexpr __arg_t __arg = __determine_arg_t<_Context, _Dp>();
static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");
static_assert(__formattable_with<_Tp, _Context>);
// Not all types can be used to directly initialize the
// __basic_format_arg_value. First handle all types needing adjustment, the
// final else requires no adjustment.
if constexpr (__arg == __arg_t::__char_type)
// On some platforms initializing a wchar_t from a char is a narrowing
// conversion.
return basic_format_arg<_Context>{__arg, static_cast<typename _Context::char_type>(__value)};
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
if constexpr (same_as<typename _Context::char_type, wchar_t> && same_as<_Dp, char>)
return basic_format_arg<_Context>{__arg, static_cast<wchar_t>(static_cast<unsigned char>(__value))};
else
# endif
return basic_format_arg<_Context>{__arg, __value};
else if constexpr (__arg == __arg_t::__int)
return basic_format_arg<_Context>{__arg, static_cast<int>(__value)};
else if constexpr (__arg == __arg_t::__long_long)
@ -175,9 +188,9 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp&& __val
return basic_format_arg<_Context>{__arg, static_cast<unsigned long long>(__value)};
else if constexpr (__arg == __arg_t::__string_view)
// Using std::size on a character array will add the NUL-terminator to the size.
if constexpr (is_array_v<remove_cvref_t<_Tp>>)
if constexpr (is_array_v<_Dp>)
return basic_format_arg<_Context>{
__arg, basic_string_view<typename _Context::char_type>{__value, extent_v<remove_cvref_t<_Tp>> - 1}};
__arg, basic_string_view<typename _Context::char_type>{__value, extent_v<_Dp> - 1}};
else
// When the _Traits or _Allocator are different an implicit conversion will
// fail.
@ -186,15 +199,14 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp&& __val
else if constexpr (__arg == __arg_t::__ptr)
return basic_format_arg<_Context>{__arg, static_cast<const void*>(__value)};
else if constexpr (__arg == __arg_t::__handle)
return basic_format_arg<_Context>{
__arg, typename __basic_format_arg_value<_Context>::__handle{_VSTD::forward<_Tp>(__value)}};
return basic_format_arg<_Context>{__arg, typename __basic_format_arg_value<_Context>::__handle{__value}};
else
return basic_format_arg<_Context>{__arg, __value};
}
template <class _Context, class... _Args>
_LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values,
_Args&&... __args) noexcept {
_LIBCPP_HIDE_FROM_ABI void
__create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept {
int __shift = 0;
(
[&] {
@ -211,27 +223,26 @@ _LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_fo
}
template <class _Context, class... _Args>
_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&&... __args) noexcept {
_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&... __args) noexcept {
([&] { *__data++ = __format::__create_format_arg<_Context>(__args); }(), ...);
}
template <class _Context, size_t N>
template <class _Context, size_t _Np>
struct __packed_format_arg_store {
__basic_format_arg_value<_Context> __values_[N];
uint64_t __types_;
__basic_format_arg_value<_Context> __values_[_Np];
uint64_t __types_ = 0;
};
template <class _Context, size_t N>
template <class _Context, size_t _Np>
struct __unpacked_format_arg_store {
basic_format_arg<_Context> __args_[N];
basic_format_arg<_Context> __args_[_Np];
};
} // namespace __format
template <class _Context, class... _Args>
struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
_LIBCPP_HIDE_FROM_ABI
__format_arg_store(_Args&... __args) noexcept {
_LIBCPP_HIDE_FROM_ABI __format_arg_store(_Args&... __args) noexcept {
if constexpr (sizeof...(_Args) != 0) {
if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args)))
__format::__create_packed_storage(__storage.__types_, __storage.__values_, __args...);
@ -240,9 +251,10 @@ struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
}
}
using _Storage = conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)),
__format::__packed_format_arg_store<_Context, sizeof...(_Args)>,
__format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>;
using _Storage =
conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)),
__format::__packed_format_arg_store<_Context, sizeof...(_Args)>,
__format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>;
_Storage __storage;
};

View file

@ -10,11 +10,10 @@
#ifndef _LIBCPP___FORMAT_FORMAT_ARGS_H
#define _LIBCPP___FORMAT_FORMAT_ARGS_H
#include <__availability>
#include <__config>
#include <__format/format_arg.h>
#include <__format/format_arg_store.h>
#include <__format/format_fwd.h>
#include <__fwd/format.h>
#include <cstddef>
#include <cstdint>
@ -29,22 +28,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Context>
class _LIBCPP_TEMPLATE_VIS basic_format_args {
public:
basic_format_args() noexcept = default;
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI basic_format_args(const __format_arg_store<_Context, _Args...>& __store) noexcept
: __size_(sizeof...(_Args)) {
if constexpr (sizeof...(_Args) != 0) {
if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args))) {
__values_ = __store.__storage.__values_;
__types_ = __store.__storage.__types_;
__types_ = __store.__storage.__types_;
} else
__args_ = __store.__storage.__args_;
}
}
_LIBCPP_HIDE_FROM_ABI
basic_format_arg<_Context> get(size_t __id) const noexcept {
_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> get(size_t __id) const noexcept {
if (__id >= __size_)
return basic_format_arg<_Context>{};

View file

@ -10,7 +10,6 @@
#ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H
#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H
#include <__availability>
#include <__concepts/same_as.h>
#include <__config>
#include <__format/buffer.h>
@ -18,7 +17,7 @@
#include <__format/format_arg_store.h>
#include <__format/format_args.h>
#include <__format/format_error.h>
#include <__format/format_fwd.h>
#include <__fwd/format.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/concepts.h>
#include <__memory/addressof.h>
@ -27,23 +26,26 @@
#include <cstddef>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
#include <locale>
#include <optional>
# include <__locale>
# include <optional>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
template <class _OutIt, class _CharT>
requires output_iterator<_OutIt, const _CharT&>
requires output_iterator<_OutIt, const _CharT&>
class _LIBCPP_TEMPLATE_VIS basic_format_context;
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
/**
* Helper to create a basic_format_context.
*
@ -51,32 +53,26 @@ class _LIBCPP_TEMPLATE_VIS basic_format_context;
*/
template <class _OutIt, class _CharT>
_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
__format_context_create(
_OutIt __out_it,
basic_format_args<basic_format_context<_OutIt, _CharT>> __args,
optional<_VSTD::locale>&& __loc = nullopt) {
return _VSTD::basic_format_context(_VSTD::move(__out_it), __args, _VSTD::move(__loc));
__format_context_create(_OutIt __out_it,
basic_format_args<basic_format_context<_OutIt, _CharT>> __args,
optional<std::locale>&& __loc = nullopt) {
return std::basic_format_context(std::move(__out_it), __args, std::move(__loc));
}
#else
# else
template <class _OutIt, class _CharT>
_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
__format_context_create(
_OutIt __out_it,
basic_format_args<basic_format_context<_OutIt, _CharT>> __args) {
return _VSTD::basic_format_context(_VSTD::move(__out_it), __args);
__format_context_create(_OutIt __out_it, basic_format_args<basic_format_context<_OutIt, _CharT>> __args) {
return std::basic_format_context(std::move(__out_it), __args);
}
#endif
# endif
using format_context =
basic_format_context<back_insert_iterator<__format::__output_buffer<char>>,
char>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wformat_context = basic_format_context<
back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>;
#endif
using format_context = basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, char>;
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wformat_context = basic_format_context< back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>;
# endif
template <class _OutIt, class _CharT>
requires output_iterator<_OutIt, const _CharT&>
requires output_iterator<_OutIt, const _CharT&>
class
// clang-format off
_LIBCPP_TEMPLATE_VIS
@ -85,29 +81,28 @@ class
// clang-format on
basic_format_context {
public:
using iterator = _OutIt;
using iterator = _OutIt;
using char_type = _CharT;
template <class _Tp>
using formatter_type = formatter<_Tp, _CharT>;
_LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context>
arg(size_t __id) const noexcept {
_LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
return __args_.get(__id);
}
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
_LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() {
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
_LIBCPP_HIDE_FROM_ABI std::locale locale() {
if (!__loc_)
__loc_ = _VSTD::locale{};
__loc_ = std::locale{};
return *__loc_;
}
#endif
# 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_;
basic_format_args<basic_format_context> __args_;
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
// The Standard doesn't specify how the locale is stored.
// [format.context]/6
@ -118,30 +113,27 @@ private:
// locale() is called and the optional has no value the value will be created.
// This allows the implementation to lazily create the locale.
// TODO FMT Validate whether lazy creation is the best solution.
optional<_VSTD::locale> __loc_;
optional<std::locale> __loc_;
template <class __OutIt, class __CharT>
friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT>
__format_context_create(__OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>,
optional<_VSTD::locale>&&);
template <class _OtherOutIt, class _OtherCharT>
friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> __format_context_create(
_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>, optional<std::locale>&&);
// Note: the Standard doesn't specify the required constructors.
_LIBCPP_HIDE_FROM_ABI
explicit basic_format_context(_OutIt __out_it,
basic_format_args<basic_format_context> __args,
optional<_VSTD::locale>&& __loc)
: __out_it_(_VSTD::move(__out_it)), __args_(__args),
__loc_(_VSTD::move(__loc)) {}
#else
template <class __OutIt, class __CharT>
friend _LIBCPP_HIDE_FROM_ABI basic_format_context<__OutIt, __CharT>
__format_context_create(__OutIt, basic_format_args<basic_format_context<__OutIt, __CharT>>);
_LIBCPP_HIDE_FROM_ABI explicit basic_format_context(
_OutIt __out_it, basic_format_args<basic_format_context> __args, optional<std::locale>&& __loc)
: __out_it_(std::move(__out_it)), __args_(__args), __loc_(std::move(__loc)) {}
# else
template <class _OtherOutIt, class _OtherCharT>
friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT>
__format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>);
_LIBCPP_HIDE_FROM_ABI
explicit basic_format_context(_OutIt __out_it,
basic_format_args<basic_format_context> __args)
: __out_it_(_VSTD::move(__out_it)), __args_(__args) {}
#endif
_LIBCPP_HIDE_FROM_ABI explicit basic_format_context(_OutIt __out_it, basic_format_args<basic_format_context> __args)
: __out_it_(std::move(__out_it)), __args_(__args) {}
# endif
basic_format_context(const basic_format_context&) = delete;
basic_format_context& operator=(const basic_format_context&) = delete;
};
// A specialization for __retarget_buffer
@ -161,8 +153,7 @@ private:
// 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
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
class _LIBCPP_TEMPLATE_VIS basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
public:
using iterator = typename __format::__retarget_buffer<_CharT>::__iterator;
using char_type = _CharT;
@ -177,20 +168,25 @@ public:
# 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));
auto __visitor = [&](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)};
};
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor));
# else
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id));
_LIBCPP_SUPPRESS_DEPRECATED_POP
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
}) {
}
@ -198,7 +194,7 @@ public:
return __arg_(__ctx_, __id);
}
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
_LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); }
_LIBCPP_HIDE_FROM_ABI std::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); }
@ -219,4 +215,6 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H

View file

@ -11,7 +11,7 @@
#define _LIBCPP___FORMAT_FORMAT_ERROR_H
#include <__config>
#include <cstdlib>
#include <__verbose_abort>
#include <stdexcept>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -24,25 +24,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_DIAGNOSTIC_PUSH
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables")
class _LIBCPP_EXCEPTION_ABI format_error : public runtime_error {
class _LIBCPP_EXPORTED_FROM_ABI format_error : public runtime_error {
public:
_LIBCPP_HIDE_FROM_ABI explicit format_error(const string& __s)
: runtime_error(__s) {}
_LIBCPP_HIDE_FROM_ABI explicit format_error(const char* __s)
: runtime_error(__s) {}
_LIBCPP_HIDE_FROM_ABI explicit format_error(const string& __s) : runtime_error(__s) {}
_LIBCPP_HIDE_FROM_ABI explicit format_error(const char* __s) : runtime_error(__s) {}
_LIBCPP_HIDE_FROM_ABI format_error(const format_error&) = default;
_LIBCPP_HIDE_FROM_ABI format_error& operator=(const format_error&) = default;
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
~format_error() noexcept override = default;
};
_LIBCPP_DIAGNOSTIC_POP
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void
__throw_format_error(const char* __s) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_format_error(const char* __s) {
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
throw format_error(__s);
#else
(void)__s;
_VSTD::abort();
#endif
# else
_LIBCPP_VERBOSE_ABORT("format_error was thrown in -fno-exceptions mode with message \"%s\"", __s);
# endif
}
#endif //_LIBCPP_STD_VER >= 20

View file

@ -11,11 +11,9 @@
#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
#include <__algorithm/clamp.h>
#include <__availability>
#include <__concepts/convertible_to.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__debug>
#include <__format/buffer.h>
#include <__format/format_arg.h>
#include <__format/format_arg_store.h>
@ -36,20 +34,23 @@
#include <__iterator/back_insert_iterator.h>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/readable_traits.h> // iter_value_t
#include <__iterator/iterator_traits.h> // iter_value_t
#include <__variant/monostate.h>
#include <array>
#include <string>
#include <string_view>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
#include <locale>
# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
@ -60,21 +61,21 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// to do this optimization now.
using format_args = basic_format_args<format_context>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wformat_args = basic_format_args<wformat_context>;
#endif
# endif
template <class _Context = format_context, class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&... __args) {
return std::__format_arg_store<_Context, _Args...>(__args...);
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&&... __args) {
return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&... __args) {
return std::__format_arg_store<wformat_context, _Args...>(__args...);
}
#endif
# endif
namespace __format {
@ -128,13 +129,13 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const {
if (__id >= __size_)
std::__throw_format_error("Argument index out of bounds");
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
return __args_[__id];
}
_LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const {
if (__id >= __size_)
std::__throw_format_error("Argument index out of bounds");
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
return __handles_[__id];
}
@ -189,9 +190,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_validate_argument(
// This function is not user facing, so it can directly use the non-standard types of the "variant".
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_format_parse_context<_CharT>& __parse_ctx,
__compile_time_basic_format_context<_CharT>& __ctx,
__arg_t __type) {
_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(
basic_format_parse_context<_CharT>& __parse_ctx,
__compile_time_basic_format_context<_CharT>& __ctx,
__arg_t __type) {
switch (__type) {
case __arg_t::__none:
std::__throw_format_error("Invalid argument");
@ -204,22 +206,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_forma
case __arg_t::__long_long:
return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx);
case __arg_t::__i128:
# ifndef _LIBCPP_HAS_NO_INT128
# ifndef _LIBCPP_HAS_NO_INT128
return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);
# else
# else
std::__throw_format_error("Invalid argument");
# endif
# endif
return;
case __arg_t::__unsigned:
return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx);
case __arg_t::__unsigned_long_long:
return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx);
case __arg_t::__u128:
# ifndef _LIBCPP_HAS_NO_INT128
# ifndef _LIBCPP_HAS_NO_INT128
return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);
# else
# else
std::__throw_format_error("Invalid argument");
# endif
# endif
return;
case __arg_t::__float:
return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx);
@ -241,11 +243,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg(basic_forma
template <contiguous_iterator _Iterator, class _ParseCtx, class _Ctx>
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator
__handle_replacement_field(_Iterator __begin, _Iterator __end,
_ParseCtx& __parse_ctx, _Ctx& __ctx) {
using _CharT = iter_value_t<_Iterator>;
__handle_replacement_field(_Iterator __begin, _Iterator __end, _ParseCtx& __parse_ctx, _Ctx& __ctx) {
using _CharT = iter_value_t<_Iterator>;
__format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx);
if (__r.__last == __end)
std::__throw_format_error("The argument index should end with a ':' or a '}'");
bool __parse = *__r.__last == _CharT(':');
switch (*__r.__last) {
case _CharT(':'):
@ -257,22 +261,22 @@ __handle_replacement_field(_Iterator __begin, _Iterator __end,
__parse_ctx.advance_to(__r.__last);
break;
default:
std::__throw_format_error("The replacement field arg-id should terminate at a ':' or '}'");
std::__throw_format_error("The argument index should end with a ':' or a '}'");
}
if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) {
__arg_t __type = __ctx.arg(__r.__value);
if (__type == __arg_t::__none)
std::__throw_format_error("Argument index out of bounds");
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
else if (__type == __arg_t::__handle)
__ctx.__handle(__r.__value).__parse(__parse_ctx);
else if (__parse)
__format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type);
} else
_VSTD::__visit_format_arg(
std::__visit_format_arg(
[&](auto __arg) {
if constexpr (same_as<decltype(__arg), monostate>)
std::__throw_format_error("Argument index out of bounds");
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
__arg.format(__parse_ctx, __ctx);
else {
@ -292,13 +296,12 @@ __handle_replacement_field(_Iterator __begin, _Iterator __end,
}
template <class _ParseCtx, class _Ctx>
_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator
__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
using _CharT = typename _ParseCtx::char_type;
static_assert(same_as<typename _Ctx::char_type, _CharT>);
auto __begin = __parse_ctx.begin();
auto __end = __parse_ctx.end();
auto __begin = __parse_ctx.begin();
auto __end = __parse_ctx.end();
typename _Ctx::iterator __out_it = __ctx.out();
while (__begin != __end) {
switch (*__begin) {
@ -308,9 +311,8 @@ __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
std::__throw_format_error("The format string terminates at a '{'");
if (*__begin != _CharT('{')) [[likely]] {
__ctx.advance_to(_VSTD::move(__out_it));
__begin =
__format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
__ctx.advance_to(std::move(__out_it));
__begin = __format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
__out_it = __ctx.out();
// The output is written and __begin points to the next character. So
@ -336,6 +338,30 @@ __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
} // namespace __format
# if _LIBCPP_STD_VER >= 26
template <class _CharT>
struct _LIBCPP_TEMPLATE_VIS __runtime_format_string {
private:
basic_string_view<_CharT> __str_;
template <class _Cp, class... _Args>
friend struct _LIBCPP_TEMPLATE_VIS basic_format_string;
public:
_LIBCPP_HIDE_FROM_ABI __runtime_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
__runtime_format_string(const __runtime_format_string&) = delete;
__runtime_format_string& operator=(const __runtime_format_string&) = delete;
};
_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<char> runtime_format(string_view __fmt) noexcept { return __fmt; }
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<wchar_t> runtime_format(wstring_view __fmt) noexcept {
return __fmt;
}
# endif
# endif //_LIBCPP_STD_VER >= 26
template <class _CharT, class... _Args>
struct _LIBCPP_TEMPLATE_VIS basic_format_string {
template <class _Tp>
@ -345,9 +371,10 @@ struct _LIBCPP_TEMPLATE_VIS basic_format_string {
_Context{__types_.data(), __handles_.data(), sizeof...(_Args)});
}
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept {
return __str_;
}
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept { return __str_; }
# if _LIBCPP_STD_VER >= 26
_LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {}
# endif
private:
basic_string_view<_CharT> __str_;
@ -357,20 +384,6 @@ private:
static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{
__format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...};
// TODO FMT remove this work-around when the AIX ICE has been resolved.
# if defined(_AIX) && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER < 1400
template <class _Tp>
static constexpr __format::__compile_time_handle<_CharT> __get_handle() {
__format::__compile_time_handle<_CharT> __handle;
if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
__handle.template __enable<_Tp>();
return __handle;
}
static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{
__get_handle<_Args>()...};
# else
static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] {
using _Tp = remove_cvref_t<_Args>;
__format::__compile_time_handle<_CharT> __handle;
@ -379,30 +392,29 @@ private:
return __handle;
}()...};
# endif
};
template <class... _Args>
using format_string = basic_format_string<char, type_identity_t<_Args>...>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
#endif
# endif
template <class _OutIt, class _CharT, class _FormatOutIt>
requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
__vformat_to(
_OutIt __out_it, basic_string_view<_CharT> __fmt,
basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
requires(output_iterator<_OutIt, const _CharT&>)
_LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(_OutIt __out_it,
basic_string_view<_CharT> __fmt,
basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
if constexpr (same_as<_OutIt, _FormatOutIt>)
return _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(_VSTD::move(__out_it), __args));
return std::__format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()}, std::__format_context_create(std::move(__out_it), __args));
else {
__format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
_VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
return _VSTD::move(__buffer).__out_it();
__format::__format_buffer<_OutIt, _CharT> __buffer{std::move(__out_it)};
std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
std::__format_context_create(__buffer.__make_output_iterator(), __args));
return std::move(__buffer).__out_it();
}
}
@ -410,268 +422,259 @@ requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
// https://reviews.llvm.org/D110499#inline-1180704
// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.
template <output_iterator<const char&> _OutIt>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
return std::__vformat_to(std::move(__out_it), __fmt, __args);
}
#endif
# endif
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
_VSTD::make_format_args(__args...));
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt.get(),
_VSTD::make_wformat_args(__args...));
return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
vformat(string_view __fmt, format_args __args) {
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
string __res;
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
std::vformat_to(std::back_inserter(__res), __fmt, __args);
return __res;
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
vformat(wstring_view __fmt, wformat_args __args) {
wstring __res;
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
std::vformat_to(std::back_inserter(__res), __fmt, __args);
return __res;
}
#endif
# endif
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(format_string<_Args...> __fmt,
_Args&&... __args) {
return _VSTD::vformat(__fmt.get(), _VSTD::make_format_args(__args...));
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
format(format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(__fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
format(wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat(__fmt.get(), _VSTD::make_wformat_args(__args...));
return std::vformat(__fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
template <class _Context, class _OutIt, class _CharT>
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
basic_string_view<_CharT> __fmt,
basic_format_args<_Context> __args) {
__format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
_VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
return _VSTD::move(__buffer).__result();
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
__vformat_to_n(_OutIt __out_it,
iter_difference_t<_OutIt> __n,
basic_string_view<_CharT> __fmt,
basic_format_args<_Context> __args) {
__format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n};
std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
std::__format_context_create(__buffer.__make_output_iterator(), __args));
return std::move(__buffer).__result();
}
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_format_args(__args...));
return std::__vformat_to_n<format_context>(std::move(__out_it), __n, __fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt,
_Args&&... __args) {
return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, __fmt.get(), _VSTD::make_wformat_args(__args...));
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<wformat_context>(std::move(__out_it), __n, __fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) {
__format::__formatted_size_buffer<_CharT> __buffer;
_VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args));
return _VSTD::move(__buffer).__result();
std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
std::__format_context_create(__buffer.__make_output_iterator(), __args));
return std::move(__buffer).__result();
}
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(format_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_format_args(__args...)});
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::__vformatted_size(__fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)});
}
#endif
# endif
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
template <class _OutIt, class _CharT, class _FormatOutIt>
requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
__vformat_to(
_OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
requires(output_iterator<_OutIt, const _CharT&>)
_LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(
_OutIt __out_it,
locale __loc,
basic_string_view<_CharT> __fmt,
basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
if constexpr (same_as<_OutIt, _FormatOutIt>)
return _VSTD::__format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(_VSTD::move(__out_it), __args, _VSTD::move(__loc)));
return std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()},
std::__format_context_create(std::move(__out_it), __args, std::move(__loc)));
else {
__format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)};
_VSTD::__format::__vformat_to(
__format::__format_buffer<_OutIt, _CharT> __buffer{std::move(__out_it)};
std::__format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
return _VSTD::move(__buffer).__out_it();
std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc)));
return std::move(__buffer).__out_it();
}
}
template <output_iterator<const char&> _OutIt>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(
_OutIt __out_it, locale __loc, string_view __fmt, format_args __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
__args);
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, locale __loc, string_view __fmt, format_args __args) {
return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args);
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(
_OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) {
return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
__args);
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) {
return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args);
}
#endif
# endif
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
_VSTD::make_format_args(__args...));
return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt
format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt.get(),
_VSTD::make_wformat_args(__args...));
return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
vformat(locale __loc, string_view __fmt, format_args __args) {
string __res;
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
__args);
std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args);
return __res;
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
// fires too eagerly, see http://llvm.org/PR61563.
template <class = void>
_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
wstring __res;
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
__args);
std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args);
return __res;
}
#endif
# endif
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string format(locale __loc,
format_string<_Args...> __fmt,
_Args&&... __args) {
return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
_VSTD::make_format_args(__args...));
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string
format(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
return std::vformat(std::move(__loc), __fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring
format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::vformat(_VSTD::move(__loc), __fmt.get(),
_VSTD::make_wformat_args(__args...));
return std::vformat(std::move(__loc), __fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
template <class _Context, class _OutIt, class _CharT>
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n,
locale __loc, basic_string_view<_CharT> __fmt,
basic_format_args<_Context> __args) {
__format::__format_to_n_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it), __n};
_VSTD::__format::__vformat_to(
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n(
_OutIt __out_it,
iter_difference_t<_OutIt> __n,
locale __loc,
basic_string_view<_CharT> __fmt,
basic_format_args<_Context> __args) {
__format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n};
std::__format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
return _VSTD::move(__buffer).__result();
std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc)));
return std::move(__buffer).__result();
}
template <output_iterator<const char&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt,
_Args&&... __args) {
return _VSTD::__vformat_to_n<format_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
_VSTD::make_format_args(__args...));
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n(
_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<format_context>(
std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_format_args(__args...));
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <output_iterator<const wchar_t&> _OutIt, class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>
format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt,
_Args&&... __args) {
return _VSTD::__vformat_to_n<wformat_context>(_VSTD::move(__out_it), __n, _VSTD::move(__loc), __fmt.get(),
_VSTD::make_wformat_args(__args...));
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n(
_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
return std::__vformat_to_n<wformat_context>(
std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_wformat_args(__args...));
}
#endif
# endif
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) {
__format::__formatted_size_buffer<_CharT> __buffer;
_VSTD::__format::__vformat_to(
std::__format::__vformat_to(
basic_format_parse_context{__fmt, __args.__size()},
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
return _VSTD::move(__buffer).__result();
std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc)));
return std::move(__buffer).__result();
}
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_format_args(__args...)});
return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_format_args(__args...)});
}
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t
formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {
return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt.get(), basic_format_args{_VSTD::make_wformat_args(__args...)});
return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_wformat_args(__args...)});
}
#endif
#endif // _LIBCPP_HAS_NO_LOCALIZATION
# endif
# endif // _LIBCPP_HAS_NO_LOCALIZATION
#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS

View file

@ -1,39 +0,0 @@
// -*- 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_FORMAT_FWD_H
#define _LIBCPP___FORMAT_FORMAT_FWD_H
#include <__availability>
#include <__config>
#include <__iterator/concepts.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
template <class _Context>
class _LIBCPP_TEMPLATE_VIS basic_format_arg;
template <class _OutIt, class _CharT>
requires output_iterator<_OutIt, const _CharT&>
class _LIBCPP_TEMPLATE_VIS basic_format_context;
template <class _Tp, class _CharT = char>
struct _LIBCPP_TEMPLATE_VIS formatter;
#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___FORMAT_FORMAT_FWD_H

View file

@ -26,32 +26,24 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _CharT>
class _LIBCPP_TEMPLATE_VIS basic_format_parse_context {
public:
using char_type = _CharT;
using char_type = _CharT;
using const_iterator = typename basic_string_view<_CharT>::const_iterator;
using iterator = const_iterator;
using iterator = const_iterator;
_LIBCPP_HIDE_FROM_ABI
constexpr explicit basic_format_parse_context(basic_string_view<_CharT> __fmt,
size_t __num_args = 0) noexcept
_LIBCPP_HIDE_FROM_ABI constexpr explicit basic_format_parse_context(
basic_string_view<_CharT> __fmt, size_t __num_args = 0) noexcept
: __begin_(__fmt.begin()),
__end_(__fmt.end()),
__indexing_(__unknown),
__next_arg_id_(0),
__num_args_(__num_args) {}
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context&
operator=(const basic_format_parse_context&) = delete;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
return __begin_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
return __end_;
}
_LIBCPP_HIDE_FROM_ABI constexpr void advance_to(const_iterator __it) {
__begin_ = __it;
}
_LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { return __begin_; }
_LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { return __end_; }
_LIBCPP_HIDE_FROM_ABI constexpr void advance_to(const_iterator __it) { __begin_ = __it; }
_LIBCPP_HIDE_FROM_ABI constexpr size_t next_arg_id() {
if (__indexing_ == __manual)
@ -102,9 +94,9 @@ private:
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_parse_context);
using format_parse_context = basic_format_parse_context<char>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
using wformat_parse_context = basic_format_parse_context<wchar_t>;
#endif
# endif
#endif //_LIBCPP_STD_VER >= 20

View file

@ -14,7 +14,7 @@
#include <__config>
#include <__format/format_error.h>
#include <__iterator/concepts.h>
#include <__iterator/readable_traits.h> // iter_value_t
#include <__iterator/iterator_traits.h> // iter_value_t
#include <cstddef>
#include <cstdint>
@ -38,8 +38,7 @@ template <contiguous_iterator _Iterator>
__parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>;
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_number(_Iterator __begin, _Iterator __end);
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> __parse_number(_Iterator __begin, _Iterator __end);
/**
* The maximum value of a numeric argument.
@ -66,8 +65,7 @@ template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) {
size_t __value = __parse_ctx.next_arg_id();
_LIBCPP_ASSERT(__value <= __number_max,
"Compilers don't support this number of arguments");
_LIBCPP_ASSERT_UNCATEGORIZED(__value <= __number_max, "Compilers don't support this number of arguments");
return {__begin, uint32_t(__value)};
}
@ -92,8 +90,7 @@ template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
__parse_number(_Iterator __begin, _Iterator __end_input) {
using _CharT = iter_value_t<_Iterator>;
static_assert(__format::__number_max == INT32_MAX,
"The algorithm is implemented based on this value.");
static_assert(__format::__number_max == INT32_MAX, "The algorithm is implemented based on this value.");
/*
* Limit the input to 9 digits, otherwise we need two checks during every
* iteration:
@ -101,7 +98,7 @@ __parse_number(_Iterator __begin, _Iterator __end_input) {
* - Does the value exceed width of an uint32_t? (Switching to uint64_t would
* have the same issue, but with a higher maximum.)
*/
_Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;
_Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input;
uint32_t __value = *__begin - _CharT('0');
while (++__begin != __end) {
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
@ -110,9 +107,7 @@ __parse_number(_Iterator __begin, _Iterator __end_input) {
__value = __value * 10 + *__begin - _CharT('0');
}
if (__begin != __end_input && *__begin >= _CharT('0') &&
*__begin <= _CharT('9')) {
if (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')) {
/*
* There are more than 9 digits, do additional validations:
* - Does the 10th digit exceed the maximum allowed value?
@ -120,10 +115,8 @@ __parse_number(_Iterator __begin, _Iterator __end_input) {
* (More than 10 digits always overflows the maximum.)
*/
uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0');
if (__v > __number_max ||
(__begin != __end_input && *__begin >= _CharT('0') &&
*__begin <= _CharT('9')))
std::__throw_format_error("The numeric value of the format-spec is too large");
if (__v > __number_max || (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')))
std::__throw_format_error("The numeric value of the format specifier is too large");
__value = __v;
}
@ -153,7 +146,7 @@ __parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
return __detail::__parse_automatic(__begin, __end, __parse_ctx);
}
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
std::__throw_format_error("The arg-id of the format-spec starts with an invalid character");
std::__throw_format_error("The argument index starts with an invalid character");
return __detail::__parse_manual(__begin, __end, __parse_ctx);
}

View file

@ -10,9 +10,8 @@
#ifndef _LIBCPP___FORMAT_FORMATTER_H
#define _LIBCPP___FORMAT_FORMATTER_H
#include <__availability>
#include <__config>
#include <__format/format_fwd.h>
#include <__fwd/format.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -33,8 +32,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
/// - is_move_assignable<F>.
template <class _Tp, class _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter {
formatter() = delete;
formatter(const formatter&) = delete;
formatter() = delete;
formatter(const formatter&) = delete;
formatter& operator=(const formatter&) = delete;
};

View file

@ -11,20 +11,17 @@
#define _LIBCPP___FORMAT_FORMATTER_BOOL_H
#include <__algorithm/copy.h>
#include <__availability>
#include <__assert>
#include <__config>
#include <__debug>
#include <__format/concepts.h>
#include <__format/format_error.h>
#include <__format/format_parse_context.h>
#include <__format/formatter.h>
#include <__format/formatter_integral.h>
#include <__format/parser_std_format_spec.h>
#include <__utility/unreachable.h>
#include <string_view>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# include <locale>
# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -41,7 +38,7 @@ public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral);
__format_spec::__process_parsed_bool(__parser_);
__format_spec::__process_parsed_bool(__parser_, "a bool");
return __result;
}
@ -64,7 +61,7 @@ public:
static_cast<unsigned>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx));
default:
_LIBCPP_ASSERT(false, "The parse function should have validated the type");
_LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
__libcpp_unreachable();
}
}

View file

@ -10,7 +10,6 @@
#ifndef _LIBCPP___FORMAT_FORMATTER_CHAR_H
#define _LIBCPP___FORMAT_FORMATTER_CHAR_H
#include <__availability>
#include <__concepts/same_as.h>
#include <__config>
#include <__format/concepts.h>
@ -19,8 +18,9 @@
#include <__format/formatter_integral.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__format/write_escaped.h>
#include <__type_traits/conditional.h>
#include <__type_traits/is_signed.h>
#include <__type_traits/make_unsigned.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -36,7 +36,7 @@ public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral);
__format_spec::__process_parsed_char(__parser_);
__format_spec::__process_parsed_char(__parser_, "a character");
return __result;
}
@ -50,22 +50,21 @@ public:
return __formatter::__format_escaped_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
# endif
if constexpr (sizeof(_CharT) <= sizeof(int))
// Promotes _CharT to an integral type. This reduces the number of
// instantiations of __format_integer reducing code size.
if constexpr (sizeof(_CharT) <= sizeof(unsigned))
return __formatter::__format_integer(
static_cast<conditional_t<is_signed_v<_CharT>, int, unsigned>>(__value),
static_cast<unsigned>(static_cast<make_unsigned_t<_CharT>>(__value)),
__ctx,
__parser_.__get_parsed_std_specifications(__ctx));
else
return __formatter::__format_integer(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx));
return __formatter::__format_integer(
static_cast<make_unsigned_t<_CharT>>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx));
}
template <class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(char __value, _FormatContext& __ctx) const
requires(same_as<_CharT, wchar_t>)
{
return format(static_cast<wchar_t>(__value), __ctx);
return format(static_cast<wchar_t>(static_cast<unsigned char>(__value)), __ctx);
}
# if _LIBCPP_STD_VER >= 23
@ -83,8 +82,7 @@ template <>
struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t> : public __formatter_char<wchar_t> {};
template <>
struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t> : public __formatter_char<wchar_t> {
};
struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t> : public __formatter_char<wchar_t> {};
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS

View file

@ -16,6 +16,7 @@
#include <__algorithm/min.h>
#include <__algorithm/rotate.h>
#include <__algorithm/transform.h>
#include <__assert>
#include <__charconv/chars_format.h>
#include <__charconv/to_chars_floating_point.h>
#include <__charconv/to_chars_result.h>
@ -28,6 +29,7 @@
#include <__format/formatter_integral.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__iterator/concepts.h>
#include <__memory/allocator.h>
#include <__system_error/errc.h>
#include <__type_traits/conditional.h>
@ -37,7 +39,7 @@
#include <cstddef>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# include <locale>
# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -55,22 +57,22 @@ namespace __formatter {
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) {
to_chars_result __r = _VSTD::to_chars(__first, __last, __value);
_LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
to_chars_result __r = std::to_chars(__first, __last, __value);
_LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) {
to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt);
_LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
to_chars_result __r = std::to_chars(__first, __last, __value, __fmt);
_LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
template <floating_point _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) {
to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt, __precision);
_LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
to_chars_result __r = std::to_chars(__first, __last, __value, __fmt, __precision);
_LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
}
@ -115,8 +117,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr size_t __float_buffer_size(int __precision) {
template <>
struct __traits<float> {
static constexpr int __max_integral = 38;
static constexpr int __max_fractional = 149;
static constexpr int __max_integral = 38;
static constexpr int __max_fractional = 149;
static constexpr int __max_fractional_value = 3;
static constexpr size_t __stack_buffer_size = 256;
@ -125,8 +127,8 @@ struct __traits<float> {
template <>
struct __traits<double> {
static constexpr int __max_integral = 308;
static constexpr int __max_fractional = 1074;
static constexpr int __max_integral = 308;
static constexpr int __max_fractional = 1074;
static constexpr int __max_fractional_value = 4;
static constexpr size_t __stack_buffer_size = 1024;
@ -135,7 +137,7 @@ struct __traits<double> {
/// Helper class to store the conversion buffer.
///
/// Depending on the maxium size required for a value, the buffer is allocated
/// Depending on the maximum size required for a value, the buffer is allocated
/// on the stack or the heap.
template <floating_point _Fp>
class _LIBCPP_TEMPLATE_VIS __float_buffer {
@ -152,7 +154,6 @@ public:
// required.
explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision)
: __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) {
// When the precision is larger than _Traits::__max_fractional the digits in
// the range (_Traits::__max_fractional, precision] will contain the value
// zero. There's no need to request to_chars to write these zeros:
@ -164,7 +165,7 @@ public:
// to be converted from a char to a wchar_t.
if (__precision_ > _Traits::__max_fractional) {
__num_trailing_zeros_ = __precision_ - _Traits::__max_fractional;
__precision_ = _Traits::__max_fractional;
__precision_ = _Traits::__max_fractional;
}
__size_ = __formatter::__float_buffer_size<_Fp>(__precision_);
@ -179,7 +180,7 @@ public:
if (__size_ > _Traits::__stack_buffer_size)
allocator<char>{}.deallocate(__begin_, __size_);
}
_LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete;
_LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete;
_LIBCPP_HIDE_FROM_ABI __float_buffer& operator=(const __float_buffer&) = delete;
_LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; }
@ -223,7 +224,7 @@ struct __float_result {
constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char* __last) {
ptrdiff_t __size = __last - __first;
if (__size >= 4) {
__first = __last - _VSTD::min(__size, ptrdiff_t(6));
__first = __last - std::min(__size, ptrdiff_t(6));
for (; __first != __last - 3; ++__first) {
if (*__first == 'e')
return __first;
@ -233,8 +234,8 @@ constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value,
char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result
__format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, char* __integral) {
__float_result __result;
__result.__integral = __integral;
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value);
@ -244,7 +245,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffe
// Constrains:
// - There's at least one decimal digit before the radix point.
// - The radix point, when present, is placed before the exponent.
__result.__radix_point = _VSTD::find(__result.__integral + 1, __result.__exponent, '.');
__result.__radix_point = std::find(__result.__integral + 1, __result.__exponent, '.');
// When the radix point isn't found its position is the exponent instead of
// __result.__last.
@ -252,19 +253,18 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffe
__result.__radix_point = __result.__last;
// clang-format off
_LIBCPP_ASSERT((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last || *__result.__exponent == 'e'),
"Post-condition failure.");
_LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last || *__result.__exponent == 'e'),
"Post-condition failure.");
// clang-format on
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(const __float_buffer<_Fp>& __buffer,
_Tp __value, int __precision,
char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(
const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result;
__result.__integral = __integral;
if (__precision == -1)
@ -296,67 +296,64 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(cons
// 0123456789
static_assert(__traits<_Fp>::__hex_precision_digits <= 4, "Guard against possible underflow.");
char* __last = __result.__last - 2;
__first = __last - __traits<_Fp>::__hex_precision_digits;
__result.__exponent = _VSTD::find(__first, __last, 'p');
char* __last = __result.__last - 2;
__first = __last - __traits<_Fp>::__hex_precision_digits;
__result.__exponent = std::find(__first, __last, 'p');
} else {
__result.__radix_point = __result.__last;
__result.__exponent = __first;
__result.__exponent = __first;
}
// clang-format off
_LIBCPP_ASSERT((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent != __result.__last && *__result.__exponent == 'p'),
"Post-condition failure.");
_LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent != __result.__last && *__result.__exponent == 'p'),
"Post-condition failure.");
// clang-format on
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case(const __float_buffer<_Fp>& __buffer,
_Tp __value, int __precision,
char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case(
const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result =
__formatter::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral);
_VSTD::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper);
std::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper);
*__result.__exponent = 'P';
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(const __float_buffer<_Fp>& __buffer,
_Tp __value, int __precision,
char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(
const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result;
__result.__integral = __integral;
__result.__last =
__formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision);
char* __first = __integral + 1;
_LIBCPP_ASSERT(__first != __result.__last, "No exponent present");
_LIBCPP_ASSERT_INTERNAL(__first != __result.__last, "No exponent present");
if (*__first == '.') {
__result.__radix_point = __first;
__result.__exponent = __formatter::__find_exponent(__first + 1, __result.__last);
} else {
__result.__radix_point = __result.__last;
__result.__exponent = __first;
__result.__exponent = __first;
}
// clang-format off
_LIBCPP_ASSERT((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent != __result.__last && *__result.__exponent == 'e'),
"Post-condition failure.");
_LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent != __result.__last && *__result.__exponent == 'e'),
"Post-condition failure.");
// clang-format on
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(const __float_buffer<_Fp>& __buffer,
_Tp __value, int __precision,
char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(
const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result =
__formatter::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral);
*__result.__exponent = 'E';
@ -364,8 +361,8 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(const
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value,
int __precision, char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result
__format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result;
__result.__integral = __integral;
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision);
@ -375,21 +372,20 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_fixed(const __float_buffer<
// By converting __precision to a bool the subtraction can be done
// unconditionally.
__result.__radix_point = __result.__last - (__precision + bool(__precision));
__result.__exponent = __result.__last;
__result.__exponent = __result.__last;
// clang-format off
_LIBCPP_ASSERT((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last),
"Post-condition failure.");
_LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last),
"Post-condition failure.");
// clang-format on
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value,
int __precision, char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result
__format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__buffer.__remove_trailing_zeros();
__float_result __result;
@ -399,7 +395,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_
char* __first = __integral + 1;
if (__first == __result.__last) {
__result.__radix_point = __result.__last;
__result.__exponent = __result.__last;
__result.__exponent = __result.__last;
} else {
__result.__exponent = __formatter::__find_exponent(__first, __result.__last);
if (__result.__exponent != __result.__last)
@ -410,23 +406,23 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_
// In fixed mode the algorithm truncates trailing spaces and possibly the
// radix point. There's no good guess for the position of the radix point
// therefore scan the output after the first digit.
__result.__radix_point = _VSTD::find(__first, __result.__last, '.');
__result.__radix_point = std::find(__first, __result.__last, '.');
}
}
// clang-format off
_LIBCPP_ASSERT((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last || *__result.__exponent == 'e'),
"Post-condition failure.");
_LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) &&
(__result.__radix_point == __result.__last || *__result.__radix_point == '.') &&
(__result.__exponent == __result.__last || *__result.__exponent == 'e'),
"Post-condition failure.");
// clang-format on
return __result;
}
template <class _Fp, class _Tp>
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value,
int __precision, char* __integral) {
_LIBCPP_HIDE_FROM_ABI __float_result
__format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) {
__float_result __result = __formatter::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral);
if (__result.__exponent != __result.__last)
*__result.__exponent = 'E';
@ -490,7 +486,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(
return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first);
default:
_LIBCPP_ASSERT(false, "The parser should have validated the type");
_LIBCPP_ASSERT_INTERNAL(false, "The parser should have validated the type");
__libcpp_unreachable();
}
}
@ -501,13 +497,13 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
_OutIt __out_it,
const __float_buffer<_Fp>& __buffer,
const __float_result& __result,
_VSTD::locale __loc,
std::locale __loc,
__format_spec::__parsed_specifications<_CharT> __specs) {
const auto& __np = std::use_facet<numpunct<_CharT>>(__loc);
const auto& __np = std::use_facet<numpunct<_CharT>>(__loc);
string __grouping = __np.grouping();
char* __first = __result.__integral;
char* __first = __result.__integral;
// When no radix point or exponent are present __last will be __result.__last.
char* __last = _VSTD::min(__result.__radix_point, __result.__exponent);
char* __last = std::min(__result.__radix_point, __result.__exponent);
ptrdiff_t __digits = __last - __first;
if (!__grouping.empty()) {
@ -523,11 +519,11 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
__grouping.size() - // Grouping contains one
!__grouping.empty(); // additional character
__formatter::__padding_size_result __padding = {0, 0};
bool __zero_padding = __specs.__alignment_ == __format_spec::__alignment::__zero_padding;
__formatter::__padding_size_result __padding = {0, 0};
bool __zero_padding = __specs.__alignment_ == __format_spec::__alignment::__zero_padding;
if (__size < __specs.__width_) {
if (__zero_padding) {
__specs.__alignment_ = __format_spec::__alignment::__right;
__specs.__alignment_ = __format_spec::__alignment::__right;
__specs.__fill_.__data[0] = _CharT('0');
}
@ -537,16 +533,16 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// sign and (zero padding or alignment)
if (__zero_padding && __first != __buffer.begin())
*__out_it++ = *__buffer.begin();
__out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
if (!__zero_padding && __first != __buffer.begin())
*__out_it++ = *__buffer.begin();
// integral part
if (__grouping.empty()) {
__out_it = __formatter::__copy(__first, __digits, _VSTD::move(__out_it));
__out_it = __formatter::__copy(__first, __digits, std::move(__out_it));
} else {
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
_CharT __sep = __np.thousands_sep();
// The output is divided in small groups of numbers to write:
// - A group before the first separator.
@ -555,7 +551,7 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// This loop achieves that process by testing the termination condition
// midway in the loop.
while (true) {
__out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
__out_it = __formatter::__copy(__first, *__r, std::move(__out_it));
__first += *__r;
if (__r == __e)
@ -569,16 +565,16 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// fractional part
if (__result.__radix_point != __result.__last) {
*__out_it++ = __np.decimal_point();
__out_it = __formatter::__copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it));
__out_it = __formatter::__fill(_VSTD::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0'));
__out_it = __formatter::__copy(__result.__radix_point + 1, __result.__exponent, std::move(__out_it));
__out_it = __formatter::__fill(std::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0'));
}
// exponent
if (__result.__exponent != __result.__last)
__out_it = __formatter::__copy(__result.__exponent, __result.__last, _VSTD::move(__out_it));
__out_it = __formatter::__copy(__result.__exponent, __result.__last, std::move(__out_it));
// alignment
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
}
# endif // _LIBCPP_HAS_NO_LOCALIZATION
@ -596,7 +592,7 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite(
__specs.__std_.__type_ == __format_spec::__type::__scientific_upper_case ||
__specs.__std_.__type_ == __format_spec::__type::__fixed_upper_case ||
__specs.__std_.__type_ == __format_spec::__type::__general_upper_case;
__last = _VSTD::copy_n(&("infnanINFNAN"[6 * __upper_case + 3 * __isnan]), 3, __last);
__last = std::copy_n(&("infnanINFNAN"[6 * __upper_case + 3 * __isnan]), 3, __last);
// [format.string.std]/13
// A zero (0) character preceding the width field pads the field with
@ -605,16 +601,45 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite(
if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding)
__specs.__alignment_ = __format_spec::__alignment::__right;
return __formatter::__write(__buffer, __last, _VSTD::move(__out_it), __specs);
return __formatter::__write(__buffer, __last, std::move(__out_it), __specs);
}
/// Writes additional zero's for the precision before the exponent.
/// This is used when the precision requested in the format string is larger
/// than the maximum precision of the floating-point type. These precision
/// digits are always 0.
///
/// \param __exponent The location of the exponent character.
/// \param __num_trailing_zeros The number of 0's to write before the exponent
/// character.
template <class _CharT, class _ParserCharT>
_LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
const _CharT* __first,
const _CharT* __last,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
size_t __size,
const _CharT* __exponent,
size_t __num_trailing_zeros) -> decltype(__out_it) {
_LIBCPP_ASSERT_INTERNAL(__first <= __last, "Not a valid range");
_LIBCPP_ASSERT_INTERNAL(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
__padding_size_result __padding =
__formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_);
__out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__copy(__first, __exponent, std::move(__out_it));
__out_it = __formatter::__fill(std::move(__out_it), __num_trailing_zeros, _CharT('0'));
__out_it = __formatter::__copy(__exponent, __last, std::move(__out_it));
return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
}
template <floating_point _Tp, class _CharT, class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
__format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) {
bool __negative = _VSTD::signbit(__value);
bool __negative = std::signbit(__value);
if (!_VSTD::isfinite(__value)) [[unlikely]]
return __formatter::__format_floating_point_non_finite(__ctx.out(), __specs, __negative, _VSTD::isnan(__value));
if (!std::isfinite(__value)) [[unlikely]]
return __formatter::__format_floating_point_non_finite(__ctx.out(), __specs, __negative, std::isnan(__value));
// Depending on the std-format-spec string the sign and the value
// might not be outputted together:
@ -640,7 +665,7 @@ __format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__par
// When there is an exponent the point needs to be moved before the
// exponent. When there's no exponent the rotate does nothing. Since
// rotate tests whether the operation is a nop, call it unconditionally.
_VSTD::rotate(__result.__exponent, __result.__last - 1, __result.__last);
std::rotate(__result.__exponent, __result.__last - 1, __result.__last);
__result.__radix_point = __result.__exponent;
// The radix point is always placed before the exponent.
@ -665,7 +690,7 @@ __format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__par
// Let P equal the precision if nonzero, 6 if the precision is not
// specified, or 1 if the precision is 0. Then, if a conversion with
// style E would have an exponent of X:
int __p = _VSTD::max(1, (__specs.__has_precision() ? __specs.__precision_ : 6));
int __p = std::max<int>(1, (__specs.__has_precision() ? __specs.__precision_ : 6));
if (__result.__exponent == __result.__last)
// if P > X >= -4, the conversion is with style f or F and precision P - 1 - X.
// By including the radix point it calculates P - (1 + X)
@ -711,15 +736,15 @@ __format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__par
*__out_it++ = *__first++;
// After the sign is written, zero padding is the same a right alignment
// with '0'.
__specs.__alignment_ = __format_spec::__alignment::__right;
__specs.__alignment_ = __format_spec::__alignment::__right;
__specs.__fill_.__data[0] = _CharT('0');
}
if (__num_trailing_zeros)
return __formatter::__write_using_trailing_zeros(
__first, __result.__last, _VSTD::move(__out_it), __specs, __size, __result.__exponent, __num_trailing_zeros);
__first, __result.__last, std::move(__out_it), __specs, __size, __result.__exponent, __num_trailing_zeros);
return __formatter::__write(__first, __result.__last, _VSTD::move(__out_it), __specs, __size);
return __formatter::__write(__first, __result.__last, std::move(__out_it), __specs, __size);
}
} // namespace __formatter
@ -730,7 +755,7 @@ public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_floating_point);
__format_spec::__process_parsed_floating_point(__parser_);
__format_spec::__process_parsed_floating_point(__parser_, "a floating-point");
return __result;
}
@ -743,14 +768,11 @@ public:
};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<float, _CharT>
: public __formatter_floating_point<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<float, _CharT> : public __formatter_floating_point<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<double, _CharT>
: public __formatter_floating_point<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<double, _CharT> : public __formatter_floating_point<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<long double, _CharT>
: public __formatter_floating_point<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<long double, _CharT> : public __formatter_floating_point<_CharT> {};
#endif //_LIBCPP_STD_VER >= 20

View file

@ -10,7 +10,6 @@
#ifndef _LIBCPP___FORMAT_FORMATTER_INTEGER_H
#define _LIBCPP___FORMAT_FORMATTER_INTEGER_H
#include <__availability>
#include <__concepts/arithmetic.h>
#include <__config>
#include <__format/concepts.h>
@ -19,25 +18,24 @@
#include <__format/formatter_integral.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_void.h>
#include <__type_traits/make_32_64_or_128_bit.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_integer {
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_integer {
public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral);
__format_spec::__process_parsed_integer(__parser_);
__format_spec::__process_parsed_integer(__parser_, "an integer");
return __result;
}
@ -49,7 +47,7 @@ public:
return __formatter::__format_char(__value, __ctx.out(), __specs);
using _Type = __make_32_64_or_128_bit_t<_Tp>;
static_assert(!is_same<_Type, void>::value, "unsupported integral type used in __formatter_integer::__format");
static_assert(!is_void<_Type>::value, "unsupported integral type used in __formatter_integer::__format");
// Reduce the number of instantiation of the integer formatter
return __formatter::__format_integer(static_cast<_Type>(__value), __ctx, __specs);
@ -60,44 +58,34 @@ public:
// Signed integral types.
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT> : public __formatter_integer<_CharT> {
};
struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<int, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<long, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT> : public __formatter_integer<_CharT> {};
# ifndef _LIBCPP_HAS_NO_INT128
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT> : public __formatter_integer<_CharT> {};
# endif
// Unsigned integral types.
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT> : public __formatter_integer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT> : public __formatter_integer<_CharT> {};
# ifndef _LIBCPP_HAS_NO_INT128
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT>
: public __formatter_integer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT> : public __formatter_integer<_CharT> {};
# endif
#endif //_LIBCPP_STD_VER >= 20

View file

@ -20,6 +20,9 @@
#include <__format/format_error.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
#include <__system_error/errc.h>
#include <__type_traits/make_unsigned.h>
#include <__utility/unreachable.h>
@ -29,7 +32,7 @@
#include <string_view>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# include <locale>
# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -49,7 +52,9 @@ namespace __formatter {
// Generic
//
_LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) {
template <contiguous_iterator _Iterator>
requires same_as<char, iter_value_t<_Iterator>>
_LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) {
if (__negative)
*__buf++ = '-';
else
@ -85,9 +90,8 @@ _LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, _
* regardless whether the @c std::numpunct's type is @c char or @c wchar_t.
*/
_LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) {
_LIBCPP_ASSERT(!__grouping.empty() && __size > __grouping[0],
"The slow grouping formatting is used while there will be no "
"separators written");
_LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0],
"The slow grouping formatting is used while there will be no separators written");
string __r;
auto __end = __grouping.end() - 1;
auto __ptr = __grouping.begin();
@ -119,10 +123,10 @@ _LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const
//
template <__fmt_char_type _CharT>
_LIBCPP_HIDE_FROM_ABI auto __format_char(
integral auto __value,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
_LIBCPP_HIDE_FROM_ABI auto
__format_char(integral auto __value,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
using _Tp = decltype(__value);
if constexpr (!same_as<_CharT, _Tp>) {
// cmp_less and cmp_greater can't be used for character types.
@ -141,21 +145,23 @@ _LIBCPP_HIDE_FROM_ABI auto __format_char(
}
const auto __c = static_cast<_CharT>(__value);
return __formatter::__write(_VSTD::addressof(__c), _VSTD::addressof(__c) + 1, _VSTD::move(__out_it), __specs);
return __formatter::__write(std::addressof(__c), std::addressof(__c) + 1, std::move(__out_it), __specs);
}
//
// Integer
//
/** Wrapper around @ref to_chars, returning the output pointer. */
template <integral _Tp>
_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, int __base) {
/** Wrapper around @ref to_chars, returning the output iterator. */
template <contiguous_iterator _Iterator, integral _Tp>
requires same_as<char, iter_value_t<_Iterator>>
_LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) {
// TODO FMT Evaluate code overhead due to not calling the internal function
// directly. (Should be zero overhead.)
to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __base);
_LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
return __r.ptr;
to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base);
_LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
auto __diff = __r.ptr - std::to_address(__first);
return __first + __diff;
}
/**
@ -203,22 +209,93 @@ consteval size_t __buffer_size() noexcept
+ 1; // Reserve space for the sign.
}
template <unsigned_integral _Tp, class _CharT, class _FormatContext>
template <class _OutIt, contiguous_iterator _Iterator, class _CharT>
requires same_as<char, iter_value_t<_Iterator>>
_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(
_OutIt __out_it,
_Iterator __begin,
_Iterator __first,
_Iterator __last,
string&& __grouping,
_CharT __sep,
__format_spec::__parsed_specifications<_CharT> __specs) {
int __size = (__first - __begin) + // [sign][prefix]
(__last - __first) + // data
(__grouping.size() - 1); // number of separator characters
__padding_size_result __padding = {0, 0};
if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) {
// Write [sign][prefix].
__out_it = __formatter::__copy(__begin, __first, std::move(__out_it));
if (__specs.__width_ > __size) {
// Write zero padding.
__padding.__before_ = __specs.__width_ - __size;
__out_it = __formatter::__fill(std::move(__out_it), __specs.__width_ - __size, _CharT('0'));
}
} else {
if (__specs.__width_ > __size) {
// Determine padding and write padding.
__padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
__out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
}
// Write [sign][prefix].
__out_it = __formatter::__copy(__begin, __first, std::move(__out_it));
}
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
_LIBCPP_ASSERT_INTERNAL(
__r != __e, "The slow grouping formatting is used while there will be no separators written.");
// The output is divided in small groups of numbers to write:
// - A group before the first separator.
// - A separator and a group, repeated for the number of separators.
// - A group after the last separator.
// This loop achieves that process by testing the termination condition
// midway in the loop.
//
// TODO FMT This loop evaluates the loop invariant `__parser.__type !=
// _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
// happens in the __write call.) Benchmark whether making two loops and
// hoisting the invariant is worth the effort.
while (true) {
if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) {
__last = __first + *__r;
__out_it = __formatter::__transform(__first, __last, std::move(__out_it), __hex_to_upper);
__first = __last;
} else {
__out_it = __formatter::__copy(__first, *__r, std::move(__out_it));
__first += *__r;
}
if (__r == __e)
break;
++__r;
*__out_it++ = __sep;
}
return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
}
template <unsigned_integral _Tp, contiguous_iterator _Iterator, class _CharT, class _FormatContext>
requires same_as<char, iter_value_t<_Iterator>>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
_Tp __value,
_FormatContext& __ctx,
__format_spec::__parsed_specifications<_CharT> __specs,
bool __negative,
char* __begin,
char* __end,
_Iterator __begin,
_Iterator __end,
const char* __prefix,
int __base) {
char* __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
_Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_);
if (__specs.__std_.__alternate_form_ && __prefix)
while (*__prefix)
*__first++ = *__prefix++;
char* __last = __formatter::__to_buffer(__first, __end, __value, __base);
_Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base);
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
if (__specs.__std_.__locale_specific_form_) {
@ -249,12 +326,12 @@ _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer(
// The zero padding is done like:
// - Write [sign][prefix]
// - Write data right aligned with '0' as fill character.
__out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
__specs.__alignment_ = __format_spec::__alignment::__right;
__out_it = __formatter::__copy(__begin, __first, std::move(__out_it));
__specs.__alignment_ = __format_spec::__alignment::__right;
__specs.__fill_.__data[0] = _CharT('0');
int32_t __size = __first - __begin;
int32_t __size = __first - __begin;
__specs.__width_ -= _VSTD::min(__size, __specs.__width_);
__specs.__width_ -= std::min(__size, __specs.__width_);
}
if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]]
@ -299,7 +376,7 @@ __format_integer(_Tp __value,
return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16);
}
default:
_LIBCPP_ASSERT(false, "The parse function should have validated the type");
_LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
__libcpp_unreachable();
}
}

View file

@ -12,35 +12,32 @@
#include <__algorithm/ranges_copy.h>
#include <__algorithm/ranges_fill_n.h>
#include <__algorithm/ranges_for_each.h>
#include <__algorithm/ranges_transform.h>
#include <__bit/countl.h>
#include <__charconv/to_chars_integral.h>
#include <__charconv/to_chars_result.h>
#include <__chrono/statically_widen.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__format/buffer.h>
#include <__format/concepts.h>
#include <__format/escaped_output_table.h>
#include <__format/formatter.h>
#include <__format/parser_std_format_spec.h>
#include <__format/unicode.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/concepts.h>
#include <__iterator/readable_traits.h> // iter_value_t
#include <__system_error/errc.h>
#include <__type_traits/make_unsigned.h>
#include <__iterator/iterator_traits.h>
#include <__memory/addressof.h>
#include <__memory/pointer_traits.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <cstddef>
#include <string>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
@ -65,15 +62,15 @@ _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) {
return __c;
}
struct _LIBCPP_TYPE_VIS __padding_size_result {
struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result {
size_t __before_;
size_t __after_;
};
_LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
__padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) {
_LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required");
_LIBCPP_ASSERT(
_LIBCPP_ASSERT_INTERNAL(__width > __size, "don't call this function when no padding is required");
_LIBCPP_ASSERT_INTERNAL(
__align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
size_t __fill = __width - __size;
@ -103,51 +100,55 @@ __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align
///
/// This uses a "mass output function" of __format::__output_buffer when possible.
template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
_LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it)
-> decltype(__out_it) {
if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
_LIBCPP_HIDE_FROM_ABI auto
__copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) {
if constexpr (std::same_as<decltype(__out_it), std::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>) {
} else if constexpr (std::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;
return std::ranges::copy(__str, std::move(__out_it)).out;
}
}
template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
template <contiguous_iterator _Iterator,
__fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
__fmt_char_type _OutCharT = _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it)
-> decltype(__out_it) {
return __formatter::__copy(basic_string_view{__first, __last}, _VSTD::move(__out_it));
__copy(_Iterator __first, _Iterator __last, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) {
return __formatter::__copy(basic_string_view{__first, __last}, std::move(__out_it));
}
template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
_LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
-> decltype(__out_it) {
return __formatter::__copy(basic_string_view{__first, __n}, _VSTD::move(__out_it));
template <contiguous_iterator _Iterator,
__fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
__fmt_char_type _OutCharT = _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__copy(_Iterator __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) {
return __formatter::__copy(basic_string_view{std::to_address(__first), __n}, std::move(__out_it));
}
/// Transform wrapper.
///
/// This uses a "mass output function" of __format::__output_buffer when possible.
template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation>
template <contiguous_iterator _Iterator,
__fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type,
__fmt_char_type _OutCharT = _CharT,
class _UnaryOperation>
_LIBCPP_HIDE_FROM_ABI auto
__transform(const _CharT* __first,
const _CharT* __last,
__transform(_Iterator __first,
_Iterator __last,
output_iterator<const _OutCharT&> auto __out_it,
_UnaryOperation __operation) -> decltype(__out_it) {
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));
if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
__out_it.__get_container()->__transform(__first, __last, std::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));
} else if constexpr (std::same_as<decltype(__out_it), typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
__out_it.__buffer_->__transform(__first, __last, std::move(__operation));
return __out_it;
} else {
return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out;
return std::ranges::transform(__first, __last, std::move(__out_it), __operation).out;
}
}
@ -156,14 +157,14 @@ __transform(const _CharT* __first,
/// This uses a "mass output function" of __format::__output_buffer when possible.
template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
_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>>>) {
if constexpr (std::same_as<decltype(__out_it), std::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>) {
} else if constexpr (std::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);
return std::ranges::fill_n(std::move(__out_it), __n, __value);
}
}
@ -207,70 +208,6 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::
}
# endif // _LIBCPP_HAS_NO_UNICODE
template <class _OutIt, class _CharT>
_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first,
const char* __last, string&& __grouping, _CharT __sep,
__format_spec::__parsed_specifications<_CharT> __specs) {
int __size = (__first - __begin) + // [sign][prefix]
(__last - __first) + // data
(__grouping.size() - 1); // number of separator characters
__padding_size_result __padding = {0, 0};
if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) {
// Write [sign][prefix].
__out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
if (__specs.__width_ > __size) {
// Write zero padding.
__padding.__before_ = __specs.__width_ - __size;
__out_it = __formatter::__fill(_VSTD::move(__out_it), __specs.__width_ - __size, _CharT('0'));
}
} else {
if (__specs.__width_ > __size) {
// Determine padding and write padding.
__padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
__out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
}
// Write [sign][prefix].
__out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
}
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
_LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while "
"there will be no separators written.");
// The output is divided in small groups of numbers to write:
// - A group before the first separator.
// - A separator and a group, repeated for the number of separators.
// - A group after the last separator.
// This loop achieves that process by testing the termination condition
// midway in the loop.
//
// TODO FMT This loop evaluates the loop invariant `__parser.__type !=
// _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
// happens in the __write call.) Benchmark whether making two loops and
// hoisting the invariant is worth the effort.
while (true) {
if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) {
__last = __first + *__r;
__out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __hex_to_upper);
__first = __last;
} else {
__out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
__first += *__r;
}
if (__r == __e)
break;
++__r;
*__out_it++ = __sep;
}
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
/// Writes the input to the output with the required padding.
///
/// Since the output column width is specified the function can be used for
@ -299,12 +236,12 @@ __write(basic_string_view<_CharT> __str,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
ptrdiff_t __size) -> decltype(__out_it) {
if (__size >= __specs.__width_)
return __formatter::__copy(__str, _VSTD::move(__out_it));
return __formatter::__copy(__str, std::move(__out_it));
__padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_);
__out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__copy(__str, _VSTD::move(__out_it));
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
__out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__copy(__str, std::move(__out_it));
return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
}
template <contiguous_iterator _Iterator, class _ParserCharT>
@ -314,8 +251,8 @@ __write(_Iterator __first,
output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
ptrdiff_t __size) -> decltype(__out_it) {
_LIBCPP_ASSERT(__first <= __last, "Not a valid range");
return __formatter::__write(basic_string_view{__first, __last}, _VSTD::move(__out_it), __specs, __size);
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range");
return __formatter::__write(basic_string_view{__first, __last}, std::move(__out_it), __specs, __size);
}
/// \overload
@ -327,54 +264,30 @@ __write(_Iterator __first,
_Iterator __last,
output_iterator<const iter_value_t<_Iterator>&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) {
_LIBCPP_ASSERT(__first <= __last, "Not a valid range");
return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first);
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range");
return __formatter::__write(__first, __last, std::move(__out_it), __specs, __last - __first);
}
template <class _CharT, class _ParserCharT, class _UnaryOperation>
_LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
_UnaryOperation __op) -> decltype(__out_it) {
_LIBCPP_ASSERT(__first <= __last, "Not a valid range");
template <contiguous_iterator _Iterator,
class _CharT = typename iterator_traits<_Iterator>::value_type,
class _ParserCharT,
class _UnaryOperation>
_LIBCPP_HIDE_FROM_ABI auto __write_transformed(
_Iterator __first,
_Iterator __last,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
_UnaryOperation __op) -> decltype(__out_it) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range");
ptrdiff_t __size = __last - __first;
if (__size >= __specs.__width_)
return __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op);
return __formatter::__transform(__first, __last, std::move(__out_it), __op);
__padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
__out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op);
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
/// Writes additional zero's for the precision before the exponent.
/// This is used when the precision requested in the format string is larger
/// than the maximum precision of the floating-point type. These precision
/// digits are always 0.
///
/// \param __exponent The location of the exponent character.
/// \param __num_trailing_zeros The number of 0's to write before the exponent
/// character.
template <class _CharT, class _ParserCharT>
_LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
const _CharT* __first,
const _CharT* __last,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_ParserCharT> __specs,
size_t __size,
const _CharT* __exponent,
size_t __num_trailing_zeros) -> decltype(__out_it) {
_LIBCPP_ASSERT(__first <= __last, "Not a valid range");
_LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
__padding_size_result __padding =
__formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_);
__out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__copy(__first, __exponent, _VSTD::move(__out_it));
__out_it = __formatter::__fill(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0'));
__out_it = __formatter::__copy(__exponent, __last, _VSTD::move(__out_it));
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
__out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_);
__out_it = __formatter::__transform(__first, __last, std::move(__out_it), __op);
return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_);
}
/// Writes a string using format's width estimation algorithm.
@ -388,11 +301,11 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
basic_string_view<_CharT> __str,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
_LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string");
_LIBCPP_ASSERT_INTERNAL(!__specs.__has_precision(), "use __write_string");
// No padding -> copy the string
if (!__specs.__has_width())
return __formatter::__copy(__str, _VSTD::move(__out_it));
return __formatter::__copy(__str, std::move(__out_it));
// Note when the estimated width is larger than size there's no padding. So
// there's no reason to get the real size when the estimate is larger than or
@ -400,7 +313,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
size_t __size =
__format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up)
.__width_;
return __formatter::__write(__str, _VSTD::move(__out_it), __specs, __size);
return __formatter::__write(__str, std::move(__out_it), __specs, __size);
}
template <class _CharT>
@ -411,187 +324,12 @@ _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __pre
return __result.__width_;
}
/// Writes a string using format's width estimation algorithm.
///
/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
/// input is ASCII.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto __write_string(
basic_string_view<_CharT> __str,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
if (!__specs.__has_precision())
return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs);
int __size = __formatter::__truncate(__str, __specs.__precision_);
return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
}
# if _LIBCPP_STD_VER >= 23
struct __nul_terminator {};
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) {
return *__cstr == _CharT('\0');
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void
__write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) {
back_insert_iterator __out_it{__str};
std::ranges::copy(__prefix, __nul_terminator{}, __out_it);
char __buffer[8];
to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
_LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
__str += _CharT('}');
}
// [format.string.escaped]/2.2.1.2
// ...
// then the sequence \u{hex-digit-sequence} is appended to E, where
// hex-digit-sequence is the shortest hexadecimal representation of C using
// lower-case hexadecimal digits.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) {
__formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{"));
}
// [format.string.escaped]/2.2.3
// Otherwise (X is a sequence of ill-formed code units), each code unit U is
// appended to E in order as the sequence \x{hex-digit-sequence}, where
// hex-digit-sequence is the shortest hexadecimal representation of U using
// lower-case hexadecimal digits.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) {
__formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{"));
}
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value) {
# ifdef _LIBCPP_HAS_NO_UNICODE
// For ASCII assume everything above 127 is printable.
if (__value > 127)
return false;
# endif
if (!__escaped_output_table::__needs_escape(__value))
return false;
__formatter::__write_well_formed_escaped_code_unit(__str, __value);
return true;
}
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) {
return static_cast<make_unsigned_t<_CharT>>(__value);
}
enum class _LIBCPP_ENUM_VIS __escape_quotation_mark { __apostrophe, __double_quote };
// [format.string.escaped]/2
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
__is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value, __escape_quotation_mark __mark) {
// 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
switch (__value) {
case _CharT('\t'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t");
return true;
case _CharT('\n'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n");
return true;
case _CharT('\r'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r");
return true;
case _CharT('\''):
if (__mark == __escape_quotation_mark::__apostrophe)
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')");
else
__str += __value;
return true;
case _CharT('"'):
if (__mark == __escape_quotation_mark::__double_quote)
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")");
else
__str += __value;
return true;
case _CharT('\\'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)");
return true;
// 2.2.1.2 - Space
case _CharT(' '):
__str += __value;
return true;
}
// 2.2.2
// Otherwise, if X is a shift sequence, the effect on E and further
// decoding of S is unspecified.
// For now shift sequences are ignored and treated as Unicode. Other parts
// of the format library do the same. It's unknown how ostream treats them.
// TODO FMT determine what to do with shift sequences.
// 2.2.1.2.1 and 2.2.1.2.2 - Escape
return __formatter::__is_escaped_sequence_written(__str, __formatter::__to_char32(__value));
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void
__escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) {
__unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()};
while (!__view.__at_end()) {
auto __first = __view.__position();
typename __unicode::__consume_result __result = __view.__consume();
if (__result.__status == __unicode::__consume_result::__ok) {
if (!__formatter::__is_escaped_sequence_written(__str, __result.__code_point, __mark))
// 2.2.1.3 - Add the character
ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str));
} else {
// 2.2.3 sequence of ill-formed code units
ranges::for_each(__first, __view.__position(), [&](_CharT __value) {
__formatter::__write_escape_ill_formed_code_unit(__str, __formatter::__to_char32(__value));
});
}
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__format_escaped_char(_CharT __value,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
basic_string<_CharT> __str;
__str += _CharT('\'');
__formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe);
__str += _CharT('\'');
return __formatter::__write(__str.data(), __str.data() + __str.size(), _VSTD::move(__out_it), __specs, __str.size());
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__format_escaped_string(basic_string_view<_CharT> __values,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
basic_string<_CharT> __str;
__str += _CharT('"');
__formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote);
__str += _CharT('"');
return __formatter::__write_string(basic_string_view{__str}, _VSTD::move(__out_it), __specs);
}
# endif // _LIBCPP_STD_VER >= 23
} // namespace __formatter
#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H

View file

@ -10,7 +10,6 @@
#ifndef _LIBCPP___FORMAT_FORMATTER_POINTER_H
#define _LIBCPP___FORMAT_FORMATTER_POINTER_H
#include <__availability>
#include <__config>
#include <__format/concepts.h>
#include <__format/format_parse_context.h>
@ -35,7 +34,7 @@ public:
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_pointer);
__format_spec::__process_display_type_pointer(__parser_.__type_);
__format_spec::__process_display_type_pointer(__parser_.__type_, "a pointer");
return __result;
}
@ -43,11 +42,15 @@ public:
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const void* __ptr, _FormatContext& __ctx) const {
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
__specs.__std_.__alternate_form_ = true;
__specs.__std_.__type_ = __format_spec::__type::__hexadecimal_lower_case;
__specs.__std_.__type_ =
__specs.__std_.__type_ == __format_spec::__type::__pointer_upper_case
? __format_spec::__type::__hexadecimal_upper_case
: __format_spec::__type::__hexadecimal_lower_case;
return __formatter::__format_integer(reinterpret_cast<uintptr_t>(__ptr), __ctx, __specs);
}
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
__format_spec::__parser<_CharT> __parser_;
};
// [format.formatter.spec]/2.4
@ -56,14 +59,11 @@ public:
// - template<> struct formatter<void*, charT>;
// - template<> struct formatter<const void*, charT>;
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<nullptr_t, _CharT>
: public __formatter_pointer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<nullptr_t, _CharT> : public __formatter_pointer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<void*, _CharT> : public __formatter_pointer<_CharT> {
};
struct _LIBCPP_TEMPLATE_VIS formatter<void*, _CharT> : public __formatter_pointer<_CharT> {};
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<const void*, _CharT>
: public __formatter_pointer<_CharT> {};
struct _LIBCPP_TEMPLATE_VIS formatter<const void*, _CharT> : public __formatter_pointer<_CharT> {};
#endif //_LIBCPP_STD_VER >= 20

View file

@ -10,14 +10,13 @@
#ifndef _LIBCPP___FORMAT_FORMATTER_STRING_H
#define _LIBCPP___FORMAT_FORMATTER_STRING_H
#include <__availability>
#include <__config>
#include <__format/concepts.h>
#include <__format/format_parse_context.h>
#include <__format/formatter.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__utility/move.h>
#include <__format/write_escaped.h>
#include <string>
#include <string_view>
@ -59,14 +58,12 @@ public:
// Formatter const char*.
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT>
: public __formatter_string<_CharT> {
struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT> : public __formatter_string<_CharT> {
using _Base = __formatter_string<_CharT>;
template <class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const {
_LIBCPP_ASSERT(__str, "The basic_format_arg constructor should have "
"prevented an invalid pointer.");
_LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer.");
__format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx);
# if _LIBCPP_STD_VER >= 23
@ -98,8 +95,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter<const _CharT*, _CharT>
// Formatter char*.
template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT>
: public formatter<const _CharT*, _CharT> {
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT> : public formatter<const _CharT*, _CharT> {
using _Base = formatter<const _CharT*, _CharT>;
template <class _FormatContext>
@ -110,12 +106,12 @@ struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT>
// Formatter char[].
template <__fmt_char_type _CharT, size_t _Size>
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT>
: public __formatter_string<_CharT> {
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT> : public __formatter_string<_CharT> {
using _Base = __formatter_string<_CharT>;
template <class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __str[_Size], _FormatContext& __ctx) const {
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
format(const _CharT (&__str)[_Size], _FormatContext& __ctx) const {
return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx);
}
};
@ -136,8 +132,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter<basic_string<_CharT, _Traits, _Allocator>,
// Formatter std::string_view.
template <__fmt_char_type _CharT, class _Traits>
struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT>
: public __formatter_string<_CharT> {
struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT> : public __formatter_string<_CharT> {
using _Base = __formatter_string<_CharT>;
template <class _FormatContext>

View file

@ -11,19 +11,16 @@
#define _LIBCPP___FORMAT_FORMATTER_TUPLE_H
#include <__algorithm/ranges_copy.h>
#include <__availability>
#include <__chrono/statically_widen.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/format_parse_context.h>
#include <__format/formatter.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__iterator/back_insert_iterator.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/integer_sequence.h>
#include <__utility/pair.h>
@ -54,22 +51,20 @@ struct _LIBCPP_TEMPLATE_VIS __formatter_tuple {
auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple);
auto __end = __ctx.end();
if (__begin != __end) {
if (*__begin == _CharT('m')) {
if constexpr (sizeof...(_Args) == 2) {
set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
set_brackets({}, {});
++__begin;
} else
std::__throw_format_error("The format specifier m requires a pair or a two-element tuple");
} else if (*__begin == _CharT('n')) {
// Note 'n' is part of the type here
if (__parser_.__clear_brackets_)
set_brackets({}, {});
else if (__begin != __end && *__begin == _CharT('m')) {
if constexpr (sizeof...(_Args) == 2) {
set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
set_brackets({}, {});
++__begin;
}
} else
std::__throw_format_error("Type m requires a pair or a tuple with two elements");
}
if (__begin != __end && *__begin != _CharT('}'))
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
std::__throw_format_error("The format specifier should consume the input or end with a '}'");
__ctx.advance_to(__begin);

View file

@ -0,0 +1,350 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// WARNING, this entire header is generated by
// utils/generate_indic_conjunct_break_table.py
// DO NOT MODIFY!
// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
//
// See Terms of Use <https://www.unicode.org/copyright.html>
// for definitions of Unicode Inc.'s Data Files and Software.
//
// NOTICE TO USER: Carefully read the following legal agreement.
// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
// TERMS AND CONDITIONS OF THIS AGREEMENT.
// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
// THE DATA FILES OR SOFTWARE.
//
// COPYRIGHT AND PERMISSION NOTICE
//
// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved.
// Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of the Unicode data files and any associated documentation
// (the "Data Files") or Unicode software and any associated documentation
// (the "Software") to deal in the Data Files or Software
// without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, and/or sell copies of
// the Data Files or Software, and to permit persons to whom the Data Files
// or Software are furnished to do so, provided that either
// (a) this copyright and permission notice appear with all copies
// of the Data Files or Software, or
// (b) this copyright and permission notice appear in associated
// Documentation.
//
// THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THE DATA FILES OR SOFTWARE.
//
// Except as contained in this notice, the name of a copyright holder
// shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in these Data Files or Software without prior
// written authorization of the copyright holder.
#ifndef _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H
#define _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H
#include <__algorithm/ranges_upper_bound.h>
#include <__config>
#include <__iterator/access.h>
#include <cstddef>
#include <cstdint>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
namespace __indic_conjunct_break {
enum class __property : uint8_t {
// Values generated from the data files.
__Consonant,
__Extend,
__Linker,
// The code unit has none of above properties.
__none
};
/// The entries of the indic conjunct break property table.
///
/// The data is generated from
/// - https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
///
/// The data has 3 values
/// - bits [0, 1] The property. One of the values generated from the datafiles
/// of \ref __property
/// - bits [2, 10] The size of the range.
/// - bits [11, 31] The lower bound code point of the range. The upper bound of
/// the range is lower bound + size.
///
/// The 9 bits for the size allow a maximum range of 512 elements. Some ranges
/// in the Unicode tables are larger. They are stored in multiple consecutive
/// ranges in the data table. An alternative would be to store the sizes in a
/// separate 16-bit value. The original MSVC STL code had such an approach, but
/// this approach uses less space for the data and is about 4% faster in the
/// following benchmark.
/// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp
// clang-format off
_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = {
0x00180139,
0x001a807d,
0x00241811,
0x002c88b1,
0x002df801,
0x002e0805,
0x002e2005,
0x002e3801,
0x00308029,
0x00325851,
0x00338001,
0x0036b019,
0x0036f815,
0x00373805,
0x0037500d,
0x00388801,
0x00398069,
0x003f5821,
0x003fe801,
0x0040b00d,
0x0040d821,
0x00412809,
0x00414811,
0x0042c809,
0x0044c01d,
0x0046505d,
0x00471871,
0x0048a890,
0x0049e001,
0x004a6802,
0x004a880d,
0x004ac01c,
0x004bc01c,
0x004ca84c,
0x004d5018,
0x004d9000,
0x004db00c,
0x004de001,
0x004e6802,
0x004ee004,
0x004ef800,
0x004f8004,
0x004ff001,
0x0051e001,
0x0054a84c,
0x00555018,
0x00559004,
0x0055a810,
0x0055e001,
0x00566802,
0x0057c800,
0x0058a84c,
0x00595018,
0x00599004,
0x0059a810,
0x0059e001,
0x005a6802,
0x005ae004,
0x005af800,
0x005b8800,
0x0060a84c,
0x0061503c,
0x0061e001,
0x00626802,
0x0062a805,
0x0062c008,
0x0065e001,
0x0068a894,
0x0069d805,
0x006a6802,
0x0071c009,
0x0072400d,
0x0075c009,
0x0076400d,
0x0078c005,
0x0079a801,
0x0079b801,
0x0079c801,
0x007b8805,
0x007ba001,
0x007bd00d,
0x007c0001,
0x007c1009,
0x007c3005,
0x007e3001,
0x0081b801,
0x0081c805,
0x00846801,
0x009ae809,
0x00b8a001,
0x00be9001,
0x00bee801,
0x00c54801,
0x00c9c809,
0x00d0b805,
0x00d30001,
0x00d3a81d,
0x00d3f801,
0x00d58035,
0x00d5f83d,
0x00d9a001,
0x00db5821,
0x00dd5801,
0x00df3001,
0x00e1b801,
0x00e68009,
0x00e6a031,
0x00e71019,
0x00e76801,
0x00e7a001,
0x00e7c005,
0x00ee00fd,
0x01006801,
0x01068031,
0x01070801,
0x0107282d,
0x01677809,
0x016bf801,
0x016f007d,
0x01815015,
0x0184c805,
0x05337801,
0x0533a025,
0x0534f005,
0x05378005,
0x05416001,
0x05470045,
0x05495809,
0x054d9801,
0x05558001,
0x05559009,
0x0555b805,
0x0555f005,
0x05560801,
0x0557b001,
0x055f6801,
0x07d8f001,
0x07f1003d,
0x080fe801,
0x08170001,
0x081bb011,
0x08506801,
0x08507801,
0x0851c009,
0x0851f801,
0x08572805,
0x0869200d,
0x08755805,
0x0877e809,
0x087a3029,
0x087c100d,
0x08838001,
0x0883f801,
0x0885d001,
0x08880009,
0x08899805,
0x088b9801,
0x088e5001,
0x0891b001,
0x08974805,
0x0899d805,
0x089b3019,
0x089b8011,
0x08a23001,
0x08a2f001,
0x08a61801,
0x08ae0001,
0x08b5b801,
0x08b95801,
0x08c1d001,
0x08c9f001,
0x08ca1801,
0x08d1a001,
0x08d23801,
0x08d4c801,
0x08ea1001,
0x08ea2005,
0x08ecb801,
0x08fa1001,
0x0b578011,
0x0b598019,
0x0de4f001,
0x0e8b2801,
0x0e8b3809,
0x0e8b7011,
0x0e8bd81d,
0x0e8c2819,
0x0e8d500d,
0x0e921009,
0x0f000019,
0x0f004041,
0x0f00d819,
0x0f011805,
0x0f013011,
0x0f047801,
0x0f098019,
0x0f157001,
0x0f17600d,
0x0f27600d,
0x0f468019,
0x0f4a2019};
// clang-format on
/// Returns the indic conjuct break property of a code point.
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept {
// The algorithm searches for the upper bound of the range and, when found,
// steps back one entry. This algorithm is used since the code point can be
// anywhere in the range. After a lower bound is found the next step is to
// compare whether the code unit is indeed in the range.
//
// Since the entry contains a code unit, size, and property the code point
// being sought needs to be adjusted. Just shifting the code point to the
// proper position doesn't work; suppose an entry has property 0, size 1,
// and lower bound 3. This results in the entry 0x1810.
// When searching for code point 3 it will search for 0x1800, find 0x1810
// and moves to the previous entry. Thus the lower bound value will never
// be found.
// The simple solution is to set the bits belonging to the property and
// size. Then the upper bound for code point 3 will return the entry after
// 0x1810. After moving to the previous entry the algorithm arrives at the
// correct entry.
ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries;
if (__i == 0)
return __property::__none;
--__i;
uint32_t __upper_bound = (__entries[__i] >> 11) + ((__entries[__i] >> 2) & 0b1'1111'1111);
if (__code_point <= __upper_bound)
return static_cast<__property>(__entries[__i] & 0b11);
return __property::__none;
}
} // namespace __indic_conjunct_break
#endif //_LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H

View file

@ -17,13 +17,11 @@
/// affect the std-format-spec.
#include <__algorithm/copy_n.h>
#include <__algorithm/find_if.h>
#include <__algorithm/min.h>
#include <__assert>
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.h>
#include <__config>
#include <__debug>
#include <__format/format_arg.h>
#include <__format/format_error.h>
#include <__format/format_parse_context.h>
@ -31,12 +29,14 @@
#include <__format/unicode.h>
#include <__format/width_estimation_table.h>
#include <__iterator/concepts.h>
#include <__iterator/readable_traits.h> // iter_value_t
#include <__iterator/iterator_traits.h> // iter_value_t
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_trivially_copyable.h>
#include <__variant/monostate.h>
#include <cstdint>
#include <string>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -52,6 +52,17 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace __format_spec {
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void
__throw_invalid_option_format_error(const char* __id, const char* __option) {
std::__throw_format_error(
(string("The format specifier for ") + __id + " does not allow the " + __option + " option").c_str());
}
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __throw_invalid_type_format_error(const char* __id) {
std::__throw_format_error(
(string("The type option contains an invalid value for ") + __id + " formatting argument").c_str());
}
template <contiguous_iterator _Iterator, class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator>
__parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) {
@ -59,20 +70,19 @@ __parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) {
// This function is a wrapper to call the real parser. But it does the
// validation for the pre-conditions and post-conditions.
if (__begin == __end)
std::__throw_format_error("End of input while parsing format-spec arg-id");
std::__throw_format_error("End of input while parsing an argument index");
__format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __ctx);
if (__r.__last == __end || *__r.__last != _CharT('}'))
std::__throw_format_error("Invalid arg-id");
std::__throw_format_error("The argument index is invalid");
++__r.__last;
return __r;
}
template <class _Context>
_LIBCPP_HIDE_FROM_ABI constexpr uint32_t
__substitute_arg_id(basic_format_arg<_Context> __format_arg) {
_LIBCPP_HIDE_FROM_ABI constexpr uint32_t __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
// [format.string.std]/8
// If the corresponding formatting argument is not of integral type...
// This wording allows char and bool too. LWG-3720 changes the wording to
@ -81,11 +91,11 @@ __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
// This means the 128-bit will not be valid anymore.
// TODO FMT Verify this resolution is accepted and add a test to verify
// 128-bit integrals fail and switch to visit_format_arg.
return _VSTD::__visit_format_arg(
return std::__visit_format_arg(
[](auto __arg) -> uint32_t {
using _Type = decltype(__arg);
if constexpr (same_as<_Type, monostate>)
std::__throw_format_error("Argument index out of bounds");
std::__throw_format_error("The argument index value is too large for the number of arguments supplied");
// [format.string.std]/8
// If { arg-idopt } is used in a width or precision, the value of the
@ -101,12 +111,12 @@ __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
same_as<_Type, long long> || same_as<_Type, unsigned long long>) {
if constexpr (signed_integral<_Type>) {
if (__arg < 0)
std::__throw_format_error("A format-spec arg-id replacement shouldn't have a negative value");
std::__throw_format_error("An argument index may not have a negative value");
}
using _CT = common_type_t<_Type, decltype(__format::__number_max)>;
if (static_cast<_CT>(__arg) > static_cast<_CT>(__format::__number_max))
std::__throw_format_error("A format-spec arg-id replacement exceeds the maximum supported value");
std::__throw_format_error("The value of the argument index exceeds its maximum value");
return __arg;
} else
@ -119,48 +129,52 @@ __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
///
/// They default to false so when a new field is added it needs to be opted in
/// explicitly.
// TODO FMT Use an ABI tag for this struct.
struct __fields {
uint8_t __sign_ : 1 {false};
uint8_t __alternate_form_ : 1 {false};
uint8_t __zero_padding_ : 1 {false};
uint8_t __precision_ : 1 {false};
uint8_t __locale_specific_form_ : 1 {false};
uint8_t __type_ : 1 {false};
struct _LIBCPP_HIDE_FROM_ABI __fields {
uint16_t __sign_ : 1 {false};
uint16_t __alternate_form_ : 1 {false};
uint16_t __zero_padding_ : 1 {false};
uint16_t __precision_ : 1 {false};
uint16_t __locale_specific_form_ : 1 {false};
uint16_t __type_ : 1 {false};
// Determines the valid values for fill.
//
// Originally the fill could be any character except { and }. Range-based
// formatters use the colon to mark the beginning of the
// underlying-format-spec. To avoid parsing ambiguities these formatter
// specializations prohibit the use of the colon as a fill character.
uint8_t __use_range_fill_ : 1 {false};
uint16_t __use_range_fill_ : 1 {false};
uint16_t __clear_brackets_ : 1 {false};
uint16_t __consume_all_ : 1 {false};
};
// By not placing this constant in the formatter class it's not duplicated for
// char and wchar_t.
inline constexpr __fields __fields_bool{.__locale_specific_form_ = true, .__type_ = true, .__consume_all_ = true};
inline constexpr __fields __fields_integral{
.__sign_ = true,
.__alternate_form_ = true,
.__zero_padding_ = true,
.__locale_specific_form_ = true,
.__type_ = true};
.__type_ = true,
.__consume_all_ = true};
inline constexpr __fields __fields_floating_point{
.__sign_ = true,
.__alternate_form_ = true,
.__zero_padding_ = true,
.__precision_ = true,
.__locale_specific_form_ = true,
.__type_ = true};
inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true};
inline constexpr __fields __fields_pointer{.__type_ = true};
.__type_ = true,
.__consume_all_ = true};
inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true, .__consume_all_ = true};
inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = true, .__consume_all_ = true};
# if _LIBCPP_STD_VER >= 23
inline constexpr __fields __fields_tuple{.__use_range_fill_ = true};
inline constexpr __fields __fields_range{.__use_range_fill_ = true};
inline constexpr __fields __fields_tuple{.__use_range_fill_ = true, .__clear_brackets_ = true};
inline constexpr __fields __fields_range{.__use_range_fill_ = true, .__clear_brackets_ = true};
inline constexpr __fields __fields_fill_align_width{};
# endif
enum class _LIBCPP_ENUM_VIS __alignment : uint8_t {
enum class __alignment : uint8_t {
/// No alignment is set in the format string.
__default,
__left,
@ -169,7 +183,7 @@ enum class _LIBCPP_ENUM_VIS __alignment : uint8_t {
__zero_padding
};
enum class _LIBCPP_ENUM_VIS __sign : uint8_t {
enum class __sign : uint8_t {
/// No sign is set in the format string.
///
/// The sign isn't allowed for certain format-types. By using this value
@ -181,8 +195,8 @@ enum class _LIBCPP_ENUM_VIS __sign : uint8_t {
__space
};
enum class _LIBCPP_ENUM_VIS __type : uint8_t {
__default,
enum class __type : uint8_t {
__default = 0,
__string,
__binary_lower_case,
__binary_upper_case,
@ -190,7 +204,8 @@ enum class _LIBCPP_ENUM_VIS __type : uint8_t {
__decimal,
__hexadecimal_lower_case,
__hexadecimal_upper_case,
__pointer,
__pointer_lower_case,
__pointer_upper_case,
__char,
__hexfloat_lower_case,
__hexfloat_upper_case,
@ -203,23 +218,42 @@ enum class _LIBCPP_ENUM_VIS __type : uint8_t {
__debug
};
_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __create_type_mask(__type __t) {
uint32_t __shift = static_cast<uint32_t>(__t);
if (__shift == 0)
return 1;
if (__shift > 31)
std::__throw_format_error("The type does not fit in the mask");
return 1 << __shift;
}
inline constexpr uint32_t __type_mask_integer =
__create_type_mask(__type::__binary_lower_case) | //
__create_type_mask(__type::__binary_upper_case) | //
__create_type_mask(__type::__decimal) | //
__create_type_mask(__type::__octal) | //
__create_type_mask(__type::__hexadecimal_lower_case) | //
__create_type_mask(__type::__hexadecimal_upper_case);
struct __std {
__alignment __alignment_ : 3;
__sign __sign_ : 2;
bool __alternate_form_ : 1;
__alignment __alignment_ : 3;
__sign __sign_ : 2;
bool __alternate_form_ : 1;
bool __locale_specific_form_ : 1;
__type __type_;
};
struct __chrono {
__alignment __alignment_ : 3;
__alignment __alignment_ : 3;
bool __locale_specific_form_ : 1;
bool __hour_ : 1;
bool __weekday_name_ : 1;
bool __weekday_name_ : 1;
bool __weekday_ : 1;
bool __day_of_year_ : 1;
bool __week_of_year_ : 1;
bool __month_name_ : 1;
bool __month_name_ : 1;
};
// The fill UCS scalar value.
@ -303,50 +337,163 @@ static_assert(is_trivially_copyable_v<__parsed_specifications<wchar_t>>);
template <class _CharT>
class _LIBCPP_TEMPLATE_VIS __parser {
public:
// Parses the format specification.
//
// Depending on whether the parsing is done compile-time or run-time
// the method slightly differs.
// - Only parses a field when it is in the __fields. Accepting all
// fields and then validating the valid ones has a performance impact.
// This is faster but gives slighly worse error messages.
// - At compile-time when a field is not accepted the parser will still
// parse it and give an error when it's present. This gives a more
// accurate error.
// The idea is that most times the format instead of the vformat
// functions are used. In that case the error will be detected during
// compilation and there is no need to pay for the run-time overhead.
template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) {
auto __begin = __ctx.begin();
auto __end = __ctx.end();
if (__begin == __end)
if (__begin == __end || *__begin == _CharT('}') || (__fields.__use_range_fill_ && *__begin == _CharT(':')))
return __begin;
if (__parse_fill_align(__begin, __end, __fields.__use_range_fill_) && __begin == __end)
if (__parse_fill_align(__begin, __end) && __begin == __end)
return __begin;
if (__fields.__sign_ && __parse_sign(__begin) && __begin == __end)
return __begin;
if (__fields.__sign_) {
if (__parse_sign(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_sign(__begin)) {
std::__throw_format_error("The format specification does not allow the sign option");
}
if (__fields.__alternate_form_ && __parse_alternate_form(__begin) && __begin == __end)
return __begin;
if (__fields.__alternate_form_) {
if (__parse_alternate_form(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_alternate_form(__begin)) {
std::__throw_format_error("The format specifier does not allow the alternate form option");
}
if (__fields.__zero_padding_ && __parse_zero_padding(__begin) && __begin == __end)
return __begin;
if (__fields.__zero_padding_) {
if (__parse_zero_padding(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_zero_padding(__begin)) {
std::__throw_format_error("The format specifier does not allow the zero-padding option");
}
if (__parse_width(__begin, __end, __ctx) && __begin == __end)
return __begin;
if (__fields.__precision_ && __parse_precision(__begin, __end, __ctx) && __begin == __end)
return __begin;
if (__fields.__precision_) {
if (__parse_precision(__begin, __end, __ctx) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_precision(__begin, __end, __ctx)) {
std::__throw_format_error("The format specifier does not allow the precision option");
}
if (__fields.__locale_specific_form_ && __parse_locale_specific_form(__begin) && __begin == __end)
return __begin;
if (__fields.__locale_specific_form_) {
if (__parse_locale_specific_form(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_locale_specific_form(__begin)) {
std::__throw_format_error("The format specifier does not allow the locale-specific form option");
}
if (__fields.__type_) {
if (__fields.__clear_brackets_) {
if (__parse_clear_brackets(__begin) && __begin == __end)
return __begin;
} else if (std::is_constant_evaluated() && __parse_clear_brackets(__begin)) {
std::__throw_format_error("The format specifier does not allow the n option");
}
if (__fields.__type_)
__parse_type(__begin);
// When __type_ is false the calling parser is expected to do additional
// parsing. In that case that parser should do the end of format string
// validation.
if (__begin != __end && *__begin != _CharT('}'))
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
}
if (!__fields.__consume_all_)
return __begin;
if (__begin != __end && *__begin != _CharT('}'))
std::__throw_format_error("The format specifier should consume the input or end with a '}'");
return __begin;
}
// Validates the selected the parsed data.
//
// The valid fields in the parser may depend on the display type
// selected. But the type is the last optional field, so by the time
// it's known an option can't be used, it already has been parsed.
// This does the validation again.
//
// For example an integral may have a sign, zero-padding, or alternate
// form when the type option is not 'c'. So the generic approach is:
//
// typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral);
// if (__parser.__type_ == __format_spec::__type::__char) {
// __parser.__validate((__format_spec::__fields_bool, "an integer");
// ... // more char adjustments
// } else {
// ... // validate an integral type.
// }
//
// For some types all valid options need a second validation run, like
// boolean types.
//
// Depending on whether the validation is done at compile-time or
// run-time the error differs
// - run-time the exception is thrown and contains the type of field
// being validated.
// - at compile-time the line with `std::__throw_format_error` is shown
// in the output. In that case it's important for the error to be on one
// line.
// Note future versions of C++ may allow better compile-time error
// reporting.
_LIBCPP_HIDE_FROM_ABI constexpr void
__validate(__fields __fields, const char* __id, uint32_t __type_mask = -1) const {
if (!__fields.__sign_ && __sign_ != __sign::__default) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the sign option");
else
__format_spec::__throw_invalid_option_format_error(__id, "sign");
}
if (!__fields.__alternate_form_ && __alternate_form_) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the alternate form option");
else
__format_spec::__throw_invalid_option_format_error(__id, "alternate form");
}
if (!__fields.__zero_padding_ && __alignment_ == __alignment::__zero_padding) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the zero-padding option");
else
__format_spec::__throw_invalid_option_format_error(__id, "zero-padding");
}
if (!__fields.__precision_ && __precision_ != -1) { // Works both when the precision has a value or an arg-id.
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the precision option");
else
__format_spec::__throw_invalid_option_format_error(__id, "precision");
}
if (!__fields.__locale_specific_form_ && __locale_specific_form_) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier does not allow the locale-specific form option");
else
__format_spec::__throw_invalid_option_format_error(__id, "locale-specific form");
}
if ((__create_type_mask(__type_) & __type_mask) == 0) {
if (std::is_constant_evaluated())
std::__throw_format_error("The format specifier uses an invalid value for the type option");
else
__format_spec::__throw_invalid_type_format_error(__id);
}
}
/// \returns the `__parsed_specifications` with the resolved dynamic sizes..
_LIBCPP_HIDE_FROM_ABI
__parsed_specifications<_CharT> __get_parsed_std_specifications(auto& __ctx) const {
_LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_std_specifications(auto& __ctx) const {
return __parsed_specifications<_CharT>{
.__std_ = __std{.__alignment_ = __alignment_,
.__sign_ = __sign_,
@ -374,11 +521,11 @@ public:
.__fill_{__fill_}};
}
__alignment __alignment_ : 3 {__alignment::__default};
__sign __sign_ : 2 {__sign::__default};
bool __alternate_form_ : 1 {false};
__alignment __alignment_ : 3 {__alignment::__default};
__sign __sign_ : 2 {__sign::__default};
bool __alternate_form_ : 1 {false};
bool __locale_specific_form_ : 1 {false};
bool __reserved_0_ : 1 {false};
bool __clear_brackets_ : 1 {false};
__type __type_{__type::__default};
// These flags are only used for formatting chrono. Since the struct has
@ -393,11 +540,11 @@ public:
bool __month_name_ : 1 {false};
uint8_t __reserved_1_ : 2 {0};
uint8_t __reserved_2_ : 6 {0};
uint8_t __reserved_0_ : 2 {0};
uint8_t __reserved_1_ : 6 {0};
// These two flags are only used internally and not part of the
// __parsed_specifications. Therefore put them at the end.
bool __width_as_arg_ : 1 {false};
bool __width_as_arg_ : 1 {false};
bool __precision_as_arg_ : 1 {false};
/// The requested width, either the value or the arg-id.
@ -426,13 +573,11 @@ private:
return false;
}
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill, bool __use_range_fill) {
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill) {
// The forbidden fill characters all code points formed from a single code unit, thus the
// check can be omitted when more code units are used.
if (__use_range_fill && (__fill == _CharT('{') || __fill == _CharT('}') || __fill == _CharT(':')))
std::__throw_format_error("The format-spec range-fill field contains an invalid character");
else if (__fill == _CharT('{') || __fill == _CharT('}'))
std::__throw_format_error("The format-spec fill field contains an invalid character");
if (__fill == _CharT('{'))
std::__throw_format_error("The fill option contains an invalid value");
}
# ifndef _LIBCPP_HAS_NO_UNICODE
@ -442,14 +587,15 @@ private:
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|| (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
# endif
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_ASSERT(__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
__unicode::__code_point_view<_CharT> __view{__begin, __end};
__unicode::__consume_result __consumed = __view.__consume();
if (__consumed.__status != __unicode::__consume_result::__ok)
std::__throw_format_error("The format-spec contains malformed Unicode characters");
std::__throw_format_error("The format specifier contains malformed Unicode characters");
if (__view.__position() < __end && __parse_alignment(*__view.__position())) {
ptrdiff_t __code_units = __view.__position() - __begin;
@ -457,7 +603,7 @@ private:
// The forbidden fill characters all are code points encoded
// in one code unit, thus the check can be omitted when more
// code units are used.
__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);
std::copy_n(__begin, __code_units, std::addressof(__fill_.__data[0]));
__begin += __code_units + 1;
@ -474,15 +620,16 @@ private:
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <contiguous_iterator _Iterator>
requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_ASSERT(__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
if (__begin + 1 != __end && __parse_alignment(*(__begin + 1))) {
if (!__unicode::__is_scalar_value(*__begin))
std::__throw_format_error("The fill character contains an invalid value");
std::__throw_format_error("The fill option contains an invalid value");
__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);
__fill_.__data[0] = *__begin;
__begin += 2;
@ -501,13 +648,14 @@ private:
# else // _LIBCPP_HAS_NO_UNICODE
// range-fill and tuple-fill are identical
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end, bool __use_range_fill) {
_LIBCPP_ASSERT(__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
__begin != __end,
"when called with an empty input the function will cause "
"undefined behavior by evaluating data not in the input");
if (__begin + 1 != __end) {
if (__parse_alignment(*(__begin + 1))) {
__validate_fill_character(*__begin, __use_range_fill);
__validate_fill_character(*__begin);
__fill_.__data[0] = *__begin;
__begin += 2;
@ -567,13 +715,13 @@ private:
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __ctx) {
if (*__begin == _CharT('0'))
std::__throw_format_error("A format-spec width field shouldn't have a leading zero");
std::__throw_format_error("The width option should not have a leading zero");
if (*__begin == _CharT('{')) {
__format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
__width_as_arg_ = true;
__width_ = __r.__value;
__begin = __r.__last;
__width_as_arg_ = true;
__width_ = __r.__value;
__begin = __r.__last;
return true;
}
@ -581,9 +729,10 @@ private:
return false;
__format::__parse_number_result __r = __format::__parse_number(__begin, __end);
__width_ = __r.__value;
_LIBCPP_ASSERT(__width_ != 0, "A zero value isn't allowed and should be impossible, "
"due to validations in this function");
__width_ = __r.__value;
_LIBCPP_ASSERT_INTERNAL(__width_ != 0,
"A zero value isn't allowed and should be impossible, "
"due to validations in this function");
__begin = __r.__last;
return true;
}
@ -595,23 +744,23 @@ private:
++__begin;
if (__begin == __end)
std::__throw_format_error("End of input while parsing format-spec precision");
std::__throw_format_error("End of input while parsing format specifier precision");
if (*__begin == _CharT('{')) {
__format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __ctx);
__precision_as_arg_ = true;
__precision_ = __arg_id.__value;
__begin = __arg_id.__last;
__precision_as_arg_ = true;
__precision_ = __arg_id.__value;
__begin = __arg_id.__last;
return true;
}
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
std::__throw_format_error("The format-spec precision field doesn't contain a value or arg-id");
std::__throw_format_error("The precision option does not contain a value or an argument index");
__format::__parse_number_result __r = __format::__parse_number(__begin, __end);
__precision_ = __r.__value;
__precision_as_arg_ = false;
__begin = __r.__last;
__precision_ = __r.__value;
__precision_as_arg_ = false;
__begin = __r.__last;
return true;
}
@ -625,6 +774,16 @@ private:
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr bool __parse_clear_brackets(_Iterator& __begin) {
if (*__begin != _CharT('n'))
return false;
__clear_brackets_ = true;
++__begin;
return true;
}
template <contiguous_iterator _Iterator>
_LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin) {
// Determines the type. It does not validate whether the selected type is
@ -676,7 +835,10 @@ private:
__type_ = __type::__octal;
break;
case 'p':
__type_ = __type::__pointer;
__type_ = __type::__pointer_lower_case;
break;
case 'P':
__type_ = __type::__pointer_upper_case;
break;
case 's':
__type_ = __type::__string;
@ -695,16 +857,14 @@ private:
++__begin;
}
_LIBCPP_HIDE_FROM_ABI
int32_t __get_width(auto& __ctx) const {
_LIBCPP_HIDE_FROM_ABI int32_t __get_width(auto& __ctx) const {
if (!__width_as_arg_)
return __width_;
return __format_spec::__substitute_arg_id(__ctx.arg(__width_));
}
_LIBCPP_HIDE_FROM_ABI
int32_t __get_precision(auto& __ctx) const {
_LIBCPP_HIDE_FROM_ABI int32_t __get_precision(auto& __ctx) const {
if (!__precision_as_arg_)
return __precision_;
@ -726,36 +886,28 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_string(__format_spec
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for a string argument");
std::__throw_format_error("The type option contains an invalid value for a string formatting argument");
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser) {
if (__parser.__sign_ != __sign::__default)
std::__throw_format_error("A sign field isn't allowed in this format-spec");
if (__parser.__alternate_form_)
std::__throw_format_error("An alternate form field isn't allowed in this format-spec");
if (__parser.__alignment_ == __alignment::__zero_padding)
std::__throw_format_error("A zero-padding field isn't allowed in this format-spec");
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser, const char* __id) {
__parser.__validate(__format_spec::__fields_bool, __id);
if (__parser.__alignment_ == __alignment::__default)
__parser.__alignment_ = __alignment::__left;
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_char(__parser<_CharT>& __parser) {
__format_spec::__process_display_type_bool_string(__parser);
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_char(__parser<_CharT>& __parser, const char* __id) {
__format_spec::__process_display_type_bool_string(__parser, __id);
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser) {
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__string:
__format_spec::__process_display_type_bool_string(__parser);
__format_spec::__process_display_type_bool_string(__parser, __id);
break;
case __format_spec::__type::__binary_lower_case:
@ -767,17 +919,17 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __p
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for a bool argument");
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser) {
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__char:
case __format_spec::__type::__debug:
__format_spec::__process_display_type_char(__parser);
__format_spec::__process_display_type_char(__parser, __id);
break;
case __format_spec::__type::__binary_lower_case:
@ -789,12 +941,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __p
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for a char argument");
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser) {
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__binary_lower_case:
@ -806,16 +958,16 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>&
break;
case __format_spec::__type::__char:
__format_spec::__process_display_type_char(__parser);
__format_spec::__process_display_type_char(__parser, __id);
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for an integer argument");
__format_spec::__throw_invalid_type_format_error(__id);
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_CharT>& __parser) {
_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_CharT>& __parser, const char* __id) {
switch (__parser.__type_) {
case __format_spec::__type::__default:
case __format_spec::__type::__hexfloat_lower_case:
@ -834,18 +986,19 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_C
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for a floating-point argument");
__format_spec::__throw_invalid_type_format_error(__id);
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type) {
_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type, const char* __id) {
switch (__type) {
case __format_spec::__type::__default:
case __format_spec::__type::__pointer:
case __format_spec::__type::__pointer_lower_case:
case __format_spec::__type::__pointer_upper_case:
break;
default:
std::__throw_format_error("The format-spec type has a type not supported for a pointer argument");
__format_spec::__throw_invalid_type_format_error(__id);
}
}
@ -1002,8 +1155,8 @@ __estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __col
// When Unicode isn't supported assume ASCII and every code unit is one code
// point. In ASCII the estimated column width is always one. Thus there's no
// need for rounding.
size_t __width_ = _VSTD::min(__str.size(), __maximum);
return {__width_, __str.begin() + __width_};
size_t __width = std::min(__str.size(), __maximum);
return {__width, __str.begin() + __width};
}
# endif // !defined(_LIBCPP_HAS_NO_UNICODE)

View file

@ -10,8 +10,11 @@
#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 <__algorithm/ranges_copy.h>
#include <__availability>
#include <__chrono/statically_widen.h>
#include <__concepts/same_as.h>
#include <__config>
@ -21,11 +24,12 @@
#include <__iterator/back_insert_iterator.h>
#include <__ranges/concepts.h>
#include <__ranges/data.h>
#include <__ranges/from_range.h>
#include <__ranges/size.h>
#include <__type_traits/conditional.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/pair.h>
#include <string_view>
#include <tuple>
_LIBCPP_BEGIN_NAMESPACE_STD
@ -108,8 +112,9 @@ public:
return __underlying_.parse(__ctx);
}
template <class FormatContext>
_LIBCPP_HIDE_FROM_ABI typename FormatContext::iterator format(__maybe_const_r& __range, FormatContext& __ctx) const {
template <class _FormatContext>
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
format(__maybe_const_r& __range, _FormatContext& __ctx) const {
return __underlying_.format(__range, __ctx);
}
};
@ -193,15 +198,8 @@ public:
// specialization is the "basic" string formatter in libc++.
if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>)
return __underlying_.format(basic_string_view<_CharT>{ranges::data(__range), ranges::size(__range)}, __ctx);
else {
// 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 __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx);
basic_string<_CharT> __str;
std::ranges::copy(__range, back_insert_iterator{__str});
return __underlying_.format(static_cast<basic_string_view<_CharT>>(__str), __ctx);
}
else
return __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx);
}
};

View file

@ -10,14 +10,16 @@
#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>
@ -26,6 +28,7 @@
#include <__iterator/back_insert_iterator.h>
#include <__ranges/concepts.h>
#include <__ranges/data.h>
#include <__ranges/from_range.h>
#include <__ranges/size.h>
#include <__type_traits/remove_cvref.h>
#include <string_view>
@ -62,18 +65,8 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
// 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) [[unlikely]] {
// Since there is no more data, clear the brackets before returning.
set_brackets({}, {});
return __parse_empty_range_underlying_spec(__ctx, __begin);
}
}
__parse_type(__begin, __end);
if (__clear_brackets)
if (__parser_.__clear_brackets_)
set_brackets({}, {});
if (__begin == __end) [[unlikely]]
return __parse_empty_range_underlying_spec(__ctx, __begin);
@ -89,7 +82,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
// processed by the underlying. For example {:-} for a range in invalid,
// the sign field is not present. Without this check the underlying_ will
// get -} as input which my be valid.
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
std::__throw_format_error("The format specifier should consume the input or end with a '}'");
__ctx.advance_to(__begin);
__begin = __underlying_.parse(__ctx);
@ -102,13 +95,13 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
// could consume more than it should.
if (__begin != __end && *__begin != _CharT('}'))
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
std::__throw_format_error("The format specifier should consume the input or end with a '}'");
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_.__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");
@ -192,13 +185,7 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter {
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);
return __formatter.format(basic_string<_CharT>{from_range, __range}, __ctx);
}
}
@ -231,7 +218,7 @@ private:
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");
std::__throw_format_error("Type m requires a pair or a tuple with two elements");
break;
case _CharT('s'):
@ -239,18 +226,18 @@ private:
__parser_.__type_ = __format_spec::__type::__string;
++__begin;
} else
std::__throw_format_error("The range-format-spec type s requires formatting a character type");
std::__throw_format_error("Type s requires character type as formatting argument");
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 '}'");
std::__throw_format_error("The format specifier 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");
std::__throw_format_error("Type ?s requires character type as formatting argument");
}
}
@ -259,8 +246,8 @@ private:
__parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) {
__ctx.advance_to(__begin);
[[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx);
_LIBCPP_ASSERT(__result == __begin,
"the underlying's parse function should not advance the input beyond the end of the input");
_LIBCPP_ASSERT_INTERNAL(__result == __begin,
"the underlying's parse function should not advance the input beyond the end of the input");
return __begin;
}

View file

@ -15,9 +15,9 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__format/extended_grapheme_cluster_table.h>
#include <__format/indic_conjunct_break_table.h>
#include <__iterator/concepts.h>
#include <__iterator/readable_traits.h> // iter_value_t
#include <__type_traits/make_unsigned.h>
#include <__utility/unreachable.h>
#include <string_view>
@ -105,7 +105,7 @@ template <contiguous_iterator _Iterator>
requires same_as<iter_value_t<_Iterator>, char>
_LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(_Iterator __char, int __count) {
do {
if ((*__char & 0b1000'0000) != 0b1000'0000)
if ((*__char & 0b1100'0000) != 0b1000'0000)
return false;
--__count;
++__char;
@ -155,7 +155,7 @@ public:
// - The parser always needs to consume these code units
// - The code is optimized for well-formed UTF-8
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
_LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
_LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
// Based on the number of leading 1 bits the number of code units in the
// code point can be determined. See
@ -261,7 +261,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
_LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
_LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
char32_t __value = static_cast<char32_t>(*__first_++);
if constexpr (sizeof(wchar_t) == 2) {
@ -294,85 +294,231 @@ private:
};
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
_LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break(
bool& __ri_break_allowed,
bool __has_extened_pictographic,
__extended_grapheme_custer_property_boundary::__property __prev,
__extended_grapheme_custer_property_boundary::__property __next) {
using __extended_grapheme_custer_property_boundary::__property;
// State machine to implement the Extended Grapheme Cluster Boundary
//
// The exact rules may change between Unicode versions.
// This implements the extended rules see
// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
class __extended_grapheme_cluster_break {
using __EGC_property = __extended_grapheme_custer_property_boundary::__property;
using __inCB_property = __indic_conjunct_break::__property;
__has_extened_pictographic |= __prev == __property::__Extended_Pictographic;
// https://www.unicode.org/reports/tr29/tr29-39.html#Grapheme_Cluster_Boundary_Rules
// *** Break at the start and end of text, unless the text is empty. ***
_LIBCPP_ASSERT(__prev != __property::__sot, "should be handled in the constructor"); // GB1
_LIBCPP_ASSERT(__prev != __property::__eot, "should be handled by our caller"); // GB2
// *** Do not break between a CR and LF. Otherwise, break before and after controls. ***
if (__prev == __property::__CR && __next == __property::__LF) // GB3
return false;
if (__prev == __property::__Control || __prev == __property::__CR || __prev == __property::__LF) // GB4
return true;
if (__next == __property::__Control || __next == __property::__CR || __next == __property::__LF) // GB5
return true;
// *** Do not break Hangul syllable sequences. ***
if (__prev == __property::__L &&
(__next == __property::__L || __next == __property::__V || __next == __property::__LV ||
__next == __property::__LVT)) // GB6
return false;
if ((__prev == __property::__LV || __prev == __property::__V) &&
(__next == __property::__V || __next == __property::__T)) // GB7
return false;
if ((__prev == __property::__LVT || __prev == __property::__T) && __next == __property::__T) // GB8
return false;
// *** Do not break before extending characters or ZWJ. ***
if (__next == __property::__Extend || __next == __property::__ZWJ)
return false; // GB9
// *** Do not break before SpacingMarks, or after Prepend characters. ***
if (__next == __property::__SpacingMark) // GB9a
return false;
if (__prev == __property::__Prepend) // GB9b
return false;
// *** Do not break within emoji modifier sequences or emoji zwj sequences. ***
// GB11 \p{Extended_Pictographic} Extend* ZWJ x \p{Extended_Pictographic}
//
// Note that several parts of this rule are matched by GB9: Any x (Extend | ZWJ)
// - \p{Extended_Pictographic} x Extend
// - Extend x Extend
// - \p{Extended_Pictographic} x ZWJ
// - Extend x ZWJ
//
// So the only case left to test is
// - \p{Extended_Pictographic}' x ZWJ x \p{Extended_Pictographic}
// where \p{Extended_Pictographic}' is stored in __has_extened_pictographic
if (__has_extened_pictographic && __prev == __property::__ZWJ && __next == __property::__Extended_Pictographic)
return false;
// *** Do not break within emoji flag sequences ***
// That is, do not break between regional indicator (RI) symbols if there
// is an odd number of RI characters before the break point.
if (__prev == __property::__Regional_Indicator && __next == __property::__Regional_Indicator) { // GB12 + GB13
__ri_break_allowed = !__ri_break_allowed;
return __ri_break_allowed;
public:
_LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_break(char32_t __first_code_point)
: __prev_code_point_(__first_code_point),
__prev_property_(__extended_grapheme_custer_property_boundary::__get_property(__first_code_point)) {
// Initializes the active rule.
if (__prev_property_ == __EGC_property::__Extended_Pictographic)
__active_rule_ = __rule::__GB11_emoji;
else if (__prev_property_ == __EGC_property::__Regional_Indicator)
__active_rule_ = __rule::__GB12_GB13_regional_indicator;
else if (__indic_conjunct_break::__get_property(__first_code_point) == __inCB_property::__Consonant)
__active_rule_ = __rule::__GB9c_indic_conjunct_break;
}
// *** Otherwise, break everywhere. ***
return true; // GB999
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(char32_t __next_code_point) {
__EGC_property __next_property = __extended_grapheme_custer_property_boundary::__get_property(__next_code_point);
bool __result = __evaluate(__next_code_point, __next_property);
__prev_code_point_ = __next_code_point;
__prev_property_ = __next_property;
return __result;
}
// The code point whose break propery are considered during the next
// evaluation cyle.
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __current_code_point() const { return __prev_code_point_; }
private:
// The naming of the identifiers matches the Unicode standard.
// NOLINTBEGIN(readability-identifier-naming)
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool
__evaluate(char32_t __next_code_point, __EGC_property __next_property) {
switch (__active_rule_) {
case __rule::__none:
return __evaluate_none(__next_code_point, __next_property);
case __rule::__GB9c_indic_conjunct_break:
return __evaluate_GB9c_indic_conjunct_break(__next_code_point, __next_property);
case __rule::__GB11_emoji:
return __evaluate_GB11_emoji(__next_code_point, __next_property);
case __rule::__GB12_GB13_regional_indicator:
return __evaluate_GB12_GB13_regional_indicator(__next_code_point, __next_property);
}
__libcpp_unreachable();
}
_LIBCPP_HIDE_FROM_ABI constexpr bool __evaluate_none(char32_t __next_code_point, __EGC_property __next_property) {
// *** Break at the start and end of text, unless the text is empty. ***
_LIBCPP_ASSERT_INTERNAL(__prev_property_ != __EGC_property::__sot, "should be handled in the constructor"); // GB1
_LIBCPP_ASSERT_INTERNAL(__prev_property_ != __EGC_property::__eot, "should be handled by our caller"); // GB2
// *** Do not break between a CR and LF. Otherwise, break before and after controls. ***
if (__prev_property_ == __EGC_property::__CR && __next_property == __EGC_property::__LF) // GB3
return false;
if (__prev_property_ == __EGC_property::__Control || __prev_property_ == __EGC_property::__CR ||
__prev_property_ == __EGC_property::__LF) // GB4
return true;
if (__next_property == __EGC_property::__Control || __next_property == __EGC_property::__CR ||
__next_property == __EGC_property::__LF) // GB5
return true;
// *** Do not break Hangul syllable sequences. ***
if (__prev_property_ == __EGC_property::__L &&
(__next_property == __EGC_property::__L || __next_property == __EGC_property::__V ||
__next_property == __EGC_property::__LV || __next_property == __EGC_property::__LVT)) // GB6
return false;
if ((__prev_property_ == __EGC_property::__LV || __prev_property_ == __EGC_property::__V) &&
(__next_property == __EGC_property::__V || __next_property == __EGC_property::__T)) // GB7
return false;
if ((__prev_property_ == __EGC_property::__LVT || __prev_property_ == __EGC_property::__T) &&
__next_property == __EGC_property::__T) // GB8
return false;
// *** Do not break before extending characters or ZWJ. ***
if (__next_property == __EGC_property::__Extend || __next_property == __EGC_property::__ZWJ)
return false; // GB9
// *** Do not break before SpacingMarks, or after Prepend characters. ***
if (__next_property == __EGC_property::__SpacingMark) // GB9a
return false;
if (__prev_property_ == __EGC_property::__Prepend) // GB9b
return false;
// *** Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. ***
if (__indic_conjunct_break::__get_property(__next_code_point) == __inCB_property::__Consonant) {
__active_rule_ = __rule::__GB9c_indic_conjunct_break;
__GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant;
return true;
}
// *** Do not break within emoji modifier sequences or emoji zwj sequences. ***
if (__next_property == __EGC_property::__Extended_Pictographic) {
__active_rule_ = __rule::__GB11_emoji;
__GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic;
return true;
}
// *** Do not break within emoji flag sequences ***
// That is, do not break between regional indicator (RI) symbols if there
// is an odd number of RI characters before the break point.
if (__next_property == __EGC_property::__Regional_Indicator) { // GB12 + GB13
__active_rule_ = __rule::__GB12_GB13_regional_indicator;
return true;
}
// *** Otherwise, break everywhere. ***
return true; // GB999
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool
__evaluate_GB9c_indic_conjunct_break(char32_t __next_code_point, __EGC_property __next_property) {
__inCB_property __break = __indic_conjunct_break::__get_property(__next_code_point);
if (__break == __inCB_property::__none) {
__active_rule_ = __rule::__none;
return __evaluate_none(__next_code_point, __next_property);
}
switch (__GB9c_indic_conjunct_break_state_) {
case __GB9c_indic_conjunct_break_state::__Consonant:
if (__break == __inCB_property::__Extend) {
return false;
}
if (__break == __inCB_property::__Linker) {
__GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Linker;
return false;
}
__active_rule_ = __rule::__none;
return __evaluate_none(__next_code_point, __next_property);
case __GB9c_indic_conjunct_break_state::__Linker:
if (__break == __inCB_property::__Extend) {
return false;
}
if (__break == __inCB_property::__Linker) {
return false;
}
if (__break == __inCB_property::__Consonant) {
__GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant;
return false;
}
__active_rule_ = __rule::__none;
return __evaluate_none(__next_code_point, __next_property);
}
__libcpp_unreachable();
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool
__evaluate_GB11_emoji(char32_t __next_code_point, __EGC_property __next_property) {
switch (__GB11_emoji_state_) {
case __GB11_emoji_state::__Extended_Pictographic:
if (__next_property == __EGC_property::__Extend) {
__GB11_emoji_state_ = __GB11_emoji_state::__Extend;
return false;
}
[[fallthrough]];
case __GB11_emoji_state::__Extend:
if (__next_property == __EGC_property::__ZWJ) {
__GB11_emoji_state_ = __GB11_emoji_state::__ZWJ;
return false;
}
if (__next_property == __EGC_property::__Extend)
return false;
__active_rule_ = __rule::__none;
return __evaluate_none(__next_code_point, __next_property);
case __GB11_emoji_state::__ZWJ:
if (__next_property == __EGC_property::__Extended_Pictographic) {
__GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic;
return false;
}
__active_rule_ = __rule::__none;
return __evaluate_none(__next_code_point, __next_property);
}
__libcpp_unreachable();
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool
__evaluate_GB12_GB13_regional_indicator(char32_t __next_code_point, __EGC_property __next_property) {
__active_rule_ = __rule::__none;
if (__next_property == __EGC_property::__Regional_Indicator)
return false;
return __evaluate_none(__next_code_point, __next_property);
}
char32_t __prev_code_point_;
__EGC_property __prev_property_;
enum class __rule {
__none,
__GB9c_indic_conjunct_break,
__GB11_emoji,
__GB12_GB13_regional_indicator,
};
__rule __active_rule_ = __rule::__none;
enum class __GB11_emoji_state {
__Extended_Pictographic,
__Extend,
__ZWJ,
};
__GB11_emoji_state __GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic;
enum class __GB9c_indic_conjunct_break_state {
__Consonant,
__Linker,
};
__GB9c_indic_conjunct_break_state __GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant;
// NOLINTEND(readability-identifier-naming)
};
/// Helper class to extract an extended grapheme cluster from a Unicode character range.
///
@ -385,9 +531,7 @@ class __extended_grapheme_cluster_view {
public:
_LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(_Iterator __first, _Iterator __last)
: __code_point_view_(__first, __last),
__next_code_point_(__code_point_view_.__consume().__code_point),
__next_prop_(__extended_grapheme_custer_property_boundary::__get_property(__next_code_point_)) {}
: __code_point_view_(__first, __last), __at_break_(__code_point_view_.__consume().__code_point) {}
struct __cluster {
/// The first code point of the extended grapheme cluster.
@ -403,45 +547,20 @@ public:
_Iterator __last_;
};
_LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() {
_LIBCPP_ASSERT(
__next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot,
"can't move beyond the end of input");
char32_t __code_point = __next_code_point_;
if (!__code_point_view_.__at_end())
return {__code_point, __get_break()};
__next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot;
return {__code_point, __code_point_view_.__position()};
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() {
char32_t __code_point = __at_break_.__current_code_point();
_Iterator __position = __code_point_view_.__position();
while (!__code_point_view_.__at_end()) {
if (__at_break_(__code_point_view_.__consume().__code_point))
break;
__position = __code_point_view_.__position();
}
return {__code_point, __position};
}
private:
__code_point_view<_CharT> __code_point_view_;
char32_t __next_code_point_;
__extended_grapheme_custer_property_boundary::__property __next_prop_;
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __get_break() {
bool __ri_break_allowed = true;
bool __has_extened_pictographic = false;
while (true) {
_Iterator __result = __code_point_view_.__position();
__extended_grapheme_custer_property_boundary::__property __prev = __next_prop_;
if (__code_point_view_.__at_end()) {
__next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot;
return __result;
}
__next_code_point_ = __code_point_view_.__consume().__code_point;
__next_prop_ = __extended_grapheme_custer_property_boundary::__get_property(__next_code_point_);
__has_extened_pictographic |=
__prev == __extended_grapheme_custer_property_boundary::__property::__Extended_Pictographic;
if (__at_extended_grapheme_cluster_break(__ri_break_allowed, __has_extened_pictographic, __prev, __next_prop_))
return __result;
}
}
__extended_grapheme_cluster_break __at_break_;
};
template <contiguous_iterator _Iterator>
@ -463,7 +582,7 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept {
_LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
_LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input");
return {static_cast<char32_t>(*__first_++)};
}

View file

@ -119,7 +119,7 @@ namespace __width_estimation_table {
/// - bits [0, 13] The size of the range, allowing 16384 elements.
/// - bits [14, 31] The lower bound code point of the range. The upper bound of
/// the range is lower bound + size.
inline constexpr uint32_t __entries[108] = {
_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = {
0x0440005f /* 00001100 - 0000115f [ 96] */, //
0x08c68001 /* 0000231a - 0000231b [ 2] */, //
0x08ca4001 /* 00002329 - 0000232a [ 2] */, //
@ -158,14 +158,13 @@ inline constexpr uint32_t __entries[108] = {
0x0ba00019 /* 00002e80 - 00002e99 [ 26] */, //
0x0ba6c058 /* 00002e9b - 00002ef3 [ 89] */, //
0x0bc000d5 /* 00002f00 - 00002fd5 [ 214] */, //
0x0bfc000b /* 00002ff0 - 00002ffb [ 12] */, //
0x0c00003e /* 00003000 - 0000303e [ 63] */, //
0x0bfc004e /* 00002ff0 - 0000303e [ 79] */, //
0x0c104055 /* 00003041 - 00003096 [ 86] */, //
0x0c264066 /* 00003099 - 000030ff [ 103] */, //
0x0c41402a /* 00003105 - 0000312f [ 43] */, //
0x0c4c405d /* 00003131 - 0000318e [ 94] */, //
0x0c640053 /* 00003190 - 000031e3 [ 84] */, //
0x0c7c002e /* 000031f0 - 0000321e [ 47] */, //
0x0c7bc02f /* 000031ef - 0000321e [ 48] */, //
0x0c880027 /* 00003220 - 00003247 [ 40] */, //
0x0c943fff /* 00003250 - 0000724f [16384] */, //
0x1c94323c /* 00007250 - 0000a48c [12861] */, //
@ -238,7 +237,7 @@ inline constexpr uint32_t __table_upper_bound = 0x0003fffd;
/// Returns the estimated width of a Unicode code point.
///
/// \pre The code point is a valid Unicode code point.
/// \\pre The code point is a valid Unicode code point.
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int __estimated_width(const char32_t __code_point) noexcept {
// Since __table_upper_bound contains the unshifted range do the
// comparison without shifting.

View file

@ -0,0 +1,242 @@
// -*- 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_WRITE_ESCAPED_H
#define _LIBCPP___FORMAT_WRITE_ESCAPED_H
#include <__algorithm/ranges_copy.h>
#include <__algorithm/ranges_for_each.h>
#include <__charconv/to_chars_integral.h>
#include <__charconv/to_chars_result.h>
#include <__chrono/statically_widen.h>
#include <__format/escaped_output_table.h>
#include <__format/formatter_output.h>
#include <__format/parser_std_format_spec.h>
#include <__format/unicode.h>
#include <__iterator/back_insert_iterator.h>
#include <__memory/addressof.h>
#include <__system_error/errc.h>
#include <__type_traits/make_unsigned.h>
#include <__utility/move.h>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
namespace __formatter {
#if _LIBCPP_STD_VER >= 20
/// Writes a string using format's width estimation algorithm.
///
/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
/// input is ASCII.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__write_string(basic_string_view<_CharT> __str,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
if (!__specs.__has_precision())
return __formatter::__write_string_no_precision(__str, std::move(__out_it), __specs);
int __size = __formatter::__truncate(__str, __specs.__precision_);
return __formatter::__write(__str.begin(), __str.end(), std::move(__out_it), __specs, __size);
}
#endif // _LIBCPP_STD_VER >= 20
#if _LIBCPP_STD_VER >= 23
struct __nul_terminator {};
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) {
return *__cstr == _CharT('\0');
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void
__write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) {
back_insert_iterator __out_it{__str};
std::ranges::copy(__prefix, __nul_terminator{}, __out_it);
char __buffer[8];
to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
_LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
__str += _CharT('}');
}
// [format.string.escaped]/2.2.1.2
// ...
// then the sequence \u{hex-digit-sequence} is appended to E, where
// hex-digit-sequence is the shortest hexadecimal representation of C using
// lower-case hexadecimal digits.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) {
__formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{"));
}
// [format.string.escaped]/2.2.3
// Otherwise (X is a sequence of ill-formed code units), each code unit U is
// appended to E in order as the sequence \x{hex-digit-sequence}, where
// hex-digit-sequence is the shortest hexadecimal representation of U using
// lower-case hexadecimal digits.
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) {
__formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{"));
}
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
__is_escaped_sequence_written(basic_string<_CharT>& __str, bool __last_escaped, char32_t __value) {
# ifdef _LIBCPP_HAS_NO_UNICODE
// For ASCII assume everything above 127 is printable.
if (__value > 127)
return false;
# endif
// [format.string.escaped]/2.2.1.2.1
// CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar
// value whose Unicode property General_Category has a value in the groups
// Separator (Z) or Other (C), as described by UAX #44 of the Unicode Standard,
if (!__escaped_output_table::__needs_escape(__value))
// [format.string.escaped]/2.2.1.2.2
// CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar
// value with the Unicode property Grapheme_Extend=Yes as described by UAX
// #44 of the Unicode Standard and C is not immediately preceded in S by a
// character P appended to E without translation to an escape sequence,
if (!__last_escaped || __extended_grapheme_custer_property_boundary::__get_property(__value) !=
__extended_grapheme_custer_property_boundary::__property::__Extend)
return false;
__formatter::__write_well_formed_escaped_code_unit(__str, __value);
return true;
}
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) {
return static_cast<make_unsigned_t<_CharT>>(__value);
}
enum class __escape_quotation_mark { __apostrophe, __double_quote };
// [format.string.escaped]/2
template <class _CharT>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(
basic_string<_CharT>& __str, char32_t __value, bool __last_escaped, __escape_quotation_mark __mark) {
// 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
switch (__value) {
case _CharT('\t'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t");
return true;
case _CharT('\n'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n");
return true;
case _CharT('\r'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r");
return true;
case _CharT('\''):
if (__mark == __escape_quotation_mark::__apostrophe)
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')");
else
__str += __value;
return true;
case _CharT('"'):
if (__mark == __escape_quotation_mark::__double_quote)
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")");
else
__str += __value;
return true;
case _CharT('\\'):
__str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)");
return true;
// 2.2.1.2 - Space
case _CharT(' '):
__str += __value;
return true;
}
// 2.2.2
// Otherwise, if X is a shift sequence, the effect on E and further
// decoding of S is unspecified.
// For now shift sequences are ignored and treated as Unicode. Other parts
// of the format library do the same. It's unknown how ostream treats them.
// TODO FMT determine what to do with shift sequences.
// 2.2.1.2.1 and 2.2.1.2.2 - Escape
return __formatter::__is_escaped_sequence_written(__str, __last_escaped, __formatter::__to_char32(__value));
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI void
__escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) {
__unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()};
// When the first code unit has the property Grapheme_Extend=Yes it needs to
// be escaped. This happens when the previous code unit was also escaped.
bool __escape = true;
while (!__view.__at_end()) {
auto __first = __view.__position();
typename __unicode::__consume_result __result = __view.__consume();
if (__result.__status == __unicode::__consume_result::__ok) {
__escape = __formatter::__is_escaped_sequence_written(__str, __result.__code_point, __escape, __mark);
if (!__escape)
// 2.2.1.3 - Add the character
ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str));
} else {
// 2.2.3 sequence of ill-formed code units
ranges::for_each(__first, __view.__position(), [&](_CharT __value) {
__formatter::__write_escape_ill_formed_code_unit(__str, __formatter::__to_char32(__value));
});
}
}
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__format_escaped_char(_CharT __value,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
basic_string<_CharT> __str;
__str += _CharT('\'');
__formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe);
__str += _CharT('\'');
return __formatter::__write(__str.data(), __str.data() + __str.size(), std::move(__out_it), __specs, __str.size());
}
template <class _CharT>
_LIBCPP_HIDE_FROM_ABI auto
__format_escaped_string(basic_string_view<_CharT> __values,
output_iterator<const _CharT&> auto __out_it,
__format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
basic_string<_CharT> __str;
__str += _CharT('"');
__formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote);
__str += _CharT('"');
return __formatter::__write_string(basic_string_view{__str}, std::move(__out_it), __specs);
}
#endif // _LIBCPP_STD_VER >= 23
} // namespace __formatter
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_WRITE_ESCAPED_H