Skip to content

Commit

Permalink
Merge pull request #440 from beached/v3
Browse files Browse the repository at this point in the history
Bugfix #439 in serialization of numbers with fractional leading zeros
  • Loading branch information
beached authored Aug 10, 2024
2 parents 5d18bbc + 8e5b308 commit 1cb3753
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
cmake_minimum_required( VERSION 3.14 )

project( "daw-json-link"
VERSION "3.27.0"
VERSION "3.27.1"
DESCRIPTION "Static JSON parsing in C++"
HOMEPAGE_URL "https://github.com/beached/daw_json_link"
LANGUAGES C CXX )
Expand Down
40 changes: 40 additions & 0 deletions include/daw/json/impl/to_daw_json_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,34 @@ namespace daw::json {
}
}

constexpr int count_digits( std::uint64_t value ) {
constexpr std::uint64_t powers[19] = { 10ull,
100ull,
1000ull,
10000ull,
100000ull,
1000000ull,
10000000ull,
100000000ull,
1000000000ull,
10000000000ull,
100000000000ull,
1000000000000ull,
10000000000000ull,
100000000000000ull,
1000000000000000ull,
10000000000000000ull,
100000000000000000ull,
1000000000000000000ull,
10000000000000000000ull };

auto b =
-( value > 0 ) & ( 63 - daw::cxmath::count_leading_zeroes( value ) );
auto a = ( b * 77 ) / 256;
return static_cast<int>( 1 + a + ( value >= powers[a] ) );
}
static_assert( count_digits( 1'000'000ULL ) == 7 );

template<options::FPOutputFormat fp_output_fmt, typename WriteableType,
typename Real>
static constexpr WriteableType to_chars( Real const &value,
Expand Down Expand Up @@ -1534,10 +1562,22 @@ namespace daw::json {
}
out_it.put( '.' );
auto const p2val = dec.significand - ( p1val * p1pow );
// ensure we account for leading zeros
// auto const sig_sigits =
{
auto const l10_sig = count_digits( dec.significand );
auto const l10_p1val = count_digits( p1val );
auto const l10_p2val = count_digits( p2val );
auto const extra_zeros = l10_sig - ( l10_p2val + l10_p1val );
for( int n = 0; n < extra_zeros; ++n ) {
out_it.put( '0' );
}
}
out_it = utils::integer_to_string( out_it, p2val );
return out_it;
}
out_it = utils::integer_to_string( out_it, dec.significand );

while( dec.exponent > 0 ) {
out_it.put( '0' );
--dec.exponent;
Expand Down
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,12 @@ if( magic_enum_FOUND )
add_dependencies( full issue_433_test )
endif()

add_executable( issue_439_test src/issue_439_test.cpp )
target_link_libraries( issue_439_test PRIVATE json_test )
add_test( NAME issue_439_test COMMAND issue_439_test WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test_data/" )
add_dependencies( ci_tests issue_439_test )
add_dependencies( full issue_439_test )

add_executable( multi_tu_test src/multi_tu_p0_test.cpp src/multi_tu_p1_test.cpp )
target_link_libraries( multi_tu_test json_test )
add_test( NAME multi_tu_test_test COMMAND multi_tu_test )
Expand Down
102 changes: 102 additions & 0 deletions tests/src/issue_439_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Darrell Wright
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/beached/
//

#include <daw/json/daw_json_link.h>

#include <daw/daw_ensure.h>

#include <string>
#include <vector>

struct TestClass {
int i;
double d;
bool b;
std::string s{ };
std::vector<int> y{ };

bool operator==( TestClass const &rhs ) const {
return std::tie( i, d, b, s, y ) ==
std::tie( rhs.i, rhs.d, rhs.b, rhs.s, rhs.y );
}
};

namespace daw::json {
template<>
struct json_data_contract<TestClass> {
static constexpr char const mem_i[] = "i";
static constexpr char const mem_d[] = "d";
static constexpr char const mem_b[] = "b";
static constexpr char const mem_s[] = "s";
static constexpr char const mem_y[] = "y";
using type = json_member_list<json_number<mem_i, int>, json_number<mem_d>,
json_bool<mem_b>, json_string<mem_s>,
json_array<mem_y, int>>;

static inline auto to_json_data( TestClass const &value ) {
return std::forward_as_tuple( value.i, value.d, value.b, value.s,
value.y );
}
};
} // namespace daw::json

int main( ) {
static constexpr std::string_view json_doc1 = R"([
{
"i":5,
"d":0.002,
"b":false,
"s":"hello world",
"y":[1,2,3,4]
},
{
"i":4,
"d":1.000005,
"b":true,
"s":"goodbye world",
"y":[4,3,1,4]
}])";

static constexpr std::string_view json_doc2 = R"json(
{
"i":4,
"d":1.000005,
"b":true,
"s":"goodbye world",
"y":[4,3,1,4]
}
)json";

auto const flttest0 = daw::json::to_json( 1.000005f );
daw_ensure( flttest0 == "1.000005" );

auto const flttest1 = daw::json::to_json( 1.05f );
daw_ensure( flttest1 == "1.05" );

auto const flttest2 = daw::json::to_json( 1.55f );
daw_ensure( flttest2 == "1.55" );

auto const flttest3 = daw::json::to_json( 21.05f );
daw_ensure( flttest3 == "21.05" );
auto obj = daw::json::from_json<TestClass>( json_doc2 );
daw_ensure( obj.d == 1.000005 );
auto obj_json = daw::json::to_json( obj );
daw_ensure( obj_json[0] == '{' );

auto arry_of_test_class = daw::json::from_json_array<TestClass>( json_doc1 );

daw_ensure( arry_of_test_class[1].d == 1.000005 );
auto json_array = daw::json::to_json( arry_of_test_class );

auto arry_of_test_class2 =
daw::json::from_json_array<TestClass>( json_array );

daw_ensure( arry_of_test_class2[1].d == 1.000005 );

daw_ensure( arry_of_test_class == arry_of_test_class2 );
}

0 comments on commit 1cb3753

Please sign in to comment.