24 #ifndef TSL_HTRIE_HASH_H 25 #define TSL_HTRIE_HASH_H 38 #include <type_traits> 41 #include "array-hash/array_map.h" 42 #include "array-hash/array_set.h" 50 # if __has_include
(<string_view>) && __cplusplus
>= 201703L
51 # define TSL_HT_HAS_STRING_VIEW 56 #ifdef TSL_HT_HAS_STRING_VIEW 57 # include <string_view> 62 # define tsl_ht_assert(expr) assert(expr) 64 # define tsl_ht_assert(expr) (static_cast<void>(0
)) 72 template<
typename T,
typename =
void>
77 struct is_iterator<T,
typename std::enable_if<!std::is_same<
typename std::iterator_traits<T>::iterator_category,
void>::value>::
type>: std::true_type {
80 template<
typename T,
typename... U>
81 struct is_related: std::false_type {};
83 template<
typename T,
typename U>
84 struct is_related<T, U>: std::is_same<
typename std::remove_cv<
typename std::remove_reference<T>::type>::type,
85 typename std::remove_cv<
typename std::remove_reference<U>::type>::type> {};
87 template<
typename T,
typename U>
88 static T numeric_cast(U value,
const char* error_message =
"numeric_cast() failed.") {
89 T ret =
static_cast<T>(value);
90 if(
static_cast<U>(ret) != value) {
91 throw std::runtime_error(error_message);
94 const bool is_same_signedness = (std::is_unsigned<T>::value && std::is_unsigned<U>::value) ||
95 (std::is_signed<T>::value && std::is_signed<U>::value);
96 if(!is_same_signedness && (ret < T{}) != (value < U{})) {
97 throw std::runtime_error(error_message);
111 template<
class... Args,
typename std::enable_if<!is_related<value_node, Args...>::value>::type* =
nullptr>
112 value_node(Args&&... args): m_value(std::forward<Args>(args)...) {
119 struct value_node<
void> {
126 template<
class CharT,
133 using has_value =
typename std::integral_constant<
bool, !std::is_same<U,
void>::value>;
135 static_assert(std::is_same<CharT,
char>::value,
"char is the only supported CharT type for now.");
137 static const std::size_t ALPHABET_SIZE =
138 std::numeric_limits<
typename std::make_unsigned<CharT>::type>::max() + 1;
142 template<
bool IsConst,
bool IsPrefixIterator>
146 using char_type = CharT;
147 using key_size_type = KeySizeT;
148 using size_type = std::size_t;
157 using array_hash_type =
158 typename std::conditional<
160 tsl::array_map<CharT, T, Hash,
tsl::ah::str_equal<CharT>,
false,
161 KeySizeT, std::uint16_t,
tsl::ah::power_of_two_growth_policy<4>>,
162 tsl::array_set<CharT, Hash,
tsl::ah::str_equal<CharT>,
false,
163 KeySizeT, std::uint16_t,
tsl::ah::power_of_two_growth_policy<4>>>::type;
196 friend class trie_node;
203 virtual ~anode() =
default;
205 bool is_trie_node()
const noexcept {
206 return m_node_type == node_type::TRIE_NODE;
209 bool is_hash_node()
const noexcept {
210 return m_node_type == node_type::HASH_NODE;
213 trie_node& as_trie_node()
noexcept {
215 return static_cast<trie_node&>(*
this);
218 hash_node& as_hash_node()
noexcept {
220 return static_cast<hash_node&>(*
this);
223 const trie_node& as_trie_node()
const noexcept {
225 return static_cast<
const trie_node&>(*
this);
228 const hash_node& as_hash_node()
const noexcept {
230 return static_cast<
const hash_node&>(*
this);
236 CharT child_of_char()
const noexcept {
238 return m_child_of_char;
244 trie_node* parent()
noexcept {
245 return m_parent_node;
248 const trie_node* parent()
const noexcept {
249 return m_parent_node;
253 enum class node_type:
unsigned char {
258 anode(node_type node_type_): m_node_type(node_type_), m_child_of_char(0),
259 m_parent_node(
nullptr)
263 anode(node_type node_type_, CharT child_of_char): m_node_type(node_type_),
264 m_child_of_char(child_of_char),
265 m_parent_node(
nullptr)
271 node_type m_node_type;
288 CharT m_child_of_char;
289 trie_node* m_parent_node;
293 static std::size_t as_position(CharT c)
noexcept {
294 return static_cast<std::size_t>(
static_cast<
typename std::make_unsigned<CharT>::type>(c));
297 class trie_node:
public anode {
299 trie_node(): anode(anode::node_type::TRIE_NODE),
300 m_value_node(
nullptr), m_children()
304 trie_node(
const trie_node& other): anode(anode::node_type::TRIE_NODE, other.m_child_of_char),
305 m_value_node(
nullptr), m_children()
307 if(other.m_value_node !=
nullptr) {
308 m_value_node.reset(
new value_node(*other.m_value_node));
312 for(std::size_t ichild = 0; ichild < other.m_children.size(); ichild++) {
313 if(other.m_children[ichild] !=
nullptr) {
314 if(other.m_children[ichild]->is_hash_node()) {
315 m_children[ichild].reset(
new hash_node(other.m_children[ichild]->as_hash_node()));
318 m_children[ichild].reset(
new trie_node(other.m_children[ichild]->as_trie_node()));
321 m_children[ichild]->m_parent_node =
this;
326 trie_node(trie_node&& other) =
delete;
327 trie_node& operator=(
const trie_node& other) =
delete;
328 trie_node& operator=(trie_node&& other) =
delete;
333 anode* first_child()
noexcept {
334 return const_cast<anode*>(
static_cast<
const trie_node*>(
this)->first_child());
337 const anode* first_child()
const noexcept {
338 for(std::size_t ichild = 0; ichild < m_children.size(); ichild++) {
339 if(m_children[ichild] !=
nullptr) {
340 return m_children[ichild].get();
351 anode* next_child(
const anode& current_child)
noexcept {
352 return const_cast<anode*>(
static_cast<
const trie_node*>(
this)->next_child(current_child));
355 const anode* next_child(
const anode& current_child)
const noexcept {
358 for(std::size_t ichild = as_position(current_child.child_of_char()) + 1;
359 ichild < m_children.size();
362 if(m_children[ichild] !=
nullptr) {
363 return m_children[ichild].get();
374 trie_node& most_left_descendant_value_trie_node()
noexcept {
375 return const_cast<trie_node&>(
static_cast<
const trie_node*>(
this)->most_left_descendant_value_trie_node());
378 const trie_node& most_left_descendant_value_trie_node()
const noexcept {
379 const trie_node* current_node =
this;
381 if(current_node->m_value_node !=
nullptr) {
382 return *current_node;
385 const anode* first_child = current_node->first_child();
387 if(first_child->is_hash_node()) {
388 return *current_node;
391 current_node = &first_child->as_trie_node();
397 size_type nb_children()
const noexcept {
398 return std::count_if(m_children.cbegin(), m_children.cend(),
399 [](
const std::unique_ptr<anode>& n) {
return n !=
nullptr; });
402 bool empty()
const noexcept {
403 return std::all_of(m_children.cbegin(), m_children.cend(),
404 [](
const std::unique_ptr<anode>& n) {
return n ==
nullptr; });
407 std::unique_ptr<anode>& child(CharT for_char)
noexcept {
408 return m_children[as_position(for_char)];
411 const std::unique_ptr<anode>& child(CharT for_char)
const noexcept {
412 return m_children[as_position(for_char)];
415 typename std::array<std::unique_ptr<anode>, ALPHABET_SIZE>::iterator begin()
noexcept {
416 return m_children.begin();
419 typename std::array<std::unique_ptr<anode>, ALPHABET_SIZE>::iterator end()
noexcept {
420 return m_children.end();
423 void set_child(CharT for_char, std::unique_ptr<anode> child)
noexcept {
424 if(child !=
nullptr) {
425 child->m_child_of_char = for_char;
426 child->m_parent_node =
this;
429 m_children[as_position(for_char)] = std::move(child);
432 std::unique_ptr<value_node>& val_node()
noexcept {
436 const std::unique_ptr<value_node>& val_node()
const noexcept {
442 std::unique_ptr<value_node> m_value_node;
453 std::array<std::unique_ptr<anode>, ALPHABET_SIZE> m_children;
457 class hash_node:
public anode {
459 hash_node(
const Hash& hash,
float max_load_factor):
460 hash_node(HASH_NODE_DEFAULT_INIT_BUCKETS_COUNT, hash, max_load_factor)
464 hash_node(size_type bucket_count,
const Hash& hash,
float max_load_factor):
465 anode(anode::node_type::HASH_NODE), m_array_hash(bucket_count, hash)
467 m_array_hash.max_load_factor(max_load_factor);
470 hash_node(array_hash_type&& array_hash)
noexcept(std::is_nothrow_move_constructible<array_hash_type>::value):
471 anode(anode::node_type::HASH_NODE), m_array_hash(std::move(array_hash))
475 hash_node(
const hash_node& other) =
default;
477 hash_node(hash_node&& other) =
delete;
478 hash_node& operator=(
const hash_node& other) =
delete;
479 hash_node& operator=(hash_node&& other) =
delete;
482 array_hash_type& array_hash()
noexcept {
486 const array_hash_type& array_hash()
const noexcept {
491 array_hash_type m_array_hash;
497 template<
bool IsConst,
bool IsPrefixIterator>
502 using anode_type =
typename std::conditional<IsConst,
const anode, anode>::type;
503 using trie_node_type =
typename std::conditional<IsConst,
const trie_node, trie_node>::type;
504 using hash_node_type =
typename std::conditional<IsConst,
const hash_node, hash_node>::type;
506 using array_hash_iterator_type =
507 typename std::conditional<IsConst,
508 typename array_hash_type::const_iterator,
509 typename array_hash_type::iterator>::type;
512 using iterator_category = std::forward_iterator_tag;
513 using value_type =
typename std::conditional<has_value<T>::value, T,
void>::type;
514 using difference_type = std::ptrdiff_t;
515 using reference =
typename std::conditional<
517 typename std::conditional<IsConst,
518 typename std::add_lvalue_reference<
const T>::type,
519 typename std::add_lvalue_reference<T>::type>::type,
521 using pointer =
typename std::conditional<
523 typename std::conditional<IsConst,
const T*, T*>::type,
530 htrie_hash_iterator(hash_node_type& start_hash_node)
noexcept:
538 htrie_hash_iterator(hash_node_type& start_hash_node, array_hash_iterator_type begin)
noexcept:
539 m_current_trie_node(start_hash_node.parent()), m_current_hash_node(&start_hash_node),
540 m_array_hash_iterator(begin),
541 m_array_hash_end_iterator(start_hash_node.array_hash().end()),
542 m_read_trie_node_value(
false)
550 htrie_hash_iterator(trie_node_type& start_trie_node)
noexcept:
551 m_current_trie_node(&start_trie_node), m_current_hash_node(
nullptr),
552 m_read_trie_node_value(
true)
557 template<
bool P = IsPrefixIterator,
typename std::enable_if<!P>::type* =
nullptr>
558 htrie_hash_iterator(trie_node_type* tnode, hash_node_type* hnode,
559 array_hash_iterator_type begin, array_hash_iterator_type end,
560 bool read_trie_node_value)
noexcept:
561 m_current_trie_node(tnode), m_current_hash_node(hnode),
562 m_array_hash_iterator(begin), m_array_hash_end_iterator(end),
563 m_read_trie_node_value(read_trie_node_value)
567 template<
bool P = IsPrefixIterator,
typename std::enable_if<P>::type* =
nullptr>
568 htrie_hash_iterator(trie_node_type* tnode, hash_node_type* hnode,
569 array_hash_iterator_type begin, array_hash_iterator_type end,
570 bool read_trie_node_value, std::basic_string<CharT> prefix_filter)
noexcept:
571 m_current_trie_node(tnode), m_current_hash_node(hnode),
572 m_array_hash_iterator(begin), m_array_hash_end_iterator(end),
573 m_read_trie_node_value(read_trie_node_value), m_prefix_filter(std::move(prefix_filter))
581 template<
bool P = IsPrefixIterator,
typename std::enable_if<!P>::type* =
nullptr>
583 m_current_trie_node(other.m_current_trie_node), m_current_hash_node(other.m_current_hash_node),
584 m_array_hash_iterator(other.m_array_hash_iterator),
585 m_array_hash_end_iterator(other.m_array_hash_end_iterator),
586 m_read_trie_node_value(other.m_read_trie_node_value)
590 template<
bool P = IsPrefixIterator,
typename std::enable_if<P>::type* =
nullptr>
592 m_current_trie_node(other.m_current_trie_node), m_current_hash_node(other.m_current_hash_node),
593 m_array_hash_iterator(other.m_array_hash_iterator),
594 m_array_hash_end_iterator(other.m_array_hash_end_iterator),
595 m_read_trie_node_value(other.m_read_trie_node_value), m_prefix_filter(other.m_prefix_filter)
599 void key(std::basic_string<CharT>& key_buffer_out)
const {
600 key_buffer_out.clear();
602 trie_node_type* tnode = m_current_trie_node;
603 while(tnode !=
nullptr && tnode->parent() !=
nullptr) {
604 key_buffer_out.push_back(tnode->child_of_char());
605 tnode = tnode->parent();
608 std::reverse(key_buffer_out.begin(), key_buffer_out.end());
610 if(!m_read_trie_node_value) {
612 if(m_current_hash_node->parent() !=
nullptr) {
613 key_buffer_out.push_back(m_current_hash_node->child_of_char());
616 key_buffer_out.append(m_array_hash_iterator.key(), m_array_hash_iterator.key_size());
620 std::basic_string<CharT>
key()
const {
621 std::basic_string<CharT> key_buffer;
627 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
629 if(
this->m_read_trie_node_value) {
631 tsl_ht_assert(
this->m_current_trie_node->val_node() !=
nullptr);
633 return this->m_current_trie_node->val_node()->m_value;
636 return this->m_array_hash_iterator.value();
640 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
645 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
647 return std::addressof(value());
651 if(m_read_trie_node_value) {
654 m_read_trie_node_value =
false;
656 anode_type* child = m_current_trie_node->first_child();
657 if(child !=
nullptr) {
658 set_most_left_descendant_as_next_node(*child);
660 else if(m_current_trie_node->parent() !=
nullptr) {
661 trie_node_type* current_node_child = m_current_trie_node;
662 m_current_trie_node = m_current_trie_node->parent();
664 set_next_node_ascending(*current_node_child);
667 set_as_end_iterator();
671 ++m_array_hash_iterator;
672 if(m_array_hash_iterator != m_array_hash_end_iterator) {
676 else if(m_current_trie_node ==
nullptr) {
677 set_as_end_iterator();
681 set_next_node_ascending(*m_current_hash_node);
697 if(lhs.m_current_trie_node != rhs.m_current_trie_node ||
698 lhs.m_read_trie_node_value != rhs.m_read_trie_node_value)
702 else if(lhs.m_read_trie_node_value) {
706 if(lhs.m_current_hash_node != rhs.m_current_hash_node) {
709 else if(lhs.m_current_hash_node ==
nullptr) {
713 return lhs.m_array_hash_iterator == rhs.m_array_hash_iterator &&
714 lhs.m_array_hash_end_iterator == rhs.m_array_hash_end_iterator;
720 return !(lhs == rhs);
724 void hash_node_prefix(std::basic_string<CharT>& key_buffer_out)
const {
726 key_buffer_out.clear();
728 trie_node_type* tnode = m_current_trie_node;
729 while(tnode !=
nullptr && tnode->parent() !=
nullptr) {
730 key_buffer_out.push_back(tnode->child_of_char());
731 tnode = tnode->parent();
734 std::reverse(key_buffer_out.begin(), key_buffer_out.end());
737 if(m_current_hash_node->parent() !=
nullptr) {
738 key_buffer_out.push_back(m_current_hash_node->child_of_char());
742 template<
bool P = IsPrefixIterator,
typename std::enable_if<!P>::type* =
nullptr>
743 void filter_prefix() {
746 template<
bool P = IsPrefixIterator,
typename std::enable_if<P>::type* =
nullptr>
747 void filter_prefix() {
748 tsl_ht_assert(m_array_hash_iterator != m_array_hash_end_iterator);
749 tsl_ht_assert(!m_read_trie_node_value && m_current_hash_node !=
nullptr);
751 if(m_prefix_filter.empty()) {
755 while((m_prefix_filter.size() > m_array_hash_iterator.key_size() ||
756 m_prefix_filter.compare(0, m_prefix_filter.size(),
757 m_array_hash_iterator.key(), m_prefix_filter.size()) != 0))
759 ++m_array_hash_iterator;
760 if(m_array_hash_iterator == m_array_hash_end_iterator) {
761 if(m_current_trie_node ==
nullptr) {
762 set_as_end_iterator();
766 set_next_node_ascending(*m_current_hash_node);
778 void set_next_node_ascending(anode_type& current_trie_node_child) {
780 tsl_ht_assert(current_trie_node_child.parent() == m_current_trie_node);
782 anode_type* next_node = m_current_trie_node->next_child(current_trie_node_child);
783 while(next_node ==
nullptr && m_current_trie_node->parent() !=
nullptr) {
784 anode_type* current_child = m_current_trie_node;
785 m_current_trie_node = m_current_trie_node->parent();
786 next_node = m_current_trie_node->next_child(*current_child);
790 if(next_node ==
nullptr) {
791 set_as_end_iterator();
794 set_most_left_descendant_as_next_node(*next_node);
798 void set_most_left_descendant_as_next_node(anode_type& search_start) {
799 if(search_start.is_hash_node()) {
800 set_current_hash_node(search_start.as_hash_node());
803 m_current_trie_node = &search_start.as_trie_node().most_left_descendant_value_trie_node();
804 if(m_current_trie_node->val_node() !=
nullptr) {
805 m_read_trie_node_value =
true;
808 anode_type* first_child = m_current_trie_node->first_child();
812 set_current_hash_node(first_child->as_hash_node());
817 void set_current_hash_node(hash_node_type& hnode) {
820 m_current_hash_node = &hnode;
821 m_array_hash_iterator = m_current_hash_node->array_hash().begin();
822 m_array_hash_end_iterator = m_current_hash_node->array_hash().end();
825 void set_as_end_iterator() {
826 m_current_trie_node =
nullptr;
827 m_current_hash_node =
nullptr;
828 m_read_trie_node_value =
false;
831 void skip_hash_node() {
832 tsl_ht_assert(!m_read_trie_node_value && m_current_hash_node !=
nullptr);
833 if(m_current_trie_node ==
nullptr) {
834 set_as_end_iterator();
838 set_next_node_ascending(*m_current_hash_node);
843 trie_node_type* m_current_trie_node;
844 hash_node_type* m_current_hash_node;
846 array_hash_iterator_type m_array_hash_iterator;
847 array_hash_iterator_type m_array_hash_end_iterator;
849 bool m_read_trie_node_value;
851 typename std::conditional<IsPrefixIterator, std::basic_string<CharT>,
bool>::type m_prefix_filter;
857 htrie_hash(
const Hash& hash,
float max_load_factor, size_type burst_threshold):
858 m_root(
nullptr), m_nb_elements(0),
859 m_hash(hash), m_max_load_factor(max_load_factor)
861 this->burst_threshold(burst_threshold);
865 m_hash(other.m_hash), m_max_load_factor(other.m_max_load_factor),
866 m_burst_threshold(other.m_burst_threshold)
868 if(other.m_root !=
nullptr) {
869 if(other.m_root->is_hash_node()) {
870 m_root.reset(
new hash_node(other.m_root->as_hash_node()));
873 m_root.reset(
new trie_node(other.m_root->as_trie_node()));
879 : m_root(std::move(other.m_root)),
880 m_nb_elements(other.m_nb_elements),
881 m_hash(std::move(other.m_hash)),
882 m_max_load_factor(other.m_max_load_factor),
883 m_burst_threshold(other.m_burst_threshold)
890 std::unique_ptr<anode> new_root =
nullptr;
891 if(other.m_root !=
nullptr) {
892 if(other.m_root->is_hash_node()) {
893 new_root.reset(
new hash_node(other.m_root->as_hash_node()));
896 new_root.reset(
new trie_node(other.m_root->as_trie_node()));
900 m_hash = other.m_hash;
901 m_root = std::move(new_root);
902 m_nb_elements = other.m_nb_elements;
903 m_max_load_factor = other.m_max_load_factor;
904 m_burst_threshold = other.m_burst_threshold;
921 return mutable_iterator(cbegin());
924 const_iterator
begin()
const noexcept {
933 return cbegin<const_iterator>(*m_root);
938 it.set_as_end_iterator();
943 const_iterator
end()
const noexcept {
947 const_iterator
cend()
const noexcept {
949 it.set_as_end_iterator();
959 return m_nb_elements == 0;
962 size_type
size()
const noexcept {
963 return m_nb_elements;
967 return std::numeric_limits<size_type>::max();
971 return array_hash_type::MAX_KEY_SIZE;
975 auto first = begin();
978 while(first != last) {
979 if(first.m_read_trie_node_value) {
988 hash_node* hnode = first.m_current_hash_node;
989 first.skip_hash_node();
992 hnode->array_hash().shrink_to_fit();
1002 m_root.reset(
nullptr);
1006 template<
class... ValueArgs>
1007 std::pair<iterator,
bool>
insert(
const CharT* key, size_type key_size, ValueArgs&&... value_args) {
1009 throw std::length_error(
"Key is too long.");
1012 if(m_root ==
nullptr) {
1013 m_root.reset(
new hash_node(m_hash, m_max_load_factor));
1016 return insert_impl(*m_root, key, key_size, std::forward<ValueArgs>(value_args)...);
1020 return erase(mutable_iterator(pos));
1023 iterator
erase(const_iterator first, const_iterator last) {
1025 const std::size_t nb_to_erase = std::size_t(std::distance(first, last));
1026 auto to_delete = mutable_iterator(first);
1027 for(std::size_t i = 0; i < nb_to_erase; i++) {
1028 to_delete = erase(to_delete);
1034 size_type
erase(
const CharT* key, size_type key_size) {
1035 auto it = find(key, key_size);
1047 if(m_root ==
nullptr) {
1051 anode* current_node = m_root.get();
1052 for(size_type iprefix = 0; iprefix < prefix_size; iprefix++) {
1053 if(current_node->is_trie_node()) {
1054 trie_node* tnode = ¤t_node->as_trie_node();
1056 if(tnode->child(prefix[iprefix]) ==
nullptr) {
1060 current_node = tnode->child(prefix[iprefix]).get();
1064 hash_node& hnode = current_node->as_hash_node();
1065 return erase_prefix_hash_node(hnode, prefix + iprefix, prefix_size - iprefix);
1070 if(current_node->is_trie_node()) {
1071 trie_node* parent = current_node->parent();
1073 if(parent !=
nullptr) {
1074 const size_type nb_erased = size_descendants(current_node->as_trie_node());
1076 parent->set_child(current_node->child_of_char(),
nullptr);
1077 m_nb_elements -= nb_erased;
1079 if(parent->empty()) {
1080 clear_empty_nodes(*parent);
1086 const size_type nb_erased = m_nb_elements;
1087 m_root.reset(
nullptr);
1094 const size_type nb_erased = current_node->as_hash_node().array_hash().size();
1096 current_node->as_hash_node().array_hash().clear();
1097 m_nb_elements -= nb_erased;
1099 clear_empty_nodes(current_node->as_hash_node());
1108 swap(m_hash, other.m_hash);
1109 swap(m_root, other.m_root);
1110 swap(m_nb_elements, other.m_nb_elements);
1111 swap(m_max_load_factor, other.m_max_load_factor);
1112 swap(m_burst_threshold, other.m_burst_threshold);
1118 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
1119 U&
at(
const CharT* key, size_type key_size) {
1120 return const_cast<U&>(
static_cast<
const htrie_hash*>(
this)->at(key, key_size));
1123 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
1124 const U&
at(
const CharT* key, size_type key_size)
const {
1125 auto it_find = find(key, key_size);
1126 if(it_find != cend()) {
1127 return it_find.value();
1130 throw std::out_of_range(
"Couldn't find key.");
1135 template<
class U = T,
typename std::enable_if<has_value<U>::value>::type* =
nullptr>
1137 auto it_find = find(key, key_size);
1138 if(it_find != cend()) {
1139 return it_find.value();
1142 return insert(key, key_size, U{}).first.value();
1146 size_type
count(
const CharT* key, size_type key_size)
const {
1147 if(find(key, key_size) != cend()) {
1155 iterator
find(
const CharT* key, size_type key_size) {
1156 if(m_root ==
nullptr) {
1160 return find_impl(*m_root, key, key_size);
1163 const_iterator
find(
const CharT* key, size_type key_size)
const {
1164 if(m_root ==
nullptr) {
1168 return find_impl(*m_root, key, key_size);
1171 std::pair<iterator, iterator>
equal_range(
const CharT* key, size_type key_size) {
1172 iterator it = find(key, key_size);
1173 return std::make_pair(it, (it == end())?it:std::next(it));
1176 std::pair<const_iterator, const_iterator>
equal_range(
const CharT* key, size_type key_size)
const {
1177 const_iterator it = find(key, key_size);
1178 return std::make_pair(it, (it == cend())?it:std::next(it));
1181 std::pair<prefix_iterator, prefix_iterator>
equal_prefix_range(
const CharT* prefix, size_type prefix_size) {
1182 if(m_root ==
nullptr) {
1183 return std::make_pair(prefix_end(), prefix_end());
1186 return equal_prefix_range_impl(*m_root, prefix, prefix_size);
1190 size_type prefix_size)
const 1192 if(m_root ==
nullptr) {
1193 return std::make_pair(prefix_cend(), prefix_cend());
1196 return equal_prefix_range_impl(*m_root, prefix, prefix_size);
1200 if(m_root ==
nullptr) {
1204 return longest_prefix_impl(*m_root, key, key_size);
1208 if(m_root ==
nullptr) {
1212 return longest_prefix_impl(*m_root, key, key_size);
1220 return m_max_load_factor;
1224 m_max_load_factor = ml;
1231 return m_burst_threshold;
1235 const size_type min_burst_threshold = MIN_BURST_THRESHOLD;
1236 m_burst_threshold = std::max(min_burst_threshold, threshold);
1249 template<
class Serializer>
1251 serialize_impl(serializer);
1254 template<
class Deserializer>
1256 deserialize_impl(deserializer, hash_compatible);
1263 template<
typename Iterator>
1264 Iterator cbegin(
const anode& search_start_node)
const noexcept {
1265 if(search_start_node.is_hash_node()) {
1266 return Iterator(search_start_node.as_hash_node());
1269 const trie_node& tnode = search_start_node.as_trie_node().most_left_descendant_value_trie_node();
1270 if(tnode.val_node() !=
nullptr) {
1271 return Iterator(tnode);
1274 const anode* first_child = tnode.first_child();
1277 return Iterator(first_child->as_hash_node());
1284 template<
typename Iterator>
1285 Iterator cend(
const anode& search_start_node)
const noexcept {
1286 if(search_start_node.parent() ==
nullptr) {
1288 it.set_as_end_iterator();
1293 const trie_node* current_trie_node = search_start_node.parent();
1294 const anode* next_node = current_trie_node->next_child(search_start_node);
1296 while(next_node ==
nullptr && current_trie_node->parent() !=
nullptr) {
1297 const anode* current_child = current_trie_node;
1298 current_trie_node = current_trie_node->parent();
1299 next_node = current_trie_node->next_child(*current_child);
1302 if(next_node ==
nullptr) {
1304 it.set_as_end_iterator();
1309 return cbegin<Iterator>(*next_node);
1313 prefix_iterator prefix_end()
noexcept {
1315 it.set_as_end_iterator();
1320 const_prefix_iterator prefix_cend()
const noexcept {
1321 const_prefix_iterator it;
1322 it.set_as_end_iterator();
1327 size_type size_descendants(
const anode& start_node)
const {
1328 auto first = cbegin<const_iterator>(start_node);
1329 auto last = cend<const_iterator>(start_node);
1331 size_type nb_elements = 0;
1332 while(first != last) {
1333 if(first.m_read_trie_node_value) {
1338 nb_elements += first.m_current_hash_node->array_hash().size();
1339 first.skip_hash_node();
1346 template<
class... ValueArgs>
1347 std::pair<iterator,
bool> insert_impl(anode& search_start_node,
1348 const CharT* key, size_type key_size, ValueArgs&&... value_args)
1350 anode* current_node = &search_start_node;
1352 for(size_type ikey = 0; ikey < key_size; ikey++) {
1353 if(current_node->is_trie_node()) {
1354 trie_node& tnode = current_node->as_trie_node();
1356 if(tnode.child(key[ikey]) !=
nullptr) {
1357 current_node = tnode.child(key[ikey]).get();
1360 std::unique_ptr<hash_node> hnode(
new hash_node(m_hash, m_max_load_factor));
1361 auto insert_it = hnode->array_hash().emplace_ks(key + ikey + 1, key_size - ikey - 1,
1362 std::forward<ValueArgs>(value_args)...);
1364 tnode.set_child(key[ikey], std::move(hnode));
1368 return std::make_pair(iterator(tnode.child(key[ikey])->as_hash_node(),
1369 insert_it.first),
true);
1373 return insert_in_hash_node(current_node->as_hash_node(),
1374 key + ikey, key_size - ikey, std::forward<ValueArgs>(value_args)...);
1379 if(current_node->is_trie_node()) {
1380 trie_node& tnode = current_node->as_trie_node();
1381 if(tnode.val_node() !=
nullptr) {
1382 return std::make_pair(iterator(tnode),
false);
1385 tnode.val_node().reset(
new value_node(std::forward<ValueArgs>(value_args)...));
1388 return std::make_pair(iterator(tnode),
true);
1392 return insert_in_hash_node(current_node->as_hash_node(),
1393 "", 0, std::forward<ValueArgs>(value_args)...);
1397 template<
class... ValueArgs>
1398 std::pair<iterator,
bool> insert_in_hash_node(hash_node& hnode,
1399 const CharT* key, size_type key_size, ValueArgs&&... value_args)
1401 if(need_burst(hnode)) {
1402 std::unique_ptr<trie_node> new_node = burst(hnode);
1403 if(hnode.parent() ==
nullptr) {
1406 m_root = std::move(new_node);
1407 return insert_impl(*m_root, key, key_size, std::forward<ValueArgs>(value_args)...);
1410 trie_node* parent = hnode.parent();
1411 const CharT child_of_char = hnode.child_of_char();
1413 parent->set_child(child_of_char, std::move(new_node));
1415 return insert_impl(*parent->child(child_of_char),
1416 key, key_size, std::forward<ValueArgs>(value_args)...);
1420 auto it_insert = hnode.array_hash().emplace_ks(key, key_size,
1421 std::forward<ValueArgs>(value_args)...);
1422 if(it_insert.second) {
1426 return std::make_pair(iterator(hnode, it_insert.first), it_insert.second);
1431 iterator erase(iterator pos) {
1432 iterator next_pos = std::next(pos);
1434 if(pos.m_read_trie_node_value) {
1435 tsl_ht_assert(pos.m_current_trie_node !=
nullptr && pos.m_current_trie_node->val_node() !=
nullptr);
1437 pos.m_current_trie_node->val_node().reset(
nullptr);
1440 if(pos.m_current_trie_node->empty()) {
1441 clear_empty_nodes(*pos.m_current_trie_node);
1448 auto next_array_hash_it = pos.m_current_hash_node->array_hash().erase(pos.m_array_hash_iterator);
1451 if(next_array_hash_it != pos.m_current_hash_node->array_hash().end()) {
1453 return iterator(*pos.m_current_hash_node, next_array_hash_it);
1456 if(pos.m_current_hash_node->array_hash().empty()) {
1457 clear_empty_nodes(*pos.m_current_hash_node);
1470 void clear_empty_nodes(anode& empty_node)
noexcept {
1472 (empty_node.as_trie_node().empty() && empty_node.as_trie_node().val_node() ==
nullptr));
1473 tsl_ht_assert(!empty_node.is_hash_node() || empty_node.as_hash_node().array_hash().empty());
1476 trie_node* parent = empty_node.parent();
1477 if(parent ==
nullptr) {
1480 m_root.reset(
nullptr);
1482 else if(parent->val_node() !=
nullptr || parent->nb_children() > 1) {
1483 parent->child(empty_node.child_of_char()).reset(
nullptr);
1485 else if(parent->parent() ==
nullptr) {
1488 m_root.reset(
nullptr);
1500 trie_node* grand_parent = parent->parent();
1501 grand_parent->set_child(parent->child_of_char(),
1502 std::move(parent->child(empty_node.child_of_char())));
1505 clear_empty_nodes(empty_node);
1512 iterator find_impl(
const anode& search_start_node,
const CharT* key, size_type key_size) {
1513 return mutable_iterator(
static_cast<
const htrie_hash*>(
this)->find_impl(search_start_node, key, key_size));
1516 const_iterator find_impl(
const anode& search_start_node,
const CharT* key, size_type key_size)
const {
1517 const anode* current_node = &search_start_node;
1519 for(size_type ikey = 0; ikey < key_size; ikey++) {
1520 if(current_node->is_trie_node()) {
1521 const trie_node* tnode = ¤t_node->as_trie_node();
1523 if(tnode->child(key[ikey]) ==
nullptr) {
1527 current_node = tnode->child(key[ikey]).get();
1531 return find_in_hash_node(current_node->as_hash_node(),
1532 key + ikey, key_size - ikey);
1537 if(current_node->is_trie_node()) {
1538 const trie_node& tnode = current_node->as_trie_node();
1539 return (tnode.val_node() !=
nullptr)?const_iterator(tnode):cend();
1542 return find_in_hash_node(current_node->as_hash_node(),
"", 0);
1546 const_iterator find_in_hash_node(
const hash_node& hnode,
1547 const CharT* key, size_type key_size)
const 1549 auto it = hnode.array_hash().find_ks(key, key_size);
1550 if(it != hnode.array_hash().end()) {
1551 return const_iterator(hnode, it);
1559 iterator longest_prefix_impl(
const anode& search_start_node,
1560 const CharT* value, size_type value_size)
1562 return mutable_iterator(
static_cast<
const htrie_hash*>(
this)->longest_prefix_impl(search_start_node,
1563 value, value_size));
1566 const_iterator longest_prefix_impl(
const anode& search_start_node,
1567 const CharT* value, size_type value_size)
const 1569 const anode* current_node = &search_start_node;
1570 const_iterator longest_found_prefix = cend();
1572 for(size_type ivalue = 0; ivalue < value_size; ivalue++) {
1573 if(current_node->is_trie_node()) {
1574 const trie_node& tnode = current_node->as_trie_node();
1576 if(tnode.val_node() !=
nullptr) {
1577 longest_found_prefix = const_iterator(tnode);
1580 if(tnode.child(value[ivalue]) ==
nullptr) {
1581 return longest_found_prefix;
1584 current_node = tnode.child(value[ivalue]).get();
1588 const hash_node& hnode = current_node->as_hash_node();
1595 for(std::size_t i = ivalue; i <= value_size; i++) {
1596 auto it = hnode.array_hash().find_ks(value + ivalue, (value_size - i));
1597 if(it != hnode.array_hash().end()) {
1598 return const_iterator(hnode, it);
1602 return longest_found_prefix;
1606 if(current_node->is_trie_node()) {
1607 const trie_node& tnode = current_node->as_trie_node();
1609 if(tnode.val_node() !=
nullptr) {
1610 longest_found_prefix = const_iterator(tnode);
1614 const hash_node& hnode = current_node->as_hash_node();
1616 auto it = hnode.array_hash().find_ks(
"", 0);
1617 if(it != hnode.array_hash().end()) {
1618 longest_found_prefix = const_iterator(hnode, it);
1622 return longest_found_prefix;
1626 std::pair<prefix_iterator, prefix_iterator> equal_prefix_range_impl(
1627 anode& search_start_node,
1628 const CharT* prefix, size_type prefix_size)
1630 auto range =
static_cast<
const htrie_hash*>(
this)->equal_prefix_range_impl(search_start_node,
1631 prefix, prefix_size);
1632 return std::make_pair(mutable_iterator(range.first), mutable_iterator(range.second));
1635 std::pair<const_prefix_iterator, const_prefix_iterator> equal_prefix_range_impl(
1636 const anode& search_start_node,
1637 const CharT* prefix, size_type prefix_size)
const 1639 const anode* current_node = &search_start_node;
1641 for(size_type iprefix = 0; iprefix < prefix_size; iprefix++) {
1642 if(current_node->is_trie_node()) {
1643 const trie_node* tnode = ¤t_node->as_trie_node();
1645 if(tnode->child(prefix[iprefix]) ==
nullptr) {
1646 return std::make_pair(prefix_cend(), prefix_cend());
1649 current_node = tnode->child(prefix[iprefix]).get();
1653 const hash_node& hnode = current_node->as_hash_node();
1654 const_prefix_iterator begin(hnode.parent(), &hnode,
1655 hnode.array_hash().begin(), hnode.array_hash().end(),
1656 false, std::basic_string<CharT>(prefix + iprefix, prefix_size - iprefix));
1657 begin.filter_prefix();
1659 const_prefix_iterator end = cend<const_prefix_iterator>(*current_node);
1661 return std::make_pair(begin, end);
1666 const_prefix_iterator begin = cbegin<const_prefix_iterator>(*current_node);
1667 const_prefix_iterator end = cend<const_prefix_iterator>(*current_node);
1669 return std::make_pair(begin, end);
1672 size_type erase_prefix_hash_node(hash_node& hnode,
const CharT* prefix, size_type prefix_size) {
1673 size_type nb_erased = 0;
1675 auto it = hnode.array_hash().begin();
1676 while(it != hnode.array_hash().end()) {
1677 if(it.key_size() >= prefix_size &&
1678 std::memcmp(prefix, it.key(), prefix_size *
sizeof(CharT)) == 0)
1680 it = hnode.array_hash().erase(it);
1696 bool need_burst(hash_node& node)
const {
1697 return node.array_hash().size() >= m_burst_threshold;
1706 template<
class U = T,
typename std::enable_if<has_value<U>::value &&
1707 std::is_copy_constructible<U>::value &&
1708 (!std::is_nothrow_move_constructible<U>::value ||
1709 !std::is_nothrow_move_assignable<U>::value ||
1710 std::is_arithmetic<U>::value ||
1711 std::is_pointer<U>::value)>::type* =
nullptr>
1712 std::unique_ptr<trie_node> burst(hash_node& node) {
1713 const std::array<size_type, ALPHABET_SIZE> first_char_count =
1714 get_first_char_count(node.array_hash().cbegin(),
1715 node.array_hash().cend());
1718 std::unique_ptr<trie_node> new_node(
new trie_node());
1719 for(
auto it = node.array_hash().cbegin(); it != node.array_hash().cend(); ++it) {
1720 if(it.key_size() == 0) {
1721 new_node->val_node().reset(
new value_node(it.value()));
1724 hash_node& hnode = get_hash_node_for_char(first_char_count, *new_node, it.key()[0]);
1725 hnode.array_hash().insert_ks(it.key() + 1, it.key_size() - 1, it.value());
1730 tsl_ht_assert(new_node->val_node() !=
nullptr || !new_node->empty());
1737 template<
class U = T,
typename std::enable_if<has_value<U>::value &&
1738 std::is_nothrow_move_constructible<U>::value &&
1739 std::is_nothrow_move_assignable<U>::value &&
1740 !std::is_arithmetic<U>::value &&
1741 !std::is_pointer<U>::value>::type* =
nullptr>
1742 std::unique_ptr<trie_node> burst(hash_node& node) {
1748 std::vector<T*> moved_values_rollback;
1749 moved_values_rollback.reserve(node.array_hash().size());
1752 const std::array<size_type, ALPHABET_SIZE> first_char_count =
1753 get_first_char_count(node.array_hash().cbegin(), node.array_hash().cend());
1756 std::unique_ptr<trie_node> new_node(
new trie_node());
1757 for(
auto it = node.array_hash().begin(); it != node.array_hash().end(); ++it) {
1758 if(it.key_size() == 0) {
1759 new_node->val_node().reset(
new value_node(std::move(it.value())));
1760 moved_values_rollback.push_back(std::addressof(new_node->val_node()->m_value));
1763 hash_node& hnode = get_hash_node_for_char(first_char_count, *new_node, it.key()[0]);
1764 auto it_insert = hnode.array_hash().insert_ks(it.key() + 1, it.key_size() - 1,
1765 std::move(it.value()));
1766 moved_values_rollback.push_back(std::addressof(it_insert.first.value()));
1771 tsl_ht_assert(new_node->val_node() !=
nullptr || !new_node->empty());
1776 auto it = node.array_hash().begin();
1777 for(std::size_t ivalue = 0; ivalue < moved_values_rollback.size(); ivalue++) {
1778 it.value() = std::move(*moved_values_rollback[ivalue]);
1787 template<
class U = T,
typename std::enable_if<!has_value<U>::value>::type* =
nullptr>
1788 std::unique_ptr<trie_node> burst(hash_node& node) {
1789 const std::array<size_type, ALPHABET_SIZE> first_char_count =
1790 get_first_char_count(node.array_hash().begin(), node.array_hash().end());
1793 std::unique_ptr<trie_node> new_node(
new trie_node());
1794 for(
auto it = node.array_hash().cbegin(); it != node.array_hash().cend(); ++it) {
1795 if(it.key_size() == 0) {
1796 new_node->val_node().reset(
new value_node());
1799 hash_node& hnode = get_hash_node_for_char(first_char_count, *new_node, it.key()[0]);
1800 hnode.array_hash().insert_ks(it.key() + 1, it.key_size() - 1);
1805 tsl_ht_assert(new_node->val_node() !=
nullptr || !new_node->empty());
1809 std::array<size_type, ALPHABET_SIZE> get_first_char_count(
typename array_hash_type::const_iterator begin,
1810 typename array_hash_type::const_iterator end)
const 1812 std::array<size_type, ALPHABET_SIZE> count{{}};
1813 for(
auto it = begin; it != end; ++it) {
1814 if(it.key_size() == 0) {
1818 count[as_position(it.key()[0])]++;
1825 hash_node& get_hash_node_for_char(
const std::array<size_type, ALPHABET_SIZE>& first_char_count,
1826 trie_node& tnode, CharT for_char)
1828 if(tnode.child(for_char) ==
nullptr) {
1829 const size_type nb_buckets =
1831 std::ceil(
float(first_char_count[as_position(for_char)] +
1832 HASH_NODE_DEFAULT_INIT_BUCKETS_COUNT/2)
1836 tnode.set_child(for_char, std::unique_ptr<hash_node>(
1837 new hash_node(nb_buckets, m_hash, m_max_load_factor)));
1840 return tnode.child(for_char)->as_hash_node();
1843 iterator mutable_iterator(const_iterator it)
noexcept {
1845 if(it.m_current_hash_node ==
nullptr || it.m_read_trie_node_value) {
1846 typename array_hash_type::iterator default_it;
1848 return iterator(
const_cast<trie_node*>(it.m_current_trie_node),
nullptr,
1849 default_it, default_it, it.m_read_trie_node_value);
1852 hash_node* hnode =
const_cast<hash_node*>(it.m_current_hash_node);
1853 return iterator(
const_cast<trie_node*>(it.m_current_trie_node), hnode,
1854 hnode->array_hash().mutable_iterator(it.m_array_hash_iterator),
1855 hnode->array_hash().mutable_iterator(it.m_array_hash_end_iterator),
1856 it.m_read_trie_node_value);
1860 prefix_iterator mutable_iterator(const_prefix_iterator it)
noexcept {
1862 if(it.m_current_hash_node ==
nullptr || it.m_read_trie_node_value) {
1863 typename array_hash_type::iterator default_it;
1865 return prefix_iterator(
const_cast<trie_node*>(it.m_current_trie_node),
nullptr,
1866 default_it, default_it, it.m_read_trie_node_value,
"");
1869 hash_node* hnode =
const_cast<hash_node*>(it.m_current_hash_node);
1870 return prefix_iterator(
const_cast<trie_node*>(it.m_current_trie_node), hnode,
1871 hnode->array_hash().mutable_iterator(it.m_array_hash_iterator),
1872 hnode->array_hash().mutable_iterator(it.m_array_hash_end_iterator),
1873 it.m_read_trie_node_value, it.m_prefix_filter);
1877 template<
class Serializer>
1878 void serialize_impl(Serializer& serializer)
const {
1879 const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION;
1880 serializer(version);
1882 const slz_size_type nb_elements = m_nb_elements;
1883 serializer(nb_elements);
1885 const float max_load_factor = m_max_load_factor;
1886 serializer(max_load_factor);
1888 const slz_size_type burst_threshold = m_burst_threshold;
1889 serializer(burst_threshold);
1892 std::basic_string<CharT> str_buffer;
1899 if(it.m_read_trie_node_value) {
1900 const CharT node_type =
static_cast<
typename std::underlying_type<slz_node_type>::type>(slz_node_type::TRIE_NODE);
1901 serializer(&node_type, 1);
1905 const slz_size_type str_size = str_buffer.size();
1906 serializer(str_size);
1907 serializer(str_buffer.data(), str_buffer.size());
1908 serialize_value(serializer, it);
1915 const CharT node_type =
static_cast<
typename std::underlying_type<slz_node_type>::type>(slz_node_type::HASH_NODE);
1916 serializer(&node_type, 1);
1918 it.hash_node_prefix(str_buffer);
1920 const slz_size_type str_size = str_buffer.size();
1921 serializer(str_size);
1922 serializer(str_buffer.data(), str_buffer.size());
1924 const hash_node* hnode = it.m_current_hash_node;
1926 hnode->array_hash().serialize(serializer);
1929 it.skip_hash_node();
1934 template<
class Serializer,
class U = T,
1935 typename std::enable_if<!has_value<U>::value>::type* =
nullptr>
1936 void serialize_value(Serializer& , const_iterator )
const {
1939 template<
class Serializer,
class U = T,
1940 typename std::enable_if<has_value<U>::value>::type* =
nullptr>
1941 void serialize_value(Serializer& serializer, const_iterator it)
const {
1942 serializer(it.value());
1945 template<
class Deserializer>
1946 void deserialize_impl(Deserializer& deserializer,
bool hash_compatible) {
1949 const slz_size_type version = deserialize_value<slz_size_type>(deserializer);
1952 if(version != SERIALIZATION_PROTOCOL_VERSION) {
1953 throw std::runtime_error(
"Can't deserialize the htrie_map/set. The protocol version header is invalid.");
1957 const slz_size_type nb_elements = deserialize_value<slz_size_type>(deserializer);
1958 const float max_load_factor = deserialize_value<
float>(deserializer);
1959 const slz_size_type burst_threshold = deserialize_value<slz_size_type>(deserializer);
1961 this->burst_threshold(numeric_cast<std::size_t>(burst_threshold,
"Deserialized burst_threshold is too big."));
1962 this->max_load_factor(max_load_factor);
1965 std::vector<CharT> str_buffer;
1966 while(m_nb_elements < nb_elements) {
1967 CharT node_type_marker;
1968 deserializer(&node_type_marker, 1);
1970 static_assert(std::is_same<CharT,
typename std::underlying_type<slz_node_type>::type>::value,
"");
1971 const slz_node_type node_type =
static_cast<slz_node_type>(node_type_marker);
1972 if(node_type == slz_node_type::TRIE_NODE) {
1973 const std::size_t str_size = numeric_cast<std::size_t>(deserialize_value<slz_size_type>(deserializer),
1974 "Deserialized str_size is too big.");
1976 str_buffer.resize(str_size);
1977 deserializer(str_buffer.data(), str_size);
1980 trie_node* current_node = insert_prefix_trie_nodes(str_buffer.data(), str_size);
1981 deserialize_value_node(deserializer, current_node);
1984 else if(node_type == slz_node_type::HASH_NODE) {
1985 const std::size_t str_size = numeric_cast<std::size_t>(deserialize_value<slz_size_type>(deserializer),
1986 "Deserialized str_size is too big.");
1991 m_root.reset(
new hash_node(array_hash_type::deserialize(deserializer, hash_compatible)));
1992 m_nb_elements += m_root->as_hash_node().array_hash().size();
1997 str_buffer.resize(str_size);
1998 deserializer(str_buffer.data(), str_size);
2001 std::unique_ptr<hash_node> hnode(
new hash_node(array_hash_type::deserialize(deserializer, hash_compatible)));
2002 m_nb_elements += hnode->array_hash().size();
2004 trie_node* current_node = insert_prefix_trie_nodes(str_buffer.data(), str_size - 1);
2005 current_node->set_child(str_buffer[str_size - 1], std::move(hnode));
2009 throw std::runtime_error(
"Unknown deserialized node type.");
2016 trie_node* insert_prefix_trie_nodes(
const CharT* prefix, std::size_t prefix_size) {
2017 if(m_root ==
nullptr) {
2018 m_root.reset(
new trie_node());
2021 trie_node* current_node = &m_root->as_trie_node();
2022 for(std::size_t iprefix = 0; iprefix < prefix_size; iprefix++) {
2023 if(current_node->child(prefix[iprefix]) ==
nullptr) {
2024 current_node->set_child(prefix[iprefix], std::unique_ptr<trie_node>(
new trie_node()));
2027 current_node = ¤t_node->child(prefix[iprefix])->as_trie_node();
2030 return current_node;
2033 template<
class Deserializer,
class U = T,
2034 typename std::enable_if<!has_value<U>::value>::type* =
nullptr>
2035 void deserialize_value_node(Deserializer& , trie_node* current_node) {
2037 current_node->val_node().reset(
new value_node());
2040 template<
class Deserializer,
class U = T,
2041 typename std::enable_if<has_value<U>::value>::type* =
nullptr>
2042 void deserialize_value_node(Deserializer& deserializer, trie_node* current_node) {
2044 current_node->val_node().reset(
new value_node(deserialize_value<T>(deserializer)));
2047 template<
class U,
class Deserializer>
2048 static U deserialize_value(Deserializer& deserializer) {
2050 #if defined (_MSC_VER) && _MSC_VER < 1910
2051 return deserializer.Deserializer::operator()<U>();
2053 return deserializer.Deserializer::
template operator()<U>();
2067 using slz_size_type = std::uint64_t;
2068 enum class slz_node_type: CharT { TRIE_NODE = 0, HASH_NODE = 1 };
2073 static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1;
2075 static const size_type HASH_NODE_DEFAULT_INIT_BUCKETS_COUNT = 32;
2076 static const size_type MIN_BURST_THRESHOLD = 4;
2078 std::unique_ptr<anode> m_root;
2079 size_type m_nb_elements;
2081 float m_max_load_factor;
2082 size_type m_burst_threshold;
static const size_type DEFAULT_BURST_THRESHOLD
Definition: htrie_hash.h:2059
htrie_hash & operator=(const htrie_hash &other)
Definition: htrie_hash.h:888
const U & at(const CharT *key, size_type key_size) const
Definition: htrie_hash.h:1124
void swap(htrie_hash &other)
Definition: htrie_hash.h:1105
htrie_hash_iterator(const htrie_hash_iterator< false, false > &other) noexcept
Definition: htrie_hash.h:582
const_iterator cbegin() const noexcept
Definition: htrie_hash.h:928
static constexpr float HASH_NODE_DEFAULT_MAX_LOAD_FACTOR
Definition: htrie_hash.h:2058
size_type erase_prefix(const CharT *prefix, size_type prefix_size)
Definition: htrie_hash.h:1046
Definition: htrie_hash.h:68
htrie_hash_iterator operator++(int)
Definition: htrie_hash.h:689
friend bool operator==(const htrie_hash_iterator &lhs, const htrie_hash_iterator &rhs)
Definition: htrie_hash.h:696
float max_load_factor() const
Definition: htrie_hash.h:1219
htrie_hash(const Hash &hash, float max_load_factor, size_type burst_threshold)
Definition: htrie_hash.h:857
htrie_hash(htrie_hash &&other) noexcept(std::is_nothrow_move_constructible< Hash >::value)
Definition: htrie_hash.h:878
pointer operator->() const
Definition: htrie_hash.h:646
size_type count(const CharT *key, size_type key_size) const
Definition: htrie_hash.h:1146
iterator erase(const_iterator first, const_iterator last)
Definition: htrie_hash.h:1023
htrie_hash(const htrie_hash &other)
Definition: htrie_hash.h:864
iterator end() noexcept
Definition: htrie_hash.h:936
hasher hash_function() const
Definition: htrie_hash.h:1242
htrie_hash & operator=(htrie_hash &&other)
Definition: htrie_hash.h:910
friend bool operator!=(const htrie_hash_iterator &lhs, const htrie_hash_iterator &rhs)
Definition: htrie_hash.h:719
iterator longest_prefix(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1199
void max_load_factor(float ml)
Definition: htrie_hash.h:1223
U & access_operator(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1136
std::basic_string< CharT > key() const
Definition: htrie_hash.h:620
iterator erase(const_iterator pos)
Definition: htrie_hash.h:1019
size_type erase(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1034
reference value() const
Definition: htrie_hash.h:628
htrie_hash_iterator(const htrie_hash_iterator< false, true > &other) noexcept
Definition: htrie_hash.h:591
void serialize(Serializer &serializer) const
Definition: htrie_hash.h:1250
size_type size() const noexcept
Definition: htrie_hash.h:962
void deserialize(Deserializer &deserializer, bool hash_compatible)
Definition: htrie_hash.h:1255
bool empty() const noexcept
Definition: htrie_hash.h:958
htrie_hash_iterator & operator++()
Definition: htrie_hash.h:650
U & at(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1119
htrie_hash_iterator() noexcept
Definition: htrie_hash.h:578
std::pair< prefix_iterator, prefix_iterator > equal_prefix_range(const CharT *prefix, size_type prefix_size)
Definition: htrie_hash.h:1181
const_iterator find(const CharT *key, size_type key_size) const
Definition: htrie_hash.h:1163
std::pair< iterator, bool > insert(const CharT *key, size_type key_size, ValueArgs &&... value_args)
Definition: htrie_hash.h:1007
iterator begin() noexcept
Definition: htrie_hash.h:920
void clear() noexcept
Definition: htrie_hash.h:1001
std::pair< iterator, iterator > equal_range(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1171
size_type max_key_size() const noexcept
Definition: htrie_hash.h:970
reference operator*() const
Definition: htrie_hash.h:641
size_type burst_threshold() const
Definition: htrie_hash.h:1230
Definition: htrie_hash.h:73
#define tsl_ht_assert(expr)
Definition: htrie_hash.h:64
void burst_threshold(size_type threshold)
Definition: htrie_hash.h:1234
void key(std::basic_string< CharT > &key_buffer_out) const
Definition: htrie_hash.h:599
const_iterator longest_prefix(const CharT *key, size_type key_size) const
Definition: htrie_hash.h:1207
const_iterator end() const noexcept
Definition: htrie_hash.h:943
Definition: htrie_hash.h:130
friend class htrie_hash
Definition: htrie_hash.h:499
std::pair< const_iterator, const_iterator > equal_range(const CharT *key, size_type key_size) const
Definition: htrie_hash.h:1176
void shrink_to_fit()
Definition: htrie_hash.h:974
Definition: htrie_hash.h:70
iterator find(const CharT *key, size_type key_size)
Definition: htrie_hash.h:1155
const_iterator cend() const noexcept
Definition: htrie_hash.h:947
std::pair< const_prefix_iterator, const_prefix_iterator > equal_prefix_range(const CharT *prefix, size_type prefix_size) const
Definition: htrie_hash.h:1189
size_type max_size() const noexcept
Definition: htrie_hash.h:966
const_iterator begin() const noexcept
Definition: htrie_hash.h:924