Implement `formatter<vector<bool>::reference>` (#4133)

Co-authored-by: Casey Carter <cacarter@microsoft.com>
Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
Co-authored-by: Jakub Mazurkiewicz <mazkuba3@gmail.com>
This commit is contained in:
A. Jiang 2023-11-30 04:29:21 +08:00 коммит произвёл GitHub
Родитель 730af178f7
Коммит 8234695bd7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 515 добавлений и 275 удалений

Просмотреть файл

@ -12,6 +12,7 @@ set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_cxx_stdatomic.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_filebuf.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_format_ucd_tables.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_formatter.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_int128.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_iter_core.hpp
${CMAKE_CURRENT_LIST_DIR}/inc/__msvc_print.hpp

Просмотреть файл

@ -0,0 +1,277 @@
// __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 || !defined(__cpp_lib_concepts) // TRANSITION, GH-395
#error The contents of <format> are only available with C++20. (Also, you should not include this internal header.)
#endif // !_HAS_CXX20 || !defined(__cpp_lib_concepts)
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <type_traits>
#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
_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;
};
_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>;
// Generic formatter definition, the deleted default constructor
// makes it "disabled" as per N4950 [format.formatter.spec]/5
_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
#define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \
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
// 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
};
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // __MSVC_FORMATTER_HPP

Просмотреть файл

@ -5812,7 +5812,8 @@ private:
_CHRONO _Chrono_formatter<_CharT> _Impl;
};
// Per LWG-3997, the _CharT template parameter is constrained to supported character types.
// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is
// constrained to character types supported by `format`.
template <class _Rep, class _Period, _Format_supported_charT _CharT>
struct formatter<_CHRONO duration<_Rep, _Period>, _CharT>

Просмотреть файл

