forked from OSchip/llvm-project
[libc++][format] Add basic_format_parse_context.
Implements parts of: - P0645 Text Formatting Depends on D92214 Reviewed By: ldionne, curdeius, #libc Differential Revision: https://reviews.llvm.org/D93166
This commit is contained in:
parent
c73c23f2a9
commit
35a57f39b5
|
|
@ -19,14 +19,51 @@ namespace std {
|
|||
explicit format_error(const string& what_arg);
|
||||
explicit format_error(const char* what_arg);
|
||||
};
|
||||
|
||||
// [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>;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#include <__config>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <version>
|
||||
|
||||
#ifdef _LIBCPP_NO_EXCEPTIONS
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
|
@ -47,6 +84,88 @@ public:
|
|||
virtual ~format_error() noexcept;
|
||||
};
|
||||
|
||||
_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY void
|
||||
__throw_format_error(const char* __s) {
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
throw format_error(__s);
|
||||
#else
|
||||
(void)__s;
|
||||
_VSTD::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class _CharT>
|
||||
class _LIBCPP_TEMPLATE_VIS basic_format_parse_context {
|
||||
public:
|
||||
using char_type = _CharT;
|
||||
using const_iterator =
|
||||
typename _VSTD::basic_string_view<_CharT>::const_iterator;
|
||||
using iterator = const_iterator;
|
||||
|
||||
public:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
constexpr explicit basic_format_parse_context(
|
||||
_VSTD::basic_string_view<_CharT> __fmt, size_t __num_args = 0) noexcept
|
||||
: __begin_(__fmt.begin()),
|
||||
__end_(__fmt.end()),
|
||||
__indexing_(__unknown),
|
||||
__next_arg_id_(0),
|
||||
__num_args_(__num_args) {}
|
||||
|
||||
basic_format_parse_context(const basic_format_parse_context&) = delete;
|
||||
basic_format_parse_context&
|
||||
operator=(const basic_format_parse_context&) = delete;
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY constexpr const_iterator begin() const noexcept {
|
||||
return __begin_;
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY constexpr const_iterator end() const noexcept {
|
||||
return __end_;
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY constexpr void advance_to(const_iterator __it) {
|
||||
__begin_ = __it;
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY constexpr size_t next_arg_id() {
|
||||
if (__indexing_ == __manual)
|
||||
__throw_format_error("Using automatic argument numbering in manual "
|
||||
"argument numbering mode");
|
||||
|
||||
if (__indexing_ == __unknown)
|
||||
__indexing_ = __automatic;
|
||||
return __next_arg_id_++;
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY constexpr void check_arg_id(size_t __id) {
|
||||
if (__indexing_ == __automatic)
|
||||
__throw_format_error("Using manual argument numbering in automatic "
|
||||
"argument numbering mode");
|
||||
|
||||
if (__indexing_ == __unknown)
|
||||
__indexing_ = __manual;
|
||||
|
||||
// Throws an exception to make the expression a non core constant
|
||||
// expression as required by:
|
||||
// [format.parse.ctx]/11
|
||||
// Remarks: Call expressions where id >= num_args_ are not core constant
|
||||
// expressions ([expr.const]).
|
||||
// Note: the Throws clause [format.parse.ctx]/10 doesn't specify the
|
||||
// behavior when id >= num_args_.
|
||||
if (_VSTD::is_constant_evaluated() && __id >= __num_args_)
|
||||
__throw_format_error("Argument index outside the valid range");
|
||||
}
|
||||
|
||||
private:
|
||||
iterator __begin_;
|
||||
iterator __end_;
|
||||
enum _Indexing { __unknown, __manual, __automatic };
|
||||
_Indexing __indexing_;
|
||||
size_t __next_arg_id_;
|
||||
size_t __num_args_;
|
||||
};
|
||||
|
||||
using format_parse_context = basic_format_parse_context<char>;
|
||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr void advance_to(const_iterator it);
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(const CharT* fmt) {
|
||||
{
|
||||
std::basic_format_parse_context<CharT> context(fmt);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == &fmt[1]);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == &fmt[2]);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == context.end());
|
||||
}
|
||||
{
|
||||
std::basic_string_view view{fmt};
|
||||
std::basic_format_parse_context context(view);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == view.begin() + 1);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == view.begin() + 2);
|
||||
|
||||
context.advance_to(context.begin() + 1);
|
||||
assert(context.begin() == context.end());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test("abc");
|
||||
test(L"abc");
|
||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||
test(u8"abc");
|
||||
#endif
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||
test(u"abc");
|
||||
test(U"abc");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr begin() const noexcept;
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(const CharT* fmt) {
|
||||
{
|
||||
std::basic_format_parse_context<CharT> context(fmt);
|
||||
assert(context.begin() == &fmt[0]);
|
||||
ASSERT_NOEXCEPT(context.begin());
|
||||
}
|
||||
{
|
||||
std::basic_string_view view{fmt};
|
||||
std::basic_format_parse_context context(view);
|
||||
assert(context.begin() == view.begin());
|
||||
ASSERT_NOEXCEPT(context.begin());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test("abc");
|
||||
test(L"abc");
|
||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||
test(u8"abc");
|
||||
#endif
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||
test(u"abc");
|
||||
test(U"abc");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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: no-exceptions
|
||||
|
||||
// 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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr void check_arg_id(size_t id);
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
constexpr bool test() {
|
||||
std::format_parse_context context("", 10);
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
context.check_arg_id(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void test_exception() {
|
||||
[] {
|
||||
std::format_parse_context context("", 1);
|
||||
context.next_arg_id();
|
||||
try {
|
||||
context.check_arg_id(0);
|
||||
assert(false);
|
||||
} catch (const std::format_error& e) {
|
||||
assert(strcmp(e.what(), "Using manual argument numbering in automatic "
|
||||
"argument numbering mode") == 0);
|
||||
return;
|
||||
}
|
||||
assert(false);
|
||||
}();
|
||||
|
||||
auto test_arg = [](size_t num_args) {
|
||||
std::format_parse_context context("", num_args);
|
||||
// Out of bounds access is valid if !std::is_constant_evaluated()
|
||||
for (size_t i = 0; i <= num_args; ++i)
|
||||
context.check_arg_id(i);
|
||||
};
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
test_arg(i);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
test_exception();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr explicit
|
||||
// basic_format_parse_context(basic_string_view<charT> fmt,
|
||||
// size_t num_args = 0) noexcept
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(const CharT* fmt) {
|
||||
// Validate the constructor is explicit.
|
||||
static_assert(
|
||||
!std::is_convertible_v<std::basic_string_view<CharT>,
|
||||
std::basic_format_parse_context<CharT> >);
|
||||
static_assert(
|
||||
!std::is_copy_constructible_v<std::basic_format_parse_context<CharT> >);
|
||||
static_assert(
|
||||
!std::is_copy_assignable_v<std::basic_format_parse_context<CharT> >);
|
||||
// The move operations are implicitly deleted due to the
|
||||
// deleted copy operations.
|
||||
static_assert(
|
||||
!std::is_move_constructible_v<std::basic_format_parse_context<CharT> >);
|
||||
static_assert(
|
||||
!std::is_move_assignable_v<std::basic_format_parse_context<CharT> >);
|
||||
|
||||
ASSERT_NOEXCEPT(
|
||||
std::basic_format_parse_context{std::basic_string_view<CharT>{}});
|
||||
ASSERT_NOEXCEPT(
|
||||
std::basic_format_parse_context{std::basic_string_view<CharT>{}, 42});
|
||||
|
||||
{
|
||||
std::basic_format_parse_context<CharT> context(fmt);
|
||||
assert(context.begin() == &fmt[0]);
|
||||
assert(context.end() == &fmt[3]);
|
||||
}
|
||||
{
|
||||
std::basic_string_view view{fmt};
|
||||
std::basic_format_parse_context context(view);
|
||||
assert(context.begin() == view.begin());
|
||||
assert(context.end() == view.end());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test("abc");
|
||||
test(L"abc");
|
||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||
test(u8"abc");
|
||||
#endif
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||
test(u"abc");
|
||||
test(U"abc");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr end() const noexcept;
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test(const CharT* fmt) {
|
||||
{
|
||||
std::basic_format_parse_context<CharT> context(fmt);
|
||||
assert(context.end() == &fmt[3]);
|
||||
ASSERT_NOEXCEPT(context.end());
|
||||
}
|
||||
{
|
||||
std::basic_string_view view{fmt};
|
||||
std::basic_format_parse_context context(view);
|
||||
assert(context.end() == view.end());
|
||||
ASSERT_NOEXCEPT(context.end());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test("abc");
|
||||
test(L"abc");
|
||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||
test(u8"abc");
|
||||
#endif
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||
test(u"abc");
|
||||
test(U"abc");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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: no-exceptions
|
||||
|
||||
// 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
|
||||
|
||||
// <format>
|
||||
|
||||
// constexpr size_t next_arg_id();
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
constexpr bool test() {
|
||||
std::format_parse_context context("");
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
assert(i == context.next_arg_id());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void test_exception() {
|
||||
std::format_parse_context context("", 1);
|
||||
context.check_arg_id(0);
|
||||
|
||||
try {
|
||||
context.next_arg_id();
|
||||
assert(false);
|
||||
} catch (const std::format_error& e) {
|
||||
assert(strcmp(e.what(), "Using automatic argument numbering in manual "
|
||||
"argument numbering mode") == 0);
|
||||
return;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
test_exception();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
|
||||
// <format>
|
||||
|
||||
// Class typedefs:
|
||||
// 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;
|
||||
// }
|
||||
//
|
||||
// Namespace std typedefs:
|
||||
// using format_parse_context = basic_format_parse_context<char>;
|
||||
// using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||
|
||||
#include <format>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class CharT>
|
||||
constexpr void test() {
|
||||
static_assert(
|
||||
std::is_same_v<typename std::basic_format_parse_context<CharT>::char_type,
|
||||
CharT>);
|
||||
static_assert(std::is_same_v<
|
||||
typename std::basic_format_parse_context<CharT>::const_iterator,
|
||||
typename std::basic_string_view<CharT>::const_iterator>);
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
typename std::basic_format_parse_context<CharT>::iterator,
|
||||
typename std::basic_format_parse_context<CharT>::const_iterator>);
|
||||
}
|
||||
|
||||
constexpr 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
|
||||
}
|
||||
|
||||
static_assert(std::is_same_v<std::format_parse_context,
|
||||
std::basic_format_parse_context<char> >);
|
||||
static_assert(std::is_same_v<std::wformat_parse_context,
|
||||
std::basic_format_parse_context<wchar_t> >);
|
||||
|
||||
// Required for MSVC internal test runner compatibility.
|
||||
int main(int, char**) { return 0; }
|
||||
Loading…
Reference in New Issue