[libc++][format] Add __format_arg_store.

This implements the struct `__format_arg_store` and its dependencies:
* the class basic_format_arg,
* the class basic_format_args,
* the class basic_format_context,
* the function make_format_args,
* the function wmake_format_args,
* the function visit_format_arg,
* several Standard required typedefs.

The following parts will be implemented in a later patch:

* the child class `basic_format_arg::handle`,
* the function `basic_format_arg::basic_format_arg(const T* p)`.

The following extension has been implemented:
* the class basic_format_arg supports `__[u]int128_t` on platform where libc++ supports 128 bit integrals.

Implements parts of:
* P0645 Text Formatting

Completes:
* LWG3371 visit_format_arg and make_format_args are not hidden friends
* LWG3542 basic_format_arg mishandles basic_string_view with custom traits

Note https://mordante.github.io/blog/2021/06/05/format.html gives a bit more information about the goals and non-goals of this initial patch series.

Reviewed By: #libc, ldionne, vitaut

Differential Revision: https://reviews.llvm.org/D103357
This commit is contained in:
Mark de Wever
2020-12-05 11:45:21 +01:00
parent c969349260
commit 0922ce56f4
35 changed files with 2587 additions and 12 deletions

View File

@@ -275,7 +275,7 @@
"`3364 <https://wg21.link/LWG3364>`__","Initialize data members of ranges and their iterators","Prague","",""
"`3367 <https://wg21.link/LWG3367>`__","Integer-class conversions should not throw","Prague","",""
"`3369 <https://wg21.link/LWG3369>`__","``span``\ 's deduction-guide for built-in arrays doesn't work","Prague","",""
"`3371 <https://wg21.link/LWG3371>`__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","",""
"`3371 <https://wg21.link/LWG3371>`__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","|Complete|","14.0"
"`3372 <https://wg21.link/LWG3372>`__","``vformat_to``\ should not try to deduce ``Out``\ twice","Prague","",""
"`3373 <https://wg21.link/LWG3373>`__","``{to,from}_chars_result``\ and ``format_to_n_result``\ need the ""we really mean what we say"" wording","Prague","",""
"`3374 <https://wg21.link/LWG3374>`__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0"
1 Issue # Issue Name Meeting Status First released version
275 `3364 <https://wg21.link/LWG3364>`__ Initialize data members of ranges and their iterators Prague
276 `3367 <https://wg21.link/LWG3367>`__ Integer-class conversions should not throw Prague
277 `3369 <https://wg21.link/LWG3369>`__ ``span``\ 's deduction-guide for built-in arrays doesn't work Prague
278 `3371 <https://wg21.link/LWG3371>`__ ``visit_format_arg``\ and ``make_format_args``\ are not hidden friends Prague |Complete| 14.0
279 `3372 <https://wg21.link/LWG3372>`__ ``vformat_to``\ should not try to deduce ``Out``\ twice Prague
280 `3373 <https://wg21.link/LWG3373>`__ ``{to,from}_chars_result``\ and ``format_to_n_result``\ need the "we really mean what we say" wording Prague
281 `3374 <https://wg21.link/LWG3374>`__ P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ Prague |Complete| 12.0

View File

@@ -39,10 +39,6 @@ Misc. Items and TODOs
(Please mark all Format-related TODO comments with the string ``TODO FMT``, so we
can find them easily.)
* C++23 may break the ABI with `P2216 <https://wg21.link/P2216>`_.
This ABI break may be backported to C++20. Therefore the library will not
be available on platforms where the ABI break is an issue.
Paper and Issue Status
======================

View File

@@ -128,7 +128,11 @@ set(files
__config
__debug
__errc
__format/format_arg.h
__format/format_args.h
__format/format_context.h
__format/format_error.h
__format/format_fwd.h
__format/format_parse_context.h
__function_like.h
__functional_base

View File

@@ -139,9 +139,9 @@
// # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_semaphore
// This controls the availability of the C++20 format library.
// The library is in development and not ABI stable yet. Currently
// P2216 is aiming to be retroactively accepted in C++20. This paper
// contains ABI breaking changes.
// The library is in development and not ABI stable yet. P2216 is
// retroactively accepted in C++20. This paper contains ABI breaking
// changes.
# define _LIBCPP_AVAILABILITY_FORMAT
// # define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format
@@ -238,9 +238,9 @@
# endif
// This controls the availability of the C++20 format library.
// The library is in development and not ABI stable yet. Currently
// P2216 is aiming to be retroactively accepted in C++20. This paper
// contains ABI breaking changes.
// The library is in development and not ABI stable yet. P2216 is
// retroactively accepted in C++20. This paper contains ABI breaking
// changes.
# define _LIBCPP_AVAILABILITY_FORMAT \
__attribute__((unavailable))
# define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format

View File

@@ -0,0 +1,256 @@
// -*- 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 <__config>
#include <__format/format_error.h>
#include <__format/format_fwd.h>
#include <__functional_base>
#include <__variant/monostate.h>
#include <concepts>
#include <string>
#include <string_view>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
namespace __format {
/** The type stored in @ref basic_format_arg. */
enum class _LIBCPP_ENUM_VIS __arg_t : uint8_t {
__none,
__bool,
__char_type,
__int,
__long_long,
#ifndef _LIBCPP_HAS_NO_INT128
__i128,
#endif
__unsigned,
__unsigned_long_long,
#ifndef _LIBCPP_HAS_NO_INT128
__u128,
#endif
__float,
__double,
__long_double,
__const_char_type_ptr,
__string_view,
__ptr
};
} // namespace __format
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT 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), monostate{});
case __format::__arg_t::__bool:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__bool);
case __format::__arg_t::__char_type:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__char_type);
case __format::__arg_t::__int:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__int);
case __format::__arg_t::__long_long:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_long);
#ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__i128);
#endif
case __format::__arg_t::__unsigned:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__unsigned);
case __format::__arg_t::__unsigned_long_long:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis),
__arg.__unsigned_long_long);
#ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__u128:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__u128);
#endif
case __format::__arg_t::__float:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__float);
case __format::__arg_t::__double:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__double);
case __format::__arg_t::__long_double:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__long_double);
case __format::__arg_t::__const_char_type_ptr:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis),
__arg.__const_char_type_ptr);
case __format::__arg_t::__string_view:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__string_view);
case __format::__arg_t::__ptr:
return _VSTD::invoke(_VSTD::forward<_Visitor>(__vis), __arg.__ptr);
}
_LIBCPP_UNREACHABLE();
}
template <class _Context>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg {
public:
// TODO FMT Define the handle class.
class 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.
template <class _Ctx, class... _Args>
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_FORMAT friend __format_arg_store<_Ctx, _Args...>
_VSTD::make_format_args(const _Args&...);
template <class _Visitor, class _Ctx>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT friend decltype(auto)
_VSTD::visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg);
union {
bool __bool;
char_type __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 char_type* __const_char_type_ptr;
basic_string_view<char_type> __string_view;
const void* __ptr;
// TODO FMT Add the handle.
};
__format::__arg_t __type_;
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(bool __v) noexcept
: __bool(__v), __type_(__format::__arg_t::__bool) {}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(_Tp __v) noexcept
requires(same_as<_Tp, char_type> ||
(same_as<_Tp, char> && same_as<char_type, wchar_t>))
: __char_type(__v), __type_(__format::__arg_t::__char_type) {}
template <__libcpp_signed_integer _Tp>
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(_Tp __v) noexcept {
if constexpr (sizeof(_Tp) <= sizeof(int)) {
__int = static_cast<int>(__v);
__type_ = __format::__arg_t::__int;
} else if constexpr (sizeof(_Tp) <= sizeof(long long)) {
__long_long = static_cast<long long>(__v);
__type_ = __format::__arg_t::__long_long;
}
#ifndef _LIBCPP_HAS_NO_INT128
else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) {
__i128 = __v;
__type_ = __format::__arg_t::__i128;
}
#endif
else
static_assert(sizeof(_Tp) == 0, "An unsupported signed integer was used");
}
template <__libcpp_unsigned_integer _Tp>
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(_Tp __v) noexcept {
if constexpr (sizeof(_Tp) <= sizeof(unsigned)) {
__unsigned = static_cast<unsigned>(__v);
__type_ = __format::__arg_t::__unsigned;
} else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) {
__unsigned_long_long = static_cast<unsigned long long>(__v);
__type_ = __format::__arg_t::__unsigned_long_long;
}
#ifndef _LIBCPP_HAS_NO_INT128
else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) {
__u128 = __v;
__type_ = __format::__arg_t::__u128;
}
#endif
else
static_assert(sizeof(_Tp) == 0,
"An unsupported unsigned integer was used");
}
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(float __v) noexcept
: __float(__v), __type_(__format::__arg_t::__float) {}
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(double __v) noexcept
: __double(__v), __type_(__format::__arg_t::__double) {}
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(long double __v) noexcept
: __long_double(__v), __type_(__format::__arg_t::__long_double) {}
// Note not a 'noexcept' function.
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(const char_type* __s)
: __const_char_type_ptr(__s),
__type_(__format::__arg_t::__const_char_type_ptr) {
_LIBCPP_ASSERT(__s, "Used a nullptr argument to initialize a C-string");
}
template <class _Traits>
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(
basic_string_view<char_type, _Traits> __s) noexcept
: __string_view{__s.data(), __s.size()},
__type_(__format::__arg_t::__string_view) {}
template <class _Traits, class _Allocator>
_LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(
const basic_string<char_type, _Traits, _Allocator>& __s) noexcept
: __string_view{__s.data(), __s.size()},
__type_(__format::__arg_t::__string_view) {}
_LIBCPP_HIDE_FROM_ABI
explicit basic_format_arg(nullptr_t) noexcept
: __ptr(nullptr), __type_(__format::__arg_t::__ptr) {}
// TODO FMT Implement the _Tp* constructor.
};
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_ARG_H

