Skip to content

Commit

Permalink
different approach
Browse files Browse the repository at this point in the history
  • Loading branch information
grisumbras committed Nov 7, 2022
1 parent 23f8e28 commit 6cc4182
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 98 deletions.
23 changes: 9 additions & 14 deletions include/boost/json/detail/impl/handler.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,8 @@ on_object_end(
std::size_t n,
error_code& ec)
{
if( !ignore_duplicate_keys )
ec = st.check_duplicates(n);
if( ec.failed() )
return false;

st.push_object(n);
return true;
ec = st.push_object(n, ignore_duplicate_keys);
return !ec.failed();
}

bool
Expand Down Expand Up @@ -90,7 +85,7 @@ on_key_part(
st.push_chars(s);
return true;
}

bool
handler::
on_key(
Expand All @@ -101,12 +96,12 @@ on_key(
st.push_key(s);
return true;
}

bool
handler::
on_string_part(
string_view s,
std::size_t,
std::size_t,
error_code&)
{
st.push_chars(s);
Expand All @@ -117,7 +112,7 @@ bool
handler::
on_string(
string_view s,
std::size_t,
std::size_t,
error_code&)
{
st.push_string(s);
Expand All @@ -143,7 +138,7 @@ on_int64(
st.push_int64(i);
return true;
}

bool
handler::
on_uint64(
Expand All @@ -165,7 +160,7 @@ on_double(
st.push_double(d);
return true;
}

bool
handler::
on_bool(
Expand All @@ -192,7 +187,7 @@ on_comment_part(
{
return true;
}

bool
handler::
on_comment(
Expand Down
34 changes: 20 additions & 14 deletions include/boost/json/detail/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,30 @@ class unchecked_object
// first one is a string key,
// second one is the value.
value* data_;
value* end_;
std::size_t size_;
storage_ptr const& sp_;
bool ignore_duplicates_;

public:
inline
~unchecked_object();

inline
unchecked_object(
value* data,
std::size_t size, // # of kv-pairs
storage_ptr const& sp) noexcept
: data_(data)
, size_(size)
, sp_(sp)
{
}
storage_ptr const& sp,
bool ignore_duplicates) noexcept;

unchecked_object(
unchecked_object&& other) noexcept
: data_(other.data_)
, size_(other.size_)
, end_(other.end_)
, sp_(other.sp_)
, ignore_duplicates_(other.ignore_duplicates_)
{
other.data_ = nullptr;
other.data_ = other.end_ = nullptr;
}

storage_ptr const&
Expand All @@ -60,19 +60,25 @@ class unchecked_object
return sp_;
}

inline
std::size_t
size() const noexcept
size() const noexcept;

bool
ignore_duplicate_keys() const noexcept
{
return size_;
return ignore_duplicates_;
}

value*
release() noexcept
front() noexcept
{
auto const data = data_;
data_ = nullptr;
return data;
return data_;
}

inline
void
pop_front() noexcept;
};

template<class CharRange>
Expand Down
34 changes: 29 additions & 5 deletions include/boost/json/impl/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,19 +518,43 @@ namespace detail {
unchecked_object::
~unchecked_object()
{
if(! data_)
return;
if(sp_.is_not_shared_and_deallocate_is_trivial())
return;
value* p = data_;
while(size_--)

for( value* p = data_; p != end_; p += 2 )
{
p[0].~value();
p[1].~value();
p += 2;
}
}

unchecked_object::
unchecked_object(
value* data,
std::size_t size,
storage_ptr const& sp,
bool ignore_duplicates) noexcept
: data_(data)
, end_(data + 2 * size)
, sp_(sp)
, ignore_duplicates_(ignore_duplicates)
{
}

std::size_t
unchecked_object::
size() const noexcept
{
return std::size_t(end_ - data_) / 2;
}

void
unchecked_object::
pop_front() noexcept
{
data_ += 2;
}

} // detail

BOOST_JSON_NS_END
Expand Down
29 changes: 18 additions & 11 deletions include/boost/json/impl/object.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ destroy() noexcept
//----------------------------------------------------------

object::
object(detail::unchecked_object&& uo)
object(detail::unchecked_object& uo)
: sp_(uo.storage())
{
if(uo.size() == 0)
Expand All @@ -210,20 +210,18 @@ object(detail::unchecked_object&& uo)
uo.size() <= max_size());
t_ = table::allocate(
uo.size(), 0, sp_);
t_->size = 0;

// insert all elements, keeping
// the last of any duplicate keys.
// the last of any duplicate keys, unless uo.ignore_duplicates is false.
auto dest = begin();
auto src = uo.release();
auto const end = src + 2 * uo.size();
if(t_->is_small())
{
t_->size = 0;
while(src != end)
for( ; uo.size(); uo.pop_front() )
{
auto src = uo.front();
access::construct_key_value_pair(
dest, pilfer(src[0]), pilfer(src[1]));
src += 2;
auto result = detail::find_in_object(*this, dest->key());
if(! result.first)
{
Expand All @@ -232,6 +230,11 @@ object(detail::unchecked_object&& uo)
continue;
}
// handle duplicate
if( !uo.ignore_duplicate_keys() )
{
dest->~key_value_pair();
return;
}
auto& v = *result.first;
// don't bother to check if
// storage deallocate is trivial
Expand All @@ -243,11 +246,11 @@ object(detail::unchecked_object&& uo)
}
return;
}
while(src != end)
for( ; uo.size() ; uo.pop_front() )
{
auto src = uo.front();
access::construct_key_value_pair(
dest, pilfer(src[0]), pilfer(src[1]));
src += 2;
auto& head = t_->bucket(dest->key());
auto i = head;
for(;;)
Expand All @@ -260,6 +263,7 @@ object(detail::unchecked_object&& uo)
head = static_cast<index_t>(
dest - begin());
++dest;
++t_->size;
break;
}
auto& v = (*t_)[i];
Expand All @@ -270,6 +274,11 @@ object(detail::unchecked_object&& uo)
}

// handle duplicate
if( !uo.ignore_duplicate_keys() )
{
dest->~key_value_pair();
return;
}
access::next(*dest) =
access::next(v);
// don't bother to check if
Expand All @@ -282,8 +291,6 @@ object(detail::unchecked_object&& uo)
break;
}
}
t_->size = static_cast<
index_t>(dest - begin());
}

