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
ded1e767
Commit
ded1e767
authored
Nov 21, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor floating point formatting
parent
c7edd8e5
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
176 additions
and
211 deletions
+176
-211
include/fmt/format-inl.h
include/fmt/format-inl.h
+84
-81
include/fmt/format.h
include/fmt/format.h
+86
-124
src/format.cc
src/format.cc
+5
-5
support/Vagrantfile
support/Vagrantfile
+1
-1
No files found.
include/fmt/format-inl.h
View file @
ded1e767
...
...
@@ -51,12 +51,8 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
{};
}
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
{};
}
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
{};
}
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
{};
}
FMT_BEGIN_NAMESPACE
namespace
internal
{
...
...
@@ -250,20 +246,6 @@ template <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) {
return
i
>=
0
?
i
*
char_digits
+
count_digits
<
4
,
unsigned
>
(
n
.
value
[
i
])
:
1
;
}
template
<
typename
T
>
int
format_float
(
char
*
buf
,
std
::
size_t
size
,
const
char
*
format
,
int
precision
,
T
value
)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if
(
precision
>
100000
)
throw
std
::
runtime_error
(
"fuzz mode - avoid large allocation inside snprintf"
);
#endif
// Suppress the warning about nonliteral format string.
auto
snprintf_ptr
=
FMT_SNPRINTF
;
return
precision
<
0
?
snprintf_ptr
(
buf
,
size
,
format
,
value
)
:
snprintf_ptr
(
buf
,
size
,
format
,
precision
,
value
);
}
template
<
typename
T
>
const
char
basic_data
<
T
>::
digits
[]
=
"0001020304050607080910111213141516171819"
...
...
@@ -276,9 +258,9 @@ template <typename T>
const
char
basic_data
<
T
>::
hex_digits
[]
=
"0123456789abcdef"
;
#define FMT_POWERS_OF_10(factor) \
factor * 10, (factor)
* 100, (factor) * 1000, (factor) * 10000, (factor) *
100000, \
(factor)
* 1000000, (factor) * 10000000, (factor) *
100000000, \
(factor)
*
1000000000
factor * 10, (factor)
*100, (factor)*1000, (factor)*10000, (factor)*
100000, \
(factor)
*1000000, (factor)*10000000, (factor)*
100000000, \
(factor)
*
1000000000
template
<
typename
T
>
const
uint64_t
basic_data
<
T
>::
powers_of_10_64
[]
=
{
...
...
@@ -1121,78 +1103,99 @@ bool grisu_format(Double value, buffer<char>& buf, int precision,
return
true
;
}
template
<
typename
Double
>
char
*
sprintf_format
(
Double
value
,
internal
::
buffer
<
char
>&
buf
,
sprintf_specs
specs
)
{
template
<
typename
Float
>
int
sprintf_format
(
Float
value
,
int
precision
,
float_spec
spec
,
buffer
<
char
>&
buf
)
{
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT
(
buf
.
capacity
()
!=
0
,
"empty buffer"
);
FMT_ASSERT
(
buf
.
capacity
()
>
buf
.
size
(),
"empty buffer"
);
// Subtract 1 to account for the difference in precision since we use %e for
// both general and exponent format.
if
(
spec
.
format
==
float_format
::
general
)
precision
=
(
precision
>=
0
?
precision
:
6
)
-
1
;
// Build format string.
enum
{
max_format_size
=
10
};
// longest format: %#-*.*Lg
// Build
the
format string.
enum
{
max_format_size
=
7
};
// Ths longest format is "%#.*Le".
char
format
[
max_format_size
];
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
if
(
spec
s
.
alt
||
!
specs
.
type
)
*
format_ptr
++
=
'#'
;
if
(
specs
.
precision
>=
0
)
{
if
(
spec
.
alt
)
*
format_ptr
++
=
'#'
;
if
(
precision
>
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
}
if
(
std
::
is_same
<
Double
,
long
double
>::
value
)
*
format_ptr
++
=
'L'
;
char
type
=
specs
.
type
;
if
(
type
==
'%'
)
type
=
'f'
;
else
if
(
type
==
0
||
type
==
'n'
)
type
=
'g'
;
if
(
FMT_MSC_VER
&&
type
==
'F'
)
type
=
'f'
;
// // MSVC's printf doesn't support 'F'.
*
format_ptr
++
=
type
;
if
(
std
::
is_same
<
Float
,
long
double
>
())
*
format_ptr
++
=
'L'
;
*
format_ptr
++
=
spec
.
format
!=
float_format
::
hex
?
(
spec
.
format
==
float_format
::
fixed
?
'f'
:
'e'
)
:
(
spec
.
upper
?
'A'
:
'a'
);
*
format_ptr
=
'\0'
;
// Format using snprintf.
char
*
start
=
nullptr
;
char
*
decimal_point_pos
=
nullptr
;
auto
offset
=
buf
.
size
();
for
(;;)
{
std
::
size_t
buffer_size
=
buf
.
capacity
();
start
=
&
buf
[
0
];
int
result
=
format_float
(
start
,
buffer_size
,
format
,
specs
.
precision
,
value
);
if
(
result
>=
0
)
{
unsigned
n
=
internal
::
to_unsigned
(
result
);
if
(
n
<
buf
.
capacity
())
{
// Find the decimal point.
auto
p
=
buf
.
data
(),
end
=
p
+
n
;
if
(
*
p
==
'+'
||
*
p
==
'-'
)
++
p
;
if
(
specs
.
type
!=
'a'
&&
specs
.
type
!=
'A'
)
{
while
(
p
<
end
&&
*
p
>=
'0'
&&
*
p
<=
'9'
)
++
p
;
if
(
p
<
end
&&
*
p
!=
'e'
&&
*
p
!=
'E'
)
{
decimal_point_pos
=
p
;
if
(
!
specs
.
type
)
{
// Keep only one trailing zero after the decimal point.
++
p
;
if
(
*
p
==
'0'
)
++
p
;
while
(
p
!=
end
&&
*
p
>=
'1'
&&
*
p
<=
'9'
)
++
p
;
char
*
where
=
p
;
while
(
p
!=
end
&&
*
p
==
'0'
)
++
p
;
if
(
p
==
end
||
*
p
<
'0'
||
*
p
>
'9'
)
{
if
(
p
!=
end
)
std
::
memmove
(
where
,
p
,
to_unsigned
(
end
-
p
));
n
-=
static_cast
<
unsigned
>
(
p
-
where
);
}
}
}
}
buf
.
resize
(
n
);
break
;
// The buffer is large enough - continue with formatting.
}
buf
.
reserve
(
n
+
1
);
}
else
{
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf
.
reserve
(
buf
.
capacity
()
+
1
);
auto
begin
=
buf
.
data
()
+
offset
;
auto
capacity
=
buf
.
capacity
()
-
offset
;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if
(
precision
>
100000
)
throw
std
::
runtime_error
(
"fuzz mode - avoid large allocation inside snprintf"
);
#endif
// Suppress the warning about a nonliteral format string.
auto
snprintf_ptr
=
FMT_SNPRINTF
;
int
result
=
precision
>
0
?
snprintf_ptr
(
begin
,
capacity
,
format
,
precision
,
value
)
:
snprintf_ptr
(
begin
,
capacity
,
format
,
value
);
if
(
result
<
0
)
{
buf
.
reserve
(
capacity
+
1
);
// The buffer will grow exponentially.
continue
;
}
unsigned
size
=
to_unsigned
(
result
);
if
(
size
>
capacity
)
{
buf
.
reserve
(
size
+
1
);
// Add 1 for the terminating '\0'.
continue
;
}
auto
is_digit
=
[](
char
c
)
{
return
c
>=
'0'
&&
c
<=
'9'
;
};
if
(
spec
.
format
==
float_format
::
fixed
)
{
// Find and remove the decimal point.
auto
end
=
begin
+
size
,
p
=
end
;
do
{
--
p
;
}
while
(
is_digit
(
*
p
));
int
fraction_size
=
static_cast
<
int
>
(
end
-
p
-
1
);
std
::
memmove
(
p
,
p
+
1
,
fraction_size
);
buf
.
resize
(
size
-
1
);
return
-
fraction_size
;
}
if
(
spec
.
format
==
float_format
::
hex
)
{
buf
.
resize
(
size
+
offset
);
return
0
;
}
// Find and parse the exponent.
auto
end
=
begin
+
size
,
exp_pos
=
end
;
do
{
--
exp_pos
;
}
while
(
*
exp_pos
!=
'e'
);
char
sign
=
exp_pos
[
1
];
assert
(
sign
==
'+'
||
sign
==
'-'
);
int
exp
=
0
;
auto
p
=
exp_pos
+
2
;
// Skip 'e' and sign.
do
{
assert
(
is_digit
(
*
p
));
exp
=
exp
*
10
+
(
*
p
++
-
'0'
);
}
while
(
p
!=
end
);
if
(
sign
==
'-'
)
exp
=
-
exp
;
if
(
exp_pos
!=
begin
+
1
)
{
// Remove trailing zeros.
auto
fraction_end
=
exp_pos
-
1
;
while
(
*
fraction_end
==
'0'
)
--
fraction_end
;
// Move the fractional part left to get rid of the decimal point.
int
fraction_size
=
static_cast
<
int
>
(
fraction_end
-
begin
-
1
);
std
::
memmove
(
begin
+
1
,
begin
+
2
,
fraction_size
);
buf
.
resize
(
fraction_size
+
offset
+
1
);
exp
-=
fraction_size
;
}
return
exp
;
}
return
decimal_point_pos
;
}
}
// namespace internal
...
...
include/fmt/format.h
View file @
ded1e767
...
...
@@ -1074,6 +1074,7 @@ struct float_spec {
bool
upper
;
bool
locale
;
bool
percent
;
bool
alt
;
};
struct
gen_digits_params
{
...
...
@@ -1086,7 +1087,7 @@ struct gen_digits_params {
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template
<
typename
Char
,
typename
It
>
It
write_exponent
(
int
exp
,
It
it
)
{
FMT_ASSERT
(
-
1000
<
exp
&&
exp
<
1
000
,
"exponent out of range"
);
FMT_ASSERT
(
-
1000
0
<
exp
&&
exp
<
10
000
,
"exponent out of range"
);
if
(
exp
<
0
)
{
*
it
++
=
static_cast
<
Char
>
(
'-'
);
exp
=
-
exp
;
...
...
@@ -1094,7 +1095,9 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
*
it
++
=
static_cast
<
Char
>
(
'+'
);
}
if
(
exp
>=
100
)
{
*
it
++
=
static_cast
<
Char
>
(
static_cast
<
char
>
(
'0'
+
exp
/
100
));
const
char
*
top
=
data
::
digits
+
(
exp
/
100
)
*
2
;
if
(
exp
>=
1000
)
*
it
++
=
static_cast
<
Char
>
(
top
[
0
]);
*
it
++
=
static_cast
<
Char
>
(
top
[
1
]);
exp
%=
100
;
}
const
char
*
d
=
data
::
digits
+
exp
*
2
;
...
...
@@ -1103,7 +1106,7 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
return
it
;
}
template
<
typename
Char
>
class
grisu
_writer
{
template
<
typename
Char
>
class
float
_writer
{
private:
// The number is given as v = digits_ * pow(10, exp_).
const
char
*
digits_
;
...
...
@@ -1177,7 +1180,7 @@ template <typename Char> class grisu_writer {
}
public:
grisu
_writer
(
const
char
*
digits
,
int
num_digits
,
int
exp
,
float
_writer
(
const
char
*
digits
,
int
num_digits
,
int
exp
,
gen_digits_params
params
,
Char
decimal_point
)
:
digits_
(
digits
),
num_digits_
(
num_digits
),
...
...
@@ -1217,26 +1220,15 @@ inline bool grisu_format(Double, buffer<char>&, int, unsigned, int&) {
return
false
;
}
struct
sprintf_specs
{
int
precision
;
char
type
;
bool
alt
:
1
;
template
<
typename
Char
>
constexpr
sprintf_specs
(
basic_format_specs
<
Char
>
specs
)
:
precision
(
specs
.
precision
),
type
(
specs
.
type
),
alt
(
specs
.
alt
)
{}
constexpr
bool
has_precision
()
const
{
return
precision
>=
0
;
}
};
template
<
typename
Double
>
char
*
sprintf_format
(
Double
,
internal
::
buffer
<
char
>&
,
sprintf_specs
);
template
<
typename
Float
>
int
sprintf_format
(
Float
value
,
int
precision
,
float_spec
spec
,
buffer
<
char
>&
buf
);
template
<
>
inline
char
*
sprintf_format
<
float
>
(
float
value
,
internal
::
buffer
<
char
>&
buf
,
sprintf_specs
specs
)
{
//
printf does not have a float format specifier, it only supports
double.
return
sprintf_format
<
double
>
(
value
,
buf
,
specs
);
inline
int
sprintf_format
<
float
>
(
float
value
,
int
precision
,
float_spec
spec
,
buffer
<
char
>&
buf
)
{
//
sprintf does not support float so convert to
double.
return
sprintf_format
<
double
>
(
value
,
precision
,
spec
,
buf
);
}
template
<
typename
Handler
>
...
...
@@ -1422,7 +1414,7 @@ template <typename Range> class basic_writer {
private:
iterator
out_
;
// Output iterator.
internal
::
locale_ref
locale_
;
locale_ref
locale_
;
// Attempts to reserve space for n extra characters in the output range.
// Returns a pointer to the reserved range or a reference to out_.
...
...
@@ -1442,7 +1434,7 @@ template <typename Range> class basic_writer {
template
<
typename
It
>
void
operator
()(
It
&&
it
)
const
{
if
(
prefix
.
size
()
!=
0
)
it
=
internal
::
copy_str
<
char_type
>
(
prefix
.
begin
(),
prefix
.
end
(),
it
);
it
=
copy_str
<
char_type
>
(
prefix
.
begin
(),
prefix
.
end
(),
it
);
it
=
std
::
fill_n
(
it
,
padding
,
fill
);
f
(
it
);
}
...
...
@@ -1453,18 +1445,18 @@ template <typename Range> class basic_writer {
// where <digits> are written by f(it).
template
<
typename
F
>
void
write_int
(
int
num_digits
,
string_view
prefix
,
format_specs
specs
,
F
f
)
{
std
::
size_t
size
=
prefix
.
size
()
+
internal
::
to_unsigned
(
num_digits
);
std
::
size_t
size
=
prefix
.
size
()
+
to_unsigned
(
num_digits
);
char_type
fill
=
specs
.
fill
[
0
];
std
::
size_t
padding
=
0
;
if
(
specs
.
align
==
align
::
numeric
)
{
auto
unsiged_width
=
internal
::
to_unsigned
(
specs
.
width
);
auto
unsiged_width
=
to_unsigned
(
specs
.
width
);
if
(
unsiged_width
>
size
)
{
padding
=
unsiged_width
-
size
;
size
=
unsiged_width
;
}
}
else
if
(
specs
.
precision
>
num_digits
)
{
size
=
prefix
.
size
()
+
internal
::
to_unsigned
(
specs
.
precision
);
padding
=
internal
::
to_unsigned
(
specs
.
precision
-
num_digits
);
size
=
prefix
.
size
()
+
to_unsigned
(
specs
.
precision
);
padding
=
to_unsigned
(
specs
.
precision
-
num_digits
);
fill
=
static_cast
<
char_type
>
(
'0'
);
}
if
(
specs
.
align
==
align
::
none
)
specs
.
align
=
align
::
right
;
...
...
@@ -1474,14 +1466,13 @@ template <typename Range> class basic_writer {
// Writes a decimal integer.
template
<
typename
Int
>
void
write_decimal
(
Int
value
)
{
auto
abs_value
=
static_cast
<
uint32_or_64_or_128_t
<
Int
>>
(
value
);
bool
is_negative
=
internal
::
is_negative
(
value
);
bool
negative
=
is_negative
(
value
);
// Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
if
(
is_negative
)
abs_value
=
~
abs_value
+
1
;
int
num_digits
=
internal
::
count_digits
(
abs_value
);
auto
&&
it
=
reserve
((
is_negative
?
1
:
0
)
+
static_cast
<
size_t
>
(
num_digits
));
if
(
is_negative
)
*
it
++
=
static_cast
<
char_type
>
(
'-'
);
it
=
internal
::
format_decimal
<
char_type
>
(
it
,
abs_value
,
num_digits
);
if
(
negative
)
abs_value
=
~
abs_value
+
1
;
int
num_digits
=
count_digits
(
abs_value
);
auto
&&
it
=
reserve
((
negative
?
1
:
0
)
+
static_cast
<
size_t
>
(
num_digits
));
if
(
negative
)
*
it
++
=
static_cast
<
char_type
>
(
'-'
);
it
=
format_decimal
<
char_type
>
(
it
,
abs_value
,
num_digits
);
}
// The handle_int_type_spec handler that writes an integer.
...
...
@@ -1501,7 +1492,7 @@ template <typename Range> class basic_writer {
specs
(
s
),
abs_value
(
static_cast
<
unsigned_type
>
(
value
)),
prefix_size
(
0
)
{
if
(
i
nternal
::
i
s_negative
(
value
))
{
if
(
is_negative
(
value
))
{
prefix
[
0
]
=
'-'
;
++
prefix_size
;
abs_value
=
0
-
abs_value
;
...
...
@@ -1521,7 +1512,7 @@ template <typename Range> class basic_writer {
};
void
on_dec
()
{
int
num_digits
=
internal
::
count_digits
(
abs_value
);
int
num_digits
=
count_digits
(
abs_value
);
writer
.
write_int
(
num_digits
,
get_prefix
(),
specs
,
dec_writer
{
abs_value
,
num_digits
});
}
...
...
@@ -1531,8 +1522,8 @@ template <typename Range> class basic_writer {
int
num_digits
;
template
<
typename
It
>
void
operator
()(
It
&&
it
)
const
{
it
=
internal
::
format_uint
<
4
,
char_type
>
(
it
,
self
.
abs_value
,
num_digits
,
self
.
specs
.
type
!=
'x'
);
it
=
format_uint
<
4
,
char_type
>
(
it
,
self
.
abs_value
,
num_digits
,
self
.
specs
.
type
!=
'x'
);
}
};
...
...
@@ -1541,7 +1532,7 @@ template <typename Range> class basic_writer {
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
specs
.
type
;
}
int
num_digits
=
internal
::
count_digits
<
4
>
(
abs_value
);
int
num_digits
=
count_digits
<
4
>
(
abs_value
);
writer
.
write_int
(
num_digits
,
get_prefix
(),
specs
,
hex_writer
{
*
this
,
num_digits
});
}
...
...
@@ -1551,7 +1542,7 @@ template <typename Range> class basic_writer {
int
num_digits
;
template
<
typename
It
>
void
operator
()(
It
&&
it
)
const
{
it
=
internal
::
format_uint
<
BITS
,
char_type
>
(
it
,
abs_value
,
num_digits
);
it
=
format_uint
<
BITS
,
char_type
>
(
it
,
abs_value
,
num_digits
);
}
};
...
...
@@ -1560,13 +1551,13 @@ template <typename Range> class basic_writer {
prefix
[
prefix_size
++
]
=
'0'
;
prefix
[
prefix_size
++
]
=
static_cast
<
char
>
(
specs
.
type
);
}
int
num_digits
=
internal
::
count_digits
<
1
>
(
abs_value
);
int
num_digits
=
count_digits
<
1
>
(
abs_value
);
writer
.
write_int
(
num_digits
,
get_prefix
(),
specs
,
bin_writer
<
1
>
{
abs_value
,
num_digits
});
}
void
on_oct
()
{
int
num_digits
=
internal
::
count_digits
<
3
>
(
abs_value
);
int
num_digits
=
count_digits
<
3
>
(
abs_value
);
if
(
specs
.
alt
&&
specs
.
precision
<=
num_digits
&&
abs_value
!=
0
)
{
// Octal prefix '0' is counted as a digit, so only add it if precision
// is not greater than the number of digits.
...
...
@@ -1590,7 +1581,7 @@ template <typename Range> class basic_writer {
// index 0.
unsigned
digit_index
=
0
;
std
::
string
::
const_iterator
group
=
groups
.
cbegin
();
it
=
internal
::
format_decimal
<
char_type
>
(
it
=
format_decimal
<
char_type
>
(
it
,
abs_value
,
size
,
[
this
,
s
,
&
group
,
&
digit_index
](
char_type
*&
buffer
)
{
if
(
*
group
<=
0
||
++
digit_index
%
*
group
!=
0
||
...
...
@@ -1602,17 +1593,17 @@ template <typename Range> class basic_writer {
}
buffer
-=
s
.
size
();
std
::
uninitialized_copy
(
s
.
data
(),
s
.
data
()
+
s
.
size
(),
internal
::
make_checked
(
buffer
,
s
.
size
()));
make_checked
(
buffer
,
s
.
size
()));
});
}
};
void
on_num
()
{
std
::
string
groups
=
internal
::
grouping
<
char_type
>
(
writer
.
locale_
);
std
::
string
groups
=
grouping
<
char_type
>
(
writer
.
locale_
);
if
(
groups
.
empty
())
return
on_dec
();
auto
sep
=
internal
::
thousands_sep
<
char_type
>
(
writer
.
locale_
);
auto
sep
=
thousands_sep
<
char_type
>
(
writer
.
locale_
);
if
(
!
sep
)
return
on_dec
();
int
num_digits
=
internal
::
count_digits
(
abs_value
);
int
num_digits
=
count_digits
(
abs_value
);
int
size
=
num_digits
;
std
::
string
::
const_iterator
group
=
groups
.
cbegin
();
while
(
group
!=
groups
.
cend
()
&&
num_digits
>
*
group
&&
*
group
>
0
&&
...
...
@@ -1632,38 +1623,17 @@ template <typename Range> class basic_writer {
}
};
struct
double_writer
{
sign_t
sign
;
internal
::
buffer
<
char
>&
buffer
;
char
*
decimal_point_pos
;
char_type
decimal_point
;
size_t
size
()
const
{
return
buffer
.
size
()
+
(
sign
?
1
:
0
);
}
size_t
width
()
const
{
return
size
();
}
template
<
typename
It
>
void
operator
()(
It
&&
it
)
{
if
(
sign
)
*
it
++
=
static_cast
<
char_type
>
(
data
::
signs
[
sign
]);
auto
begin
=
buffer
.
begin
();
if
(
decimal_point_pos
)
{
it
=
internal
::
copy_str
<
char_type
>
(
begin
,
decimal_point_pos
,
it
);
*
it
++
=
decimal_point
;
begin
=
decimal_point_pos
+
1
;
}
it
=
internal
::
copy_str
<
char_type
>
(
begin
,
buffer
.
end
(),
it
);
}
};
template
<
typename
Char
>
struct
str_writer
{
const
Char
*
s
;
size_t
size_
;
size_t
size
()
const
{
return
size_
;
}
size_t
width
()
const
{
return
internal
::
count_code_points
(
basic_string_view
<
Char
>
(
s
,
size_
));
return
count_code_points
(
basic_string_view
<
Char
>
(
s
,
size_
));
}
template
<
typename
It
>
void
operator
()(
It
&&
it
)
const
{
it
=
internal
::
copy_str
<
char_type
>
(
s
,
s
+
size_
,
it
);
it
=
copy_str
<
char_type
>
(
s
,
s
+
size_
,
it
);
}
};
...
...
@@ -1677,13 +1647,12 @@ template <typename Range> class basic_writer {
template
<
typename
It
>
void
operator
()(
It
&&
it
)
const
{
*
it
++
=
static_cast
<
char_type
>
(
'0'
);
*
it
++
=
static_cast
<
char_type
>
(
'x'
);
it
=
internal
::
format_uint
<
4
,
char_type
>
(
it
,
value
,
num_digits
);
it
=
format_uint
<
4
,
char_type
>
(
it
,
value
,
num_digits
);
}
};
public:
explicit
basic_writer
(
Range
out
,
internal
::
locale_ref
loc
=
internal
::
locale_ref
())
explicit
basic_writer
(
Range
out
,
locale_ref
loc
=
locale_ref
())
:
out_
(
out
.
begin
()),
locale_
(
loc
)
{}
iterator
out
()
const
{
return
out_
;
}
...
...
@@ -1727,15 +1696,13 @@ template <typename Range> class basic_writer {
void
write
(
uint128_t
value
)
{
write_decimal
(
value
);
}
#endif
// Writes a formatted integer.
template
<
typename
T
,
typename
Spec
>
void
write_int
(
T
value
,
const
Spec
&
spec
)
{
internal
::
handle_int_type_spec
(
spec
.
type
,
int_writer
<
T
,
Spec
>
(
*
this
,
value
,
spec
));
handle_int_type_spec
(
spec
.
type
,
int_writer
<
T
,
Spec
>
(
*
this
,
value
,
spec
));
}
template
<
typename
T
,
FMT_ENABLE_IF
(
std
::
is_floating_point
<
T
>
::
value
)
>
void
write
(
T
value
,
const
format_specs
&
specs
=
{})
{
void
write
(
T
value
,
format_specs
specs
=
{})
{
auto
sign
=
specs
.
sign
;
if
(
std
::
signbit
(
value
))
{
// value < 0 is false for NaN so use signbit.
sign
=
sign
::
minus
;
...
...
@@ -1751,61 +1718,61 @@ template <typename Range> class basic_writer {
return
write_padded
(
specs
,
inf_or_nan_writer
<
char_type
>
{
sign
,
str
});
}
if
(
specs
.
align
==
align
::
numeric
)
{
if
(
sign
)
{
auto
&&
it
=
reserve
(
1
);
*
it
++
=
static_cast
<
char_type
>
(
data
::
signs
[
sign
]);
sign
=
sign
::
none
;
if
(
specs
.
width
!=
0
)
--
specs
.
width
;
}
specs
.
align
=
align
::
right
;
}
else
if
(
specs
.
align
==
align
::
none
)
{
specs
.
align
=
align
::
right
;
}
memory_buffer
buffer
;
int
exp
=
0
;
if
(
fspec
.
format
==
float_format
::
hex
)
{
if
(
sign
)
buffer
.
push_back
(
data
::
signs
[
sign
]);
fspec
.
alt
=
specs
.
alt
;
sprintf_format
(
value
,
specs
.
precision
,
fspec
,
buffer
);
write_padded
(
specs
,
str_writer
<
char
>
{
buffer
.
data
(),
buffer
.
size
()});
return
;
}
int
precision
=
specs
.
precision
>=
0
||
!
specs
.
type
?
specs
.
precision
:
6
;
int
num_digits
=
fspec
.
format
==
float_format
::
exp
?
precision
+
1
:
precision
;
unsigned
options
=
0
;
if
(
fspec
.
format
==
float_format
::
fixed
)
options
|=
grisu_options
::
fixed
;
if
(
const_check
(
s
izeof
(
value
)
==
sizeof
(
float
)))
if
(
const_check
(
s
td
::
is_same
<
T
,
float
>
(
)))
options
|=
grisu_options
::
binary32
;
if
(
const_check
(
FMT_DEPRECATED_PERCENT
)
&&
fspec
.
percent
)
value
*=
100
;
int
exp
=
0
;
bool
use_grisu
=
internal
::
use_grisu
<
T
>
()
&&
(
specs
.
type
!=
'a'
&&
specs
.
type
!=
'A'
)
&&
grisu_format
(
static_cast
<
double
>
(
value
),
buffer
,
num_digits
,
options
,
exp
);
char
*
decimal_point_pos
=
nullptr
;
if
(
!
use_grisu
)
decimal_point_pos
=
sprintf_format
(
value
,
buffer
,
specs
);
if
(
!
use_grisu
)
exp
=
sprintf_format
(
value
,
precision
,
fspec
,
buffer
);
if
(
const_check
(
FMT_DEPRECATED_PERCENT
)
&&
fspec
.
percent
)
{
buffer
.
push_back
(
'%'
);
--
exp
;
// Adjust decimal place position.
}
format_specs
as
=
specs
;
if
(
specs
.
align
==
align
::
numeric
)
{
if
(
sign
)
{
auto
&&
it
=
reserve
(
1
);
*
it
++
=
static_cast
<
char_type
>
(
data
::
signs
[
sign
]);
sign
=
sign
::
none
;
if
(
as
.
width
)
--
as
.
width
;
}
as
.
align
=
align
::
right
;
}
else
if
(
specs
.
align
==
align
::
none
)
{
as
.
align
=
align
::
right
;
}
auto
params
=
gen_digits_params
();
params
.
sign
=
sign
;
params
.
format
=
fspec
.
format
;
params
.
num_digits
=
num_digits
;
params
.
trailing_zeros
=
(
precision
!=
0
&&
(
!
specs
.
type
||
fspec
.
format
==
float_format
::
fixed
||
fspec
.
format
==
float_format
::
exp
))
||
specs
.
alt
;
params
.
upper
=
fspec
.
upper
;
num_digits
=
static_cast
<
int
>
(
buffer
.
size
());
char_type
point
=
fspec
.
locale
?
decimal_point
<
char_type
>
(
locale_
)
:
static_cast
<
char_type
>
(
'.'
);
if
(
use_grisu
)
{
auto
params
=
gen_digits_params
();
params
.
sign
=
sign
;
params
.
format
=
fspec
.
format
;
params
.
num_digits
=
num_digits
;
params
.
trailing_zeros
=
(
precision
!=
0
&&
(
!
specs
.
type
||
fspec
.
format
==
float_format
::
fixed
||
fspec
.
format
==
float_format
::
exp
))
||
specs
.
alt
;
params
.
upper
=
fspec
.
upper
;
num_digits
=
static_cast
<
int
>
(
buffer
.
size
());
write_padded
(
as
,
grisu_writer
<
char_type
>
(
buffer
.
data
(),
num_digits
,
exp
,
params
,
point
));
}
else
{
write_padded
(
as
,
double_writer
{
sign
,
buffer
,
decimal_point_pos
,
point
});
}
write_padded
(
specs
,
float_writer
<
char_type
>
(
buffer
.
data
(),
num_digits
,
exp
,
params
,
point
));
}
// Writes a character to the buffer.
void
write
(
char
value
)
{
auto
&&
it
=
reserve
(
1
);
*
it
++
=
value
;
...
...
@@ -1817,10 +1784,9 @@ template <typename Range> class basic_writer {
*
it
++
=
value
;
}
// Writes value to the buffer.
void
write
(
string_view
value
)
{
auto
&&
it
=
reserve
(
value
.
size
());
it
=
internal
::
copy_str
<
char_type
>
(
value
.
begin
(),
value
.
end
(),
it
);
it
=
copy_str
<
char_type
>
(
value
.
begin
(),
value
.
end
(),
it
);
}
void
write
(
wstring_view
value
)
{
static_assert
(
std
::
is_same
<
char_type
,
wchar_t
>::
value
,
""
);
...
...
@@ -1828,26 +1794,23 @@ template <typename Range> class basic_writer {
it
=
std
::
copy
(
value
.
begin
(),
value
.
end
(),
it
);
}
// Writes a formatted string.
template
<
typename
Char
>
void
write
(
const
Char
*
s
,
std
::
size_t
size
,
const
format_specs
&
specs
)
{
write_padded
(
specs
,
str_writer
<
Char
>
{
s
,
size
});
}
template
<
typename
Char
>
void
write
(
basic_string_view
<
Char
>
s
,
const
format_specs
&
specs
=
format_specs
())
{
void
write
(
basic_string_view
<
Char
>
s
,
const
format_specs
&
specs
=
{})
{
const
Char
*
data
=
s
.
data
();
std
::
size_t
size
=
s
.
size
();
if
(
specs
.
precision
>=
0
&&
internal
::
to_unsigned
(
specs
.
precision
)
<
size
)
size
=
internal
::
code_point_index
(
s
,
internal
::
to_unsigned
(
specs
.
precision
));
if
(
specs
.
precision
>=
0
&&
to_unsigned
(
specs
.
precision
)
<
size
)
size
=
code_point_index
(
s
,
to_unsigned
(
specs
.
precision
));
write
(
data
,
size
,
specs
);
}
template
<
typename
UIntPtr
>
void
write_pointer
(
UIntPtr
value
,
const
format_specs
*
specs
)
{
int
num_digits
=
internal
::
count_digits
<
4
>
(
value
);
int
num_digits
=
count_digits
<
4
>
(
value
);
auto
pw
=
pointer_writer
<
UIntPtr
>
{
value
,
num_digits
};
if
(
!
specs
)
return
pw
(
reserve
(
to_unsigned
(
num_digits
)
+
2
));
format_specs
specs_copy
=
*
specs
;
...
...
@@ -3477,8 +3440,7 @@ inline std::basic_string<Char> internal::vformat(
*/
template
<
typename
...
Args
>
inline
std
::
size_t
formatted_size
(
string_view
format_str
,
const
Args
&
...
args
)
{
auto
it
=
format_to
(
internal
::
counting_iterator
(),
format_str
,
args
...);
return
it
.
count
();
return
format_to
(
internal
::
counting_iterator
(),
format_str
,
args
...).
count
();
}
#if FMT_USE_USER_DEFINED_LITERALS
...
...
src/format.cc
View file @
ded1e767
...
...
@@ -36,11 +36,11 @@ template FMT_API std::string internal::vformat<char>(
template
FMT_API
format_context
::
iterator
internal
::
vformat_to
(
internal
::
buffer
<
char
>
&
,
string_view
,
basic_format_args
<
format_context
>);
template
FMT_API
char
*
internal
::
sprintf_format
(
double
,
internal
::
buffer
<
char
>
&
,
sprintf_specs
);
template
FMT_API
char
*
internal
::
sprintf_format
(
long
double
,
internal
::
buffer
<
char
>
&
,
sprintf_specs
);
template
FMT_API
int
internal
::
sprintf_format
(
double
,
int
,
internal
::
float_spec
,
internal
::
buffer
<
char
>
&
);
template
FMT_API
int
internal
::
sprintf_format
(
long
double
,
int
,
internal
::
float_spec
,
internal
::
buffer
<
char
>
&
);
// Explicit instantiations for wchar_t.
...
...
support/Vagrantfile
View file @
ded1e767
...
...
@@ -3,7 +3,7 @@
# A vagrant config for testing against gcc-4.8.
Vagrant
.
configure
(
"2"
)
do
|
config
|
config
.
vm
.
box
=
"ubuntu/
trusty
64"
config
.
vm
.
box
=
"ubuntu/
xenial
64"
config
.
vm
.
provider
"virtualbox"
do
|
vb
|
vb
.
memory
=
"4096"
...
...
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