You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unordered_map.h 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Frozen
  3. * Copyright 2016 QuarksLab
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. */
  22. #ifndef FROZEN_LETITGO_UNORDERED_MAP_H
  23. #define FROZEN_LETITGO_UNORDERED_MAP_H
  24. #include "frozen/bits/basic_types.h"
  25. #include "frozen/bits/constexpr_assert.h"
  26. #include "frozen/bits/elsa.h"
  27. #include "frozen/bits/exceptions.h"
  28. #include "frozen/bits/pmh.h"
  29. #include "frozen/bits/version.h"
  30. #include "frozen/random.h"
  31. #include <tuple>
  32. #include <functional>
  33. namespace frozen {
  34. namespace bits {
  35. struct GetKey {
  36. template <class KV> constexpr auto const &operator()(KV const &kv) const {
  37. return kv.first;
  38. }
  39. };
  40. } // namespace bits
  41. template <class Key, class Value, std::size_t N, typename Hash = anna<Key>,
  42. class KeyEqual = std::equal_to<Key>>
  43. class unordered_map {
  44. static constexpr std::size_t storage_size =
  45. bits::next_highest_power_of_two(N) * (N < 32 ? 2 : 1); // size adjustment to prevent high collision rate for small sets
  46. using container_type = bits::carray<std::pair<Key, Value>, N>;
  47. using tables_type = bits::pmh_tables<storage_size, Hash>;
  48. KeyEqual const equal_;
  49. container_type items_;
  50. tables_type tables_;
  51. public:
  52. /* typedefs */
  53. using Self = unordered_map<Key, Value, N, Hash, KeyEqual>;
  54. using key_type = Key;
  55. using mapped_type = Value;
  56. using value_type = typename container_type::value_type;
  57. using size_type = typename container_type::size_type;
  58. using difference_type = typename container_type::difference_type;
  59. using hasher = Hash;
  60. using key_equal = KeyEqual;
  61. using reference = typename container_type::reference;
  62. using const_reference = typename container_type::const_reference;
  63. using pointer = typename container_type::pointer;
  64. using const_pointer = typename container_type::const_pointer;
  65. using iterator = typename container_type::iterator;
  66. using const_iterator = typename container_type::const_iterator;
  67. public:
  68. /* constructors */
  69. unordered_map(unordered_map const &) = default;
  70. constexpr unordered_map(container_type items,
  71. Hash const &hash, KeyEqual const &equal)
  72. : equal_{equal}
  73. , items_{items}
  74. , tables_{
  75. bits::make_pmh_tables<storage_size>(
  76. items_, hash, bits::GetKey{}, default_prg_t{})} {}
  77. explicit constexpr unordered_map(container_type items)
  78. : unordered_map{items, Hash{}, KeyEqual{}} {}
  79. constexpr unordered_map(std::initializer_list<value_type> items,
  80. Hash const & hash, KeyEqual const & equal)
  81. : unordered_map{container_type{items}, hash, equal} {
  82. constexpr_assert(items.size() == N, "Inconsistent initializer_list size and type size argument");
  83. }
  84. constexpr unordered_map(std::initializer_list<value_type> items)
  85. : unordered_map{items, Hash{}, KeyEqual{}} {}
  86. /* iterators */
  87. constexpr iterator begin() { return items_.begin(); }
  88. constexpr iterator end() { return items_.end(); }
  89. constexpr const_iterator begin() const { return items_.begin(); }
  90. constexpr const_iterator end() const { return items_.end(); }
  91. constexpr const_iterator cbegin() const { return items_.cbegin(); }
  92. constexpr const_iterator cend() const { return items_.cend(); }
  93. /* capacity */
  94. constexpr bool empty() const { return !N; }
  95. constexpr size_type size() const { return N; }
  96. constexpr size_type max_size() const { return N; }
  97. /* lookup */
  98. constexpr std::size_t count(Key const &key) const {
  99. auto const &kv = lookup(key);
  100. return equal_(kv.first, key);
  101. }
  102. constexpr Value const &at(Key const &key) const {
  103. return at_impl(*this, key);
  104. }
  105. constexpr Value &at(Key const &key) {
  106. return at_impl(*this, key);
  107. }
  108. constexpr const_iterator find(Key const &key) const {
  109. return find_impl(*this, key);
  110. }
  111. constexpr iterator find(Key const &key) {
  112. return find_impl(*this, key);
  113. }
  114. constexpr std::pair<const_iterator, const_iterator> equal_range(Key const &key) const {
  115. return equal_range_impl(*this, key);
  116. }
  117. constexpr std::pair<iterator, iterator> equal_range(Key const &key) {
  118. return equal_range_impl(*this, key);
  119. }
  120. /* bucket interface */
  121. constexpr std::size_t bucket_count() const { return storage_size; }
  122. constexpr std::size_t max_bucket_count() const { return storage_size; }
  123. /* observers*/
  124. constexpr hasher hash_function() const { return tables_.hash_; }
  125. constexpr key_equal key_eq() const { return equal_; }
  126. private:
  127. template <class This>
  128. static inline constexpr auto& at_impl(This&& self, Key const &key) {
  129. auto& kv = self.lookup(key);
  130. if (self.equal_(kv.first, key))
  131. return kv.second;
  132. else
  133. FROZEN_THROW_OR_ABORT(std::out_of_range("unknown key"));
  134. }
  135. template <class This>
  136. static inline constexpr auto find_impl(This&& self, Key const &key) {
  137. auto& kv = self.lookup(key);
  138. if (self.equal_(kv.first, key))
  139. return &kv;
  140. else
  141. return self.items_.end();
  142. }
  143. template <class This>
  144. static inline constexpr auto equal_range_impl(This&& self, Key const &key) {
  145. auto& kv = self.lookup(key);
  146. using kv_ptr = decltype(&kv);
  147. if (self.equal_(kv.first, key))
  148. return std::pair<kv_ptr, kv_ptr>{&kv, &kv + 1};
  149. else
  150. return std::pair<kv_ptr, kv_ptr>{self.items_.end(), self.items_.end()};
  151. }
  152. template <class This>
  153. static inline constexpr auto& lookup_impl(This&& self, Key const &key) {
  154. return self.items_[self.tables_.lookup(key)];
  155. }
  156. constexpr auto const& lookup(Key const &key) const {
  157. return lookup_impl(*this, key);
  158. }
  159. constexpr auto& lookup(Key const &key) {
  160. return lookup_impl(*this, key);
  161. }
  162. };
  163. template <typename T, typename U, std::size_t N>
  164. constexpr auto make_unordered_map(std::pair<T, U> const (&items)[N]) {
  165. return unordered_map<T, U, N>{items};
  166. }
  167. } // namespace frozen
  168. #endif