Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions stl/inc/format
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ concept _Parse_spec_callbacks = requires(_Ty _At, basic_string_view<_CharT> _Sv,
{ _At._On_width(_STD declval<int>()) } -> same_as<void>;
{ _At._On_dynamic_width(_STD declval<int>()) } -> same_as<void>;
{ _At._On_dynamic_width(_STD declval<_Auto_id_tag>()) } -> same_as<void>;
{ _At._On_precision(_STD declval<int>()) } -> same_as<void>;
{ _At._On_dynamic_precision(_STD declval<int>()) } -> same_as<void>;
{ _At._On_dynamic_precision(_STD declval<_Auto_id_tag>()) } -> same_as<void>;
Comment thread
barcharcraz marked this conversation as resolved.

/* { _At._On_type(_STD declval<_CharT>()) } -> same_as<void>; */
Comment thread
barcharcraz marked this conversation as resolved.
};
template <class _Ty, class _CharT>
concept _Parse_arg_id_callbacks = requires(_Ty _At) {
Expand Down Expand Up @@ -86,6 +91,7 @@ constexpr const _CharT* _Parse_arg_id(const _CharT* _Begin, const _CharT* _End,
_Callbacks._On_auto_id();
return _Begin;
}

if (_Ch >= '0' && _Ch <= '9') {
int _Index = 0;
// arg_id is not allowed to have any leading zeros, but is allowed to be
Expand Down Expand Up @@ -161,7 +167,7 @@ template <class _CharT, _Parse_spec_callbacks<_CharT> _Callbacks_type>
struct _Width_adapter {
_Callbacks_type& _Callbacks;

explicit constexpr _Width_adapter(_Callbacks_type& _Handler) : _Callbacks(_Handler) {}
constexpr explicit _Width_adapter(_Callbacks_type& _Handler) : _Callbacks(_Handler) {}

constexpr void _On_auto_id() {
_Callbacks._On_dynamic_width(_Auto_id_tag{});
Expand All @@ -171,6 +177,22 @@ struct _Width_adapter {
}
};

// Adapts a type modeling _Parse_spec_callbacks to model _Parse_arg_id_callbacks.
// Used in _Parse_precision so that _Parse_arg_id can be used to parse dynamic precisions.
template <class _CharT, _Parse_spec_callbacks<_CharT> _Callbacks_type>
struct _Precision_adapter {
_Callbacks_type& _Callbacks;

constexpr explicit _Precision_adapter(_Callbacks_type& _Handler) : _Callbacks(_Handler) {}

constexpr void _On_auto_id() {
_Callbacks._On_dynamic_precision(_Auto_id_tag{});
}
constexpr void _On_manual_id(int _Id) {
_Callbacks._On_dynamic_precision(_Id);
}
};

template <class _CharT, _Parse_spec_callbacks<_CharT> _Callbacks_type>
constexpr const _CharT* _Parse_width(const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) {
_STL_INTERNAL_CHECK(_Begin != _End);
Expand All @@ -181,7 +203,7 @@ constexpr const _CharT* _Parse_width(const _CharT* _Begin, const _CharT* _End, _
} else if (*_Begin == '{') {
++_Begin;
if (_Begin != _End) {
_Begin = _Parse_arg_id(_Begin, _End, _Width_adapter<_CharT, _Callbacks_type>(_Callbacks));
_Begin = _Parse_arg_id(_Begin, _End, _Width_adapter<_CharT, _Callbacks_type>{_Callbacks});
}
if (_Begin == _End || *_Begin != '}') {
throw format_error("Invalid format string.");
Expand All @@ -191,6 +213,33 @@ constexpr const _CharT* _Parse_width(const _CharT* _Begin, const _CharT* _End, _
return _Begin;
}

template <class _CharT, _Parse_spec_callbacks<_CharT> _Callbacks_type>
constexpr const _CharT* _Parse_precision(const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) {
Comment thread
barcharcraz marked this conversation as resolved.
Comment thread
barcharcraz marked this conversation as resolved.
++_Begin;
Comment thread
barcharcraz marked this conversation as resolved.
Comment thread
StephanTLavavej marked this conversation as resolved.
_CharT _Ch = '\0';
if (_Begin != _End) {
_Ch = *_Begin;
}

if ('0' <= _Ch && _Ch <= '9') {
Comment thread
barcharcraz marked this conversation as resolved.
int _Precision = 0;
_Begin = _Parse_nonnegative_integer(_Begin, _End, _Precision);
_Callbacks._On_precision(_Precision);
} else if (_Ch == '{') {
++_Begin;
if (_Begin != _End) {
_Begin = _Parse_arg_id(_Begin, _End, _Precision_adapter<_CharT, _Callbacks_type>{_Callbacks});
}

if (_Begin == _End || *_Begin != '}') {
throw format_error("Invalid format string.");
Comment thread
barcharcraz marked this conversation as resolved.
}
} else {
throw format_error("Missing precision specifier.");
}
return _Begin;
}

template <class _Ty, class _CharT = char>
struct formatter;

Expand Down
90 changes: 69 additions & 21 deletions tests/std/tests/P0645R10_text_formatting_parsing/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ template <typename CharT>
struct testing_callbacks {
_Align expected_alignment = _Align::_None;
basic_string_view<CharT> expected_fill;
int expected_width = -1;
int expected_dynamic_width = -1;
bool expected_auto_dynamic_width = false;
int expected_width = -1;
int expected_dynamic_width = -1;
bool expected_auto_dynamic_width = false;
int expected_precision = -1;
int expected_dynamic_precision = -1;
bool expected_auto_dynamic_precision = false;
constexpr void _On_align(_Align aln) {
assert(aln == expected_alignment);
}
Expand All @@ -51,6 +54,15 @@ struct testing_callbacks {
constexpr void _On_dynamic_width(_Auto_id_tag) {
assert(expected_auto_dynamic_width);
}
constexpr void _On_precision(int pre) {
assert(pre == expected_precision);
}
constexpr void _On_dynamic_precision(int id) {
assert(id == expected_dynamic_precision);
}
constexpr void _On_dynamic_precision(_Auto_id_tag) {
assert(expected_auto_dynamic_precision);
}
};
template <typename CharT>
testing_callbacks(_Align, basic_string_view<CharT>) -> testing_callbacks<CharT>;
Expand Down Expand Up @@ -81,10 +93,10 @@ constexpr bool test_parse_align() {
auto parse_align_fn = _Parse_align<CharT, testing_callbacks<CharT>>;
using view_typ = basic_string_view<CharT>;

auto s0 = view_typ(TYPED_LITERAL(CharT, ""));
auto s1 = view_typ(TYPED_LITERAL(CharT, "*<"));
auto s2 = view_typ(TYPED_LITERAL(CharT, "*>"));
auto s3 = view_typ(TYPED_LITERAL(CharT, "*^"));
view_typ s0(TYPED_LITERAL(CharT, ""));
view_typ s1(TYPED_LITERAL(CharT, "*<"));
view_typ s2(TYPED_LITERAL(CharT, "*>"));
view_typ s3(TYPED_LITERAL(CharT, "*^"));

test_parse_helper(parse_align_fn, s0, false, view_typ::npos, {_Align::_None, view_typ(TYPED_LITERAL(CharT, ""))});
test_parse_helper(parse_align_fn, s1, false, view_typ::npos, {_Align::_Left, view_typ(TYPED_LITERAL(CharT, "*"))});
Expand All @@ -108,12 +120,12 @@ constexpr bool test_parse_width() {
auto parse_width_fn = _Parse_width<CharT, testing_callbacks<CharT>>;
using view_typ = basic_string_view<CharT>;

auto s0 = view_typ(TYPED_LITERAL(CharT, "1"));
auto s1 = view_typ(TYPED_LITERAL(CharT, "{1}"));
auto s2 = view_typ(TYPED_LITERAL(CharT, "{0}"));
auto s3 = view_typ(TYPED_LITERAL(CharT, "{}"));
auto i0 = view_typ(TYPED_LITERAL(CharT, "0"));
auto i1 = view_typ(TYPED_LITERAL(CharT, "01"));
view_typ s0(TYPED_LITERAL(CharT, "1"));
view_typ s1(TYPED_LITERAL(CharT, "{1}"));
view_typ s2(TYPED_LITERAL(CharT, "{0}"));
view_typ s3(TYPED_LITERAL(CharT, "{}"));
view_typ i0(TYPED_LITERAL(CharT, "0"));
view_typ i1(TYPED_LITERAL(CharT, "01"));

test_parse_helper(parse_width_fn, s0, false, view_typ::npos, {.expected_width = 1});
test_parse_helper(parse_width_fn, s1, false, view_typ::npos, {.expected_dynamic_width = 1});
Expand All @@ -130,14 +142,14 @@ constexpr bool test_parse_arg_id() {
using view_typ = basic_string_view<CharT>;
// note that parse arg id starts with the arg id itself, not the { beginning of the
// format spec
auto s0 = view_typ(TYPED_LITERAL(CharT, "}"));
auto s1 = view_typ(TYPED_LITERAL(CharT, ":"));
auto s2 = view_typ(TYPED_LITERAL(CharT, ":}"));
auto s3 = view_typ(TYPED_LITERAL(CharT, "0:}"));
auto s4 = view_typ(TYPED_LITERAL(CharT, "0:"));
auto s5 = view_typ(TYPED_LITERAL(CharT, "1}"));
auto i0 = view_typ(TYPED_LITERAL(CharT, "01}"));
auto i1 = view_typ(TYPED_LITERAL(CharT, "0"));
view_typ s0(TYPED_LITERAL(CharT, "}"));
view_typ s1(TYPED_LITERAL(CharT, ":"));
view_typ s2(TYPED_LITERAL(CharT, ":}"));
view_typ s3(TYPED_LITERAL(CharT, "0:}"));
view_typ s4(TYPED_LITERAL(CharT, "0:"));
view_typ s5(TYPED_LITERAL(CharT, "1}"));
view_typ i0(TYPED_LITERAL(CharT, "01}"));
view_typ i1(TYPED_LITERAL(CharT, "0"));

test_parse_helper(parse_arg_id_fn, s0, false, 0);
test_parse_helper(parse_arg_id_fn, s1, false, 0);
Expand All @@ -156,6 +168,38 @@ constexpr bool test_parse_arg_id() {
return true;
}

template <typename CharT>
constexpr bool test_parse_precision() {
Comment thread
barcharcraz marked this conversation as resolved.
auto parse_pre_fn = _Parse_precision<CharT, testing_callbacks<CharT>>;
using view_typ = basic_string_view<CharT>;

view_typ s0(TYPED_LITERAL(CharT, ".0"));
view_typ s1(TYPED_LITERAL(CharT, ".1"));
view_typ s2(TYPED_LITERAL(CharT, ".12"));
view_typ s3(TYPED_LITERAL(CharT, ".{1}"));
view_typ s4(TYPED_LITERAL(CharT, ".{}"));

view_typ i0(TYPED_LITERAL(CharT, ".{ }"));
view_typ i1(TYPED_LITERAL(CharT, "."));
view_typ i2(TYPED_LITERAL(CharT, ".{ |"));
view_typ i3(TYPED_LITERAL(CharT, ".{"));

test_parse_helper(parse_pre_fn, s0, false, view_typ::npos, {.expected_precision = 0});
test_parse_helper(parse_pre_fn, s1, false, view_typ::npos, {.expected_precision = 1});
test_parse_helper(parse_pre_fn, s2, false, view_typ::npos, {.expected_precision = 12});
test_parse_helper(parse_pre_fn, s3, false, view_typ::npos, {.expected_dynamic_precision = 1});
test_parse_helper(parse_pre_fn, s4, false, view_typ::npos, {.expected_auto_dynamic_precision = true});

if (!is_constant_evaluated()) {
test_parse_helper(parse_pre_fn, i0, true);
test_parse_helper(parse_pre_fn, i1, true);
test_parse_helper(parse_pre_fn, i2, true);
test_parse_helper(parse_pre_fn, i3, true);
}

return true;
}

int main() {
test_parse_align<char>();
test_parse_align<wchar_t>();
Expand All @@ -169,5 +213,9 @@ int main() {
test_parse_width<wchar_t>();
static_assert(test_parse_width<char>());
static_assert(test_parse_width<wchar_t>());
test_parse_precision<char>();
test_parse_precision<wchar_t>();
static_assert(test_parse_precision<char>());
static_assert(test_parse_precision<wchar_t>());
return 0;
}