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
418659ad
Commit
418659ad
authored
Mar 03, 2018
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix compilation errors on gcc 4.4
parent
1d2adef2
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
232 additions
and
183 deletions
+232
-183
include/fmt/core.h
include/fmt/core.h
+17
-3
include/fmt/format.h
include/fmt/format.h
+156
-128
include/fmt/ostream.h
include/fmt/ostream.h
+2
-2
include/fmt/printf.h
include/fmt/printf.h
+23
-23
test/custom-formatter-test.cc
test/custom-formatter-test.cc
+1
-1
test/format-impl-test.cc
test/format-impl-test.cc
+2
-2
test/format-test.cc
test/format-test.cc
+8
-5
test/util-test.cc
test/util-test.cc
+23
-19
No files found.
include/fmt/core.h
View file @
418659ad
...
...
@@ -167,6 +167,11 @@
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif
// std::result_of is defined in <functional> in gcc 4.4.
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
# include <functional>
#endif
namespace
fmt
{
// An implementation of declval for pre-C++11 compilers such as gcc 4.
...
...
@@ -302,8 +307,6 @@ class basic_buffer {
std
::
size_t
capacity_
;
protected:
typedef
const
T
&
const_reference
;
basic_buffer
(
T
*
p
=
FMT_NULL
,
std
::
size_t
size
=
0
,
std
::
size_t
capacity
=
0
)
FMT_NOEXCEPT:
ptr_
(
p
),
size_
(
size
),
capacity_
(
capacity
)
{}
...
...
@@ -322,6 +325,7 @@ class basic_buffer {
public:
typedef
T
value_type
;
typedef
const
T
&
const_reference
;
virtual
~
basic_buffer
()
{}
...
...
@@ -655,6 +659,16 @@ enum { MAX_PACKED_ARGS = 15 };
template
<
typename
Context
>
class
arg_map
;
template
<
typename
>
struct
result_of
;
template
<
typename
F
,
typename
...
Args
>
struct
result_of
<
F
(
Args
...)
>
{
// A workaround for gcc 4.4 that doesn't allow F to be a reference.
typedef
typename
std
::
result_of
<
typename
std
::
remove_reference
<
F
>::
type
(
Args
...)
>::
type
type
;
};
}
// A formatting argument. It is a trivially copyable/constructible type to
...
...
@@ -669,7 +683,7 @@ class basic_arg {
friend
FMT_CONSTEXPR
basic_arg
<
ContextType
>
internal
::
make_arg
(
const
T
&
value
);
template
<
typename
Visitor
,
typename
Ctx
>
friend
FMT_CONSTEXPR
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
friend
FMT_CONSTEXPR
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
basic_arg
<
Ctx
>
arg
);
friend
class
basic_format_args
<
Context
>
;
...
...
include/fmt/format.h
View file @
418659ad
...
...
@@ -156,6 +156,13 @@
# endif
#endif
// A workaround for gcc 4.4 that doesn't support union members with ctors.
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
# define FMT_UNION struct
#else
# define FMT_UNION union
#endif
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
// MSVC intrinsics if the clz and clzll builtins are not available.
...
...
@@ -225,6 +232,13 @@ FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); }
template
<
typename
T
,
std
::
size_t
N
>
FMT_CONSTEXPR
T
*
end
(
T
(
&
array
)[
N
])
FMT_NOEXCEPT
{
return
array
+
N
;
}
// For std::result_of in gcc 4.4.
template
<
typename
Result
>
struct
function
{
template
<
typename
T
>
struct
result
{
typedef
Result
type
;
};
};
struct
dummy_int
{
int
data
[
2
];
operator
int
()
const
{
return
0
;
}
...
...
@@ -1016,7 +1030,7 @@ struct monostate {};
\endrst
*/
template
<
typename
Visitor
,
typename
Context
>
FMT_CONSTEXPR
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
FMT_CONSTEXPR
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
basic_arg
<
Context
>
arg
)
{
typedef
typename
Context
::
char_type
char_type
;
switch
(
arg
.
type_
)
{
...
...
@@ -1051,7 +1065,7 @@ FMT_CONSTEXPR typename std::result_of<Visitor(int)>::type
case
internal
:
:
custom_type
:
return
vis
(
typename
basic_arg
<
Context
>::
handle
(
arg
.
value_
.
custom
));
}
return
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
();
return
typename
internal
::
result_of
<
Visitor
(
int
)
>::
type
();
}
enum
alignment
{
...
...
@@ -1405,33 +1419,35 @@ class arg_formatter_base {
write
(
value
);
}
void
operator
()(
char_type
value
)
{
struct
spec_handler
:
internal
::
error_handler
{
arg_formatter_base
&
formatter
;
char_type
value
;
struct
char_spec_handler
:
internal
::
error_handler
{
arg_formatter_base
&
formatter
;
char_type
value
;
spec_handler
(
arg_formatter_base
&
f
,
char_type
val
)
:
formatter
(
f
),
value
(
val
)
{}
char_
spec_handler
(
arg_formatter_base
&
f
,
char_type
val
)
:
formatter
(
f
),
value
(
val
)
{}
void
on_int
()
{
formatter
.
writer_
.
write_int
(
value
,
formatter
.
specs_
);
}
void
on_char
()
{
formatter
.
write_char
(
value
);
}
};
internal
::
handle_char_specs
(
specs_
,
spec_handler
(
*
this
,
value
));
void
on_int
()
{
formatter
.
writer_
.
write_int
(
value
,
formatter
.
specs_
);
}
void
on_char
()
{
formatter
.
write_char
(
value
);
}
};
void
operator
()(
char_type
value
)
{
internal
::
handle_char_specs
(
specs_
,
char_spec_handler
(
*
this
,
value
));
}
void
operator
()(
const
char_type
*
value
)
{
struct
spec_handler
:
internal
::
error_handler
{
arg_formatter_base
&
formatter
;
const
char_type
*
value
;
struct
cstring_spec_handler
:
internal
::
error_handler
{
arg_formatter_base
&
formatter
;
const
char_type
*
value
;
spec_handler
(
arg_formatter_base
&
f
,
const
char_type
*
val
)
:
formatter
(
f
),
value
(
val
)
{}
cstring_
spec_handler
(
arg_formatter_base
&
f
,
const
char_type
*
val
)
:
formatter
(
f
),
value
(
val
)
{}
void
on_string
()
{
formatter
.
write
(
value
);
}
void
on_pointer
()
{
formatter
.
write_pointer
(
value
);
}
};
void
on_string
()
{
formatter
.
write
(
value
);
}
void
on_pointer
()
{
formatter
.
write_pointer
(
value
);
}
};
void
operator
()(
const
char_type
*
value
)
{
internal
::
handle_cstring_type_spec
(
specs_
.
type_
,
spec_handler
(
*
this
,
value
));
specs_
.
type_
,
cstring_
spec_handler
(
*
this
,
value
));
}
void
operator
()(
basic_string_view
<
char_type
>
value
)
{
...
...
@@ -1480,20 +1496,20 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
}
template
<
typename
Char
,
typename
Context
>
class
custom_formatter
{
class
custom_formatter
:
public
function
<
bool
>
{
private:
Context
&
ctx_
;
public:
explicit
custom_formatter
(
Context
&
ctx
)
:
ctx_
(
ctx
)
{}
bool
operator
()(
typename
basic_arg
<
Context
>::
handle
h
)
{
bool
operator
()(
typename
basic_arg
<
Context
>::
handle
h
)
const
{
h
.
format
(
ctx_
);
return
true
;
}
template
<
typename
T
>
bool
operator
()(
T
)
{
return
false
;
}
bool
operator
()(
T
)
const
{
return
false
;
}
};
template
<
typename
T
>
...
...
@@ -1505,12 +1521,13 @@ struct is_integer {
};
template
<
typename
ErrorHandler
>
class
width_checker
{
class
width_checker
:
public
function
<
unsigned
long
long
>
{
public:
explicit
FMT_CONSTEXPR
width_checker
(
ErrorHandler
&
eh
)
:
handler_
(
eh
)
{}
template
<
typename
T
>
FMT_CONSTEXPR
typename
std
::
enable_if
<
FMT_CONSTEXPR
typename
std
::
enable_if
<
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
value
)
{
if
(
is_negative
(
value
))
handler_
.
on_error
(
"negative width"
);
...
...
@@ -1529,7 +1546,7 @@ class width_checker {
};
template
<
typename
ErrorHandler
>
class
precision_checker
{
class
precision_checker
:
public
function
<
unsigned
long
long
>
{
public:
explicit
FMT_CONSTEXPR
precision_checker
(
ErrorHandler
&
eh
)
:
handler_
(
eh
)
{}
...
...
@@ -1716,7 +1733,7 @@ struct arg_ref {
}
Kind
kind
;
union
{
FMT_UNION
{
unsigned
index
;
basic_string_view
<
Char
>
name
;
};
...
...
@@ -2103,7 +2120,8 @@ void handle_dynamic_spec(
/** The default argument formatter. */
template
<
typename
Range
>
class
arg_formatter
:
public
internal
::
arg_formatter_base
<
Range
>
{
class
arg_formatter
:
public
internal
::
function
<
void
>
,
public
internal
::
arg_formatter_base
<
Range
>
{
private:
typedef
typename
Range
::
value_type
char_type
;
typedef
decltype
(
internal
::
declval
<
Range
>
().
begin
())
iterator
;
...
...
@@ -2129,7 +2147,7 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
using
base
::
operator
();
/** Formats an argument of a custom (user-defined) type. */
void
operator
()(
typename
basic_arg
<
context_type
>::
handle
handle
)
{
void
operator
()(
typename
basic_arg
<
context_type
>::
handle
handle
)
const
{
handle
.
format
(
ctx_
);
}
};
...
...
@@ -2516,10 +2534,10 @@ class basic_writer {
Formats *value* and writes it to the buffer.
\endrst
*/
template
<
typename
T
,
typename
...
FormatSpecs
>
template
<
typename
T
,
typename
FormatSpec
,
typename
...
FormatSpecs
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
void
>::
type
write
(
T
value
,
FormatSpecs
...
specs
)
{
format_specs
s
(
specs
...);
write
(
T
value
,
FormatSpec
spec
,
FormatSpec
s
...
specs
)
{
format_specs
s
(
spec
,
spec
s
...);
s
.
align_
=
ALIGN_RIGHT
;
write_int
(
value
,
s
);
}
...
...
@@ -2619,48 +2637,50 @@ void basic_writer<Range>::write_str(
write_str
(
data
,
size
,
spec
);
}
template
<
typename
Range
>
template
<
typename
T
>
void
basic_writer
<
Range
>::
write_double
(
T
value
,
const
format_specs
&
spec
)
{
// Check type.
struct
spec_handler
{
char_type
type
;
bool
upper
;
template
<
typename
Char
>
struct
float_spec_handler
{
Char
type
;
bool
upper
;
explicit
spec_handler
(
char_type
t
)
:
type
(
t
),
upper
(
false
)
{}
explicit
float_spec_handler
(
Char
t
)
:
type
(
t
),
upper
(
false
)
{}
void
on_general
()
{
if
(
type
==
'G'
)
upper
=
true
;
else
type
=
'g'
;
}
void
on_general
()
{
if
(
type
==
'G'
)
upper
=
true
;
else
type
=
'g'
;
}
void
on_exp
()
{
if
(
type
==
'E'
)
upper
=
true
;
}
void
on_exp
()
{
if
(
type
==
'E'
)
upper
=
true
;
}
void
on_fixed
()
{
if
(
type
==
'F'
)
{
upper
=
true
;
void
on_fixed
()
{
if
(
type
==
'F'
)
{
upper
=
true
;
#if FMT_MSC_VER
// MSVC's printf doesn't support 'F'.
type
=
'f'
;
// MSVC's printf doesn't support 'F'.
type
=
'f'
;
#endif
}
}
}
void
on_hex
()
{
if
(
type
==
'A'
)
upper
=
true
;
}
void
on_hex
()
{
if
(
type
==
'A'
)
upper
=
true
;
}
void
on_error
()
{
FMT_THROW
(
format_error
(
"invalid type specifier"
));
}
};
spec_handler
handler
(
spec
.
type
());
void
on_error
()
{
FMT_THROW
(
format_error
(
"invalid type specifier"
));
}
};
template
<
typename
Range
>
template
<
typename
T
>
void
basic_writer
<
Range
>::
write_double
(
T
value
,
const
format_specs
&
spec
)
{
// Check type.
float_spec_handler
<
char_type
>
handler
(
spec
.
type
());
internal
::
handle_float_type_spec
(
spec
.
type
(),
handler
);
char
sign
=
0
;
...
...
@@ -3049,7 +3069,17 @@ struct formatter<T, Char,
// }
// };
template
<
typename
Char
=
char
>
struct
dynamic_formatter
{
class
dynamic_formatter
{
private:
struct
null_handler
:
internal
::
error_handler
{
void
on_align
(
alignment
)
{}
void
on_plus
()
{}
void
on_minus
()
{}
void
on_space
()
{}
void
on_hash
()
{}
};
public:
template
<
typename
ParseContext
>
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
auto
it
=
internal
::
null_terminating_iterator
<
Char
>
(
ctx
);
...
...
@@ -3062,13 +3092,6 @@ struct dynamic_formatter {
template
<
typename
T
,
typename
FormatContext
>
auto
format
(
const
T
&
val
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
handle_specs
(
ctx
);
struct
null_handler
:
internal
::
error_handler
{
void
on_align
(
alignment
)
{}
void
on_plus
()
{}
void
on_minus
()
{}
void
on_space
()
{}
void
on_hash
()
{}
};
internal
::
specs_checker
<
null_handler
>
checker
(
null_handler
(),
internal
::
get_type
<
FormatContext
,
T
>::
value
);
checker
.
on_align
(
specs_
.
align
());
...
...
@@ -3115,66 +3138,70 @@ typename basic_context<Range, Char>::format_arg
return
arg
;
}
/** Formats arguments and writes the output to the buffer. */
template
<
typename
ArgFormatter
,
typename
Char
,
typename
Context
>
typename
Context
::
iterator
do_vformat_to
(
typename
ArgFormatter
::
range
out
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
Context
>
args
)
{
struct
format_handler
:
internal
::
error_handler
{
typedef
internal
::
null_terminating_iterator
<
Char
>
iterator
;
typedef
typename
ArgFormatter
::
range
range
;
struct
handler
:
internal
::
error_handler
{
handler
(
range
r
,
basic_string_view
<
Char
>
str
,
basic_format_args
<
Context
>
format_args
)
:
context
(
r
.
begin
(),
str
,
format_args
)
{}
void
on_text
(
iterator
begin
,
iterator
end
)
{
size_t
size
=
end
-
begin
;
auto
out
=
context
.
begin
();
auto
&&
it
=
internal
::
reserve
(
out
,
size
);
it
=
std
::
copy_n
(
begin
,
size
,
it
);
context
.
advance_to
(
out
);
}
format_handler
(
range
r
,
basic_string_view
<
Char
>
str
,
basic_format_args
<
Context
>
format_args
)
:
context
(
r
.
begin
(),
str
,
format_args
)
{}
void
on_arg_id
()
{
arg
=
context
.
next_arg
();
}
void
on_arg_id
(
unsigned
id
)
{
context
.
parse_context
().
check_arg_id
(
id
);
arg
=
context
.
get_arg
(
id
);
}
void
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
arg
=
context
.
get_arg
(
id
);
}
void
on_text
(
iterator
begin
,
iterator
end
)
{
size_t
size
=
end
-
begin
;
auto
out
=
context
.
begin
();
auto
&&
it
=
internal
::
reserve
(
out
,
size
);
it
=
std
::
copy_n
(
begin
,
size
,
it
);
context
.
advance_to
(
out
);
}
void
on_replacement_field
(
iterator
it
)
{
context
.
parse_context
().
advance_to
(
pointer_from
(
it
));
using
internal
::
custom_formatter
;
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
context
),
arg
))
return
;
basic_format_specs
<
Char
>
specs
;
visit
(
ArgFormatter
(
context
,
specs
),
arg
);
}
void
on_arg_id
()
{
arg
=
context
.
next_arg
();
}
void
on_arg_id
(
unsigned
id
)
{
context
.
parse_context
().
check_arg_id
(
id
)
;
arg
=
context
.
get_arg
(
id
);
}
void
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
arg
=
context
.
get_arg
(
id
);
}
iterator
on_format_specs
(
iterator
it
)
{
auto
&
parse_ctx
=
context
.
parse_context
();
parse_ctx
.
advance_to
(
pointer_from
(
it
));
using
internal
::
custom_formatter
;
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
context
),
arg
))
return
iterator
(
parse_ctx
);
basic_format_specs
<
Char
>
specs
;
using
internal
::
specs_handler
;
internal
::
specs_checker
<
specs_handler
<
Context
>>
handler
(
specs_handler
<
Context
>
(
specs
,
context
),
arg
.
type
());
it
=
parse_format_specs
(
it
,
handler
);
if
(
*
it
!=
'}'
)
on_error
(
"missing '}' in format string"
);
parse_ctx
.
advance_to
(
pointer_from
(
it
));
visit
(
ArgFormatter
(
context
,
specs
),
arg
);
return
it
;
}
void
on_replacement_field
(
iterator
it
)
{
context
.
parse_context
().
advance_to
(
pointer_from
(
it
));
using
internal
::
custom_formatter
;
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
context
),
arg
))
return
;
basic_format_specs
<
Char
>
specs
;
visit
(
ArgFormatter
(
context
,
specs
),
arg
);
}
iterator
on_format_specs
(
iterator
it
)
{
auto
&
parse_ctx
=
context
.
parse_context
();
parse_ctx
.
advance_to
(
pointer_from
(
it
));
using
internal
::
custom_formatter
;
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
context
),
arg
))
return
iterator
(
parse_ctx
);
basic_format_specs
<
Char
>
specs
;
using
internal
::
specs_handler
;
internal
::
specs_checker
<
specs_handler
<
Context
>>
handler
(
specs_handler
<
Context
>
(
specs
,
context
),
arg
.
type
());
it
=
parse_format_specs
(
it
,
handler
);
if
(
*
it
!=
'}'
)
on_error
(
"missing '}' in format string"
);
parse_ctx
.
advance_to
(
pointer_from
(
it
));
visit
(
ArgFormatter
(
context
,
specs
),
arg
);
return
it
;
}
Context
context
;
basic_arg
<
Context
>
arg
;
};
Context
context
;
basic_arg
<
Context
>
arg
;
}
h
(
out
,
format_str
,
args
);
/** Formats arguments and writes the output to the buffer. */
template
<
typename
ArgFormatter
,
typename
Char
,
typename
Context
>
typename
Context
::
iterator
do_vformat_to
(
typename
ArgFormatter
::
range
out
,
basic_string_view
<
Char
>
format_str
,
basic_format_args
<
Context
>
args
)
{
typedef
internal
::
null_terminating_iterator
<
Char
>
iterator
;
format_handler
<
ArgFormatter
,
Char
,
Context
>
h
(
out
,
format_str
,
args
);
parse_format_string
(
iterator
(
format_str
.
begin
(),
format_str
.
end
()),
h
);
return
h
.
context
.
begin
();
}
...
...
@@ -3250,7 +3277,8 @@ arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
return
arg_join
<
It
,
wchar_t
>
(
begin
,
end
,
sep
);
}
#if FMT_USE_TRAILING_RETURN
// The following causes ICE in gcc 4.4.
#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
template
<
typename
Range
>
auto
join
(
const
Range
&
range
,
string_view
sep
)
->
arg_join
<
decltype
(
internal
::
begin
(
range
)),
char
>
{
...
...
include/fmt/ostream.h
View file @
418659ad
...
...
@@ -61,8 +61,8 @@ class convert_to_int<T, Char, true> {
private:
template
<
typename
U
>
static
decltype
(
std
::
declval
<
test_stream
<
Char
>&>
()
<<
std
::
declval
<
U
>
(),
std
::
true_type
()
)
test
(
int
);
internal
::
declval
<
test_stream
<
Char
>&>
(
)
<<
internal
::
declval
<
U
>
(),
std
::
true_type
())
test
(
int
);
template
<
typename
>
static
std
::
false_type
test
(...);
...
...
include/fmt/printf.h
View file @
418659ad
...
...
@@ -19,7 +19,7 @@ namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template
<
bool
IsSigned
>
struct
IntC
hecker
{
struct
int_c
hecker
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
unsigned
max
=
std
::
numeric_limits
<
int
>::
max
();
...
...
@@ -29,7 +29,7 @@ struct IntChecker {
};
template
<
>
struct
IntC
hecker
<
true
>
{
struct
int_c
hecker
<
true
>
{
template
<
typename
T
>
static
bool
fits_in_int
(
T
value
)
{
return
value
>=
std
::
numeric_limits
<
int
>::
min
()
&&
...
...
@@ -38,12 +38,12 @@ struct IntChecker<true> {
static
bool
fits_in_int
(
int
)
{
return
true
;
}
};
class
PrintfPrecisionHandler
{
class
printf_precision_handler
:
public
function
<
int
>
{
public:
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
int
>::
type
operator
()(
T
value
)
{
if
(
!
IntC
hecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
fits_in_int
(
value
))
if
(
!
int_c
hecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
fits_in_int
(
value
))
FMT_THROW
(
format_error
(
"number is too big"
));
return
static_cast
<
int
>
(
value
);
}
...
...
@@ -57,7 +57,7 @@ class PrintfPrecisionHandler {
};
// An argument visitor that returns true iff arg is a zero integer.
class
IsZeroInt
{
class
is_zero_int
:
public
function
<
bool
>
{
public:
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
bool
>::
type
...
...
@@ -77,7 +77,7 @@ struct make_unsigned_or_bool<bool> {
};
template
<
typename
T
,
typename
Context
>
class
ArgConverter
{
class
arg_converter
:
public
function
<
void
>
{
private:
typedef
typename
Context
::
char_type
Char
;
...
...
@@ -85,7 +85,7 @@ class ArgConverter {
typename
Context
::
char_type
type_
;
public:
ArgC
onverter
(
basic_arg
<
Context
>
&
arg
,
Char
type
)
arg_c
onverter
(
basic_arg
<
Context
>
&
arg
,
Char
type
)
:
arg_
(
arg
),
type_
(
type
)
{}
void
operator
()(
bool
value
)
{
...
...
@@ -134,19 +134,19 @@ class ArgConverter {
// unsigned).
template
<
typename
T
,
typename
Context
,
typename
Char
>
void
convert_arg
(
basic_arg
<
Context
>
&
arg
,
Char
type
)
{
visit
(
ArgC
onverter
<
T
,
Context
>
(
arg
,
type
),
arg
);
visit
(
arg_c
onverter
<
T
,
Context
>
(
arg
,
type
),
arg
);
}
// Converts an integer argument to char for printf.
template
<
typename
Context
>
class
CharConverter
{
class
char_converter
:
public
function
<
void
>
{
private:
basic_arg
<
Context
>
&
arg_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
CharC
onverter
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
char_c
onverter
);
public:
explicit
CharC
onverter
(
basic_arg
<
Context
>
&
arg
)
:
arg_
(
arg
)
{}
explicit
char_c
onverter
(
basic_arg
<
Context
>
&
arg
)
:
arg_
(
arg
)
{}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
>::
type
...
...
@@ -163,16 +163,16 @@ class CharConverter {
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template
<
typename
Char
>
class
PrintfWidthHandler
{
class
printf_width_handler
:
public
function
<
unsigned
>
{
private:
typedef
basic_format_specs
<
Char
>
format_specs
;
format_specs
&
spec_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
PrintfWidthH
andler
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
printf_width_h
andler
);
public:
explicit
PrintfWidthH
andler
(
format_specs
&
spec
)
:
spec_
(
spec
)
{}
explicit
printf_width_h
andler
(
format_specs
&
spec
)
:
spec_
(
spec
)
{}
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
unsigned
>::
type
...
...
@@ -213,10 +213,11 @@ class basic_printf_context;
\endrst
*/
template
<
typename
Range
>
class
printf_arg_formatter
:
public
internal
::
arg_formatter_base
<
Range
>
{
class
printf_arg_formatter
:
public
internal
::
function
<
void
>
,
public
internal
::
arg_formatter_base
<
Range
>
{
private:
typedef
typename
Range
::
value_type
char_type
;
typedef
decltype
(
std
::
declval
<
Range
>
().
begin
())
iterator
;
typedef
decltype
(
internal
::
declval
<
Range
>
().
begin
())
iterator
;
typedef
internal
::
arg_formatter_base
<
Range
>
base
;
typedef
basic_printf_context
<
iterator
,
char_type
>
context_type
;
...
...
@@ -417,7 +418,7 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
}
else
if
(
*
it
==
'*'
)
{
++
it
;
spec
.
width_
=
visit
(
internal
::
PrintfWidthH
andler
<
char_type
>
(
spec
),
get_arg
(
it
));
visit
(
internal
::
printf_width_h
andler
<
char_type
>
(
spec
),
get_arg
(
it
));
}
return
arg_index
;
}
...
...
@@ -453,14 +454,14 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
}
else
if
(
*
it
==
'*'
)
{
++
it
;
spec
.
precision_
=
visit
(
internal
::
PrintfPrecisionH
andler
(),
get_arg
(
it
));
visit
(
internal
::
printf_precision_h
andler
(),
get_arg
(
it
));
}
else
{
spec
.
precision_
=
0
;
}
}
format_arg
arg
=
get_arg
(
it
,
arg_index
);
if
(
spec
.
flag
(
HASH_FLAG
)
&&
visit
(
internal
::
IsZeroI
nt
(),
arg
))
if
(
spec
.
flag
(
HASH_FLAG
)
&&
visit
(
internal
::
is_zero_i
nt
(),
arg
))
spec
.
flags_
&=
~
internal
::
to_unsigned
<
int
>
(
HASH_FLAG
);
if
(
spec
.
fill_
==
'0'
)
{
if
(
arg
.
is_arithmetic
())
...
...
@@ -514,7 +515,7 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
break
;
case
'c'
:
// TODO: handle wchar_t
visit
(
internal
::
CharC
onverter
<
basic_printf_context
>
(
arg
),
arg
);
visit
(
internal
::
char_c
onverter
<
basic_printf_context
>
(
arg
),
arg
);
break
;
}
}
...
...
@@ -539,8 +540,7 @@ struct printf_context {
std
::
back_insert_iterator
<
Buffer
>
,
typename
Buffer
::
value_type
>
type
;
};
typedef
basic_format_args
<
typename
printf_context
<
internal
::
buffer
>::
type
>
printf_args
;
typedef
basic_format_args
<
printf_context
<
internal
::
buffer
>::
type
>
printf_args
;
inline
std
::
string
vsprintf
(
string_view
format
,
printf_args
args
)
{
memory_buffer
buffer
;
...
...
@@ -565,7 +565,7 @@ inline std::string sprintf(string_view format_str, const Args & ... args) {
inline
std
::
wstring
vsprintf
(
wstring_view
format
,
basic_format_args
<
typename
printf_context
<
internal
::
wbuffer
>::
type
>
args
)
{
basic_format_args
<
printf_context
<
internal
::
wbuffer
>::
type
>
args
)
{
wmemory_buffer
buffer
;
printf
(
buffer
,
format
,
args
);
return
to_string
(
buffer
);
...
...
test/custom-formatter-test.cc
View file @
418659ad
...
...
@@ -18,7 +18,7 @@ class CustomArgFormatter :
public
fmt
::
arg_formatter
<
fmt
::
back_insert_range
<
fmt
::
internal
::
buffer
>>
{
public:
typedef
fmt
::
back_insert_range
<
fmt
::
internal
::
buffer
>
range
;
typedef
decltype
(
std
::
declval
<
range
>
().
begin
())
iterator
;
typedef
decltype
(
fmt
::
internal
::
declval
<
range
>
().
begin
())
iterator
;
typedef
fmt
::
arg_formatter
<
range
>
base
;
CustomArgFormatter
(
fmt
::
basic_context
<
iterator
,
char
>
&
ctx
,
...
...
test/format-impl-test.cc
View file @
418659ad
...
...
@@ -44,7 +44,7 @@
#undef max
template
<
typename
T
>
struct
ValueExtractor
{
struct
ValueExtractor
:
fmt
::
internal
::
function
<
T
>
{
T
operator
()(
T
value
)
{
return
value
;
}
...
...
@@ -59,7 +59,7 @@ struct ValueExtractor {
TEST
(
FormatTest
,
ArgConverter
)
{
long
long
value
=
std
::
numeric_limits
<
long
long
>::
max
();
auto
arg
=
fmt
::
internal
::
make_arg
<
fmt
::
context
>
(
value
);
visit
(
fmt
::
internal
::
ArgC
onverter
<
long
long
,
fmt
::
context
>
(
arg
,
'd'
),
arg
);
visit
(
fmt
::
internal
::
arg_c
onverter
<
long
long
,
fmt
::
context
>
(
arg
,
'd'
),
arg
);
EXPECT_EQ
(
value
,
visit
(
ValueExtractor
<
long
long
>
(),
arg
));
}
...
...
test/format-test.cc
View file @
418659ad
...
...
@@ -1205,7 +1205,9 @@ TEST(FormatterTest, FormatPointer) {
EXPECT_EQ
(
"0x"
+
std
::
string
(
sizeof
(
void
*
)
*
CHAR_BIT
/
4
,
'f'
),
format
(
"{0}"
,
reinterpret_cast
<
void
*>
(
~
uintptr_t
())));
EXPECT_EQ
(
"0x1234"
,
format
(
"{}"
,
fmt
::
ptr
(
reinterpret_cast
<
int
*>
(
0x1234
))));
EXPECT_EQ
(
"0x0"
,
format
(
"{}"
,
nullptr
));
#if FMT_USE_NULLPTR
EXPECT_EQ
(
"0x0"
,
format
(
"{}"
,
FMT_NULL
));
#endif
}
TEST
(
FormatterTest
,
FormatString
)
{
...
...
@@ -1450,7 +1452,7 @@ TEST(FormatTest, JoinArg) {
EXPECT_EQ
(
L"(1, 2, 3)"
,
format
(
L"({})"
,
join
(
v1
,
v1
+
3
,
L", "
)));
EXPECT_EQ
(
"1, 2, 3"
,
format
(
"{0:{1}}"
,
join
(
v1
,
v1
+
3
,
", "
),
1
));
#if FMT_
HAS_GXX_CXX11
#if FMT_
USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405)
EXPECT_EQ
(
"(1, 2, 3)"
,
format
(
"({})"
,
join
(
v1
,
", "
)));
EXPECT_EQ
(
"(+01.20, +03.40)"
,
format
(
"({:+06.2f})"
,
join
(
v2
,
", "
)));
#endif
...
...
@@ -1551,7 +1553,8 @@ TEST(FormatTest, FixedEnum) {
typedef
fmt
::
back_insert_range
<
fmt
::
internal
::
buffer
>
buffer_range
;
class
mock_arg_formatter
:
class
mock_arg_formatter
:
public
fmt
::
internal
::
function
<
void
>
,
public
fmt
::
internal
::
arg_formatter_base
<
buffer_range
>
{
private:
MOCK_METHOD1
(
call
,
void
(
int
value
));
...
...
@@ -1602,8 +1605,8 @@ template <>
struct
formatter
<
variant
>
:
dynamic_formatter
<>
{
auto
format
(
variant
value
,
context
&
ctx
)
->
decltype
(
ctx
.
begin
())
{
if
(
value
.
type
==
variant
::
INT
)
return
dynamic_formatter
::
format
(
42
,
ctx
);
return
dynamic_formatter
::
format
(
"foo"
,
ctx
);
return
dynamic_formatter
<>
::
format
(
42
,
ctx
);
return
dynamic_formatter
<>
::
format
(
"foo"
,
ctx
);
}
};
}
...
...
test/util-test.cc
View file @
418659ad
...
...
@@ -478,12 +478,12 @@ bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) {
}
}
template
<
typename
T
>
struct
MockVisitor
{
// Use a unique result type to make sure that there are no undesirable
// conversions.
struct
Result
{};
// Use a unique result type to make sure that there are no undesirable
// conversions.
struct
Result
{};
template
<
typename
T
>
struct
MockVisitor
:
fmt
::
internal
::
function
<
Result
>
{
MockVisitor
()
{
ON_CALL
(
*
this
,
visit
(
_
)).
WillByDefault
(
Return
(
Result
()));
}
...
...
@@ -529,8 +529,9 @@ VISIT_TYPE(float, double);
fmt::visit(visitor, make_arg<fmt::basic_context<iterator, Char>>(value)); \
}
#define CHECK_ARG(value) { \
typename VisitType<decltype(value)>::Type expected = value; \
#define CHECK_ARG(value, typename_) { \
typedef decltype(value) value_type; \
typename_ VisitType<value_type>::Type expected = value; \
CHECK_ARG_(char, expected, value) \
CHECK_ARG_(wchar_t, expected, value) \
}
...
...
@@ -556,9 +557,9 @@ typename std::enable_if<std::is_floating_point<T>::value, T>::type
}
TYPED_TEST
(
NumericArgTest
,
MakeAndVisit
)
{
CHECK_ARG
(
test_value
<
TypeParam
>
());
CHECK_ARG
(
std
::
numeric_limits
<
TypeParam
>::
min
());
CHECK_ARG
(
std
::
numeric_limits
<
TypeParam
>::
max
());
CHECK_ARG
(
test_value
<
TypeParam
>
()
,
typename
);
CHECK_ARG
(
std
::
numeric_limits
<
TypeParam
>::
min
()
,
typename
);
CHECK_ARG
(
std
::
numeric_limits
<
TypeParam
>::
max
()
,
typename
);
}
TEST
(
UtilTest
,
CharArg
)
{
...
...
@@ -594,22 +595,25 @@ TEST(UtilTest, PointerArg) {
const
void
*
cp
=
0
;
CHECK_ARG_
(
char
,
cp
,
p
);
CHECK_ARG_
(
wchar_t
,
cp
,
p
);
CHECK_ARG
(
cp
);
CHECK_ARG
(
cp
,
);
}
TEST
(
UtilTest
,
CustomArg
)
{
::
Test
test
;
typedef
typename
fmt
::
basic_arg
<
fmt
::
context
>::
handle
handle
;
typedef
MockVisitor
<
handle
>
visitor
;
testing
::
StrictMock
<
visitor
>
v
;
EXPECT_CALL
(
v
,
visit
(
_
)).
WillOnce
(
testing
::
Invoke
([
&
](
handle
h
)
{
struct
check_custom
{
Result
operator
()(
fmt
::
basic_arg
<
fmt
::
context
>::
handle
h
)
const
{
fmt
::
memory_buffer
buffer
;
fmt
::
internal
::
basic_buffer
<
char
>
&
base
=
buffer
;
fmt
::
context
ctx
(
std
::
back_inserter
(
base
),
""
,
fmt
::
format_args
());
h
.
format
(
ctx
);
EXPECT_EQ
(
"test"
,
std
::
string
(
buffer
.
data
(),
buffer
.
size
()));
return
visitor
::
Result
();
}));
return
Result
();
}
};
TEST
(
UtilTest
,
CustomArg
)
{
::
Test
test
;
typedef
MockVisitor
<
fmt
::
basic_arg
<
fmt
::
context
>::
handle
>
visitor
;
testing
::
StrictMock
<
visitor
>
v
;
EXPECT_CALL
(
v
,
visit
(
_
)).
WillOnce
(
testing
::
Invoke
(
check_custom
()));
fmt
::
visit
(
v
,
make_arg
<
fmt
::
context
>
(
test
));
}
...
...
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