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
4ce006fb
Commit
4ce006fb
authored
Aug 25, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Simplify format string compilation
parent
e2e557e2
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
24 additions
and
273 deletions
+24
-273
include/fmt/compile.h
include/fmt/compile.h
+24
-93
test/compile-test.cc
test/compile-test.cc
+0
-180
No files found.
include/fmt/compile.h
View file @
4ce006fb
...
...
@@ -113,28 +113,26 @@ class format_preparation_handler : public internal::error_handler {
if
(
begin
==
end
)
return
;
const
auto
offset
=
begin
-
format_
.
data
();
const
auto
size
=
end
-
begin
;
parts_
.
add
(
part
(
string_view_metadata
(
offset
,
size
)));
parts_
.
push_back
(
part
(
string_view_metadata
(
offset
,
size
)));
}
FMT_CONSTEXPR
void
on_arg_id
()
{
parts_
.
add
(
part
(
parse_context_
.
next_arg_id
()));
parts_
.
push_back
(
part
(
parse_context_
.
next_arg_id
()));
}
FMT_CONSTEXPR
void
on_arg_id
(
unsigned
id
)
{
parse_context_
.
check_arg_id
(
id
);
parts_
.
add
(
part
(
id
));
parts_
.
push_back
(
part
(
id
));
}
FMT_CONSTEXPR
void
on_arg_id
(
basic_string_view
<
Char
>
id
)
{
const
auto
view
=
string_view_metadata
(
format_
,
id
);
const
auto
arg_id
=
typename
part
::
named_argument_id
(
view
);
parts_
.
add
(
part
(
arg_id
));
parts_
.
push_back
(
part
(
arg_id
));
}
FMT_CONSTEXPR
void
on_replacement_field
(
const
Char
*
ptr
)
{
auto
last_part
=
parts_
.
last
();
last_part
.
end_of_argument_id
=
ptr
-
format_
.
begin
();
parts_
.
substitute_last
(
last_part
);
parts_
.
back
().
end_of_argument_id
=
ptr
-
format_
.
begin
();
}
FMT_CONSTEXPR
const
Char
*
on_format_specs
(
const
Char
*
begin
,
...
...
@@ -148,19 +146,13 @@ class format_preparation_handler : public internal::error_handler {
if
(
*
begin
!=
'}'
)
on_error
(
"missing '}' in format string"
);
const
auto
last_part
=
parts_
.
last
();
auto
&
last_part
=
parts_
.
back
();
auto
specs
=
last_part
.
which
==
part
::
which_value
::
argument_id
?
typename
part
::
specification
(
last_part
.
val
.
arg_id
)
:
typename
part
::
specification
(
last_part
.
val
.
named_arg_id
);
specs
.
parsed_specs
=
parsed_specs
;
auto
new_part
=
part
(
specs
);
new_part
.
end_of_argument_id
=
specs_offset
;
parts_
.
substitute_last
(
new_part
);
last_part
=
part
(
specs
);
last_part
.
end_of_argument_id
=
specs_offset
;
return
begin
;
}
...
...
@@ -346,7 +338,6 @@ template <typename Format> class compiletime_prepared_parts_type_provider {
FMT_CONSTEXPR
value_type
&
operator
[](
unsigned
ind
)
{
return
arr
[
ind
];
}
FMT_CONSTEXPR
const
value_type
*
begin
()
const
{
return
arr
;
}
FMT_CONSTEXPR
const
value_type
*
end
()
const
{
return
begin
()
+
N
;
}
private:
...
...
@@ -370,13 +361,9 @@ template <typename Parts> class compiletime_prepared_parts_collector {
FMT_CONSTEXPR
explicit
compiletime_prepared_parts_collector
(
Parts
&
parts
)
:
parts_
{
parts
},
counter_
{
0u
}
{}
FMT_CONSTEXPR
void
add
(
format_part
part
)
{
parts_
[
counter_
++
]
=
part
;
}
FMT_CONSTEXPR
void
substitute_last
(
format_part
part
)
{
parts_
[
counter_
-
1
]
=
part
;
}
FMT_CONSTEXPR
void
push_back
(
format_part
part
)
{
parts_
[
counter_
++
]
=
part
;
}
FMT_CONSTEXPR
format_part
last
()
{
return
parts_
[
counter_
-
1
];
}
FMT_CONSTEXPR
format_part
&
back
()
{
return
parts_
[
counter_
-
1
];
}
private:
Parts
&
parts_
;
...
...
@@ -431,87 +418,31 @@ struct compiletime_parts_provider {
}
};
template
<
bool
IS_CONSTEXPR
,
typename
Format
,
typename
/*PartsContainer*/
>
struct
parts_provider_type
{
using
type
=
compiletime_parts_provider
<
Format
,
typename
compiletime_prepared_parts_type_provider
<
Format
>::
type
>
;
};
template
<
typename
Format
,
typename
PartsContainer
>
struct
parts_provider_type
<
/*IS_CONSTEXPR=*/
false
,
Format
,
PartsContainer
>
{
using
type
=
runtime_parts_provider
<
PartsContainer
>
;
};
template
<
typename
Format
,
typename
PreparedPartsContainer
,
typename
...
Args
>
struct
basic_prepared_format
{
using
type
=
internal
::
prepared_format
<
Format
,
typename
internal
::
parts_provider_type
<
is_compile_string
<
Format
>::
value
,
Format
,
PreparedPartsContainer
>::
type
,
using
basic_prepared_format
=
internal
::
prepared_format
<
Format
,
conditional_t
<
is_compile_string
<
Format
>::
value
,
compiletime_parts_provider
<
Format
,
typename
compiletime_prepared_parts_type_provider
<
Format
>::
type
>
,
runtime_parts_provider
<
PreparedPartsContainer
>>
,
Args
...
>
;
};
template
<
typename
Char
>
std
::
basic_string
<
Char
>
to_runtime_format
(
basic_string_view
<
Char
>
format
)
{
return
std
::
basic_string
<
Char
>
(
format
.
begin
(),
format
.
size
());
}
template
<
typename
Char
>
std
::
basic_string
<
Char
>
to_runtime_format
(
const
Char
*
format
)
{
return
std
::
basic_string
<
Char
>
(
format
);
}
template
<
typename
Char
,
typename
Container
=
std
::
vector
<
format_part
<
Char
>
>>
class
parts_container
{
public:
using
format_part_type
=
format_part
<
Char
>
;
void
add
(
format_part_type
part
)
{
parts_
.
push_back
(
std
::
move
(
part
));
}
void
substitute_last
(
format_part_type
part
)
{
parts_
.
back
()
=
std
::
move
(
part
);
}
format_part_type
last
()
{
return
parts_
.
back
();
}
auto
begin
()
->
decltype
(
std
::
declval
<
Container
>
().
begin
())
{
return
parts_
.
begin
();
}
auto
begin
()
const
->
decltype
(
std
::
declval
<
const
Container
>
().
begin
())
{
return
parts_
.
begin
();
}
auto
end
()
->
decltype
(
std
::
declval
<
Container
>
().
end
())
{
return
parts_
.
end
();
}
auto
end
()
const
->
decltype
(
std
::
declval
<
const
Container
>
().
end
())
{
return
parts_
.
end
();
}
private:
Container
parts_
;
};
}
// namespace internal
#if FMT_USE_CONSTEXPR
template
<
typename
...
Args
,
typename
S
,
FMT_ENABLE_IF
(
is_compile_string
<
S
>
::
value
)
>
FMT_CONSTEXPR
auto
compile
(
S
format_str
)
{
return
typename
internal
::
basic_prepared_format
<
S
,
void
,
Args
...
>::
type
(
format_str
);
return
internal
::
basic_prepared_format
<
S
,
void
,
Args
...
>
(
format_str
);
}
#endif
template
<
typename
...
Args
,
typename
Char
,
size_t
N
>
auto
compile
(
const
Char
(
&
format_str
)[
N
])
->
typename
internal
::
basic_prepared_format
<
std
::
basic_string
<
Char
>
,
internal
::
parts_container
<
Char
>
,
Args
...
>::
type
{
const
auto
view
=
basic_string_view
<
Char
>
(
format_str
,
N
-
1
);
return
internal
::
to_runtime_format
(
view
);
auto
compile
(
const
Char
(
&
format_str
)[
N
])
->
internal
::
basic_prepared_format
<
std
::
basic_string
<
Char
>
,
std
::
vector
<
internal
::
format_part
<
Char
>>
,
Args
...
>
{
return
std
::
basic_string
<
Char
>
(
format_str
,
N
-
1
);
}
template
<
typename
CompiledFormat
,
typename
...
Args
,
...
...
test/compile-test.cc
View file @
4ce006fb
...
...
@@ -34,13 +34,6 @@
using
testing
::
Return
;
using
testing
::
StrictMock
;
class
mock_parts_collector
{
public:
MOCK_METHOD1
(
add
,
void
(
fmt
::
internal
::
format_part
<
char
>
));
MOCK_METHOD1
(
substitute_last
,
void
(
fmt
::
internal
::
format_part
<
char
>
));
MOCK_METHOD0
(
last
,
fmt
::
internal
::
format_part
<
char
>
());
};
FMT_BEGIN_NAMESPACE
namespace
internal
{
bool
operator
==
(
const
internal
::
string_view_metadata
&
lhs
,
...
...
@@ -227,179 +220,6 @@ TEST(CompileTest, FormatPart_ComparisonOperators) {
}
}
TEST
(
CompileTest
,
FormatPreparationHandler_OnText_AddsPartWithText
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
format
=
fmt
::
internal
::
to_string_view
(
"text"
);
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
format
,
parts
);
const
auto
expected_text
=
fmt
::
internal
::
string_view_metadata
(
0u
,
static_cast
<
unsigned
>
(
format
.
size
()));
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_text
)));
handler
.
on_text
(
format
.
begin
(),
format
.
end
());
}
TEST
(
CompileTest
,
FormatPreparationHandler_OnArgId_AddsPartWithIncrementedId
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
format
=
fmt
::
internal
::
to_string_view
(
""
);
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
format
,
parts
);
const
auto
expected_first_arg_id
=
0u
;
const
auto
expected_second_arg_id
=
1u
;
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_first_arg_id
)));
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_second_arg_id
)));
handler
.
on_arg_id
();
handler
.
on_arg_id
();
}
TEST
(
CompileTest
,
FormatPreparationHandler_OnArgId_AddsPartWithPassedId
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
format
=
fmt
::
internal
::
to_string_view
(
""
);
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
format
,
parts
);
const
auto
expected_first_arg_id
=
2u
;
const
auto
expected_second_arg_id
=
0u
;
const
auto
expected_third_arg_id
=
1u
;
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_first_arg_id
)));
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_second_arg_id
)));
EXPECT_CALL
(
parts
,
add
(
format_part
(
expected_third_arg_id
)));
handler
.
on_arg_id
(
expected_first_arg_id
);
handler
.
on_arg_id
(
expected_second_arg_id
);
handler
.
on_arg_id
(
expected_third_arg_id
);
}
TEST
(
CompileTest
,
FormatPreparationHandler_OnArgId_AddsPartWithPassedNamedId
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
format_part
::
named_argument_id
named_argument_id
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
format
=
fmt
::
internal
::
to_string_view
(
"0123456789"
);
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
format
,
parts
);
const
auto
expected_first_arg_id
=
fmt
::
string_view
(
format
.
data
(),
1
);
const
auto
expected_first_arg_view_metadata
=
fmt
::
internal
::
string_view_metadata
(
0
,
1
);
const
auto
expected_second_arg_id
=
fmt
::
string_view
(
format
.
data
()
+
3
,
2
);
const
auto
expected_second_arg_view_metadata
=
fmt
::
internal
::
string_view_metadata
(
3
,
2
);
const
auto
expected_third_arg_id
=
fmt
::
string_view
(
format
.
data
()
+
6
,
3
);
const
auto
expected_third_arg_view_metadata
=
fmt
::
internal
::
string_view_metadata
(
6
,
3
);
EXPECT_CALL
(
parts
,
add
(
format_part
(
named_argument_id
(
expected_first_arg_view_metadata
))));
EXPECT_CALL
(
parts
,
add
(
format_part
(
named_argument_id
(
expected_second_arg_view_metadata
))));
EXPECT_CALL
(
parts
,
add
(
format_part
(
named_argument_id
(
expected_third_arg_view_metadata
))));
handler
.
on_arg_id
(
expected_first_arg_id
);
handler
.
on_arg_id
(
expected_second_arg_id
);
handler
.
on_arg_id
(
expected_third_arg_id
);
}
TEST
(
CompileTest
,
FormatPreparationHandler_OnReplacementField_SetsEndOfArgumentId
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
const
auto
format
=
fmt
::
internal
::
to_string_view
(
"{:<}"
);
parts_mock
parts
;
const
auto
last_part
=
format_part
(
0u
);
EXPECT_CALL
(
parts
,
last
()).
WillOnce
(
Return
(
last_part
));
auto
expected_substitution_part
=
last_part
;
expected_substitution_part
.
end_of_argument_id
=
1
;
EXPECT_CALL
(
parts
,
substitute_last
(
expected_substitution_part
));
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
format
,
parts
);
handler
.
on_replacement_field
(
format
.
data
()
+
1
);
}
TEST
(
CompileTest
,
FormatPreparationHandlerLastPartArgIndex_OnFormatSpecs_UpdatesLastAddedPart
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
specification_test_text
=
fmt
::
internal
::
to_string_view
(
"{:<10}"
);
const
auto
specification_offset
=
2u
;
const
auto
specification_begin_it
=
specification_test_text
.
begin
()
+
specification_offset
;
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
specification_test_text
,
parts
);
const
auto
last_part
=
format_part
(
0u
);
format_part
::
specification
expected_specification
(
0u
);
fmt
::
internal
::
dynamic_format_specs
<
char
>
specs
{};
specs
.
align
=
fmt
::
align
::
left
;
specs
.
width
=
10
;
expected_specification
.
parsed_specs
=
specs
;
auto
expected_substitution_part
=
format_part
(
expected_specification
);
expected_substitution_part
.
end_of_argument_id
=
specification_offset
;
EXPECT_CALL
(
parts
,
last
()).
WillOnce
(
Return
(
last_part
));
EXPECT_CALL
(
parts
,
substitute_last
(
expected_substitution_part
));
handler
.
on_format_specs
(
specification_begin_it
,
specification_test_text
.
end
());
}
TEST
(
CompileTest
,
FormatPreparationHandlerLastPartNamedArgIndex_OnFormatSpecs_UpdatesLastAddedPart
)
{
typedef
fmt
::
internal
::
format_part
<
char
>
format_part
;
typedef
StrictMock
<
mock_parts_collector
>
parts_mock
;
parts_mock
parts
;
const
auto
specification_test_text
=
fmt
::
internal
::
to_string_view
(
"{:<10}"
);
const
auto
specification_offset
=
2u
;
const
auto
specification_begin_it
=
specification_test_text
.
begin
()
+
specification_offset
;
fmt
::
internal
::
format_preparation_handler
<
char
,
parts_mock
>
handler
(
specification_test_text
,
parts
);
const
auto
arg_id
=
fmt
::
internal
::
string_view_metadata
(
0
,
42
);
const
auto
last_part
=
format_part
(
format_part
::
named_argument_id
(
arg_id
));
format_part
::
specification
expected_specification
(
arg_id
);
fmt
::
internal
::
dynamic_format_specs
<
char
>
specs
{};
specs
.
align
=
fmt
::
align
::
left
;
specs
.
width
=
10
;
expected_specification
.
parsed_specs
=
specs
;
auto
expected_substitution_part
=
format_part
(
expected_specification
);
expected_substitution_part
.
end_of_argument_id
=
specification_offset
;
EXPECT_CALL
(
parts
,
last
()).
WillOnce
(
Return
(
last_part
));
EXPECT_CALL
(
parts
,
substitute_last
(
expected_substitution_part
));
handler
.
on_format_specs
(
specification_begin_it
,
specification_test_text
.
end
());
}
// compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr.
#if FMT_USE_CONSTEXPR
...
...
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