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
Expand all
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 @@
...
@@ -51,12 +51,8 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
// system functions are not available.
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
inline
fmt
::
internal
::
null
<>
strerror_r
(
int
,
char
*
,
...)
{
return
{};
}
return
{};
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
{};
}
}
inline
fmt
::
internal
::
null
<>
strerror_s
(
char
*
,
std
::
size_t
,
...)
{
return
{};
}
FMT_BEGIN_NAMESPACE
FMT_BEGIN_NAMESPACE
namespace
internal
{
namespace
internal
{
...
@@ -250,20 +246,6 @@ template <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) {
...
@@ -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
;
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
>
template
<
typename
T
>
const
char
basic_data
<
T
>::
digits
[]
=
const
char
basic_data
<
T
>::
digits
[]
=
"0001020304050607080910111213141516171819"
"0001020304050607080910111213141516171819"
...
@@ -276,9 +258,9 @@ template <typename T>
...
@@ -276,9 +258,9 @@ template <typename T>
const
char
basic_data
<
T
>::
hex_digits
[]
=
"0123456789abcdef"
;
const
char
basic_data
<
T
>::
hex_digits
[]
=
"0123456789abcdef"
;
#define FMT_POWERS_OF_10(factor) \
#define FMT_POWERS_OF_10(factor) \
factor * 10, (factor)
* 100, (factor) * 1000, (factor) * 10000, (factor) *
100000, \
factor * 10, (factor)
*100, (factor)*1000, (factor)*10000, (factor)*
100000, \
(factor)
* 1000000, (factor) * 10000000, (factor) *
100000000, \
(factor)
*1000000, (factor)*10000000, (factor)*
100000000, \
(factor)
*
1000000000
(factor)
*
1000000000
template
<
typename
T
>
template
<
typename
T
>
const
uint64_t
basic_data
<
T
>::
powers_of_10_64
[]
=
{
const
uint64_t
basic_data
<
T
>::
powers_of_10_64
[]
=
{
...
@@ -1121,78 +1103,99 @@ bool grisu_format(Double value, buffer<char>& buf, int precision,
...
@@ -1121,78 +1103,99 @@ bool grisu_format(Double value, buffer<char>& buf, int precision,
return
true
;
return
true
;
}
}
template
<
typename
Double
>
template
<
typename
Float
>
char
*
sprintf_format
(
Double
value
,
internal
::
buffer
<
char
>&
buf
,
int
sprintf_format
(
Float
value
,
int
precision
,
float_spec
spec
,
sprintf_specs
specs
)
{
buffer
<
char
>&
buf
)
{
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
// 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.
// Build
the
format string.
enum
{
max_format_size
=
10
};
// longest format: %#-*.*Lg
enum
{
max_format_size
=
7
};
// Ths longest format is "%#.*Le".
char
format
[
max_format_size
];
char
format
[
max_format_size
];
char
*
format_ptr
=
format
;
char
*
format_ptr
=
format
;
*
format_ptr
++
=
'%'
;
*
format_ptr
++
=
'%'
;
if
(
spec
s
.
alt
||
!
specs
.
type
)
*
format_ptr
++
=
'#'
;
if
(
spec
.
alt
)
*
format_ptr
++
=
'#'
;
if
(
specs
.
precision
>=
0
)
{
if
(
precision
>
0
)
{
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'.'
;
*
format_ptr
++
=
'*'
;
*
format_ptr
++
=
'*'
;
}
}
if
(
std
::
is_same
<
Double
,
long
double
>::
value
)
*
format_ptr
++
=
'L'
;
if
(
std
::
is_same
<
Float
,
long
double
>
())
*
format_ptr
++
=
'L'
;
*
format_ptr
++
=
spec
.
format
!=
float_format
::
hex
char
type
=
specs
.
type
;
?
(
spec
.
format
==
float_format
::
fixed
?
'f'
:
'e'
)
:
(
spec
.
upper
?
'A'
:
'a'
);
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
;
*
format_ptr
=
'\0'
;
*
format_ptr
=
'\0'
;
// Format using snprintf.
// Format using snprintf.
char
*
start
=
nullptr
;
auto
offset
=
buf
.
size
();
char
*
decimal_point_pos
=
nullptr
;
for
(;;)
{
for
(;;)
{
std
::
size_t
buffer_size
=
buf
.
capacity
();
auto
begin
=
buf
.
data
()
+
offset
;
start
=
&
buf
[
0
];
auto
capacity
=
buf
.
capacity
()
-
offset
;
int
result
=
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
format_float
(
start
,
buffer_size
,
format
,
specs
.
precision
,
value
);
if
(
precision
>
100000
)
if
(
result
>=
0
)
{
throw
std
::
runtime_error
(
unsigned
n
=
internal
::
to_unsigned
(
result
);
"fuzz mode - avoid large allocation inside snprintf"
);
if
(
n
<
buf
.
capacity
())
{
#endif
// Find the decimal point.
// Suppress the warning about a nonliteral format string.
auto
p
=
buf
.
data
(),
end
=
p
+
n
;
auto
snprintf_ptr
=
FMT_SNPRINTF
;
if
(
*
p
==
'+'
||
*
p
==
'-'
)
++
p
;
int
result
=
precision
>
0
if
(
specs
.
type
!=
'a'
&&
specs
.
type
!=
'A'
)
{
?
snprintf_ptr
(
begin
,
capacity
,
format
,
precision
,
value
)
while
(
p
<
end
&&
*
p
>=
'0'
&&
*
p
<=
'9'
)
++
p
;
:
snprintf_ptr
(
begin
,
capacity
,
format
,
value
);
if
(
p
<
end
&&
*
p
!=
'e'
&&
*
p
!=
'E'
)
{
if
(
result
<
0
)
{
decimal_point_pos
=
p
;
buf
.
reserve
(
capacity
+
1
);
// The buffer will grow exponentially.
if
(
!
specs
.
type
)
{
continue
;
// Keep only one trailing zero after the decimal point.
}
++
p
;
unsigned
size
=
to_unsigned
(
result
);
if
(
*
p
==
'0'
)
++
p
;
if
(
size
>
capacity
)
{
while
(
p
!=
end
&&
*
p
>=
'1'
&&
*
p
<=
'9'
)
++
p
;
buf
.
reserve
(
size
+
1
);
// Add 1 for the terminating '\0'.
char
*
where
=
p
;
continue
;
while
(
p
!=
end
&&
*
p
==
'0'
)
++
p
;
}
if
(
p
==
end
||
*
p
<
'0'
||
*
p
>
'9'
)
{
auto
is_digit
=
[](
char
c
)
{
return
c
>=
'0'
&&
c
<=
'9'
;
};
if
(
p
!=
end
)
std
::
memmove
(
where
,
p
,
to_unsigned
(
end
-
p
));
if
(
spec
.
format
==
float_format
::
fixed
)
{
n
-=
static_cast
<
unsigned
>
(
p
-
where
);
// Find and remove the decimal point.
}
auto
end
=
begin
+
size
,
p
=
end
;
}
do
{
}
--
p
;
}
}
while
(
is_digit
(
*
p
));
buf
.
resize
(
n
);
int
fraction_size
=
static_cast
<
int
>
(
end
-
p
-
1
);
break
;
// The buffer is large enough - continue with formatting.
std
::
memmove
(
p
,
p
+
1
,
fraction_size
);
}
buf
.
resize
(
size
-
1
);
buf
.
reserve
(
n
+
1
);
return
-
fraction_size
;
}
else
{
}
// If result is negative we ask to increase the capacity by at least 1,
if
(
spec
.
format
==
float_format
::
hex
)
{
// but as std::vector, the buffer grows exponentially.
buf
.
resize
(
size
+
offset
);
buf
.
reserve
(
buf
.
capacity
()
+
1
);
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
}
// namespace internal
...
...
include/fmt/format.h
View file @
ded1e767
This diff is collapsed.
Click to expand it.
src/format.cc
View file @
ded1e767
...
@@ -36,11 +36,11 @@ template FMT_API std::string internal::vformat<char>(
...
@@ -36,11 +36,11 @@ template FMT_API std::string internal::vformat<char>(
template
FMT_API
format_context
::
iterator
internal
::
vformat_to
(
template
FMT_API
format_context
::
iterator
internal
::
vformat_to
(
internal
::
buffer
<
char
>
&
,
string_view
,
basic_format_args
<
format_context
>);
internal
::
buffer
<
char
>
&
,
string_view
,
basic_format_args
<
format_context
>);
template
FMT_API
char
*
internal
::
sprintf_format
(
double
,
internal
::
buffer
<
char
>
&
,
template
FMT_API
int
internal
::
sprintf_format
(
double
,
int
,
internal
::
float_spec
,
sprintf_specs
);
internal
::
buffer
<
char
>
&
);
template
FMT_API
char
*
internal
::
sprintf_format
(
long
double
,
template
FMT_API
int
internal
::
sprintf_format
(
long
double
,
int
,
internal
::
buffer
<
char
>
&
,
internal
::
float_spec
,
sprintf_specs
);
internal
::
buffer
<
char
>
&
);
// Explicit instantiations for wchar_t.
// Explicit instantiations for wchar_t.
...
...
support/Vagrantfile
View file @
ded1e767
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
# A vagrant config for testing against gcc-4.8.
# A vagrant config for testing against gcc-4.8.
Vagrant
.
configure
(
"2"
)
do
|
config
|
Vagrant
.
configure
(
"2"
)
do
|
config
|
config
.
vm
.
box
=
"ubuntu/
trusty
64"
config
.
vm
.
box
=
"ubuntu/
xenial
64"
config
.
vm
.
provider
"virtualbox"
do
|
vb
|
config
.
vm
.
provider
"virtualbox"
do
|
vb
|
vb
.
memory
=
"4096"
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