From b8a9d7fc19d610401532f3a993a25f710127ba1d Mon Sep 17 00:00:00 2001 From: Pavel Novikov Date: Thu, 30 Nov 2023 16:58:55 +0300 Subject: [PATCH 1/4] sped up parsing by ~0..10% --- include/tao/json/events/set_value.hpp | 36 ++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/include/tao/json/events/set_value.hpp b/include/tao/json/events/set_value.hpp index 17bb85a0..a04989f4 100644 --- a/include/tao/json/events/set_value.hpp +++ b/include/tao/json/events/set_value.hpp @@ -22,7 +22,14 @@ namespace tao::json::events template< template< typename... > class Traits > struct set_basic_value { + static constexpr size_t count_ = 4; + struct ArrayElements + { + basic_value< Traits > array[ count_ ]; + size_t count = 0; + }; std::vector< basic_value< Traits > > stack_; + std::vector< ArrayElements > elements_; std::vector< std::string > keys_; basic_value< Traits >& value_; @@ -96,29 +103,50 @@ namespace tao::json::events void begin_array() { - stack_.emplace_back( empty_array ); + stack_.push_back( empty_array ); + elements_.emplace_back(); } void begin_array( const std::size_t size ) { begin_array(); + elements_.back().count = count_ + 1; stack_.back().get_array().reserve( size ); } void element() { - stack_.back().emplace_back( std::move( value_ ) ); + auto& elements = elements_.back(); + if( elements.count < count_ ) { + elements.array[ elements.count ] = std::move( value_ ); + ++elements.count; + return; + } + auto& a = stack_.back().get_array(); + if( elements.count == count_ ) { + a.reserve( count_ + 1 ); + for( auto& i : elements.array ) + a.push_back( std::move( i ) ); + ++elements.count; + } + a.push_back( std::move( value_ ) ); } void end_array( const std::size_t /*unused*/ = 0 ) { - value_ = std::move( stack_.back() ); + auto& elements = elements_.back(); + auto& v = stack_.back(); + if( elements.count <= count_ ) + v.get_array().assign( std::make_move_iterator( elements.array ), + std::make_move_iterator( elements.array + elements.count ) ); + value_ = std::move( v ); stack_.pop_back(); + elements_.pop_back(); } void begin_object( const std::size_t /*unused*/ = 0 ) { - stack_.emplace_back( empty_object ); + stack_.push_back( empty_object ); } void key( const std::string_view v ) From 0fffbc3e5134f136d7c1f85299ecb256222124fb Mon Sep 17 00:00:00 2001 From: Pavel Novikov Date: Mon, 4 Aug 2025 14:15:06 +0300 Subject: [PATCH 2/4] sped up parsing by ~0..30% --- include/tao/json/events/set_value.hpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/include/tao/json/events/set_value.hpp b/include/tao/json/events/set_value.hpp index a04989f4..ab6c9796 100644 --- a/include/tao/json/events/set_value.hpp +++ b/include/tao/json/events/set_value.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -22,14 +23,27 @@ namespace tao::json::events template< template< typename... > class Traits > struct set_basic_value { - static constexpr size_t count_ = 4; - struct ArrayElements + static constexpr size_t count_ = 42; + struct InPlaceVector { - basic_value< Traits > array[ count_ ]; + union + { + basic_value< Traits > array[ count_ ]; + }; size_t count = 0; + InPlaceVector() {} + ~InPlaceVector() + { + std::destroy_n( array, std::min( count, count_ ) ); + } + void emplace_back( basic_value< Traits >&& v ) + { + ::new( array + count ) basic_value< Traits >{ std::move( v ) }; + ++count; + } }; std::vector< basic_value< Traits > > stack_; - std::vector< ArrayElements > elements_; + std::deque< InPlaceVector > elements_; std::vector< std::string > keys_; basic_value< Traits >& value_; @@ -118,8 +132,7 @@ namespace tao::json::events { auto& elements = elements_.back(); if( elements.count < count_ ) { - elements.array[ elements.count ] = std::move( value_ ); - ++elements.count; + elements.emplace_back( std::move( value_ ) ); return; } auto& a = stack_.back().get_array(); From 784a46783a7545ec84bed44ae762ebd57621d126 Mon Sep 17 00:00:00 2001 From: Pavel Novikov Date: Mon, 4 Aug 2025 15:41:20 +0300 Subject: [PATCH 3/4] sped up parsing by ~0..40% --- include/tao/json/events/set_value.hpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/include/tao/json/events/set_value.hpp b/include/tao/json/events/set_value.hpp index ab6c9796..24fe6cc7 100644 --- a/include/tao/json/events/set_value.hpp +++ b/include/tao/json/events/set_value.hpp @@ -34,13 +34,17 @@ namespace tao::json::events InPlaceVector() {} ~InPlaceVector() { - std::destroy_n( array, std::min( count, count_ ) ); + std::destroy_n( array, size() ); } void emplace_back( basic_value< Traits >&& v ) { ::new( array + count ) basic_value< Traits >{ std::move( v ) }; ++count; } + size_t size() const + { + return std::min( count, count_ ); + } }; std::vector< basic_value< Traits > > stack_; std::deque< InPlaceVector > elements_; @@ -138,8 +142,7 @@ namespace tao::json::events auto& a = stack_.back().get_array(); if( elements.count == count_ ) { a.reserve( count_ + 1 ); - for( auto& i : elements.array ) - a.push_back( std::move( i ) ); + a.resize( count_ ); ++elements.count; } a.push_back( std::move( value_ ) ); @@ -149,9 +152,19 @@ namespace tao::json::events { auto& elements = elements_.back(); auto& v = stack_.back(); - if( elements.count <= count_ ) - v.get_array().assign( std::make_move_iterator( elements.array ), - std::make_move_iterator( elements.array + elements.count ) ); + if( elements.count ) { + const auto size = elements.size(); + auto& a = v.get_array(); + if( a.empty() ) { + a.assign( std::make_move_iterator( elements.array ), + std::make_move_iterator( elements.array + size ) ); + } + else { + std::copy_n( std::make_move_iterator( elements.array ), + size, + a.begin() ); + } + } value_ = std::move( v ); stack_.pop_back(); elements_.pop_back(); From 2e81c9be6900e9b0f3e7112a72274a2e34c12e72 Mon Sep 17 00:00:00 2001 From: Pavel Novikov Date: Tue, 5 Aug 2025 12:34:01 +0300 Subject: [PATCH 4/4] ensured correct work when `begin_array(const std::size_t)` is also used --- include/tao/json/events/set_value.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/tao/json/events/set_value.hpp b/include/tao/json/events/set_value.hpp index 24fe6cc7..0986dcce 100644 --- a/include/tao/json/events/set_value.hpp +++ b/include/tao/json/events/set_value.hpp @@ -24,6 +24,7 @@ namespace tao::json::events struct set_basic_value { static constexpr size_t count_ = 42; + static constexpr size_t count_skip_bit_ = size_t{ 1 } << ( std::numeric_limits< size_t >::digits - 1 ); struct InPlaceVector { union @@ -43,7 +44,7 @@ namespace tao::json::events } size_t size() const { - return std::min( count, count_ ); + return count & ~count_skip_bit_; } }; std::vector< basic_value< Traits > > stack_; @@ -128,7 +129,7 @@ namespace tao::json::events void begin_array( const std::size_t size ) { begin_array(); - elements_.back().count = count_ + 1; + elements_.back().count |= count_skip_bit_; stack_.back().get_array().reserve( size ); } @@ -143,7 +144,7 @@ namespace tao::json::events if( elements.count == count_ ) { a.reserve( count_ + 1 ); a.resize( count_ ); - ++elements.count; + elements.count |= count_skip_bit_; } a.push_back( std::move( value_ ) ); } @@ -152,8 +153,7 @@ namespace tao::json::events { auto& elements = elements_.back(); auto& v = stack_.back(); - if( elements.count ) { - const auto size = elements.size(); + if( const size_t size = elements.size() ) { auto& a = v.get_array(); if( a.empty() ) { a.assign( std::make_move_iterator( elements.array ),