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
8668639a
Commit
8668639a
authored
Dec 13, 2018
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Get rid of null_terminating_iterator in format
parent
93fd473b
Changes
4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
222 additions
and
251 deletions
+222
-251
include/fmt/format.h
include/fmt/format.h
+67
-228
include/fmt/printf.h
include/fmt/printf.h
+124
-0
include/fmt/time.h
include/fmt/time.h
+5
-6
test/format-test.cc
test/format-test.cc
+26
-17
No files found.
include/fmt/format.h
View file @
8668639a
This diff is collapsed.
Click to expand it.
include/fmt/printf.h
View file @
8668639a
...
@@ -16,6 +16,130 @@
...
@@ -16,6 +16,130 @@
FMT_BEGIN_NAMESPACE
FMT_BEGIN_NAMESPACE
namespace
internal
{
namespace
internal
{
// An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string
// vs string_view.
template
<
typename
Char
>
class
null_terminating_iterator
{
public:
typedef
std
::
ptrdiff_t
difference_type
;
typedef
Char
value_type
;
typedef
const
Char
*
pointer
;
typedef
const
Char
&
reference
;
typedef
std
::
random_access_iterator_tag
iterator_category
;
null_terminating_iterator
()
:
ptr_
(
0
),
end_
(
0
)
{}
FMT_CONSTEXPR
null_terminating_iterator
(
const
Char
*
ptr
,
const
Char
*
end
)
:
ptr_
(
ptr
),
end_
(
end
)
{}
template
<
typename
Range
>
FMT_CONSTEXPR
explicit
null_terminating_iterator
(
const
Range
&
r
)
:
ptr_
(
r
.
begin
()),
end_
(
r
.
end
())
{}
FMT_CONSTEXPR
null_terminating_iterator
&
operator
=
(
const
Char
*
ptr
)
{
assert
(
ptr
<=
end_
);
ptr_
=
ptr
;
return
*
this
;
}
FMT_CONSTEXPR
Char
operator
*
()
const
{
return
ptr_
!=
end_
?
*
ptr_
:
Char
();
}
FMT_CONSTEXPR
null_terminating_iterator
operator
++
()
{
++
ptr_
;
return
*
this
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
++
(
int
)
{
null_terminating_iterator
result
(
*
this
);
++
ptr_
;
return
result
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
--
()
{
--
ptr_
;
return
*
this
;
}
FMT_CONSTEXPR
null_terminating_iterator
operator
+
(
difference_type
n
)
{
return
null_terminating_iterator
(
ptr_
+
n
,
end_
);
}
FMT_CONSTEXPR
null_terminating_iterator
operator
-
(
difference_type
n
)
{
return
null_terminating_iterator
(
ptr_
-
n
,
end_
);
}
FMT_CONSTEXPR
null_terminating_iterator
operator
+=
(
difference_type
n
)
{
ptr_
+=
n
;
return
*
this
;
}
FMT_CONSTEXPR
difference_type
operator
-
(
null_terminating_iterator
other
)
const
{
return
ptr_
-
other
.
ptr_
;
}
FMT_CONSTEXPR
bool
operator
!=
(
null_terminating_iterator
other
)
const
{
return
ptr_
!=
other
.
ptr_
;
}
bool
operator
>=
(
null_terminating_iterator
other
)
const
{
return
ptr_
>=
other
.
ptr_
;
}
// This should be a friend specialization pointer_from<Char> but the latter
// doesn't compile by gcc 5.1 due to a compiler bug.
template
<
typename
CharT
>
friend
FMT_CONSTEXPR_DECL
const
CharT
*
pointer_from
(
null_terminating_iterator
<
CharT
>
it
);
private:
const
Char
*
ptr_
;
const
Char
*
end_
;
};
template
<
typename
T
>
FMT_CONSTEXPR
const
T
*
pointer_from
(
const
T
*
p
)
{
return
p
;
}
template
<
typename
Char
>
FMT_CONSTEXPR
const
Char
*
pointer_from
(
null_terminating_iterator
<
Char
>
it
)
{
return
it
.
ptr_
;
}
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
// that the first character is a digit and presence of a non-digit character at
// the end.
// it: an iterator pointing to the beginning of the input range.
template
<
typename
Iterator
,
typename
ErrorHandler
>
FMT_CONSTEXPR
unsigned
parse_nonnegative_int
(
Iterator
&
it
,
ErrorHandler
&&
eh
)
{
assert
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
if
(
*
it
==
'0'
)
{
++
it
;
return
0
;
}
unsigned
value
=
0
;
// Convert to unsigned to prevent a warning.
unsigned
max_int
=
(
std
::
numeric_limits
<
int
>::
max
)();
unsigned
big
=
max_int
/
10
;
do
{
// Check for overflow.
if
(
value
>
big
)
{
value
=
max_int
+
1
;
break
;
}
value
=
value
*
10
+
unsigned
(
*
it
-
'0'
);
// Workaround for MSVC "setup_exception stack overflow" error:
auto
next
=
it
;
++
next
;
it
=
next
;
}
while
(
'0'
<=
*
it
&&
*
it
<=
'9'
);
if
(
value
>
max_int
)
eh
.
on_error
(
"number is too big"
);
return
value
;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
// signed and unsigned integers.
template
<
bool
IsSigned
>
template
<
bool
IsSigned
>
...
...
include/fmt/time.h
View file @
8668639a
...
@@ -116,17 +116,16 @@ template <typename Char>
...
@@ -116,17 +116,16 @@ template <typename Char>
struct
formatter
<
std
::
tm
,
Char
>
{
struct
formatter
<
std
::
tm
,
Char
>
{
template
<
typename
ParseContext
>
template
<
typename
ParseContext
>
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
it
=
internal
::
null_terminating_iterator
<
Char
>
(
ctx
);
auto
it
=
ctx
.
begin
(
);
if
(
*
it
==
':'
)
if
(
it
!=
ctx
.
end
()
&&
*
it
==
':'
)
++
it
;
++
it
;
auto
end
=
it
;
auto
end
=
it
;
while
(
*
end
&&
*
end
!=
'}'
)
while
(
end
!=
ctx
.
end
()
&&
*
end
!=
'}'
)
++
end
;
++
end
;
tm_format
.
reserve
(
end
-
it
+
1
);
tm_format
.
reserve
(
end
-
it
+
1
);
using
internal
::
pointer_from
;
tm_format
.
append
(
it
,
end
);
tm_format
.
append
(
pointer_from
(
it
),
pointer_from
(
end
));
tm_format
.
push_back
(
'\0'
);
tm_format
.
push_back
(
'\0'
);
return
pointer_from
(
end
)
;
return
end
;
}
}
template
<
typename
FormatContext
>
template
<
typename
FormatContext
>
...
...
test/format-test.cc
View file @
8668639a
...
@@ -193,13 +193,16 @@ TEST(UtilTest, ParseNonnegativeInt) {
...
@@ -193,13 +193,16 @@ TEST(UtilTest, ParseNonnegativeInt) {
fmt
::
print
(
"Skipping parse_nonnegative_int test
\n
"
);
fmt
::
print
(
"Skipping parse_nonnegative_int test
\n
"
);
return
;
return
;
}
}
const
char
*
s
=
"10000000000"
;
fmt
::
string_view
s
=
"10000000000"
;
auto
begin
=
s
.
begin
(),
end
=
s
.
end
();
EXPECT_THROW_MSG
(
EXPECT_THROW_MSG
(
parse_nonnegative_int
(
s
,
fmt
::
internal
::
error_handler
()),
parse_nonnegative_int
(
begin
,
end
,
fmt
::
internal
::
error_handler
()),
fmt
::
format_error
,
"number is too big"
);
fmt
::
format_error
,
"number is too big"
);
s
=
"2147483649"
;
s
=
"2147483649"
;
begin
=
s
.
begin
();
end
=
s
.
end
();
EXPECT_THROW_MSG
(
EXPECT_THROW_MSG
(
parse_nonnegative_int
(
s
,
fmt
::
internal
::
error_handler
()),
parse_nonnegative_int
(
begin
,
end
,
fmt
::
internal
::
error_handler
()),
fmt
::
format_error
,
"number is too big"
);
fmt
::
format_error
,
"number is too big"
);
}
}
...
@@ -941,6 +944,7 @@ TEST(FormatterTest, Fill) {
...
@@ -941,6 +944,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ
(
"abc**"
,
format
(
"{0:*<5}"
,
"abc"
));
EXPECT_EQ
(
"abc**"
,
format
(
"{0:*<5}"
,
"abc"
));
EXPECT_EQ
(
"**0xface"
,
format
(
"{0:*>8}"
,
reinterpret_cast
<
void
*>
(
0xface
)));
EXPECT_EQ
(
"**0xface"
,
format
(
"{0:*>8}"
,
reinterpret_cast
<
void
*>
(
0xface
)));
EXPECT_EQ
(
"foo="
,
format
(
"{:}="
,
"foo"
));
EXPECT_EQ
(
"foo="
,
format
(
"{:}="
,
"foo"
));
EXPECT_EQ
(
std
::
string
(
"
\0\0\0
*"
,
4
),
format
(
string_view
(
"{:
\0
>4}"
,
6
),
'*'
));
}
}
TEST
(
FormatterTest
,
PlusSign
)
{
TEST
(
FormatterTest
,
PlusSign
)
{
...
@@ -2087,9 +2091,10 @@ struct test_arg_id_handler {
...
@@ -2087,9 +2091,10 @@ struct test_arg_id_handler {
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
res
=
ERROR
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
res
=
ERROR
;
}
};
};
FMT_CONSTEXPR
test_arg_id_handler
parse_arg_id
(
const
char
*
s
)
{
template
<
size_t
N
>
FMT_CONSTEXPR
test_arg_id_handler
parse_arg_id
(
const
char
(
&
s
)[
N
])
{
test_arg_id_handler
h
;
test_arg_id_handler
h
;
fmt
::
internal
::
parse_arg_id
(
s
,
h
);
fmt
::
internal
::
parse_arg_id
(
s
,
s
+
N
,
h
);
return
h
;
return
h
;
}
}
...
@@ -2149,9 +2154,10 @@ struct test_format_specs_handler {
...
@@ -2149,9 +2154,10 @@ struct test_format_specs_handler {
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
res
=
ERROR
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
res
=
ERROR
;
}
};
};
FMT_CONSTEXPR
test_format_specs_handler
parse_test_specs
(
const
char
*
s
)
{
template
<
size_t
N
>
FMT_CONSTEXPR
test_format_specs_handler
parse_test_specs
(
const
char
(
&
s
)[
N
])
{
test_format_specs_handler
h
;
test_format_specs_handler
h
;
fmt
::
internal
::
parse_format_specs
(
s
,
h
);
fmt
::
internal
::
parse_format_specs
(
s
,
s
+
N
,
h
);
return
h
;
return
h
;
}
}
...
@@ -2195,11 +2201,12 @@ struct test_context {
...
@@ -2195,11 +2201,12 @@ struct test_context {
FMT_CONSTEXPR
test_context
error_handler
()
{
return
*
this
;
}
FMT_CONSTEXPR
test_context
error_handler
()
{
return
*
this
;
}
};
};
FMT_CONSTEXPR
fmt
::
format_specs
parse_specs
(
const
char
*
s
)
{
template
<
size_t
N
>
FMT_CONSTEXPR
fmt
::
format_specs
parse_specs
(
const
char
(
&
s
)[
N
])
{
fmt
::
format_specs
specs
;
fmt
::
format_specs
specs
;
test_context
ctx
{};
test_context
ctx
{};
fmt
::
internal
::
specs_handler
<
test_context
>
h
(
specs
,
ctx
);
fmt
::
internal
::
specs_handler
<
test_context
>
h
(
specs
,
ctx
);
parse_format_specs
(
s
,
h
);
parse_format_specs
(
s
,
s
+
N
,
h
);
return
specs
;
return
specs
;
}
}
...
@@ -2220,12 +2227,13 @@ TEST(FormatTest, ConstexprSpecsHandler) {
...
@@ -2220,12 +2227,13 @@ TEST(FormatTest, ConstexprSpecsHandler) {
static_assert
(
parse_specs
(
"d"
).
type
==
'd'
,
""
);
static_assert
(
parse_specs
(
"d"
).
type
==
'd'
,
""
);
}
}
template
<
size_t
N
>
FMT_CONSTEXPR
fmt
::
internal
::
dynamic_format_specs
<
char
>
FMT_CONSTEXPR
fmt
::
internal
::
dynamic_format_specs
<
char
>
parse_dynamic_specs
(
const
char
*
s
)
{
parse_dynamic_specs
(
const
char
(
&
s
)[
N
]
)
{
fmt
::
internal
::
dynamic_format_specs
<
char
>
specs
;
fmt
::
internal
::
dynamic_format_specs
<
char
>
specs
;
test_context
ctx
{};
test_context
ctx
{};
fmt
::
internal
::
dynamic_specs_handler
<
test_context
>
h
(
specs
,
ctx
);
fmt
::
internal
::
dynamic_specs_handler
<
test_context
>
h
(
specs
,
ctx
);
parse_format_specs
(
s
,
h
);
parse_format_specs
(
s
,
s
+
N
,
h
);
return
specs
;
return
specs
;
}
}
...
@@ -2246,10 +2254,11 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
...
@@ -2246,10 +2254,11 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
static_assert
(
parse_dynamic_specs
(
"d"
).
type
==
'd'
,
""
);
static_assert
(
parse_dynamic_specs
(
"d"
).
type
==
'd'
,
""
);
}
}
FMT_CONSTEXPR
test_format_specs_handler
check_specs
(
const
char
*
s
)
{
template
<
size_t
N
>
FMT_CONSTEXPR
test_format_specs_handler
check_specs
(
const
char
(
&
s
)[
N
])
{
fmt
::
internal
::
specs_checker
<
test_format_specs_handler
>
fmt
::
internal
::
specs_checker
<
test_format_specs_handler
>
checker
(
test_format_specs_handler
(),
fmt
::
internal
::
double_type
);
checker
(
test_format_specs_handler
(),
fmt
::
internal
::
double_type
);
parse_format_specs
(
s
,
checker
);
parse_format_specs
(
s
,
s
+
N
,
checker
);
return
checker
;
return
checker
;
}
}
...
@@ -2278,11 +2287,11 @@ struct test_format_string_handler {
...
@@ -2278,11 +2287,11 @@ struct test_format_string_handler {
template
<
typename
T
>
template
<
typename
T
>
FMT_CONSTEXPR
void
on_arg_id
(
T
)
{}
FMT_CONSTEXPR
void
on_arg_id
(
T
)
{}
template
<
typename
Iterator
>
FMT_CONSTEXPR
void
on_replacement_field
(
const
char
*
)
{}
FMT_CONSTEXPR
void
on_replacement_field
(
Iterator
)
{}
template
<
typename
Iterator
>
FMT_CONSTEXPR
const
char
*
on_format_specs
(
const
char
*
begin
,
const
char
*
)
{
FMT_CONSTEXPR
Iterator
on_format_specs
(
Iterator
it
)
{
return
it
;
}
return
begin
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
error
=
true
;
}
FMT_CONSTEXPR
void
on_error
(
const
char
*
)
{
error
=
true
;
}
...
...
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