diff --git a/bench/bench.cpp b/bench/bench.cpp index aaf53ee7..45e5d637 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -125,6 +125,166 @@ public: //---------------------------------------------------------- +class boost_vec_impl : public any_impl +{ + struct vec_parser : basic_parser + { + std::size_t n_ = std::size_t(-1); + char buf[256]; + std::vector vec_; + double d_ = 0; + + vec_parser() + { + } + + ~vec_parser() + { + } + + void + on_stack_info( + stack& s) noexcept override + { + s.base = buf; + s.capacity = sizeof(buf); + } + + void + on_stack_grow( + stack&, + unsigned, + error_code& ec) override + { + ec = error::too_deep; + } + + void + on_document_begin( + error_code&) override + { + } + + void + on_object_begin( + error_code&) override + { + } + + void + on_object_end( + error_code&) override + { + } + + void + on_array_begin( + error_code&) override + { + } + + void + on_array_end( + error_code&) override + { + } + + void + on_key_data( + string_view, + error_code&) override + { + } + + void + on_key_end( + string_view, + error_code&) override + { + } + + void + on_string_data( + string_view, + error_code&) override + { + } + + void + on_string_end( + string_view, + error_code&) override + { + } + + void + on_int64( + int64_t, + error_code&) override + { + } + + void + on_uint64( + uint64_t, + error_code&) override + { + } + + void + on_double( + double d, + error_code&) override + { + vec_.push_back(d); + } + + void + on_bool( + bool, + error_code&) override + { + } + + void + on_null(error_code&) override + { + } + }; + +public: + string_view + name() const noexcept override + { + return "boost(vec)"; + } + + void + parse( + string_view s, + int repeat) const override + { + while(repeat--) + { + error_code ec; + vec_parser p; + p.write(s.data(), s.size(), ec); + } + } + + void + serialize( + string_view s, + int repeat) const override + { + auto jv = json::parse(s); + while(repeat--) + to_string(jv); + } +}; + +//---------------------------------------------------------- + struct rapidjson_impl : public any_impl { string_view @@ -222,14 +382,14 @@ benchParse( std::endl; for(unsigned j = 0; j < vi.size(); ++j) { - for(unsigned k = 0; k < 15; ++k) + for(unsigned k = 0; k < 10; ++k) { auto const when = clock_type::now(); vi[j]->parse(vs[i].text, 250); auto const ms = std::chrono::duration_cast< std::chrono::milliseconds>( clock_type::now() - when).count(); - if(k > 9) + if(k > 4) dout << " " << vi[j]->name() << ": " << std::to_string(ms) << "ms" << std::endl; @@ -296,6 +456,7 @@ main( vi.reserve(10); //vi.emplace_back(new boost_default_impl); vi.emplace_back(new boost_impl); + //vi.emplace_back(new boost_vec_impl); vi.emplace_back(new rapidjson_impl); //vi.emplace_back(new nlohmann_impl); diff --git a/include/boost/json/detail/config.hpp b/include/boost/json/detail/config.hpp index 9b525892..e447ce5f 100644 --- a/include/boost/json/detail/config.hpp +++ b/include/boost/json/detail/config.hpp @@ -62,8 +62,6 @@ // optimizations -#define BOOST_JSON_VALUE_IS_TRIVIAL - #ifndef BOOST_JSON_NO_SSE2 # if (defined(_M_IX86) && _M_IX86_FP == 2) || \ defined(_M_X64) || defined(__SSE2__) diff --git a/include/boost/json/detail/number.hpp b/include/boost/json/detail/number.hpp index 2dec4ee8..aaafc4db 100644 --- a/include/boost/json/detail/number.hpp +++ b/include/boost/json/detail/number.hpp @@ -37,7 +37,7 @@ class number_parser { init, init0, init1, mant, mantn, mantd, - frac1, frac2, frac3, fracd, + frac1, frac2, fracd, exp1, exp2, exp3, done }; diff --git a/include/boost/json/detail/number.ipp b/include/boost/json/detail/number.ipp index 854bcdbf..ec8b4941 100644 --- a/include/boost/json/detail/number.ipp +++ b/include/boost/json/detail/number.ipp @@ -393,7 +393,7 @@ loop: { ++p; n_.d = static_cast(m); - st_ = state::frac3; + st_ = state::fracd; goto loop; } ++p; @@ -420,7 +420,7 @@ loop: } // zero or more [0..9] (double) - case state::frac3: + case state::fracd: { BOOST_JSON_ASSERT( n_.kind == kind::double_); @@ -505,7 +505,7 @@ loop: { if(p < p1) { - auto const lim = 308 - off_; + //auto const lim = 308 - off_; auto e = exp_; while(p < p1) { @@ -620,7 +620,7 @@ write_eof( st_ = state::done; break; - case state::frac3: + case state::fracd: BOOST_JSON_ASSERT( n_.kind == kind::double_); ec = {}; diff --git a/include/boost/json/impl/array.ipp b/include/boost/json/impl/array.ipp index 23ffb4e3..a4992021 100644 --- a/include/boost/json/impl/array.ipp +++ b/include/boost/json/impl/array.ipp @@ -635,7 +635,6 @@ relocate( value* src, size_type n) noexcept { -#ifdef BOOST_JSON_VALUE_IS_TRIVIAL if(n == 0) return; std::memmove( @@ -644,25 +643,6 @@ relocate( reinterpret_cast< void const*>(src), n * sizeof(value)); -#else - if( dest >= src && - dest < src + n) - { - // backwards - dest += n; - auto it = src + n; - while(it != src) - boost::relocate( - --dest, *--it); - } - else - { - auto last = src + n; - while(src != last) - boost::relocate( - dest++, *src++); - } -#endif } } // json diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index 07d3ba4b..d8e75739 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -861,6 +861,7 @@ loop_num: auto const num = iep_.get(); switch(num.kind) { + default: case kind::int64: this->on_int64(num.i, ec); break; @@ -1107,6 +1108,7 @@ write_eof(error_code& ec) auto const num = iep_.get(); switch(num.kind) { + default: case kind::int64: this->on_int64(num.i, ec); break; diff --git a/include/boost/json/impl/parser.ipp b/include/boost/json/impl/parser.ipp index 1e196846..2f771657 100644 --- a/include/boost/json/impl/parser.ipp +++ b/include/boost/json/impl/parser.ipp @@ -130,9 +130,9 @@ on_object_begin(error_code& ec) } else if(jv.is_array()) { - jv.if_array()->emplace_back(object{}); + jv.get_array().emplace_back(object_kind); stack_.push( - &jv.if_array()->back()); + &jv.get_array().back()); } else { @@ -177,9 +177,9 @@ on_array_begin(error_code& ec) else if(jv.is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(array{}); + jv.get_array().emplace_back(array_kind); stack_.push( - &jv.if_array()->back()); + &jv.get_array().back()); } else { @@ -227,7 +227,7 @@ on_key_end( s = {s_.data(), s_.size()}; } auto const result = - jv.if_object()->emplace(s, nullptr); + jv.get_object().emplace(s, nullptr); // overwrite duplicate keys if(! result.second) result.first->second.emplace_null(); @@ -253,9 +253,9 @@ on_string_data( else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(string{}); + jv.get_array().emplace_back(string{}); stack_.push( - &jv.if_array()->back()); + &jv.get_array().back()); stack_.front()->if_string()->append( s.data(), s.size()); } @@ -308,7 +308,7 @@ on_int64( else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(i); + jv.get_array().emplace_back(i); } else { @@ -334,7 +334,7 @@ on_uint64( else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(u); + jv.get_array().emplace_back(u); } else { @@ -360,7 +360,7 @@ on_double( else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(d); + jv.get_array().emplace_back(d); } else { @@ -384,7 +384,7 @@ on_bool(bool b, error_code&) else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(b); + jv.get_array().emplace_back(b); } else { @@ -407,7 +407,7 @@ on_null(error_code&) else if(stack_.front()->is_array()) { BOOST_JSON_ASSERT(s_.empty()); - jv.if_array()->emplace_back(nullptr); + jv.get_array().emplace_back(nullptr); } else { diff --git a/include/boost/json/impl/value.ipp b/include/boost/json/impl/value.ipp index 11dd447d..d83fd2f4 100644 --- a/include/boost/json/impl/value.ipp +++ b/include/boost/json/impl/value.ipp @@ -104,64 +104,9 @@ value:: value:: value(pilfered p) noexcept { -#ifdef BOOST_JSON_VALUE_IS_TRIVIAL std::memcpy(this, &p.get(), sizeof(*this)); ::new(&p.get().sca_.sp) storage_ptr{}; p.get().kind_ = json::kind::null; -#else - auto& other = p.get(); - switch(other.kind_) - { - case json::kind::object: - relocate(&obj_, other.obj_); - ::new(&other.sca_.sp) storage_ptr; - break; - - case json::kind::array: - relocate(&arr_, other.arr_); - ::new(&other.sca_.sp) storage_ptr; - break; - - case json::kind::string: - relocate(&str_, other.str_); - ::new(&other.sca_.sp) storage_ptr; - break; - - case json::kind::int64: - ::new(&sca_.i) std::int64_t( - other.sca_.i); - ::new(&sca_.sp) storage_ptr( - std::move(other.sca_.sp)); - break; - - case json::kind::uint64: - ::new(&sca_.u) std::uint64_t( - other.sca_.u); - ::new(&sca_.sp) storage_ptr( - std::move(other.sca_.sp)); - break; - - case json::kind::double_: - ::new(&sca_.d) double( - other.sca_.d); - ::new(&sca_.sp) storage_ptr( - std::move(other.sca_.sp)); - break; - - case json::kind::boolean: - ::new(&sca_.b) bool(other.sca_.b); - ::new(&sca_.sp) storage_ptr( - std::move(other.sca_.sp)); - break; - - case json::kind::null: - ::new(&sca_.sp) storage_ptr( - std::move(other.sca_.sp)); - break; - } - kind_ = other.kind_; - other.kind_ = json::kind::null; -#endif } value:: @@ -225,63 +170,9 @@ value( value:: value(value&& other) noexcept { -#ifdef BOOST_JSON_VALUE_IS_TRIVIAL std::memcpy(this, &other, sizeof(*this)); ::new(&other.sca_.sp) storage_ptr{}; other.kind_ = json::kind::null; -#else - switch(other.kind_) - { - case json::kind::object: - ::new(&obj_) object( - std::move(other.obj_)); - break; - - case json::kind::array: - ::new(&arr_) array( - std::move(other.arr_)); - break; - - case json::kind::string: - ::new(&str_) string( - std::move(other.str_)); - break; - - case json::kind::int64: - ::new(&sca_.i) std::int64_t( - other.sca_.i); - ::new(&sca_.sp) storage_ptr( - other.sca_.sp); - break; - - case json::kind::uint64: - ::new(&sca_.u) std::uint64_t( - other.sca_.u); - ::new(&sca_.sp) storage_ptr( - other.sca_.sp); - break; - - case json::kind::double_: - ::new(&sca_.d) double( - other.sca_.d); - ::new(&sca_.sp) storage_ptr( - other.sca_.sp); - break; - - case json::kind::boolean: - ::new(&sca_.b) bool( - other.sca_.b); - ::new(&sca_.sp) storage_ptr( - other.sca_.sp); - break; - - case json::kind::null: - ::new(&sca_.sp) storage_ptr( - other.sca_.sp); - break; - } - kind_ = other.kind_; -#endif } value:: diff --git a/include/boost/json/kind.hpp b/include/boost/json/kind.hpp index 46d197c4..1386d2ef 100644 --- a/include/boost/json/kind.hpp +++ b/include/boost/json/kind.hpp @@ -44,6 +44,17 @@ enum class kind null }; +struct object_kind_t +{ +}; + +struct array_kind_t +{ +}; + +BOOST_JSON_INLINE_VARIABLE(object_kind, object_kind_t); +BOOST_JSON_INLINE_VARIABLE(array_kind, array_kind_t); + } // json } // boost diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp index f40c8243..f3f01489 100644 --- a/include/boost/json/value.hpp +++ b/include/boost/json/value.hpp @@ -352,7 +352,7 @@ public: // //------------------------------------------------------ - /** Construct an object + /** Construct an object. */ value(object obj) noexcept : obj_(std::move(obj)) @@ -360,7 +360,7 @@ public: { } - /** Construct an object + /** Construct an object. */ value(object obj, storage_ptr sp) : obj_(std::move(obj), std::move(sp)) @@ -368,7 +368,16 @@ public: { } - /** Construct an array + /** Construct an object. + */ + value(object_kind_t, + storage_ptr sp = {}) noexcept + : obj_(std::move(sp)) + , kind_(json::kind::object) + { + } + + /** Construct an array. */ value(array arr) noexcept : arr_(std::move(arr)) @@ -376,7 +385,7 @@ public: { } - /** Construct an array + /** Construct an array. */ value(array arr, storage_ptr sp) : arr_(std::move(arr), std::move(sp)) @@ -384,7 +393,16 @@ public: { } - /** Construct a string + /** Construct an array. + */ + value(array_kind_t, + storage_ptr sp = {}) noexcept + : arr_(std::move(sp)) + , kind_(json::kind::array) + { + } + + /** Construct a string. */ value( string str) noexcept @@ -393,7 +411,7 @@ public: { } - /** Construct a string + /** Construct a string. */ value(string str, storage_ptr sp) : str_(std::move(str), std::move(sp)) @@ -401,7 +419,7 @@ public: { } - /** Construct a string + /** Construct a string. */ value( string_view s, @@ -411,7 +429,7 @@ public: { } - /** Construct a string + /** Construct a string. */ value( char const* s, @@ -1531,6 +1549,112 @@ public: //------------------------------------------------------ + /** Return a value as an object, without checking. + + This is a fast way to gain access to an object + value when the kind is known. + + @par Preconditions + + @code + this->is_object() + @endcode + + @par Complexity + + Constant. + + @par Exception Safety + + No-throw guarantee. + */ + object& + get_object() noexcept + { + BOOST_JSON_ASSERT(is_object()); + return obj_; + } + + /** Return a value as an object, without checking. + + This is a fast way to gain access to an object + value when the kind is known. + + @par Preconditions + + @code + this->is_object() + @endcode + + @par Complexity + + Constant. + + @par Exception Safety + + No-throw guarantee. + */ + object const& + get_object() const noexcept + { + BOOST_JSON_ASSERT(is_object()); + return obj_; + } + + /** Return a value as an array, without checking. + + This is a fast way to gain access to an array + value when the kind is known. + + @par Preconditions + + @code + this->is_array() + @endcode + + @par Complexity + + Constant. + + @par Exception Safety + + No-throw guarantee. + */ + array& + get_array() noexcept + { + BOOST_JSON_ASSERT(is_array()); + return arr_; + } + + /** Return a value as an array, without checking. + + This is a fast way to gain access to an array + value when the kind is known. + + @par Preconditions + + @code + this->is_array() + @endcode + + @par Complexity + + Constant. + + @par Exception Safety + + No-throw guarantee. + */ + array const& + get_array() const noexcept + { + BOOST_JSON_ASSERT(is_array()); + return arr_; + } + + //------------------------------------------------------ + private: BOOST_JSON_DECL storage_ptr diff --git a/test/number.cpp b/test/number.cpp index 067a28ef..33d6061e 100644 --- a/test/number.cpp +++ b/test/number.cpp @@ -167,8 +167,8 @@ public: check_int64( "99999999999999999", 99999999999999999); check_int64( "999999999999999999", 999999999999999999); check_int64( "9223372036854775807", INT64_MAX); - check_uint64( "9223372036854775808", 9223372036854775808); - check_uint64( "9999999999999999999", 9999999999999999999); + check_uint64( "9223372036854775808", 9223372036854775808ULL); + check_uint64( "9999999999999999999", 9999999999999999999ULL); check_uint64( "18446744073709551615", UINT64_MAX); check_double( "18446744073709551616", 18446744073709551616.0); check_double( "99999999999999999999", 99999999999999999999.0); diff --git a/test/value.cpp b/test/value.cpp index 8a07e4ca..496803d5 100644 --- a/test/value.cpp +++ b/test/value.cpp @@ -515,34 +515,62 @@ public: // value(object) // value(object, storage_ptr) + // value(object_kind, storage_ptr) { { auto jv = value(object()); + BEAST_EXPECT(jv.is_object()); BEAST_EXPECT(*jv.get_storage() == *dsp); } { auto jv = value(object(sp)); + BEAST_EXPECT(jv.is_object()); BEAST_EXPECT(*jv.get_storage() == *sp); } { auto jv = value(object(), sp); + BEAST_EXPECT(jv.is_object()); + BEAST_EXPECT(*jv.get_storage() == *sp); + } + { + auto jv = value(object_kind); + BEAST_EXPECT(jv.is_object()); + BEAST_EXPECT(*jv.get_storage() == *dsp); + } + { + auto jv = value(object_kind, sp); + BEAST_EXPECT(jv.is_object()); BEAST_EXPECT(*jv.get_storage() == *sp); } } // value(array) // value(array, storage_ptr) + // value(object_kind, storage_ptr) { { auto jv = value(array()); + BEAST_EXPECT(jv.is_array()); BEAST_EXPECT(*jv.get_storage() == *dsp); } { auto jv = value(array(sp)); + BEAST_EXPECT(jv.is_array()); BEAST_EXPECT(*jv.get_storage() == *sp); } { auto jv = value(array(), sp); + BEAST_EXPECT(jv.is_array()); + BEAST_EXPECT(*jv.get_storage() == *sp); + } + { + auto jv = value(array_kind); + BEAST_EXPECT(jv.is_array()); + BEAST_EXPECT(*jv.get_storage() == *dsp); + } + { + auto jv = value(array_kind, sp); + BEAST_EXPECT(jv.is_array()); BEAST_EXPECT(*jv.get_storage() == *sp); } } @@ -552,14 +580,17 @@ public: { { auto jv = value(string()); + BEAST_EXPECT(jv.is_string()); BEAST_EXPECT(*jv.get_storage() == *dsp); } { auto jv = value(string(sp)); + BEAST_EXPECT(jv.is_string()); BEAST_EXPECT(*jv.get_storage() == *sp); } { auto jv = value(string(), sp); + BEAST_EXPECT(jv.is_string()); BEAST_EXPECT(*jv.get_storage() == *sp); } } @@ -609,6 +640,36 @@ public: } } + // value(bool) + // value(bool, storage_ptr) + { + { + auto jv = value(true); + BEAST_EXPECT(jv.is_bool()); + BEAST_EXPECT(*jv.get_storage() == *dsp); + } + { + auto jv = value(true, sp); + BEAST_EXPECT(jv.is_bool()); + BEAST_EXPECT(*jv.get_storage() == *sp); + } + } + + // value(nullptr_t) + // value(nullptr_t, storage_ptr) + { + { + auto jv = value(nullptr); + BEAST_EXPECT(jv.is_null()); + BEAST_EXPECT(*jv.get_storage() == *dsp); + } + { + auto jv = value(nullptr, sp); + BEAST_EXPECT(jv.is_null()); + BEAST_EXPECT(*jv.get_storage() == *sp); + } + } + // value(initializer_list) // value(initializer_list, storage_ptr) {