mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
Upgrade to 2022-era LLVM LIBCXX
This commit is contained in:
parent
2f4ca71f26
commit
8e68384e15
2078 changed files with 165657 additions and 65010 deletions
643
third_party/libcxx/__format/buffer.h
vendored
Normal file
643
third_party/libcxx/__format/buffer.h
vendored
Normal file
|
@ -0,0 +1,643 @@
|
|||
// -*- 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_BUFFER_H
|
||||
#define _LIBCPP___FORMAT_BUFFER_H
|
||||
|
||||
#include <__algorithm/copy_n.h>
|
||||
#include <__algorithm/fill_n.h>
|
||||
#include <__algorithm/max.h>
|
||||
#include <__algorithm/min.h>
|
||||
#include <__algorithm/ranges_copy_n.h>
|
||||
#include <__algorithm/transform.h>
|
||||
#include <__algorithm/unwrap_iter.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/enable_insertable.h>
|
||||
#include <__format/format_to_n_result.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/wrap_iter.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__memory/allocate_at_least.h>
|
||||
#include <__memory/allocator_traits.h>
|
||||
#include <__memory/construct_at.h>
|
||||
#include <__memory/ranges_construct_at.h>
|
||||
#include <__memory/uninitialized_algorithms.h>
|
||||
#include <__type_traits/add_pointer.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__utility/exception_guard.h>
|
||||
#include <__utility/move.h>
|
||||
#include <cstddef>
|
||||
#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
|
||||
|
||||
namespace __format {
|
||||
|
||||
/// A "buffer" that handles writing to the proper iterator.
|
||||
///
|
||||
/// This helper is used together with the @ref back_insert_iterator to offer
|
||||
/// type-erasure for the formatting functions. This reduces the number to
|
||||
/// template instantiations.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __output_buffer {
|
||||
public:
|
||||
using value_type = _CharT;
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
|
||||
: __ptr_(__ptr),
|
||||
__capacity_(__capacity),
|
||||
__flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
|
||||
__obj_(__obj) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
|
||||
__ptr_ = __ptr;
|
||||
__capacity_ = __capacity;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
|
||||
|
||||
// Used in std::back_insert_iterator.
|
||||
_LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
|
||||
__ptr_[__size_++] = __c;
|
||||
|
||||
// Profiling showed flushing after adding is more efficient than flushing
|
||||
// when entering the function.
|
||||
if (__size_ == __capacity_)
|
||||
__flush();
|
||||
}
|
||||
|
||||
/// Copies the input __str to the buffer.
|
||||
///
|
||||
/// Since some of the input is generated by std::to_chars, there needs to be a
|
||||
/// conversion when _CharT is wchar_t.
|
||||
template <__fmt_char_type _InCharT>
|
||||
_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
|
||||
// case a better approach could be:
|
||||
// - flush the buffer
|
||||
// - container.append(__str.begin(), __str.end());
|
||||
// The same holds true for the fill.
|
||||
// For transform it might be slightly harder, however the use case for
|
||||
// transform is slightly less common; it converts hexadecimal values to
|
||||
// upper case. For integral these strings are short.
|
||||
// TODO FMT Look at the improvements above.
|
||||
size_t __n = __str.size();
|
||||
|
||||
__flush_on_overflow(__n);
|
||||
if (__n <= __capacity_) {
|
||||
_VSTD::copy_n(__str.data(), __n, _VSTD::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");
|
||||
const _InCharT* __first = __str.data();
|
||||
do {
|
||||
size_t __chunk = _VSTD::min(__n, __capacity_);
|
||||
_VSTD::copy_n(__first, __chunk, _VSTD::addressof(__ptr_[__size_]));
|
||||
__size_ = __chunk;
|
||||
__first += __chunk;
|
||||
__n -= __chunk;
|
||||
__flush();
|
||||
} while (__n);
|
||||
}
|
||||
|
||||
/// 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");
|
||||
|
||||
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));
|
||||
__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");
|
||||
do {
|
||||
size_t __chunk = _VSTD::min(__n, __capacity_);
|
||||
_VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation);
|
||||
__size_ = __chunk;
|
||||
__first += __chunk;
|
||||
__n -= __chunk;
|
||||
__flush();
|
||||
} while (__n);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
__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");
|
||||
do {
|
||||
size_t __chunk = _VSTD::min(__n, __capacity_);
|
||||
_VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value);
|
||||
__size_ = __chunk;
|
||||
__n -= __chunk;
|
||||
__flush();
|
||||
} while (__n);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush() {
|
||||
__flush_(__ptr_, __size_, __obj_);
|
||||
__size_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
_CharT* __ptr_;
|
||||
size_t __capacity_;
|
||||
size_t __size_{0};
|
||||
void (*__flush_)(_CharT*, size_t, void*);
|
||||
void* __obj_;
|
||||
|
||||
/// Flushes the buffer when the output operation would overflow the buffer.
|
||||
///
|
||||
/// A simple approach for the overflow detection would be something along the
|
||||
/// lines:
|
||||
/// \code
|
||||
/// // The internal buffer is large enough.
|
||||
/// if (__n <= __capacity_) {
|
||||
/// // Flush when we really would overflow.
|
||||
/// if (__size_ + __n >= __capacity_)
|
||||
/// __flush();
|
||||
/// ...
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// This approach works for all cases but one:
|
||||
/// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
|
||||
/// In that case the \ref __capacity_ of the buffer changes during the first
|
||||
/// \ref __flush. During that operation the output buffer switches from its
|
||||
/// __writer_ to its __storage_. The \ref __capacity_ of the former depends
|
||||
/// on the value of n, of the latter is a fixed size. For example:
|
||||
/// - a format_to_n call with a 10'000 char buffer,
|
||||
/// - the buffer is filled with 9'500 chars,
|
||||
/// - adding 1'000 elements would overflow the buffer so the buffer gets
|
||||
/// changed and the \ref __capacity_ decreases from 10'000 to
|
||||
/// __buffer_size (256 at the time of writing).
|
||||
///
|
||||
/// This means that the \ref __flush for this class may need to copy a part of
|
||||
/// the internal buffer to the proper output. In this example there will be
|
||||
/// 500 characters that need this copy operation.
|
||||
///
|
||||
/// Note it would be more efficient to write 500 chars directly and then swap
|
||||
/// the buffers. This would make the code more complex and \ref format_to_n is
|
||||
/// not the most common use case. Therefore the optimization isn't done.
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
|
||||
if (__size_ + __n >= __capacity_)
|
||||
__flush();
|
||||
}
|
||||
};
|
||||
|
||||
/// A storage using an internal buffer.
|
||||
///
|
||||
/// This storage is used when writing a single element to the output iterator
|
||||
/// is expensive.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __internal_storage {
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
|
||||
|
||||
static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
|
||||
|
||||
private:
|
||||
_CharT __buffer_[__buffer_size];
|
||||
};
|
||||
|
||||
/// A storage writing directly to the storage.
|
||||
///
|
||||
/// This requires the storage to be a contiguous buffer of \a _CharT.
|
||||
/// Since the output is directly written to the underlying storage this class
|
||||
/// is just an empty class.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __direct_storage {};
|
||||
|
||||
template <class _OutIt, class _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
|
||||
);
|
||||
|
||||
/// 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 _OutIt __out_it() { return __out_it_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
|
||||
// _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
|
||||
// is adjusted.
|
||||
__out_it_ += __n;
|
||||
}
|
||||
|
||||
private:
|
||||
_OutIt __out_it_;
|
||||
};
|
||||
|
||||
/// Write policy for copying the buffer to the output.
|
||||
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 _OutIt __out_it() && { return std::move(__out_it_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
|
||||
__out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
|
||||
}
|
||||
|
||||
private:
|
||||
_OutIt __out_it_;
|
||||
};
|
||||
|
||||
/// Concept to see whether a \a _Container is insertable.
|
||||
///
|
||||
/// The concept is used to validate whether multiple calls to a
|
||||
/// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
|
||||
///
|
||||
/// \note a \a _Container needs to opt-in to the concept by specializing
|
||||
/// \ref __enable_insertable.
|
||||
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,
|
||||
add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
|
||||
|
||||
/// Extract the container type of a \ref back_insert_iterator.
|
||||
template <class _It>
|
||||
struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <__insertable _Container>
|
||||
struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
|
||||
using type = _Container;
|
||||
};
|
||||
|
||||
/// Write policy for inserting the buffer in a container.
|
||||
template <class _Container>
|
||||
class _LIBCPP_TEMPLATE_VIS __writer_container {
|
||||
public:
|
||||
using _CharT = typename _Container::value_type;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
|
||||
: __container_{__out_it.__get_container()} {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
|
||||
__container_->insert(__container_->end(), __ptr, __ptr + __n);
|
||||
}
|
||||
|
||||
private:
|
||||
_Container* __container_;
|
||||
};
|
||||
|
||||
/// Selects the type of the writer used for the output iterator.
|
||||
template <class _OutIt, class _CharT>
|
||||
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>>>;
|
||||
};
|
||||
|
||||
/// The generic formatting buffer.
|
||||
template <class _OutIt, __fmt_char_type _CharT>
|
||||
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>>;
|
||||
|
||||
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)) {}
|
||||
|
||||
_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 auto __make_output_iterator() { return __output_.__make_output_iterator(); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
|
||||
__output_.__flush();
|
||||
return _VSTD::move(__writer_).__out_it();
|
||||
}
|
||||
|
||||
private:
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
|
||||
__output_buffer<_CharT> __output_;
|
||||
typename __writer_selector<_OutIt, _CharT>::type __writer_;
|
||||
};
|
||||
|
||||
/// A buffer that counts the number of insertions.
|
||||
///
|
||||
/// Since \ref formatted_size only needs to know the size, the output itself is
|
||||
/// discarded.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI size_t __result() && {
|
||||
__output_.__flush();
|
||||
return __size_;
|
||||
}
|
||||
|
||||
private:
|
||||
__internal_storage<_CharT> __storage_;
|
||||
__output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
|
||||
size_t __size_{0};
|
||||
};
|
||||
|
||||
/// The base of a buffer that counts and limits the number of insertions.
|
||||
template <class _OutIt, __fmt_char_type _CharT, bool>
|
||||
requires(output_iterator<_OutIt, const _CharT&>)
|
||||
struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
|
||||
using _Size = iter_difference_t<_OutIt>;
|
||||
|
||||
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)) {}
|
||||
|
||||
_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_));
|
||||
__size_ += __n;
|
||||
}
|
||||
|
||||
protected:
|
||||
__internal_storage<_CharT> __storage_;
|
||||
__output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
|
||||
typename __writer_selector<_OutIt, _CharT>::type __writer_;
|
||||
|
||||
_Size __max_size_;
|
||||
_Size __size_{0};
|
||||
};
|
||||
|
||||
/// The base of a buffer that counts and limits the number of insertions.
|
||||
///
|
||||
/// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
|
||||
///
|
||||
/// This class limits the size available to the direct writer so it will not
|
||||
/// exceed the maximum number of code units.
|
||||
template <class _OutIt, __fmt_char_type _CharT>
|
||||
requires(output_iterator<_OutIt, const _CharT&>)
|
||||
class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
|
||||
using _Size = iter_difference_t<_OutIt>;
|
||||
|
||||
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)),
|
||||
__max_size_(__max_size) {
|
||||
if (__max_size <= 0) [[unlikely]]
|
||||
__output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
|
||||
// A __flush to the direct writer happens in the following occasions:
|
||||
// - The format function has written the maximum number of allowed code
|
||||
// units. At this point it's no longer valid to write to this writer. So
|
||||
// switch to the internal storage. This internal storage doesn't need to
|
||||
// be written anywhere so the __flush for that storage writes no output.
|
||||
// - Like above, but the next "mass write" operation would overflow the
|
||||
// buffer. In that case the buffer is pre-emptively switched. The still
|
||||
// valid code units will be written separately.
|
||||
// - The format_to_n function is finished. In this case there's no need to
|
||||
// switch the buffer, but for simplicity the buffers are still switched.
|
||||
// When the __max_size <= 0 the constructor already switched the buffers.
|
||||
if (__size_ == 0 && __ptr != __storage_.__begin()) {
|
||||
__writer_.__flush(__ptr, __n);
|
||||
__output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
|
||||
} 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_);
|
||||
std::copy_n(__ptr, __s, __writer_.__out_it());
|
||||
__writer_.__flush(__ptr, __s);
|
||||
}
|
||||
|
||||
__size_ += __n;
|
||||
}
|
||||
|
||||
protected:
|
||||
__internal_storage<_CharT> __storage_;
|
||||
__output_buffer<_CharT> __output_;
|
||||
__writer_direct<_OutIt, _CharT> __writer_;
|
||||
|
||||
_Size __max_size_;
|
||||
_Size __size_{0};
|
||||
};
|
||||
|
||||
/// The buffer that counts and limits the number of insertions.
|
||||
template <class _OutIt, __fmt_char_type _CharT>
|
||||
requires(output_iterator<_OutIt, const _CharT&>)
|
||||
struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
|
||||
: public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
|
||||
using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
|
||||
using _Size = iter_difference_t<_OutIt>;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
|
||||
: _Base(_VSTD::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_};
|
||||
}
|
||||
};
|
||||
|
||||
// A dynamically growing buffer intended to be used for retargeting a context.
|
||||
//
|
||||
// P2286 Formatting ranges adds range formatting support. It allows the user to
|
||||
// specify the minimum width for the entire formatted range. The width of the
|
||||
// range is not known until the range is formatted. Formatting is done to an
|
||||
// output_iterator so there's no guarantee it would be possible to add the fill
|
||||
// to the front of the output. Instead the range is formatted to a temporary
|
||||
// buffer and that buffer is formatted as a string.
|
||||
//
|
||||
// There is an issue with that approach, the format context used in
|
||||
// std::formatter<T>::format contains the output iterator used as part of its
|
||||
// type. So using this output iterator means there needs to be a new format
|
||||
// context and the format arguments need to be retargeted to the new context.
|
||||
// This retargeting is done by a basic_format_context specialized for the
|
||||
// __iterator of this container.
|
||||
//
|
||||
// This class uses its own buffer management, since using vector
|
||||
// would lead to a circular include with formatter for vector<bool>.
|
||||
template <__fmt_char_type _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
|
||||
using _Alloc = allocator<_CharT>;
|
||||
|
||||
public:
|
||||
using value_type = _CharT;
|
||||
|
||||
struct __iterator {
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
|
||||
: __buffer_(std::addressof(__buffer)) {}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
|
||||
__buffer_->push_back(__c);
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
|
||||
__buffer_->push_back(__c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
|
||||
__retarget_buffer* __buffer_;
|
||||
};
|
||||
|
||||
__retarget_buffer(const __retarget_buffer&) = delete;
|
||||
__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));
|
||||
__ptr_ = __result.ptr;
|
||||
__capacity_ = __result.count;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
|
||||
ranges::destroy_n(__ptr_, __size_);
|
||||
allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
|
||||
std::construct_at(__ptr_ + __size_, __c);
|
||||
++__size_;
|
||||
|
||||
if (__size_ == __capacity_)
|
||||
__grow_buffer();
|
||||
}
|
||||
|
||||
template <__fmt_char_type _InCharT>
|
||||
_LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
|
||||
size_t __n = __str.size();
|
||||
if (__size_ + __n >= __capacity_)
|
||||
// Push_back requires the buffer to have room for at least one character.
|
||||
__grow_buffer(__size_ + __n + 1);
|
||||
|
||||
std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
|
||||
__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");
|
||||
|
||||
size_t __n = static_cast<size_t>(__last - __first);
|
||||
if (__size_ + __n >= __capacity_)
|
||||
// Push_back requires the buffer to have room for at least one character.
|
||||
__grow_buffer(__size_ + __n + 1);
|
||||
|
||||
std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
|
||||
std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
|
||||
__size_ += __n;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
|
||||
if (__size_ + __n >= __capacity_)
|
||||
// Push_back requires the buffer to have room for at least one character.
|
||||
__grow_buffer(__size_ + __n + 1);
|
||||
|
||||
std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
|
||||
__size_ += __n;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
|
||||
|
||||
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");
|
||||
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
|
||||
// guard is optimized away so there is no runtime overhead.
|
||||
std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
|
||||
__guard.__complete();
|
||||
ranges::destroy_n(__ptr_, __size_);
|
||||
allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
|
||||
|
||||
__ptr_ = __result.ptr;
|
||||
__capacity_ = __result.count;
|
||||
}
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
|
||||
_CharT* __ptr_;
|
||||
size_t __capacity_;
|
||||
size_t __size_{0};
|
||||
};
|
||||
|
||||
} // namespace __format
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___FORMAT_BUFFER_H
|
76
third_party/libcxx/__format/concepts.h
vendored
Normal file
76
third_party/libcxx/__format/concepts.h
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
// -*- 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_CONCEPTS_H
|
||||
#define _LIBCPP___FORMAT_CONCEPTS_H
|
||||
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__concepts/semiregular.h>
|
||||
#include <__config>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__type_traits/is_specialization.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <tuple>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
/// The character type specializations of \ref formatter.
|
||||
template <class _CharT>
|
||||
concept __fmt_char_type =
|
||||
same_as<_CharT, char>
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
|| same_as<_CharT, wchar_t>
|
||||
# endif
|
||||
;
|
||||
|
||||
// The output iterator isn't specified. A formatter should accept any
|
||||
// output_iterator. This iterator is a minimal iterator to test the concept.
|
||||
// (Note testing for (w)format_context would be a valid choice, but requires
|
||||
// selecting the proper one depending on the type of _CharT.)
|
||||
template <class _CharT>
|
||||
using __fmt_iter_for = _CharT*;
|
||||
|
||||
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>>;
|
||||
};
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
template <class _Tp, class _CharT>
|
||||
concept formattable = __formattable<_Tp, _CharT>;
|
||||
|
||||
// [tuple.like] defines a tuple-like exposition only concept. This concept is
|
||||
// not related to that. Therefore it uses a different name for the concept.
|
||||
//
|
||||
// TODO FMT Add a test to validate we fail when using that concept after P2165
|
||||
// has been implemented.
|
||||
template <class _Tp>
|
||||
concept __fmt_pair_like =
|
||||
__is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2);
|
||||
|
||||
# endif //_LIBCPP_STD_VER >= 23
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_CONCEPTS_H
|
71
third_party/libcxx/__format/container_adaptor.h
vendored
Normal file
71
third_party/libcxx/__format/container_adaptor.h
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// -*- 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_CONTAINER_ADAPTOR_H
|
||||
#define _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/range_default_formatter.h>
|
||||
#include <__ranges/all.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
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
// [container.adaptors.format] only specifies the library should provide the
|
||||
// formatter specializations, not which header should provide them.
|
||||
// Since <format> includes a lot of headers, add these headers here instead of
|
||||
// adding more dependencies like, locale, optinal, string, tuple, etc. to the
|
||||
// adaptor headers. To use the format functions users already include <format>.
|
||||
|
||||
template <class _Adaptor, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_container_adaptor {
|
||||
private:
|
||||
using __maybe_const_container = __fmt_maybe_const<typename _Adaptor::container_type, _CharT>;
|
||||
using __maybe_const_adaptor = __maybe_const<is_const_v<__maybe_const_container>, _Adaptor>;
|
||||
formatter<ranges::ref_view<__maybe_const_container>, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return __underlying_.parse(__ctx);
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(__maybe_const_adaptor& __adaptor, _FormatContext& __ctx) const {
|
||||
return __underlying_.format(__adaptor.__get_container(), __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <class _CharT, class _Tp, formattable<_CharT> _Container>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<queue<_Tp, _Container>, _CharT>
|
||||
: public __formatter_container_adaptor<queue<_Tp, _Container>, _CharT> {};
|
||||
|
||||
template <class _CharT, class _Tp, class _Container, class _Compare>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<priority_queue<_Tp, _Container, _Compare>, _CharT>
|
||||
: public __formatter_container_adaptor<priority_queue<_Tp, _Container, _Compare>, _CharT> {};
|
||||
|
||||
template <class _CharT, class _Tp, formattable<_CharT> _Container>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<stack<_Tp, _Container>, _CharT>
|
||||
: public __formatter_container_adaptor<stack<_Tp, _Container>, _CharT> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H
|
35
third_party/libcxx/__format/enable_insertable.h
vendored
Normal file
35
third_party/libcxx/__format/enable_insertable.h
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// -*- 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_ENABLE_INSERTABLE_H
|
||||
#define _LIBCPP___FORMAT_ENABLE_INSERTABLE_H
|
||||
|
||||
#include <__config>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
namespace __format {
|
||||
|
||||
/// Opt-in to enable \ref __insertable for a \a _Container.
|
||||
template <class _Container>
|
||||
inline constexpr bool __enable_insertable = false;
|
||||
|
||||
} // namespace __format
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_ENABLE_INSERTABLE_H
|
1038
third_party/libcxx/__format/escaped_output_table.h
vendored
Normal file
1038
third_party/libcxx/__format/escaped_output_table.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1661
third_party/libcxx/__format/extended_grapheme_cluster_table.h
vendored
Normal file
1661
third_party/libcxx/__format/extended_grapheme_cluster_table.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
305
third_party/libcxx/__format/format_arg.h
vendored
Normal file
305
third_party/libcxx/__format/format_arg.h
vendored
Normal file
|
@ -0,0 +1,305 @@
|
|||
// -*- 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_ARG_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_ARG_H
|
||||
|
||||
#include <__assert>
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__config>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__type_traits/is_const.h>
|
||||
#include <__utility/declval.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/unreachable.h>
|
||||
#include <__variant/monostate.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
namespace __format {
|
||||
/// The type stored in @ref basic_format_arg.
|
||||
///
|
||||
/// @note The 128-bit types are unconditionally in the list to avoid the values
|
||||
/// of the enums to depend on the availability of 128-bit integers.
|
||||
///
|
||||
/// @note The value is stored as a 5-bit value in the __packed_arg_t_bits. This
|
||||
/// limits the maximum number of elements to 32.
|
||||
/// When modifying update the test
|
||||
/// test/libcxx/utilities/format/format.arguments/format.arg/arg_t.compile.pass.cpp
|
||||
/// It could be packed in 4-bits but that means a new type directly becomes an
|
||||
/// ABI break. The packed type is 64-bit so this reduces the maximum number of
|
||||
/// packed elements from 16 to 12.
|
||||
///
|
||||
/// @note Some members of this enum are an extension. These extensions need
|
||||
/// special behaviour in visit_format_arg. There they need to be wrapped in a
|
||||
/// 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 {
|
||||
__none,
|
||||
__boolean,
|
||||
__char_type,
|
||||
__int,
|
||||
__long_long,
|
||||
__i128, // extension
|
||||
__unsigned,
|
||||
__unsigned_long_long,
|
||||
__u128, // extension
|
||||
__float,
|
||||
__double,
|
||||
__long_double,
|
||||
__const_char_type_ptr,
|
||||
__string_view,
|
||||
__ptr,
|
||||
__handle
|
||||
};
|
||||
|
||||
inline constexpr unsigned __packed_arg_t_bits = 5;
|
||||
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;
|
||||
|
||||
_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, "");
|
||||
|
||||
if (__id > 0)
|
||||
__types >>= __id * __packed_arg_t_bits;
|
||||
|
||||
return static_cast<__format::__arg_t>(__types & __packed_arg_t_mask);
|
||||
}
|
||||
|
||||
} // namespace __format
|
||||
|
||||
// This function is not user obervable, 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) {
|
||||
switch (__arg.__type_) {
|
||||
case __format::__arg_t::__none:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
|
||||
case __format::__arg_t::__boolean:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
|
||||
case __format::__arg_t::__char_type:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
|
||||
case __format::__arg_t::__int:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__int_);
|
||||
case __format::__arg_t::__long_long:
|
||||
return _VSTD::invoke(_VSTD::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_);
|
||||
# else
|
||||
__libcpp_unreachable();
|
||||
# endif
|
||||
case __format::__arg_t::__unsigned:
|
||||
return _VSTD::invoke(_VSTD::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_);
|
||||
case __format::__arg_t::__u128:
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
return _VSTD::invoke(_VSTD::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_);
|
||||
case __format::__arg_t::__double:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__double_);
|
||||
case __format::__arg_t::__long_double:
|
||||
return _VSTD::invoke(_VSTD::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_);
|
||||
case __format::__arg_t::__string_view:
|
||||
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
|
||||
case __format::__arg_t::__ptr:
|
||||
return _VSTD::invoke(_VSTD::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_});
|
||||
}
|
||||
|
||||
__libcpp_unreachable();
|
||||
}
|
||||
|
||||
/// Contains the values used in basic_format_arg.
|
||||
///
|
||||
/// This is a separate type so it's possible to store the values and types in
|
||||
/// separate arrays.
|
||||
template <class _Context>
|
||||
class __basic_format_arg_value {
|
||||
using _CharT = typename _Context::char_type;
|
||||
|
||||
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)),
|
||||
__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>;
|
||||
|
||||
static_assert(__const_formattable || !is_const_v<remove_reference_t<_Tp>>, "Mandated by [format.arg]/18");
|
||||
|
||||
_Formatter __f;
|
||||
__parse_ctx.advance_to(__f.parse(__parse_ctx));
|
||||
__ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Dp*>(__ptr)), __ctx));
|
||||
}) {}
|
||||
|
||||
const void* __ptr_;
|
||||
void (*__format_)(basic_format_parse_context<_CharT>&, _Context&, const void*);
|
||||
};
|
||||
|
||||
union {
|
||||
monostate __monostate_;
|
||||
bool __boolean_;
|
||||
_CharT __char_type_;
|
||||
int __int_;
|
||||
unsigned __unsigned_;
|
||||
long long __long_long_;
|
||||
unsigned long long __unsigned_long_long_;
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
__int128_t __i128_;
|
||||
__uint128_t __u128_;
|
||||
# endif
|
||||
float __float_;
|
||||
double __double_;
|
||||
long double __long_double_;
|
||||
const _CharT* __const_char_type_ptr_;
|
||||
basic_string_view<_CharT> __string_view_;
|
||||
const void* __ptr_;
|
||||
__handle __handle_;
|
||||
};
|
||||
|
||||
// These constructors contain the exact storage type used. If adjustments are
|
||||
// required, these will be done in __create_format_arg.
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value() noexcept : __monostate_() {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(bool __value) noexcept : __boolean_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(_CharT __value) noexcept : __char_type_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(int __value) noexcept : __int_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned __value) noexcept : __unsigned_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long long __value) noexcept : __long_long_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned long long __value) noexcept
|
||||
: __unsigned_long_long_(__value) {}
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__int128_t __value) noexcept : __i128_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__uint128_t __value) noexcept : __u128_(__value) {}
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(float __value) noexcept : __float_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(double __value) noexcept : __double_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long double __value) noexcept : __long_double_(__value) {}
|
||||
_LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const _CharT* __value) noexcept : __const_char_type_ptr_(__value) {}
|
||||
_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)) {}
|
||||
};
|
||||
|
||||
template <class _Context>
|
||||
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 explicit operator bool() const noexcept {
|
||||
return __type_ != __format::__arg_t::__none;
|
||||
}
|
||||
|
||||
private:
|
||||
using char_type = typename _Context::char_type;
|
||||
|
||||
// TODO FMT Implement constrain [format.arg]/4
|
||||
// Constraints: The template specialization
|
||||
// typename Context::template formatter_type<T>
|
||||
// meets the Formatter requirements ([formatter.requirements]). The extent
|
||||
// to which an implementation determines that the specialization meets the
|
||||
// Formatter requirements is unspecified, except that as a minimum the
|
||||
// expression
|
||||
// typename Context::template formatter_type<T>()
|
||||
// .format(declval<const T&>(), declval<Context&>())
|
||||
// shall be well-formed when treated as an unevaluated operand.
|
||||
|
||||
public:
|
||||
__basic_format_arg_value<_Context> __value_;
|
||||
__format::__arg_t __type_;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(__format::__arg_t __type,
|
||||
__basic_format_arg_value<_Context> __value) noexcept
|
||||
: __value_(__value), __type_(__type) {}
|
||||
};
|
||||
|
||||
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 {
|
||||
__handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle& __handle) noexcept
|
||||
: __handle_(__handle) {}
|
||||
|
||||
private:
|
||||
typename __basic_format_arg_value<_Context>::__handle& __handle_;
|
||||
};
|
||||
|
||||
// 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) {
|
||||
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});
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
# endif
|
||||
default:
|
||||
return _VSTD::__visit_format_arg(_VSTD::forward<_Visitor>(__vis), __arg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_ARG_H
|
254
third_party/libcxx/__format/format_arg_store.h
vendored
Normal file
254
third_party/libcxx/__format/format_arg_store.h
vendored
Normal file
|
@ -0,0 +1,254 @@
|
|||
// -*- 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_ARG_STORE_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
|
||||
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#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 <string>
|
||||
#include <string_view>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
namespace __format {
|
||||
|
||||
/// \returns The @c __arg_t based on the type of the formatting argument.
|
||||
///
|
||||
/// \pre \c __formattable<_Tp, typename _Context::char_type>
|
||||
template <class _Context, class _Tp>
|
||||
consteval __arg_t __determine_arg_t();
|
||||
|
||||
// Boolean
|
||||
template <class, same_as<bool> _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__boolean;
|
||||
}
|
||||
|
||||
// Char
|
||||
template <class _Context, same_as<typename _Context::char_type> _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__char_type;
|
||||
}
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class _Context, class _CharT>
|
||||
requires(same_as<typename _Context::char_type, wchar_t> && same_as<_CharT, char>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__char_type;
|
||||
}
|
||||
# endif
|
||||
|
||||
// Signed integers
|
||||
template <class, __libcpp_signed_integer _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
if constexpr (sizeof(_Tp) <= sizeof(int))
|
||||
return __arg_t::__int;
|
||||
else if constexpr (sizeof(_Tp) <= sizeof(long long))
|
||||
return __arg_t::__long_long;
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
else if constexpr (sizeof(_Tp) == sizeof(__int128_t))
|
||||
return __arg_t::__i128;
|
||||
# endif
|
||||
else
|
||||
static_assert(sizeof(_Tp) == 0, "an unsupported signed integer was used");
|
||||
}
|
||||
|
||||
// Unsigned integers
|
||||
template <class, __libcpp_unsigned_integer _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
if constexpr (sizeof(_Tp) <= sizeof(unsigned))
|
||||
return __arg_t::__unsigned;
|
||||
else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long))
|
||||
return __arg_t::__unsigned_long_long;
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
else if constexpr (sizeof(_Tp) == sizeof(__uint128_t))
|
||||
return __arg_t::__u128;
|
||||
# endif
|
||||
else
|
||||
static_assert(sizeof(_Tp) == 0, "an unsupported unsigned integer was used");
|
||||
}
|
||||
|
||||
// Floating-point
|
||||
template <class, same_as<float> _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__float;
|
||||
}
|
||||
template <class, same_as<double> _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__double;
|
||||
}
|
||||
template <class, same_as<long double> _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__long_double;
|
||||
}
|
||||
|
||||
// Char pointer
|
||||
template <class _Context, class _Tp>
|
||||
requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__const_char_type_ptr;
|
||||
}
|
||||
|
||||
// Char array
|
||||
template <class _Context, class _Tp>
|
||||
requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__string_view;
|
||||
}
|
||||
|
||||
// String view
|
||||
template <class _Context, class _Tp>
|
||||
requires(same_as<typename _Context::char_type, typename _Tp::value_type> &&
|
||||
same_as<_Tp, basic_string_view<typename _Tp::value_type, typename _Tp::traits_type>>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__string_view;
|
||||
}
|
||||
|
||||
// String
|
||||
template <class _Context, class _Tp>
|
||||
requires(
|
||||
same_as<typename _Context::char_type, typename _Tp::value_type> &&
|
||||
same_as<_Tp, basic_string<typename _Tp::value_type, typename _Tp::traits_type, typename _Tp::allocator_type>>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__string_view;
|
||||
}
|
||||
|
||||
// Pointers
|
||||
template <class, class _Ptr>
|
||||
requires(same_as<_Ptr, void*> || same_as<_Ptr, const void*> || same_as<_Ptr, nullptr_t>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__ptr;
|
||||
}
|
||||
|
||||
// Handle
|
||||
//
|
||||
// Note this version can't be constrained avoiding ambiguous overloads.
|
||||
// That means it can be instantiated by disabled formatters. To solve this, a
|
||||
// constrained version for not formattable formatters is added.
|
||||
template <class _Context, class _Tp>
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__handle;
|
||||
}
|
||||
|
||||
// The overload for not formattable types allows triggering the static
|
||||
// assertion below.
|
||||
template <class _Context, class _Tp>
|
||||
requires(!__formattable<_Tp, typename _Context::char_type>)
|
||||
consteval __arg_t __determine_arg_t() {
|
||||
return __arg_t::__none;
|
||||
}
|
||||
|
||||
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>>();
|
||||
static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");
|
||||
|
||||
// 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)};
|
||||
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)
|
||||
return basic_format_arg<_Context>{__arg, static_cast<long long>(__value)};
|
||||
else if constexpr (__arg == __arg_t::__unsigned)
|
||||
return basic_format_arg<_Context>{__arg, static_cast<unsigned>(__value)};
|
||||
else if constexpr (__arg == __arg_t::__unsigned_long_long)
|
||||
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>>)
|
||||
return basic_format_arg<_Context>{
|
||||
__arg, basic_string_view<typename _Context::char_type>{__value, extent_v<remove_cvref_t<_Tp>> - 1}};
|
||||
else
|
||||
// When the _Traits or _Allocator are different an implicit conversion will
|
||||
// fail.
|
||||
return basic_format_arg<_Context>{
|
||||
__arg, basic_string_view<typename _Context::char_type>{__value.data(), __value.size()}};
|
||||
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)}};
|
||||
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 {
|
||||
int __shift = 0;
|
||||
(
|
||||
[&] {
|
||||
basic_format_arg<_Context> __arg = __format::__create_format_arg<_Context>(__args);
|
||||
if (__shift != 0)
|
||||
__types |= static_cast<uint64_t>(__arg.__type_) << __shift;
|
||||
else
|
||||
// Assigns the initial value.
|
||||
__types = static_cast<uint64_t>(__arg.__type_);
|
||||
__shift += __packed_arg_t_bits;
|
||||
*__values++ = __arg.__value_;
|
||||
}(),
|
||||
...);
|
||||
}
|
||||
|
||||
template <class _Context, class... _Args>
|
||||
_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>
|
||||
struct __packed_format_arg_store {
|
||||
__basic_format_arg_value<_Context> __values_[N];
|
||||
uint64_t __types_;
|
||||
};
|
||||
|
||||
template <class _Context, size_t N>
|
||||
struct __unpacked_format_arg_store {
|
||||
basic_format_arg<_Context> __args_[N];
|
||||
};
|
||||
|
||||
} // namespace __format
|
||||
|
||||
template <class _Context, class... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
|
||||
_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...);
|
||||
else
|
||||
__format::__store_basic_format_arg<_Context>(__storage.__args_, __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;
|
||||
};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
|
82
third_party/libcxx/__format/format_args.h
vendored
Normal file
82
third_party/libcxx/__format/format_args.h
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// -*- 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_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 <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
|
||||
|
||||
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_;
|
||||
} else
|
||||
__args_ = __store.__storage.__args_;
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
basic_format_arg<_Context> get(size_t __id) const noexcept {
|
||||
if (__id >= __size_)
|
||||
return basic_format_arg<_Context>{};
|
||||
|
||||
if (__format::__use_packed_format_arg_store(__size_))
|
||||
return basic_format_arg<_Context>{__format::__get_packed_type(__types_, __id), __values_[__id]};
|
||||
|
||||
return __args_[__id];
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI size_t __size() const noexcept { return __size_; }
|
||||
|
||||
private:
|
||||
size_t __size_{0};
|
||||
// [format.args]/5
|
||||
// [Note 1: Implementations are encouraged to optimize the representation of
|
||||
// basic_format_args for small number of formatting arguments by storing
|
||||
// indices of type alternatives separately from values and packing the
|
||||
// former. - end note]
|
||||
union {
|
||||
struct {
|
||||
const __basic_format_arg_value<_Context>* __values_;
|
||||
uint64_t __types_;
|
||||
};
|
||||
const basic_format_arg<_Context>* __args_;
|
||||
};
|
||||
};
|
||||
|
||||
template <class _Context, class... _Args>
|
||||
basic_format_args(__format_arg_store<_Context, _Args...>) -> basic_format_args<_Context>;
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_ARGS_H
|
222
third_party/libcxx/__format/format_context.h
vendored
Normal file
222
third_party/libcxx/__format/format_context.h
vendored
Normal file
|
@ -0,0 +1,222 @@
|
|||
// -*- 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_CONTEXT_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/buffer.h>
|
||||
#include <__format/format_arg.h>
|
||||
#include <__format/format_arg_store.h>
|
||||
#include <__format/format_args.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__variant/monostate.h>
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
#include <locale>
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <class _OutIt, class _CharT>
|
||||
requires output_iterator<_OutIt, const _CharT&>
|
||||
class _LIBCPP_TEMPLATE_VIS basic_format_context;
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
/**
|
||||
* Helper to create a basic_format_context.
|
||||
*
|
||||
* This is needed since the constructor is private.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#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&>
|
||||
class
|
||||
// clang-format off
|
||||
_LIBCPP_TEMPLATE_VIS
|
||||
_LIBCPP_PREFERRED_NAME(format_context)
|
||||
_LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context))
|
||||
// clang-format on
|
||||
basic_format_context {
|
||||
public:
|
||||
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 {
|
||||
return __args_.get(__id);
|
||||
}
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
_LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() {
|
||||
if (!__loc_)
|
||||
__loc_ = _VSTD::locale{};
|
||||
return *__loc_;
|
||||
}
|
||||
#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
|
||||
|
||||
// The Standard doesn't specify how the locale is stored.
|
||||
// [format.context]/6
|
||||
// std::locale locale();
|
||||
// Returns: The locale passed to the formatting function if the latter
|
||||
// takes one, and std::locale() otherwise.
|
||||
// This is done by storing the locale of the constructor in this optional. If
|
||||
// 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_;
|
||||
|
||||
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>&&);
|
||||
|
||||
// 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)
|
||||
: __out_it_(_VSTD::move(__out_it)), __args_(__args) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
// A specialization for __retarget_buffer
|
||||
//
|
||||
// See __retarget_buffer for the motivation for this specialization.
|
||||
//
|
||||
// This context holds a reference to the instance of the basic_format_context
|
||||
// that is retargeted. It converts a formatting argument when it is requested
|
||||
// during formatting. It is expected that the usage of the arguments is rare so
|
||||
// the lookups are not expected to be used often. An alternative would be to
|
||||
// convert all elements during construction.
|
||||
//
|
||||
// The elements of the retargets context are only used when an underlying
|
||||
// formatter uses a locale specific formatting or an formatting argument is
|
||||
// part for the format spec. For example
|
||||
// format("{:256:{}}", input, 8);
|
||||
// Here the width of an element in input is determined dynamically.
|
||||
// Note when the top-level element has no width the retargeting is not needed.
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS
|
||||
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
|
||||
public:
|
||||
using iterator = typename __format::__retarget_buffer<_CharT>::__iterator;
|
||||
using char_type = _CharT;
|
||||
template <class _Tp>
|
||||
using formatter_type = formatter<_Tp, _CharT>;
|
||||
|
||||
template <class _Context>
|
||||
_LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx)
|
||||
: __out_it_(std::move(__out_it)),
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
__loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }),
|
||||
# endif
|
||||
__ctx_(std::addressof(__ctx)),
|
||||
__arg_([](void* __c, size_t __id) {
|
||||
return std::visit_format_arg(
|
||||
[&](auto __arg) -> basic_format_arg<basic_format_context> {
|
||||
if constexpr (same_as<decltype(__arg), monostate>)
|
||||
return {};
|
||||
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
|
||||
// At the moment it's not possible for formatting to use a re-targeted handle.
|
||||
// TODO FMT add this when support is needed.
|
||||
std::__throw_format_error("Re-targeting handle not supported");
|
||||
else
|
||||
return basic_format_arg<basic_format_context>{
|
||||
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
|
||||
__basic_format_arg_value<basic_format_context>(__arg)};
|
||||
},
|
||||
static_cast<_Context*>(__c)->arg(__id));
|
||||
}) {
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
|
||||
return __arg_(__ctx_, __id);
|
||||
}
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
_LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); }
|
||||
# endif
|
||||
_LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
|
||||
_LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
|
||||
|
||||
private:
|
||||
iterator __out_it_;
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
std::locale (*__loc_)(void* __ctx);
|
||||
# endif
|
||||
|
||||
void* __ctx_;
|
||||
basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id);
|
||||
};
|
||||
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H
|
52
third_party/libcxx/__format/format_error.h
vendored
Normal file
52
third_party/libcxx/__format/format_error.h
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
// -*- 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_ERROR_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_ERROR_H
|
||||
|
||||
#include <__config>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables")
|
||||
class _LIBCPP_EXCEPTION_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_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
|
||||
throw format_error(__s);
|
||||
#else
|
||||
(void)__s;
|
||||
_VSTD::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_ERROR_H
|
677
third_party/libcxx/__format/format_functions.h
vendored
Normal file
677
third_party/libcxx/__format/format_functions.h
vendored
Normal file
|
@ -0,0 +1,677 @@
|
|||
// -*- 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_FUNCTIONS
|
||||
#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>
|
||||
#include <__format/format_args.h>
|
||||
#include <__format/format_context.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/format_string.h>
|
||||
#include <__format/format_to_n_result.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_bool.h>
|
||||
#include <__format/formatter_char.h>
|
||||
#include <__format/formatter_floating_point.h>
|
||||
#include <__format/formatter_integer.h>
|
||||
#include <__format/formatter_pointer.h>
|
||||
#include <__format/formatter_string.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/readable_traits.h> // iter_value_t
|
||||
#include <__variant/monostate.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
// TODO FMT Evaluate which templates should be external templates. This
|
||||
// improves the efficiency of the header. However since the header is still
|
||||
// under heavy development and not all classes are stable it makes no sense
|
||||
// to do this optimization now.
|
||||
|
||||
using format_args = basic_format_args<format_context>;
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
using wformat_args = basic_format_args<wformat_context>;
|
||||
#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...);
|
||||
}
|
||||
|
||||
#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...);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace __format {
|
||||
|
||||
/// Helper class parse and handle argument.
|
||||
///
|
||||
/// When parsing a handle which is not enabled the code is ill-formed.
|
||||
/// This helper uses the parser of the appropriate formatter for the stored type.
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS __compile_time_handle {
|
||||
public:
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __parse(_ParseContext& __ctx) const {
|
||||
__parse_(__ctx);
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __enable() {
|
||||
__parse_ = [](basic_format_parse_context<_CharT>& __ctx) {
|
||||
formatter<_Tp, _CharT> __f;
|
||||
__ctx.advance_to(__f.parse(__ctx));
|
||||
};
|
||||
}
|
||||
|
||||
// Before calling __parse the proper handler needs to be set with __enable.
|
||||
// The default handler isn't a core constant expression.
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle()
|
||||
: __parse_([](basic_format_parse_context<_CharT>&) { std::__throw_format_error("Not a handle"); }) {}
|
||||
|
||||
private:
|
||||
void (*__parse_)(basic_format_parse_context<_CharT>&);
|
||||
};
|
||||
|
||||
// Dummy format_context only providing the parts used during constant
|
||||
// validation of the basic_format_string.
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context {
|
||||
public:
|
||||
using char_type = _CharT;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context(
|
||||
const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size)
|
||||
: __args_(__args), __handles_(__handles), __size_(__size) {}
|
||||
|
||||
// During the compile-time validation nothing needs to be written.
|
||||
// Therefore all operations of this iterator are a NOP.
|
||||
struct iterator {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; }
|
||||
};
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const {
|
||||
if (__id >= __size_)
|
||||
std::__throw_format_error("Argument index out of bounds");
|
||||
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");
|
||||
return __handles_[__id];
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {}
|
||||
|
||||
private:
|
||||
const __arg_t* __args_;
|
||||
const __compile_time_handle<_CharT>* __handles_;
|
||||
size_t __size_;
|
||||
};
|
||||
|
||||
// [format.string.std]/8
|
||||
// If { arg-idopt } is used in a width or precision, the value of the
|
||||
// corresponding formatting argument is used in its place. If the
|
||||
// corresponding formatting argument is not of standard signed or unsigned
|
||||
// integer type, or its value is negative for precision or non-positive for
|
||||
// width, an exception of type format_error is thrown.
|
||||
//
|
||||
// _HasPrecision does the formatter have a precision?
|
||||
template <class _CharT, class _Tp, bool _HasPrecision = false>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_validate_argument(
|
||||
basic_format_parse_context<_CharT>& __parse_ctx, __compile_time_basic_format_context<_CharT>& __ctx) {
|
||||
auto __validate_type = [](__arg_t __type) {
|
||||
// LWG3720 originally allowed "signed or unsigned integer types", however
|
||||
// the final version explicitly changed it to "*standard* signed or unsigned
|
||||
// integer types". It's trivial to use 128-bit integrals in libc++'s
|
||||
// implementation, but other implementations may not implement it.
|
||||
// (Using a width or precision, that does not fit in 64-bits, sounds very
|
||||
// unlikely in real world code.)
|
||||
switch (__type) {
|
||||
case __arg_t::__int:
|
||||
case __arg_t::__long_long:
|
||||
case __arg_t::__unsigned:
|
||||
case __arg_t::__unsigned_long_long:
|
||||
return;
|
||||
|
||||
default:
|
||||
std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type");
|
||||
}
|
||||
};
|
||||
|
||||
formatter<_Tp, _CharT> __formatter;
|
||||
__parse_ctx.advance_to(__formatter.parse(__parse_ctx));
|
||||
if (__formatter.__parser_.__width_as_arg_)
|
||||
__validate_type(__ctx.arg(__formatter.__parser_.__width_));
|
||||
|
||||
if constexpr (_HasPrecision)
|
||||
if (__formatter.__parser_.__precision_as_arg_)
|
||||
__validate_type(__ctx.arg(__formatter.__parser_.__precision_));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
switch (__type) {
|
||||
case __arg_t::__none:
|
||||
std::__throw_format_error("Invalid argument");
|
||||
case __arg_t::__boolean:
|
||||
return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx);
|
||||
case __arg_t::__char_type:
|
||||
return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx);
|
||||
case __arg_t::__int:
|
||||
return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx);
|
||||
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
|
||||
return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);
|
||||
# else
|
||||
std::__throw_format_error("Invalid argument");
|
||||
# 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
|
||||
return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);
|
||||
# else
|
||||
std::__throw_format_error("Invalid argument");
|
||||
# endif
|
||||
return;
|
||||
case __arg_t::__float:
|
||||
return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx);
|
||||
case __arg_t::__double:
|
||||
return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx);
|
||||
case __arg_t::__long_double:
|
||||
return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx);
|
||||
case __arg_t::__const_char_type_ptr:
|
||||
return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx);
|
||||
case __arg_t::__string_view:
|
||||
return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx);
|
||||
case __arg_t::__ptr:
|
||||
return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx);
|
||||
case __arg_t::__handle:
|
||||
std::__throw_format_error("Handle should use __compile_time_validate_handle_argument");
|
||||
}
|
||||
std::__throw_format_error("Invalid argument");
|
||||
}
|
||||
|
||||
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>;
|
||||
__format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx);
|
||||
|
||||
bool __parse = *__r.__last == _CharT(':');
|
||||
switch (*__r.__last) {
|
||||
case _CharT(':'):
|
||||
// The arg-id has a format-specifier, advance the input to the format-spec.
|
||||
__parse_ctx.advance_to(__r.__last + 1);
|
||||
break;
|
||||
case _CharT('}'):
|
||||
// The arg-id has no format-specifier.
|
||||
__parse_ctx.advance_to(__r.__last);
|
||||
break;
|
||||
default:
|
||||
std::__throw_format_error("The replacement field arg-id should terminate at a ':' or '}'");
|
||||
}
|
||||
|
||||
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");
|
||||
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(
|
||||
[&](auto __arg) {
|
||||
if constexpr (same_as<decltype(__arg), monostate>)
|
||||
std::__throw_format_error("Argument index out of bounds");
|
||||
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
|
||||
__arg.format(__parse_ctx, __ctx);
|
||||
else {
|
||||
formatter<decltype(__arg), _CharT> __formatter;
|
||||
if (__parse)
|
||||
__parse_ctx.advance_to(__formatter.parse(__parse_ctx));
|
||||
__ctx.advance_to(__formatter.format(__arg, __ctx));
|
||||
}
|
||||
},
|
||||
__ctx.arg(__r.__value));
|
||||
|
||||
__begin = __parse_ctx.begin();
|
||||
if (__begin == __end || *__begin != _CharT('}'))
|
||||
std::__throw_format_error("The replacement field misses a terminating '}'");
|
||||
|
||||
return ++__begin;
|
||||
}
|
||||
|
||||
template <class _ParseCtx, class _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();
|
||||
typename _Ctx::iterator __out_it = __ctx.out();
|
||||
while (__begin != __end) {
|
||||
switch (*__begin) {
|
||||
case _CharT('{'):
|
||||
++__begin;
|
||||
if (__begin == __end)
|
||||
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);
|
||||
__out_it = __ctx.out();
|
||||
|
||||
// The output is written and __begin points to the next character. So
|
||||
// start the next iteration.
|
||||
continue;
|
||||
}
|
||||
// The string is an escape character.
|
||||
break;
|
||||
|
||||
case _CharT('}'):
|
||||
++__begin;
|
||||
if (__begin == __end || *__begin != _CharT('}'))
|
||||
std::__throw_format_error("The format string contains an invalid escape sequence");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Copy the character to the output verbatim.
|
||||
*__out_it++ = *__begin++;
|
||||
}
|
||||
return __out_it;
|
||||
}
|
||||
|
||||
} // namespace __format
|
||||
|
||||
template <class _CharT, class... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS basic_format_string {
|
||||
template <class _Tp>
|
||||
requires convertible_to<const _Tp&, basic_string_view<_CharT>>
|
||||
consteval basic_format_string(const _Tp& __str) : __str_{__str} {
|
||||
__format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)},
|
||||
_Context{__types_.data(), __handles_.data(), sizeof...(_Args)});
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept {
|
||||
return __str_;
|
||||
}
|
||||
|
||||
private:
|
||||
basic_string_view<_CharT> __str_;
|
||||
|
||||
using _Context = __format::__compile_time_basic_format_context<_CharT>;
|
||||
|
||||
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;
|
||||
if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle)
|
||||
__handle.template __enable<_Tp>();
|
||||
|
||||
return __handle;
|
||||
}()...};
|
||||
# endif
|
||||
};
|
||||
|
||||
template <class... _Args>
|
||||
using format_string = basic_format_string<char, type_identity_t<_Args>...>;
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class... _Args>
|
||||
using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;
|
||||
#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) {
|
||||
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));
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining
|
||||
// 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);
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
#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...));
|
||||
}
|
||||
|
||||
#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...));
|
||||
}
|
||||
#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) {
|
||||
string __res;
|
||||
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
|
||||
return __res;
|
||||
}
|
||||
|
||||
#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
|
||||
vformat(wstring_view __fmt, wformat_args __args) {
|
||||
wstring __res;
|
||||
_VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
|
||||
return __res;
|
||||
}
|
||||
#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...));
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class... _Args>
|
||||
_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...));
|
||||
}
|
||||
#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();
|
||||
}
|
||||
|
||||
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...));
|
||||
}
|
||||
|
||||
#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...));
|
||||
}
|
||||
#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();
|
||||
}
|
||||
|
||||
template <class... _Args>
|
||||
_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...)});
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class... _Args>
|
||||
_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...)});
|
||||
}
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
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)));
|
||||
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, _VSTD::move(__loc)));
|
||||
return _VSTD::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);
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
#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...));
|
||||
}
|
||||
|
||||
#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...));
|
||||
}
|
||||
#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(locale __loc, string_view __fmt, format_args __args) {
|
||||
string __res;
|
||||
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
|
||||
__args);
|
||||
return __res;
|
||||
}
|
||||
|
||||
#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
|
||||
vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
|
||||
wstring __res;
|
||||
_VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
|
||||
__args);
|
||||
return __res;
|
||||
}
|
||||
#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...));
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class... _Args>
|
||||
_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...));
|
||||
}
|
||||
#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(
|
||||
basic_format_parse_context{__fmt, __args.__size()},
|
||||
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
|
||||
return _VSTD::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...));
|
||||
}
|
||||
|
||||
#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...));
|
||||
}
|
||||
#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(
|
||||
basic_format_parse_context{__fmt, __args.__size()},
|
||||
_VSTD::__format_context_create(__buffer.__make_output_iterator(), __args, _VSTD::move(__loc)));
|
||||
return _VSTD::move(__buffer).__result();
|
||||
}
|
||||
|
||||
template <class... _Args>
|
||||
_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...)});
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <class... _Args>
|
||||
_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...)});
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _LIBCPP_HAS_NO_LOCALIZATION
|
||||
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS
|
39
third_party/libcxx/__format/format_fwd.h
vendored
Normal file
39
third_party/libcxx/__format/format_fwd.h
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// -*- 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
|
113
third_party/libcxx/__format/format_parse_context.h
vendored
Normal file
113
third_party/libcxx/__format/format_parse_context.h
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
// -*- 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_PARSE_CONTEXT_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H
|
||||
|
||||
#include <__config>
|
||||
#include <__format/format_error.h>
|
||||
#include <__type_traits/is_constant_evaluated.h>
|
||||
#include <string_view>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS basic_format_parse_context {
|
||||
public:
|
||||
using char_type = _CharT;
|
||||
using const_iterator = typename basic_string_view<_CharT>::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
|
||||
: __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;
|
||||
|
||||
_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)
|
||||
std::__throw_format_error("Using automatic argument numbering in manual argument numbering mode");
|
||||
|
||||
if (__indexing_ == __unknown)
|
||||
__indexing_ = __automatic;
|
||||
|
||||
// Throws an exception to make the expression a non core constant
|
||||
// expression as required by:
|
||||
// [format.parse.ctx]/8
|
||||
// Remarks: Let cur-arg-id be the value of next_arg_id_ prior to this
|
||||
// call. Call expressions where cur-arg-id >= num_args_ is true are not
|
||||
// core constant expressions (7.7 [expr.const]).
|
||||
// Note: the Throws clause [format.parse.ctx]/9 doesn't specify the
|
||||
// behavior when id >= num_args_.
|
||||
if (is_constant_evaluated() && __next_arg_id_ >= __num_args_)
|
||||
std::__throw_format_error("Argument index outside the valid range");
|
||||
|
||||
return __next_arg_id_++;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void check_arg_id(size_t __id) {
|
||||
if (__indexing_ == __automatic)
|
||||
std::__throw_format_error("Using manual argument numbering in automatic argument numbering mode");
|
||||
|
||||
if (__indexing_ == __unknown)
|
||||
__indexing_ = __manual;
|
||||
|
||||
// Throws an exception to make the expression a non core constant
|
||||
// expression as required by:
|
||||
// [format.parse.ctx]/11
|
||||
// Remarks: Call expressions where id >= num_args_ are not core constant
|
||||
// expressions ([expr.const]).
|
||||
// Note: the Throws clause [format.parse.ctx]/10 doesn't specify the
|
||||
// behavior when id >= num_args_.
|
||||
if (is_constant_evaluated() && __id >= __num_args_)
|
||||
std::__throw_format_error("Argument index outside the valid range");
|
||||
}
|
||||
|
||||
private:
|
||||
iterator __begin_;
|
||||
iterator __end_;
|
||||
enum _Indexing { __unknown, __manual, __automatic };
|
||||
_Indexing __indexing_;
|
||||
size_t __next_arg_id_;
|
||||
size_t __num_args_;
|
||||
};
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_parse_context);
|
||||
|
||||
using format_parse_context = basic_format_parse_context<char>;
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||
#endif
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H
|
167
third_party/libcxx/__format/format_string.h
vendored
Normal file
167
third_party/libcxx/__format/format_string.h
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
// -*- 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_STRING_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_STRING_H
|
||||
|
||||
#include <__assert>
|
||||
#include <__config>
|
||||
#include <__format/format_error.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/readable_traits.h> // iter_value_t
|
||||
#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 __format {
|
||||
|
||||
template <contiguous_iterator _Iterator>
|
||||
struct _LIBCPP_TEMPLATE_VIS __parse_number_result {
|
||||
_Iterator __last;
|
||||
uint32_t __value;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* The maximum value of a numeric argument.
|
||||
*
|
||||
* This is used for:
|
||||
* * arg-id
|
||||
* * width as value or arg-id.
|
||||
* * precision as value or arg-id.
|
||||
*
|
||||
* The value is compatible with the maximum formatting width and precision
|
||||
* using the `%*` syntax on a 32-bit system.
|
||||
*/
|
||||
inline constexpr uint32_t __number_max = INT32_MAX;
|
||||
|
||||
namespace __detail {
|
||||
template <contiguous_iterator _Iterator>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
|
||||
__parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) {
|
||||
__parse_ctx.check_arg_id(0);
|
||||
return {++__begin, 0}; // can never be larger than the maximum.
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
return {__begin, uint32_t(__value)};
|
||||
}
|
||||
|
||||
template <contiguous_iterator _Iterator>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
|
||||
__parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
|
||||
__parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end);
|
||||
__parse_ctx.check_arg_id(__r.__value);
|
||||
return __r;
|
||||
}
|
||||
|
||||
} // namespace __detail
|
||||
|
||||
/**
|
||||
* Parses a number.
|
||||
*
|
||||
* The number is used for the 31-bit values @em width and @em precision. This
|
||||
* allows a maximum value of 2147483647.
|
||||
*/
|
||||
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.");
|
||||
/*
|
||||
* Limit the input to 9 digits, otherwise we need two checks during every
|
||||
* iteration:
|
||||
* - Are we at the end of the 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;
|
||||
uint32_t __value = *__begin - _CharT('0');
|
||||
while (++__begin != __end) {
|
||||
if (*__begin < _CharT('0') || *__begin > _CharT('9'))
|
||||
return {__begin, __value};
|
||||
|
||||
__value = __value * 10 + *__begin - _CharT('0');
|
||||
}
|
||||
|
||||
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?
|
||||
* - Are there more than 10 digits?
|
||||
* (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");
|
||||
|
||||
__value = __v;
|
||||
}
|
||||
|
||||
return {__begin, __value};
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplexer for all parse functions.
|
||||
*
|
||||
* The parser will return a pointer beyond the last consumed character. This
|
||||
* should be the closing '}' of the arg-id.
|
||||
*/
|
||||
template <contiguous_iterator _Iterator>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator>
|
||||
__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) {
|
||||
using _CharT = iter_value_t<_Iterator>;
|
||||
switch (*__begin) {
|
||||
case _CharT('0'):
|
||||
return __detail::__parse_zero(__begin, __end, __parse_ctx);
|
||||
|
||||
case _CharT(':'):
|
||||
// This case is conditionally valid. It's allowed in an arg-id in the
|
||||
// replacement-field, but not in the std-format-spec. The caller can
|
||||
// provide a better diagnostic, so accept it here unconditionally.
|
||||
case _CharT('}'):
|
||||
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");
|
||||
|
||||
return __detail::__parse_manual(__begin, __end, __parse_ctx);
|
||||
}
|
||||
|
||||
} // namespace __format
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_STRING_H
|
35
third_party/libcxx/__format/format_to_n_result.h
vendored
Normal file
35
third_party/libcxx/__format/format_to_n_result.h
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// -*- 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_TO_N_RESULT_H
|
||||
#define _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H
|
||||
|
||||
#include <__config>
|
||||
#include <__iterator/incrementable_traits.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 _OutIt>
|
||||
struct _LIBCPP_TEMPLATE_VIS format_to_n_result {
|
||||
_OutIt out;
|
||||
iter_difference_t<_OutIt> size;
|
||||
};
|
||||
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(format_to_n_result);
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H
|
54
third_party/libcxx/__format/formatter.h
vendored
Normal file
54
third_party/libcxx/__format/formatter.h
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
// -*- 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_FORMATTER_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__config>
|
||||
#include <__format/format_fwd.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
/// The default formatter template.
|
||||
///
|
||||
/// [format.formatter.spec]/5
|
||||
/// If F is a disabled specialization of formatter, these values are false:
|
||||
/// - is_default_constructible_v<F>,
|
||||
/// - is_copy_constructible_v<F>,
|
||||
/// - is_move_constructible_v<F>,
|
||||
/// - is_copy_assignable<F>, and
|
||||
/// - is_move_assignable<F>.
|
||||
template <class _Tp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter {
|
||||
formatter() = delete;
|
||||
formatter(const formatter&) = delete;
|
||||
formatter& operator=(const formatter&) = delete;
|
||||
};
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __set_debug_format(_Tp& __formatter) {
|
||||
if constexpr (requires { __formatter.set_debug_format(); })
|
||||
__formatter.set_debug_format();
|
||||
}
|
||||
|
||||
# endif // _LIBCPP_STD_VER >= 23
|
||||
#endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_H
|
79
third_party/libcxx/__format/formatter_bool.h
vendored
Normal file
79
third_party/libcxx/__format/formatter_bool.h
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// -*- 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_FORMATTER_BOOL_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_BOOL_H
|
||||
|
||||
#include <__algorithm/copy.h>
|
||||
#include <__availability>
|
||||
#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>
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
|
||||
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_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(bool __value, _FormatContext& __ctx) const {
|
||||
switch (__parser_.__type_) {
|
||||
case __format_spec::__type::__default:
|
||||
case __format_spec::__type::__string:
|
||||
return __formatter::__format_bool(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx));
|
||||
|
||||
case __format_spec::__type::__binary_lower_case:
|
||||
case __format_spec::__type::__binary_upper_case:
|
||||
case __format_spec::__type::__octal:
|
||||
case __format_spec::__type::__decimal:
|
||||
case __format_spec::__type::__hexadecimal_lower_case:
|
||||
case __format_spec::__type::__hexadecimal_upper_case:
|
||||
// Promotes bool to an integral type. This reduces the number of
|
||||
// instantiations of __format_integer reducing code size.
|
||||
return __formatter::__format_integer(
|
||||
static_cast<unsigned>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx));
|
||||
|
||||
default:
|
||||
_LIBCPP_ASSERT(false, "The parse function should have validated the type");
|
||||
__libcpp_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_;
|
||||
};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H
|
95
third_party/libcxx/__format/formatter_char.h
vendored
Normal file
95
third_party/libcxx/__format/formatter_char.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// -*- 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_FORMATTER_CHAR_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_CHAR_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_integral.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__type_traits/is_signed.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_char {
|
||||
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_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __value, _FormatContext& __ctx) const {
|
||||
if (__parser_.__type_ == __format_spec::__type::__default || __parser_.__type_ == __format_spec::__type::__char)
|
||||
return __formatter::__format_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
if (__parser_.__type_ == __format_spec::__type::__debug)
|
||||
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.
|
||||
return __formatter::__format_integer(
|
||||
static_cast<conditional_t<is_signed_v<_CharT>, int, unsigned>>(__value),
|
||||
__ctx,
|
||||
__parser_.__get_parsed_std_specifications(__ctx));
|
||||
else
|
||||
return __formatter::__format_integer(__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);
|
||||
}
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; }
|
||||
# endif
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<char, char> : public __formatter_char<char> {};
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
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> {
|
||||
};
|
||||
|
||||
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_CHAR_H
|
761
third_party/libcxx/__format/formatter_floating_point.h
vendored
Normal file
761
third_party/libcxx/__format/formatter_floating_point.h
vendored
Normal file
|
@ -0,0 +1,761 @@
|
|||
// -*- 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_FORMATTER_FLOATING_POINT_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H
|
||||
|
||||
#include <__algorithm/copy_n.h>
|
||||
#include <__algorithm/find.h>
|
||||
#include <__algorithm/max.h>
|
||||
#include <__algorithm/min.h>
|
||||
#include <__algorithm/rotate.h>
|
||||
#include <__algorithm/transform.h>
|
||||
#include <__charconv/chars_format.h>
|
||||
#include <__charconv/to_chars_floating_point.h>
|
||||
#include <__charconv/to_chars_result.h>
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_integral.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__memory/allocator.h>
|
||||
#include <__system_error/errc.h>
|
||||
#include <__type_traits/conditional.h>
|
||||
#include <__utility/move.h>
|
||||
#include <__utility/unreachable.h>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
# 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
|
||||
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
return __r.ptr;
|
||||
}
|
||||
|
||||
// https://en.cppreference.com/w/cpp/language/types#cite_note-1
|
||||
// float min subnormal: +/-0x1p-149 max: +/- 3.402,823,4 10^38
|
||||
// double min subnormal: +/-0x1p-1074 max +/- 1.797,693,134,862,315,7 10^308
|
||||
// long double (x86) min subnormal: +/-0x1p-16446 max: +/- 1.189,731,495,357,231,765,021 10^4932
|
||||
//
|
||||
// The maximum number of digits required for the integral part is based on the
|
||||
// maximum's value power of 10. Every power of 10 requires one additional
|
||||
// decimal digit.
|
||||
// The maximum number of digits required for the fractional part is based on
|
||||
// the minimal subnormal hexadecimal output's power of 10. Every division of a
|
||||
// fraction's binary 1 by 2, requires one additional decimal digit.
|
||||
//
|
||||
// The maximum size of a formatted value depends on the selected output format.
|
||||
// Ignoring the fact the format string can request a precision larger than the
|
||||
// values maximum required, these values are:
|
||||
//
|
||||
// sign 1 code unit
|
||||
// __max_integral
|
||||
// radix point 1 code unit
|
||||
// __max_fractional
|
||||
// exponent character 1 code unit
|
||||
// sign 1 code unit
|
||||
// __max_fractional_value
|
||||
// -----------------------------------
|
||||
// total 4 code units extra required.
|
||||
//
|
||||
// TODO FMT Optimize the storage to avoid storing digits that are known to be zero.
|
||||
// https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
|
||||
|
||||
// TODO FMT Add long double specialization when to_chars has proper long double support.
|
||||
template <class _Tp>
|
||||
struct __traits;
|
||||
|
||||
template <floating_point _Fp>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr size_t __float_buffer_size(int __precision) {
|
||||
using _Traits = __traits<_Fp>;
|
||||
return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct __traits<float> {
|
||||
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;
|
||||
|
||||
static constexpr int __hex_precision_digits = 3;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct __traits<double> {
|
||||
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;
|
||||
|
||||
static constexpr int __hex_precision_digits = 4;
|
||||
};
|
||||
|
||||
/// Helper class to store the conversion buffer.
|
||||
///
|
||||
/// Depending on the maxium 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 {
|
||||
using _Traits = __traits<_Fp>;
|
||||
|
||||
public:
|
||||
// TODO FMT Improve this constructor to do a better estimate.
|
||||
// When using a scientific formatting with a precision of 6 a stack buffer
|
||||
// will always suffice. At the moment that isn't important since floats and
|
||||
// doubles use a stack buffer, unless the precision used in the format string
|
||||
// is large.
|
||||
// When supporting long doubles the __max_integral part becomes 4932 which
|
||||
// may be too much for some platforms. For these cases a better estimate is
|
||||
// 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:
|
||||
// - When the value is large a temporary heap buffer needs to be allocated.
|
||||
// - When to_chars writes the values they need to be "copied" to the output:
|
||||
// - char: std::fill on the output iterator is faster than std::copy.
|
||||
// - wchar_t: same argument as char, but additional std::copy won't work.
|
||||
// The input is always a char buffer, so every char in the buffer needs
|
||||
// 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;
|
||||
}
|
||||
|
||||
__size_ = __formatter::__float_buffer_size<_Fp>(__precision_);
|
||||
if (__size_ > _Traits::__stack_buffer_size)
|
||||
// The allocated buffer's contents don't need initialization.
|
||||
__begin_ = allocator<char>{}.allocate(__size_);
|
||||
else
|
||||
__begin_ = __buffer_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI ~__float_buffer() {
|
||||
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& operator=(const __float_buffer&) = delete;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; }
|
||||
_LIBCPP_HIDE_FROM_ABI char* end() const { return __begin_ + __size_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI int __precision() const { return __precision_; }
|
||||
_LIBCPP_HIDE_FROM_ABI int __num_trailing_zeros() const { return __num_trailing_zeros_; }
|
||||
_LIBCPP_HIDE_FROM_ABI void __remove_trailing_zeros() { __num_trailing_zeros_ = 0; }
|
||||
_LIBCPP_HIDE_FROM_ABI void __add_trailing_zeros(int __zeros) { __num_trailing_zeros_ += __zeros; }
|
||||
|
||||
private:
|
||||
int __precision_;
|
||||
int __num_trailing_zeros_{0};
|
||||
size_t __size_;
|
||||
char* __begin_;
|
||||
char __buffer_[_Traits::__stack_buffer_size];
|
||||
};
|
||||
|
||||
struct __float_result {
|
||||
/// Points at the beginning of the integral part in the buffer.
|
||||
///
|
||||
/// When there's no sign character this points at the start of the buffer.
|
||||
char* __integral;
|
||||
|
||||
/// Points at the radix point, when not present it's the same as \ref __last.
|
||||
char* __radix_point;
|
||||
|
||||
/// Points at the exponent character, when not present it's the same as \ref __last.
|
||||
char* __exponent;
|
||||
|
||||
/// Points beyond the last written element in the buffer.
|
||||
char* __last;
|
||||
};
|
||||
|
||||
/// Finds the position of the exponent character 'e' at the end of the buffer.
|
||||
///
|
||||
/// Assuming there is an exponent the input will terminate with
|
||||
/// eSdd and eSdddd (S = sign, d = digit)
|
||||
///
|
||||
/// \returns a pointer to the exponent or __last when not found.
|
||||
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));
|
||||
for (; __first != __last - 3; ++__first) {
|
||||
if (*__first == 'e')
|
||||
return __first;
|
||||
}
|
||||
}
|
||||
return __last;
|
||||
}
|
||||
|
||||
template <class _Fp, class _Tp>
|
||||
_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);
|
||||
|
||||
__result.__exponent = __formatter::__find_exponent(__result.__integral, __result.__last);
|
||||
|
||||
// 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, '.');
|
||||
|
||||
// When the radix point isn't found its position is the exponent instead of
|
||||
// __result.__last.
|
||||
if (__result.__radix_point == __result.__exponent)
|
||||
__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.");
|
||||
// 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) {
|
||||
__float_result __result;
|
||||
__result.__integral = __integral;
|
||||
if (__precision == -1)
|
||||
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex);
|
||||
else
|
||||
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex, __precision);
|
||||
|
||||
// H = one or more hex-digits
|
||||
// S = sign
|
||||
// D = one or more decimal-digits
|
||||
// When the fractional part is zero and no precision the output is 0p+0
|
||||
// else the output is 0.HpSD
|
||||
// So testing the second position can differentiate between these two cases.
|
||||
char* __first = __integral + 1;
|
||||
if (*__first == '.') {
|
||||
__result.__radix_point = __first;
|
||||
// One digit is the minimum
|
||||
// 0.hpSd
|
||||
// ^-- last
|
||||
// ^---- integral = end of search
|
||||
// ^-------- start of search
|
||||
// 0123456
|
||||
//
|
||||
// Four digits is the maximum
|
||||
// 0.hpSdddd
|
||||
// ^-- last
|
||||
// ^---- integral = end of search
|
||||
// ^-------- start of search
|
||||
// 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');
|
||||
} else {
|
||||
__result.__radix_point = __result.__last;
|
||||
__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.");
|
||||
// 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) {
|
||||
__float_result __result =
|
||||
__formatter::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral);
|
||||
_VSTD::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) {
|
||||
__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");
|
||||
if (*__first == '.') {
|
||||
__result.__radix_point = __first;
|
||||
__result.__exponent = __formatter::__find_exponent(__first + 1, __result.__last);
|
||||
} else {
|
||||
__result.__radix_point = __result.__last;
|
||||
__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.");
|
||||
// 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) {
|
||||
__float_result __result =
|
||||
__formatter::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral);
|
||||
*__result.__exponent = 'E';
|
||||
return __result;
|
||||
}
|
||||
|
||||
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) {
|
||||
__float_result __result;
|
||||
__result.__integral = __integral;
|
||||
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision);
|
||||
|
||||
// When there's no precision there's no radix point.
|
||||
// Else the radix point is placed at __precision + 1 from the end.
|
||||
// By converting __precision to a bool the subtraction can be done
|
||||
// unconditionally.
|
||||
__result.__radix_point = __result.__last - (__precision + bool(__precision));
|
||||
__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.");
|
||||
// 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) {
|
||||
|
||||
__buffer.__remove_trailing_zeros();
|
||||
|
||||
__float_result __result;
|
||||
__result.__integral = __integral;
|
||||
__result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::general, __precision);
|
||||
|
||||
char* __first = __integral + 1;
|
||||
if (__first == __result.__last) {
|
||||
__result.__radix_point = __result.__last;
|
||||
__result.__exponent = __result.__last;
|
||||
} else {
|
||||
__result.__exponent = __formatter::__find_exponent(__first, __result.__last);
|
||||
if (__result.__exponent != __result.__last)
|
||||
// In scientific mode if there's a radix point it will always be after
|
||||
// the first digit. (This is the position __first points at).
|
||||
__result.__radix_point = *__first == '.' ? __first : __result.__last;
|
||||
else {
|
||||
// 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, '.');
|
||||
}
|
||||
}
|
||||
|
||||
// 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.");
|
||||
// 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) {
|
||||
__float_result __result = __formatter::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral);
|
||||
if (__result.__exponent != __result.__last)
|
||||
*__result.__exponent = 'E';
|
||||
return __result;
|
||||
}
|
||||
|
||||
/// Fills the buffer with the data based on the requested formatting.
|
||||
///
|
||||
/// This function, when needed, turns the characters to upper case and
|
||||
/// determines the "interesting" locations which are returned to the caller.
|
||||
///
|
||||
/// This means the caller never has to convert the contents of the buffer to
|
||||
/// upper case or search for radix points and the location of the exponent.
|
||||
/// This gives a bit of overhead. The original code didn't do that, but due
|
||||
/// to the number of possible additional work needed to turn this number to
|
||||
/// the proper output the code was littered with tests for upper cases and
|
||||
/// searches for radix points and exponents.
|
||||
/// - When a precision larger than the type's precision is selected
|
||||
/// additional zero characters need to be written before the exponent.
|
||||
/// - alternate form needs to add a radix point when not present.
|
||||
/// - localization needs to do grouping in the integral part.
|
||||
template <class _Fp, class _Tp>
|
||||
// TODO FMT _Fp should just be _Tp when to_chars has proper long double support.
|
||||
_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(
|
||||
__float_buffer<_Fp>& __buffer,
|
||||
_Tp __value,
|
||||
bool __negative,
|
||||
bool __has_precision,
|
||||
__format_spec::__sign __sign,
|
||||
__format_spec::__type __type) {
|
||||
char* __first = __formatter::__insert_sign(__buffer.begin(), __negative, __sign);
|
||||
switch (__type) {
|
||||
case __format_spec::__type::__default:
|
||||
if (__has_precision)
|
||||
return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first);
|
||||
else
|
||||
return __formatter::__format_buffer_default(__buffer, __value, __first);
|
||||
|
||||
case __format_spec::__type::__hexfloat_lower_case:
|
||||
return __formatter::__format_buffer_hexadecimal_lower_case(
|
||||
__buffer, __value, __has_precision ? __buffer.__precision() : -1, __first);
|
||||
|
||||
case __format_spec::__type::__hexfloat_upper_case:
|
||||
return __formatter::__format_buffer_hexadecimal_upper_case(
|
||||
__buffer, __value, __has_precision ? __buffer.__precision() : -1, __first);
|
||||
|
||||
case __format_spec::__type::__scientific_lower_case:
|
||||
return __formatter::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first);
|
||||
|
||||
case __format_spec::__type::__scientific_upper_case:
|
||||
return __formatter::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first);
|
||||
|
||||
case __format_spec::__type::__fixed_lower_case:
|
||||
case __format_spec::__type::__fixed_upper_case:
|
||||
return __formatter::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first);
|
||||
|
||||
case __format_spec::__type::__general_lower_case:
|
||||
return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first);
|
||||
|
||||
case __format_spec::__type::__general_upper_case:
|
||||
return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first);
|
||||
|
||||
default:
|
||||
_LIBCPP_ASSERT(false, "The parser should have validated the type");
|
||||
__libcpp_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
template <class _OutIt, class _Fp, class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
|
||||
_OutIt __out_it,
|
||||
const __float_buffer<_Fp>& __buffer,
|
||||
const __float_result& __result,
|
||||
_VSTD::locale __loc,
|
||||
__format_spec::__parsed_specifications<_CharT> __specs) {
|
||||
const auto& __np = std::use_facet<numpunct<_CharT>>(__loc);
|
||||
string __grouping = __np.grouping();
|
||||
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);
|
||||
|
||||
ptrdiff_t __digits = __last - __first;
|
||||
if (!__grouping.empty()) {
|
||||
if (__digits <= __grouping[0])
|
||||
__grouping.clear();
|
||||
else
|
||||
__grouping = __formatter::__determine_grouping(__digits, __grouping);
|
||||
}
|
||||
|
||||
ptrdiff_t __size =
|
||||
__result.__last - __buffer.begin() + // Formatted string
|
||||
__buffer.__num_trailing_zeros() + // Not yet rendered zeros
|
||||
__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;
|
||||
if (__size < __specs.__width_) {
|
||||
if (__zero_padding) {
|
||||
__specs.__alignment_ = __format_spec::__alignment::__right;
|
||||
__specs.__fill_.__data[0] = _CharT('0');
|
||||
}
|
||||
|
||||
__padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
|
||||
}
|
||||
|
||||
// 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_);
|
||||
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));
|
||||
} else {
|
||||
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.
|
||||
// - 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.
|
||||
while (true) {
|
||||
__out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
|
||||
__first += *__r;
|
||||
|
||||
if (__r == __e)
|
||||
break;
|
||||
|
||||
++__r;
|
||||
*__out_it++ = __sep;
|
||||
}
|
||||
}
|
||||
|
||||
// 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'));
|
||||
}
|
||||
|
||||
// exponent
|
||||
if (__result.__exponent != __result.__last)
|
||||
__out_it = __formatter::__copy(__result.__exponent, __result.__last, _VSTD::move(__out_it));
|
||||
|
||||
// alignment
|
||||
return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
|
||||
}
|
||||
# endif // _LIBCPP_HAS_NO_LOCALIZATION
|
||||
|
||||
template <class _OutIt, class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite(
|
||||
_OutIt __out_it, __format_spec::__parsed_specifications<_CharT> __specs, bool __negative, bool __isnan) {
|
||||
char __buffer[4];
|
||||
char* __last = __formatter::__insert_sign(__buffer, __negative, __specs.__std_.__sign_);
|
||||
|
||||
// to_chars can return inf, infinity, nan, and nan(n-char-sequence).
|
||||
// The format library requires inf and nan.
|
||||
// All in one expression to avoid dangling references.
|
||||
bool __upper_case =
|
||||
__specs.__std_.__type_ == __format_spec::__type::__hexfloat_upper_case ||
|
||||
__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);
|
||||
|
||||
// [format.string.std]/13
|
||||
// A zero (0) character preceding the width field pads the field with
|
||||
// leading zeros (following any indication of sign or base) to the field
|
||||
// width, except when applied to an infinity or NaN.
|
||||
if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding)
|
||||
__specs.__alignment_ = __format_spec::__alignment::__right;
|
||||
|
||||
return __formatter::__write(__buffer, __last, _VSTD::move(__out_it), __specs);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!_VSTD::isfinite(__value)) [[unlikely]]
|
||||
return __formatter::__format_floating_point_non_finite(__ctx.out(), __specs, __negative, _VSTD::isnan(__value));
|
||||
|
||||
// Depending on the std-format-spec string the sign and the value
|
||||
// might not be outputted together:
|
||||
// - zero-padding may insert additional '0' characters.
|
||||
// Therefore the value is processed as a non negative value.
|
||||
// The function @ref __insert_sign will insert a '-' when the value was
|
||||
// negative.
|
||||
|
||||
if (__negative)
|
||||
__value = -__value;
|
||||
|
||||
// TODO FMT _Fp should just be _Tp when to_chars has proper long double support.
|
||||
using _Fp = conditional_t<same_as<_Tp, long double>, double, _Tp>;
|
||||
// Force the type of the precision to avoid -1 to become an unsigned value.
|
||||
__float_buffer<_Fp> __buffer(__specs.__precision_);
|
||||
__float_result __result = __formatter::__format_buffer(
|
||||
__buffer, __value, __negative, (__specs.__has_precision()), __specs.__std_.__sign_, __specs.__std_.__type_);
|
||||
|
||||
if (__specs.__std_.__alternate_form_) {
|
||||
if (__result.__radix_point == __result.__last) {
|
||||
*__result.__last++ = '.';
|
||||
|
||||
// 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);
|
||||
__result.__radix_point = __result.__exponent;
|
||||
|
||||
// The radix point is always placed before the exponent.
|
||||
// - No exponent needs to point to the new last.
|
||||
// - An exponent needs to move one position to the right.
|
||||
// So it's safe to increment the value unconditionally.
|
||||
++__result.__exponent;
|
||||
}
|
||||
|
||||
// [format.string.std]/6
|
||||
// In addition, for g and G conversions, trailing zeros are not removed
|
||||
// from the result.
|
||||
//
|
||||
// If the type option for a floating-point type is none it may use the
|
||||
// general formatting, but it's not a g or G conversion. So in that case
|
||||
// the formatting should not append trailing zeros.
|
||||
bool __is_general = __specs.__std_.__type_ == __format_spec::__type::__general_lower_case ||
|
||||
__specs.__std_.__type_ == __format_spec::__type::__general_upper_case;
|
||||
|
||||
if (__is_general) {
|
||||
// https://en.cppreference.com/w/c/io/fprintf
|
||||
// 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));
|
||||
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)
|
||||
__p -= __result.__radix_point - __result.__integral;
|
||||
else
|
||||
// otherwise, the conversion is with style e or E and precision P - 1.
|
||||
--__p;
|
||||
|
||||
ptrdiff_t __precision = (__result.__exponent - __result.__radix_point) - 1;
|
||||
if (__precision < __p)
|
||||
__buffer.__add_trailing_zeros(__p - __precision);
|
||||
}
|
||||
}
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
if (__specs.__std_.__locale_specific_form_)
|
||||
return __formatter::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(), __specs);
|
||||
# endif
|
||||
|
||||
ptrdiff_t __size = __result.__last - __buffer.begin();
|
||||
int __num_trailing_zeros = __buffer.__num_trailing_zeros();
|
||||
if (__size + __num_trailing_zeros >= __specs.__width_) {
|
||||
if (__num_trailing_zeros && __result.__exponent != __result.__last)
|
||||
// Insert trailing zeros before exponent character.
|
||||
return __formatter::__copy(
|
||||
__result.__exponent,
|
||||
__result.__last,
|
||||
__formatter::__fill(__formatter::__copy(__buffer.begin(), __result.__exponent, __ctx.out()),
|
||||
__num_trailing_zeros,
|
||||
_CharT('0')));
|
||||
|
||||
return __formatter::__fill(
|
||||
__formatter::__copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, _CharT('0'));
|
||||
}
|
||||
|
||||
auto __out_it = __ctx.out();
|
||||
char* __first = __buffer.begin();
|
||||
if (__specs.__alignment_ == __format_spec::__alignment ::__zero_padding) {
|
||||
// When there is a sign output it before the padding. Note the __size
|
||||
// doesn't need any adjustment, regardless whether the sign is written
|
||||
// here or in __formatter::__write.
|
||||
if (__first != __result.__integral)
|
||||
*__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.__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);
|
||||
|
||||
return __formatter::__write(__first, __result.__last, _VSTD::move(__out_it), __specs, __size);
|
||||
}
|
||||
|
||||
} // namespace __formatter
|
||||
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_floating_point {
|
||||
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_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <floating_point _Tp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const {
|
||||
return __formatter::__format_floating_point(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx));
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_;
|
||||
};
|
||||
|
||||
template <__fmt_char_type _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> {};
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<long double, _CharT>
|
||||
: public __formatter_floating_point<_CharT> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H
|
107
third_party/libcxx/__format/formatter_integer.h
vendored
Normal file
107
third_party/libcxx/__format/formatter_integer.h
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
// -*- 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_FORMATTER_INTEGER_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_INTEGER_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#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/make_32_64_or_128_bit.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
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_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <integral _Tp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const {
|
||||
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
|
||||
|
||||
if (__specs.__std_.__type_ == __format_spec::__type::__char)
|
||||
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");
|
||||
|
||||
// Reduce the number of instantiation of the integer formatter
|
||||
return __formatter::__format_integer(static_cast<_Type>(__value), __ctx, __specs);
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_;
|
||||
};
|
||||
|
||||
// Signed integral types.
|
||||
template <__fmt_char_type _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> {
|
||||
};
|
||||
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> {};
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <__fmt_char_type _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> {};
|
||||
template <__fmt_char_type _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> {};
|
||||
template <__fmt_char_type _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> {};
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT>
|
||||
: public __formatter_integer<_CharT> {};
|
||||
# endif
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_INTEGER_H
|
368
third_party/libcxx/__format/formatter_integral.h
vendored
Normal file
368
third_party/libcxx/__format/formatter_integral.h
vendored
Normal file
|
@ -0,0 +1,368 @@
|
|||
// -*- 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_FORMATTER_INTEGRAL_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
|
||||
|
||||
#include <__charconv/to_chars_integral.h>
|
||||
#include <__charconv/to_chars_result.h>
|
||||
#include <__charconv/traits.h>
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__system_error/errc.h>
|
||||
#include <__type_traits/make_unsigned.h>
|
||||
#include <__utility/unreachable.h>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
# 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
|
||||
|
||||
namespace __formatter {
|
||||
|
||||
//
|
||||
// Generic
|
||||
//
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative, __format_spec::__sign __sign) {
|
||||
if (__negative)
|
||||
*__buf++ = '-';
|
||||
else
|
||||
switch (__sign) {
|
||||
case __format_spec::__sign::__default:
|
||||
case __format_spec::__sign::__minus:
|
||||
// No sign added.
|
||||
break;
|
||||
case __format_spec::__sign::__plus:
|
||||
*__buf++ = '+';
|
||||
break;
|
||||
case __format_spec::__sign::__space:
|
||||
*__buf++ = ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
return __buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the required grouping based on the size of the input.
|
||||
*
|
||||
* The grouping's last element will be repeated. For simplicity this repeating
|
||||
* is unwrapped based on the length of the input. (When the input is short some
|
||||
* groups are not processed.)
|
||||
*
|
||||
* @returns The size of the groups to write. This means the number of
|
||||
* separator characters written is size() - 1.
|
||||
*
|
||||
* @note Since zero-sized groups cause issues they are silently ignored.
|
||||
*
|
||||
* @note The grouping field of the locale is always a @c std::string,
|
||||
* 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");
|
||||
string __r;
|
||||
auto __end = __grouping.end() - 1;
|
||||
auto __ptr = __grouping.begin();
|
||||
|
||||
while (true) {
|
||||
__size -= *__ptr;
|
||||
if (__size > 0)
|
||||
__r.push_back(*__ptr);
|
||||
else {
|
||||
// __size <= 0 so the value pushed will be <= *__ptr.
|
||||
__r.push_back(*__ptr + __size);
|
||||
return __r;
|
||||
}
|
||||
|
||||
// Proceed to the next group.
|
||||
if (__ptr != __end) {
|
||||
do {
|
||||
++__ptr;
|
||||
// Skip grouping with a width of 0.
|
||||
} while (*__ptr == 0 && __ptr != __end);
|
||||
}
|
||||
}
|
||||
|
||||
__libcpp_unreachable();
|
||||
}
|
||||
|
||||
//
|
||||
// Char
|
||||
//
|
||||
|
||||
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) {
|
||||
using _Tp = decltype(__value);
|
||||
if constexpr (!same_as<_CharT, _Tp>) {
|
||||
// cmp_less and cmp_greater can't be used for character types.
|
||||
if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) {
|
||||
if (__value < numeric_limits<_CharT>::min() || __value > numeric_limits<_CharT>::max())
|
||||
std::__throw_format_error("Integral value outside the range of the char type");
|
||||
} else if constexpr (signed_integral<_CharT>) {
|
||||
// _CharT is signed _Tp is unsigned
|
||||
if (__value > static_cast<make_unsigned_t<_CharT>>(numeric_limits<_CharT>::max()))
|
||||
std::__throw_format_error("Integral value outside the range of the char type");
|
||||
} else {
|
||||
// _CharT is unsigned _Tp is signed
|
||||
if (__value < 0 || static_cast<make_unsigned_t<_Tp>>(__value) > numeric_limits<_CharT>::max())
|
||||
std::__throw_format_error("Integral value outside the range of the char type");
|
||||
}
|
||||
}
|
||||
|
||||
const auto __c = static_cast<_CharT>(__value);
|
||||
return __formatter::__write(_VSTD::addressof(__c), _VSTD::addressof(__c) + 1, _VSTD::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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to determine the buffer size to output a integer in Base @em x.
|
||||
*
|
||||
* There are several overloads for the supported bases. The function uses the
|
||||
* base as template argument so it can be used in a constant expression.
|
||||
*/
|
||||
template <unsigned_integral _Tp, size_t _Base>
|
||||
consteval size_t __buffer_size() noexcept
|
||||
requires(_Base == 2)
|
||||
{
|
||||
return numeric_limits<_Tp>::digits // The number of binary digits.
|
||||
+ 2 // Reserve space for the '0[Bb]' prefix.
|
||||
+ 1; // Reserve space for the sign.
|
||||
}
|
||||
|
||||
template <unsigned_integral _Tp, size_t _Base>
|
||||
consteval size_t __buffer_size() noexcept
|
||||
requires(_Base == 8)
|
||||
{
|
||||
return numeric_limits<_Tp>::digits // The number of binary digits.
|
||||
/ 3 // Adjust to octal.
|
||||
+ 1 // Turn floor to ceil.
|
||||
+ 1 // Reserve space for the '0' prefix.
|
||||
+ 1; // Reserve space for the sign.
|
||||
}
|
||||
|
||||
template <unsigned_integral _Tp, size_t _Base>
|
||||
consteval size_t __buffer_size() noexcept
|
||||
requires(_Base == 10)
|
||||
{
|
||||
return numeric_limits<_Tp>::digits10 // The floored value.
|
||||
+ 1 // Turn floor to ceil.
|
||||
+ 1; // Reserve space for the sign.
|
||||
}
|
||||
|
||||
template <unsigned_integral _Tp, size_t _Base>
|
||||
consteval size_t __buffer_size() noexcept
|
||||
requires(_Base == 16)
|
||||
{
|
||||
return numeric_limits<_Tp>::digits // The number of binary digits.
|
||||
/ 4 // Adjust to hexadecimal.
|
||||
+ 2 // Reserve space for the '0[Xx]' prefix.
|
||||
+ 1; // Reserve space for the sign.
|
||||
}
|
||||
|
||||
template <unsigned_integral _Tp, class _CharT, class _FormatContext>
|
||||
_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,
|
||||
const char* __prefix,
|
||||
int __base) {
|
||||
char* __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);
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
if (__specs.__std_.__locale_specific_form_) {
|
||||
const auto& __np = std::use_facet<numpunct<_CharT>>(__ctx.locale());
|
||||
string __grouping = __np.grouping();
|
||||
ptrdiff_t __size = __last - __first;
|
||||
// Writing the grouped form has more overhead than the normal output
|
||||
// routines. If there will be no separators written the locale-specific
|
||||
// form is identical to the normal routine. Test whether to grouped form
|
||||
// is required.
|
||||
if (!__grouping.empty() && __size > __grouping[0])
|
||||
return __formatter::__write_using_decimal_separators(
|
||||
__ctx.out(),
|
||||
__begin,
|
||||
__first,
|
||||
__last,
|
||||
__formatter::__determine_grouping(__size, __grouping),
|
||||
__np.thousands_sep(),
|
||||
__specs);
|
||||
}
|
||||
# endif
|
||||
auto __out_it = __ctx.out();
|
||||
if (__specs.__alignment_ != __format_spec::__alignment::__zero_padding)
|
||||
__first = __begin;
|
||||
else {
|
||||
// __buf contains [sign][prefix]data
|
||||
// ^ location of __first
|
||||
// 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;
|
||||
__specs.__fill_.__data[0] = _CharT('0');
|
||||
int32_t __size = __first - __begin;
|
||||
|
||||
__specs.__width_ -= _VSTD::min(__size, __specs.__width_);
|
||||
}
|
||||
|
||||
if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]]
|
||||
return __formatter::__write(__first, __last, __ctx.out(), __specs);
|
||||
|
||||
return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper);
|
||||
}
|
||||
|
||||
template <unsigned_integral _Tp, class _CharT, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_integer(_Tp __value,
|
||||
_FormatContext& __ctx,
|
||||
__format_spec::__parsed_specifications<_CharT> __specs,
|
||||
bool __negative = false) {
|
||||
switch (__specs.__std_.__type_) {
|
||||
case __format_spec::__type::__binary_lower_case: {
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array;
|
||||
return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0b", 2);
|
||||
}
|
||||
case __format_spec::__type::__binary_upper_case: {
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 2>()> __array;
|
||||
return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0B", 2);
|
||||
}
|
||||
case __format_spec::__type::__octal: {
|
||||
// Octal is special; if __value == 0 there's no prefix.
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 8>()> __array;
|
||||
return __formatter::__format_integer(
|
||||
__value, __ctx, __specs, __negative, __array.begin(), __array.end(), __value != 0 ? "0" : nullptr, 8);
|
||||
}
|
||||
case __format_spec::__type::__default:
|
||||
case __format_spec::__type::__decimal: {
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 10>()> __array;
|
||||
return __formatter::__format_integer(
|
||||
__value, __ctx, __specs, __negative, __array.begin(), __array.end(), nullptr, 10);
|
||||
}
|
||||
case __format_spec::__type::__hexadecimal_lower_case: {
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array;
|
||||
return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0x", 16);
|
||||
}
|
||||
case __format_spec::__type::__hexadecimal_upper_case: {
|
||||
array<char, __formatter::__buffer_size<decltype(__value), 16>()> __array;
|
||||
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_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
template <signed_integral _Tp, class _CharT, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) {
|
||||
// Depending on the std-format-spec string the sign and the value
|
||||
// might not be outputted together:
|
||||
// - alternate form may insert a prefix string.
|
||||
// - zero-padding may insert additional '0' characters.
|
||||
// Therefore the value is processed as a positive unsigned value.
|
||||
// The function @ref __insert_sign will a '-' when the value was negative.
|
||||
auto __r = std::__to_unsigned_like(__value);
|
||||
bool __negative = __value < 0;
|
||||
if (__negative)
|
||||
__r = std::__complement(__r);
|
||||
|
||||
return __formatter::__format_integer(__r, __ctx, __specs, __negative);
|
||||
}
|
||||
|
||||
//
|
||||
// Formatter arithmetic (bool)
|
||||
//
|
||||
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings;
|
||||
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings<char> {
|
||||
static constexpr string_view __true{"true"};
|
||||
static constexpr string_view __false{"false"};
|
||||
};
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <>
|
||||
struct _LIBCPP_TEMPLATE_VIS __bool_strings<wchar_t> {
|
||||
static constexpr wstring_view __true{L"true"};
|
||||
static constexpr wstring_view __false{L"false"};
|
||||
};
|
||||
# endif
|
||||
|
||||
template <class _CharT, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) {
|
||||
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
|
||||
if (__specs.__std_.__locale_specific_form_) {
|
||||
const auto& __np = std::use_facet<numpunct<_CharT>>(__ctx.locale());
|
||||
basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
|
||||
return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
|
||||
}
|
||||
# endif
|
||||
basic_string_view<_CharT> __str =
|
||||
__value ? __formatter::__bool_strings<_CharT>::__true : __formatter::__bool_strings<_CharT>::__false;
|
||||
return __formatter::__write(__str.begin(), __str.end(), __ctx.out(), __specs);
|
||||
}
|
||||
|
||||
} // namespace __formatter
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H
|
597
third_party/libcxx/__format/formatter_output.h
vendored
Normal file
597
third_party/libcxx/__format/formatter_output.h
vendored
Normal file
|
@ -0,0 +1,597 @@
|
|||
// -*- 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_FORMATTER_OUTPUT_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_OUTPUT_H
|
||||
|
||||
#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 <__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_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
namespace __formatter {
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) {
|
||||
switch (__c) {
|
||||
case 'a':
|
||||
return 'A';
|
||||
case 'b':
|
||||
return 'B';
|
||||
case 'c':
|
||||
return 'C';
|
||||
case 'd':
|
||||
return 'D';
|
||||
case 'e':
|
||||
return 'E';
|
||||
case 'f':
|
||||
return 'F';
|
||||
}
|
||||
return __c;
|
||||
}
|
||||
|
||||
struct _LIBCPP_TYPE_VIS __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(
|
||||
__align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
|
||||
|
||||
size_t __fill = __width - __size;
|
||||
switch (__align) {
|
||||
case __format_spec::__alignment::__zero_padding:
|
||||
__libcpp_unreachable();
|
||||
|
||||
case __format_spec::__alignment::__left:
|
||||
return {0, __fill};
|
||||
|
||||
case __format_spec::__alignment::__center: {
|
||||
// The extra padding is divided per [format.string.std]/3
|
||||
// __before = floor(__fill, 2);
|
||||
// __after = ceil(__fill, 2);
|
||||
size_t __before = __fill / 2;
|
||||
size_t __after = __fill - __before;
|
||||
return {__before, __after};
|
||||
}
|
||||
case __format_spec::__alignment::__default:
|
||||
case __format_spec::__alignment::__right:
|
||||
return {__fill, 0};
|
||||
}
|
||||
__libcpp_unreachable();
|
||||
}
|
||||
|
||||
/// Copy wrapper.
|
||||
///
|
||||
/// 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>>>) {
|
||||
__out_it.__get_container()->__copy(__str);
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it),
|
||||
typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
|
||||
__out_it.__buffer_->__copy(__str);
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::copy(__str, _VSTD::move(__out_it)).out;
|
||||
}
|
||||
}
|
||||
|
||||
template <__fmt_char_type _CharT, __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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/// 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>
|
||||
_LIBCPP_HIDE_FROM_ABI auto
|
||||
__transform(const _CharT* __first,
|
||||
const _CharT* __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));
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it),
|
||||
typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
|
||||
__out_it.__buffer_->__transform(__first, __last, _VSTD::move(__operation));
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out;
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill wrapper.
|
||||
///
|
||||
/// 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>>>) {
|
||||
__out_it.__get_container()->__fill(__n, __value);
|
||||
return __out_it;
|
||||
} else if constexpr (_VSTD::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) {
|
||||
__out_it.__buffer_->__fill(__n, __value);
|
||||
return __out_it;
|
||||
} else {
|
||||
return std::ranges::fill_n(_VSTD::move(__out_it), __n, __value);
|
||||
}
|
||||
}
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_UNICODE
|
||||
template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
|
||||
requires(same_as<_CharT, char>)
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
|
||||
std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0]));
|
||||
if (__bytes == 0)
|
||||
return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
|
||||
|
||||
for (size_t __i = 0; __i < __n; ++__i)
|
||||
__out_it = __formatter::__copy(
|
||||
std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it));
|
||||
return __out_it;
|
||||
}
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
|
||||
requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2)
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
|
||||
if (!__unicode::__is_high_surrogate(__value.__data[0]))
|
||||
return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
|
||||
|
||||
for (size_t __i = 0; __i < __n; ++__i)
|
||||
__out_it = __formatter::__copy(
|
||||
std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it));
|
||||
return __out_it;
|
||||
}
|
||||
|
||||
template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
|
||||
requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4)
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
|
||||
return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
|
||||
}
|
||||
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
# else // _LIBCPP_HAS_NO_UNICODE
|
||||
template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
|
||||
_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) {
|
||||
return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]);
|
||||
}
|
||||
# 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
|
||||
/// ASCII and Unicode output.
|
||||
///
|
||||
/// \pre \a __size <= \a __width. Using this function when this pre-condition
|
||||
/// doesn't hold incurs an unwanted overhead.
|
||||
///
|
||||
/// \param __str The string to write.
|
||||
/// \param __out_it The output iterator to write to.
|
||||
/// \param __specs The parsed formatting specifications.
|
||||
/// \param __size The (estimated) output column width. When the elements
|
||||
/// to be written are ASCII the following condition holds
|
||||
/// \a __size == \a __last - \a __first.
|
||||
///
|
||||
/// \returns An iterator pointing beyond the last element written.
|
||||
///
|
||||
/// \note The type of the elements in range [\a __first, \a __last) can differ
|
||||
/// from the type of \a __specs. Integer output uses \c std::to_chars for its
|
||||
/// conversion, which means the [\a __first, \a __last) always contains elements
|
||||
/// of the type \c char.
|
||||
template <class _CharT, class _ParserCharT>
|
||||
_LIBCPP_HIDE_FROM_ABI auto
|
||||
__write(basic_string_view<_CharT> __str,
|
||||
output_iterator<const _CharT&> auto __out_it,
|
||||
__format_spec::__parsed_specifications<_ParserCharT> __specs,
|
||||
ptrdiff_t __size) -> decltype(__out_it) {
|
||||
if (__size >= __specs.__width_)
|
||||
return __formatter::__copy(__str, _VSTD::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_);
|
||||
}
|
||||
|
||||
template <contiguous_iterator _Iterator, class _ParserCharT>
|
||||
_LIBCPP_HIDE_FROM_ABI auto
|
||||
__write(_Iterator __first,
|
||||
_Iterator __last,
|
||||
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);
|
||||
}
|
||||
|
||||
/// \overload
|
||||
///
|
||||
/// Calls the function above where \a __size = \a __last - \a __first.
|
||||
template <contiguous_iterator _Iterator, class _ParserCharT>
|
||||
_LIBCPP_HIDE_FROM_ABI auto
|
||||
__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);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
ptrdiff_t __size = __last - __first;
|
||||
if (__size >= __specs.__width_)
|
||||
return __formatter::__transform(__first, __last, _VSTD::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_);
|
||||
}
|
||||
|
||||
/// Writes a string using format's width estimation algorithm.
|
||||
///
|
||||
/// \pre !__specs.__has_precision()
|
||||
///
|
||||
/// \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_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");
|
||||
|
||||
// No padding -> copy the string
|
||||
if (!__specs.__has_width())
|
||||
return __formatter::__copy(__str, _VSTD::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
|
||||
// equal to the minimum field width.
|
||||
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);
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
_LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) {
|
||||
__format_spec::__column_width_result __result =
|
||||
__format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down);
|
||||
__str = basic_string_view<_CharT>{__str.begin(), __result.__last_};
|
||||
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
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H
|
72
third_party/libcxx/__format/formatter_pointer.h
vendored
Normal file
72
third_party/libcxx/__format/formatter_pointer.h
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
// -*- 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_FORMATTER_POINTER_H
|
||||
#define _LIBCPP___FORMAT_FORMATTER_POINTER_H
|
||||
|
||||
#include <__availability>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_integral.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.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
|
||||
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_pointer {
|
||||
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_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_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;
|
||||
return __formatter::__format_integer(reinterpret_cast<uintptr_t>(__ptr), __ctx, __specs);
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
|
||||
};
|
||||
|
||||
// [format.formatter.spec]/2.4
|
||||
// For each charT, the pointer type specializations template<>
|
||||
// - struct formatter<nullptr_t, charT>;
|
||||
// - 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> {};
|
||||
template <__fmt_char_type _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> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_POINTER_H
|
155
third_party/libcxx/__format/formatter_string.h
vendored
Normal file
155
third_party/libcxx/__format/formatter_string.h
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// -*- 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_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 <string>
|
||||
#include <string_view>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_string {
|
||||
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_string);
|
||||
__format_spec::__process_display_type_string(__parser_.__type_);
|
||||
return __result;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(basic_string_view<_CharT> __str, _FormatContext& __ctx) const {
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
if (__parser_.__type_ == __format_spec::__type::__debug)
|
||||
return __formatter::__format_escaped_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
|
||||
# endif
|
||||
|
||||
return __formatter::__write_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
|
||||
}
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; }
|
||||
# endif
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left};
|
||||
};
|
||||
|
||||
// Formatter const char*.
|
||||
template <__fmt_char_type _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.");
|
||||
|
||||
__format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx);
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
if (_Base::__parser_.__type_ == __format_spec::__type::__debug)
|
||||
return __formatter::__format_escaped_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
|
||||
# endif
|
||||
|
||||
// When using a center or right alignment and the width option the length
|
||||
// of __str must be known to add the padding upfront. This case is handled
|
||||
// by the base class by converting the argument to a basic_string_view.
|
||||
//
|
||||
// When using left alignment and the width option the padding is added
|
||||
// after outputting __str so the length can be determined while outputting
|
||||
// __str. The same holds true for the precision, during outputting __str it
|
||||
// can be validated whether the precision threshold has been reached. For
|
||||
// now these optimizations aren't implemented. Instead the base class
|
||||
// handles these options.
|
||||
// TODO FMT Implement these improvements.
|
||||
if (__specs.__has_width() || __specs.__has_precision())
|
||||
return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
|
||||
|
||||
// No formatting required, copy the string to the output.
|
||||
auto __out_it = __ctx.out();
|
||||
while (*__str)
|
||||
*__out_it++ = *__str++;
|
||||
return __out_it;
|
||||
}
|
||||
};
|
||||
|
||||
// Formatter char*.
|
||||
template <__fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT>
|
||||
: public formatter<const _CharT*, _CharT> {
|
||||
using _Base = formatter<const _CharT*, _CharT>;
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT* __str, _FormatContext& __ctx) const {
|
||||
return _Base::format(__str, __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// Formatter char[].
|
||||
template <__fmt_char_type _CharT, size_t _Size>
|
||||
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 {
|
||||
return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// Formatter std::string.
|
||||
template <__fmt_char_type _CharT, class _Traits, class _Allocator>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT>
|
||||
: public __formatter_string<_CharT> {
|
||||
using _Base = __formatter_string<_CharT>;
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(const basic_string<_CharT, _Traits, _Allocator>& __str, _FormatContext& __ctx) const {
|
||||
// Drop _Traits and _Allocator to have one std::basic_string formatter.
|
||||
return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// 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> {
|
||||
using _Base = __formatter_string<_CharT>;
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(basic_string_view<_CharT, _Traits> __str, _FormatContext& __ctx) const {
|
||||
// Drop _Traits to have one std::basic_string_view formatter.
|
||||
return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_STRING_H
|
155
third_party/libcxx/__format/formatter_tuple.h
vendored
Normal file
155
third_party/libcxx/__format/formatter_tuple.h
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// -*- 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_FORMATTER_TUPLE_H
|
||||
#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>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS __formatter_tuple {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept {
|
||||
__separator_ = __separator;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void
|
||||
set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept {
|
||||
__opening_bracket_ = __opening_bracket;
|
||||
__closing_bracket_ = __closing_bracket;
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
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')) {
|
||||
set_brackets({}, {});
|
||||
++__begin;
|
||||
}
|
||||
}
|
||||
|
||||
if (__begin != __end && *__begin != _CharT('}'))
|
||||
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
|
||||
|
||||
__ctx.advance_to(__begin);
|
||||
|
||||
// [format.tuple]/7
|
||||
// ... For each element e in underlying_, if e.set_debug_format()
|
||||
// is a valid expression, calls e.set_debug_format().
|
||||
std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> {
|
||||
auto& __formatter = std::get<_Index>(__underlying_);
|
||||
__formatter.parse(__ctx);
|
||||
// Unlike the range_formatter we don't guard against evil parsers. Since
|
||||
// this format-spec never has a format-spec for the underlying type
|
||||
// adding the test would give additional overhead.
|
||||
std::__set_debug_format(__formatter);
|
||||
});
|
||||
|
||||
return __begin;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI
|
||||
format(conditional_t<(formattable<const _Args, _CharT> && ...), const _Tuple&, _Tuple&> __tuple,
|
||||
_FormatContext& __ctx) const {
|
||||
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
|
||||
|
||||
if (!__specs.__has_width())
|
||||
return __format_tuple(__tuple, __ctx);
|
||||
|
||||
// The size of the buffer needed is:
|
||||
// - open bracket characters
|
||||
// - close bracket character
|
||||
// - n elements where every element may have a different size
|
||||
// - (n -1) separators
|
||||
// The size of the element is hard to predict, knowing the type helps but
|
||||
// it depends on the format-spec. As an initial estimate we guess 6
|
||||
// characters.
|
||||
// Typically both brackets are 1 character and the separator is 2
|
||||
// characters. Which means there will be
|
||||
// (n - 1) * 2 + 1 + 1 = n * 2 character
|
||||
// So estimate 8 times the range size as buffer.
|
||||
__format::__retarget_buffer<_CharT> __buffer{8 * tuple_size_v<_Tuple>};
|
||||
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{
|
||||
__buffer.__make_output_iterator(), __ctx};
|
||||
|
||||
__format_tuple(__tuple, __c);
|
||||
|
||||
return __formatter::__write_string_no_precision(basic_string_view{__buffer.__view()}, __ctx.out(), __specs);
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_tuple(auto&& __tuple, _FormatContext& __ctx) const {
|
||||
__ctx.advance_to(std::ranges::copy(__opening_bracket_, __ctx.out()).out);
|
||||
|
||||
std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> {
|
||||
if constexpr (_Index)
|
||||
__ctx.advance_to(std::ranges::copy(__separator_, __ctx.out()).out);
|
||||
__ctx.advance_to(std::get<_Index>(__underlying_).format(std::get<_Index>(__tuple), __ctx));
|
||||
});
|
||||
|
||||
return std::ranges::copy(__closing_bracket_, __ctx.out()).out;
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left};
|
||||
|
||||
private:
|
||||
tuple<formatter<remove_cvref_t<_Args>, _CharT>...> __underlying_;
|
||||
basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", ");
|
||||
basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "(");
|
||||
basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ")");
|
||||
};
|
||||
|
||||
template <__fmt_char_type _CharT, formattable<_CharT>... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<pair<_Args...>, _CharT>
|
||||
: public __formatter_tuple<_CharT, pair<_Args...>, _Args...> {};
|
||||
|
||||
template <__fmt_char_type _CharT, formattable<_CharT>... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<tuple<_Args...>, _CharT>
|
||||
: public __formatter_tuple<_CharT, tuple<_Args...>, _Args...> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_TUPLE_H
|
1019
third_party/libcxx/__format/parser_std_format_spec.h
vendored
Normal file
1019
third_party/libcxx/__format/parser_std_format_spec.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
216
third_party/libcxx/__format/range_default_formatter.h
vendored
Normal file
216
third_party/libcxx/__format/range_default_formatter.h
vendored
Normal file
|
@ -0,0 +1,216 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
||||
#define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
||||
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__availability>
|
||||
#include <__chrono/statically_widen.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/range_formatter.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/data.h>
|
||||
#include <__ranges/size.h>
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
#include <__utility/pair.h>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Rp, class _CharT>
|
||||
concept __const_formattable_range =
|
||||
ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>;
|
||||
|
||||
template <class _Rp, class _CharT>
|
||||
using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>;
|
||||
|
||||
_LIBCPP_DIAGNOSTIC_PUSH
|
||||
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow")
|
||||
_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow")
|
||||
// This shadows map, set, and string.
|
||||
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||
_LIBCPP_DIAGNOSTIC_POP
|
||||
|
||||
// There is no definition of this struct, it's purely intended to be used to
|
||||
// generate diagnostics.
|
||||
template <class _Rp>
|
||||
struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind;
|
||||
|
||||
template <class _Rp>
|
||||
constexpr range_format format_kind = [] {
|
||||
// [format.range.fmtkind]/1
|
||||
// A program that instantiates the primary template of format_kind is ill-formed.
|
||||
static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type");
|
||||
return range_format::disabled;
|
||||
}();
|
||||
|
||||
template <ranges::input_range _Rp>
|
||||
requires same_as<_Rp, remove_cvref_t<_Rp>>
|
||||
inline constexpr range_format format_kind<_Rp> = [] {
|
||||
// [format.range.fmtkind]/2
|
||||
|
||||
// 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true,
|
||||
// Otherwise format_kind<R> is range_format::disabled.
|
||||
if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>)
|
||||
return range_format::disabled;
|
||||
// 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type:
|
||||
else if constexpr (requires { typename _Rp::key_type; }) {
|
||||
// 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ...
|
||||
if constexpr (requires { typename _Rp::mapped_type; } &&
|
||||
// 2.2.1 ... If either U is a specialization of pair or U is a specialization
|
||||
// of tuple and tuple_size_v<U> == 2
|
||||
__fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>)
|
||||
return range_format::map;
|
||||
else
|
||||
// 2.2.2 Otherwise format_kind<R> is range_format::set.
|
||||
return range_format::set;
|
||||
} else
|
||||
// 2.3 Otherwise, format_kind<R> is range_format::sequence.
|
||||
return range_format::sequence;
|
||||
}();
|
||||
|
||||
template <range_format _Kp, ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __range_default_formatter;
|
||||
|
||||
// Required specializations
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::sequence, _Rp, _CharT> {
|
||||
private:
|
||||
using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>;
|
||||
range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept {
|
||||
__underlying_.set_separator(__separator);
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void
|
||||
set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept {
|
||||
__underlying_.set_brackets(__opening_bracket, __closing_bracket);
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return __underlying_.parse(__ctx);
|
||||
}
|
||||
|
||||
template <class FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename FormatContext::iterator format(__maybe_const_r& __range, FormatContext& __ctx) const {
|
||||
return __underlying_.format(__range, __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::map, _Rp, _CharT> {
|
||||
private:
|
||||
using __maybe_const_map = __fmt_maybe_const<_Rp, _CharT>;
|
||||
using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_map>>;
|
||||
range_formatter<__element_type, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter()
|
||||
requires(__fmt_pair_like<__element_type>)
|
||||
{
|
||||
__underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
|
||||
__underlying_.underlying().set_brackets({}, {});
|
||||
__underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return __underlying_.parse(__ctx);
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(__maybe_const_map& __range, _FormatContext& __ctx) const {
|
||||
return __underlying_.format(__range, __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::set, _Rp, _CharT> {
|
||||
private:
|
||||
using __maybe_const_set = __fmt_maybe_const<_Rp, _CharT>;
|
||||
using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_set>>;
|
||||
range_formatter<__element_type, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() {
|
||||
__underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return __underlying_.parse(__ctx);
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(__maybe_const_set& __range, _FormatContext& __ctx) const {
|
||||
return __underlying_.format(__range, __ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <range_format _Kp, ranges::input_range _Rp, class _CharT>
|
||||
requires(_Kp == range_format::string || _Kp == range_format::debug_string)
|
||||
struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<_Kp, _Rp, _CharT> {
|
||||
private:
|
||||
// This deviates from the Standard, there the exposition only type is
|
||||
// formatter<basic_string<charT>, charT> underlying_;
|
||||
// Using a string_view allows the format function to avoid a copy of the
|
||||
// input range when it is a contigious range.
|
||||
formatter<basic_string_view<_CharT>, _CharT> __underlying_;
|
||||
|
||||
public:
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
typename _ParseContext::iterator __i = __underlying_.parse(__ctx);
|
||||
if constexpr (_Kp == range_format::debug_string)
|
||||
__underlying_.set_debug_format();
|
||||
return __i;
|
||||
}
|
||||
|
||||
template <class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
format(conditional_t<ranges::input_range<const _Rp>, const _Rp&, _Rp&> __range, _FormatContext& __ctx) const {
|
||||
// When the range is contiguous use a basic_string_view instead to avoid a
|
||||
// copy of the underlying data. The basic_string_view formatter
|
||||
// specialization is the "basic" string formatter in libc++.
|
||||
if constexpr (ranges::contiguous_range<_Rp> && std::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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <ranges::input_range _Rp, class _CharT>
|
||||
requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>)
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<_Rp, _CharT> : __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
|
277
third_party/libcxx/__format/range_formatter.h
vendored
Normal file
277
third_party/libcxx/__format/range_formatter.h
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___FORMAT_RANGE_FORMATTER_H
|
||||
#define _LIBCPP___FORMAT_RANGE_FORMATTER_H
|
||||
|
||||
#include <__algorithm/ranges_copy.h>
|
||||
#include <__availability>
|
||||
#include <__chrono/statically_widen.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/buffer.h>
|
||||
#include <__format/concepts.h>
|
||||
#include <__format/format_args.h>
|
||||
#include <__format/format_context.h>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <__iterator/back_insert_iterator.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/data.h>
|
||||
#include <__ranges/size.h>
|
||||
#include <__type_traits/remove_cvref.h>
|
||||
#include <string_view>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
template <class _Tp, class _CharT = char>
|
||||
requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS range_formatter {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept {
|
||||
__separator_ = __separator;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void
|
||||
set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept {
|
||||
__opening_bracket_ = __opening_bracket;
|
||||
__closing_bracket_ = __closing_bracket;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() noexcept { return __underlying_; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const noexcept { return __underlying_; }
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_range);
|
||||
auto __end = __ctx.end();
|
||||
// Note the cases where __begin == __end in this code only happens when the
|
||||
// replacement-field has no terminating }, or when the parse is manually
|
||||
// called with a format-spec. The former is an error and the latter means
|
||||
// using a formatter without the format functions or print.
|
||||
if (__begin == __end) [[unlikely]]
|
||||
return __parse_empty_range_underlying_spec(__ctx, __begin);
|
||||
|
||||
// The n field overrides a possible m type, therefore delay applying the
|
||||
// effect of n until the type has been procesed.
|
||||
bool __clear_brackets = (*__begin == _CharT('n'));
|
||||
if (__clear_brackets) {
|
||||
++__begin;
|
||||
if (__begin == __end) [[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)
|
||||
set_brackets({}, {});
|
||||
if (__begin == __end) [[unlikely]]
|
||||
return __parse_empty_range_underlying_spec(__ctx, __begin);
|
||||
|
||||
bool __has_range_underlying_spec = *__begin == _CharT(':');
|
||||
if (__has_range_underlying_spec) {
|
||||
// range-underlying-spec:
|
||||
// : format-spec
|
||||
++__begin;
|
||||
} else if (__begin != __end && *__begin != _CharT('}'))
|
||||
// When there is no underlaying range the current parse should have
|
||||
// consumed the format-spec. If not, the not consumed input will be
|
||||
// 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 '}'");
|
||||
|
||||
__ctx.advance_to(__begin);
|
||||
__begin = __underlying_.parse(__ctx);
|
||||
|
||||
// This test should not be required if __has_range_underlying_spec is false.
|
||||
// However this test makes sure the underlying formatter left the parser in
|
||||
// a valid state. (Note this is not a full protection against evil parsers.
|
||||
// For example
|
||||
// } this is test for the next argument {}
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
|
||||
// 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 '}'");
|
||||
|
||||
if (__parser_.__type_ != __format_spec::__type::__default) {
|
||||
// [format.range.formatter]/6
|
||||
// If the range-type is s or ?s, then there shall be no n option and no
|
||||
// range-underlying-spec.
|
||||
if (__clear_brackets) {
|
||||
if (__parser_.__type_ == __format_spec::__type::__string)
|
||||
std::__throw_format_error("The n option and type s can't be used together");
|
||||
std::__throw_format_error("The n option and type ?s can't be used together");
|
||||
}
|
||||
if (__has_range_underlying_spec) {
|
||||
if (__parser_.__type_ == __format_spec::__type::__string)
|
||||
std::__throw_format_error("Type s and an underlying format specification can't be used together");
|
||||
std::__throw_format_error("Type ?s and an underlying format specification can't be used together");
|
||||
}
|
||||
} else if (!__has_range_underlying_spec)
|
||||
std::__set_debug_format(__underlying_);
|
||||
|
||||
return __begin;
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
requires formattable<ranges::range_reference_t<_Rp>, _CharT> &&
|
||||
same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Rp&& __range, _FormatContext& __ctx) const {
|
||||
__format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
|
||||
|
||||
if (!__specs.__has_width())
|
||||
return __format_range(__range, __ctx, __specs);
|
||||
|
||||
// The size of the buffer needed is:
|
||||
// - open bracket characters
|
||||
// - close bracket character
|
||||
// - n elements where every element may have a different size
|
||||
// - (n -1) separators
|
||||
// The size of the element is hard to predict, knowing the type helps but
|
||||
// it depends on the format-spec. As an initial estimate we guess 6
|
||||
// characters.
|
||||
// Typically both brackets are 1 character and the separator is 2
|
||||
// characters. Which means there will be
|
||||
// (n - 1) * 2 + 1 + 1 = n * 2 character
|
||||
// So estimate 8 times the range size as buffer.
|
||||
std::size_t __capacity_hint = 0;
|
||||
if constexpr (std::ranges::sized_range<_Rp>)
|
||||
__capacity_hint = 8 * ranges::size(__range);
|
||||
__format::__retarget_buffer<_CharT> __buffer{__capacity_hint};
|
||||
basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{
|
||||
__buffer.__make_output_iterator(), __ctx};
|
||||
|
||||
__format_range(__range, __c, __specs);
|
||||
|
||||
return __formatter::__write_string_no_precision(__buffer.__view(), __ctx.out(), __specs);
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI
|
||||
__format_range(_Rp&& __range, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) const {
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
switch (__specs.__std_.__type_) {
|
||||
case __format_spec::__type::__string:
|
||||
case __format_spec::__type::__debug:
|
||||
return __format_as_string(__range, __ctx, __specs.__std_.__type_ == __format_spec::__type::__debug);
|
||||
default:
|
||||
return __format_as_sequence(__range, __ctx);
|
||||
}
|
||||
} else
|
||||
return __format_as_sequence(__range, __ctx);
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_as_string(_Rp&& __range, _FormatContext& __ctx, bool __debug_format) const {
|
||||
// When the range is contiguous use a basic_string_view instead to avoid a
|
||||
// copy of the underlying data. The basic_string_view formatter
|
||||
// specialization is the "basic" string formatter in libc++.
|
||||
if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) {
|
||||
std::formatter<basic_string_view<_CharT>, _CharT> __formatter;
|
||||
if (__debug_format)
|
||||
__formatter.set_debug_format();
|
||||
return __formatter.format(
|
||||
basic_string_view<_CharT>{
|
||||
ranges::data(__range),
|
||||
ranges::size(__range),
|
||||
},
|
||||
__ctx);
|
||||
} else {
|
||||
std::formatter<basic_string<_CharT>, _CharT> __formatter;
|
||||
if (__debug_format)
|
||||
__formatter.set_debug_format();
|
||||
// P2106's from_range has not been implemented yet. Instead use a simple
|
||||
// copy operation.
|
||||
// TODO FMT use basic_string's "from_range" constructor.
|
||||
// return std::formatter<basic_string<_CharT>, _CharT>{}.format(basic_string<_CharT>{from_range, __range}, __ctx);
|
||||
basic_string<_CharT> __str;
|
||||
ranges::copy(__range, back_insert_iterator{__str});
|
||||
return __formatter.format(__str, __ctx);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range _Rp, class _FormatContext>
|
||||
_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
|
||||
__format_as_sequence(_Rp&& __range, _FormatContext& __ctx) const {
|
||||
__ctx.advance_to(ranges::copy(__opening_bracket_, __ctx.out()).out);
|
||||
bool __use_separator = false;
|
||||
for (auto&& __e : __range) {
|
||||
if (__use_separator)
|
||||
__ctx.advance_to(ranges::copy(__separator_, __ctx.out()).out);
|
||||
else
|
||||
__use_separator = true;
|
||||
|
||||
__ctx.advance_to(__underlying_.format(__e, __ctx));
|
||||
}
|
||||
|
||||
return ranges::copy(__closing_bracket_, __ctx.out()).out;
|
||||
}
|
||||
|
||||
__format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left};
|
||||
|
||||
private:
|
||||
template <contiguous_iterator _Iterator>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin, _Iterator __end) {
|
||||
switch (*__begin) {
|
||||
case _CharT('m'):
|
||||
if constexpr (__fmt_pair_like<_Tp>) {
|
||||
set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
|
||||
set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", "));
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type m requires two elements for a pair or tuple");
|
||||
break;
|
||||
|
||||
case _CharT('s'):
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
__parser_.__type_ = __format_spec::__type::__string;
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type s requires formatting a character type");
|
||||
break;
|
||||
|
||||
case _CharT('?'):
|
||||
++__begin;
|
||||
if (__begin == __end || *__begin != _CharT('s'))
|
||||
std::__throw_format_error("The format-spec should consume the input or end with a '}'");
|
||||
if constexpr (same_as<_Tp, _CharT>) {
|
||||
__parser_.__type_ = __format_spec::__type::__debug;
|
||||
++__begin;
|
||||
} else
|
||||
std::__throw_format_error("The range-format-spec type ?s requires formatting a character type");
|
||||
}
|
||||
}
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
|
||||
__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");
|
||||
return __begin;
|
||||
}
|
||||
|
||||
formatter<_Tp, _CharT> __underlying_;
|
||||
basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", ");
|
||||
basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "[");
|
||||
basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "]");
|
||||
};
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_RANGE_FORMATTER_H
|
483
third_party/libcxx/__format/unicode.h
vendored
Normal file
483
third_party/libcxx/__format/unicode.h
vendored
Normal file
|
@ -0,0 +1,483 @@
|
|||
// -*- 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_UNICODE_H
|
||||
#define _LIBCPP___FORMAT_UNICODE_H
|
||||
|
||||
#include <__assert>
|
||||
#include <__bit/countl.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__format/extended_grapheme_cluster_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>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
||||
namespace __unicode {
|
||||
|
||||
// Helper struct for the result of a consume operation.
|
||||
//
|
||||
// The status value for a correct code point is 0. This allows a valid value to
|
||||
// be used without masking.
|
||||
// When the decoding fails it know the number of code units affected. For the
|
||||
// current use-cases that value is not needed, therefore it is not stored.
|
||||
// The escape routine needs the number of code units for both a valid and
|
||||
// invalid character and keeps track of it itself. Doing it in this result
|
||||
// unconditionally would give some overhead when the value is unneeded.
|
||||
struct __consume_result {
|
||||
// When __status == __ok it contains the decoded code point.
|
||||
// Else it contains the replacement character U+FFFD
|
||||
char32_t __code_point : 31;
|
||||
|
||||
enum : char32_t {
|
||||
// Consumed a well-formed code point.
|
||||
__ok = 0,
|
||||
// Encountered invalid UTF-8
|
||||
__error = 1
|
||||
} __status : 1 {__ok};
|
||||
};
|
||||
static_assert(sizeof(__consume_result) == sizeof(char32_t));
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_UNICODE
|
||||
|
||||
/// Implements the grapheme cluster boundary rules
|
||||
///
|
||||
/// These rules are used to implement format's width estimation as stated in
|
||||
/// [format.string.std]/11
|
||||
///
|
||||
/// The Standard refers to UAX \#29 for Unicode 12.0.0
|
||||
/// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
|
||||
///
|
||||
/// The data tables used are
|
||||
/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
|
||||
/// https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
|
||||
/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt (for testing only)
|
||||
|
||||
inline constexpr char32_t __replacement_character = U'\ufffd';
|
||||
|
||||
// The error of a consume operation.
|
||||
//
|
||||
// This sets the code point to the replacement character. This code point does
|
||||
// not participate in the grapheme clustering, so grapheme clustering code can
|
||||
// ignore the error status and always use the code point.
|
||||
inline constexpr __consume_result __consume_result_error{__replacement_character, __consume_result::__error};
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_high_surrogate(char32_t __value) {
|
||||
return __value >= 0xd800 && __value <= 0xdbff;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_low_surrogate(char32_t __value) {
|
||||
return __value >= 0xdc00 && __value <= 0xdfff;
|
||||
}
|
||||
|
||||
// https://www.unicode.org/glossary/#surrogate_code_point
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_surrogate(char32_t __value) {
|
||||
return __value >= 0xd800 && __value <= 0xdfff;
|
||||
}
|
||||
|
||||
// https://www.unicode.org/glossary/#code_point
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_code_point(char32_t __value) {
|
||||
return __value <= 0x10ffff;
|
||||
}
|
||||
|
||||
// https://www.unicode.org/glossary/#unicode_scalar_value
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_scalar_value(char32_t __value) {
|
||||
return __unicode::__is_code_point(__value) && !__unicode::__is_surrogate(__value);
|
||||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
--__count;
|
||||
++__char;
|
||||
} while (__count);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Helper class to extract a code unit from a Unicode character range.
|
||||
///
|
||||
/// The stored range is a view. There are multiple specialization for different
|
||||
/// character types.
|
||||
template <class _CharT>
|
||||
class __code_point_view;
|
||||
|
||||
/// UTF-8 specialization.
|
||||
template <>
|
||||
class __code_point_view<char> {
|
||||
using _Iterator = basic_string_view<char>::const_iterator;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
|
||||
: __first_(__first), __last_(__last) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
|
||||
|
||||
// https://www.unicode.org/versions/latest/ch03.pdf#G7404
|
||||
// Based on Table 3-7, Well-Formed UTF-8 Byte Sequences
|
||||
//
|
||||
// Code Points First Byte Second Byte Third Byte Fourth Byte Remarks
|
||||
// U+0000..U+007F 00..7F U+0000..U+007F 1 code unit range
|
||||
// C0..C1 80..BF invalid overlong encoding
|
||||
// U+0080..U+07FF C2..DF 80..BF U+0080..U+07FF 2 code unit range
|
||||
// E0 80..9F 80..BF invalid overlong encoding
|
||||
// U+0800..U+0FFF E0 A0..BF 80..BF U+0800..U+FFFF 3 code unit range
|
||||
// U+1000..U+CFFF E1..EC 80..BF 80..BF
|
||||
// U+D000..U+D7FF ED 80..9F 80..BF
|
||||
// U+D800..U+DFFF ED A0..BF 80..BF invalid encoding of surrogate code point
|
||||
// U+E000..U+FFFF EE..EF 80..BF 80..BF
|
||||
// F0 80..8F 80..BF 80..BF invalid overlong encoding
|
||||
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF U+10000..U+10FFFF 4 code unit range
|
||||
// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
|
||||
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
|
||||
// F4 90..BF 80..BF 80..BF U+110000.. invalid code point range
|
||||
//
|
||||
// Unlike other parsers, these invalid entries are tested after decoding.
|
||||
// - 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");
|
||||
|
||||
// Based on the number of leading 1 bits the number of code units in the
|
||||
// code point can be determined. See
|
||||
// https://en.wikipedia.org/wiki/UTF-8#Encoding
|
||||
switch (std::countl_one(static_cast<unsigned char>(*__first_))) {
|
||||
case 0:
|
||||
return {static_cast<unsigned char>(*__first_++)};
|
||||
|
||||
case 2: {
|
||||
if (__last_ - __first_ < 2 || !__unicode::__is_continuation(__first_ + 1, 1)) [[unlikely]]
|
||||
break;
|
||||
|
||||
char32_t __value = static_cast<unsigned char>(*__first_++) & 0x1f;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
|
||||
// These values should be encoded in 1 UTF-8 code unit.
|
||||
if (__value < 0x0080) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
return {__value};
|
||||
}
|
||||
|
||||
case 3: {
|
||||
if (__last_ - __first_ < 3 || !__unicode::__is_continuation(__first_ + 1, 2)) [[unlikely]]
|
||||
break;
|
||||
|
||||
char32_t __value = static_cast<unsigned char>(*__first_++) & 0x0f;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
|
||||
// These values should be encoded in 1 or 2 UTF-8 code units.
|
||||
if (__value < 0x0800) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
// A surrogate value is always encoded in 3 UTF-8 code units.
|
||||
if (__unicode::__is_surrogate(__value)) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
return {__value};
|
||||
}
|
||||
|
||||
case 4: {
|
||||
if (__last_ - __first_ < 4 || !__unicode::__is_continuation(__first_ + 1, 3)) [[unlikely]]
|
||||
break;
|
||||
|
||||
char32_t __value = static_cast<unsigned char>(*__first_++) & 0x07;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
__value <<= 6;
|
||||
__value |= static_cast<unsigned char>(*__first_++) & 0x3f;
|
||||
|
||||
// These values should be encoded in 1, 2, or 3 UTF-8 code units.
|
||||
if (__value < 0x10000) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
// A value too large is always encoded in 4 UTF-8 code units.
|
||||
if (!__unicode::__is_code_point(__value)) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
return {__value};
|
||||
}
|
||||
}
|
||||
// An invalid number of leading ones can be garbage or a code unit in the
|
||||
// middle of a code point. By consuming one code unit the parser may get
|
||||
// "in sync" after a few code units.
|
||||
++__first_;
|
||||
return __consume_result_error;
|
||||
}
|
||||
|
||||
private:
|
||||
_Iterator __first_;
|
||||
_Iterator __last_;
|
||||
};
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_high(wchar_t __value) {
|
||||
return __value >= 0xd800 && __value <= 0xdbff;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_low(wchar_t __value) {
|
||||
return __value >= 0xdc00 && __value <= 0xdfff;
|
||||
}
|
||||
|
||||
/// This specialization depends on the size of wchar_t
|
||||
/// - 2 UTF-16 (for example Windows and AIX)
|
||||
/// - 4 UTF-32 (for example Linux)
|
||||
template <>
|
||||
class __code_point_view<wchar_t> {
|
||||
using _Iterator = typename basic_string_view<wchar_t>::const_iterator;
|
||||
|
||||
public:
|
||||
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "sizeof(wchar_t) has a not implemented value");
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
|
||||
: __first_(__first), __last_(__last) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; }
|
||||
_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");
|
||||
|
||||
char32_t __value = static_cast<char32_t>(*__first_++);
|
||||
if constexpr (sizeof(wchar_t) == 2) {
|
||||
if (__unicode::__is_low_surrogate(__value)) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
if (__unicode::__is_high_surrogate(__value)) {
|
||||
if (__first_ == __last_ || !__unicode::__is_low_surrogate(static_cast<char32_t>(*__first_))) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
|
||||
__value -= 0xd800;
|
||||
__value <<= 10;
|
||||
__value += static_cast<char32_t>(*__first_++) - 0xdc00;
|
||||
__value += 0x10000;
|
||||
|
||||
if (!__unicode::__is_code_point(__value)) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
}
|
||||
} else {
|
||||
if (!__unicode::__is_scalar_value(__value)) [[unlikely]]
|
||||
return __consume_result_error;
|
||||
}
|
||||
|
||||
return {__value};
|
||||
}
|
||||
|
||||
private:
|
||||
_Iterator __first_;
|
||||
_Iterator __last_;
|
||||
};
|
||||
# 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;
|
||||
|
||||
__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;
|
||||
}
|
||||
|
||||
// *** Otherwise, break everywhere. ***
|
||||
return true; // GB999
|
||||
}
|
||||
|
||||
/// Helper class to extract an extended grapheme cluster from a Unicode character range.
|
||||
///
|
||||
/// This function is used to determine the column width of an extended grapheme
|
||||
/// cluster. In order to do that only the first code point is evaluated.
|
||||
/// Therefore only this code point is extracted.
|
||||
template <class _CharT>
|
||||
class __extended_grapheme_cluster_view {
|
||||
using _Iterator = typename basic_string_view<_CharT>::const_iterator;
|
||||
|
||||
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_)) {}
|
||||
|
||||
struct __cluster {
|
||||
/// The first code point of the extended grapheme cluster.
|
||||
///
|
||||
/// The first code point is used to estimate the width of the extended
|
||||
/// grapheme cluster.
|
||||
char32_t __code_point_;
|
||||
|
||||
/// Points one beyond the last code unit in the extended grapheme cluster.
|
||||
///
|
||||
/// It's expected the caller has the start position and thus can determine
|
||||
/// the code unit range of the extended grapheme cluster.
|
||||
_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()};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <contiguous_iterator _Iterator>
|
||||
__extended_grapheme_cluster_view(_Iterator, _Iterator) -> __extended_grapheme_cluster_view<iter_value_t<_Iterator>>;
|
||||
|
||||
# else // _LIBCPP_HAS_NO_UNICODE
|
||||
|
||||
// For ASCII every character is a "code point".
|
||||
// This makes it easier to write code agnostic of the _LIBCPP_HAS_NO_UNICODE define.
|
||||
template <class _CharT>
|
||||
class __code_point_view {
|
||||
using _Iterator = typename basic_string_view<_CharT>::const_iterator;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last)
|
||||
: __first_(__first), __last_(__last) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
|
||||
_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");
|
||||
return {static_cast<char32_t>(*__first_++)};
|
||||
}
|
||||
|
||||
private:
|
||||
_Iterator __first_;
|
||||
_Iterator __last_;
|
||||
};
|
||||
|
||||
# endif // _LIBCPP_HAS_NO_UNICODE
|
||||
|
||||
} // namespace __unicode
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_UNICODE_H
|
271
third_party/libcxx/__format/width_estimation_table.h
vendored
Normal file
271
third_party/libcxx/__format/width_estimation_table.h
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
// -*- 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_width_estimation_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_WIDTH_ESTIMATION_TABLE_H
|
||||
#define _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H
|
||||
|
||||
#include <__algorithm/ranges_upper_bound.h>
|
||||
#include <__config>
|
||||
#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 __width_estimation_table {
|
||||
|
||||
/// The entries of the characters with an estimated width of 2.
|
||||
///
|
||||
/// Contains the entries for [format.string.std]/12
|
||||
/// - Any code point with the East_Asian_Width="W" or East_Asian_Width="F"
|
||||
/// Derived Extracted Property as described by UAX #44
|
||||
/// - U+4DC0 - U+4DFF (Yijing Hexagram Symbols)
|
||||
/// - U+1F300 - U+1F5FF (Miscellaneous Symbols and Pictographs)
|
||||
/// - U+1F900 - U+1F9FF (Supplemental Symbols and Pictographs)
|
||||
///
|
||||
/// The data is generated from
|
||||
/// - https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
|
||||
/// - The "overrides" in [format.string.std]/12
|
||||
///
|
||||
/// The format of EastAsianWidth.txt is two fields separated by a semicolon.
|
||||
/// Field 0: Unicode code point value or range of code point values
|
||||
/// Field 1: East_Asian_Width property, consisting of one of the following values:
|
||||
/// "A", "F", "H", "N", "Na", "W"
|
||||
/// - All code points, assigned or unassigned, that are not listed
|
||||
/// explicitly are given the value "N".
|
||||
/// - The unassigned code points in the following blocks default to "W":
|
||||
/// CJK Unified Ideographs Extension A: U+3400..U+4DBF
|
||||
/// CJK Unified Ideographs: U+4E00..U+9FFF
|
||||
/// CJK Compatibility Ideographs: U+F900..U+FAFF
|
||||
/// - All undesignated code points in Planes 2 and 3, whether inside or
|
||||
/// outside of allocated blocks, default to "W":
|
||||
/// Plane 2: U+20000..U+2FFFD
|
||||
/// Plane 3: U+30000..U+3FFFD
|
||||
///
|
||||
/// The table is similar to the table
|
||||
/// __extended_grapheme_custer_property_boundary::__entries
|
||||
/// which explains the details of these classes. The only difference is this
|
||||
/// table lacks a property, thus having more bits available for the size.
|
||||
///
|
||||
/// The maximum code point that has an estimated width of 2 is U+3FFFD. This
|
||||
/// value can be encoded in 18 bits. Thus the upper 3 bits of the code point
|
||||
/// are always 0. These 3 bits are used to enlarge the offset range. This
|
||||
/// optimization reduces the table in Unicode 15 from 184 to 104 entries,
|
||||
/// saving 320 bytes.
|
||||
///
|
||||
/// The data has 2 values:
|
||||
/// - 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] = {
|
||||
0x0440005f /* 00001100 - 0000115f [ 96] */, //
|
||||
0x08c68001 /* 0000231a - 0000231b [ 2] */, //
|
||||
0x08ca4001 /* 00002329 - 0000232a [ 2] */, //
|
||||
0x08fa4003 /* 000023e9 - 000023ec [ 4] */, //
|
||||
0x08fc0000 /* 000023f0 - 000023f0 [ 1] */, //
|
||||
0x08fcc000 /* 000023f3 - 000023f3 [ 1] */, //
|
||||
0x097f4001 /* 000025fd - 000025fe [ 2] */, //
|
||||
0x09850001 /* 00002614 - 00002615 [ 2] */, //
|
||||
0x0992000b /* 00002648 - 00002653 [ 12] */, //
|
||||
0x099fc000 /* 0000267f - 0000267f [ 1] */, //
|
||||
0x09a4c000 /* 00002693 - 00002693 [ 1] */, //
|
||||
0x09a84000 /* 000026a1 - 000026a1 [ 1] */, //
|
||||
0x09aa8001 /* 000026aa - 000026ab [ 2] */, //
|
||||
0x09af4001 /* 000026bd - 000026be [ 2] */, //
|
||||
0x09b10001 /* 000026c4 - 000026c5 [ 2] */, //
|
||||
0x09b38000 /* 000026ce - 000026ce [ 1] */, //
|
||||
0x09b50000 /* 000026d4 - 000026d4 [ 1] */, //
|
||||
0x09ba8000 /* 000026ea - 000026ea [ 1] */, //
|
||||
0x09bc8001 /* 000026f2 - 000026f3 [ 2] */, //
|
||||
0x09bd4000 /* 000026f5 - 000026f5 [ 1] */, //
|
||||
0x09be8000 /* 000026fa - 000026fa [ 1] */, //
|
||||
0x09bf4000 /* 000026fd - 000026fd [ 1] */, //
|
||||
0x09c14000 /* 00002705 - 00002705 [ 1] */, //
|
||||
0x09c28001 /* 0000270a - 0000270b [ 2] */, //
|
||||
0x09ca0000 /* 00002728 - 00002728 [ 1] */, //
|
||||
0x09d30000 /* 0000274c - 0000274c [ 1] */, //
|
||||
0x09d38000 /* 0000274e - 0000274e [ 1] */, //
|
||||
0x09d4c002 /* 00002753 - 00002755 [ 3] */, //
|
||||
0x09d5c000 /* 00002757 - 00002757 [ 1] */, //
|
||||
0x09e54002 /* 00002795 - 00002797 [ 3] */, //
|
||||
0x09ec0000 /* 000027b0 - 000027b0 [ 1] */, //
|
||||
0x09efc000 /* 000027bf - 000027bf [ 1] */, //
|
||||
0x0ac6c001 /* 00002b1b - 00002b1c [ 2] */, //
|
||||
0x0ad40000 /* 00002b50 - 00002b50 [ 1] */, //
|
||||
0x0ad54000 /* 00002b55 - 00002b55 [ 1] */, //
|
||||
0x0ba00019 /* 00002e80 - 00002e99 [ 26] */, //
|
||||
0x0ba6c058 /* 00002e9b - 00002ef3 [ 89] */, //
|
||||
0x0bc000d5 /* 00002f00 - 00002fd5 [ 214] */, //
|
||||
0x0bfc000b /* 00002ff0 - 00002ffb [ 12] */, //
|
||||
0x0c00003e /* 00003000 - 0000303e [ 63] */, //
|
||||
0x0c104055 /* 00003041 - 00003096 [ 86] */, //
|
||||
0x0c264066 /* 00003099 - 000030ff [ 103] */, //
|
||||
0x0c41402a /* 00003105 - 0000312f [ 43] */, //
|
||||
0x0c4c405d /* 00003131 - 0000318e [ 94] */, //
|
||||
0x0c640053 /* 00003190 - 000031e3 [ 84] */, //
|
||||
0x0c7c002e /* 000031f0 - 0000321e [ 47] */, //
|
||||
0x0c880027 /* 00003220 - 00003247 [ 40] */, //
|
||||
0x0c943fff /* 00003250 - 0000724f [16384] */, //
|
||||
0x1c94323c /* 00007250 - 0000a48c [12861] */, //
|
||||
0x29240036 /* 0000a490 - 0000a4c6 [ 55] */, //
|
||||
0x2a58001c /* 0000a960 - 0000a97c [ 29] */, //
|
||||
0x2b002ba3 /* 0000ac00 - 0000d7a3 [11172] */, //
|
||||
0x3e4001ff /* 0000f900 - 0000faff [ 512] */, //
|
||||
0x3f840009 /* 0000fe10 - 0000fe19 [ 10] */, //
|
||||
0x3f8c0022 /* 0000fe30 - 0000fe52 [ 35] */, //
|
||||
0x3f950012 /* 0000fe54 - 0000fe66 [ 19] */, //
|
||||
0x3f9a0003 /* 0000fe68 - 0000fe6b [ 4] */, //
|
||||
0x3fc0405f /* 0000ff01 - 0000ff60 [ 96] */, //
|
||||
0x3ff80006 /* 0000ffe0 - 0000ffe6 [ 7] */, //
|
||||
0x5bf80004 /* 00016fe0 - 00016fe4 [ 5] */, //
|
||||
0x5bfc0001 /* 00016ff0 - 00016ff1 [ 2] */, //
|
||||
0x5c0017f7 /* 00017000 - 000187f7 [ 6136] */, //
|
||||
0x620004d5 /* 00018800 - 00018cd5 [ 1238] */, //
|
||||
0x63400008 /* 00018d00 - 00018d08 [ 9] */, //
|
||||
0x6bfc0003 /* 0001aff0 - 0001aff3 [ 4] */, //
|
||||
0x6bfd4006 /* 0001aff5 - 0001affb [ 7] */, //
|
||||
0x6bff4001 /* 0001affd - 0001affe [ 2] */, //
|
||||
0x6c000122 /* 0001b000 - 0001b122 [ 291] */, //
|
||||
0x6c4c8000 /* 0001b132 - 0001b132 [ 1] */, //
|
||||
0x6c540002 /* 0001b150 - 0001b152 [ 3] */, //
|
||||
0x6c554000 /* 0001b155 - 0001b155 [ 1] */, //
|
||||
0x6c590003 /* 0001b164 - 0001b167 [ 4] */, //
|
||||
0x6c5c018b /* 0001b170 - 0001b2fb [ 396] */, //
|
||||
0x7c010000 /* 0001f004 - 0001f004 [ 1] */, //
|
||||
0x7c33c000 /* 0001f0cf - 0001f0cf [ 1] */, //
|
||||
0x7c638000 /* 0001f18e - 0001f18e [ 1] */, //
|
||||
0x7c644009 /* 0001f191 - 0001f19a [ 10] */, //
|
||||
0x7c800002 /* 0001f200 - 0001f202 [ 3] */, //
|
||||
0x7c84002b /* 0001f210 - 0001f23b [ 44] */, //
|
||||
0x7c900008 /* 0001f240 - 0001f248 [ 9] */, //
|
||||
0x7c940001 /* 0001f250 - 0001f251 [ 2] */, //
|
||||
0x7c980005 /* 0001f260 - 0001f265 [ 6] */, //
|
||||
0x7cc0034f /* 0001f300 - 0001f64f [ 848] */, //
|
||||
0x7da00045 /* 0001f680 - 0001f6c5 [ 70] */, //
|
||||
0x7db30000 /* 0001f6cc - 0001f6cc [ 1] */, //
|
||||
0x7db40002 /* 0001f6d0 - 0001f6d2 [ 3] */, //
|
||||
0x7db54002 /* 0001f6d5 - 0001f6d7 [ 3] */, //
|
||||
0x7db70003 /* 0001f6dc - 0001f6df [ 4] */, //
|
||||
0x7dbac001 /* 0001f6eb - 0001f6ec [ 2] */, //
|
||||
0x7dbd0008 /* 0001f6f4 - 0001f6fc [ 9] */, //
|
||||
0x7df8000b /* 0001f7e0 - 0001f7eb [ 12] */, //
|
||||
0x7dfc0000 /* 0001f7f0 - 0001f7f0 [ 1] */, //
|
||||
0x7e4000ff /* 0001f900 - 0001f9ff [ 256] */, //
|
||||
0x7e9c000c /* 0001fa70 - 0001fa7c [ 13] */, //
|
||||
0x7ea00008 /* 0001fa80 - 0001fa88 [ 9] */, //
|
||||
0x7ea4002d /* 0001fa90 - 0001fabd [ 46] */, //
|
||||
0x7eafc006 /* 0001fabf - 0001fac5 [ 7] */, //
|
||||
0x7eb3800d /* 0001face - 0001fadb [ 14] */, //
|
||||
0x7eb80008 /* 0001fae0 - 0001fae8 [ 9] */, //
|
||||
0x7ebc0008 /* 0001faf0 - 0001faf8 [ 9] */, //
|
||||
0x80003fff /* 00020000 - 00023fff [16384] */, //
|
||||
0x90003fff /* 00024000 - 00027fff [16384] */, //
|
||||
0xa0003fff /* 00028000 - 0002bfff [16384] */, //
|
||||
0xb0003ffd /* 0002c000 - 0002fffd [16382] */, //
|
||||
0xc0003fff /* 00030000 - 00033fff [16384] */, //
|
||||
0xd0003fff /* 00034000 - 00037fff [16384] */, //
|
||||
0xe0003fff /* 00038000 - 0003bfff [16384] */, //
|
||||
0xf0003ffd /* 0003c000 - 0003fffd [16382] */};
|
||||
|
||||
/// The upper bound entry of EastAsianWidth.txt.
|
||||
///
|
||||
/// Values greater than this value may have more than 18 significant bits.
|
||||
/// They always have a width of 1. This property makes it possible to store
|
||||
/// the table in its compact form.
|
||||
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.
|
||||
[[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.
|
||||
if (__code_point > __table_upper_bound) [[unlikely]]
|
||||
return 1;
|
||||
|
||||
// When the code-point is less than the first element in the table
|
||||
// the lookup is quite expensive. Since quite some scripts are in
|
||||
// that range, it makes sense to validate that first.
|
||||
// The std_format_spec_string_unicode benchmark gives a measurable
|
||||
// improvement.
|
||||
if (__code_point < (__entries[0] >> 14))
|
||||
return 1;
|
||||
|
||||
ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 14) | 0x3fffu) - __entries;
|
||||
if (__i == 0)
|
||||
return 1;
|
||||
|
||||
--__i;
|
||||
uint32_t __upper_bound = (__entries[__i] >> 14) + (__entries[__i] & 0x3fffu);
|
||||
return 1 + (__code_point <= __upper_bound);
|
||||
}
|
||||
|
||||
} // namespace __width_estimation_table
|
||||
|
||||
#endif //_LIBCPP_STD_VER >= 20
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H
|
Loading…
Add table
Add a link
Reference in a new issue