View 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_FORMAT_ARGS_H
#define _LIBCPP___FORMAT_FORMAT_ARGS_H
#include <__availability>
#include <__config>
#include <__format/format_fwd.h>
#include <cstddef>
#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 > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
template <class _Context>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_args {
public:
// TODO FMT Implement [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]
// Note: Change __format_arg_store to use a built-in array.
_LIBCPP_HIDE_FROM_ABI 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)), __data_(__store.__args.data()) {}
_LIBCPP_HIDE_FROM_ABI
basic_format_arg<_Context> get(size_t __id) const noexcept {
return __id < __size_ ? __data_[__id] : basic_format_arg<_Context>{};
}
_LIBCPP_HIDE_FROM_ABI size_t __size() const noexcept { return __size_; }
private:
size_t __size_{0};
const basic_format_arg<_Context>* __data_{nullptr};
};
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_ARGS_H

View File

@@ -0,0 +1,160 @@
// -*- 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 <__config>
#include <__format/format_args.h>
#include <__format/format_fwd.h>
#include <__iterator/concepts.h>
#include <concepts>
#include <iterator>
#include <string>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
#include <locale>
#include <optional>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
template <class _OutIt, class _CharT>
requires output_iterator<_OutIt, const _CharT&>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT 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
template <class _OutIt, class _CharT>
requires output_iterator<_OutIt, const _CharT&>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_context {
public:
using iterator = _OutIt;
using char_type = _CharT;
template <class _Tp>
using formatter_type = formatter<_Tp, _CharT>;
basic_format_context(const basic_format_context&) = delete;
basic_format_context& operator=(const basic_format_context&) = delete;
_LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context>
arg(size_t __id) const {
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 __out_it_; }
_LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = __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>
_VSTD::__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>
_VSTD::__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
};
// TODO FMT Implement [format.context]/4
// [Note 1: For a given type charT, implementations are encouraged to provide a
// single instantiation of basic_format_context for appending to
// basic_string<charT>, vector<charT>, or any other container with contiguous
// storage by wrapping those in temporary objects with a uniform interface
// (such as a span<charT>) and polymorphic reallocation. - end note]
using format_context = basic_format_context<back_insert_iterator<string>, char>;
using wformat_context =
basic_format_context<back_insert_iterator<wstring>, wchar_t>;
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H

View File

@@ -0,0 +1,56 @@
// -*- 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>
#include <__utility/forward.h>
#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 > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
template <class _Context>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT basic_format_arg;
template <class _Context, class... _Args>
struct _LIBCPP_TEMPLATE_VIS __format_arg_store;
template <class _Ctx, class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Ctx, _Args...>
make_format_args(const _Args&...);
template <class _Tp, class _CharT = char>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter;
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FORMAT_FORMAT_FWD_H

View File

