🔨 refactored code to avoid using strcpy/strlen/strcat (#463)

This commit is contained in:
Niels Lohmann 2017-02-20 17:37:34 +01:00
parent 716485a965
commit 83a9c60dbd
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
2 changed files with 74 additions and 22 deletions

View file

@ -38,7 +38,7 @@ SOFTWARE.
#include <cstddef> // nullptr_t, ptrdiff_t, size_t #include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // int64_t, uint64_t #include <cstdint> // int64_t, uint64_t
#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull #include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull
#include <cstring> // strcpy, strlen #include <cstring> // strlen
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <functional> // function, hash, less #include <functional> // function, hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
@ -8259,6 +8259,7 @@ class basic_json
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::true_type) void x_write(NumberType x, /*is_integral=*/std::true_type)
{ {
// special case for "0"
if (x == 0) if (x == 0)
{ {
m_buf[0] = '0'; m_buf[0] = '0';
@ -8291,9 +8292,17 @@ class basic_json
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::false_type) void x_write(NumberType x, /*is_integral=*/std::false_type)
{ {
// special case for 0.0 and -0.0
if (x == 0) if (x == 0)
{ {
std::strcpy(m_buf.data(), std::signbit(x) ? "-0.0" : "0.0"); size_t i = 0;
if (std::signbit(x))
{
m_buf[i++] = '-';
}
m_buf[i++] = '0';
m_buf[i++] = '.';
m_buf[i] = '0';
return; return;
} }
@ -8342,18 +8351,35 @@ class basic_json
} }
// determine if need to append ".0" // determine if need to append ".0"
const auto data_end = m_buf.begin() + strlen(m_buf.data()); size_t i = 0;
bool value_is_int_like = true;
const bool value_is_int_like = for (i = 0; i < m_buf.size(); ++i)
std::none_of(m_buf.begin(), data_end, [](const char c)
{ {
return (c == '.' or c == 'e' or c == 'E'); // break when end of number is reached
}); if (m_buf[i] == '\0')
assert(data_end + 2 < m_buf.end()); {
break;
}
// check if we find non-int character
value_is_int_like = value_is_int_like and m_buf[i] != '.' and
m_buf[i] != 'e' and m_buf[i] != 'E';
}
if (value_is_int_like) if (value_is_int_like)
{ {
strcat(m_buf.data(), ".0"); // there must be 2 bytes left for ".0"
assert((i + 2) < m_buf.size());
// we write to the end of the number
assert(m_buf[i] == '\0');
assert(m_buf[i - 1] != '\0');
// add ".0"
m_buf[i] = '.';
m_buf[i + 1] = '0';
// the resulting string is properly terminated
assert(m_buf[i + 2] == '\0');
} }
} }
}; };
@ -11136,7 +11162,7 @@ basic_json_parser_74:
// update data to point to the modified bytes // update data to point to the modified bytes
if ((len + 1) < buf.size()) if ((len + 1) < buf.size())
{ {
std::copy(m_start, m_end, buf.data()); std::copy(m_start, m_end, buf.begin());
buf[len] = 0; buf[len] = 0;
buf[ds_pos] = decimal_point_char; buf[ds_pos] = decimal_point_char;
data = buf.data(); data = buf.data();

View file

@ -38,7 +38,7 @@ SOFTWARE.
#include <cstddef> // nullptr_t, ptrdiff_t, size_t #include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // int64_t, uint64_t #include <cstdint> // int64_t, uint64_t
#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull #include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull
#include <cstring> // strcpy, strlen #include <cstring> // strlen
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <functional> // function, hash, less #include <functional> // function, hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
@ -8259,6 +8259,7 @@ class basic_json
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::true_type) void x_write(NumberType x, /*is_integral=*/std::true_type)
{ {
// special case for "0"
if (x == 0) if (x == 0)
{ {
m_buf[0] = '0'; m_buf[0] = '0';
@ -8291,9 +8292,17 @@ class basic_json
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::false_type) void x_write(NumberType x, /*is_integral=*/std::false_type)
{ {
// special case for 0.0 and -0.0
if (x == 0) if (x == 0)
{ {
std::strcpy(m_buf.data(), std::signbit(x) ? "-0.0" : "0.0"); size_t i = 0;
if (std::signbit(x))
{
m_buf[i++] = '-';
}
m_buf[i++] = '0';
m_buf[i++] = '.';
m_buf[i] = '0';
return; return;
} }
@ -8342,18 +8351,35 @@ class basic_json
} }
// determine if need to append ".0" // determine if need to append ".0"
const auto data_end = m_buf.begin() + strlen(m_buf.data()); size_t i = 0;
bool value_is_int_like = true;
const bool value_is_int_like = for (i = 0; i < m_buf.size(); ++i)
std::none_of(m_buf.begin(), data_end, [](const char c)
{ {
return (c == '.' or c == 'e' or c == 'E'); // break when end of number is reached
}); if (m_buf[i] == '\0')
assert(data_end + 2 < m_buf.end()); {
break;
}
// check if we find non-int character
value_is_int_like = value_is_int_like and m_buf[i] != '.' and
m_buf[i] != 'e' and m_buf[i] != 'E';
}
if (value_is_int_like) if (value_is_int_like)
{ {
strcat(m_buf.data(), ".0"); // there must be 2 bytes left for ".0"
assert((i + 2) < m_buf.size());
// we write to the end of the number
assert(m_buf[i] == '\0');
assert(m_buf[i - 1] != '\0');
// add ".0"
m_buf[i] = '.';
m_buf[i + 1] = '0';
// the resulting string is properly terminated
assert(m_buf[i + 2] == '\0');
} }
} }
}; };
@ -10170,7 +10196,7 @@ class basic_json
// update data to point to the modified bytes // update data to point to the modified bytes
if ((len + 1) < buf.size()) if ((len + 1) < buf.size())
{ {
std::copy(m_start, m_end, buf.data()); std::copy(m_start, m_end, buf.begin());
buf[len] = 0; buf[len] = 0;
buf[ds_pos] = decimal_point_char; buf[ds_pos] = decimal_point_char;
data = buf.data(); data = buf.data();