Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yaml-cpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
yaml-cpp
Commits
ebfbf271
Commit
ebfbf271
authored
Oct 22, 2024
by
Simon Gene Gottlieb
Committed by
Jesse Beder
Nov 07, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
patch: added more defensive programming techniques
parent
06ffaf31
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
41 additions
and
8 deletions
+41
-8
src/fptostring.cpp
+41
-8
No files found.
src/fptostring.cpp
View file @
ebfbf271
...
@@ -15,10 +15,10 @@ namespace fp_formatting {
...
@@ -15,10 +15,10 @@ namespace fp_formatting {
/**
/**
* Converts a integer into its ASCII digits.
* Converts a integer into its ASCII digits.
*
*
* @param begin/end - a buffer, must be at least 20bytes long
* @param begin/end - a buffer, must be at least 20bytes long
.
* @param value
- input value
* @param value
- input value.
* @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
* @param width
- minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
* @return
- number of digits filled into the buffer.
* @return
- number of digits filled into the buffer (or -1 if preconditions are not meet)
*
*
* Example:
* Example:
* std::array<char, 20> buffer;
* std::array<char, 20> buffer;
...
@@ -29,10 +29,26 @@ namespace fp_formatting {
...
@@ -29,10 +29,26 @@ namespace fp_formatting {
* assert(buffer[2] == '3');
* assert(buffer[2] == '3');
*/
*/
int
ConvertToChars
(
char
*
begin
,
char
*
end
,
size_t
value
,
int
width
=
1
)
{
int
ConvertToChars
(
char
*
begin
,
char
*
end
,
size_t
value
,
int
width
=
1
)
{
// precondition of this function (will trigger in debug build)
assert
(
width
>=
1
);
assert
(
width
>=
1
);
assert
(
end
>=
begin
);
// end must be after begin
assert
(
end
>=
begin
);
// end must be after begin
assert
(
end
-
begin
>=
width
);
// Buffer must be large enough
assert
(
end
-
begin
>=
width
);
// Buffer must be large enough
assert
(
end
-
begin
>=
20
);
// 2^64 has 20digits, so at least 20 digits must be available
assert
(
end
-
begin
>=
20
);
// 2^64 has 20digits, so at least 20 digits must be available
// defensive programming, abort if precondition are not met (will trigger in release build)
if
(
width
<
1
)
{
return
-
1
;
}
if
(
end
<
begin
)
{
return
-
1
;
}
if
(
end
-
begin
<
width
)
{
return
-
1
;
}
if
(
end
-
begin
<
20
)
{
return
-
1
;
}
// count number of digits, and fill digits array accordingly
// count number of digits, and fill digits array accordingly
int
digits_ct
{};
int
digits_ct
{};
...
@@ -59,8 +75,7 @@ int ConvertToChars(char* begin, char* end, size_t value, int width=1) {
...
@@ -59,8 +75,7 @@ int ConvertToChars(char* begin, char* end, size_t value, int width=1) {
*/
*/
template
<
typename
T
>
template
<
typename
T
>
std
::
string
FpToString
(
T
v
,
int
precision
=
0
)
{
std
::
string
FpToString
(
T
v
,
int
precision
=
0
)
{
// assert(precision > 0);
// hard coded constant, at which exponent should switch to a scientific notation
// hardcoded constant, at which exponent should switch to a scientific notation
int
const
lowerExponentThreshold
=
-
5
;
int
const
lowerExponentThreshold
=
-
5
;
int
const
upperExponentThreshold
=
(
precision
==
0
)
?
6
:
precision
;
int
const
upperExponentThreshold
=
(
precision
==
0
)
?
6
:
precision
;
if
(
precision
==
0
)
{
if
(
precision
==
0
)
{
...
@@ -70,6 +85,7 @@ std::string FpToString(T v, int precision = 0) {
...
@@ -70,6 +85,7 @@ std::string FpToString(T v, int precision = 0) {
// dragonbox/to_decimal does not handle value 0, inf, NaN
// dragonbox/to_decimal does not handle value 0, inf, NaN
if
(
v
==
0
||
std
::
isinf
(
v
)
||
std
::
isnan
(
v
))
{
if
(
v
==
0
||
std
::
isinf
(
v
)
||
std
::
isnan
(
v
))
{
std
::
stringstream
ss
;
std
::
stringstream
ss
;
ss
.
imbue
(
std
::
locale
(
"C"
));
ss
<<
v
;
ss
<<
v
;
return
ss
.
str
();
return
ss
.
str
();
}
}
...
@@ -79,6 +95,14 @@ std::string FpToString(T v, int precision = 0) {
...
@@ -79,6 +95,14 @@ std::string FpToString(T v, int precision = 0) {
auto
digits
=
std
::
array
<
char
,
20
>
{};
// max digits of size_t is 20.
auto
digits
=
std
::
array
<
char
,
20
>
{};
// max digits of size_t is 20.
auto
digits_ct
=
ConvertToChars
(
digits
.
data
(),
digits
.
data
()
+
digits
.
size
(),
r
.
significand
);
auto
digits_ct
=
ConvertToChars
(
digits
.
data
(),
digits
.
data
()
+
digits
.
size
(),
r
.
significand
);
// defensive programming, ConvertToChars arguments are invalid
if
(
digits_ct
==
-
1
)
{
std
::
stringstream
ss
;
ss
.
imbue
(
std
::
locale
(
"C"
));
ss
<<
v
;
return
ss
.
str
();
}
// check if requested precision is lower than
// check if requested precision is lower than
// required digits for exact representation
// required digits for exact representation
if
(
digits_ct
>
precision
)
{
if
(
digits_ct
>
precision
)
{
...
@@ -133,6 +157,15 @@ std::string FpToString(T v, int precision = 0) {
...
@@ -133,6 +157,15 @@ std::string FpToString(T v, int precision = 0) {
*
(
output_ptr
++
)
=
(
exponent
>=
0
)
?
'+'
:
'-'
;
*
(
output_ptr
++
)
=
(
exponent
>=
0
)
?
'+'
:
'-'
;
auto
exp_digits
=
std
::
array
<
char
,
20
>
{};
auto
exp_digits
=
std
::
array
<
char
,
20
>
{};
auto
exp_digits_ct
=
ConvertToChars
(
exp_digits
.
data
(),
exp_digits
.
data
()
+
exp_digits
.
size
(),
std
::
abs
(
exponent
),
/*.precision=*/
2
);
auto
exp_digits_ct
=
ConvertToChars
(
exp_digits
.
data
(),
exp_digits
.
data
()
+
exp_digits
.
size
(),
std
::
abs
(
exponent
),
/*.precision=*/
2
);
// defensive programming, ConvertToChars arguments are invalid
if
(
exp_digits_ct
==
-
1
)
{
std
::
stringstream
ss
;
ss
.
imbue
(
std
::
locale
(
"C"
));
ss
<<
v
;
return
ss
.
str
();
}
for
(
int
i
{
0
};
i
<
exp_digits_ct
;
++
i
)
{
for
(
int
i
{
0
};
i
<
exp_digits_ct
;
++
i
)
{
*
(
output_ptr
++
)
=
exp_digits
[
i
];
*
(
output_ptr
++
)
=
exp_digits
[
i
];
}
}
...
...
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