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
d9db8981
Commit
d9db8981
authored
Apr 28, 2014
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor action classes, Action -> Sink, add comments.
parent
d2bf0733
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
197 additions
and
141 deletions
+197
-141
format-test.cc
format-test.cc
+33
-22
format.cc
format.cc
+5
-4
format.h
format.h
+159
-115
No files found.
format-test.cc
View file @
d9db8981
...
...
@@ -1479,32 +1479,43 @@ TEST(StringRefTest, ConvertToString) {
EXPECT_EQ
(
"abc"
,
s
);
}
struct
CountCalls
{
int
&
num_calls
;
TEST
(
FormatterTest
,
Ctor
)
{
fmt
::
Formatter
<>
f1
(
"test"
);
fmt
::
Formatter
<>
f1copy
(
f1
);
fmt
::
Formatter
<>
f2
(
"test"
,
fmt
::
NullSink
());
fmt
::
Formatter
<
fmt
::
NullSink
>
f3
(
"test"
);
fmt
::
Formatter
<
fmt
::
NullSink
,
wchar_t
>
f4
(
L"test"
);
fmt
::
Formatter
<
fmt
::
NullSink
,
wchar_t
>
f4copy
(
f4
);
fmt
::
Formatter
<
fmt
::
NullSink
,
wchar_t
>
f5
(
L"test"
,
fmt
::
NullSink
());
}
// A sink that counts the number of times the output is written to it.
struct
CountingSink
{
int
&
num_writes
;
CountCalls
(
int
&
num_calls
)
:
num_calls
(
num_call
s
)
{}
explicit
CountingSink
(
int
&
num_calls
)
:
num_writes
(
num_write
s
)
{}
void
operator
()(
const
Writer
&
)
const
{
++
num_
call
s
;
++
num_
write
s
;
}
};
TEST
(
FormatterTest
,
Action
)
{
int
num_
call
s
=
0
;
TEST
(
FormatterTest
,
Sink
)
{
int
num_
write
s
=
0
;
{
fmt
::
Formatter
<
Count
Calls
>
af
(
"test"
,
CountCalls
(
num_call
s
));
EXPECT_EQ
(
0
,
num_
call
s
);
fmt
::
Formatter
<
Count
ingSink
>
f
(
"test"
,
CountingSink
(
num_write
s
));
EXPECT_EQ
(
0
,
num_
write
s
);
}
EXPECT_EQ
(
1
,
num_
call
s
);
EXPECT_EQ
(
1
,
num_
write
s
);
}
TEST
(
FormatterTest
,
ActionNotCalled
OnError
)
{
int
num_
call
s
=
0
;
TEST
(
FormatterTest
,
OutputNotWritten
OnError
)
{
int
num_
write
s
=
0
;
{
typedef
fmt
::
Formatter
<
Count
Calls
>
TestFormatter
;
EXPECT_THROW
(
TestFormatter
af
(
"{0"
,
CountCalls
(
num_call
s
)),
FormatError
);
typedef
fmt
::
Formatter
<
Count
ingSink
>
TestFormatter
;
EXPECT_THROW
(
TestFormatter
f
(
"{0"
,
CountingSink
(
num_write
s
)),
FormatError
);
}
EXPECT_EQ
(
0
,
num_
call
s
);
EXPECT_EQ
(
0
,
num_
write
s
);
}
// The test doesn't compile on older compilers which follow C++03 and
...
...
@@ -1641,7 +1652,7 @@ class File {
int
fd
()
const
{
return
fd_
;
}
};
TEST
(
Color
Test
,
PrintColored
)
{
TEST
(
Format
Test
,
PrintColored
)
{
std
::
fflush
(
stdout
);
File
saved_stdio
(
dup
(
1
));
EXPECT_NE
(
-
1
,
saved_stdio
.
fd
());
...
...
@@ -1661,6 +1672,13 @@ TEST(ColorTest, PrintColored) {
#endif
#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
TEST
(
FormatTest
,
Variadic
)
{
EXPECT_EQ
(
"Hello, world!1"
,
str
(
Format
(
"Hello, {}!{}"
,
"world"
,
1
)));
EXPECT_EQ
(
L"Hello, world!1"
,
str
(
Format
(
L"Hello, {}!{}"
,
L"world"
,
1
)));
}
#endif // FMT_USE_VARIADIC_TEMPLATES
template
<
typename
T
>
std
::
string
str
(
const
T
&
value
)
{
return
fmt
::
str
(
fmt
::
Format
(
"{0}"
)
<<
value
);
...
...
@@ -1672,13 +1690,6 @@ TEST(StrTest, Convert) {
EXPECT_EQ
(
"2012-12-9"
,
s
);
}
#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
TEST
(
FormatTest
,
Variadic
)
{
EXPECT_EQ
(
"Hello, world!1"
,
str
(
Format
(
"Hello, {}!{}"
,
"world"
,
1
)));
EXPECT_EQ
(
L"Hello, world!1"
,
str
(
Format
(
L"Hello, {}!{}"
,
L"world"
,
1
)));
}
#endif // FMT_USE_VARIADIC_TEMPLATES
int
main
(
int
argc
,
char
**
argv
)
{
#ifdef _WIN32
// Disable message boxes on assertion failures.
...
...
format.cc
View file @
d9db8981
...
...
@@ -688,12 +688,13 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
writer
.
buffer_
.
append
(
start
,
s
);
}
void
fmt
::
ColorWriter
::
operator
()(
const
fmt
::
BasicWriter
<
char
>
&
w
)
const
{
void
fmt
::
ANSITerminalSink
::
operator
()(
const
fmt
::
BasicWriter
<
char
>
&
w
)
const
{
char
escape
[]
=
"
\x1b
[30m"
;
escape
[
3
]
=
'0'
+
static_cast
<
char
>
(
color_
);
std
::
fputs
(
escape
,
stdout
);
std
::
fwrite
(
w
.
data
(),
1
,
w
.
size
(),
stdout
);
std
::
fputs
(
RESET_COLOR
,
stdout
);
std
::
fputs
(
escape
,
file_
);
std
::
fwrite
(
w
.
data
(),
1
,
w
.
size
(),
file_
);
std
::
fputs
(
RESET_COLOR
,
file_
);
}
// Explicit instantiations for char.
...
...
format.h
View file @
d9db8981
...
...
@@ -805,13 +805,13 @@ class BasicWriter {
};
};
// Argument action that does nothing.
struct
Empty
ArgAction
{
// A
n a
rgument action that does nothing.
struct
Null
ArgAction
{
void
operator
()()
const
{}
};
// A wrapper around a format argument.
template
<
typename
Action
=
Empty
ArgAction
>
template
<
typename
Action
=
Null
ArgAction
>
class
BasicArg
:
public
Action
,
public
ArgInfo
{
private:
// This method is private to disallow formatting of arbitrary pointers.
...
...
@@ -1039,7 +1039,7 @@ class BasicWriter {
}
/**
*
Writes a character to the stream.
Writes a character to the stream.
*/
BasicWriter
&
operator
<<
(
char
value
)
{
*
GrowBuffer
(
1
)
=
value
;
...
...
@@ -1239,7 +1239,7 @@ class BasicFormatter {
// Here an Arg object wraps a temporary std::string which is destroyed at
// the end of the full expression. Since the string object is constructed
// before the Arg object, it will be destroyed after, so it will be alive
// in the Arg's destructor where the action is
call
ed.
// in the Arg's destructor where the action is
invok
ed.
// Note that the string object will not necessarily be alive when the
// destructor of BasicFormatter is called. Otherwise we wouldn't need
// this class.
...
...
@@ -1368,41 +1368,41 @@ inline const wchar_t *c_str(internal::FormatterProxy<wchar_t> p) {
}
/**
A
formatting action that does nothing
.
A
sink that ignores output
.
*/
class
N
oAction
{
class
N
ullSink
{
public:
/**
Does nothing
. */
/**
Ignores the output
. */
template
<
typename
Char
>
void
operator
()(
const
BasicWriter
<
Char
>
&
)
const
{}
};
/**
\rst
A formatter
with an action performed when formatting is complete.
Objects of this class normally exist only as temporaries returned
by one of the formatting functions. You can use this class to create
your own functions similar to
:cpp:func:`fmt::Format()`.
A formatter
that sends output to a sink. Objects of this class normally
exist only as temporaries returned by one of the formatting functions.
You can use this class to create your own functions similar to
:cpp:func:`fmt::Format()`.
**Example**::
struct
PrintError
{
struct
ErrorSink
{
void operator()(const fmt::Writer &w) const {
fmt::Print("Error: {}\n") << w.str();
}
};
// Formats an error message and prints it to stdout.
fmt::Formatter<
PrintError
> ReportError(const char *format) {
fmt::Formatter f<
PrintError
>(format);
fmt::Formatter<
ErrorSink
> ReportError(const char *format) {
fmt::Formatter f<
ErrorSink
>(format);
return f;
}
ReportError("File not found: {}") << path;
\endrst
*/
template
<
typename
Action
=
NoAction
,
typename
Char
=
char
>
class
Formatter
:
private
Action
,
public
BasicFormatter
<
Char
>
{
template
<
typename
Sink
=
NullSink
,
typename
Char
=
char
>
class
Formatter
:
private
Sink
,
public
BasicFormatter
<
Char
>
{
private:
BasicWriter
<
Char
>
writer_
;
bool
inactive_
;
...
...
@@ -1412,26 +1412,44 @@ class Formatter : private Action, public BasicFormatter<Char> {
public:
/**
\rst
Constructs a formatter with a format string and a
n action
.
The
action
should be an unary function object that takes a const
reference to :cpp:class:`fmt::BasicWriter`
as an argument.
See :cpp:class:`fmt::NoAction` and :cpp:class:`fmt::Write` for
examples of action
classes.
Constructs a formatter with a format string and a
sink
.
The
sink
should be an unary function object that takes a const
reference to :cpp:class:`fmt::BasicWriter`
, representing the
formatting output, as an argument. See :cpp:class:`fmt::NullSink`
and :cpp:class:`fmt::FileSink` for examples of sink
classes.
\endrst
*/
explicit
Formatter
(
BasicStringRef
<
Char
>
format
,
Action
a
=
Action
())
:
Action
(
a
),
BasicFormatter
<
Char
>
(
writer_
,
format
.
c_str
()),
explicit
Formatter
(
BasicStringRef
<
Char
>
format
,
Sink
s
=
Sink
())
:
Sink
(
s
),
BasicFormatter
<
Char
>
(
writer_
,
format
.
c_str
()),
inactive_
(
false
)
{
}
Formatter
(
Formatter
&
f
)
:
Action
(
f
),
BasicFormatter
<
Char
>
(
writer_
,
f
.
TakeFormatString
()),
/**
\rst
A "move" constructor. Constructs a formatter transferring the format
string from other to this object. This constructor is used to return
a formatter object from a formatting function since the copy constructor
taking a const reference is disabled to prevent misuse of the API.
It is not implemented as a move constructor for compatibility with
pre-C++11 compilers, but should be treated as such.
**Example**::
fmt::Formatter<> Format(fmt::StringRef format) {
fmt::Formatter<> f(format);
return f;
}
\endrst
*/
Formatter
(
Formatter
&
other
)
:
Sink
(
other
),
BasicFormatter
<
Char
>
(
writer_
,
other
.
TakeFormatString
()),
inactive_
(
false
)
{
f
.
inactive_
=
true
;
other
.
inactive_
=
true
;
}
/**
Performs the actual formatting, invokes the action and destroys the object.
Performs the formatting, sends the output to the sink and destroys
the object.
*/
~
Formatter
()
FMT_NOEXCEPT
(
false
)
{
if
(
!
inactive_
)
{
...
...
@@ -1441,6 +1459,118 @@ class Formatter : private Action, public BasicFormatter<Char> {
}
};
/**
\rst
Formats a string similarly to Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`__.
Returns a temporary formatter object that accepts arguments via
operator ``<<``.
*format* is a format string that contains literal text and replacement
fields surrounded by braces ``{}``. The formatter object replaces the
fields with formatted arguments and stores the output in a memory buffer.
The content of the buffer can be converted to ``std::string`` with
:cpp:func:`fmt::str()` or accessed as a C string with
:cpp:func:`fmt::c_str()`.
**Example**::
std::string message = str(Format("The answer is {}") << 42);
See also `Format String Syntax`_.
\endrst
*/
inline
Formatter
<>
Format
(
StringRef
format
)
{
Formatter
<>
f
(
format
);
return
f
;
}
inline
Formatter
<
NullSink
,
wchar_t
>
Format
(
WStringRef
format
)
{
Formatter
<
NullSink
,
wchar_t
>
f
(
format
);
return
f
;
}
/** A sink that writes output to a file. */
class
FileSink
{
private:
std
::
FILE
*
file_
;
public:
FileSink
(
std
::
FILE
*
f
)
:
file_
(
f
)
{}
/** Writes the output to a file. */
void
operator
()(
const
BasicWriter
<
char
>
&
w
)
const
{
// TODO: check error
std
::
fwrite
(
w
.
data
(),
w
.
size
(),
1
,
file_
);
}
};
// Formats a string and prints it to stdout.
// Example:
// Print("Elapsed time: {0:.2f} seconds") << 1.23;
// TODO: wchar overload
inline
Formatter
<
FileSink
>
Print
(
StringRef
format
)
{
Formatter
<
FileSink
>
f
(
format
,
stdout
);
return
f
;
}
enum
Color
{
BLACK
,
RED
,
GREEN
,
YELLOW
,
BLUE
,
MAGENTA
,
CYAN
,
WHITE
};
/**
A sink that writes output to a terminal using ANSI escape sequences
to specify color.
*/
class
ANSITerminalSink
{
private:
std
::
FILE
*
file_
;
Color
color_
;
public:
ANSITerminalSink
(
std
::
FILE
*
f
,
Color
c
)
:
file_
(
f
),
color_
(
c
)
{}
/**
Writes the output to a terminal using ANSI escape sequences to
specify color.
*/
void
operator
()(
const
BasicWriter
<
char
>
&
w
)
const
;
};
/**
Formats a string and prints it to stdout using ANSI escape sequences
to specify color (experimental).
Example:
PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
*/
inline
Formatter
<
ANSITerminalSink
>
PrintColored
(
Color
c
,
StringRef
format
)
{
Formatter
<
ANSITerminalSink
>
f
(
format
,
ANSITerminalSink
(
stdout
,
c
));
return
f
;
}
#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
template
<
typename
...
Args
>
inline
Writer
Format
(
const
StringRef
&
format
,
const
Args
&
...
args
)
{
Writer
w
;
w
.
Format
(
format
,
args
...);
return
std
::
move
(
w
);
}
template
<
typename
...
Args
>
inline
WWriter
Format
(
const
WStringRef
&
format
,
const
Args
&
...
args
)
{
WWriter
w
;
w
.
Format
(
format
,
args
...);
return
std
::
move
(
w
);
}
template
<
typename
...
Args
>
void
Print
(
StringRef
format
,
const
Args
&
...
args
)
{
Writer
w
;
w
.
Format
(
format
,
args
...);
std
::
fwrite
(
w
.
data
(),
1
,
w
.
size
(),
stdout
);
}
#endif // FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
/**
Fast integer formatter.
*/
...
...
@@ -1542,92 +1672,6 @@ inline void FormatDec(char *&buffer, T value) {
internal
::
FormatDecimal
(
buffer
,
abs_value
,
num_digits
);
buffer
+=
num_digits
;
}
/**
\rst
Formats a string similarly to Python's `str.format
<http://docs.python.org/3/library/stdtypes.html#str.format>`__.
Returns a temporary formatter object that accepts arguments via
operator ``<<``.
*format* is a format string that contains literal text and replacement
fields surrounded by braces ``{}``. The formatter object replaces the
fields with formatted arguments and stores the output in a memory buffer.
The content of the buffer can be converted to ``std::string`` with
:cpp:func:`fmt::str()` or accessed as a C string with
:cpp:func:`fmt::c_str()`.
**Example**::
std::string message = str(Format("The answer is {}") << 42);
See also `Format String Syntax`_.
\endrst
*/
inline
Formatter
<>
Format
(
StringRef
format
)
{
Formatter
<>
f
(
format
);
return
f
;
}
inline
Formatter
<
NoAction
,
wchar_t
>
Format
(
WStringRef
format
)
{
Formatter
<
NoAction
,
wchar_t
>
f
(
format
);
return
f
;
}
/** A formatting action that writes formatted output to stdout. */
class
Write
{
public:
/** Writes the output to stdout. */
void
operator
()(
const
BasicWriter
<
char
>
&
w
)
const
{
std
::
fwrite
(
w
.
data
(),
1
,
w
.
size
(),
stdout
);
}
};
// Formats a string and prints it to stdout.
// Example:
// Print("Elapsed time: {0:.2f} seconds") << 1.23;
inline
Formatter
<
Write
>
Print
(
StringRef
format
)
{
Formatter
<
Write
>
f
(
format
);
return
f
;
}
enum
Color
{
BLACK
,
RED
,
GREEN
,
YELLOW
,
BLUE
,
MAGENTA
,
CYAN
,
WHITE
};
/** A formatting action that writes colored output to stdout. */
class
ColorWriter
{
private:
Color
color_
;
public:
explicit
ColorWriter
(
Color
c
)
:
color_
(
c
)
{}
/** Writes the colored output to stdout. */
void
operator
()(
const
BasicWriter
<
char
>
&
w
)
const
;
};
// Formats a string and prints it to stdout with the given color.
// Example:
// PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
inline
Formatter
<
ColorWriter
>
PrintColored
(
Color
c
,
StringRef
format
)
{
Formatter
<
ColorWriter
>
f
(
format
,
ColorWriter
(
c
));
return
f
;
}
#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
template
<
typename
...
Args
>
inline
Writer
Format
(
const
StringRef
&
format
,
const
Args
&
...
args
)
{
Writer
w
;
w
.
Format
(
format
,
args
...);
return
std
::
move
(
w
);
}
template
<
typename
...
Args
>
inline
WWriter
Format
(
const
WStringRef
&
format
,
const
Args
&
...
args
)
{
WWriter
w
;
w
.
Format
(
format
,
args
...);
return
std
::
move
(
w
);
}
#endif // FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES
}
// Restore warnings.
...
...
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