Skip to content

Commit f48cc9e

Browse files
committed
refactor into one loop
1 parent d05bc04 commit f48cc9e

File tree

3 files changed

+148
-79
lines changed

3 files changed

+148
-79
lines changed

include/boost/json/detail/value.hpp

+24
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,30 @@ struct access
269269
{
270270
return e.next_;
271271
}
272+
273+
template< class Object >
274+
static
275+
index_t&
276+
bucket(Object& obj, string_view key) noexcept
277+
{
278+
return obj.t_->bucket( key );
279+
}
280+
281+
template< class Object >
282+
static
283+
void
284+
grow_size(Object& obj) noexcept
285+
{
286+
++obj.t_->size;
287+
}
288+
289+
template< class Object >
290+
static constexpr
291+
index_t
292+
null_index(Object const&) noexcept
293+
{
294+
return Object::null_index_;
295+
}
272296
};
273297

274298
} // detail

include/boost/json/impl/object.ipp

+121-79
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,126 @@ find_in_object<string_view>(
7070
object const& obj,
7171
string_view key) noexcept;
7272

73+
// returns pointer to duplicate element
74+
template< bool SmallTable >
75+
key_value_pair*
76+
add_to_bucket( object& obj, key_value_pair* kv ) noexcept
77+
{
78+
return find_in_object( obj, kv->key() ).first;
79+
}
80+
81+
template<>
82+
key_value_pair*
83+
add_to_bucket< false >( object& obj, key_value_pair* kv )
84+
noexcept
85+
{
86+
auto& head = access::bucket( obj, kv->key() );
87+
auto i = head;
88+
while( true )
89+
{
90+
if(i == access::null_index(obj) )
91+
{
92+
// end of bucket
93+
access::next(*kv) = head;
94+
head = static_cast< access::index_t >( kv - obj.begin() );
95+
return nullptr;
96+
}
97+
98+
auto& v = obj.begin()[i];
99+
if( v.key() != kv->key() )
100+
{
101+
i = access::next(v);
102+
continue;
103+
}
104+
105+
access::next(*kv) = access::next(v);
106+
return &v;
107+
}
108+
}
109+
110+
template< bool Ignore >
111+
std::integral_constant<bool, Ignore>
112+
handle_duplicate( key_value_pair& new_kv, key_value_pair& old_kv ) noexcept
113+
{
114+
// don't bother to check if
115+
// storage deallocate is trivial
116+
old_kv.~key_value_pair();
117+
// trivial relocate
118+
std::memcpy( static_cast<void*>(&old_kv), &new_kv, sizeof(old_kv) );
119+
return {};
120+
}
121+
122+
template<>
123+
std::integral_constant<bool, false>
124+
handle_duplicate< false >( key_value_pair&, key_value_pair& ) noexcept
125+
{
126+
return {};
127+
}
128+
129+
template< class SmallTable, class IgnoreDuplicates >
130+
void
131+
unchecked_init_impl(
132+
object& obj, unchecked_object& uo, SmallTable, IgnoreDuplicates )
133+
{
134+
// insert all elements, either keeping the last of any duplicate keys, or
135+
// aborting insertion, depending on whether uo.ignore_duplicates is false.
136+
auto dest = obj.begin();
137+
for( ; uo.size(); uo.pop_front() )
138+
{
139+
auto src = uo.front();
140+
access::construct_key_value_pair(
141+
dest, pilfer(src[0]), pilfer(src[1]));
142+
143+
auto const duplicate = add_to_bucket< SmallTable::value >( obj, dest );
144+
if( !duplicate )
145+
{
146+
++dest;
147+
access::grow_size(obj);
148+
continue;
149+
}
150+
if( !handle_duplicate< IgnoreDuplicates::value >(*dest, *duplicate) )
151+
{
152+
dest->~key_value_pair();
153+
return;
154+
}
155+
}
156+
}
157+
158+
template< class SmallTable >
159+
struct unchecked_init_helper2
160+
{
161+
object& obj;
162+
unchecked_object& uo;
163+
164+
template< class IgnoreDuplicates >
165+
void operator()(IgnoreDuplicates) const
166+
{
167+
unchecked_init_impl( obj, uo, SmallTable(), IgnoreDuplicates() );
168+
}
169+
};
170+
171+
struct unchecked_init_helper1
172+
{
173+
object& obj;
174+
unchecked_object& uo;
175+
176+
template< class SmallTable >
177+
void operator()(SmallTable) const
178+
{
179+
mp11::mp_with_index<2>(
180+
uo.ignore_duplicate_keys(),
181+
unchecked_init_helper2< SmallTable >{obj, uo} );
182+
}
183+
};
184+
185+
void
186+
initialize_from_unchecked(object& obj, unchecked_object& uo, bool small_table)
187+
{
188+
mp11::mp_with_index<2>(
189+
small_table,
190+
unchecked_init_helper1{obj, uo});
191+
}
192+
73193
} // namespace detail
74194

75195
//----------------------------------------------------------
@@ -212,85 +332,7 @@ object(detail::unchecked_object& uo)
212332
uo.size(), 0, sp_);
213333
t_->size = 0;
214334

215-
// insert all elements, keeping
216-
// the last of any duplicate keys, unless uo.ignore_duplicates is false.
217-
auto dest = begin();
218-
if(t_->is_small())
219-
{
220-
for( ; uo.size(); uo.pop_front() )
221-
{
222-
auto src = uo.front();
223-
access::construct_key_value_pair(
224-
dest, pilfer(src[0]), pilfer(src[1]));
225-
auto result = detail::find_in_object(*this, dest->key());
226-
if(! result.first)
227-
{
228-
++dest;
229-
++t_->size;
230-
continue;
231-
}
232-
// handle duplicate
233-
if( !uo.ignore_duplicate_keys() )
234-
{
235-
dest->~key_value_pair();
236-
return;
237-
}
238-
auto& v = *result.first;
239-
// don't bother to check if
240-
// storage deallocate is trivial
241-
v.~key_value_pair();
242-
// trivial relocate
243-
std::memcpy(
244-
static_cast<void*>(&v),
245-
dest, sizeof(v));
246-
}
247-
return;
248-
}
249-
for( ; uo.size() ; uo.pop_front() )
250-
{
251-
auto src = uo.front();
252-
access::construct_key_value_pair(
253-
dest, pilfer(src[0]), pilfer(src[1]));
254-
auto& head = t_->bucket(dest->key());
255-
auto i = head;
256-
for(;;)
257-
{
258-
if(i == null_index_)
259-
{
260-
// end of bucket
261-
access::next(
262-
*dest) = head;
263-
head = static_cast<index_t>(
264-
dest - begin());
265-
++dest;
266-
++t_->size;
267-
break;
268-
}
269-
auto& v = (*t_)[i];
270-
if(v.key() != dest->key())
271-
{
272-
i = access::next(v);
273-
continue;
274-
}
275-
276-
// handle duplicate
277-
if( !uo.ignore_duplicate_keys() )
278-
{
279-
dest->~key_value_pair();
280-
return;
281-
}
282-
access::next(*dest) =
283-
access::next(v);
284-
// don't bother to check if
285-
// storage deallocate is trivial
286-
v.~key_value_pair();
287-
// trivial relocate
288-
std::memcpy(
289-
static_cast<void*>(&v),
290-
dest, sizeof(v));
291-
break;
292-
}
293-
}
335+
detail::initialize_from_unchecked( *this, uo, t_->is_small() );
294336
}
295337

296338
object::

include/boost/json/object.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,10 @@ class object
15521552
operator<<(
15531553
std::ostream& os,
15541554
object const& obj);
1555+
15551556
private:
1557+
friend struct detail::access;
1558+
15561559
#ifndef BOOST_JSON_DOCS
15571560
// VFALCO friending a detail function makes it public
15581561
template<class CharRange>

0 commit comments

Comments
 (0)