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
8beadace
Commit
8beadace
authored
Nov 21, 2015
by
vitaut
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve detection of isinf, isnan and getsign
parent
223575b5
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
65 additions
and
60 deletions
+65
-60
format.h
format.h
+64
-59
test/format-impl-test.cc
test/format-impl-test.cc
+1
-1
No files found.
format.h
View file @
8beadace
...
@@ -215,18 +215,73 @@ inline uint32_t clzll(uint64_t x) {
...
@@ -215,18 +215,73 @@ inline uint32_t clzll(uint64_t x) {
# define FMT_ASSERT(condition, message) assert((condition) && message)
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
#endif
// Dummy implementations of signbit and _ecvt_s called if corresponding system
namespace
fmt
{
// functions are not available. These functions are in the namespace fmt_system
namespace
internal
{
// rather than fmt::internal to make sure they don't hide the potential
// overloads in the std namespace.
namespace
fmt_system
{
struct
DummyInt
{
struct
DummyInt
{
int
data
[
2
];
int
data
[
2
];
operator
int
()
const
{
return
0
;
}
operator
int
()
const
{
return
0
;
}
};
};
typedef
std
::
numeric_limits
<
fmt
::
internal
::
DummyInt
>
FPUtil
;
// Dummy implementations of system functions such as signbit and ecvt called
// if the latter are not available.
inline
DummyInt
signbit
(...)
{
return
DummyInt
();
}
inline
DummyInt
signbit
(...)
{
return
DummyInt
();
}
inline
DummyInt
_ecvt_s
(...)
{
return
DummyInt
();
}
inline
DummyInt
_ecvt_s
(...)
{
return
DummyInt
();
}
inline
DummyInt
isinf
(...)
{
return
DummyInt
();
}
inline
DummyInt
_finite
(...)
{
return
DummyInt
();
}
inline
DummyInt
isnan
(...)
{
return
DummyInt
();
}
inline
DummyInt
_isnan
(...)
{
return
DummyInt
();
}
}
}
}
// namespace fmt
namespace
std
{
// Standard permits specialization of std::numeric_limits. This specialization
// is used to resolve ambiguity between isinf and std::isinf in glibc:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891
// and the same for isnan and signbit.
template
<
>
class
numeric_limits
<
fmt
::
internal
::
DummyInt
>
:
public
std
::
numeric_limits
<
int
>
{
public:
// Portable version of isinf.
template
<
typename
T
>
static
bool
isinfinity
(
T
x
)
{
using
namespace
fmt
::
internal
;
// The resolution "priority" is:
// isinf macro > std::isinf > ::isinf > fmt::internal::isinf
if
(
sizeof
(
isinf
(
x
))
==
sizeof
(
bool
)
||
sizeof
(
isinf
(
x
))
==
sizeof
(
int
))
return
isinf
(
x
);
return
!
_finite
(
x
);
}
// Portable version of isnan.
template
<
typename
T
>
static
bool
isnotanumber
(
T
x
)
{
using
namespace
fmt
::
internal
;
if
(
sizeof
(
isnan
(
x
))
==
sizeof
(
bool
)
||
sizeof
(
isnan
(
x
))
==
sizeof
(
int
))
return
isnan
(
x
);
return
_isnan
(
x
);
}
// Portable version of signbit.
static
bool
isnegative
(
double
x
)
{
using
namespace
fmt
::
internal
;
if
(
sizeof
(
signbit
(
x
))
==
sizeof
(
int
))
return
signbit
(
x
);
if
(
x
<
0
)
return
true
;
if
(
!
isnotanumber
(
x
))
return
false
;
int
dec
=
0
,
sign
=
0
;
if
(
sizeof
(
_ecvt_s
(
0
,
0
,
x
,
0
,
0
,
0
))
==
sizeof
(
int
))
{
char
buffer
[
2
];
// The buffer size must be >= 2 or _ecvt_s will fail.
_ecvt_s
(
buffer
,
sizeof
(
buffer
),
x
,
0
,
&
dec
,
&
sign
);
return
sign
;
}
char
*
result
=
ecvt
(
x
,
0
,
&
dec
,
&
sign
);
(
void
)
result
;
// Suppress a warning about unused return value of ecvt.
return
sign
;
}
};
}
// namespace std
namespace
fmt
{
namespace
fmt
{
...
@@ -592,56 +647,6 @@ class FixedBuffer : public fmt::Buffer<Char> {
...
@@ -592,56 +647,6 @@ class FixedBuffer : public fmt::Buffer<Char> {
void
grow
(
std
::
size_t
size
);
void
grow
(
std
::
size_t
size
);
};
};
// Portable version of signbit.
inline
int
getsign
(
double
x
)
{
// When compiled in C++11 mode signbit is no longer a macro but a
// function defined in namespace std and the macro is undefined.
using
namespace
std
;
using
namespace
fmt_system
;
if
(
sizeof
(
signbit
(
x
))
==
sizeof
(
int
))
return
signbit
(
x
);
if
(
x
<
0
)
return
1
;
if
(
x
==
x
)
return
0
;
int
dec
=
0
,
sign
=
0
;
if
(
sizeof
(
_ecvt_s
(
0
,
0
,
x
,
0
,
0
,
0
))
==
sizeof
(
int
))
{
char
buffer
[
2
];
// The buffer size must be >= 2 or _ecvt_s will fail.
_ecvt_s
(
buffer
,
sizeof
(
buffer
),
x
,
0
,
&
dec
,
&
sign
);
return
sign
;
}
char
*
result
=
ecvt
(
x
,
0
,
&
dec
,
&
sign
);
(
void
)
result
;
// Suppress warning about unused return value of ecvt.
return
sign
;
}
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
// Portable version of isinf.
# ifdef isinf
inline
int
isinfinity
(
double
x
)
{
return
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
isinf
(
x
);
}
# else
inline
int
isinfinity
(
double
x
)
{
return
std
::
isinf
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
std
::
isinf
(
x
);
}
# endif
// Portable version of isnan.
# ifdef isnan
inline
int
isnotanumber
(
double
x
)
{
return
isnan
(
x
);
}
inline
int
isnotanumber
(
long
double
x
)
{
return
isnan
(
x
);
}
# else
inline
int
isnotanumber
(
double
x
)
{
return
std
::
isnan
(
x
);
}
inline
int
isnotanumber
(
long
double
x
)
{
return
std
::
isnan
(
x
);
}
# endif
#else
inline
int
isinfinity
(
double
x
)
{
return
!
_finite
(
x
);
}
inline
int
isinfinity
(
long
double
x
)
{
return
!
_finite
(
static_cast
<
double
>
(
x
));
}
inline
int
isnotanumber
(
double
x
)
{
return
_isnan
(
x
);
}
inline
int
isnotanumber
(
long
double
x
)
{
return
_isnan
(
static_cast
<
double
>
(
x
));
}
#endif
template
<
typename
Char
>
template
<
typename
Char
>
class
BasicCharTraits
{
class
BasicCharTraits
{
public:
public:
...
@@ -2411,16 +2416,16 @@ void BasicWriter<Char>::write_double(
...
@@ -2411,16 +2416,16 @@ void BasicWriter<Char>::write_double(
}
}
char
sign
=
0
;
char
sign
=
0
;
// Use
getsign
instead of value < 0 because the latter is always
// Use
isnegative
instead of value < 0 because the latter is always
// false for NaN.
// false for NaN.
if
(
internal
::
getsign
(
static_cast
<
double
>
(
value
)))
{
if
(
internal
::
FPUtil
::
isnegative
(
static_cast
<
double
>
(
value
)))
{
sign
=
'-'
;
sign
=
'-'
;
value
=
-
value
;
value
=
-
value
;
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
}
else
if
(
spec
.
flag
(
SIGN_FLAG
))
{
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
sign
=
spec
.
flag
(
PLUS_FLAG
)
?
'+'
:
' '
;
}
}
if
(
internal
::
isnotanumber
(
value
))
{
if
(
internal
::
FPUtil
::
isnotanumber
(
value
))
{
// Format NaN ourselves because sprintf's output is not consistent
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
nan_size
=
4
;
std
::
size_t
nan_size
=
4
;
...
@@ -2435,7 +2440,7 @@ void BasicWriter<Char>::write_double(
...
@@ -2435,7 +2440,7 @@ void BasicWriter<Char>::write_double(
return
;
return
;
}
}
if
(
internal
::
isinfinity
(
value
))
{
if
(
internal
::
FPUtil
::
isinfinity
(
value
))
{
// Format infinity ourselves because sprintf's output is not consistent
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
// across platforms.
std
::
size_t
inf_size
=
4
;
std
::
size_t
inf_size
=
4
;
...
...
test/format-impl-test.cc
View file @
8beadace
...
@@ -49,7 +49,7 @@ TEST(FormatTest, ArgConverter) {
...
@@ -49,7 +49,7 @@ TEST(FormatTest, ArgConverter) {
TEST
(
FormatTest
,
FormatNegativeNaN
)
{
TEST
(
FormatTest
,
FormatNegativeNaN
)
{
double
nan
=
std
::
numeric_limits
<
double
>::
quiet_NaN
();
double
nan
=
std
::
numeric_limits
<
double
>::
quiet_NaN
();
if
(
fmt
::
internal
::
getsign
(
-
nan
))
if
(
fmt
::
internal
::
FPUtil
::
isnegative
(
-
nan
))
EXPECT_EQ
(
"-nan"
,
fmt
::
format
(
"{}"
,
-
nan
));
EXPECT_EQ
(
"-nan"
,
fmt
::
format
(
"{}"
,
-
nan
));
else
else
fmt
::
print
(
"Warning: compiler doesn't handle negative NaN correctly"
);
fmt
::
print
(
"Warning: compiler doesn't handle negative NaN correctly"
);
...
...
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