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
4e4b8570
Commit
4e4b8570
authored
May 28, 2018
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement simple version of Grisu
parent
40275579
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
103 additions
and
57 deletions
+103
-57
include/fmt/format-inl.h
include/fmt/format-inl.h
+1
-1
include/fmt/format.h
include/fmt/format.h
+102
-56
No files found.
include/fmt/format-inl.h
View file @
4e4b8570
...
...
@@ -346,7 +346,7 @@ FMT_FUNC fp operator*(fp x, fp y) {
FMT_FUNC
fp
get_cached_power
(
int
min_exponent
,
int
&
pow10_exponent
)
{
const
double
one_over_log2_10
=
0.30102999566398114
;
// 1 / log2(10)
int
index
=
static_cast
<
int
>
(
std
::
ceil
(
(
min_exponent
+
fp
::
fp_
significand_size
-
1
)
*
one_over_log2_10
));
(
min_exponent
+
fp
::
significand_size
-
1
)
*
one_over_log2_10
));
// Decimal exponent of the first (smallest) cached power of 10.
const
int
first_dec_exp
=
-
348
;
// Difference between two consecutive decimal exponents in cached powers of 10.
...
...
include/fmt/format.h
View file @
4e4b8570
...
...
@@ -132,10 +132,15 @@
# endif
#endif
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || FMT_MSC_VER >= 1600
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \
FMT_MSC_VER >= 1600
# define FMT_USE_TRAILING_RETURN 1
#endif
#ifndef FMT_USE_GRISU
# define FMT_USE_GRISU 0
#endif
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
#ifndef _MSC_VER
...
...
@@ -274,8 +279,7 @@ class fp {
significand_type
f
;
int
e
;
static
constexpr
int
fp_significand_size
=
sizeof
(
significand_type
)
*
char_size
;
static
constexpr
int
significand_size
=
sizeof
(
significand_type
)
*
char_size
;
fp
(
uint64_t
f
,
int
e
)
:
f
(
f
),
e
(
e
)
{}
...
...
@@ -311,7 +315,7 @@ class fp {
--
e
;
}
// Subtract 1 to account for hidden bit.
auto
offset
=
fp_
significand_size
-
double_significand_size
-
SHIFT
-
1
;
auto
offset
=
significand_size
-
double_significand_size
-
SHIFT
-
1
;
f
<<=
offset
;
e
-=
offset
;
}
...
...
@@ -395,6 +399,38 @@ FMT_BEGIN_NAMESPACE
template
<
typename
Range
>
class
basic_writer
;
template
<
typename
OutputIt
,
typename
T
=
typename
OutputIt
::
value_type
>
class
output_range
{
private:
OutputIt
it_
;
// Unused yet.
typedef
void
sentinel
;
sentinel
end
()
const
;
public:
typedef
OutputIt
iterator
;
typedef
T
value_type
;
explicit
output_range
(
OutputIt
it
)
:
it_
(
it
)
{}
OutputIt
begin
()
const
{
return
it_
;
}
};
// A range where begin() returns back_insert_iterator.
template
<
typename
Container
>
class
back_insert_range
:
public
output_range
<
std
::
back_insert_iterator
<
Container
>>
{
typedef
output_range
<
std
::
back_insert_iterator
<
Container
>>
base
;
public:
typedef
typename
Container
::
value_type
value_type
;
back_insert_range
(
Container
&
c
)
:
base
(
std
::
back_inserter
(
c
))
{}
back_insert_range
(
typename
base
::
iterator
it
)
:
base
(
it
)
{}
};
typedef
basic_writer
<
back_insert_range
<
internal
::
buffer
>>
writer
;
typedef
basic_writer
<
back_insert_range
<
internal
::
wbuffer
>>
wwriter
;
/** A formatting error such as invalid format string. */
class
format_error
:
public
std
::
runtime_error
{
public:
...
...
@@ -2619,6 +2655,10 @@ class basic_writer {
// Formats a floating-point number (double or long double).
template
<
typename
T
>
void
write_double
(
T
value
,
const
format_specs
&
spec
);
template
<
typename
T
>
void
write_double_sprintf
(
T
value
,
const
format_specs
&
spec
,
internal
::
basic_buffer
<
char_type
>&
buffer
,
char
sign
);
template
<
typename
Char
>
struct
str_writer
{
...
...
@@ -2841,7 +2881,60 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
return
write_inf_or_nan
(
handler
.
upper
?
"INF"
:
"inf"
);
basic_memory_buffer
<
char_type
>
buffer
;
if
(
FMT_USE_GRISU
&&
sizeof
(
T
)
<=
sizeof
(
double
)
&&
std
::
numeric_limits
<
double
>::
is_iec559
)
{
internal
::
fp
fp_value
(
static_cast
<
double
>
(
value
));
fp_value
.
normalize
();
// Find a cached power of 10 close to 1 / fp_value.
int
dec_exp
=
0
;
int
min_exp
=
-
60
;
auto
dec_pow
=
internal
::
get_cached_power
(
min_exp
-
(
fp_value
.
e
+
internal
::
fp
::
significand_size
),
dec_exp
);
internal
::
fp
product
=
fp_value
*
dec_pow
;
// Generate output.
internal
::
fp
one
(
1ull
<<
-
product
.
e
,
product
.
e
);
uint32_t
hi
=
product
.
f
>>
-
one
.
e
;
uint64_t
f
=
product
.
f
&
(
one
.
f
-
1
);
typedef
back_insert_range
<
internal
::
basic_buffer
<
char_type
>>
range
;
basic_writer
<
range
>
w
{
range
(
buffer
)};
w
.
write
(
hi
);
w
.
write
(
'.'
);
for
(
int
i
=
0
;
i
<
18
;
++
i
)
{
f
*=
10
;
w
.
write
(
static_cast
<
char
>
(
'0'
+
(
f
>>
-
one
.
e
)));
f
&=
one
.
f
-
1
;
}
w
.
write
(
'e'
);
w
.
write
(
-
dec_exp
);
}
else
{
format_specs
normalized_spec
(
spec
);
normalized_spec
.
type_
=
handler
.
type
;
write_double_sprintf
(
value
,
normalized_spec
,
buffer
,
sign
);
}
unsigned
n
=
buffer
.
size
();
align_spec
as
=
spec
;
if
(
spec
.
align
()
==
ALIGN_NUMERIC
)
{
if
(
sign
)
{
*
reserve
(
1
)
=
sign
;
sign
=
0
;
if
(
as
.
width_
)
--
as
.
width_
;
}
as
.
align_
=
ALIGN_RIGHT
;
}
else
{
if
(
spec
.
align
()
==
ALIGN_DEFAULT
)
as
.
align_
=
ALIGN_RIGHT
;
if
(
sign
)
++
n
;
}
write_padded
(
n
,
as
,
double_writer
{
n
,
sign
,
buffer
});
}
template
<
typename
Range
>
template
<
typename
T
>
void
basic_writer
<
Range
>::
write_double_sprintf
(
T
value
,
const
format_specs
&
spec
,
internal
::
basic_buffer
<
char_type
>&
buffer
,
char
sign
)
{
unsigned
width
=
spec
.
width
();
if
(
sign
)
{
buffer
.
reserve
(
width
>
1u
?
width
:
1u
);
...
...
@@ -2864,11 +2957,10 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
}
append_float_length
(
format_ptr
,
value
);
*
format_ptr
++
=
handler
.
type
;
*
format_ptr
++
=
spec
.
type
()
;
*
format_ptr
=
'\0'
;
// Format using snprintf.
unsigned
n
=
0
;
char_type
*
start
=
FMT_NULL
;
for
(;;)
{
std
::
size_t
buffer_size
=
buffer
.
capacity
();
...
...
@@ -2885,9 +2977,11 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
int
result
=
internal
::
char_traits
<
char_type
>::
format_float
(
start
,
buffer_size
,
format
,
width_for_sprintf
,
spec
.
precision
(),
value
);
if
(
result
>=
0
)
{
n
=
internal
::
to_unsigned
(
result
);
if
(
n
<
buffer
.
capacity
())
unsigned
n
=
internal
::
to_unsigned
(
result
);
if
(
n
<
buffer
.
capacity
())
{
buffer
.
resize
(
n
);
break
;
// The buffer is large enough - continue with formatting.
}
buffer
.
reserve
(
n
+
1
);
}
else
{
// If result is negative we ask to increase the capacity by at least 1,
...
...
@@ -2895,56 +2989,8 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
buffer
.
reserve
(
buffer
.
capacity
()
+
1
);
}
}
align_spec
as
=
spec
;
if
(
spec
.
align
()
==
ALIGN_NUMERIC
)
{
if
(
sign
)
{
*
reserve
(
1
)
=
sign
;
sign
=
0
;
if
(
as
.
width_
)
--
as
.
width_
;
}
as
.
align_
=
ALIGN_RIGHT
;
}
else
{
if
(
spec
.
align
()
==
ALIGN_DEFAULT
)
as
.
align_
=
ALIGN_RIGHT
;
if
(
sign
)
++
n
;
}
write_padded
(
n
,
as
,
double_writer
{
n
,
sign
,
buffer
});
}
template
<
typename
OutputIt
,
typename
T
=
typename
OutputIt
::
value_type
>
class
output_range
{
private:
OutputIt
it_
;
// Unused yet.
typedef
void
sentinel
;
sentinel
end
()
const
;
public:
typedef
OutputIt
iterator
;
typedef
T
value_type
;
explicit
output_range
(
OutputIt
it
)
:
it_
(
it
)
{}
OutputIt
begin
()
const
{
return
it_
;
}
};
// A range where begin() returns back_insert_iterator.
template
<
typename
Container
>
class
back_insert_range
:
public
output_range
<
std
::
back_insert_iterator
<
Container
>>
{
typedef
output_range
<
std
::
back_insert_iterator
<
Container
>>
base
;
public:
typedef
typename
Container
::
value_type
value_type
;
back_insert_range
(
Container
&
c
)
:
base
(
std
::
back_inserter
(
c
))
{}
back_insert_range
(
typename
base
::
iterator
it
)
:
base
(
it
)
{}
};
typedef
basic_writer
<
back_insert_range
<
internal
::
buffer
>>
writer
;
typedef
basic_writer
<
back_insert_range
<
internal
::
wbuffer
>>
wwriter
;
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.
FMT_API
void
report_system_error
(
int
error_code
,
...
...
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