diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -275,7 +275,7 @@ "`3364 `__","Initialize data members of ranges and their iterators","Prague","","" "`3367 `__","Integer-class conversions should not throw","Prague","","" "`3369 `__","``span``\ 's deduction-guide for built-in arrays doesn't work","Prague","","" -"`3371 `__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","","" +"`3371 `__","``visit_format_arg``\ and ``make_format_args``\ are not hidden friends","Prague","|Complete|","13.0" "`3372 `__","``vformat_to``\ should not try to deduce ``Out``\ twice","Prague","","" "`3373 `__","``{to,from}_chars_result``\ and ``format_to_n_result``\ need the ""we really mean what we say"" wording","Prague","","" "`3374 `__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0" diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -13,6 +13,137 @@ /* namespace std { + // [format.context], class template basic_format_context + template + class basic_format_context { + basic_format_args args_; // exposition only + Out out_; // exposition only + + public: + using iterator = Out; + using char_type = charT; + template using formatter_type = formatter; + + basic_format_arg arg(size_t id) const; + std::locale locale(); + + iterator out(); + void advance_to(iterator it); + }; + using format_context = basic_format_context; + using wformat_context = basic_format_context; + + // [format.args], class template basic_format_args + template + class basic_format_args { + size_t size_; // exposition only + const basic_format_arg* data_; // exposition only + + public: + basic_format_args() noexcept; + + template + basic_format_args(const format-arg-store& store) noexcept; + + basic_format_arg get(size_t i) const noexcept; + }; + using format_args = basic_format_args; + using wformat_args = basic_format_args; + + + template + using format_args_t = basic_format_args>; + + // [format.parse.ctx], class template basic_format_parse_context + template + class basic_format_parse_context { + public: + using char_type = charT; + using const_iterator = typename basic_string_view::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 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; + using wformat_parse_context = basic_format_parse_context; + + // [format.arguments], arguments + // [format.arg], class template basic_format_arg + template + class basic_format_arg { + public: + class handle; + + private: + using char_type = typename Context::char_type; // exposition only + + variant, + const void*, handle> value; // exposition only + + template 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 + explicit basic_format_arg( + basic_string_view s) noexcept; // exposition only + + template + explicit basic_format_arg( + const basic_string& s) noexcept; // exposition only + + explicit basic_format_arg(nullptr_t) noexcept; // exposition only + + template + explicit basic_format_arg(const T* p) noexcept; // exposition only + + public: + basic_format_arg() noexcept; + + explicit operator bool() const noexcept; + }; + + + template + see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + + // [format.arg.store], class template format-arg-store + template + struct format-arg-store { // exposition only + array, sizeof...(Args)> args; + }; + + template + format-arg-store + make_format_args(const Args&... args); + template + format-arg-store + make_wformat_args(const Args&... args); + // [format.error], class format_error class format_error : public runtime_error { public: @@ -56,16 +187,27 @@ */ #include <__config> +#include +#include +#include #include +#include #include +#include #include +#include #ifdef _LIBCPP_NO_EXCEPTIONS #include #endif +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +#include +#include +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header +#pragma GCC system_header #endif _LIBCPP_PUSH_MACROS @@ -100,6 +242,43 @@ #endif } +// 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. + +// libc++ has a concepts header, but currently only a small subset of the +// concepts is implemented. To ease the transition to using the not yet +// implemented concepts some helper concepts are added. +// TODO FMT Switch to the real concepts when they are available. +template +concept + __output_iterator = _VSTD::__has_iterator_category_convertible_to< + _Tp, _VSTD::output_iterator_tag>::value || + // std::string::iterator needs additional tests. + // This sounds buggy, however since the code should use + // the concept don't fix it. + (_VSTD::__has_iterator_category_convertible_to< + _Tp, _VSTD::forward_iterator_tag>::value && + !_VSTD::__is_exactly_cpp17_input_iterator<_Tp>::value); + +// Forward declarations. + +template +class _LIBCPP_TEMPLATE_VIS basic_format_arg; + +template +struct _LIBCPP_TEMPLATE_VIS __format_arg_store { + _VSTD::array, sizeof...(_Args)> __args; +}; + +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store<_Ctx, _Args...> +__make_format_args(const _Args&...); + +template +struct _LIBCPP_TEMPLATE_VIS formatter; + template class _LIBCPP_TEMPLATE_VIS basic_format_parse_context { public: @@ -172,6 +351,282 @@ using format_parse_context = basic_format_parse_context; using wformat_parse_context = basic_format_parse_context; +// TODO FMT Add unit test for testing the return value of visit. +template +_LIBCPP_INLINE_VISIBILITY auto +visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) + -> decltype(_VSTD::visit(forward<_Visitor>(__vis), __arg.__value_)) { + return _VSTD::visit(forward<_Visitor>(__vis), __arg.__value_); +} + +template +class _LIBCPP_TEMPLATE_VIS basic_format_arg { +public: + // TODO FMT Define the handle class. + class handle; + + _LIBCPP_INLINE_VISIBILITY basic_format_arg() noexcept = default; + + _LIBCPP_INLINE_VISIBILITY explicit operator bool() const noexcept { + return !holds_alternative<_VSTD::monostate>(__value_); + } + +private: + using char_type = typename _Context::char_type; + + // TODO FMT Implement constrain [format.arg]/4 + // Constraints: The template specialization + // typename Context::template formatter_type + // 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() + // .format(declval(), declval()) + // shall be well-formed when treated as an unevaluated operand. + + template + _LIBCPP_INLINE_VISIBILITY friend __format_arg_store<_Ctx, _Args...> + _VSTD::__make_format_args(const _Args&...); + + template + _LIBCPP_INLINE_VISIBILITY friend auto + _VSTD::visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx> __arg) + -> decltype(_VSTD::visit(forward<_Visitor>(__vis), __arg.__value_)); + + _VSTD::variant<_VSTD::monostate, bool, char_type, int, unsigned, long long, + unsigned long long, +#ifndef _LIBCPP_HAS_NO_INT128 + __int128_t, __uint128_t, +#endif + float, double, long double, const char_type*, + _VSTD::basic_string_view, const void* + // TODO FMT Enable the handle. + /*, handle*/> + __value_{_VSTD::monostate{}}; + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const _Tp& __value) noexcept + requires(_VSTD::is_same_v<_Tp, bool> || _VSTD::is_same_v<_Tp, char_type> +#ifndef _LIBCPP_HAS_NO_INT128 + || _VSTD::is_same_v<_Tp, __int128_t> || + _VSTD::is_same_v<_Tp, __uint128_t> +#endif + ) { + __value_ = __value; + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(const _Tp& __value) + noexcept requires( + _VSTD::is_same_v<_Tp, char>&& _VSTD::is_same_v) { + __value_ = static_cast(__value); + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const _Tp& __value) noexcept + requires(_VSTD::signed_integral<_Tp> && !_VSTD::is_same_v<_Tp, char_type> && + !(_VSTD::is_same_v<_Tp, char> && + _VSTD::is_same_v)&&sizeof(_Tp) <= + sizeof(int)) { + __value_ = static_cast(__value); + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const _Tp& __value) noexcept + // Don't depend on the signedness of the char_type. + requires(_VSTD::unsigned_integral<_Tp> && !_VSTD::is_same_v<_Tp, bool> && + !_VSTD::is_same_v<_Tp, char_type> && + sizeof(_Tp) <= sizeof(unsigned)) { + __value_ = static_cast(__value); + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const _Tp& __value) noexcept + // Avoid ambiguous lookups with types where sizeof(_Tp) <= sizeof(int) + // Since sizeof(char_type) is not larger than sizeof(int) don't test them. + requires(_VSTD::signed_integral<_Tp> && sizeof(_Tp) > sizeof(int) && + sizeof(_Tp) <= sizeof(long long)) { + __value_ = static_cast(__value); + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg(const _Tp& __value) + noexcept requires( + // Avoid ambiguous lookups with types where + // sizeof(_Tp) <= sizeof(unsigned). Since sizeof(bool) and + // sizeof(char) are not larger than sizeof(unsigned) don't test them. + _VSTD::unsigned_integral<_Tp> && sizeof(_Tp) > sizeof(unsigned) && + sizeof(_Tp) <= sizeof(unsigned long long)) { + __value_ = static_cast(__value); + } + + // TODO FMT Implement the handle overload. + + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(float __n) noexcept { __value_ = __n; } + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(double __n) noexcept { __value_ = __n; } + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(long double __n) noexcept { __value_ = __n; } + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(const char_type* __s) { + if (!__s) + __throw_format_error("Used a nullptr argument to initialize a C-string."); + __value_ = __s; + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + _VSTD::basic_string_view __s) noexcept { + __value_ = __s; + } + + template + _LIBCPP_INLINE_VISIBILITY explicit basic_format_arg( + const _VSTD::basic_string& __s) noexcept { + __value_ = _VSTD::basic_string_view(__s.data(), __s.size()); + } + + _LIBCPP_INLINE_VISIBILITY + explicit basic_format_arg(nullptr_t) noexcept { + __value_ = static_cast(nullptr); + } + + // TODO FMT Implement the const _Tp constructor. + + // The operator isn't specified in the Standard but is useful in unit tests. + friend bool operator==(const basic_format_arg& __lhs, + const basic_format_arg& __rhs) { + return __lhs.__value_ == __rhs.__value_; + } +}; + +template +class _LIBCPP_TEMPLATE_VIS 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] + _LIBCPP_INLINE_VISIBILITY basic_format_args() noexcept = default; + + template + _LIBCPP_INLINE_VISIBILITY basic_format_args( + const __format_arg_store<_Context, _Args...>& __store) noexcept { + __size_ = sizeof...(_Args); + __data_ = __store.__args.data(); + } + + _LIBCPP_INLINE_VISIBILITY + basic_format_arg<_Context> get(size_t __id) const noexcept { + return __id < __size_ ? __data_[__id] : basic_format_arg<_Context>(); + } + + // Returns: The number of formatting arguments. + size_t __size() const noexcept { return __size_; } + +private: + size_t __size_{0}; + const basic_format_arg<_Context>* __data_; +}; + +template +requires __output_iterator class _LIBCPP_TEMPLATE_VIS + basic_format_context { +public: + using iterator = _OutIt; + using char_type = _CharT; + template + using formatter_type = formatter<_Tp, _CharT>; + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + // Note: the Standard doesn't specify the required constructors. + _LIBCPP_INLINE_VISIBILITY + basic_format_context(_OutIt __out_it, + basic_format_args __args, + _VSTD::optional<_VSTD::locale>&& __loc = _VSTD::nullopt) + : __out_it_(__out_it), __args_(__args), __loc_(_VSTD::move(__loc)) {} +#else + _LIBCPP_INLINE_VISIBILITY + basic_format_context(_OutIt __out_it, + basic_format_args __args) + : __out_it_(__out_it), __args_(__args) {} +#endif + + basic_format_context(const basic_format_context&) = delete; + basic_format_context& operator=(const basic_format_context&) = delete; + + _LIBCPP_INLINE_VISIBILITY basic_format_arg + arg(size_t __id) const { + return __args_.get(__id); + } +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + _LIBCPP_INLINE_VISIBILITY _VSTD::locale locale() { + if (!__loc_) + __loc_ = _VSTD::locale(); + return *__loc_; + } +#endif + _LIBCPP_INLINE_VISIBILITY iterator out() { return __out_it_; } + _LIBCPP_INLINE_VISIBILITY void advance_to(iterator __it) { __out_it_ = __it; } + +private: + iterator __out_it_; + basic_format_args __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 create. + // This allow the implementation to lazily create the locale. + // TODO FMT Validate whether lazy creation is the best solution. + _VSTD::optional<_VSTD::locale> __loc_; +#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, vector, or any other container with contiguous +// storage by wrapping those in temporary objects with a uniform interface +// (such as a span) and polymorphic reallocation. — end note] + +using format_context = + basic_format_context<_VSTD::back_insert_iterator<_VSTD::string>, char>; +using wformat_context = + basic_format_context<_VSTD::back_insert_iterator<_VSTD::wstring>, wchar_t>; + +using format_args = basic_format_args; +using wformat_args = basic_format_args; + +template +using format_args_t = basic_format_args >; + +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store<_Context, _Args...> +__make_format_args(const _Args&... __args) { + return {basic_format_arg<_Context>(__args)...}; +} +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store<_Context, _Args...> +make_format_args(const _Args&... __args) { + return __make_format_args<_Context>(__args...); +} +template +_LIBCPP_INLINE_VISIBILITY __format_arg_store +make_wformat_args(const _Args&... __args) { + return __make_format_args(__args...); +} + #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) && !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED) #endif //_LIBCPP_STD_VER > 17 diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/class.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// struct format-arg-store { // exposition only +// array, sizeof...(Args)> args; +// }; +// +// Note more testing is done in the unit test for: +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" + +template +void test() { + { + auto store = std::make_format_args(); + static_assert( + std::is_same_v >); + static_assert( + std::is_same_v, 0> >); + assert(store.__args.size() == 0); + } + { + auto store = std::make_format_args(1); + static_assert(std::is_same_v >); + static_assert( + std::is_same_v, 1> >); + assert(store.__args.size() == 1); + } + { + auto store = std::make_format_args(1, 'c'); + static_assert(std::is_same_v >); + static_assert( + std::is_same_v, 2> >); + assert(store.__args.size() == 2); + } + { + auto store = std::make_format_args(1, 'c', nullptr); + static_assert(std::is_same_v< + decltype(store), + std::__format_arg_store >); + static_assert( + std::is_same_v, 3> >); + assert(store.__args.size() == 3); + } +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// format-arg-store make_format_args(const Args&... args); + +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + using Context = std::basic_format_context< + std::back_insert_iterator >, char>; + + auto value = std::make_format_args(42, nullptr, false, 1.0); + auto expected = + std::make_format_args( + 42, nullptr, false, 1.0); + + assert(value.__args.size() == 4); + assert(expected.__args.size() == value.__args.size()); + + for (size_t i = 0, e = value.__args.size(); i != e; ++i) + assert(value.__args[i] == expected.__args[i]); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// format-arg-store +// make_wformat_args(const Args&... args); + +#include +#include + +#include "test_macros.h" + +int main(int, char**) { + using Context = std::basic_format_context< + std::back_insert_iterator >, wchar_t>; + + auto value = std::make_wformat_args(42, nullptr, false, 1.0); + auto expected = + std::make_format_args( + 42, nullptr, false, 1.0); + + assert(value.__args.size() == 4); + assert(expected.__args.size() == value.__args.size()); + + for (size_t i = 0, e = value.__args.size(); i != e; ++i) + assert(value.__args[i] == expected.__args[i]); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/ctor.pass.cpp @@ -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 + +// + +// basic_format_arg() noexcept; +// +// The unit test for: +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); +// tests the private constructors: +// template explicit basic_format_arg(const T& v) noexcept; +// explicit basic_format_arg(float n) noexcept; +// explicit basic_format_arg(double n) noexcept; +// explicit basic_format_arg(long double n) noexcept; +// explicit basic_format_arg(const char_type* s); +// template +// explicit basic_format_arg( +// basic_string_view s) noexcept; +// template +// explicit basic_format_arg( +// const basic_string& s) noexcept; +// explicit basic_format_arg(nullptr_t) noexcept; +// template +// explicit basic_format_arg(const T* p) noexcept; + +#include +#include + +#include "test_macros.h" + +template +void test() { + ASSERT_NOEXCEPT(std::basic_format_arg{}); + + std::basic_format_arg format_arg{}; + assert(!format_arg); +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/operator_bool.pass.cpp @@ -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 + +// + +// explicit operator bool() const noexcept +// +// Note more testing is done in the unit test for: +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" + +void test(const auto& store) { + for (const auto& arg : store.__args) { + assert(arg); + assert(static_cast(arg)); + } +} + +template +void test() { + { + std::basic_format_arg format_arg{}; + ASSERT_NOEXCEPT(!format_arg); + assert(!format_arg); + ASSERT_NOEXCEPT(static_cast(format_arg)); + assert(!static_cast(format_arg)); + } + test(std::make_format_args()); + test(std::make_format_args(1)); + test(std::make_format_args(1, 'c')); + test(std::make_format_args(1, 'c', nullptr)); +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.pass.cpp @@ -0,0 +1,328 @@ +//===----------------------------------------------------------------------===// +// 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 + +// This test requires the dylib support introduced in D92214. +// XFAIL: with_system_cxx_lib=macosx10.15 +// XFAIL: with_system_cxx_lib=macosx10.14 +// XFAIL: with_system_cxx_lib=macosx10.13 +// XFAIL: with_system_cxx_lib=macosx10.12 +// XFAIL: with_system_cxx_lib=macosx10.11 +// XFAIL: with_system_cxx_lib=macosx10.10 +// XFAIL: with_system_cxx_lib=macosx10.9 + +// + +// template +// see below visit_format_arg(Visitor&& vis, basic_format_arg arg); + +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test(From value) { + auto format_args = std::make_format_args(value); + assert(format_args.__args.size() == 1); + assert(format_args.__args[0]); + std::visit_format_arg( + [v = To(value)](auto&& a) { + if constexpr (std::is_same_v >) + assert(v == a); + else + assert(false); + }, + format_args.__args[0]); +} + +template +void test() { + using char_type = typename Context::char_type; + std::basic_string empty; + std::basic_string str = MAKE_STRING(char_type, "abc"); + + // Test boolean types. + + test(true); + test(false); + + // Test char_type types. + + test('a'); + test('z'); + test('0'); + test('9'); + + // Test char types. + + if (std::is_same_v) { + // char to char -> char + test('a'); + test('z'); + test('0'); + test('9'); + } else { + if (std::is_same_v) { + // char to wchar_t -> wchar_t + test('a'); + test('z'); + test('0'); + test('9'); + } else if (std::is_signed_v) { + // 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('a'); + test('z'); + test('0'); + test('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('a'); + test('z'); + test('0'); + test('9'); + } + } + + // Test signed integer types. + + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(0); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(std::numeric_limits<__int128_t>::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test( + std::numeric_limits::min()); + test(0); + test( + std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits<__int128_t>::max()); +#endif + + // Test unsigned integer types. + + test(0); + test( + std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + unsigned long>(0); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits<__uint128_t>::max()); +#endif + + // Test floating point types. + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test( + -std::numeric_limits::max()); + test( + -std::numeric_limits::min()); + test(-0.0); + test(0.0); + test( + std::numeric_limits::min()); + test( + std::numeric_limits::max()); + + // Test const char_type pointer types. + +#ifndef _LIBCPP_NO_EXCEPTIONS + [] { + try { + test(nullptr); + assert(false); + } catch (const std::format_error& e) { + assert(strcmp(e.what(), + "Used a nullptr argument to initialize a C-string.") == 0); + return; + } + assert(false); + }(); +#endif + test(empty.c_str()); + test(str.c_str()); + + // Test string_view types. + + test >( + std::basic_string_view()); + test, + std::basic_string_view >(empty); + test, + std::basic_string_view >(str); + + // Test string types. + + test >( + std::basic_string()); + test, + std::basic_string >(empty); + test, + std::basic_string >(str); + + // Test pointer types. + + test(nullptr); +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/__size.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/__size.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/__size.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// size_t __size() const noexcept; + +#include +#include + +#include "test_macros.h" + +template +void test() { + { + const std::basic_format_args format_args{}; + ASSERT_NOEXCEPT(format_args.__size()); + assert(format_args.__size() == 0); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42)}; + assert(format_args.__size() == 1); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42, nullptr)}; + assert(format_args.__size() == 2); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42, nullptr, true)}; + assert(format_args.__size() == 3); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42, nullptr, true, 1U)}; + assert(format_args.__size() == 4); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42, nullptr, true, 1U, 1.0f)}; + assert(format_args.__size() == 5); + } + { + const std::basic_format_args format_args{ + std::make_format_args(42, nullptr, true, 1U, 1.0f, 1.0)}; + assert(format_args.__size() == 6); + } +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// basic_format_args() noexcept; +// template +// basic_format_args(const format-arg-store& store) noexcept; + +#include +#include + +#include "test_macros.h" + +template +void test() { + { + ASSERT_NOEXCEPT(std::basic_format_args{}); + + std::basic_format_args format_args{}; + assert(!format_args.get(0)); + } + { + auto store = std::make_format_args(1); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args format_args{store}; + assert(format_args.get(0)); + assert(!format_args.get(1)); + } + { + auto store = std::make_format_args(1, 'c'); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args format_args{store}; + assert(format_args.get(0)); + assert(format_args.get(1)); + assert(!format_args.get(2)); + } + { + auto store = std::make_format_args(1, 'c', nullptr); + ASSERT_NOEXCEPT(std::basic_format_args{store}); + std::basic_format_args 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> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/get.pass.cpp @@ -0,0 +1,333 @@ +//===----------------------------------------------------------------------===// +// 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 + +// This test requires the dylib support introduced in D92214. +// XFAIL: with_system_cxx_lib=macosx10.15 +// XFAIL: with_system_cxx_lib=macosx10.14 +// XFAIL: with_system_cxx_lib=macosx10.13 +// XFAIL: with_system_cxx_lib=macosx10.12 +// XFAIL: with_system_cxx_lib=macosx10.11 +// XFAIL: with_system_cxx_lib=macosx10.10 +// XFAIL: with_system_cxx_lib=macosx10.9 + +// + +// basic_format_arg get(size_t i) const noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test(From value) { + auto store = std::make_format_args(value); + const std::basic_format_args format_args{store}; + + std::visit_format_arg( + [v = To(value)](auto&& a) { + if constexpr (std::is_same_v >) + assert(v == a); + else + assert(false); + }, + format_args.get(0)); +} + +template +void test() { + { + const std::basic_format_args format_args{}; + ASSERT_NOEXCEPT(format_args.get(0)); + assert(!format_args.get(0)); + } + + using char_type = typename Context::char_type; + std::basic_string empty; + std::basic_string str = MAKE_STRING(char_type, "abc"); + + // Test boolean types. + + test(true); + test(false); + + // Test char_type types. + + test('a'); + test('z'); + test('0'); + test('9'); + + // Test char types. + + if (std::is_same_v) { + // char to char -> char + test('a'); + test('z'); + test('0'); + test('9'); + } else { + if (std::is_same_v) { + // char to wchar_t -> wchar_t + test('a'); + test('z'); + test('0'); + test('9'); + } else if (std::is_signed_v) { + // 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('a'); + test('z'); + test('0'); + test('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('a'); + test('z'); + test('0'); + test('9'); + } + } + + // Test signed integer types. + + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(std::numeric_limits::min()); + test, + long>(0); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + test, + long>(std::numeric_limits::max()); + + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(std::numeric_limits<__int128_t>::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test(std::numeric_limits::min()); + test( + std::numeric_limits::min()); + test(0); + test( + std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits<__int128_t>::max()); +#endif + + // Test unsigned integer types. + + test(0); + test( + std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + + test(0); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + test(std::numeric_limits::max()); + + test, + unsigned long>(0); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + test, + unsigned long>(std::numeric_limits::max()); + + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + +#ifndef _LIBCPP_HAS_NO_INT128 + test(0); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits::max()); + test( + std::numeric_limits<__uint128_t>::max()); +#endif + + // Test floating point types. + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test(-std::numeric_limits::max()); + test(-std::numeric_limits::min()); + test(-0.0); + test(0.0); + test(std::numeric_limits::min()); + test(std::numeric_limits::max()); + + test( + -std::numeric_limits::max()); + test( + -std::numeric_limits::min()); + test(-0.0); + test(0.0); + test( + std::numeric_limits::min()); + test( + std::numeric_limits::max()); + + // Test const char_type pointer types. + +#ifndef _LIBCPP_NO_EXCEPTIONS + [] { + try { + test(nullptr); + assert(false); + } catch (const std::format_error& e) { + assert(strcmp(e.what(), + "Used a nullptr argument to initialize a C-string.") == 0); + return; + } + assert(false); + }(); +#endif + test(empty.c_str()); + test(str.c_str()); + + // Test string_view types. + + test >( + std::basic_string_view()); + test, + std::basic_string_view >(empty); + test, + std::basic_string_view >(str); + + // Test string types. + + test >( + std::basic_string()); + test, + std::basic_string >(empty); + test, + std::basic_string >(str); + + // Test pointer types. + + test(nullptr); +} + +void test() { + test >, char> >(); + test >, wchar_t> >(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.arguments/format.args/types.compile.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// Namespace std typedefs: +// using format_args = basic_format_args; +// using wformat_args = basic_format_args; +// template +// using format_args_t = basic_format_args>; + +#include +#include +#include + +#include "test_macros.h" + +static_assert(std::is_same_v >); +static_assert(std::is_same_v >); + +static_assert(std::is_same_v< + std::format_args_t, char>, + std::basic_format_args, char> > >); + +static_assert( + std::is_same_v< + std::format_args_t, wchar_t>, + std::basic_format_args, wchar_t> > >); + +static_assert( + std::is_same_v< + std::format_args_t >, char>, + std::basic_format_args >, char> > >); + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/advance_to.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// void advance_to(iterator it); + +#include +#include + +#include "test_macros.h" + +template +void test( + std::basic_format_args > args) { + { + std::basic_string str[3]; + std::basic_format_context context{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 >, char> >())); + + test(std::basic_format_args( + std::make_format_args >, + wchar_t> >())); +#ifndef _LIBCPP_NO_HAS_CHAR8_T + test(std::basic_format_args( + std::make_format_args >, + char8_t> >())); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(std::basic_format_args( + std::make_format_args >, + char16_t> >())); + test(std::basic_format_args( + std::make_format_args >, + char32_t> >())); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/arg.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// basic_format_arg arg(size_t id) const; + +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +void test() { + std::basic_string string = MAKE_STRING(CharT, "string"); + auto store = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + std::basic_format_args args = store; + + std::basic_string str; + { + const std::basic_format_context context{OutIt{str}, args}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) { + assert(context.arg(i)); + assert(context.arg(i) == args.get(i)); + } + assert(!context.arg(args.__size())); + } +} + +int main(int, char**) { + test >, char>(); + test >, wchar_t>(); +#ifndef _LIBCPP_NO_HAS_CHAR8_T + test >, char8_t>(); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test >, char16_t>(); + test >, char32_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/ctor.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// 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-has-no-localization + +// REQUIRES: locale.en_US.UTF-8 +// REQUIRES: locale.fr_FR.UTF-8 + +// + +// The Standard does not specifiy a constructor +// basic_format_context(Out out, +// basic_format_args args, +// std::optional&& loc = std::nullopt); +// If compliled with -D_LIBCPP_HAS_NO_LOCALIZATION +// basic_format_context(Out out, +// basic_format_args args); + +#include +#include +#include + +#include "test_macros.h" +#include "platform_support.h" // locale name macros +#include "make_string.h" + +template +void test() { + static_assert( + !std::is_copy_constructible_v >); + static_assert( + !std::is_copy_assignable_v >); + // The move operations are implicitly deleted due to the + // deleted copy operations. + static_assert( + !std::is_move_constructible_v >); + static_assert( + !std::is_move_assignable_v >); + + std::basic_string string = MAKE_STRING(CharT, "string"); + std::basic_format_args args = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.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 str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, en_US}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() != fr_FR); + assert(context.locale() == en_US); + } + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, fr_FR}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() == fr_FR); + assert(context.locale() != en_US); + } +#endif +} + +void test() { + test >, char>(); + test >, wchar_t>(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/locale.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// 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-has-no-localization + +// REQUIRES: locale.en_US.UTF-8 +// REQUIRES: locale.fr_FR.UTF-8 + +// + +// std::locale locale(); + +#include +#include + +#include "test_macros.h" +#include "platform_support.h" // locale name macros +#include "make_string.h" + +template +void test() { + std::locale en_US{LOCALE_en_US_UTF_8}; + std::locale fr_FR{LOCALE_fr_FR_UTF_8}; + std::basic_string string = MAKE_STRING(CharT, "string"); + std::basic_format_args args = + std::make_format_args, CharT>( + true, CharT('a'), 42, string); + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, en_US}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() != fr_FR); + assert(context.locale() == en_US); + } + + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{out_it, args, fr_FR}; + assert(args.__size() == 4); + for (size_t i = 0, e = args.__size(); i != e; ++i) + assert(context.arg(i) == args.get(i)); + + context.out() = CharT('a'); + assert(str.size() == 1); + assert(str.front() == CharT('a')); + + assert(context.locale() == fr_FR); + assert(context.locale() != en_US); + } +} + +void test() { + test >, char>(); + test >, wchar_t>(); +#ifndef _LIBCPP_NO_HAS_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; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/out.pass.cpp @@ -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 + +// + +// iterator out(); + +#include +#include + +#include "test_macros.h" + +template +void test( + std::basic_format_args > args) { + { + std::basic_string str; + OutIt out_it{str}; + std::basic_format_context context{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 >, char> >())); + test(std::basic_format_args( + std::make_format_args >, + wchar_t> >())); +#ifndef _LIBCPP_NO_HAS_CHAR8_T + test(std::basic_format_args( + std::make_format_args >, + char8_t> >())); +#endif +#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS + test(std::basic_format_args( + std::make_format_args >, + char16_t> >())); + test(std::basic_format_args( + std::make_format_args >, + char32_t> >())); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/types.compile.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// Class typedefs: +// template +// class basic_format_context { +// public: +// using iterator = Out +// using char_type = charT; +// template using formatter_type = formatter; +// } +// +// Namespace std typedefs: +// using format_context = basic_format_context; +// using wformat_context = basic_format_context; + +#include +#include + +#include "test_macros.h" + +template +constexpr void test() { + static_assert( + std::is_same_v::iterator, + OutIt>); + static_assert( + std::is_same_v< + typename std::basic_format_context::char_type, CharT>); + static_assert(std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert(std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v:: + template formatter_type, + std::formatter >); +#ifndef _LIBCPP_HAS_NO_INT128 + static_assert( + std::is_same_v::template formatter_type<__int128_t>, + std::formatter<__int128_t, CharT> >); + static_assert( + std::is_same_v::template formatter_type<__uint128_t>, + std::formatter<__uint128_t, CharT> >); +#endif + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); + static_assert(std::is_same_v< + typename std::basic_format_context:: + template formatter_type >, + std::formatter, CharT> >); + static_assert( + std::is_same_v::template formatter_type, + std::formatter >); +} + +constexpr void test() { + test >, char>(); + test >, wchar_t>(); + test >, char8_t>(); + test >, char16_t>(); + test >, char32_t>(); +} + +static_assert(std::is_same_v< + std::format_context, + std::basic_format_context< + std::back_insert_iterator >, char> >); +static_assert( + std::is_same_v< + std::wformat_context, + std::basic_format_context< + std::back_insert_iterator >, wchar_t> >); + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/check_arg_id.verify.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// 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 + +// constexpr void check_arg_id(size_t id); + +#include + +#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; +}