" micro-optimizations for dump()"

This reverts commit 909b439b03.
For some strange reason, the test suite crashes when compiled
with GCC.
This commit is contained in:
Niels Lohmann 2017-02-27 16:19:07 +01:00
parent 909b439b03
commit 9c4919ff34
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
2 changed files with 92 additions and 52 deletions

View file

@ -8252,9 +8252,14 @@ class basic_json
{ {
public: public:
template<typename NumberType> template<typename NumberType>
numtostr(NumberType value, std::ostream& o) numtostr(NumberType value)
{ {
x_write(value, std::is_integral<NumberType>(), o); x_write(value, std::is_integral<NumberType>());
}
const char* c_str() const
{
return m_buf.data();
} }
private: private:
@ -8262,12 +8267,12 @@ class basic_json
std::array < char, 64 > m_buf{{}}; std::array < char, 64 > m_buf{{}};
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::true_type, std::ostream& o) void x_write(NumberType x, /*is_integral=*/std::true_type)
{ {
// special case for "0" // special case for "0"
if (x == 0) if (x == 0)
{ {
o.put('0'); m_buf[0] = '0';
return; return;
} }
@ -8293,31 +8298,30 @@ class basic_json
} }
std::reverse(m_buf.begin(), m_buf.begin() + i); std::reverse(m_buf.begin(), m_buf.begin() + i);
o.write(m_buf.data(), static_cast<std::streamsize>(i));
} }
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::false_type, std::ostream& o) void x_write(NumberType x, /*is_integral=*/std::false_type)
{ {
// special case for 0.0 and -0.0 // special case for 0.0 and -0.0
if (x == 0) if (x == 0)
{ {
size_t i = 0;
if (std::signbit(x)) if (std::signbit(x))
{ {
o.write("-0.0", 4); m_buf[i++] = '-';
}
else
{
o.write("0.0", 3);
} }
m_buf[i++] = '0';
m_buf[i++] = '.';
m_buf[i] = '0';
return; return;
} }
// get number of digits for a text -> float -> text round-trip // get number of digits for a text -> float -> text round-trip
static constexpr auto d = std::numeric_limits<NumberType>::digits10; static constexpr auto d = std::numeric_limits<NumberType>::digits10;
// the actual conversion; store how many bytes have been written // the actual conversion
auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x); const auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(written_bytes > 0); assert(written_bytes > 0);
@ -8338,7 +8342,6 @@ class basic_json
{ {
const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep); const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep);
std::fill(end, m_buf.end(), '\0'); std::fill(end, m_buf.end(), '\0');
written_bytes -= m_buf.end() - end;
} }
// convert decimal point to '.' // convert decimal point to '.'
@ -8354,19 +8357,36 @@ class basic_json
} }
} }
o.write(m_buf.data(), static_cast<std::streamsize>(written_bytes));
// determine if need to append ".0" // determine if need to append ".0"
const bool value_is_int_like = std::all_of(m_buf.begin(), size_t i = 0;
m_buf.begin() + written_bytes + 1, bool value_is_int_like = true;
[](char c) for (i = 0; i < m_buf.size(); ++i)
{ {
// we use %g above, so there cannot be an 'E' character // break when end of number is reached
return c != '.' and c != 'e'; if (m_buf[i] == '\0')
}); {
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)
{ {
o.write(".0", 2); // 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');
} }
} }
}; };
@ -8546,19 +8566,19 @@ class basic_json
case value_t::number_integer: case value_t::number_integer:
{ {
numtostr(m_value.number_integer, o); o << numtostr(m_value.number_integer).c_str();
return; return;
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
numtostr(m_value.number_unsigned, o); o << numtostr(m_value.number_unsigned).c_str();
return; return;
} }
case value_t::number_float: case value_t::number_float:
{ {
numtostr(m_value.number_float, o); o << numtostr(m_value.number_float).c_str();
return; return;
} }

View file

@ -8252,9 +8252,14 @@ class basic_json
{ {
public: public:
template<typename NumberType> template<typename NumberType>
numtostr(NumberType value, std::ostream& o) numtostr(NumberType value)
{ {
x_write(value, std::is_integral<NumberType>(), o); x_write(value, std::is_integral<NumberType>());
}
const char* c_str() const
{
return m_buf.data();
} }
private: private:
@ -8262,12 +8267,12 @@ class basic_json
std::array < char, 64 > m_buf{{}}; std::array < char, 64 > m_buf{{}};
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::true_type, std::ostream& o) void x_write(NumberType x, /*is_integral=*/std::true_type)
{ {
// special case for "0" // special case for "0"
if (x == 0) if (x == 0)
{ {
o.put('0'); m_buf[0] = '0';
return; return;
} }
@ -8293,31 +8298,30 @@ class basic_json
} }
std::reverse(m_buf.begin(), m_buf.begin() + i); std::reverse(m_buf.begin(), m_buf.begin() + i);
o.write(m_buf.data(), static_cast<std::streamsize>(i));
} }
template<typename NumberType> template<typename NumberType>
void x_write(NumberType x, /*is_integral=*/std::false_type, std::ostream& o) void x_write(NumberType x, /*is_integral=*/std::false_type)
{ {
// special case for 0.0 and -0.0 // special case for 0.0 and -0.0
if (x == 0) if (x == 0)
{ {
size_t i = 0;
if (std::signbit(x)) if (std::signbit(x))
{ {
o.write("-0.0", 4); m_buf[i++] = '-';
}
else
{
o.write("0.0", 3);
} }
m_buf[i++] = '0';
m_buf[i++] = '.';
m_buf[i] = '0';
return; return;
} }
// get number of digits for a text -> float -> text round-trip // get number of digits for a text -> float -> text round-trip
static constexpr auto d = std::numeric_limits<NumberType>::digits10; static constexpr auto d = std::numeric_limits<NumberType>::digits10;
// the actual conversion; store how many bytes have been written // the actual conversion
auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x); const auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(written_bytes > 0); assert(written_bytes > 0);
@ -8338,7 +8342,6 @@ class basic_json
{ {
const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep); const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep);
std::fill(end, m_buf.end(), '\0'); std::fill(end, m_buf.end(), '\0');
written_bytes -= m_buf.end() - end;
} }
// convert decimal point to '.' // convert decimal point to '.'
@ -8354,19 +8357,36 @@ class basic_json
} }
} }
o.write(m_buf.data(), static_cast<std::streamsize>(written_bytes));
// determine if need to append ".0" // determine if need to append ".0"
const bool value_is_int_like = std::all_of(m_buf.begin(), size_t i = 0;
m_buf.begin() + written_bytes + 1, bool value_is_int_like = true;
[](char c) for (i = 0; i < m_buf.size(); ++i)
{ {
// we use %g above, so there cannot be an 'E' character // break when end of number is reached
return c != '.' and c != 'e'; if (m_buf[i] == '\0')
}); {
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)
{ {
o.write(".0", 2); // 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');
} }
} }
}; };
@ -8546,19 +8566,19 @@ class basic_json
case value_t::number_integer: case value_t::number_integer:
{ {
numtostr(m_value.number_integer, o); o << numtostr(m_value.number_integer).c_str();
return; return;
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
numtostr(m_value.number_unsigned, o); o << numtostr(m_value.number_unsigned).c_str();
return; return;
} }
case value_t::number_float: case value_t::number_float:
{ {
numtostr(m_value.number_float, o); o << numtostr(m_value.number_float).c_str();
return; return;
} }