⏪ "⚡ 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:
parent
909b439b03
commit
9c4919ff34
2 changed files with 92 additions and 52 deletions
72
src/json.hpp
72
src/json.hpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue