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
56a2e207
Commit
56a2e207
authored
Nov 18, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor float spec parsing
parent
ed117baa
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
55 additions
and
96 deletions
+55
-96
include/fmt/format.h
include/fmt/format.h
+54
-94
test/format
test/format
+1
-2
No files found.
include/fmt/format.h
View file @
56a2e207
...
@@ -70,6 +70,12 @@
...
@@ -70,6 +70,12 @@
# define FMT_HAS_BUILTIN(x) 0
# define FMT_HAS_BUILTIN(x) 0
#endif
#endif
#if FMT_HAS_CPP_ATTRIBUTE(fallthrough) >= 201603 && __cplusplus >= 201703
# define FMT_FALLTHROUGH [[fallthrough]]
#else
# define FMT_FALLTHROUGH
#endif
#ifndef FMT_THROW
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# if FMT_EXCEPTIONS
# if FMT_MSC_VER
# if FMT_MSC_VER
...
@@ -1053,9 +1059,18 @@ namespace internal {
...
@@ -1053,9 +1059,18 @@ namespace internal {
// A floating-point presentation format.
// A floating-point presentation format.
enum
class
float_format
{
enum
class
float_format
{
general
,
// General: shortest of exponential and fixed.
shortest
,
// Shortest round-trip format.
exp
,
// Exponential: 1e42
general
,
// General: exponent notation or fixed point based on magnitude.
fixed
// Fixed: 1.42
exp
,
// Exponent notation with the default precision of 6, e.g. 1.2e-3.
fixed
,
// Fixed point with the default precision of 6, e.g. 0.0012.
hex
};
struct
float_spec
{
float_format
format
;
bool
upper
;
bool
locale
;
bool
percent
;
};
};
struct
gen_digits_params
{
struct
gen_digits_params
{
...
@@ -1244,36 +1259,48 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
...
@@ -1244,36 +1259,48 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
}
}
}
}
template
<
typename
Handler
>
template
<
typename
ErrorHandler
=
error_handler
>
FMT_CONSTEXPR
void
handle_float_type_spec
(
char
spec
,
Handler
&&
handler
)
{
FMT_CONSTEXPR
float_spec
parse_float_type_spec
(
char
spec
,
ErrorHandler
&&
eh
=
{})
{
auto
result
=
float_spec
();
switch
(
spec
)
{
switch
(
spec
)
{
case
'G'
:
result
.
upper
=
true
;
FMT_FALLTHROUGH
;
case
0
:
case
0
:
case
'g'
:
case
'g'
:
case
'G'
:
result
.
format
=
float_format
::
general
;
handler
.
on_general
();
break
;
break
;
case
'e'
:
case
'E'
:
case
'E'
:
handler
.
on_exp
();
result
.
upper
=
true
;
FMT_FALLTHROUGH
;
case
'e'
:
result
.
format
=
float_format
::
exp
;
break
;
break
;
case
'f'
:
case
'F'
:
case
'F'
:
handler
.
on_fixed
();
result
.
upper
=
true
;
FMT_FALLTHROUGH
;
case
'f'
:
result
.
format
=
float_format
::
fixed
;
break
;
break
;
case
'%'
:
case
'%'
:
handler
.
on_percent
();
result
.
format
=
float_format
::
fixed
;
result
.
percent
=
true
;
break
;
break
;
case
'a'
:
case
'A'
:
case
'A'
:
handler
.
on_hex
();
result
.
upper
=
true
;
FMT_FALLTHROUGH
;
case
'a'
:
result
.
format
=
float_format
::
hex
;
break
;
break
;
case
'n'
:
case
'n'
:
handler
.
on_num
()
;
result
.
locale
=
true
;
break
;
break
;
default:
default:
handler
.
on_error
(
);
eh
.
on_error
(
"invalid type specifier"
);
break
;
break
;
}
}
return
result
;
}
}
template
<
typename
Char
,
typename
Handler
>
template
<
typename
Char
,
typename
Handler
>
...
@@ -1321,68 +1348,6 @@ template <typename ErrorHandler> class int_type_checker : private ErrorHandler {
...
@@ -1321,68 +1348,6 @@ template <typename ErrorHandler> class int_type_checker : private ErrorHandler {
}
}
};
};
template
<
typename
ErrorHandler
>
class
float_type_checker
:
private
ErrorHandler
{
public:
FMT_CONSTEXPR
explicit
float_type_checker
(
ErrorHandler
eh
)
:
ErrorHandler
(
eh
)
{}
FMT_CONSTEXPR
void
on_general
()
{}
FMT_CONSTEXPR
void
on_exp
()
{}
FMT_CONSTEXPR
void
on_fixed
()
{}
FMT_CONSTEXPR
void
on_percent
()
{}
FMT_CONSTEXPR
void
on_hex
()
{}
FMT_CONSTEXPR
void
on_num
()
{}
FMT_CONSTEXPR
void
on_error
()
{
ErrorHandler
::
on_error
(
"invalid type specifier"
);
}
};
struct
float_spec_handler
{
char
type
;
bool
upper
;
float_format
format
;
bool
as_percentage
;
bool
use_locale
;
explicit
float_spec_handler
(
char
t
)
:
type
(
t
),
upper
(
false
),
format
(
float_format
::
general
),
as_percentage
(
false
),
use_locale
(
false
)
{}
void
on_general
()
{
if
(
type
==
'G'
)
upper
=
true
;
}
void
on_exp
()
{
format
=
float_format
::
exp
;
if
(
type
==
'E'
)
upper
=
true
;
}
void
on_fixed
()
{
format
=
float_format
::
fixed
;
if
(
type
==
'F'
)
upper
=
true
;
}
void
on_percent
()
{
format
=
float_format
::
fixed
;
as_percentage
=
true
;
}
void
on_hex
()
{
if
(
type
==
'A'
)
upper
=
true
;
}
void
on_num
()
{
use_locale
=
true
;
}
FMT_NORETURN
void
on_error
()
{
FMT_THROW
(
format_error
(
"invalid type specifier"
));
}
};
template
<
typename
ErrorHandler
>
template
<
typename
ErrorHandler
>
class
char_specs_checker
:
public
ErrorHandler
{
class
char_specs_checker
:
public
ErrorHandler
{
private:
private:
...
@@ -2835,10 +2800,6 @@ template <typename Range>
...
@@ -2835,10 +2800,6 @@ template <typename Range>
template
<
typename
T
,
bool
USE_GRISU
>
template
<
typename
T
,
bool
USE_GRISU
>
void
internal
::
basic_writer
<
Range
>::
write_fp
(
T
value
,
void
internal
::
basic_writer
<
Range
>::
write_fp
(
T
value
,
const
format_specs
&
specs
)
{
const
format_specs
&
specs
)
{
// Check type.
float_spec_handler
handler
(
specs
.
type
);
handle_float_type_spec
(
handler
.
type
,
handler
);
auto
sign
=
specs
.
sign
;
auto
sign
=
specs
.
sign
;
// Use signbit instead of value < 0 since the latter is always false for NaN.
// Use signbit instead of value < 0 since the latter is always false for NaN.
if
(
std
::
signbit
(
value
))
{
if
(
std
::
signbit
(
value
))
{
...
@@ -2848,20 +2809,20 @@ void internal::basic_writer<Range>::write_fp(T value,
...
@@ -2848,20 +2809,20 @@ void internal::basic_writer<Range>::write_fp(T value,
sign
=
sign
::
none
;
sign
=
sign
::
none
;
}
}
float_spec
fspec
=
parse_float_type_spec
(
specs
.
type
);
if
(
!
std
::
isfinite
(
value
))
{
if
(
!
std
::
isfinite
(
value
))
{
const
char
*
str
=
std
::
isinf
(
value
)
?
(
handler
.
upper
?
"INF"
:
"inf"
)
const
char
*
str
=
std
::
isinf
(
value
)
?
(
fspec
.
upper
?
"INF"
:
"inf"
)
:
(
handler
.
upper
?
"NAN"
:
"nan"
);
:
(
fspec
.
upper
?
"NAN"
:
"nan"
);
return
write_padded
(
specs
,
return
write_padded
(
specs
,
inf_or_nan_writer
{
sign
,
fspec
.
percent
,
str
});
inf_or_nan_writer
{
sign
,
handler
.
as_percentage
,
str
});
}
}
if
(
handler
.
as_percentage
)
value
*=
100
;
if
(
fspec
.
percent
)
value
*=
100
;
memory_buffer
buffer
;
memory_buffer
buffer
;
int
exp
=
0
;
int
exp
=
0
;
int
precision
=
specs
.
precision
>=
0
||
!
specs
.
type
?
specs
.
precision
:
6
;
int
precision
=
specs
.
precision
>=
0
||
!
specs
.
type
?
specs
.
precision
:
6
;
unsigned
options
=
0
;
unsigned
options
=
0
;
if
(
handler
.
format
==
float_format
::
fixed
)
options
|=
grisu_options
::
fixed
;
if
(
fspec
.
format
==
float_format
::
fixed
)
options
|=
grisu_options
::
fixed
;
if
(
const_check
(
sizeof
(
value
)
==
sizeof
(
float
)))
if
(
const_check
(
sizeof
(
value
)
==
sizeof
(
float
)))
options
|=
grisu_options
::
binary32
;
options
|=
grisu_options
::
binary32
;
bool
use_grisu
=
bool
use_grisu
=
...
@@ -2872,7 +2833,7 @@ void internal::basic_writer<Range>::write_fp(T value,
...
@@ -2872,7 +2833,7 @@ void internal::basic_writer<Range>::write_fp(T value,
char
*
decimal_point_pos
=
nullptr
;
char
*
decimal_point_pos
=
nullptr
;
if
(
!
use_grisu
)
decimal_point_pos
=
sprintf_format
(
value
,
buffer
,
specs
);
if
(
!
use_grisu
)
decimal_point_pos
=
sprintf_format
(
value
,
buffer
,
specs
);
if
(
handler
.
as_percentage
)
{
if
(
fspec
.
percent
)
{
buffer
.
push_back
(
'%'
);
buffer
.
push_back
(
'%'
);
--
exp
;
// Adjust decimal place position.
--
exp
;
// Adjust decimal place position.
}
}
...
@@ -2888,17 +2849,17 @@ void internal::basic_writer<Range>::write_fp(T value,
...
@@ -2888,17 +2849,17 @@ void internal::basic_writer<Range>::write_fp(T value,
}
else
if
(
specs
.
align
==
align
::
none
)
{
}
else
if
(
specs
.
align
==
align
::
none
)
{
as
.
align
=
align
::
right
;
as
.
align
=
align
::
right
;
}
}
char_type
decimal_point
=
handler
.
use_
locale
char_type
decimal_point
=
fspec
.
locale
?
internal
::
decimal_point
<
char_type
>
(
locale_
)
?
internal
::
decimal_point
<
char_type
>
(
locale_
)
:
static_cast
<
char_type
>
(
'.'
);
:
static_cast
<
char_type
>
(
'.'
);
if
(
use_grisu
)
{
if
(
use_grisu
)
{
auto
params
=
gen_digits_params
();
auto
params
=
gen_digits_params
();
params
.
sign
=
sign
;
params
.
sign
=
sign
;
params
.
format
=
handler
.
format
;
params
.
format
=
fspec
.
format
;
params
.
num_digits
=
precision
;
params
.
num_digits
=
precision
;
params
.
trailing_zeros
=
params
.
trailing_zeros
=
(
precision
!=
0
&&
(
precision
!=
0
&&
(
handler
.
format
==
float_format
::
fixed
||
!
specs
.
type
))
||
(
fspec
.
format
==
float_format
::
fixed
||
!
specs
.
type
))
||
specs
.
alt
;
specs
.
alt
;
int
num_digits
=
static_cast
<
int
>
(
buffer
.
size
());
int
num_digits
=
static_cast
<
int
>
(
buffer
.
size
());
write_padded
(
as
,
grisu_writer
<
char_type
>
(
buffer
.
data
(),
num_digits
,
exp
,
write_padded
(
as
,
grisu_writer
<
char_type
>
(
buffer
.
data
(),
num_digits
,
exp
,
...
@@ -3078,8 +3039,7 @@ struct formatter<T, Char,
...
@@ -3078,8 +3039,7 @@ struct formatter<T, Char,
case
internal
:
:
float_type
:
case
internal
:
:
float_type
:
case
internal
:
:
double_type
:
case
internal
:
:
double_type
:
case
internal
:
:
long_double_type
:
case
internal
:
:
long_double_type
:
handle_float_type_spec
(
specs_
.
type
,
internal
::
parse_float_type_spec
(
specs_
.
type
,
eh
);
internal
::
float_type_checker
<
decltype
(
eh
)
>
(
eh
));
break
;
break
;
case
internal
:
:
cstring_type
:
case
internal
:
:
cstring_type
:
internal
::
handle_cstring_type_spec
(
internal
::
handle_cstring_type_spec
(
...
...
test/format
View file @
56a2e207
...
@@ -666,8 +666,7 @@ struct formatter {
...
@@ -666,8 +666,7 @@ struct formatter {
break;
break;
case internal::double_type:
case internal::double_type:
case internal::long_double_type:
case internal::long_double_type:
handle_float_type_spec(type_spec,
internal::parse_float_type_spec(type_spec, eh);
internal::float_type_checker<decltype(eh)>(eh));
break;
break;
case internal::cstring_type:
case internal::cstring_type:
internal::handle_cstring_type_spec(
internal::handle_cstring_type_spec(
...
...
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