зеркало из https://github.com/microsoft/STL.git
452 строки
17 KiB
C++
452 строки
17 KiB
C++
// __msvc_formatter.hpp internal header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
// NOTE:
|
|
// The contents of this header are derived in part from libfmt under the following license:
|
|
|
|
// Copyright (c) 2012 - present, Victor Zverovich
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
|
|
// THE SOFTWARE IS 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. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// --- Optional exception to the license ---
|
|
//
|
|
// As an exception, if, as a result of your compiling your source code, portions
|
|
// of this Software are embedded into a machine-executable object form of such
|
|
// source code, you may redistribute such embedded portions in such object form
|
|
// without including the above copyright and permission notices.
|
|
|
|
#ifndef __MSVC_FORMATTER_HPP
|
|
#define __MSVC_FORMATTER_HPP
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#if !_HAS_CXX20
|
|
#error The contents of <format> are only available with C++20. (Also, you should not include this internal header.)
|
|
#endif // !_HAS_CXX20
|
|
|
|
#include <concepts>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
#if _HAS_CXX23
|
|
#include <xutility>
|
|
#endif // _HAS_CXX23
|
|
|
|
#pragma pack(push, _CRT_PACKING)
|
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
|
_STL_DISABLE_CLANG_WARNINGS
|
|
#pragma push_macro("new")
|
|
#undef new
|
|
|
|
_STD_BEGIN
|
|
#if _HAS_CXX23
|
|
#define _FMT_P2286_BEGIN inline namespace __p2286 {
|
|
#define _FMT_P2286_END }
|
|
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
|
|
#define _FMT_P2286_BEGIN
|
|
#define _FMT_P2286_END
|
|
#endif // ^^^ !_HAS_CXX23 ^^^
|
|
|
|
enum class _Fmt_align : uint8_t { _None, _Left, _Right, _Center };
|
|
|
|
enum class _Fmt_sign : uint8_t { _None, _Plus, _Minus, _Space };
|
|
|
|
enum class _Basic_format_arg_type : uint8_t {
|
|
_None,
|
|
_Int_type,
|
|
_UInt_type,
|
|
_Long_long_type,
|
|
_ULong_long_type,
|
|
_Bool_type,
|
|
_Char_type,
|
|
_Float_type,
|
|
_Double_type,
|
|
_Long_double_type,
|
|
_Pointer_type,
|
|
_CString_type,
|
|
_String_type,
|
|
_Custom_type,
|
|
};
|
|
static_assert(static_cast<int>(_Basic_format_arg_type::_Custom_type) < 16, "must fit in 4-bit bitfield");
|
|
|
|
#if _HAS_CXX23
|
|
_EXPORT_STD template <class _Ty>
|
|
constexpr bool enable_nonlocking_formatter_optimization = false;
|
|
|
|
_NODISCARD consteval bool _Is_debug_enabled_fmt_type(_Basic_format_arg_type _Ty) {
|
|
return _Ty == _Basic_format_arg_type::_Char_type || _Ty == _Basic_format_arg_type::_CString_type
|
|
|| _Ty == _Basic_format_arg_type::_String_type;
|
|
}
|
|
#endif // _HAS_CXX23
|
|
|
|
template <class _CharT>
|
|
struct _Basic_format_specs {
|
|
int _Width = 0;
|
|
int _Precision = -1;
|
|
char _Type = '\0';
|
|
_Fmt_align _Alignment = _Fmt_align::_None;
|
|
_Fmt_sign _Sgn = _Fmt_sign::_None;
|
|
bool _Alt = false;
|
|
bool _Localized = false;
|
|
bool _Leading_zero = false;
|
|
uint8_t _Fill_length = 1;
|
|
// At most one codepoint (so one char32_t or four utf-8 char8_t).
|
|
_CharT _Fill[4 / sizeof(_CharT)] = {_CharT{' '}};
|
|
};
|
|
|
|
// Adds width and precision references to _Basic_format_specs.
|
|
// This is required for std::formatter implementations because we must
|
|
// parse the format specs without having access to the format args (via a format context).
|
|
template <class _CharT>
|
|
struct _Dynamic_format_specs : _Basic_format_specs<_CharT> {
|
|
int _Dynamic_width_index = -1;
|
|
int _Dynamic_precision_index = -1;
|
|
};
|
|
|
|
[[noreturn]] inline void _Throw_format_error(const char* _Message);
|
|
|
|
_EXPORT_STD template <class _CharT>
|
|
class basic_format_parse_context;
|
|
|
|
template <class _CharT>
|
|
concept _Format_supported_charT = _Is_any_of_v<_CharT, char, wchar_t>;
|
|
|
|
_EXPORT_STD template <class _Ty, class _CharT = char>
|
|
struct formatter {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
_FMT_P2286_BEGIN
|
|
// TRANSITION, VSO-1236041: Avoid declaring and defining member functions in different headers.
|
|
template <_Basic_format_arg_type _ArgType, class _CharT, class _Pc>
|
|
constexpr _Pc::iterator _Formatter_base_parse(_Dynamic_format_specs<_CharT>& _Specs, _Pc& _ParseCtx);
|
|
|
|
template <class _Ty, class _CharT, class _FormatContext>
|
|
_FormatContext::iterator _Formatter_base_format(
|
|
const _Dynamic_format_specs<_CharT>& _Specs, const _Ty& _Val, _FormatContext& _FormatCtx);
|
|
|
|
template <class _Ty, class _CharT, _Basic_format_arg_type _ArgType>
|
|
struct _Formatter_base {
|
|
public:
|
|
#if _HAS_CXX23
|
|
constexpr void _Set_debug_format() noexcept
|
|
requires (_Is_debug_enabled_fmt_type(_ArgType))
|
|
{
|
|
_Specs._Type = '?';
|
|
}
|
|
#endif // _HAS_CXX23
|
|
|
|
template <class _Pc = basic_format_parse_context<_CharT>>
|
|
constexpr _Pc::iterator parse(type_identity_t<_Pc&> _ParseCtx) {
|
|
return _Formatter_base_parse<_ArgType>(_Specs, _ParseCtx);
|
|
}
|
|
|
|
template <class _FormatContext>
|
|
_FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const {
|
|
return _Formatter_base_format(_Specs, _Val, _FormatCtx);
|
|
}
|
|
|
|
private:
|
|
_Dynamic_format_specs<_CharT> _Specs;
|
|
};
|
|
_FMT_P2286_END
|
|
|
|
#if _HAS_CXX23
|
|
#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \
|
|
template <> \
|
|
inline constexpr bool enable_nonlocking_formatter_optimization<_Type> = true;
|
|
#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv
|
|
#define _FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type)
|
|
#endif // ^^^ !_HAS_CXX23 ^^^
|
|
|
|
#define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \
|
|
_FORMAT_SPECIALIZE_NONLOCKING_FOR(_Type) \
|
|
template <_Format_supported_charT _CharT> \
|
|
struct formatter<_Type, _CharT> : _Formatter_base<_Type, _CharT, _ArgType> {}
|
|
|
|
_FORMAT_SPECIALIZE_FOR(int, _Basic_format_arg_type::_Int_type);
|
|
_FORMAT_SPECIALIZE_FOR(unsigned int, _Basic_format_arg_type::_UInt_type);
|
|
_FORMAT_SPECIALIZE_FOR(long long, _Basic_format_arg_type::_Long_long_type);
|
|
_FORMAT_SPECIALIZE_FOR(unsigned long long, _Basic_format_arg_type::_ULong_long_type);
|
|
_FORMAT_SPECIALIZE_FOR(bool, _Basic_format_arg_type::_Bool_type);
|
|
_FORMAT_SPECIALIZE_FOR(float, _Basic_format_arg_type::_Float_type);
|
|
_FORMAT_SPECIALIZE_FOR(double, _Basic_format_arg_type::_Double_type);
|
|
_FORMAT_SPECIALIZE_FOR(long double, _Basic_format_arg_type::_Long_double_type);
|
|
_FORMAT_SPECIALIZE_FOR(nullptr_t, _Basic_format_arg_type::_Pointer_type);
|
|
_FORMAT_SPECIALIZE_FOR(void*, _Basic_format_arg_type::_Pointer_type);
|
|
_FORMAT_SPECIALIZE_FOR(const void*, _Basic_format_arg_type::_Pointer_type);
|
|
_FORMAT_SPECIALIZE_FOR(short, _Basic_format_arg_type::_Int_type);
|
|
_FORMAT_SPECIALIZE_FOR(unsigned short, _Basic_format_arg_type::_UInt_type);
|
|
_FORMAT_SPECIALIZE_FOR(long, _Basic_format_arg_type::_Int_type);
|
|
_FORMAT_SPECIALIZE_FOR(unsigned long, _Basic_format_arg_type::_UInt_type);
|
|
_FORMAT_SPECIALIZE_FOR(signed char, _Basic_format_arg_type::_Int_type);
|
|
_FORMAT_SPECIALIZE_FOR(unsigned char, _Basic_format_arg_type::_UInt_type);
|
|
|
|
#undef _FORMAT_SPECIALIZE_FOR
|
|
#undef _FORMAT_SPECIALIZE_NONLOCKING_FOR
|
|
|
|
// not using the macro because we'd like to add 'set_debug_format' member function in C++23 mode
|
|
template <_Format_supported_charT _CharT>
|
|
struct formatter<char, _CharT> : _Formatter_base<char, _CharT, _Basic_format_arg_type::_Char_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
// not using the macro because we'd like to avoid the formatter<wchar_t, char> specialization
|
|
template <>
|
|
struct formatter<wchar_t, wchar_t> : _Formatter_base<wchar_t, wchar_t, _Basic_format_arg_type::_Char_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
// We could use the macro for these specializations, but it's confusing to refer to symbols that are defined
|
|
// inside the macro in the macro's "call".
|
|
template <_Format_supported_charT _CharT>
|
|
struct formatter<_CharT*, _CharT> : _Formatter_base<_CharT*, _CharT, _Basic_format_arg_type::_CString_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
template <_Format_supported_charT _CharT>
|
|
struct formatter<const _CharT*, _CharT>
|
|
: _Formatter_base<const _CharT*, _CharT, _Basic_format_arg_type::_CString_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
template <_Format_supported_charT _CharT, size_t _Nx>
|
|
struct formatter<_CharT[_Nx], _CharT> : _Formatter_base<_CharT[_Nx], _CharT, _Basic_format_arg_type::_CString_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
_EXPORT_STD template <class _Elem, class _Traits, class _Alloc>
|
|
class basic_string;
|
|
|
|
_EXPORT_STD template <class _Elem, class _Traits>
|
|
class basic_string_view;
|
|
|
|
template <_Format_supported_charT _CharT, class _Traits, class _Allocator>
|
|
struct formatter<basic_string<_CharT, _Traits, _Allocator>, _CharT>
|
|
: _Formatter_base<basic_string<_CharT, _Traits, _Allocator>, _CharT, _Basic_format_arg_type::_String_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
template <_Format_supported_charT _CharT, class _Traits>
|
|
struct formatter<basic_string_view<_CharT, _Traits>, _CharT>
|
|
: _Formatter_base<basic_string_view<_CharT, _Traits>, _CharT, _Basic_format_arg_type::_String_type> {
|
|
#if _HAS_CXX23
|
|
constexpr void set_debug_format() noexcept {
|
|
this->_Set_debug_format();
|
|
}
|
|
#endif // _HAS_CXX23
|
|
};
|
|
|
|
#if _HAS_CXX23
|
|
template <>
|
|
struct formatter<char*, wchar_t> {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
template <>
|
|
struct formatter<const char*, wchar_t> {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
template <size_t _Size>
|
|
struct formatter<char[_Size], wchar_t> {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
template <class _Traits, class _Allocator>
|
|
struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t> {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
template <class _Traits>
|
|
struct formatter<basic_string_view<char, _Traits>, wchar_t> {
|
|
formatter() = delete;
|
|
formatter(const formatter&) = delete;
|
|
formatter& operator=(const formatter&) = delete;
|
|
};
|
|
|
|
_EXPORT_STD enum class range_format { disabled, map, set, sequence, string, debug_string };
|
|
|
|
template <class _Ty>
|
|
struct _Invalid_format_kind {
|
|
static_assert(_Always_false<_Ty>, "A program that instantiates the primary template of format_kind is ill-formed. "
|
|
"(N4981 [format.range.fmtkind]/1)");
|
|
};
|
|
|
|
_EXPORT_STD template <class _Ty>
|
|
constexpr _Invalid_format_kind<_Ty> format_kind;
|
|
|
|
template <class _Ty>
|
|
constexpr bool _Is_two_tuple = false;
|
|
|
|
template <class _Ty, class _Uty>
|
|
constexpr bool _Is_two_tuple<pair<_Ty, _Uty>> = true;
|
|
|
|
template <class _Ty, class _Uty>
|
|
constexpr bool _Is_two_tuple<tuple<_Ty, _Uty>> = true;
|
|
|
|
template <_RANGES input_range _Rng>
|
|
requires same_as<_Rng, remove_cvref_t<_Rng>>
|
|
constexpr range_format format_kind<_Rng> = []() consteval {
|
|
using _Ref_value_t = remove_cvref_t<_RANGES range_reference_t<_Rng>>;
|
|
if constexpr (same_as<_Ref_value_t, _Rng>) {
|
|
return range_format::disabled;
|
|
} else if constexpr (requires { typename _Rng::key_type; }) {
|
|
if constexpr (requires { typename _Rng::mapped_type; } && _Is_two_tuple<_Ref_value_t>) {
|
|
return range_format::map;
|
|
} else {
|
|
return range_format::set;
|
|
}
|
|
} else {
|
|
return range_format::sequence;
|
|
}
|
|
}();
|
|
|
|
// Specializations for pairs, tuples, and ranges are forward-declared to avoid any risk of using the disabled primary
|
|
// template.
|
|
|
|
// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is
|
|
// constrained to character types supported by `format`.
|
|
|
|
template <class _Rng>
|
|
concept _Formatting_enabled_range = format_kind<_Rng> != range_format::disabled;
|
|
|
|
template <_RANGES input_range _Rng, _Format_supported_charT _CharT>
|
|
requires _Formatting_enabled_range<_Rng>
|
|
struct formatter<_Rng, _CharT>;
|
|
|
|
template <_Format_supported_charT _CharT, class _Ty1, class _Ty2>
|
|
struct formatter<pair<_Ty1, _Ty2>, _CharT>;
|
|
|
|
template <_Format_supported_charT _CharT, class... _Types>
|
|
struct formatter<tuple<_Types...>, _CharT>;
|
|
|
|
template <_Format_supported_charT _CharT>
|
|
constexpr bool enable_nonlocking_formatter_optimization<_CharT> = true;
|
|
|
|
template <_Format_supported_charT _CharT>
|
|
constexpr bool enable_nonlocking_formatter_optimization<_CharT*> = true;
|
|
|
|
template <_Format_supported_charT _CharT>
|
|
constexpr bool enable_nonlocking_formatter_optimization<const _CharT*> = true;
|
|
|
|
template <_Format_supported_charT _CharT, size_t _Nx>
|
|
constexpr bool enable_nonlocking_formatter_optimization<_CharT[_Nx]> = true;
|
|
|
|
template <_Format_supported_charT _CharT, class _Traits, class _Allocator>
|
|
constexpr bool enable_nonlocking_formatter_optimization<basic_string<_CharT, _Traits, _Allocator>> = true;
|
|
|
|
template <_Format_supported_charT _CharT, class _Traits>
|
|
constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<_CharT, _Traits>> = true;
|
|
|
|
template <class _Ty1, class _Ty2>
|
|
constexpr bool enable_nonlocking_formatter_optimization<pair<_Ty1, _Ty2>> =
|
|
enable_nonlocking_formatter_optimization<_Ty1> && enable_nonlocking_formatter_optimization<_Ty2>;
|
|
|
|
template <class... _Ts>
|
|
constexpr bool enable_nonlocking_formatter_optimization<tuple<_Ts...>> =
|
|
(enable_nonlocking_formatter_optimization<_Ts> && ...);
|
|
|
|
template <class _CharT>
|
|
struct _Fill_align_and_width_specs {
|
|
int _Width = -1;
|
|
int _Dynamic_width_index = -1;
|
|
_Fmt_align _Alignment = _Fmt_align::_None;
|
|
uint8_t _Fill_length = 1;
|
|
// At most one codepoint (so one char32_t or four utf-8 char8_t).
|
|
_CharT _Fill[4 / sizeof(_CharT)]{' '};
|
|
};
|
|
|
|
// TRANSITION, VSO-1236041: Avoid declaring and defining member functions in different headers.
|
|
template <class _CharT, class _Pc>
|
|
_NODISCARD constexpr _Pc::iterator _Fill_align_and_width_formatter_parse(
|
|
_Fill_align_and_width_specs<_CharT>& _Specs, _Pc& _Parse_ctx);
|
|
|
|
template <class _CharT, class _FormatContext, class _Func>
|
|
_NODISCARD _FormatContext::iterator _Fill_align_and_width_formatter_format(
|
|
const _Fill_align_and_width_specs<_CharT>& _Specs, _FormatContext& _Format_ctx, int _Width,
|
|
_Fmt_align _Default_align, _Func&& _Fn);
|
|
|
|
template <class _CharT>
|
|
struct _Fill_align_and_width_formatter {
|
|
public:
|
|
template <class _ParseContext = basic_format_parse_context<_CharT>> // improves throughput, see GH-5003
|
|
_NODISCARD constexpr _ParseContext::iterator _Parse(type_identity_t<_ParseContext&> _Parse_ctx) {
|
|
return _STD _Fill_align_and_width_formatter_parse(_Specs, _Parse_ctx);
|
|
}
|
|
|
|
template <class _FormatContext, class _Func>
|
|
_NODISCARD constexpr auto _Format(
|
|
_FormatContext& _Format_ctx, const int _Width, _Fmt_align _Default_align, _Func&& _Fn) const {
|
|
return _STD _Fill_align_and_width_formatter_format(
|
|
_Specs, _Format_ctx, _Width, _Default_align, _STD forward<_Func>(_Fn));
|
|
}
|
|
|
|
private:
|
|
_Fill_align_and_width_specs<_CharT> _Specs;
|
|
};
|
|
#endif // _HAS_CXX23
|
|
_STD_END
|
|
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // __MSVC_FORMATTER_HPP
|