@@ -115,7 +115,7 @@ TEMPLATE
115115inline Link CLASS::index (const Key& key) const NOEXCEPT
116116{
117117 using namespace system ;
118- const auto index = possible_narrow_cast<link>(keys::hash<Key> (key));
118+ const auto index = possible_narrow_cast<link>(keys::hash (key));
119119 return bit_and<link>(mask_, index);
120120}
121121
@@ -129,37 +129,28 @@ TEMPLATE
129129inline Link CLASS::top (const Key& key) const NOEXCEPT
130130{
131131 const auto value = get_cell (index (key));
132- if (is_collision (value, key))
132+ if (screened (value, key))
133133 return to_link (value);
134-
134+
135+ // Conflict (body) search is bypassed by filter when key is not screened.
136+ // If terminal here it is assured that table does not contain the key.
135137 return {};
136138}
137139
138140TEMPLATE
139141inline bool CLASS::push (const Link& current, bytes& next,
140142 const Key& key) NOEXCEPT
141143{
142- return push (current, next, index (key));
143- }
144-
145- TEMPLATE
146- inline bool CLASS::push (const Link& current, bytes& next,
147- const Link& index) NOEXCEPT
148- {
149- return set_cell (next, current, index) != terminal;
144+ bool unused{};
145+ return push (unused, current, next, key);
150146}
151147
152148TEMPLATE
153149inline bool CLASS::push (bool & collision, const Link& current, bytes& next,
154150 const Key& key) NOEXCEPT
155151{
156- const auto previous = set_cell (next, current, index (key));
157- if (previous == terminal)
158- return false ;
159-
160- // Caller searches Link{ next } for duplicate in case of filter collision.
161- collision = is_collision (previous, key);
162- return true ;
152+ // next holds previous top and can searched for dups if collision is true.
153+ return set_cell (collision, next, current, key);
163154}
164155
165156// protected
@@ -181,31 +172,31 @@ inline CLASS::cell CLASS::get_cell(const Link& index) const NOEXCEPT
181172 // //const std::atomic_ref<cell> top(unsafe_byte_cast<cell>(raw));
182173 const auto & top = *pointer_cast<std::atomic<cell>>(raw);
183174
184- // Acquire is necessary to synchronize with push release.
175+ // Acquire is necessary to synchronize with set_cell release.
185176 // Relaxed would miss next updates, so acquire is optimal.
186177 return top.load (std::memory_order_acquire);
187178 }
188179 else
189180 {
190- cell top{} ;
191- const auto & head = cell_array (raw) ;
181+ const auto & top = cell_array (raw) ;
182+ cell head{} ;
192183
193184 mutex_.lock_shared ();
194- cell_array (top ) = head ;
185+ cell_array (head ) = top ;
195186 mutex_.unlock_shared ();
196187
197- return top ;
188+ return head ;
198189 }
199190}
200191
201192TEMPLATE
202- inline CLASS::cell CLASS::set_cell (bytes& next, const Link& current,
203- const Link& index ) NOEXCEPT
193+ inline bool CLASS::set_cell (bool & collision, bytes& next, const Link& current,
194+ const Key& key ) NOEXCEPT
204195{
205196 using namespace system ;
206- const auto raw = file_.get_raw (link_to_position (index));
197+ const auto raw = file_.get_raw (link_to_position (index (key) ));
207198 if (is_null (raw))
208- return terminal ;
199+ return false ;
209200
210201 if constexpr (aligned)
211202 {
@@ -214,28 +205,30 @@ inline CLASS::cell CLASS::set_cell(bytes& next, const Link& current,
214205 // //const std::atomic_ref<cell> head(unsafe_byte_cast<cell>(raw));
215206 auto & top = *pointer_cast<std::atomic<cell>>(raw);
216207 auto head = top.load (std::memory_order_acquire);
208+ cell update{};
217209 do
218210 {
219211 // Compiler could order this after top.store, which would expose key
220212 // to search before next entry is linked. Thread fence imposes order.
221213 // A release fence ensures that all prior writes (like next) are
222214 // completed before any subsequent atomic store.
223215 next = link_array (head);
216+ update = to_cell (collision, head, current, key);
224217 std::atomic_thread_fence (std::memory_order_release);
225218 }
226- while (!top.compare_exchange_weak (head, to_cell (head, current) ,
219+ while (!top.compare_exchange_weak (head, update ,
227220 std::memory_order_release, std::memory_order_acquire));
228221 }
229222 else
230223 {
231- cell top{} ;
232- auto & head = cell_array (raw) ;
224+ auto & top = cell_array (raw) ;
225+ cell head{} ;
233226
234227 mutex_.lock ();
235- cell_array (top ) = head ;
236- next = link_array (top );
237- auto bytes = to_cell (top, current);
238- head = cell_array (bytes );
228+ cell_array (head ) = top ;
229+ next = link_array (head );
230+ auto update = to_cell (collision, head, current, key );
231+ top = cell_array (update );
239232 mutex_.unlock ();
240233 }
241234
@@ -247,31 +240,67 @@ inline CLASS::cell CLASS::set_cell(bytes& next, const Link& current,
247240// filters
248241
249242TEMPLATE
250- constexpr CLASS::link CLASS::to_link (cell value) NOEXCEPT
243+ INLINE constexpr bool CLASS::screened (cell value, const Key& key ) NOEXCEPT
251244{
252- if (value == terminal)
253- return {};
245+ if constexpr (sieve_t ::disabled)
246+ {
247+ return true ;
248+ }
249+ else
250+ {
251+ return sieve_t::is_screened (to_filter (value), fingerprint (key));
252+ }
253+ }
254254
255+ TEMPLATE
256+ INLINE constexpr CLASS::filter CLASS::fingerprint (const Key& key) NOEXCEPT
257+ {
255258 using namespace system ;
256- constexpr auto mask = unmask_right<cell>(link_bits);
257- return possible_narrow_cast<link>(bit_and (value, mask));
259+ return possible_narrow_cast<filter>(keys::thumb (key));
258260}
259261
260262TEMPLATE
261- constexpr CLASS::cell CLASS::to_cell (cell, link current ) NOEXCEPT
263+ INLINE constexpr CLASS::filter CLASS::to_filter (cell value ) NOEXCEPT
262264{
263- // TODO:
264- return current ;
265+ using namespace system ;
266+ return possible_narrow_cast<filter>( shift_right (value, link_bits)) ;
265267}
266268
267269TEMPLATE
268- constexpr bool CLASS::is_collision (cell value, const Key& ) NOEXCEPT
270+ INLINE constexpr CLASS::link CLASS::to_link (cell value) NOEXCEPT
269271{
270- if (value == terminal)
271- return false ;
272+ if constexpr (sieve_t ::disabled)
273+ {
274+ return system::possible_narrow_cast<link>(value);
275+ }
276+ else
277+ {
278+ using namespace system ;
279+ if (value == terminal)
280+ return {};
272281
273- // TODO:
274- return true ;
282+ constexpr auto mask = unmask_right<cell>(link_bits);
283+ return possible_narrow_cast<link>(bit_and (value, mask));
284+ }
285+ }
286+
287+ TEMPLATE
288+ INLINE constexpr CLASS::cell CLASS::to_cell (bool & collision, cell previous,
289+ link current, const Key& key) NOEXCEPT
290+ {
291+ if constexpr (sieve_t ::disabled)
292+ {
293+ collision = true ;
294+ return current;
295+ }
296+ else
297+ {
298+ using namespace system ;
299+ const auto sieve = to_filter (previous);
300+ const auto next = sieve_t::screen (sieve, fingerprint (key));
301+ collision = (next == sieve || sieve_t::is_saturated (next));
302+ return bit_or<cell>(shift_left<cell>(next, link_bits), current);
303+ }
275304}
276305
277306} // namespace database
0 commit comments