@ -43,6 +43,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of <format> are available only with C++
#else // ^^^ !defined(__cpp_lib_concepts) / defined(__cpp_lib_concepts) vvv
#include <__msvc_format_ucd_tables.hpp>
#include <__msvc_formatter.hpp>
#include <__msvc_print.hpp>
#include <bit>
#include <charconv>
@ -67,15 +68,6 @@ _STL_DISABLE_CLANG_WARNINGS
extern "C" _NODISCARD __std_win_error __stdcall __std_get_cvt(__std_code_page _Codepage, _Cvtvec* _Pcvt) noexcept;
_STD_BEGIN
#if _HAS_CXX23
#define _FMT_P2286_BEGIN inline namespace __p2286 {
#define _FMT_P2286_END }
#else // ^^^ C++23 / C++20 vvv
#define _FMT_P2286_BEGIN
#define _FMT_P2286_END
#endif // ^^^ C++20 ^^^
template <class _CharT>
_NODISCARD constexpr const _CharT* _Choose_literal(const char* const _Str, const wchar_t* const _WStr) noexcept {
if constexpr (is_same_v<_CharT, char>) {
@ -100,28 +92,6 @@ _EXPORT_STD class format_error : public runtime_error {
_THROW(format_error{_Message});
}
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");
_NODISCARD constexpr bool _Is_integral_fmt_type(_Basic_format_arg_type _Ty) {
return _Ty > _Basic_format_arg_type::_None && _Ty <= _Basic_format_arg_type::_Char_type;
}
@ -130,13 +100,6 @@ _NODISCARD constexpr bool _Is_arithmetic_fmt_type(_Basic_format_arg_type _Ty) {
return _Ty > _Basic_format_arg_type::_None && _Ty <= _Basic_format_arg_type::_Long_double_type;
}
#if _HAS_CXX23
_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
struct _Auto_id_tag {
explicit _Auto_id_tag() = default;
};
@ -571,12 +534,6 @@ public:
template <class _Ty, class _CharT>
concept _CharT_or_bool = same_as<_Ty, _CharT> || same_as<_Ty, bool>;
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;
inline void _You_see_this_error_because_arg_id_is_out_of_range() noexcept {}
inline void _Invalid_arg_type_for_dynamic_width_or_precision() noexcept {}
@ -710,7 +667,7 @@ struct _Format_arg_traits {
// Function template _Type_eraser mirrors the type dispatching mechanism in the construction of basic_format_arg
// (N4950 [format.arg]). They determine the mapping from "raw" to "erased" argument type for _Format_arg_store.
template <_Formattable_with<_Context> _Ty>
template <class _Ty>
static auto _Type_eraser();
template <class _Ty>
@ -877,7 +834,7 @@ private:
};
template <class _Context>
template <_Formattable_with<_Context> _Ty>
template <class _Ty>
auto _Format_arg_traits<_Context>::_Type_eraser() {
using _Td = remove_const_t<_Ty>;
// See N4950 [format.arg]/6
@ -1593,30 +1550,6 @@ constexpr void _Parse_format_string(basic_string_view<_CharT> _Format_str, _Hand
}
}
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;
};
// Model of _Parse_spec_callbacks that fills a _Basic_format_specs with the parsed data.
template <class _CharT>
class _Specs_setter {
@ -2281,14 +2214,9 @@ public:
#if _HAS_CXX23
template <class _CharT>
struct _Phony_fmt_iter_for {
using iterator_category = output_iterator_tag;
using value_type = _CharT;
using difference_type = ptrdiff_t;
using pointer = _CharT*;
using reference = _CharT&;
using difference_type = ptrdiff_t;
reference operator*() const;
pointer operator->() const;
_CharT& operator*() const;
_Phony_fmt_iter_for& operator++();
_Phony_fmt_iter_for operator++(int);
@ -2508,7 +2436,7 @@ struct _Invalid_format_kind {
};
_EXPORT_STD template <class _Ty>
constexpr _Invalid_format_kind<_Ty> format_kind{};
inline constexpr _Invalid_format_kind<_Ty> format_kind;
template <class _Ty>
inline constexpr bool _Is_two_tuple = false;
@ -2521,7 +2449,7 @@ inline 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 {
inline 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;
@ -3692,159 +3620,38 @@ struct _Format_handler {
return _First;
}
};
template <_Basic_format_arg_type _ArgType, class _CharT, class _Pc>
constexpr _Pc::iterator _Formatter_base_parse(_Dynamic_format_specs<_CharT>& _Specs, _Pc& _ParseCtx) {
_Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler(_Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType);
const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler);
if (_It != _ParseCtx._Unchecked_end() && *_It != '}') {
_Throw_format_error("Missing '}' in format string.");
}
return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin());
}
template <class _Ty, class _CharT, class _FormatContext>
_FormatContext::iterator _Formatter_base_format(
const _Dynamic_format_specs<_CharT>& _Specs, const _Ty& _Val, _FormatContext& _FormatCtx) {
_Dynamic_format_specs<_CharT> _Format_specs = _Specs;
if (_Specs._Dynamic_width_index >= 0) {
_Format_specs._Width =
_Get_dynamic_specs<_Width_checker>(_FormatCtx.arg(static_cast<size_t>(_Specs._Dynamic_width_index)));
}
if (_Specs._Dynamic_precision_index >= 0) {
_Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>(
_FormatCtx.arg(static_cast<size_t>(_Specs._Dynamic_precision_index)));
}
return _STD visit_format_arg(
_Arg_formatter<typename _FormatContext::iterator, _CharT>{
._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)},
basic_format_arg<_FormatContext>::_Make_from(_Val));
}
_FMT_P2286_END
// Generic formatter definition, the deleted default constructor
// makes it "disabled" as per N4950 [format.formatter.spec]/5
_EXPORT_STD template <class _Ty, class _CharT>
struct formatter {
formatter() = delete;
formatter(const formatter&) = delete;
formatter operator=(const formatter&) = delete;
};
_FMT_P2286_BEGIN
template <class _Ty, class _CharT, _Basic_format_arg_type _ArgType>
struct _Formatter_base {
private:
using _Pc = basic_format_parse_context<_CharT>;
public:
#if _HAS_CXX23
constexpr void _Set_debug_format() noexcept
requires (_Is_debug_enabled_fmt_type(_ArgType))
{
_Specs._Type = '?';
}
#endif // _HAS_CXX23
constexpr _Pc::iterator parse(_Pc& _ParseCtx) {
_Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler(_Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType);
const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler);
if (_It != _ParseCtx._Unchecked_end() && *_It != '}') {
_Throw_format_error("Missing '}' in format string.");
}
return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin());
}
template <class _FormatContext>
_FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const {
_Dynamic_format_specs<_CharT> _Format_specs = _Specs;
if (_Specs._Dynamic_width_index >= 0) {
_Format_specs._Width =
_Get_dynamic_specs<_Width_checker>(_FormatCtx.arg(static_cast<size_t>(_Specs._Dynamic_width_index)));
}
if (_Specs._Dynamic_precision_index >= 0) {
_Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>(
_FormatCtx.arg(static_cast<size_t>(_Specs._Dynamic_precision_index)));
}
return _STD visit_format_arg(
_Arg_formatter<typename _FormatContext::iterator, _CharT>{
._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)},
basic_format_arg<_FormatContext>::_Make_from(_Val));
}
private:
_Dynamic_format_specs<_CharT> _Specs;
};
_FMT_P2286_END
#define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \
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
// 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
};
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
};
_EXPORT_STD template <class _CharT, class... _Args>
struct basic_format_string {
public:
@ -4225,7 +4032,7 @@ _NODISCARD constexpr const _CharT* _Parse_fill_align_and_width_specs(
template <class _CharT>
struct _Fill_align_and_width_formatter {
public:
_NODISCARD constexpr auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
_NODISCARD constexpr auto _Parse(basic_format_parse_context<_CharT>& _Parse_ctx) {
_Fill_align_and_width_specs_setter<_CharT> _Callback{_Specs, _Parse_ctx};
const auto _It =
_Parse_fill_align_and_width_specs(_Parse_ctx._Unchecked_begin(), _Parse_ctx._Unchecked_end(), _Callback);
@ -4252,10 +4059,6 @@ private:
_Fill_align_and_width_specs<_CharT> _Specs;
};
#endif // _HAS_CXX23
#undef _FMT_P2286_END
#undef _FMT_P2286_BEGIN
_STD_END
#pragma pop_macro("new")

Просмотреть файл

@ -10,6 +10,7 @@
"__msvc_cxx_stdatomic.hpp",
"__msvc_filebuf.hpp",
"__msvc_format_ucd_tables.hpp",
"__msvc_formatter.hpp",
"__msvc_int128.hpp",
"__msvc_iter_core.hpp",
"__msvc_print.hpp",

Просмотреть файл

@ -13,11 +13,14 @@ _EMIT_STL_WARNING(STL4038, "The contents of <stacktrace> are available only with
#else // ^^^ !_HAS_CXX23 / _HAS_CXX23 vvv
#include <cstdint>
#include <format>
#include <string>
#include <type_traits>
#include <vector>
#ifdef __cpp_lib_concepts
#include <format>
#endif // __cpp_lib_concepts
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
@ -353,7 +356,7 @@ ostream& operator<<(ostream& _Os, const basic_stacktrace<_Alloc>& _St) {
template <>
struct formatter<stacktrace_entry> {
constexpr format_parse_context::iterator parse(format_parse_context& _Parse_ctx) {
return _Impl.parse(_Parse_ctx);
return _Impl._Parse(_Parse_ctx);
}
template <class _FormatContext>

Просмотреть файл

@ -437,38 +437,6 @@ _EXPORT_STD _NODISCARD inline long double stold(const wstring& _Str, size_t* _Id
return _Ans;
}
template <class _Elem, class _UTy>
_NODISCARD _Elem* _UIntegral_to_buff(_Elem* _RNext, _UTy _UVal) {
// format _UVal into buffer *ending at* _RNext
static_assert(is_unsigned_v<_UTy>, "_UTy must be unsigned");
#ifdef _WIN64
auto _UVal_trunc = _UVal;
#else // ^^^ defined(_WIN64) / !defined(_WIN64) vvv
constexpr bool _Big_uty = sizeof(_UTy) > 4;
if constexpr (_Big_uty) { // For 64-bit numbers, work in chunks to avoid 64-bit divisions.
while (_UVal > 0xFFFFFFFFU) {
auto _UVal_chunk = static_cast<unsigned long>(_UVal % 1000000000);
_UVal /= 1000000000;
for (int _Idx = 0; _Idx != 9; ++_Idx) {
*--_RNext = static_cast<_Elem>('0' + _UVal_chunk % 10);
_UVal_chunk /= 10;
}
}
}
auto _UVal_trunc = static_cast<unsigned long>(_UVal);
#endif // ^^^ !defined(_WIN64) ^^^
do {
*--_RNext = static_cast<_Elem>('0' + _UVal_trunc % 10);
_UVal_trunc /= 10;
} while (_UVal_trunc != 0);
return _RNext;
}
template <class _Elem, class _Ty>
_NODISCARD basic_string<_Elem> _Integral_to_string(const _Ty _Val) {
// convert _Val to string

Просмотреть файл

@ -10,7 +10,6 @@
#include <__msvc_chrono.hpp>
#include <memory>
#include <process.h>
#include <string>
#include <tuple>
#include <xthreads.h>
@ -19,9 +18,9 @@
#include <stop_token>
#endif // _HAS_CXX20
#if _HAS_CXX23
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#include <format>
#endif // _HAS_CXX23
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
#ifdef _M_CEE_PURE
#error <thread> is not supported when compiling with /clr:pure.
@ -297,7 +296,8 @@ basic_ostream<_Ch, _Tr>& operator<<(basic_ostream<_Ch, _Tr>& _Str, thread::id _I
}
#if _HAS_CXX23 && defined(__cpp_lib_concepts)
// Per LWG-3997, the _CharT template parameter is constrained to supported character types.
// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is
// constrained to character types supported by `format`.
template <_Format_supported_charT _CharT>
struct formatter<thread::id, _CharT> {
private:
@ -305,7 +305,7 @@ private:
public:
constexpr _Pc::iterator parse(_Pc& _Parse_ctx) {
return _Impl.parse(_Parse_ctx);
return _Impl._Parse(_Parse_ctx);
}
template <class _FormatContext>

Просмотреть файл

@ -15,6 +15,10 @@
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
#include <__msvc_formatter.hpp>
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
@ -3585,6 +3589,26 @@ namespace pmr {
} // namespace pmr
#endif // _HAS_CXX17
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
template <class _Ty, class _CharT>
requires _Is_specialization_v<_Ty, _Vb_reference>
struct formatter<_Ty, _CharT> {
private:
formatter<bool, _CharT> _Underlying;
public:
template <class _ParseContext>
constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
return _Underlying.parse(_Ctx);
}
template <class _FormatContext>
_FormatContext::iterator format(const _Ty& _Ref, _FormatContext& _Ctx) const {
return _Underlying.format(_Ref, _Ctx);
}
};
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
template <class _Alloc, bool _RequiresMutable>
_INLINE_VAR constexpr bool _Is_vb_iterator<_Vb_iterator<_Alloc>, _RequiresMutable> = true;

Просмотреть файл

@ -2614,6 +2614,38 @@ struct _Is_transparent : bool_constant<_Is_transparent_v<_Ty>> {};
template <class _Ty>
concept _Transparent = _Is_transparent_v<_Ty>;
#endif // defined(__cpp_lib_concepts)
template <class _Elem, class _UTy>
_NODISCARD _Elem* _UIntegral_to_buff(_Elem* _RNext, _UTy _UVal) { // used by both to_string and thread::id output
// format _UVal into buffer *ending at* _RNext
static_assert(is_unsigned_v<_UTy>, "_UTy must be unsigned");
#ifdef _WIN64
auto _UVal_trunc = _UVal;
#else // ^^^ defined(_WIN64) / !defined(_WIN64) vvv
constexpr bool _Big_uty = sizeof(_UTy) > 4;
if constexpr (_Big_uty) { // For 64-bit numbers, work in chunks to avoid 64-bit divisions.
while (_UVal > 0xFFFFFFFFU) {
auto _UVal_chunk = static_cast<unsigned long>(_UVal % 1000000000);
_UVal /= 1000000000;
for (int _Idx = 0; _Idx != 9; ++_Idx) {
*--_RNext = static_cast<_Elem>('0' + _UVal_chunk % 10);
_UVal_chunk /= 10;
}
}
}
auto _UVal_trunc = static_cast<unsigned long>(_UVal);
#endif // ^^^ !defined(_WIN64) ^^^
do {
*--_RNext = static_cast<_Elem>('0' + _UVal_trunc % 10);
_UVal_trunc /= 10;
} while (_UVal_trunc != 0);
return _RNext;
}
_STD_END
#pragma pop_macro("new")

Просмотреть файл

@ -602,6 +602,7 @@ tests\P2286R8_text_formatting_escaping
tests\P2286R8_text_formatting_escaping_legacy_text_encoding
tests\P2286R8_text_formatting_escaping_utf8
tests\P2286R8_text_formatting_formattable
tests\P2286R8_text_formatting_vector_bool_reference
tests\P2302R4_ranges_alg_contains
tests\P2302R4_ranges_alg_contains_subrange
tests\P2321R2_proxy_reference

Просмотреть файл

@ -16,6 +16,7 @@
#include <array>
#include <chrono>
#include <concepts>
#include <cstddef>
#include <deque>
#include <format>
#include <forward_list>
@ -52,6 +53,28 @@ concept encoded_character_type = same_as<CharT, char>
#endif // defined(__cpp_char8_t)
|| same_as<CharT, char16_t> || same_as<CharT, char32_t> || same_as<CharT, wchar_t>;
template <class T>
struct alternative_allocator {
using value_type = T;
alternative_allocator() = default;
template <class U>
constexpr alternative_allocator(const alternative_allocator<U>&) noexcept {}
T* allocate(size_t n) {
return allocator<T>{}.allocate(n);
}
void deallocate(T* p, size_t n) {
allocator<T>{}.deallocate(p, n);
}
template <class U>
bool operator==(const alternative_allocator<U>&) const noexcept {
return true;
}
};
template <class T, class CharT>
void assert_is_not_formattable() {
static_assert(!formattable<T, CharT>);
@ -179,6 +202,22 @@ void test_P2693() {
}
}
template <class CharT, class Vector>
void test_P2286_vector_bool() {
assert_is_formattable<typename Vector::reference, CharT>();
// The const_reference shall be bool.
assert_is_formattable<typename Vector::const_reference, CharT>();
}
// Tests for P2286 Formatting ranges
template <class CharT>
void test_P2286() {
test_P2286_vector_bool<CharT, vector<bool>>();
test_P2286_vector_bool<CharT, pmr::vector<bool>>();
test_P2286_vector_bool<CharT, vector<bool, alternative_allocator<bool>>>();
}
// Tests volatile qualified objects are no longer formattable.
template <class CharT>
void test_LWG3631() {
@ -313,6 +352,7 @@ void test() {
test_P0645<CharT>();
test_P1361<CharT>();
test_P2693<CharT>();
test_P2286<CharT>();
test_LWG3631<CharT>();
test_abstract_class<CharT>();
test_disabled<CharT>();

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

Просмотреть файл

@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <cassert>
#include <cstddef>
#include <format>
#include <locale>
#include <memory>
#include <memory_resource>
#include <string>
#include <type_traits>
#include <vector>
#include <test_format_support.hpp>
using namespace std;
#define STR(Str) TYPED_LITERAL(CharT, Str)
template <class T>
struct alternative_allocator {
using value_type = T;
alternative_allocator() = default;
template <class U>
constexpr alternative_allocator(const alternative_allocator<U>&) noexcept {}
T* allocate(size_t n) {
return allocator<T>{}.allocate(n);
}
void deallocate(T* p, size_t n) {
allocator<T>{}.deallocate(p, n);
}
template <class U>
bool operator==(const alternative_allocator<U>&) const noexcept {
return true;
}
};
#ifdef _DEBUG
#define DEFAULT_IDL_SETTING 2
#else
#define DEFAULT_IDL_SETTING 0
#endif
#if !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
template <class CharT>
struct yes_no_punct : numpunct<CharT> {
basic_string<CharT> do_truename() const override {
return STR("yes");
}
basic_string<CharT> do_falsename() const override {
return STR("no");
}
};
#endif // !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
template <class CharT, class Alloc>
void test_formatting_vector_bool_reference() {
vector<bool, Alloc> vb{false, true};
assert(format(STR("{}, {}"), vb[0], vb[1]) == format(STR("{}, {}"), false, true));
assert(format(STR("{:}, {:}"), vb[0], vb[1]) == format(STR("{:}, {:}"), false, true));
assert(format(STR("{:d}, {:x}"), vb[0], vb[1]) == format(STR("{:d}, {:x}"), false, true));
#if !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
locale loc{locale::classic(), new yes_no_punct<CharT>};
assert(format(loc, STR("{:L}"), vb[1]) == STR("yes"));
assert(format(loc, STR("{:L}"), vb[0]) == STR("no"));
#endif // !defined(_DLL) || _ITERATOR_DEBUG_LEVEL == DEFAULT_IDL_SETTING
}
int main() {
test_formatting_vector_bool_reference<char, allocator<bool>>();
test_formatting_vector_bool_reference<char, pmr::polymorphic_allocator<bool>>();
test_formatting_vector_bool_reference<char, alternative_allocator<bool>>();
test_formatting_vector_bool_reference<wchar_t, allocator<bool>>();
test_formatting_vector_bool_reference<wchar_t, pmr::polymorphic_allocator<bool>>();
test_formatting_vector_bool_reference<wchar_t, alternative_allocator<bool>>();
}