object::
Expand Down
57 changes: 14 additions & 43 deletions include/boost/json/impl/value_stack.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -82,37 +82,6 @@ has_chars()
return chars_ != 0;
}

error_code
value_stack::
stack::
check_duplicates(std::size_t n)
{
error_code ec;

for( value* first = top_ - 2 * n; first != top_; first += 2 )
{
BOOST_ASSERT( first->is_string() );
value* other = first + 2;
while( true )
{
BOOST_ASSERT( other->is_string() );
if( first->get_string() == other->get_string() )
{
BOOST_JSON_FAIL( ec, error::duplicate_key );
goto before_return;
}

if( other == top_ )
break;

other += 2;
}
}

before_return:
return ec;
}

//--------------------------------------

// destroy the values but
Expand Down Expand Up @@ -320,7 +289,7 @@ exchange(Unchecked&& u)
// which belongs to `u`.
detail::access::
construct_value(
&jv.v, std::move(u));
&jv.v, static_cast<Unchecked&&>(u));
std::memcpy(
reinterpret_cast<
char*>(top_),
Expand Down Expand Up @@ -395,16 +364,25 @@ push_array(std::size_t n)
st_.exchange(std::move(ua));
}

void
error_code
value_stack::
push_object(std::size_t n)
push_object(std::size_t n, bool ignore_duplicates)
{
// we already have room if n > 0
if(BOOST_JSON_UNLIKELY(n == 0))
st_.maybe_grow();

detail::unchecked_object uo(
st_.release(n * 2), n, sp_);
st_.exchange(std::move(uo));
st_.release(n * 2), n, sp_, ignore_duplicates);
st_.exchange(uo);

error_code ec;
// constructed object should have consumed all of uo's data
if( uo.size() )
{
BOOST_JSON_FAIL( ec, error::duplicate_key );
}
return ec;
}

void
Expand Down Expand Up @@ -498,13 +476,6 @@ push_null()
st_.push(nullptr, sp_);
}

error_code
value_stack::
check_duplicates(std::size_t n)
{
return st_.check_duplicates(n);
}

BOOST_JSON_NS_END

#endif
2 changes: 1 addition & 1 deletion include/boost/json/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class object

BOOST_JSON_DECL
explicit
object(detail::unchecked_object&& uo);
object(detail::unchecked_object& uo);

public:
/** The type of _Allocator_ returned by @ref get_allocator
Expand Down
4 changes: 2 additions & 2 deletions include/boost/json/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class value

explicit
value(
detail::unchecked_object&& uo)
: obj_(std::move(uo))
detail::unchecked_object& uo)
: obj_(uo)
{
}

Expand Down
Loading

0 comments on commit 6cc4182

Please sign in to comment.