6 #ifndef TURI_VALUE_CONTAINER_MAPPER_H_ 7 #define TURI_VALUE_CONTAINER_MAPPER_H_ 14 #include <core/util/code_optimization.hpp> 15 #include <sparsehash/dense_hash_set> 16 #include <core/generics/value_container_mapper_internal.hpp> 75 template <
typename Value,
typename ValueContainer>
92 inline size_t size()
const {
105 DASSERT_TRUE(hv.value() == v_ptr->get_hashkey_and_value().value());
106 DASSERT_TRUE(hv.key() == v_ptr->get_hashkey_and_value().key());
107 _insert(hv.key(), v_ptr);
122 return _find_reference<ValueContainer*, value_container_mapper>(
this, hv.key(), hv.value());
131 return _find_reference<ValueContainer*, value_container_mapper>(
this, key, t);
139 return _find_reference<const ValueContainer*, const value_container_mapper>(
this, hv.key(), hv.value());
148 return _find_reference<const ValueContainer*, const value_container_mapper>(
this, key, t);
157 DASSERT_TRUE(hv.value() == v_ptr->get_hashkey_and_value().value());
158 DASSERT_TRUE(hv.key() == v_ptr->get_hashkey_and_value().key());
159 _invalidate(hv.key(), v_ptr);
171 _invalidate(hk, v_ptr);
175 struct internal_value_type {
177 mutable ValueContainer* second;
182 return kv_pair.first.hash();
186 struct gdhs_equality {
187 bool operator()(
const internal_value_type& kv_pair_1,
const internal_value_type& kv_pair_2)
const GL_HOT_INLINE_FLATTEN {
189 if(hashkey::key_is_exact()) {
190 return kv_pair_1.first == kv_pair_2.first;
194 if(kv_pair_1.first != kv_pair_2.first)
197 if(hashkey::use_explicit_delete()) {
199 if(kv_pair_1.second ==
nullptr && kv_pair_2.second ==
nullptr)
202 return (kv_pair_1.second !=
nullptr 203 && kv_pair_2.second !=
nullptr 204 && (kv_pair_1.second->get_hashkey_and_value().value()
205 == kv_pair_2.second->get_hashkey_and_value().value()));
209 if(kv_pair_1.second ==
nullptr && kv_pair_2.second ==
nullptr)
212 return (kv_pair_1.second !=
nullptr 213 && kv_pair_2.second !=
nullptr 214 && kv_pair_1.second->get_hashkey_and_value().key() == kv_pair_1.first
215 && kv_pair_2.second->get_hashkey_and_value().key() == kv_pair_2.first
216 && (kv_pair_1.second->get_hashkey_and_value().value()
217 == kv_pair_2.second->get_hashkey_and_value().value()));
223 typedef google::dense_hash_set<internal_value_type, gdhs_hash, gdhs_equality> hash_map_type;
224 friend hash_map_type;
229 : _kv_empty_value(hashkey_and_value(hashkey::as_empty(), Value()))
230 , _kv_empty({hashkey::as_empty(),
nullptr})
231 , _kv_deleted_value(hashkey_and_value(hashkey::as_deleted(), Value()))
232 , _kv_deleted({hashkey::as_deleted(),
nullptr})
234 table.set_empty_key(_kv_empty);
236 if(hashkey::use_explicit_delete())
237 table.set_deleted_key(_kv_deleted);
240 DASSERT_TRUE(gdhs_equality()(_kv_deleted, _kv_deleted));
252 if(hashkey::use_explicit_delete()) {
270 internal_value_type kv_pair{key, v_ptr};
272 if(UNLIKELY(hashkey::is_empty(kv_pair.first) )) {
273 _erase_in_stack(kv_pair, _kv_empty, _kv_empty_overflow_stack);
277 if(UNLIKELY(hashkey::is_deleted(kv_pair.first) )) {
278 _erase_in_stack(kv_pair, _kv_deleted, _kv_deleted_overflow_stack);
282 if(hashkey::use_explicit_delete()) {
284 table.erase(kv_pair);
290 if(UNLIKELY(erase_counter >= reserved_size)) {
291 refresh_hash_table();
300 internal_value_type kv_pair{key, v_ptr};
302 if(UNLIKELY(hashkey::is_empty(kv_pair.first) )) {
303 _insert_in_stack(kv_pair, _kv_empty, _kv_empty_overflow_stack);
307 if(UNLIKELY(hashkey::is_deleted(kv_pair.first) )) {
308 _insert_in_stack(kv_pair, _kv_deleted, _kv_deleted_overflow_stack);
312 auto ret = table.insert(kv_pair);
314 if(!hashkey::use_explicit_delete()) {
315 ret.first->second = kv_pair.second;
322 inline size_t _size()
const {
323 return ( (_kv_empty.second ==
nullptr ? 0 : 1)
324 + _kv_empty_overflow_stack.size()
325 + (_kv_deleted.second ==
nullptr ? 0 : 1)
326 + _kv_deleted_overflow_stack.size()
332 inline void _clear() {
333 _kv_empty.second =
nullptr;
334 _kv_empty_overflow_stack.clear();
335 _kv_deleted.second =
nullptr;
336 _kv_deleted_overflow_stack.clear();
342 size_t reserved_size;
343 size_t erase_counter = 0;
345 ValueContainer _kv_empty_value;
346 internal_value_type _kv_empty;
347 std::vector<internal_value_type> _kv_empty_overflow_stack;
349 ValueContainer _kv_deleted_value;
350 internal_value_type _kv_deleted;
351 std::vector<internal_value_type> _kv_deleted_overflow_stack;
355 void _erase_in_stack(
const internal_value_type& kv_pair,
356 internal_value_type& kv_base,
357 std::vector<internal_value_type>& stack) GL_HOT_NOINLINE_FLATTEN {
359 if(hashkey::key_is_exact()) {
361 kv_base.second =
nullptr;
366 if(kv_base.second->get_hashkey_and_value().value()
367 == kv_pair.second->get_hashkey_and_value().value()) {
370 kv_base.second =
nullptr;
373 kv_base = stack.back();
382 size_t found_idx = size_t(-1);
383 for(
size_t idx = 0; idx < stack.size(); ++idx) {
384 if(stack[idx].second->get_hashkey_and_value().value()
385 == kv_pair.second->get_hashkey_and_value().value()) {
392 std::swap(stack[found_idx], stack.back());
398 mutable ValueContainer v_temp;
404 template <
typename _ReferenceType,
typename _ThisType>
406 static _ReferenceType _find_reference(_ThisType* c,
const hashkey& key,
const Value& t) {
408 if(hashkey::key_is_exact()) {
410 if(UNLIKELY(hashkey::is_empty(key) )) {
411 return c->_kv_empty.second;
414 if(UNLIKELY(hashkey::is_deleted(key) )) {
415 return c->_kv_deleted.second;
418 c->v_temp = ValueContainer(hashkey_and_value(key, t));
420 auto it = c->table.find(internal_value_type{key, &c->v_temp});
422 return ( (it == c->table.end()
423 || (!hashkey::use_explicit_delete() && it->first != it->second->get_hashkey_and_value().key()))
424 ? _ReferenceType(
nullptr)
429 typedef typename std::conditional<std::is_const<_ThisType>::value,
430 const internal_value_type&, internal_value_type&>::type iv_ref;
432 typedef typename std::conditional<std::is_const<_ThisType>::value,
433 const std::vector<internal_value_type>&,
434 std::vector<internal_value_type>& >::type iv_vect_ref;
437 auto find_in_stack = [&](
439 iv_vect_ref stack) GL_GCC_ONLY(GL_HOT_NOINLINE_FLATTEN) {
441 if(LIKELY(kv_base.second ==
nullptr)) {
442 return _ReferenceType(
nullptr);
445 if(kv_base.second->get_hashkey_and_value().value() == t) {
446 return _ReferenceType(kv_base.second);
449 for(
size_t idx = 0; idx < stack.size(); ++idx) {
450 if(stack[idx].second->get_hashkey_and_value().value() == t)
451 return _ReferenceType(stack[idx].second);
454 return _ReferenceType(
nullptr);
457 if(UNLIKELY(hashkey::is_empty(key) )) {
458 return find_in_stack(c->_kv_empty, c->_kv_empty_overflow_stack);
461 if(UNLIKELY(hashkey::is_deleted(key))) {
462 return find_in_stack(c->_kv_deleted, c->_kv_deleted_overflow_stack);
465 c->v_temp = ValueContainer(hashkey_and_value(key, t));
467 auto it = c->table.find(internal_value_type{key, &c->v_temp});
469 return ( (it == c->table.end()
470 || (!hashkey::use_explicit_delete() && it->first != it->second->get_hashkey_and_value().key()))
471 ? _ReferenceType(
nullptr)
477 void _insert_in_stack(
478 const internal_value_type& v,
479 internal_value_type& kv_base,
480 std::vector<internal_value_type>& stack) GL_HOT_NOINLINE_FLATTEN {
482 if(hashkey::key_is_exact()) {
484 kv_base.second = v.second;
486 if(LIKELY(kv_base.second ==
nullptr)) {
488 kv_base.second = v.second;
497 void refresh_hash_table() GL_HOT_NOINLINE_FLATTEN {
499 hash_map_type alt_table;
500 alt_table.set_empty_key(_kv_empty);
501 alt_table.resize(reserved_size);
503 for(
auto it = table.begin(); it != table.end(); ++it) {
504 if(it->second->get_hashkey_and_value().key() == it->first) {
505 alt_table.insert(*it);
509 table.swap(alt_table);
void invalidate(const hashkey &hk, ValueContainer *v_ptr) GL_HOT_INLINE_FLATTEN
ValueContainer * find(const hashkey_and_value &hv) GL_HOT_INLINE_FLATTEN
ValueContainer * find(const hashkey &key, const Value &t) GL_HOT_INLINE_FLATTEN
#define DASSERT_FALSE(cond)
#define GL_HOT_INLINE_FLATTEN
void insert(const hashkey &hk, ValueContainer *v_ptr) GL_HOT_INLINE_FLATTEN
const ValueContainer * find(const hashkey &key, const Value &t) const GL_HOT_INLINE_FLATTEN
const ValueContainer * find(const hashkey_and_value &hv) const GL_HOT_INLINE_FLATTEN
void insert(const hashkey_and_value &hv, ValueContainer *v_ptr) GL_HOT_INLINE_FLATTEN
#define DASSERT_TRUE(cond)
void invalidate(const hashkey_and_value &hv, ValueContainer *v_ptr) GL_HOT_INLINE_FLATTEN