diff --git a/include/tao/json/events/set_value.hpp b/include/tao/json/events/set_value.hpp index 17bb85a0..0986dcce 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,7 +23,32 @@ namespace tao::json::events template< template< typename... > class Traits > 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 + { + basic_value< Traits > array[ count_ ]; + }; + size_t count = 0; + InPlaceVector() {} + ~InPlaceVector() + { + 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 count & ~count_skip_bit_; + } + }; std::vector< basic_value< Traits > > stack_; + std::deque< InPlaceVector > elements_; std::vector< std::string > keys_; basic_value< Traits >& value_; @@ -96,29 +122,57 @@ 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_skip_bit_; stack_.back().get_array().reserve( size ); } void element() { - stack_.back().emplace_back( std::move( value_ ) ); + auto& elements = elements_.back(); + if( elements.count < count_ ) { + elements.emplace_back( std::move( value_ ) ); + return; + } + auto& a = stack_.back().get_array(); + if( elements.count == count_ ) { + a.reserve( count_ + 1 ); + a.resize( count_ ); + elements.count |= count_skip_bit_; + } + 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( const size_t 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(); } 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 )