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
d2f2a8b0
Commit
d2f2a8b0
authored
Oct 22, 2017
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
constexpr support of dynamic width and precision
parent
6b3840b7
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
36 additions
and
35 deletions
+36
-35
include/fmt/format.h
include/fmt/format.h
+27
-30
test/format-test.cc
test/format-test.cc
+9
-5
No files found.
include/fmt/format.h
View file @
d2f2a8b0
...
...
@@ -850,13 +850,13 @@ constexpr const Char *pointer_from(null_terminating_iterator<Char> it) {
// Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template
<
typename
T
>
inline
typename
std
::
enable_if
<
std
::
numeric_limits
<
T
>::
is_signed
,
bool
>::
type
is_negative
(
T
value
)
{
constexpr
typename
std
::
enable_if
<
std
::
numeric_limits
<
T
>::
is_signed
,
bool
>::
type
is_negative
(
T
value
)
{
return
value
<
0
;
}
template
<
typename
T
>
inline
typename
std
::
enable_if
<!
std
::
numeric_limits
<
T
>::
is_signed
,
bool
>::
type
is_negative
(
T
)
{
constexpr
typename
std
::
enable_if
<
!
std
::
numeric_limits
<
T
>::
is_signed
,
bool
>::
type
is_negative
(
T
)
{
return
false
;
}
...
...
@@ -1205,11 +1205,11 @@ class value {
custom_value
<
char_type
>
custom
;
};
value
()
{}
constexpr
value
()
{}
value
(
bool
val
)
{
set
<
BOOL
>
(
int_value
,
val
);
}
value
(
short
val
)
{
set
<
INT
>
(
int_value
,
val
);
}
value
(
unsigned
short
val
)
{
set
<
UINT
>
(
uint_value
,
val
);
}
value
(
int
val
)
{
set
<
INT
>
(
int_value
,
val
);
}
constexpr
value
(
int
val
)
:
int_value
(
val
)
{
}
value
(
unsigned
val
)
{
set
<
UINT
>
(
uint_value
,
val
);
}
value
(
long
val
)
{
...
...
@@ -1299,7 +1299,7 @@ class value {
private:
template
<
type
TYPE
,
typename
T
,
typename
U
>
void
set
(
T
&
field
,
const
U
&
value
)
{
constexpr
void
set
(
T
&
field
,
const
U
&
value
)
{
static_assert
(
get_type
<
U
>
()
==
TYPE
,
"invalid type"
);
field
=
value
;
}
...
...
@@ -1338,7 +1338,7 @@ template <typename Context>
class
arg_map
;
template
<
typename
Context
,
typename
T
>
basic_arg
<
Context
>
make_arg
(
const
T
&
value
);
constexpr
basic_arg
<
Context
>
make_arg
(
const
T
&
value
);
}
// namespace internal
struct
monostate
{};
...
...
@@ -1355,17 +1355,17 @@ class basic_arg {
internal
::
type
type_
;
template
<
typename
ContextType
,
typename
T
>
friend
basic_arg
<
ContextType
>
internal
::
make_arg
(
const
T
&
value
);
friend
constexpr
basic_arg
<
ContextType
>
internal
::
make_arg
(
const
T
&
value
);
template
<
typename
Visitor
,
typename
Ctx
>
friend
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
friend
constexpr
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
basic_arg
<
Ctx
>
arg
);
friend
class
basic_args
<
Context
>
;
friend
class
internal
::
arg_map
<
Context
>
;
public:
basic_arg
()
:
type_
(
internal
::
NONE
)
{}
constexpr
basic_arg
()
:
type_
(
internal
::
NONE
)
{}
explicit
operator
bool
()
const
noexcept
{
return
type_
!=
internal
::
NONE
;
}
...
...
@@ -1384,7 +1384,7 @@ class basic_arg {
\endrst
*/
template
<
typename
Visitor
,
typename
Context
>
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
constexpr
typename
std
::
result_of
<
Visitor
(
int
)
>::
type
visit
(
Visitor
&&
vis
,
basic_arg
<
Context
>
arg
)
{
typedef
typename
Context
::
char_type
Char
;
switch
(
arg
.
type_
)
{
...
...
@@ -1427,7 +1427,7 @@ typename std::result_of<Visitor(int)>::type
namespace
internal
{
template
<
typename
Context
,
typename
T
>
basic_arg
<
Context
>
make_arg
(
const
T
&
value
)
{
constexpr
basic_arg
<
Context
>
make_arg
(
const
T
&
value
)
{
basic_arg
<
Context
>
arg
;
arg
.
type_
=
get_type
<
T
>
();
arg
.
value_
=
value
;
...
...
@@ -3074,16 +3074,16 @@ struct is_integer {
struct
width_checker
{
template
<
typename
T
>
typename
std
::
enable_if
<
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
value
)
{
constexpr
typename
std
::
enable_if
<
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
value
)
{
if
(
is_negative
(
value
))
FMT_THROW
(
format_error
(
"negative width"
));
return
value
;
}
template
<
typename
T
>
typename
std
::
enable_if
<!
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
)
{
constexpr
typename
std
::
enable_if
<
!
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
)
{
FMT_THROW
(
format_error
(
"width is not integer"
));
return
0
;
}
...
...
@@ -3091,16 +3091,16 @@ struct width_checker {
struct
precision_checker
{
template
<
typename
T
>
typename
std
::
enable_if
<
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
value
)
{
constexpr
typename
std
::
enable_if
<
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
value
)
{
if
(
is_negative
(
value
))
FMT_THROW
(
format_error
(
"negative precision"
));
return
value
;
}
template
<
typename
T
>
typename
std
::
enable_if
<!
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
)
{
constexpr
typename
std
::
enable_if
<
!
is_integer
<
T
>::
value
,
unsigned
long
long
>::
type
operator
()(
T
)
{
FMT_THROW
(
format_error
(
"precision is not integer"
));
return
0
;
}
...
...
@@ -3217,7 +3217,7 @@ class specs_checker : public Handler {
};
template
<
typename
Handler
,
typename
T
,
typename
Context
>
inline
void
set_dynamic_spec
(
T
&
value
,
basic_arg
<
Context
>
arg
)
{
constexpr
void
set_dynamic_spec
(
T
&
value
,
basic_arg
<
Context
>
arg
)
{
unsigned
long
long
big_value
=
visit
(
Handler
(),
arg
);
if
(
big_value
>
(
std
::
numeric_limits
<
int
>::
max
)())
FMT_THROW
(
format_error
(
"number is too big"
));
...
...
@@ -3236,24 +3236,24 @@ class specs_handler: public specs_setter<typename Context::char_type> {
:
specs_setter
<
char_type
>
(
specs
),
context_
(
ctx
)
{}
template
<
typename
Id
>
void
on_dynamic_width
(
Id
arg_id
)
{
constexpr
void
on_dynamic_width
(
Id
arg_id
)
{
set_dynamic_spec
<
internal
::
width_checker
>
(
this
->
specs_
.
width_
,
get_arg
(
arg_id
));
}
template
<
typename
Id
>
void
on_dynamic_precision
(
Id
arg_id
)
{
constexpr
void
on_dynamic_precision
(
Id
arg_id
)
{
set_dynamic_spec
<
internal
::
precision_checker
>
(
this
->
specs_
.
precision_
,
get_arg
(
arg_id
));
}
private:
basic_arg
<
Context
>
get_arg
(
auto_id
)
{
constexpr
basic_arg
<
Context
>
get_arg
(
auto_id
)
{
return
context_
.
next_arg
();
}
template
<
typename
Id
>
basic_arg
<
Context
>
get_arg
(
Id
arg_id
)
{
constexpr
basic_arg
<
Context
>
get_arg
(
Id
arg_id
)
{
context_
.
check_arg_id
(
arg_id
);
return
context_
.
get_arg
(
arg_id
);
}
...
...
@@ -3511,11 +3511,8 @@ const Char *do_format_arg(basic_buffer<Char> &buffer,
basic_format_specs
<
Char
>
specs
;
if
(
*
it
==
':'
)
{
ctx
.
advance_to
(
pointer_from
(
++
it
));
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
buffer
,
ctx
),
arg
))
{
// TODO: if constexpr, then use formatter<T>::parse, else dispatch
// dynamically
if
(
visit
(
custom_formatter
<
Char
,
Context
>
(
buffer
,
ctx
),
arg
))
return
ctx
.
begin
();
}
specs_checker
<
specs_handler
<
Context
>>
handler
(
specs_handler
<
Context
>
(
specs
,
ctx
),
arg
.
type
());
it
=
parse_format_specs
(
it
,
handler
);
...
...
test/format-test.cc
View file @
d2f2a8b0
...
...
@@ -1682,17 +1682,17 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
struct
test_context
{
using
char_type
=
char
;
fmt
::
basic_arg
<
test_context
>
next_arg
()
{
return
fmt
::
basic_arg
<
test_context
>
(
);
constexpr
fmt
::
basic_arg
<
test_context
>
next_arg
()
{
return
fmt
::
internal
::
make_arg
<
test_context
>
(
11
);
}
template
<
typename
Id
>
fmt
::
basic_arg
<
test_context
>
get_arg
(
Id
)
{
return
fmt
::
basic_arg
<
test_context
>
(
);
constexpr
fmt
::
basic_arg
<
test_context
>
get_arg
(
Id
)
{
return
fmt
::
internal
::
make_arg
<
test_context
>
(
22
);
}
template
<
typename
Id
>
void
check_arg_id
(
Id
)
{}
constexpr
void
check_arg_id
(
Id
)
{}
};
constexpr
fmt
::
format_specs
parse_specs
(
const
char
*
s
)
{
...
...
@@ -1712,6 +1712,10 @@ TEST(FormatTest, ConstexprSpecsHandler) {
static_assert
(
parse_specs
(
"#"
).
flag
(
fmt
::
HASH_FLAG
),
""
);
static_assert
(
parse_specs
(
"0"
).
align
()
==
fmt
::
ALIGN_NUMERIC
,
""
);
static_assert
(
parse_specs
(
"42"
).
width
()
==
42
,
""
);
static_assert
(
parse_specs
(
"{}"
).
width
()
==
11
,
""
);
static_assert
(
parse_specs
(
"{0}"
).
width
()
==
22
,
""
);
static_assert
(
parse_specs
(
".42"
).
precision
()
==
42
,
""
);
static_assert
(
parse_specs
(
".{}"
).
precision
()
==
11
,
""
);
static_assert
(
parse_specs
(
".{0}"
).
precision
()
==
22
,
""
);
static_assert
(
parse_specs
(
"d"
).
type
()
==
'd'
,
""
);
}
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