@@ -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
296338object::
0 commit comments