diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index f8529b623..58d3ae41a 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -3747,8 +3747,8 @@ class binary_writer static bool bjdata_ndarray_value_in_range(const BasicJsonType& el) { return el.is_number_unsigned() - ? integer_fits_max(el.m_data.m_value.number_unsigned) && value_in_range_of(el.template get()) - : integer_fits(el.m_data.m_value.number_integer) && value_in_range_of(el.template get()); + ? integer_fits_max(el.m_data.m_value.number_unsigned) && value_in_range_of(static_cast(el.m_data.m_value.number_unsigned)) + : integer_fits(el.m_data.m_value.number_integer) && value_in_range_of(static_cast(el.m_data.m_value.number_integer)); } /*! @@ -3837,7 +3837,7 @@ class binary_writer */ bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run) { - const auto dval = el.template get(); + const auto dval = static_cast(el.m_data.m_value.number_float); if (dry_run) { #ifdef __GNUC__ @@ -3861,6 +3861,90 @@ class binary_writer return true; } + /*! + @brief write the elements of an ND-array as the number kind @a dtype names + (see @ref write_bjdata_ndarray), after they have been found to be + in range by a dry run of @ref write_bjdata_ndarray_elements + + The elements are encoded in blocks into space reserved from the sink. + */ + void write_bjdata_ndarray_values(const BasicJsonType& array_data, const CharType dtype) + { + switch (dtype) + { + case 'U': + case 'C': + case 'B': + write_bjdata_ndarray_block(array_data); + break; + case 'i': + write_bjdata_ndarray_block(array_data); + break; + case 'u': + write_bjdata_ndarray_block(array_data); + break; + case 'I': + write_bjdata_ndarray_block(array_data); + break; + case 'm': + write_bjdata_ndarray_block(array_data); + break; + case 'l': + write_bjdata_ndarray_block(array_data); + break; + case 'M': + write_bjdata_ndarray_block(array_data); + break; + case 'L': + write_bjdata_ndarray_block(array_data); + break; + case 'd': + write_bjdata_ndarray_block(array_data); + break; + case 'D': + default: + // 'D' (double) already spans the full range of number_float_t + write_bjdata_ndarray_block(array_data); + break; + } + } + + /// the value of an ND-array element that is an integer, as the integer type that @a T is converted from + template + static T bjdata_ndarray_integer(const BasicJsonType& el, std::true_type /*is_integral*/) noexcept + { + using storage_type = typename std::conditional::value, std::uint64_t, std::int64_t>::type; + return static_cast(el.is_number_unsigned() + ? static_cast(el.m_data.m_value.number_unsigned) + : static_cast(el.m_data.m_value.number_integer)); + } + + /// the value of an ND-array element that is a float + template + static T bjdata_ndarray_integer(const BasicJsonType& el, std::false_type /*is_integral*/) noexcept + { + return static_cast(static_cast(el.m_data.m_value.number_float)); + } + + /// write the elements of an ND-array as @a T, little-endian, in blocks + template + void write_bjdata_ndarray_block(const BasicJsonType& array_data) + { + constexpr std::size_t per_block = max_reserve_size / sizeof(T); + auto it = array_data.m_data.m_value.array->begin(); + const auto end = array_data.m_data.m_value.array->end(); + while (it != end) + { + CharType* const start = oa.reserve(per_block * sizeof(T)); + CharType* out = start; + for (std::size_t n = 0; n < per_block && it != end; ++n, ++it) + { + out = store_number(out, bjdata_ndarray_integer(*it, std::is_integral()), true); + } + oa.commit(static_cast(out - start)); + } + } + /*! @brief validate or write every element of a BJData ND-array's `_ArrayData_` @param[in] array_data the `_ArrayData_` array @@ -3870,6 +3954,12 @@ class binary_writer */ bool write_bjdata_ndarray_elements(const BasicJsonType& array_data, const CharType dtype, const bool dry_run) { + if (!dry_run) + { + write_bjdata_ndarray_values(array_data, dtype); + return true; + } + for (const auto& el : array_data) { bool ok = true; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2290bedd8..5b9bee5e0 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -28578,8 +28578,8 @@ class binary_writer static bool bjdata_ndarray_value_in_range(const BasicJsonType& el) { return el.is_number_unsigned() - ? integer_fits_max(el.m_data.m_value.number_unsigned) && value_in_range_of(el.template get()) - : integer_fits(el.m_data.m_value.number_integer) && value_in_range_of(el.template get()); + ? integer_fits_max(el.m_data.m_value.number_unsigned) && value_in_range_of(static_cast(el.m_data.m_value.number_unsigned)) + : integer_fits(el.m_data.m_value.number_integer) && value_in_range_of(static_cast(el.m_data.m_value.number_integer)); } /*! @@ -28668,7 +28668,7 @@ class binary_writer */ bool write_bjdata_ndarray_float_element(const BasicJsonType& el, const bool dry_run) { - const auto dval = el.template get(); + const auto dval = static_cast(el.m_data.m_value.number_float); if (dry_run) { #ifdef __GNUC__ @@ -28692,6 +28692,90 @@ class binary_writer return true; } + /*! + @brief write the elements of an ND-array as the number kind @a dtype names + (see @ref write_bjdata_ndarray), after they have been found to be + in range by a dry run of @ref write_bjdata_ndarray_elements + + The elements are encoded in blocks into space reserved from the sink. + */ + void write_bjdata_ndarray_values(const BasicJsonType& array_data, const CharType dtype) + { + switch (dtype) + { + case 'U': + case 'C': + case 'B': + write_bjdata_ndarray_block(array_data); + break; + case 'i': + write_bjdata_ndarray_block(array_data); + break; + case 'u': + write_bjdata_ndarray_block(array_data); + break; + case 'I': + write_bjdata_ndarray_block(array_data); + break; + case 'm': + write_bjdata_ndarray_block(array_data); + break; + case 'l': + write_bjdata_ndarray_block(array_data); + break; + case 'M': + write_bjdata_ndarray_block(array_data); + break; + case 'L': + write_bjdata_ndarray_block(array_data); + break; + case 'd': + write_bjdata_ndarray_block(array_data); + break; + case 'D': + default: + // 'D' (double) already spans the full range of number_float_t + write_bjdata_ndarray_block(array_data); + break; + } + } + + /// the value of an ND-array element that is an integer, as the integer type that @a T is converted from + template + static T bjdata_ndarray_integer(const BasicJsonType& el, std::true_type /*is_integral*/) noexcept + { + using storage_type = typename std::conditional::value, std::uint64_t, std::int64_t>::type; + return static_cast(el.is_number_unsigned() + ? static_cast(el.m_data.m_value.number_unsigned) + : static_cast(el.m_data.m_value.number_integer)); + } + + /// the value of an ND-array element that is a float + template + static T bjdata_ndarray_integer(const BasicJsonType& el, std::false_type /*is_integral*/) noexcept + { + return static_cast(static_cast(el.m_data.m_value.number_float)); + } + + /// write the elements of an ND-array as @a T, little-endian, in blocks + template + void write_bjdata_ndarray_block(const BasicJsonType& array_data) + { + constexpr std::size_t per_block = max_reserve_size / sizeof(T); + auto it = array_data.m_data.m_value.array->begin(); + const auto end = array_data.m_data.m_value.array->end(); + while (it != end) + { + CharType* const start = oa.reserve(per_block * sizeof(T)); + CharType* out = start; + for (std::size_t n = 0; n < per_block && it != end; ++n, ++it) + { + out = store_number(out, bjdata_ndarray_integer(*it, std::is_integral()), true); + } + oa.commit(static_cast(out - start)); + } + } + /*! @brief validate or write every element of a BJData ND-array's `_ArrayData_` @param[in] array_data the `_ArrayData_` array @@ -28701,6 +28785,12 @@ class binary_writer */ bool write_bjdata_ndarray_elements(const BasicJsonType& array_data, const CharType dtype, const bool dry_run) { + if (!dry_run) + { + write_bjdata_ndarray_values(array_data, dtype); + return true; + } + for (const auto& el : array_data) { bool ok = true;