@@ -152,10 +152,28 @@ namespace std {
#include <__concepts/swappable.h>
#include <__concepts/totally_ordered.h>
#include <__config>
#include <type_traits>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
// Concept helpers for the internal type traits for the fundamental types.
template <class _Tp>
concept __libcpp_unsigned_integer = __libcpp_is_unsigned_integer<_Tp>::value;
template <class _Tp>
concept __libcpp_signed_integer = __libcpp_is_signed_integer<_Tp>::value;
template <class _Tp>
concept __libcpp_floating_point = __libcpp_is_floating_point<_Tp>::value;
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_CONCEPTS

View File

@@ -13,6 +13,136 @@
/*
namespace std {
// [format.context], class template basic_format_context
template<class Out, class charT>
class basic_format_context {
basic_format_args<basic_format_context> args_; // exposition only
Out out_; // exposition only
public:
using iterator = Out;
using char_type = charT;
template<class T> using formatter_type = formatter<T, charT>;
basic_format_arg<basic_format_context> arg(size_t id) const;
std::locale locale();
iterator out();
void advance_to(iterator it);
};
using format_context = basic_format_context<unspecified, char>;
using wformat_context = basic_format_context<unspecified, wchar_t>;
// [format.args], class template basic_format_args
template<class Context>
class basic_format_args {
size_t size_; // exposition only
const basic_format_arg<Context>* data_; // exposition only
public:
basic_format_args() noexcept;
template<class... Args>
basic_format_args(const format-arg-store<Context, Args...>& store) noexcept;
basic_format_arg<Context> get(size_t i) const noexcept;
};
using format_args = basic_format_args<format_context>;
using wformat_args = basic_format_args<wformat_context>;
template<class Out, class charT>
using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
// [format.parse.ctx], class template basic_format_parse_context
template<class charT>
class basic_format_parse_context {
public:
using char_type = charT;
using const_iterator = typename basic_string_view<charT>::const_iterator;
using iterator = const_iterator;
private:
iterator begin_; // exposition only
iterator end_; // exposition only
enum indexing { unknown, manual, automatic }; // exposition only
indexing indexing_; // exposition only
size_t next_arg_id_; // exposition only
size_t num_args_; // exposition only
public:
constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
size_t num_args = 0) noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr void advance_to(const_iterator it);
constexpr size_t next_arg_id();
constexpr void check_arg_id(size_t id);
};
using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
// [format.arguments], arguments
// [format.arg], class template basic_format_arg
template<class Context>
class basic_format_arg {
public:
class handle;
private:
using char_type = typename Context::char_type; // exposition only
variant<monostate, bool, char_type,
int, unsigned int, long long int, unsigned long long int,
float, double, long double,
const char_type*, basic_string_view<char_type>,
const void*, handle> value; // exposition only
template<class T> explicit basic_format_arg(const T& v) noexcept; // exposition only
explicit basic_format_arg(float n) noexcept; // exposition only
explicit basic_format_arg(double n) noexcept; // exposition only
explicit basic_format_arg(long double n) noexcept; // exposition only
explicit basic_format_arg(const char_type* s); // exposition only
template<class traits>
explicit basic_format_arg(
basic_string_view<char_type, traits> s) noexcept; // exposition only
template<class traits, class Allocator>
explicit basic_format_arg(
const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
explicit basic_format_arg(nullptr_t) noexcept; // exposition only
template<class T>
explicit basic_format_arg(const T* p) noexcept; // exposition only
public:
basic_format_arg() noexcept;
explicit operator bool() const noexcept;
};
template<class Visitor, class Context>
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
// [format.arg.store], class template format-arg-store
template<class Context, class... Args>
struct format-arg-store { // exposition only
array<basic_format_arg<Context>, sizeof...(Args)> args;
};
template<class Context = format_context, class... Args>
format-arg-store<Context, Args...>
make_format_args(const Args&... args);
template<class... Args>
format-arg-store<wformat_context, Args...>
make_wformat_args(const Args&... args);
// [format.error], class format_error
class format_error : public runtime_error {
public:
@@ -61,13 +191,61 @@ namespace std {
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#include <__config>
#include <__format/format_arg.h>
#include <__format/format_args.h>
#include <__format/format_context.h>
#include <__format/format_error.h>
#include <__format/format_parse_context.h>
#include <array>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17
// TODO FMT Remove this once we require compilers with proper C++20 support.
// If the compiler has no concepts support, the format header will be disabled.
// Without concepts support enable_if needs to be used and that too much effort
// to support compilers with partial C++20 support.
#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
// 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>;
using wformat_args = basic_format_args<wformat_context>;
template <class _OutIt, class _CharT>
using format_args_t = basic_format_args<basic_format_context<_OutIt, _CharT>>;
template <class _Context, class... _Args>
struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
// TODO FMT Use a built-in array.
array<basic_format_arg<_Context>, sizeof...(_Args)> __args;
};
template <class _Context = format_context, class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...>
make_format_args(const _Args&... __args) {
return {basic_format_arg<_Context>(__args)...};
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
make_wformat_args(const _Args&... __args) {
return _VSTD::make_format_args<wformat_context>(__args...);
}
#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
#endif //_LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#endif // _LIBCPP_FORMAT

View File

@@ -431,7 +431,15 @@ module std [system] {
export *
module __format {
module format_arg { private header "__format/format_arg.h" }
module format_args { private header "__format/format_args.h" }
module format_context {
private header "__format/format_context.h"
export optional
export locale
}
module format_error { private header "__format/format_error.h" }
module format_fwd { private header "__format/format_fwd.h" }
module format_parse_context { private header "__format/format_parse_context.h" }
}
}

View File

@@ -790,6 +790,7 @@ _LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool is_integral_v
#endif // __has_keyword(__is_integral)
// __libcpp_is_signed_integer, __libcpp_is_unsigned_integer
// <concepts> implements __libcpp_signed_integer, __libcpp_unsigned_integer
// [basic.fundamental] defines five standard signed integer types;
// __int128_t is an extended signed integer type.
@@ -817,6 +818,7 @@ template <> struct __libcpp_is_unsigned_integer<__uint128_t> : public tru
#endif
// is_floating_point
// <concepts> implements __libcpp_floating_point
template <class _Tp> struct __libcpp_is_floating_point : public false_type {};
template <> struct __libcpp_is_floating_point<float> : public true_type {};

View File

@@ -0,0 +1,16 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: modules-build
// WARNING: This test was generated by 'generate_private_header_tests.py'
// and should not be edited manually.
// expected-error@*:* {{use of private header from outside its module: '__format/format_arg.h'}}
#include <__format/format_arg.h>

View File

@@ -0,0 +1,16 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: modules-build
// WARNING: This test was generated by 'generate_private_header_tests.py'
// and should not be edited manually.
// expected-error@*:* {{use of private header from outside its module: '__format/format_args.h'}}
#include <__format/format_args.h>

View File

@@ -0,0 +1,16 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: modules-build
// WARNING: This test was generated by 'generate_private_header_tests.py'
// and should not be edited manually.
// expected-error@*:* {{use of private header from outside its module: '__format/format_context.h'}}
#include <__format/format_context.h>

View File

@@ -0,0 +1,16 @@
// -*- 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: modules-build
// WARNING: This test was generated by 'generate_private_header_tests.py'
// and should not be edited manually.
// expected-error@*:* {{use of private header from outside its module: '__format/format_fwd.h'}}
#include <__format/format_fwd.h>

View File

@@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// template<class Context, class... Args>
// struct format-arg-store { // exposition only
// array<basic_format_arg<Context>, sizeof...(Args)> args;
// };
//
// Note more testing is done in the unit test for:
// template<class Visitor, class Context>
// see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
#include <format>
#include <cassert>
#include <type_traits>
#include "test_macros.h"
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
{
auto store = std::make_format_args<Context>();
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store), std::__format_arg_store<Context>>);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store.__args),
std::array<std::basic_format_arg<Context>, 0>>);
LIBCPP_ASSERT(store.__args.size() == 0);
}
{
auto store = std::make_format_args<Context>(1);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store), std::__format_arg_store<Context, int>>);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store.__args),
std::array<std::basic_format_arg<Context>, 1>>);
LIBCPP_ASSERT(store.__args.size() == 1);
}
{
auto store = std::make_format_args<Context>(1, 'c');
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store),
std::__format_arg_store<Context, int, char>>);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store.__args),
std::array<std::basic_format_arg<Context>, 2>>);
LIBCPP_ASSERT(store.__args.size() == 2);
}
{
auto store = std::make_format_args<Context>(1, 'c', nullptr);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store),
std::__format_arg_store<Context, int, char, nullptr_t>>);
LIBCPP_STATIC_ASSERT(
std::is_same_v<decltype(store.__args),
std::array<std::basic_format_arg<Context>, 3>>);
LIBCPP_ASSERT(store.__args.size() == 3);
}
}
void test() {
test<char>();
test<wchar_t>();
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// TODO FMT Evaluate gcc-11 status
// UNSUPPORTED: gcc-11
// <format>
// template<class Context = format_context, class... Args>
// format-arg-store<Context, Args...> make_format_args(const Args&... args);
#include <cassert>
#include <format>
#include <iterator>
#include <string>
#include "test_basic_format_arg.h"
#include "test_macros.h"
int main(int, char**) {
using Context = std::basic_format_context<
std::back_insert_iterator<std::basic_string<char>>, char>;
auto value = std::make_format_args(42, nullptr, false, 1.0);
LIBCPP_ASSERT(value.__args.size() == 4);
LIBCPP_ASSERT(test_basic_format_arg(value.__args[0], 42));
// Note [format.arg]/11 specifies a nullptr is stored as a const void*.
LIBCPP_ASSERT(test_basic_format_arg(value.__args[1],
static_cast<const void*>(nullptr)));
LIBCPP_ASSERT(test_basic_format_arg(value.__args[2], false));
LIBCPP_ASSERT(test_basic_format_arg(value.__args[3], 1.0));
return 0;
}

View File

@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// Validate it works regardless of the signedness of `char`.
// RUN: %{cxx} %{flags} %{compile_flags} -fsigned-char -fsyntax-only %s
// RUN: %{cxx} %{flags} %{compile_flags} -funsigned-char -fsyntax-only %s
// <format>
// [format.arg]/5.2
// - otherwise, if T is char and char_type is wchar_t, initializes value with static_cast<wchar_t>(v);
#include <format>
void test() {
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>('c');
}

View File

@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// TODO FMT Evaluate gcc-11 status
// UNSUPPORTED: gcc-11
// <format>
// template<class... Args>
// format-arg-store<wformat_context, Args...>
// make_wformat_args(const Args&... args);
#include <cassert>
#include <format>
#include "test_basic_format_arg.h"
#include "test_macros.h"
int main(int, char**) {
using Context = std::basic_format_context<
std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>;
auto value = std::make_wformat_args(42, nullptr, false, 1.0);
LIBCPP_ASSERT(value.__args.size() == 4);
LIBCPP_ASSERT(test_basic_format_arg(value.__args[0], 42));
// Note [format.arg]/11 specifies a nullptr is stored as a const void*.
LIBCPP_ASSERT(test_basic_format_arg(value.__args[1],
static_cast<const void*>(nullptr)));
LIBCPP_ASSERT(test_basic_format_arg(value.__args[2], false));
LIBCPP_ASSERT(test_basic_format_arg(value.__args[3], 1.0));
return 0;
}

View File

@@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// basic_format_arg() noexcept;
// The class has several exposition only private constructors. These are tested
// in visit_format_arg.pass.cpp
#include <format>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
ASSERT_NOEXCEPT(std::basic_format_arg<Context>{});
std::basic_format_arg<Context> format_arg{};
assert(!format_arg);
}
void test() {
test<char>();
test<wchar_t>();
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test<char8_t>();
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test<char16_t>();
test<char32_t>();
#endif
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// explicit operator bool() const noexcept
//
// Note more testing is done in the unit test for:
// template<class Visitor, class Context>
// see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
#include <format>
#include <cassert>
#include <type_traits>
#include "test_macros.h"
void test(const auto& store) {
for (const auto& arg : store.__args) {
assert(arg);
assert(static_cast<bool>(arg));
}
}
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
{
std::basic_format_arg<Context> format_arg{};
ASSERT_NOEXCEPT(!format_arg);
assert(!format_arg);
ASSERT_NOEXCEPT(static_cast<bool>(format_arg));
assert(!static_cast<bool>(format_arg));
}
test(std::make_format_args<Context>());
test(std::make_format_args<Context>(1));
test(std::make_format_args<Context>(1, 'c'));
test(std::make_format_args<Context>(1, 'c', nullptr));
}
void test() {
test<char>();
test<wchar_t>();
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,360 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// This test requires the dylib support introduced in D92214.
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
// <format>
// template<class Visitor, class Context>
// see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
#include <format>
#include <cassert>
#include <type_traits>
#include "constexpr_char_traits.h"
#include "test_macros.h"
#include "make_string.h"
#include "min_allocator.h"
template <class Context, class To, class From>
void test(From value) {
auto format_args = std::make_format_args<Context>(value);
assert(format_args.__args.size() == 1);
assert(format_args.__args[0]);
auto result = std::visit_format_arg(
[v = To(value)](auto a) -> To {
if constexpr (std::is_same_v<To, decltype(a)>) {
assert(v == a);
return a;
} else {
assert(false);
return {};
}
},
format_args.__args[0]);
using ct = std::common_type_t<From, To>;
assert(static_cast<ct>(result) == static_cast<ct>(value));
}
// Test specific for string and string_view.
//
// Since both result in a string_view there's no need to pass this as a
// template argument.
template <class Context, class From>
void test_string_view(From value) {
auto format_args = std::make_format_args<Context>(value);
assert(format_args.__args.size() == 1);
assert(format_args.__args[0]);
using CharT = typename Context::char_type;
using To = std::basic_string_view<CharT>;
using V = std::basic_string<CharT>;
auto result = std::visit_format_arg(
[v = V(value.begin(), value.end())](auto a) -> To {
if constexpr (std::is_same_v<To, decltype(a)>) {
assert(v == a);
return a;
} else {
assert(false);
return {};
}
},
format_args.__args[0]);
assert(std::equal(value.begin(), value.end(), result.begin(), result.end()));
}
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
std::basic_string<CharT> empty;
std::basic_string<CharT> str = MAKE_STRING(CharT, "abc");
// Test boolean types.
test<Context, bool>(true);
test<Context, bool>(false);
// Test CharT types.
test<Context, CharT, CharT>('a');
test<Context, CharT, CharT>('z');
test<Context, CharT, CharT>('0');
test<Context, CharT, CharT>('9');
// Test char types.
if (std::is_same_v<CharT, char>) {
// char to char -> char
test<Context, CharT, char>('a');
test<Context, CharT, char>('z');
test<Context, CharT, char>('0');
test<Context, CharT, char>('9');
} else {
if (std::is_same_v<CharT, wchar_t>) {
// char to wchar_t -> wchar_t
test<Context, wchar_t, char>('a');
test<Context, wchar_t, char>('z');
test<Context, wchar_t, char>('0');
test<Context, wchar_t, char>('9');
} else if (std::is_signed_v<char>) {
// char to CharT -> int
// This happens when CharT is a char8_t, char16_t, or char32_t and char
// is a signed type.
// Note if sizeof(CharT) > sizeof(int) this test fails. If there are
// platforms where that occurs extra tests need to be added for char32_t
// testing it against a long long.
test<Context, int, char>('a');
test<Context, int, char>('z');
test<Context, int, char>('0');
test<Context, int, char>('9');
} else {
// char to CharT -> unsigned
// This happens when CharT is a char8_t, char16_t, or char32_t and char
// is an unsigned type.
// Note if sizeof(CharT) > sizeof(unsigned) this test fails. If there are
// platforms where that occurs extra tests need to be added for char32_t
// testing it against an unsigned long long.
test<Context, unsigned, char>('a');
test<Context, unsigned, char>('z');
test<Context, unsigned, char>('0');
test<Context, unsigned, char>('9');
}
}
// Test signed integer types.
test<Context, int, signed char>(std::numeric_limits<signed char>::min());
test<Context, int, signed char>(0);
test<Context, int, signed char>(std::numeric_limits<signed char>::max());
test<Context, int, short>(std::numeric_limits<short>::min());
test<Context, int, short>(std::numeric_limits<signed char>::min());
test<Context, int, short>(0);
test<Context, int, short>(std::numeric_limits<signed char>::max());
test<Context, int, short>(std::numeric_limits<short>::max());
test<Context, int, int>(std::numeric_limits<int>::min());
test<Context, int, int>(std::numeric_limits<short>::min());
test<Context, int, int>(std::numeric_limits<signed char>::min());
test<Context, int, int>(0);
test<Context, int, int>(std::numeric_limits<signed char>::max());
test<Context, int, int>(std::numeric_limits<short>::max());
test<Context, int, int>(std::numeric_limits<int>::max());
using LongToType =
std::conditional_t<sizeof(long) == sizeof(int), int, long long>;
test<Context, LongToType, long>(std::numeric_limits<long>::min());
test<Context, LongToType, long>(std::numeric_limits<int>::min());
test<Context, LongToType, long>(std::numeric_limits<short>::min());
test<Context, LongToType, long>(std::numeric_limits<signed char>::min());
test<Context, LongToType, long>(0);
test<Context, LongToType, long>(std::numeric_limits<signed char>::max());
test<Context, LongToType, long>(std::numeric_limits<short>::max());
test<Context, LongToType, long>(std::numeric_limits<int>::max());
test<Context, LongToType, long>(std::numeric_limits<long>::max());
test<Context, long long, long long>(std::numeric_limits<long long>::min());
test<Context, long long, long long>(std::numeric_limits<long>::min());
test<Context, long long, long long>(std::numeric_limits<int>::min());
test<Context, long long, long long>(std::numeric_limits<short>::min());
test<Context, long long, long long>(std::numeric_limits<signed char>::min());
test<Context, long long, long long>(0);
test<Context, long long, long long>(std::numeric_limits<signed char>::max());
test<Context, long long, long long>(std::numeric_limits<short>::max());
test<Context, long long, long long>(std::numeric_limits<int>::max());
test<Context, long long, long long>(std::numeric_limits<long>::max());
test<Context, long long, long long>(std::numeric_limits<long long>::max());
#ifndef _LIBCPP_HAS_NO_INT128
test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::min());
test<Context, __int128_t, __int128_t>(
std::numeric_limits<signed char>::min());
test<Context, __int128_t, __int128_t>(0);
test<Context, __int128_t, __int128_t>(
std::numeric_limits<signed char>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::max());
#endif
// Test unsigned integer types.
test<Context, unsigned, unsigned char>(0);
test<Context, unsigned, unsigned char>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned short>(0);
test<Context, unsigned, unsigned short>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned short>(
std::numeric_limits<unsigned short>::max());
test<Context, unsigned, unsigned>(0);
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned short>::max());
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned>::max());
using UnsignedLongToType =
std::conditional_t<sizeof(unsigned long) == sizeof(unsigned), unsigned,
unsigned long long>;
test<Context, UnsignedLongToType, unsigned long>(0);
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned char>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned short>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned long>::max());
test<Context, unsigned long long, unsigned long long>(0);
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned short>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned long>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned long long>::max());
#ifndef _LIBCPP_HAS_NO_INT128
test<Context, __uint128_t, __uint128_t>(0);
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned char>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned short>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned int>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned long>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned long long>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<__uint128_t>::max());
#endif
// Test floating point types.
test<Context, float, float>(-std::numeric_limits<float>::max());
test<Context, float, float>(-std::numeric_limits<float>::min());
test<Context, float, float>(-0.0);
test<Context, float, float>(0.0);
test<Context, float, float>(std::numeric_limits<float>::min());
test<Context, float, float>(std::numeric_limits<float>::max());
test<Context, double, double>(-std::numeric_limits<double>::max());
test<Context, double, double>(-std::numeric_limits<double>::min());
test<Context, double, double>(-0.0);
test<Context, double, double>(0.0);
test<Context, double, double>(std::numeric_limits<double>::min());
test<Context, double, double>(std::numeric_limits<double>::max());
test<Context, long double, long double>(
-std::numeric_limits<long double>::max());
test<Context, long double, long double>(
-std::numeric_limits<long double>::min());
test<Context, long double, long double>(-0.0);
test<Context, long double, long double>(0.0);
test<Context, long double, long double>(
std::numeric_limits<long double>::min());
test<Context, long double, long double>(
std::numeric_limits<long double>::max());
// Test const CharT pointer types.
test<Context, const CharT*, const CharT*>(empty.c_str());
test<Context, const CharT*, const CharT*>(str.c_str());
// Test string_view types.
{
using From = std::basic_string_view<CharT>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
{
using From = std::basic_string_view<CharT, constexpr_char_traits<CharT>>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
// Test string types.
{
using From = std::basic_string<CharT>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
{
using From = std::basic_string<CharT, constexpr_char_traits<CharT>,
std::allocator<CharT>>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
{
using From =
std::basic_string<CharT, std::char_traits<CharT>, min_allocator<CharT>>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
{
using From = std::basic_string<CharT, constexpr_char_traits<CharT>,
min_allocator<CharT>>;
test_string_view<Context>(From());
test_string_view<Context>(From(empty.c_str()));
test_string_view<Context>(From(str.c_str()));
}
// Test pointer types.
test<Context, const void*>(nullptr);
}
void test() {
test<char>();
test<wchar_t>();
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// basic_format_args() noexcept;
// template<class... Args>
// basic_format_args(const format-arg-store<Context, Args...>& store) noexcept;
#include <format>
#include <cassert>
#include "test_macros.h"
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
{
ASSERT_NOEXCEPT(std::basic_format_args<Context>{});
std::basic_format_args<Context> format_args{};
assert(!format_args.get(0));
}
{
auto store = std::make_format_args<Context>(1);
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
assert(!format_args.get(1));
}
{
auto store = std::make_format_args<Context>(1, 'c');
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
assert(format_args.get(1));
assert(!format_args.get(2));
}
{
auto store = std::make_format_args<Context>(1, 'c', nullptr);
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
assert(format_args.get(1));
assert(format_args.get(2));
assert(!format_args.get(3));
}
}
void test() {
test<char>();
test<wchar_t>();
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,314 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// This test requires the dylib support introduced in D92214.
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
// <format>
// basic_format_arg<Context> get(size_t i) const noexcept;
#include <format>
#include <cassert>
#include <type_traits>
#include "test_macros.h"
#include "make_string.h"
template <class Context, class To, class From>
void test(From value) {
auto store = std::make_format_args<Context>(value);
const std::basic_format_args<Context> format_args{store};
std::visit_format_arg(
[v = To(value)](auto a) {
if constexpr (std::is_same_v<To, decltype(a)>)
assert(v == a);
else
assert(false);
},
format_args.get(0));
}
// Test specific for string and string_view.
//
// Since both result in a string_view there's no need to pass this as a
// template argument.
template <class Context, class From>
void test_string_view(From value) {
auto store = std::make_format_args<Context>(value);
const std::basic_format_args<Context> format_args{store};
using CharT = typename Context::char_type;
using To = std::basic_string_view<CharT>;
using V = std::basic_string<CharT>;
std::visit_format_arg(
[v = V(value.begin(), value.end())](auto a) {
if constexpr (std::is_same_v<To, decltype(a)>)
assert(v == a);
else
assert(false);
},
format_args.get(0));
}
template <class CharT>
void test() {
using Context = std::basic_format_context<CharT*, CharT>;
{
const std::basic_format_args<Context> format_args{};
ASSERT_NOEXCEPT(format_args.get(0));
assert(!format_args.get(0));
}
using char_type = typename Context::char_type;
std::basic_string<char_type> empty;
std::basic_string<char_type> str = MAKE_STRING(char_type, "abc");
// Test boolean types.
test<Context, bool>(true);
test<Context, bool>(false);
// Test char_type types.
test<Context, char_type, char_type>('a');
test<Context, char_type, char_type>('z');
test<Context, char_type, char_type>('0');
test<Context, char_type, char_type>('9');
// Test char types.
if (std::is_same_v<char_type, char>) {
// char to char -> char
test<Context, char_type, char>('a');
test<Context, char_type, char>('z');
test<Context, char_type, char>('0');
test<Context, char_type, char>('9');
} else {
if (std::is_same_v<char_type, wchar_t>) {
// char to wchar_t -> wchar_t
test<Context, wchar_t, char>('a');
test<Context, wchar_t, char>('z');
test<Context, wchar_t, char>('0');
test<Context, wchar_t, char>('9');
} else if (std::is_signed_v<char>) {
// char to char_type -> int
// This happens when Context::char_type is a char8_t, char16_t, or
// char32_t and char is a signed type.
// Note if sizeof(char_type) > sizeof(int) this test fails. If there are
// platforms where that occurs extra tests need to be added for char32_t
// testing it against a long long.
test<Context, int, char>('a');
test<Context, int, char>('z');
test<Context, int, char>('0');
test<Context, int, char>('9');
} else {
// char to char_type -> unsigned
// This happens when Context::char_type is a char8_t, char16_t, or
// char32_t and char is an unsigned type.
// Note if sizeof(char_type) > sizeof(unsigned) this test fails. If there
// are platforms where that occurs extra tests need to be added for
// char32_t testing it against an unsigned long long.
test<Context, unsigned, char>('a');
test<Context, unsigned, char>('z');
test<Context, unsigned, char>('0');
test<Context, unsigned, char>('9');
}
}
// Test signed integer types.
test<Context, int, signed char>(std::numeric_limits<signed char>::min());
test<Context, int, signed char>(0);
test<Context, int, signed char>(std::numeric_limits<signed char>::max());
test<Context, int, short>(std::numeric_limits<short>::min());
test<Context, int, short>(std::numeric_limits<signed char>::min());
test<Context, int, short>(0);
test<Context, int, short>(std::numeric_limits<signed char>::max());
test<Context, int, short>(std::numeric_limits<short>::max());
test<Context, int, int>(std::numeric_limits<int>::min());
test<Context, int, int>(std::numeric_limits<short>::min());
test<Context, int, int>(std::numeric_limits<signed char>::min());
test<Context, int, int>(0);
test<Context, int, int>(std::numeric_limits<signed char>::max());
test<Context, int, int>(std::numeric_limits<short>::max());
test<Context, int, int>(std::numeric_limits<int>::max());
using LongToType =
std::conditional_t<sizeof(long) == sizeof(int), int, long long>;
test<Context, LongToType, long>(std::numeric_limits<long>::min());
test<Context, LongToType, long>(std::numeric_limits<int>::min());
test<Context, LongToType, long>(std::numeric_limits<short>::min());
test<Context, LongToType, long>(std::numeric_limits<signed char>::min());
test<Context, LongToType, long>(0);
test<Context, LongToType, long>(std::numeric_limits<signed char>::max());
test<Context, LongToType, long>(std::numeric_limits<short>::max());
test<Context, LongToType, long>(std::numeric_limits<int>::max());
test<Context, LongToType, long>(std::numeric_limits<long>::max());
test<Context, long long, long long>(std::numeric_limits<long long>::min());
test<Context, long long, long long>(std::numeric_limits<long>::min());
test<Context, long long, long long>(std::numeric_limits<int>::min());
test<Context, long long, long long>(std::numeric_limits<short>::min());
test<Context, long long, long long>(std::numeric_limits<signed char>::min());
test<Context, long long, long long>(0);
test<Context, long long, long long>(std::numeric_limits<signed char>::max());
test<Context, long long, long long>(std::numeric_limits<short>::max());
test<Context, long long, long long>(std::numeric_limits<int>::max());
test<Context, long long, long long>(std::numeric_limits<long>::max());
test<Context, long long, long long>(std::numeric_limits<long long>::max());
#ifndef _LIBCPP_HAS_NO_INT128
test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::min());
test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::min());
test<Context, __int128_t, __int128_t>(
std::numeric_limits<signed char>::min());
test<Context, __int128_t, __int128_t>(0);
test<Context, __int128_t, __int128_t>(
std::numeric_limits<signed char>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::max());
test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::max());
#endif
// Test unsigned integer types.
test<Context, unsigned, unsigned char>(0);
test<Context, unsigned, unsigned char>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned short>(0);
test<Context, unsigned, unsigned short>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned short>(
std::numeric_limits<unsigned short>::max());
test<Context, unsigned, unsigned>(0);
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned char>::max());
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned short>::max());
test<Context, unsigned, unsigned>(std::numeric_limits<unsigned>::max());
using UnsignedLongToType =
std::conditional_t<sizeof(unsigned long) == sizeof(unsigned), unsigned,
unsigned long long>;
test<Context, UnsignedLongToType, unsigned long>(0);
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned char>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned short>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned>::max());
test<Context, UnsignedLongToType, unsigned long>(
std::numeric_limits<unsigned long>::max());
test<Context, unsigned long long, unsigned long long>(0);
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned char>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned short>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned long>::max());
test<Context, unsigned long long, unsigned long long>(
std::numeric_limits<unsigned long long>::max());
#ifndef _LIBCPP_HAS_NO_INT128
test<Context, __uint128_t, __uint128_t>(0);
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned char>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned short>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned int>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned long>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<unsigned long long>::max());
test<Context, __uint128_t, __uint128_t>(
std::numeric_limits<__uint128_t>::max());
#endif
// Test floating point types.
test<Context, float, float>(-std::numeric_limits<float>::max());
test<Context, float, float>(-std::numeric_limits<float>::min());
test<Context, float, float>(-0.0);
test<Context, float, float>(0.0);
test<Context, float, float>(std::numeric_limits<float>::min());
test<Context, float, float>(std::numeric_limits<float>::max());
test<Context, double, double>(-std::numeric_limits<double>::max());
test<Context, double, double>(-std::numeric_limits<double>::min());
test<Context, double, double>(-0.0);
test<Context, double, double>(0.0);
test<Context, double, double>(std::numeric_limits<double>::min());
test<Context, double, double>(std::numeric_limits<double>::max());
test<Context, long double, long double>(
-std::numeric_limits<long double>::max());
test<Context, long double, long double>(
-std::numeric_limits<long double>::min());
test<Context, long double, long double>(-0.0);
test<Context, long double, long double>(0.0);
test<Context, long double, long double>(
std::numeric_limits<long double>::min());
test<Context, long double, long double>(
std::numeric_limits<long double>::max());
// Test const char_type pointer types.
test<Context, const char_type*, const char_type*>(empty.c_str());
test<Context, const char_type*, const char_type*>(str.c_str());
// Test string_view types.
test<Context, std::basic_string_view<char_type>>(
std::basic_string_view<char_type>());
test<Context, std::basic_string_view<char_type>,
std::basic_string_view<char_type>>(empty);
test<Context, std::basic_string_view<char_type>,
std::basic_string_view<char_type>>(str);
// Test string types.
test<Context, std::basic_string_view<char_type>>(
std::basic_string<char_type>());
test<Context, std::basic_string_view<char_type>,
std::basic_string<char_type>>(empty);
test<Context, std::basic_string_view<char_type>,
std::basic_string<char_type>>(str);
// Test pointer types.
test<Context, const void*>(nullptr);
}
void test() {
test<char>();
test<wchar_t>();
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// Namespace std typedefs:
// using format_args = basic_format_args<format_context>;
// using wformat_args = basic_format_args<wformat_context>;
// template<class Out, class charT>
// using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
#include <format>
#include <vector>
#include <type_traits>
#include "test_macros.h"
static_assert(std::is_same_v<std::format_args,
std::basic_format_args<std::format_context>>);
static_assert(std::is_same_v<std::wformat_args,
std::basic_format_args<std::wformat_context>>);
static_assert(std::is_same_v<
std::format_args_t<std::back_insert_iterator<std::string>, char>,
std::basic_format_args<std::basic_format_context<
std::back_insert_iterator<std::string>, char>>>);
static_assert(
std::is_same_v<
std::format_args_t<std::back_insert_iterator<std::wstring>, wchar_t>,
std::basic_format_args<std::basic_format_context<
std::back_insert_iterator<std::wstring>, wchar_t>>>);
static_assert(
std::is_same_v<
std::format_args_t<std::back_insert_iterator<std::vector<char>>, char>,
std::basic_format_args<std::basic_format_context<
std::back_insert_iterator<std::vector<char>>, char>>>);
// Required for MSVC internal test runner compatibility.
int main(int, char**) { return 0; }

View File

@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// void advance_to(iterator it);
#include <format>
#include <cassert>
#include <string>
#include "test_macros.h"
#include "test_format_context.h"
template <class OutIt, class CharT>
void test(
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args) {
{
std::basic_string<CharT> str[3];
std::basic_format_context context =
test_format_context_create(OutIt{str[0]}, args);
context.out() = CharT('a');
context.advance_to(OutIt{str[1]});
context.out() = CharT('b');
context.advance_to(OutIt{str[2]});
context.out() = CharT('c');
assert(str[0].size() == 1);
assert(str[0].front() == CharT('a'));
assert(str[1].size() == 1);
assert(str[1].front() == CharT('b'));
assert(str[2].size() == 1);
assert(str[2].front() == CharT('c'));
}
}
void test() {
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char>>, char>>()));
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>()));
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>>()));
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char16_t>>,
char16_t>>()));
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char32_t>>,
char32_t>>()));
#endif
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// basic_format_arg<basic_format_context> arg(size_t id) const;
#include <format>
#include <cassert>
#include "test_basic_format_arg.h"
#include "test_format_context.h"
#include "test_macros.h"
#include "make_string.h"
template <class OutIt, class CharT>
void test() {
std::basic_string<CharT> string = MAKE_STRING(CharT, "string");
auto store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(
true, CharT('a'), 42, string);
std::basic_format_args args = store;
std::basic_string<CharT> output;
const std::basic_format_context context =
test_format_context_create(OutIt{output}, args);
LIBCPP_ASSERT(args.__size() == 4);
for (size_t i = 0, e = args.__size(); i != e; ++i) {
assert(context.arg(i));
}
assert(!context.arg(args.__size()));
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
}
int main(int, char**) {
test<std::back_insert_iterator<std::basic_string<char>>, char>();
test<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>();
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test<std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>();
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test<std::back_insert_iterator<std::basic_string<char16_t>>, char16_t>();
test<std::back_insert_iterator<std::basic_string<char32_t>>, char32_t>();
#endif
return 0;
}

View File

@@ -0,0 +1,139 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-localization
// UNSUPPORTED: libcpp-has-no-incomplete-format
// REQUIRES: locale.en_US.UTF-8
// REQUIRES: locale.fr_FR.UTF-8
// <format>
// The Standard does not specifiy a constructor
// basic_format_context(Out out,
// basic_format_args<basic_format_context> args,
// std::optional<std::::locale>&& loc = std::nullopt);
// If compliled with -D_LIBCPP_HAS_NO_LOCALIZATION
// basic_format_context(Out out,
// basic_format_args<basic_format_context> args);
#include <format>
#include <cassert>
#include <type_traits>
#include "test_basic_format_arg.h"
#include "test_format_context.h"
#include "make_string.h"
#include "platform_support.h" // locale name macros
#include "test_macros.h"
template <class OutIt, class CharT>
void test() {
static_assert(
!std::is_copy_constructible_v<std::basic_format_context<OutIt, CharT>>);
static_assert(
!std::is_copy_assignable_v<std::basic_format_context<OutIt, CharT>>);
// The move operations are implicitly deleted due to the
// deleted copy operations.
static_assert(
!std::is_move_constructible_v<std::basic_format_context<OutIt, CharT>>);
static_assert(
!std::is_move_assignable_v<std::basic_format_context<OutIt, CharT>>);
std::basic_string<CharT> string = MAKE_STRING(CharT, "string");
std::basic_format_args args =
std::make_format_args<std::basic_format_context<OutIt, CharT>>(
true, CharT('a'), 42, string);
{
std::basic_string<CharT> output;
OutIt out_it{output};
std::basic_format_context context =
test_format_context_create(out_it, args);
LIBCPP_ASSERT(args.__size() == 4);
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
context.out() = CharT('a');
assert(output.size() == 1);
assert(output.front() == CharT('a'));
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
assert(context.locale() == std::locale());
#endif
}
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
std::locale en_US{LOCALE_en_US_UTF_8};
std::locale fr_FR{LOCALE_fr_FR_UTF_8};
{
std::basic_string<CharT> output;
OutIt out_it{output};
std::basic_format_context context =
test_format_context_create(out_it, args, en_US);
LIBCPP_ASSERT(args.__size() == 4);
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
context.out() = CharT('a');
assert(output.size() == 1);
assert(output.front() == CharT('a'));
assert(context.locale() != fr_FR);
assert(context.locale() == en_US);
}
{
std::basic_string<CharT> output;
OutIt out_it{output};
std::basic_format_context context =
test_format_context_create(out_it, args, fr_FR);
LIBCPP_ASSERT(args.__size() == 4);
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
context.out() = CharT('a');
assert(output.size() == 1);
assert(output.front() == CharT('a'));
assert(context.locale() == fr_FR);
assert(context.locale() != en_US);
}
#endif
}
void test() {
test<std::back_insert_iterator<std::basic_string<char>>, char>();
test<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>();
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test<std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>();
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test<std::back_insert_iterator<std::basic_string<char16_t>>, char16_t>();
test<std::back_insert_iterator<std::basic_string<char32_t>>, char32_t>();
#endif
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,94 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-localization
// UNSUPPORTED: libcpp-has-no-incomplete-format
// REQUIRES: locale.en_US.UTF-8
// REQUIRES: locale.fr_FR.UTF-8
// <format>
// std::locale locale();
#include <format>
#include <cassert>
#include "make_string.h"
#include "platform_support.h" // locale name macros
#include "test_basic_format_arg.h"
#include "test_format_context.h"
#include "test_macros.h"
template <class OutIt, class CharT>
void test() {
std::locale en_US{LOCALE_en_US_UTF_8};
std::locale fr_FR{LOCALE_fr_FR_UTF_8};
std::basic_string<CharT> string = MAKE_STRING(CharT, "string");
std::basic_format_args args =
std::make_format_args<std::basic_format_context<OutIt, CharT>>(
true, CharT('a'), 42, string);
{
std::basic_string<CharT> output;
OutIt out_it{output};
std::basic_format_context context =
test_format_context_create(out_it, args, en_US);
assert(args.__size() == 4);
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
context.out() = CharT('a');
assert(output.size() == 1);
assert(output.front() == CharT('a'));
assert(context.locale() != fr_FR);
assert(context.locale() == en_US);
}
{
std::basic_string<CharT> output;
OutIt out_it{output};
std::basic_format_context context =
test_format_context_create(out_it, args, fr_FR);
assert(args.__size() == 4);
assert(test_basic_format_arg(context.arg(0), true));
assert(test_basic_format_arg(context.arg(1), CharT('a')));
assert(test_basic_format_arg(context.arg(2), 42));
assert(test_basic_format_arg(context.arg(3),
std::basic_string_view<CharT>(string)));
context.out() = CharT('a');
assert(output.size() == 1);
assert(output.front() == CharT('a'));
assert(context.locale() == fr_FR);
assert(context.locale() != en_US);
}
}
void test() {
test<std::back_insert_iterator<std::basic_string<char>>, char>();
test<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>();
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test<std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>();
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test<std::back_insert_iterator<std::basic_string<char16_t>>, char16_t>();
test<std::back_insert_iterator<std::basic_string<char32_t>>, char32_t>();
#endif
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// iterator out();
#include <format>
#include <cassert>
#include <string>
#include "test_macros.h"
#include "test_format_context.h"
template <class OutIt, class CharT>
void test(
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args) {
{
std::basic_string<CharT> str;
OutIt out_it{str};
std::basic_format_context context =
test_format_context_create(out_it, args);
context.out() = CharT('a');
context.out() = CharT('b');
context.out() = CharT('c');
assert(str.size() == 3);
assert(str[0] == CharT('a'));
assert(str[1] == CharT('b'));
assert(str[2] == CharT('c'));
}
}
void test() {
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char>>, char>>()));
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>()));
#ifndef _LIBCPP_HAS_NO_CHAR8_T
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>>()));
#endif
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char16_t>>,
char16_t>>()));
test(std::basic_format_args(
std::make_format_args<std::basic_format_context<
std::back_insert_iterator<std::basic_string<char32_t>>,
char32_t>>()));
#endif
}
int main(int, char**) {
test();
return 0;
}

View File

@@ -0,0 +1,119 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// <format>
// Class typedefs:
// template<class Out, class charT>
// class basic_format_context {
// public:
// using iterator = Out
// using char_type = charT;
// template<class T> using formatter_type = formatter<T, charT>;
// }
//
// Namespace std typedefs:
// using format_context = basic_format_context<unspecified, char>;
// using wformat_context = basic_format_context<unspecified, wchar_t>;
#include <format>
#include <string>
#include <string_view>
#include <type_traits>
#include "test_macros.h"
template <class OutIt, class CharT>
constexpr void test() {
static_assert(
std::is_same_v<typename std::basic_format_context<OutIt, CharT>::iterator,
OutIt>);
static_assert(
std::is_same_v<
typename std::basic_format_context<OutIt, CharT>::char_type, CharT>);
static_assert(std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<bool>,
std::formatter<bool, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<CharT>,
std::formatter<CharT, CharT>>);
static_assert(std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<int>,
std::formatter<int, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<unsigned>,
std::formatter<unsigned, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<long long>,
std::formatter<long long, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<OutIt, CharT>::
template formatter_type<unsigned long long>,
std::formatter<unsigned long long, CharT>>);
#ifndef _LIBCPP_HAS_NO_INT128
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<__int128_t>,
std::formatter<__int128_t, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<__uint128_t>,
std::formatter<__uint128_t, CharT>>);
#endif
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<float>,
std::formatter<float, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<double>,
std::formatter<double, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<long double>,
std::formatter<long double, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<const CharT*>,
std::formatter<const CharT*, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<OutIt, CharT>::
template formatter_type<std::basic_string_view<CharT>>,
std::formatter<std::basic_string_view<CharT>, CharT>>);
static_assert(
std::is_same_v<typename std::basic_format_context<
OutIt, CharT>::template formatter_type<const void*>,
std::formatter<const void*, CharT>>);
}
constexpr void test() {
test<std::back_insert_iterator<std::basic_string<char>>, char>();
test<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>();
test<std::back_insert_iterator<std::basic_string<char8_t>>, char8_t>();
test<std::back_insert_iterator<std::basic_string<char16_t>>, char16_t>();
test<std::back_insert_iterator<std::basic_string<char32_t>>, char32_t>();
}
static_assert(std::is_same_v<
std::format_context,
std::basic_format_context<
std::back_insert_iterator<std::basic_string<char>>, char>>);
static_assert(
std::is_same_v<
std::wformat_context,
std::basic_format_context<
std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>);
// Required for MSVC internal test runner compatibility.
int main(int, char**) { return 0; }

View File

@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: libcpp-has-no-incomplete-format
// constexpr void check_arg_id(size_t id);
#include <format>
#include "test_macros.h"
constexpr bool test() {
// [format.parse.ctx]/11
// Remarks: Call expressions where id >= num_args_ are not
// core constant expressions ([expr.const]).
std::format_parse_context context("", 0);
context.check_arg_id(1);
return true;
}
int main(int, char**) {
// expected-error@+1 {{static_assert expression is not an integral constant expression}}
static_assert(test());
return 0;
}

View File

@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
// 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
//
//===----------------------------------------------------------------------===//
#include <concepts>
#include <format>
#include "test_macros.h"
/// Returns whether the basic_format_arg contains a type T with the expected value.
template <class Context, class T>
bool test_basic_format_arg(std::basic_format_arg<Context> arg, T expected) {
return std::visit_format_arg(
[expected](auto a) {
if constexpr (std::same_as<decltype(a), T>)
return a == expected;
else
return false;
},
arg);
}

View File

@@ -0,0 +1,62 @@
// -*- 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 SUPPORT_TEST_FORMAT_CONTEXT_HPP
#define SUPPORT_TEST_FORMAT_CONTEXT_HPP
/**
* @file Helper functions to create a @ref std::basic_format_context.
*
* Since the standard doesn't specify how a @ref std::basic_format_context is
* constructed this is implementation defined. To make the public API tests of
* the class generic this header defines helper functions to create the
* required object.
*
* @note This requires every standard library implementation to write their own
* helper function. Vendors are encouraged to file a review at
* https://reviews.llvm.org/ so their specific implementation can be part of
* this file.
*/
#if TEST_STD_VER < 20
#error "The format header requires at least C++20"
#endif
#include <format>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
#include <locale>
#endif
#if defined(_LIBCPP_VERSION)
/** Creates a std::basic_format_context as-if the formatting function takes no locale. */
template <class OutIt, class CharT>
std::basic_format_context<OutIt, CharT> test_format_context_create(
OutIt out_it,
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args) {
return std::__format_context_create(std::move(out_it), args);
}
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
/** Creates a std::basic_format_context as-if the formatting function takes locale. */
template <class OutIt, class CharT>
std::basic_format_context<OutIt, CharT> test_format_context_create(
OutIt out_it,
std::basic_format_args<std::basic_format_context<OutIt, CharT>> args,
std::locale loc) {
return std::__format_context_create(std::move(out_it), args, std::move(loc));
}
#endif
#else
#error \
"Please create a vendor specific version of the test functions and file a review at https://reviews.llvm.org/"
#endif
#endif // SUPPORT_TEST_FORMAT_CONTEXT_HPP