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
3fdba049
Commit
3fdba049
authored
Jun 06, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reduce the number of nontrivial formatter instantiations
parent
f5f3ffac
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
80 additions
and
27 deletions
+80
-27
include/fmt/core.h
include/fmt/core.h
+22
-0
include/fmt/format.h
include/fmt/format.h
+55
-24
test/format-test.cc
test/format-test.cc
+3
-3
No files found.
include/fmt/core.h
View file @
3fdba049
...
...
@@ -632,6 +632,28 @@ enum type {
custom_type
};
// Maps core type T to the corresponding type enum constant.
template
<
typename
T
,
typename
Char
>
struct
type_constant
:
std
::
integral_constant
<
type
,
none_type
>
{};
#define FMT_TYPE_CONSTANT(Type, constant) \
template <typename Char> \
struct type_constant<Type, Char> : std::integral_constant<type, constant> {}
FMT_TYPE_CONSTANT
(
int
,
int_type
);
FMT_TYPE_CONSTANT
(
unsigned
,
uint_type
);
FMT_TYPE_CONSTANT
(
long
long
,
long_long_type
);
FMT_TYPE_CONSTANT
(
unsigned
long
long
,
ulong_long_type
);
FMT_TYPE_CONSTANT
(
bool
,
bool_type
);
FMT_TYPE_CONSTANT
(
Char
,
char_type
);
FMT_TYPE_CONSTANT
(
double
,
double_type
);
FMT_TYPE_CONSTANT
(
long
double
,
long_double_type
);
FMT_TYPE_CONSTANT
(
const
Char
*
,
cstring_type
);
FMT_TYPE_CONSTANT
(
basic_string_view
<
Char
>
,
string_type
);
FMT_TYPE_CONSTANT
(
const
void
*
,
pointer_type
);
#undef FMT_TYPE_CONSTANT
FMT_CONSTEXPR
bool
is_integral
(
type
t
)
{
FMT_ASSERT
(
t
!=
internal
::
named_arg_type
,
"invalid argument type"
);
return
t
>
internal
::
none_type
&&
t
<=
internal
::
last_integer_type
;
...
...
include/fmt/format.h
View file @
3fdba049
...
...
@@ -2179,7 +2179,7 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
ParseContext
&
ctx
)
{
// GCC 7.2 requires initializer.
typedef
typename
ParseContext
::
char_type
char_type
;
conditional_t
<
is_formattable
<
T
,
format_context
>::
value
,
conditional_t
<
is_formattable
<
T
,
buffer_context
<
char_type
>
>::
value
,
formatter
<
T
,
char_type
>
,
internal
::
fallback_formatter
<
T
,
char_type
>>
f
;
...
...
@@ -2255,12 +2255,6 @@ void check_format_string(S format_str) {
(
void
)
invalid_format
;
}
// Specifies whether to format T using the standard formatter.
// It is not possible to use get_type in formatter specialization directly
// because of a bug in MSVC.
template
<
typename
Context
,
typename
T
>
using
format_type
=
bool_constant
<
get_type
<
Context
,
T
>::
value
!=
custom_type
>
;
template
<
template
<
typename
>
class
Handler
,
typename
Spec
,
typename
Context
>
void
handle_dynamic_spec
(
Spec
&
value
,
arg_ref
<
typename
Context
::
char_type
>
ref
,
Context
&
ctx
,
...
...
@@ -3041,24 +3035,24 @@ class format_int {
std
::
string
str
()
const
{
return
std
::
string
(
str_
,
size
());
}
};
// Formatter of objects of type T.
// formatter specializations for the core types corresponding to internal::type
// constants.
template
<
typename
T
,
typename
Char
>
struct
formatter
<
T
,
Char
,
enable_if_t
<
internal
::
format_type
<
buffer_context
<
Char
>
,
T
>::
valu
e
>>
{
struct
formatter
<
T
,
Char
,
enable_if_t
<
internal
::
type_constant
<
T
,
Char
>::
value
!=
internal
::
none_typ
e
>>
{
FMT_CONSTEXPR
formatter
()
:
format_str_
(
nullptr
)
{}
// Parses format specifiers stopping either at the end of the range or at the
// terminating '}'.
template
<
typename
ParseContext
>
FMT_CONSTEXPR
typename
ParseContext
::
iterator
parse
(
ParseContext
&
ctx
)
{
FMT_CONSTEXPR
auto
parse
(
ParseContext
&
ctx
)
->
decltype
(
ctx
.
begin
()
)
{
format_str_
=
ctx
.
begin
();
typedef
internal
::
dynamic_specs_handler
<
ParseContext
>
handler_type
;
auto
type
=
internal
::
get_type
<
buffer_context
<
Char
>
,
T
>::
value
;
using
handler_type
=
internal
::
dynamic_specs_handler
<
ParseContext
>
;
auto
type
=
internal
::
type_constant
<
T
,
Char
>::
value
;
internal
::
specs_checker
<
handler_type
>
handler
(
handler_type
(
specs_
,
ctx
),
type
);
auto
it
=
parse_format_specs
(
ctx
.
begin
(),
ctx
.
end
(),
handler
);
auto
type_spec
=
specs_
.
type
;
auto
eh
=
ctx
.
error_handler
();
switch
(
type
)
{
case
internal
:
:
none_type
:
...
...
@@ -3070,27 +3064,27 @@ struct formatter<
case
internal
:
:
long_long_type
:
case
internal
:
:
ulong_long_type
:
case
internal
:
:
bool_type
:
handle_int_type_spec
(
type_spec
,
handle_int_type_spec
(
specs_
.
type
,
internal
::
int_type_checker
<
decltype
(
eh
)
>
(
eh
));
break
;
case
internal
:
:
char_type
:
handle_char_specs
(
&
specs_
,
internal
::
char_specs_checker
<
decltype
(
eh
)
>
(
type_spec
,
eh
));
&
specs_
,
internal
::
char_specs_checker
<
decltype
(
eh
)
>
(
specs_
.
type
,
eh
));
break
;
case
internal
:
:
double_type
:
case
internal
:
:
long_double_type
:
handle_float_type_spec
(
type_spec
,
handle_float_type_spec
(
specs_
.
type
,
internal
::
float_type_checker
<
decltype
(
eh
)
>
(
eh
));
break
;
case
internal
:
:
cstring_type
:
internal
::
handle_cstring_type_spec
(
type_spec
,
internal
::
cstring_type_checker
<
decltype
(
eh
)
>
(
eh
));
specs_
.
type
,
internal
::
cstring_type_checker
<
decltype
(
eh
)
>
(
eh
));
break
;
case
internal
:
:
string_type
:
internal
::
check_string_type_spec
(
type_spec
,
eh
);
internal
::
check_string_type_spec
(
specs_
.
type
,
eh
);
break
;
case
internal
:
:
pointer_type
:
internal
::
check_pointer_type_spec
(
type_spec
,
eh
);
internal
::
check_pointer_type_spec
(
specs_
.
type
,
eh
);
break
;
case
internal
:
:
custom_type
:
// Custom format specifiers should be checked in parse functions of
...
...
@@ -3106,9 +3100,8 @@ struct formatter<
specs_
.
width_
,
specs_
.
width_ref
,
ctx
,
format_str_
);
internal
::
handle_dynamic_spec
<
internal
::
precision_checker
>
(
specs_
.
precision
,
specs_
.
precision_ref
,
ctx
,
format_str_
);
typedef
output_range
<
typename
FormatContext
::
iterator
,
typename
FormatContext
::
char_type
>
range_type
;
using
range_type
=
output_range
<
typename
FormatContext
::
iterator
,
typename
FormatContext
::
char_type
>
;
return
visit_format_arg
(
arg_formatter
<
range_type
>
(
ctx
,
nullptr
,
&
specs_
),
internal
::
make_arg
<
FormatContext
>
(
val
));
}
...
...
@@ -3118,6 +3111,44 @@ struct formatter<
const
Char
*
format_str_
;
};
#define FMT_FORMAT_AS(Type, Base) \
template <typename Char> \
struct formatter<Type, Char> : formatter<Base, Char> { \
template <typename FormatContext> \
auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \
return formatter<Base, Char>::format(val, ctx); \
} \
}
FMT_FORMAT_AS
(
signed
char
,
int
);
FMT_FORMAT_AS
(
unsigned
char
,
unsigned
);
FMT_FORMAT_AS
(
short
,
int
);
FMT_FORMAT_AS
(
unsigned
short
,
unsigned
);
FMT_FORMAT_AS
(
long
,
long
long
);
FMT_FORMAT_AS
(
unsigned
long
,
unsigned
long
long
);
FMT_FORMAT_AS
(
float
,
double
);
FMT_FORMAT_AS
(
Char
*
,
const
Char
*
);
FMT_FORMAT_AS
(
std
::
basic_string
<
Char
>
,
basic_string_view
<
Char
>
);
FMT_FORMAT_AS
(
std
::
nullptr_t
,
const
void
*
);
#undef FMT_FORMAT_AS
template
<
typename
Char
>
struct
formatter
<
void
*
,
Char
>
:
formatter
<
const
void
*
,
Char
>
{
template
<
typename
FormatContext
>
auto
format
(
void
*
val
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
return
formatter
<
const
void
*
,
Char
>::
format
(
val
,
ctx
);
}
};
template
<
typename
Char
,
size_t
N
>
struct
formatter
<
Char
[
N
],
Char
>
:
formatter
<
basic_string_view
<
Char
>
,
Char
>
{
template
<
typename
FormatContext
>
auto
format
(
const
Char
*
val
,
FormatContext
&
ctx
)
->
decltype
(
ctx
.
out
())
{
return
formatter
<
basic_string_view
<
Char
>
,
Char
>::
format
(
val
,
ctx
);
}
};
// A formatter for types known only at run time such as variant alternatives.
//
// Usage:
...
...
test/format-test.cc
View file @
3fdba049
...
...
@@ -1876,9 +1876,9 @@ enum TestEnum { A };
TEST
(
FormatTest
,
Enum
)
{
EXPECT_EQ
(
"0"
,
fmt
::
format
(
"{}"
,
A
));
}
TEST
(
FormatTest
,
EnumFormatterUnambiguous
)
{
fmt
::
formatter
<
TestEnum
>
f
;
ASSERT_GE
(
sizeof
(
f
),
0
);
// use f to avoid compiler warning
TEST
(
FormatTest
,
FormatterNotSpecialized
)
{
EXPECT_FALSE
((
fmt
::
internal
::
is_formattable
<
fmt
::
formatter
<
TestEnum
>
,
fmt
::
format_context
>::
value
));
}
#if FMT_HAS_FEATURE(cxx_strong_enums)
...
...
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