Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
1b5ccf6c
Commit
1b5ccf6c
authored
Oct 15, 2017
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make parse_arg_id constexpr
parent
17f93fe0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
66 additions
and
19 deletions
+66
-19
fmt/format.h
fmt/format.h
+29
-19
test/format-test.cc
test/format-test.cc
+37
-0
No files found.
fmt/format.h
View file @
1b5ccf6c
...
@@ -365,7 +365,7 @@ class basic_string_view {
...
@@ -365,7 +365,7 @@ class basic_string_view {
the size with ``std::char_traits<Char>::length``.
the size with ``std::char_traits<Char>::length``.
\endrst
\endrst
*/
*/
constexpr
basic_string_view
(
const
Char
*
s
)
basic_string_view
(
const
Char
*
s
)
:
data_
(
s
),
size_
(
std
::
char_traits
<
Char
>::
length
(
s
))
{}
:
data_
(
s
),
size_
(
std
::
char_traits
<
Char
>::
length
(
s
))
{}
/**
/**
...
@@ -389,7 +389,7 @@ class basic_string_view {
...
@@ -389,7 +389,7 @@ class basic_string_view {
const
Char
*
data
()
const
{
return
data_
;
}
const
Char
*
data
()
const
{
return
data_
;
}
/** Returns the string size. */
/** Returns the string size. */
std
::
size_t
size
()
const
{
return
size_
;
}
constexpr
std
::
size_t
size
()
const
{
return
size_
;
}
const
Char
*
begin
()
const
{
return
data_
;
}
const
Char
*
begin
()
const
{
return
data_
;
}
const
Char
*
end
()
const
{
return
data_
+
size_
;
}
const
Char
*
end
()
const
{
return
data_
+
size_
;
}
...
@@ -762,7 +762,7 @@ template <typename Char>
...
@@ -762,7 +762,7 @@ template <typename Char>
class
null_terminating_iterator
;
class
null_terminating_iterator
;
template
<
typename
Char
>
template
<
typename
Char
>
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
);
const
expr
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
);
// An iterator that produces a null terminator on *end. This simplifies parsing
// An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string
// and allows comparing the performance of processing a null-terminated string
...
@@ -840,10 +840,10 @@ class null_terminating_iterator {
...
@@ -840,10 +840,10 @@ class null_terminating_iterator {
};
};
template
<
typename
T
>
template
<
typename
T
>
const
T
*
pointer_from
(
const
T
*
p
)
{
return
p
;
}
const
expr
const
T
*
pointer_from
(
const
T
*
p
)
{
return
p
;
}
template
<
typename
Char
>
template
<
typename
Char
>
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
)
{
const
expr
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
)
{
return
it
.
ptr_
;
return
it
.
ptr_
;
}
}
...
@@ -3012,7 +3012,7 @@ void arg(wstring_view, const internal::named_arg<Context>&)
...
@@ -3012,7 +3012,7 @@ void arg(wstring_view, const internal::named_arg<Context>&)
namespace
fmt
{
namespace
fmt
{
namespace
internal
{
namespace
internal
{
template
<
typename
Char
>
template
<
typename
Char
>
inline
bool
is_name_start
(
Char
c
)
{
constexpr
bool
is_name_start
(
Char
c
)
{
return
(
'a'
<=
c
&&
c
<=
'z'
)
||
(
'A'
<=
c
&&
c
<=
'Z'
)
||
'_'
==
c
;
return
(
'a'
<=
c
&&
c
<=
'z'
)
||
(
'A'
<=
c
&&
c
<=
'Z'
)
||
'_'
==
c
;
}
}
...
@@ -3020,7 +3020,7 @@ inline bool is_name_start(Char c) {
...
@@ -3020,7 +3020,7 @@ inline bool is_name_start(Char c) {
// This function assumes that the first character of it is a digit and a
// This function assumes that the first character of it is a digit and a
// presence of a non-digit character at the end.
// presence of a non-digit character at the end.
template
<
typename
Iterator
>
template
<
typename
Iterator
>
unsigned
parse_nonnegative_int
(
Iterator
&
it
)
{
constexpr
unsigned
parse_nonnegative_int
(
Iterator
&
it
)
{
assert
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
assert
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
unsigned
value
=
0
;
unsigned
value
=
0
;
do
{
do
{
...
@@ -3316,8 +3316,14 @@ class dynamic_specs_handler :
...
@@ -3316,8 +3316,14 @@ class dynamic_specs_handler :
ParseContext
&
context_
;
ParseContext
&
context_
;
};
};
struct
error_handler
{
void
on_error
(
const
char
*
message
)
{
FMT_THROW
(
format_error
(
message
));
}
};
template
<
typename
Iterator
,
typename
Handler
>
template
<
typename
Iterator
,
typename
Handler
>
Iterator
parse_arg_id
(
Iterator
it
,
Handler
handler
)
{
constexpr
Iterator
parse_arg_id
(
Iterator
it
,
Handler
&
handler
)
{
using
char_type
=
typename
std
::
iterator_traits
<
Iterator
>::
value_type
;
using
char_type
=
typename
std
::
iterator_traits
<
Iterator
>::
value_type
;
char_type
c
=
*
it
;
char_type
c
=
*
it
;
if
(
c
==
'}'
||
c
==
':'
)
{
if
(
c
==
'}'
||
c
==
':'
)
{
...
@@ -3326,13 +3332,17 @@ Iterator parse_arg_id(Iterator it, Handler handler) {
...
@@ -3326,13 +3332,17 @@ Iterator parse_arg_id(Iterator it, Handler handler) {
}
}
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
unsigned
index
=
parse_nonnegative_int
(
it
);
unsigned
index
=
parse_nonnegative_int
(
it
);
if
(
*
it
!=
'}'
&&
*
it
!=
':'
)
if
(
*
it
!=
'}'
&&
*
it
!=
':'
)
{
FMT_THROW
(
format_error
(
"invalid format string"
));
handler
.
on_error
(
"invalid format string"
);
return
it
;
}
handler
(
index
);
handler
(
index
);
return
it
;
return
it
;
}
}
if
(
!
is_name_start
(
c
))
if
(
!
is_name_start
(
c
))
{
FMT_THROW
(
format_error
(
"invalid format string"
));
handler
.
on_error
(
"invalid format string"
);
return
it
;
}
auto
start
=
it
;
auto
start
=
it
;
do
{
do
{
c
=
*++
it
;
c
=
*++
it
;
...
@@ -3413,7 +3423,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
...
@@ -3413,7 +3423,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
if
(
'0'
<=
*
it
&&
*
it
<=
'9'
)
{
if
(
'0'
<=
*
it
&&
*
it
<=
'9'
)
{
handler
.
on_width
(
parse_nonnegative_int
(
it
));
handler
.
on_width
(
parse_nonnegative_int
(
it
));
}
else
if
(
*
it
==
'{'
)
{
}
else
if
(
*
it
==
'{'
)
{
struct
width_handler
{
struct
width_handler
:
error_handler
{
explicit
width_handler
(
Handler
&
h
)
:
handler
(
h
)
{}
explicit
width_handler
(
Handler
&
h
)
:
handler
(
h
)
{}
void
operator
()()
{
handler
.
on_dynamic_width
(
auto_id
());
}
void
operator
()()
{
handler
.
on_dynamic_width
(
auto_id
());
}
...
@@ -3423,8 +3433,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
...
@@ -3423,8 +3433,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
}
}
Handler
&
handler
;
Handler
&
handler
;
};
}
wh
(
handler
)
;
it
=
parse_arg_id
(
it
+
1
,
w
idth_handler
(
handler
)
);
it
=
parse_arg_id
(
it
+
1
,
w
h
);
if
(
*
it
++
!=
'}'
)
if
(
*
it
++
!=
'}'
)
FMT_THROW
(
format_error
(
"invalid format string"
));
FMT_THROW
(
format_error
(
"invalid format string"
));
}
}
...
@@ -3435,7 +3445,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
...
@@ -3435,7 +3445,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
if
(
'0'
<=
*
it
&&
*
it
<=
'9'
)
{
if
(
'0'
<=
*
it
&&
*
it
<=
'9'
)
{
handler
.
on_precision
(
parse_nonnegative_int
(
it
));
handler
.
on_precision
(
parse_nonnegative_int
(
it
));
}
else
if
(
*
it
==
'{'
)
{
}
else
if
(
*
it
==
'{'
)
{
struct
precision_handler
{
struct
precision_handler
:
error_handler
{
explicit
precision_handler
(
Handler
&
h
)
:
handler
(
h
)
{}
explicit
precision_handler
(
Handler
&
h
)
:
handler
(
h
)
{}
void
operator
()()
{
handler
.
on_dynamic_precision
(
auto_id
());
}
void
operator
()()
{
handler
.
on_dynamic_precision
(
auto_id
());
}
...
@@ -3445,8 +3455,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
...
@@ -3445,8 +3455,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) {
}
}
Handler
&
handler
;
Handler
&
handler
;
};
}
ph
(
handler
)
;
it
=
parse_arg_id
(
it
+
1
,
p
recision_handler
(
handler
)
);
it
=
parse_arg_id
(
it
+
1
,
p
h
);
if
(
*
it
++
!=
'}'
)
if
(
*
it
++
!=
'}'
)
FMT_THROW
(
format_error
(
"invalid format string"
));
FMT_THROW
(
format_error
(
"invalid format string"
));
}
else
{
}
else
{
...
@@ -3652,7 +3662,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
...
@@ -3652,7 +3662,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
)
-
1
);
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
)
-
1
);
basic_arg
<
Context
>
arg
;
basic_arg
<
Context
>
arg
;
struct
id_handler
{
struct
id_handler
:
internal
::
error_handler
{
id_handler
(
Context
&
c
,
basic_arg
<
Context
>
&
a
)
:
context
(
c
),
arg
(
a
)
{}
id_handler
(
Context
&
c
,
basic_arg
<
Context
>
&
a
)
:
context
(
c
),
arg
(
a
)
{}
void
operator
()()
{
arg
=
context
.
next_arg
();
}
void
operator
()()
{
arg
=
context
.
next_arg
();
}
...
...
test/format-test.cc
View file @
1b5ccf6c
...
@@ -1581,3 +1581,40 @@ TEST(FormatTest, DynamicFormatter) {
...
@@ -1581,3 +1581,40 @@ TEST(FormatTest, DynamicFormatter) {
EXPECT_THROW_MSG
(
format
(
"{:.2}"
,
num
),
EXPECT_THROW_MSG
(
format
(
"{:.2}"
,
num
),
format_error
,
"precision not allowed in integer format specifier"
);
format_error
,
"precision not allowed in integer format specifier"
);
}
}
struct
TestHandler
{
enum
Result
{
NONE
,
EMPTY
,
INDEX
,
NAME
,
ERROR
};
Result
result
=
NONE
;
unsigned
index
=
0
;
string_view
name
;
constexpr
void
operator
()()
{
result
=
EMPTY
;
}
constexpr
void
operator
()(
unsigned
index
)
{
result
=
INDEX
;
this
->
index
=
index
;
}
constexpr
void
operator
()(
string_view
name
)
{
result
=
NAME
;
this
->
name
=
name
;
}
constexpr
void
on_error
(
const
char
*
)
{
result
=
ERROR
;
}
};
constexpr
TestHandler
parse_arg_id
(
const
char
*
id
)
{
TestHandler
h
;
fmt
::
internal
::
parse_arg_id
(
id
,
h
);
return
h
;
}
TEST
(
FormatTest
,
ConstexprParseArgId
)
{
static_assert
(
parse_arg_id
(
":"
).
result
==
TestHandler
::
EMPTY
,
""
);
static_assert
(
parse_arg_id
(
"}"
).
result
==
TestHandler
::
EMPTY
,
""
);
static_assert
(
parse_arg_id
(
"42:"
).
result
==
TestHandler
::
INDEX
,
""
);
static_assert
(
parse_arg_id
(
"42:"
).
index
==
42
,
""
);
static_assert
(
parse_arg_id
(
"foo:"
).
result
==
TestHandler
::
NAME
,
""
);
static_assert
(
parse_arg_id
(
"foo:"
).
name
.
size
()
==
3
,
""
);
static_assert
(
parse_arg_id
(
"!"
).
result
==
TestHandler
::
ERROR
,
""
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment