Skip to content
Merged
2 changes: 1 addition & 1 deletion .github/workflows/ci_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
matrix:
cpp_version: [ 17, 20 ]
build_type: [ Debug, Release ]
os: [ macos-latest ]
os: [ macos-latest, macos-14 ]
toolset: [ clang++ ]
runs-on: ${{ matrix.os }}
name: "${{ matrix.os }} ${{ matrix.toolset }} ${{ matrix.cpp_version }} ${{ matrix.build_type }}"
Expand Down
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.30.1"
VERSION "3.30.2"
DESCRIPTION "Static JSON parsing in C++"
HOMEPAGE_URL "https://github.com/beached/daw_json_link"
LANGUAGES C CXX )
Expand Down
34 changes: 18 additions & 16 deletions include/daw/json/daw_json_event_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,10 @@ namespace daw::json {
std::pair<iterator, iterator> value;
};

template<typename StackValue>
template<typename StackValue, typename StackType = std::vector<StackValue>>
class DefaultJsonEventParserStackPolicy {
std::vector<StackValue> m_stack{ };
using stack_t = StackType;
stack_t m_stack{ };

public:
using value_type = StackValue;
Expand Down Expand Up @@ -313,9 +314,8 @@ namespace daw::json {
}
};

template<json_options_t P, typename A,
typename StackContainerPolicy = use_default, typename Handler,
auto... ParseFlags>
template<typename StackContainerPolicy = use_default, json_options_t P,
typename A, typename Handler, auto... ParseFlags>
constexpr void json_event_parser( basic_json_value<P, A> bjv,
Handler &&handler,
options::parse_flags_t<ParseFlags...> ) {
Expand Down Expand Up @@ -521,30 +521,32 @@ namespace daw::json {
ErrorReason::InvalidEndOfValue );
}

template<json_options_t P, typename A,
typename StackContainerPolicy = use_default, typename Handler>
template<typename StackContainerPolicy = use_default, json_options_t P,
typename A, typename Handler>
DAW_ATTRIB_INLINE constexpr void
json_event_parser( basic_json_value<P, A> bjv, Handler &&handler ) {
json_event_parser( std::move( bjv ), DAW_FWD( handler ),
options::parse_flags<> );
json_event_parser<StackContainerPolicy>(
std::move( bjv ), DAW_FWD( handler ), options::parse_flags<> );
}

template<typename Handler, auto... ParseFlags>
template<typename StackContainerPolicy = use_default, typename Handler,
auto... ParseFlags>
DAW_ATTRIB_INLINE void
json_event_parser( daw::string_view json_document, Handler &&handler,
options::parse_flags_t<ParseFlags...> pflags ) {

return json_event_parser( basic_json_value( json_document ),
DAW_FWD2( Handler, handler ), pflags );
return json_event_parser<StackContainerPolicy>(
basic_json_value( json_document ), DAW_FWD2( Handler, handler ),
pflags );
}

template<typename Handler>
template<typename StackContainerPolicy = use_default, typename Handler>
DAW_ATTRIB_INLINE void json_event_parser( daw::string_view json_document,
Handler &&handler ) {

return json_event_parser( basic_json_value( json_document ),
DAW_FWD2( Handler, handler ),
options::parse_flags<> );
return json_event_parser<StackContainerPolicy>(
basic_json_value( json_document ), DAW_FWD2( Handler, handler ),
options::parse_flags<> );
}

} // namespace DAW_JSON_VER
Expand Down
31 changes: 12 additions & 19 deletions include/daw/json/impl/daw_json_parse_iso8601_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ namespace daw::json {
namespace datetime {
namespace datetime_details {

template<typename Result, string_view_bounds_type Bounds>
constexpr Result
parse_number( daw::basic_string_view<char, Bounds> sv ) {
template<typename Result>
constexpr Result parse_number( daw::string_view sv ) {
static_assert( daw::numeric_limits<Result>::digits10 >= 4 );
daw_json_ensure( not sv.empty( ), ErrorReason::InvalidNumber );
Result result = 0;
Expand Down Expand Up @@ -172,9 +171,8 @@ namespace daw::json {
std::uint32_t day;
};

template<string_view_bounds_type Bounds>
constexpr date_parts parse_iso_8601_date(
daw::basic_string_view<char, Bounds> timestamp_str ) {
constexpr date_parts
parse_iso_8601_date( daw::string_view timestamp_str ) {
auto result = date_parts{ 0, 0, 0 };
result.day = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
std::data( timestamp_str.pop_back( 2U ) ) );
Expand Down Expand Up @@ -202,21 +200,18 @@ namespace daw::json {
std::uint64_t nanosecond;
};

template<string_view_bounds_type Bounds>
constexpr time_parts parse_iso_8601_time(
daw::basic_string_view<char, Bounds> timestamp_str ) {
constexpr time_parts
parse_iso_8601_time( daw::string_view timestamp_str ) {
auto result = time_parts{ 0, 0, 0, 0 };
result.hour = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
std::data( timestamp_str.pop_front( 2 ) ) );
daw_json_ensure( result.hour >= 0 and result.hour <= 24,
ErrorReason::InvalidTimestamp );
daw_json_ensure( result.hour <= 24, ErrorReason::InvalidTimestamp );
if( not parse_utils::is_number( timestamp_str.front( ) ) ) {
timestamp_str.remove_prefix( );
}
result.minute = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
std::data( timestamp_str.pop_front( 2 ) ) );
daw_json_ensure( result.minute >= 0 and result.minute <= 59,
ErrorReason::InvalidTimestamp );
daw_json_ensure( result.minute <= 59, ErrorReason::InvalidTimestamp );
if( timestamp_str.empty( ) ) {
return result;
}
Expand All @@ -225,8 +220,7 @@ namespace daw::json {
}
result.second = parse_utils::parse_unsigned<std::uint_least32_t, 2>(
std::data( timestamp_str.pop_front( 2 ) ) );
daw_json_ensure( result.second >= 0 and result.second <= 60,
ErrorReason::InvalidTimestamp );
daw_json_ensure( result.second <= 60, ErrorReason::InvalidTimestamp );
if( timestamp_str.empty( ) ) {
return result;
}
Expand All @@ -241,9 +235,8 @@ namespace daw::json {
return result;
}

template<typename TP, string_view_bounds_type Bounds>
constexpr TP
parse_iso8601_timestamp( daw::basic_string_view<char, Bounds> ts ) {
template<typename TP>
constexpr TP parse_iso8601_timestamp( daw::string_view ts ) {
constexpr daw::string_view t_str = "T";
auto const date_str = ts.pop_front_until( t_str );
if( ts.empty( ) ) {
Expand Down Expand Up @@ -468,4 +461,4 @@ namespace daw::json {
}
} // namespace datetime
} // namespace DAW_JSON_VER
} // namespace daw::json
} // namespace daw::json
12 changes: 6 additions & 6 deletions include/daw/json/impl/to_daw_json_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ namespace daw::json {
// Need to use ADL to_string in unevaluated contexts. Limiting to it's
// own namespace
template<typename T>
[[nodiscard]] static constexpr auto
to_string( std::optional<T> const &v ) -> decltype( to_string( *v ) ) {
[[nodiscard]] static constexpr auto to_string( std::optional<T> const &v )
-> decltype( to_string( *v ) ) {
if( not has_value( v ) ) {
return { "null" };
}
Expand Down Expand Up @@ -224,7 +224,7 @@ namespace daw::json {
to_nibble_char( ( c >> 12U ) & 0xFU ),
to_nibble_char( ( c >> 8U ) & 0xFU ),
to_nibble_char( ( c >> 4U ) & 0xFU ),
to_nibble_char( c & 0xFU ) };
to_nibble_char( c & 0xFU ), '\0' };

it.write( nibbles );
return it;
Expand All @@ -240,15 +240,15 @@ namespace daw::json {
if( cp <= 0x7FFU ) {
char const tmp[] = {
static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ), '\0' };
it.write( tmp );
return;
}
if( cp <= 0xFFFFU ) {
char const tmp[]{
static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ), '\0' };
it.write( tmp );
return;
}
Expand All @@ -257,7 +257,7 @@ namespace daw::json {
static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ), '\0' };
it.write( tmp );
return;
}
Expand Down
4 changes: 2 additions & 2 deletions include/daw/json/impl/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
#if not defined( DAW_JSON_VER_OVERRIDE )
// Should be updated when a potential ABI break is anticipated
#if defined( DEBUG ) or not defined( NDEBUG )
#define DAW_JSON_VER v3_29_0d
#define DAW_JSON_VER v3_30_2d
#else
#define DAW_JSON_VER v3_29_0
#define DAW_JSON_VER v3_30_2
#endif
#else
#define DAW_JSON_VER DAW_JSON_VER_OVERRIDE
Expand Down
15 changes: 13 additions & 2 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# TODO clean this up, but for now it makes tests get appropriate options

cmake_policy( SET CMP0065 NEW )
cmake_policy( SET CMP0156 NEW )
cmake_policy( SET CMP0179 NEW )
cmake_policy( SET CMP0167 NEW )

set( CMAKE_CXX_STANDARD_REQUIRED ON )
if( CYGWIN )
Expand Down Expand Up @@ -600,9 +603,10 @@ add_test( NAME cookbook_numbers2_test COMMAND cookbook_numbers2_test ./cookbook_
add_dependencies( ci_tests cookbook_numbers2_test )
add_dependencies( full cookbook_numbers2_test )


if( Boost_FOUND AND DAW_USE_EXCEPTIONS )
add_executable( cookbook_numbers3_test src/cookbook_numbers3_test.cpp )
target_link_libraries( cookbook_numbers3_test PRIVATE test Boost::headers )
target_link_libraries( cookbook_numbers3_test PRIVATE json_test Boost::headers )
add_test( NAME cookbook_numbers3_test COMMAND cookbook_numbers3_test ./cookbook_numbers3.json WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test_data/" )
add_dependencies( ci_tests cookbook_numbers3_test )
add_dependencies( full cookbook_numbers3_test )
Expand Down Expand Up @@ -821,6 +825,13 @@ if( DAW_USE_EXCEPTIONS )
add_dependencies( ci_tests issue_413_test )
add_dependencies( full issue_413_test )

add_executable( issue_462_test src/issue_462_test.cpp )
target_link_libraries( issue_462_test PRIVATE json_test )
add_test( NAME issue_462_test COMMAND issue_462_test )
add_dependencies( ci_tests issue_462_test )
add_dependencies( full issue_462_test )


endif()

add_executable( test_details_skip_number src/test_details_skip_number.cpp )
Expand Down Expand Up @@ -1156,7 +1167,7 @@ if( GIT_FOUND )
target_compile_definitions( json_benchmark PRIVATE -DSOURCE_CONTROL_REVISION="${BUILD_VERSION}" )
target_link_libraries( json_benchmark PRIVATE json_test )
if( DEFINED MSVC AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" )
add_compile_options( "/bigobj" )
target_compile_options( json_benchmark PRIVATE /bigobj )
endif()

cmake_host_system_information( RESULT _proc_desc QUERY PROCESSOR_DESCRIPTION )
Expand Down
10 changes: 3 additions & 7 deletions tests/src/daw_json_link_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ int main( int, char ** ) {
daw::json::from_json<OptionalOrdered>( optional_ordered1_data );
daw::expecting( not v.b );
}
#if( defined( __GNUC__ ) and __GNUC__ <= 9 ) or ( defined( _MSC_VER ) )
#if ( defined( __GNUC__ ) and __GNUC__ <= 9 ) or ( defined( _MSC_VER ) )
#define CX
#elif defined( DAW_JSON_NO_CONST_EXPR )
#define CX
Expand Down Expand Up @@ -1158,7 +1158,7 @@ int main( int, char ** ) {
test_vector_of_bool( );
static_assert( from_json<bool>( "true" ) );
static_assert( not from_json<bool>( "false" ) );
static_assert( not *from_json<std::optional<bool>>( "false" ) );
static_assert( not*from_json<std::optional<bool>>( "false" ) );
static_assert( not from_json<std::optional<bool>>( "null" ) );
static_assert( from_json<signed char>( "-1" ) ==
static_cast<signed char>( -1 ) );
Expand Down Expand Up @@ -1490,12 +1490,8 @@ int main( int, char ** ) {
{
static constexpr auto most_min = LLONG_MIN;
auto most_min_json = to_json( most_min );
#define xstr( a ) str( a )
#define str( a ) #a
daw::string_view min_str = "" xstr( LLONG_MIN );
auto const min_str = std::to_string( most_min );
ensure( most_min_json == min_str );
#undef xstr
#undef str
auto const most_min_parsed = from_json<long long>( most_min_json );
ensure( most_min == most_min_parsed );
}
Expand Down
41 changes: 41 additions & 0 deletions tests/src/issue_462_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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/daw_json_link
//

#include <daw/json/daw_json_link.h>

#include <map>
#include <string>
#include <string_view>

struct request {
std::unordered_map<std::string, std::string> header;
};

namespace daw::json {
template<>
struct json_data_contract<request> {
#if defined( DAW_JSON_CNTTP_JSON_NAME )
using type = json_member_list<json_key_value<
"header", std::unordered_map<std::string, std::string>, std::string>>;
#else
static constexpr char const header[] = "header";
using type = json_member_list<json_key_value<
header, std::unordered_map<std::string, std::string>, std::string>>;
#endif
static inline auto to_json_data( request const &v ) {
return std::forward_as_tuple( v.header );
}
};
} // namespace daw::json

int main( ) {
constexpr std::string_view json_doc =
R"json({ "header": { "field1": "a", "field2": "b" } })json";

auto req = daw::json::from_json<request>( json_doc );
}