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
10e70a06
Commit
10e70a06
authored
Dec 02, 2017
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve handling of custom arguments
parent
e0243000
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
46 additions
and
64 deletions
+46
-64
include/fmt/format.h
include/fmt/format.h
+23
-8
include/fmt/printf.h
include/fmt/printf.h
+15
-12
test/custom-formatter-test.cc
test/custom-formatter-test.cc
+0
-35
test/format-test.cc
test/format-test.cc
+1
-1
test/util-test.cc
test/util-test.cc
+7
-8
No files found.
include/fmt/format.h
View file @
10e70a06
...
@@ -1385,7 +1385,22 @@ class basic_arg {
...
@@ -1385,7 +1385,22 @@ class basic_arg {
friend
class
basic_args
<
Context
>
;
friend
class
basic_args
<
Context
>
;
friend
class
internal
::
arg_map
<
Context
>
;
friend
class
internal
::
arg_map
<
Context
>
;
using
char_type
=
typename
Context
::
char_type
;
public:
public:
class
handle
{
public:
explicit
handle
(
internal
::
custom_value
<
char_type
>
custom
)
:
custom_
(
custom
)
{}
void
format
(
basic_buffer
<
char_type
>
&
buf
,
Context
&
ctx
)
{
custom_
.
format
(
buf
,
custom_
.
value
,
&
ctx
);
}
private:
internal
::
custom_value
<
char_type
>
custom_
;
};
constexpr
basic_arg
()
:
type_
(
internal
::
NONE
)
{}
constexpr
basic_arg
()
:
type_
(
internal
::
NONE
)
{}
explicit
operator
bool
()
const
noexcept
{
return
type_
!=
internal
::
NONE
;
}
explicit
operator
bool
()
const
noexcept
{
return
type_
!=
internal
::
NONE
;
}
...
@@ -1407,7 +1422,7 @@ class basic_arg {
...
@@ -1407,7 +1422,7 @@ class basic_arg {
template
<
typename
Visitor
,
typename
Context
>
template
<
typename
Visitor
,
typename
Context
>
constexpr
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
constexpr
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
basic_arg
<
Context
>
arg
)
{
visit
(
Visitor
&&
vis
,
basic_arg
<
Context
>
arg
)
{
typedef
typename
Context
::
char_type
Char
;
using
char_type
=
typename
Context
::
char_type
;
switch
(
arg
.
type_
)
{
switch
(
arg
.
type_
)
{
case
internal
:
:
NONE
:
case
internal
:
:
NONE
:
return
vis
(
monostate
());
return
vis
(
monostate
());
...
@@ -1425,7 +1440,7 @@ constexpr typename std::result_of<Visitor(int)>::type
...
@@ -1425,7 +1440,7 @@ constexpr typename std::result_of<Visitor(int)>::type
case
internal
:
:
BOOL
:
case
internal
:
:
BOOL
:
return
vis
(
arg
.
value_
.
int_value
!=
0
);
return
vis
(
arg
.
value_
.
int_value
!=
0
);
case
internal
:
:
CHAR
:
case
internal
:
:
CHAR
:
return
vis
(
static_cast
<
Char
>
(
arg
.
value_
.
int_value
));
return
vis
(
static_cast
<
char_type
>
(
arg
.
value_
.
int_value
));
case
internal
:
:
DOUBLE
:
case
internal
:
:
DOUBLE
:
return
vis
(
arg
.
value_
.
double_value
);
return
vis
(
arg
.
value_
.
double_value
);
case
internal
:
:
LONG_DOUBLE
:
case
internal
:
:
LONG_DOUBLE
:
...
@@ -1433,12 +1448,12 @@ constexpr typename std::result_of<Visitor(int)>::type
...
@@ -1433,12 +1448,12 @@ constexpr typename std::result_of<Visitor(int)>::type
case
internal
:
:
CSTRING
:
case
internal
:
:
CSTRING
:
return
vis
(
arg
.
value_
.
string
.
value
);
return
vis
(
arg
.
value_
.
string
.
value
);
case
internal
:
:
STRING
:
case
internal
:
:
STRING
:
return
vis
(
basic_string_view
<
Char
>
(
return
vis
(
basic_string_view
<
char_type
>
(
arg
.
value_
.
string
.
value
,
arg
.
value_
.
string
.
size
));
arg
.
value_
.
string
.
value
,
arg
.
value_
.
string
.
size
));
case
internal
:
:
POINTER
:
case
internal
:
:
POINTER
:
return
vis
(
arg
.
value_
.
pointer
);
return
vis
(
arg
.
value_
.
pointer
);
case
internal
:
:
CUSTOM
:
case
internal
:
:
CUSTOM
:
return
vis
(
arg
.
value_
.
custom
);
return
vis
(
typename
basic_arg
<
Context
>::
handle
(
arg
.
value_
.
custom
)
);
}
}
return
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
();
return
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
();
}
}
...
@@ -2161,8 +2176,8 @@ class custom_formatter {
...
@@ -2161,8 +2176,8 @@ class custom_formatter {
custom_formatter
(
basic_buffer
<
Char
>
&
buffer
,
Context
&
ctx
)
custom_formatter
(
basic_buffer
<
Char
>
&
buffer
,
Context
&
ctx
)
:
buffer_
(
buffer
),
ctx_
(
ctx
)
{}
:
buffer_
(
buffer
),
ctx_
(
ctx
)
{}
bool
operator
()(
internal
::
custom_value
<
Char
>
custom
)
{
bool
operator
()(
typename
basic_arg
<
Context
>::
handle
h
)
{
custom
.
format
(
buffer_
,
custom
.
value
,
&
ctx_
);
h
.
format
(
buffer_
,
ctx_
);
return
true
;
return
true
;
}
}
...
@@ -2795,8 +2810,8 @@ class arg_formatter : public internal::arg_formatter_base<Char> {
...
@@ -2795,8 +2810,8 @@ class arg_formatter : public internal::arg_formatter_base<Char> {
using
internal
::
arg_formatter_base
<
Char
>::
operator
();
using
internal
::
arg_formatter_base
<
Char
>::
operator
();
/** Formats an argument of a custom (user-defined) type. */
/** Formats an argument of a custom (user-defined) type. */
void
operator
()(
internal
::
custom_value
<
Char
>
c
)
{
void
operator
()(
typename
basic_arg
<
basic_context
<
Char
>>::
handle
handle
)
{
c
.
format
(
this
->
writer
().
buffer
(),
c
.
value
,
&
ctx_
);
handle
.
format
(
this
->
writer
().
buffer
(),
ctx_
);
}
}
};
};
...
...
include/fmt/printf.h
View file @
10e70a06
...
@@ -200,6 +200,13 @@ class PrintfWidthHandler {
...
@@ -200,6 +200,13 @@ class PrintfWidthHandler {
};
};
}
// namespace internal
}
// namespace internal
template
<
typename
Char
>
class
printf_arg_formatter
;
template
<
typename
Char
,
typename
ArgFormatter
=
printf_arg_formatter
<
Char
>
>
class
printf_context
;
/**
/**
\rst
\rst
The ``printf`` argument formatter.
The ``printf`` argument formatter.
...
@@ -208,6 +215,8 @@ class PrintfWidthHandler {
...
@@ -208,6 +215,8 @@ class PrintfWidthHandler {
template
<
typename
Char
>
template
<
typename
Char
>
class
printf_arg_formatter
:
public
internal
::
arg_formatter_base
<
Char
>
{
class
printf_arg_formatter
:
public
internal
::
arg_formatter_base
<
Char
>
{
private:
private:
printf_context
<
Char
>&
context_
;
void
write_null_pointer
()
{
void
write_null_pointer
()
{
this
->
spec
().
type_
=
0
;
this
->
spec
().
type_
=
0
;
this
->
write
(
"(nil)"
);
this
->
write
(
"(nil)"
);
...
@@ -225,8 +234,9 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
...
@@ -225,8 +234,9 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
specifier information for standard argument types.
specifier information for standard argument types.
\endrst
\endrst
*/
*/
printf_arg_formatter
(
basic_buffer
<
Char
>
&
buffer
,
format_specs
&
spec
)
printf_arg_formatter
(
:
internal
::
arg_formatter_base
<
Char
>
(
buffer
,
spec
)
{}
basic_buffer
<
Char
>
&
buffer
,
format_specs
&
spec
,
printf_context
<
Char
>
&
ctx
)
:
internal
::
arg_formatter_base
<
Char
>
(
buffer
,
spec
),
context_
(
ctx
)
{}
using
Base
::
operator
();
using
Base
::
operator
();
...
@@ -268,18 +278,11 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
...
@@ -268,18 +278,11 @@ class printf_arg_formatter : public internal::arg_formatter_base<Char> {
}
}
/** Formats an argument of a custom (user-defined) type. */
/** Formats an argument of a custom (user-defined) type. */
void
operator
()(
internal
::
custom_value
<
Char
>
c
)
{
void
operator
()(
typename
basic_arg
<
printf_context
<
Char
>>::
handle
handle
)
{
const
Char
format_str
[]
=
{
'}'
,
'\0'
};
handle
.
format
(
this
->
writer
().
buffer
(),
context_
);
auto
args
=
basic_args
<
basic_context
<
Char
>>
();
basic_context
<
Char
>
ctx
(
basic_string_view
<
Char
>
(
format_str
),
args
);
c
.
format
(
this
->
writer
().
buffer
(),
c
.
value
,
&
ctx
);
}
}
};
};
template
<
typename
Char
,
typename
ArgFormatter
=
printf_arg_formatter
<
Char
>
>
class
printf_context
;
template
<
typename
T
,
typename
Char
=
char
>
template
<
typename
T
,
typename
Char
=
char
>
struct
printf_formatter
{
struct
printf_formatter
{
template
<
typename
ParseContext
>
template
<
typename
ParseContext
>
...
@@ -506,7 +509,7 @@ void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
...
@@ -506,7 +509,7 @@ void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
start
=
it
;
start
=
it
;
// Format argument.
// Format argument.
visit
(
AF
(
buffer
,
spec
),
arg
);
visit
(
AF
(
buffer
,
spec
,
*
this
),
arg
);
}
}
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
));
buffer
.
append
(
pointer_from
(
start
),
pointer_from
(
it
));
}
}
...
...
test/custom-formatter-test.cc
View file @
10e70a06
...
@@ -29,22 +29,6 @@ class CustomArgFormatter : public fmt::arg_formatter<char> {
...
@@ -29,22 +29,6 @@ class CustomArgFormatter : public fmt::arg_formatter<char> {
}
}
};
};
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class
CustomPrintfArgFormatter
:
public
printf_arg_formatter
<
char
>
{
public:
CustomPrintfArgFormatter
(
fmt
::
buffer
&
buf
,
fmt
::
format_specs
&
spec
)
:
printf_arg_formatter
<
char
>
(
buf
,
spec
)
{}
using
printf_arg_formatter
<
char
>::
operator
();
void
operator
()(
double
value
)
{
if
(
round
(
value
*
pow
(
10
,
spec
().
precision
()))
==
0
)
value
=
0
;
printf_arg_formatter
<
char
>::
operator
()(
value
);
}
};
std
::
string
custom_vformat
(
fmt
::
string_view
format_str
,
fmt
::
args
args
)
{
std
::
string
custom_vformat
(
fmt
::
string_view
format_str
,
fmt
::
args
args
)
{
fmt
::
memory_buffer
buffer
;
fmt
::
memory_buffer
buffer
;
// Pass custom argument formatter as a template arg to vwrite.
// Pass custom argument formatter as a template arg to vwrite.
...
@@ -58,25 +42,6 @@ std::string custom_format(const char *format_str, const Args & ... args) {
...
@@ -58,25 +42,6 @@ std::string custom_format(const char *format_str, const Args & ... args) {
return
custom_vformat
(
format_str
,
va
);
return
custom_vformat
(
format_str
,
va
);
}
}
typedef
fmt
::
printf_context
<
char
,
CustomPrintfArgFormatter
>
CustomPrintfFormatter
;
std
::
string
custom_vsprintf
(
const
char
*
format_str
,
fmt
::
basic_args
<
CustomPrintfFormatter
>
args
)
{
fmt
::
memory_buffer
buffer
;
CustomPrintfFormatter
formatter
(
format_str
,
args
);
formatter
.
format
(
buffer
);
return
std
::
string
(
buffer
.
data
(),
buffer
.
size
());
}
template
<
typename
...
Args
>
std
::
string
custom_sprintf
(
const
char
*
format_str
,
const
Args
&
...
args
)
{
auto
va
=
fmt
::
make_args
<
CustomPrintfFormatter
>
(
args
...);
return
custom_vsprintf
(
format_str
,
va
);
}
TEST
(
CustomFormatterTest
,
Format
)
{
TEST
(
CustomFormatterTest
,
Format
)
{
EXPECT_EQ
(
"0.00"
,
custom_format
(
"{:.2f}"
,
-
.00001
));
EXPECT_EQ
(
"0.00"
,
custom_format
(
"{:.2f}"
,
-
.00001
));
EXPECT_EQ
(
"0.00"
,
custom_sprintf
(
"%.2f"
,
-
.00001
));
}
}
test/format-test.cc
View file @
10e70a06
...
@@ -1509,7 +1509,7 @@ class MockArgFormatter : public fmt::internal::arg_formatter_base<char> {
...
@@ -1509,7 +1509,7 @@ class MockArgFormatter : public fmt::internal::arg_formatter_base<char> {
void
operator
()(
int
value
)
{
call
(
value
);
}
void
operator
()(
int
value
)
{
call
(
value
);
}
void
operator
()(
fmt
::
internal
::
custom_value
<
char
>
)
{}
void
operator
()(
fmt
::
basic_arg
<
fmt
::
context
>::
handle
)
{}
};
};
void
custom_vformat
(
fmt
::
string_view
format_str
,
fmt
::
args
args
)
{
void
custom_vformat
(
fmt
::
string_view
format_str
,
fmt
::
args
args
)
{
...
...
test/util-test.cc
View file @
10e70a06
...
@@ -590,18 +590,17 @@ TEST(UtilTest, PointerArg) {
...
@@ -590,18 +590,17 @@ TEST(UtilTest, PointerArg) {
TEST
(
UtilTest
,
CustomArg
)
{
TEST
(
UtilTest
,
CustomArg
)
{
::
Test
test
;
::
Test
test
;
typedef
MockVisitor
<
fmt
::
internal
::
custom_value
<
char
>>
Visitor
;
using
handle
=
typename
fmt
::
basic_arg
<
fmt
::
context
>::
handle
;
testing
::
StrictMock
<
Visitor
>
visitor
;
using
visitor
=
MockVisitor
<
handle
>
;
EXPECT_CALL
(
visitor
,
visit
(
_
)).
WillOnce
(
testing
::
StrictMock
<
visitor
>
v
;
testing
::
Invoke
([
&
](
fmt
::
internal
::
custom_value
<
char
>
custom
)
{
EXPECT_CALL
(
v
,
visit
(
_
)).
WillOnce
(
testing
::
Invoke
([
&
](
handle
h
)
{
EXPECT_EQ
(
&
test
,
custom
.
value
);
fmt
::
memory_buffer
buffer
;
fmt
::
memory_buffer
buffer
;
fmt
::
context
ctx
(
""
,
fmt
::
args
());
fmt
::
context
ctx
(
""
,
fmt
::
args
());
custom
.
format
(
buffer
,
&
test
,
&
ctx
);
h
.
format
(
buffer
,
ctx
);
EXPECT_EQ
(
"test"
,
std
::
string
(
buffer
.
data
(),
buffer
.
size
()));
EXPECT_EQ
(
"test"
,
std
::
string
(
buffer
.
data
(),
buffer
.
size
()));
return
V
isitor
::
Result
();
return
v
isitor
::
Result
();
}));
}));
fmt
::
visit
(
v
isitor
,
make_arg
<
fmt
::
context
>
(
test
));
fmt
::
visit
(
v
,
make_arg
<
fmt
::
context
>
(
test
));
}
}
TEST
(
ArgVisitorTest
,
VisitInvalidArg
)
{
TEST
(
ArgVisitorTest
,
VisitInvalidArg
)
{
...
...
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