MySQL  8.0.27
Source Code Documentation
map_helpers.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, 2021, Oracle and/or its affiliates.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License, version 2.0,
5  as published by the Free Software Foundation.
6 
7  This program is also distributed with certain software (including
8  but not limited to OpenSSL) that is licensed under separate terms,
9  as designated in a particular file or component or in included license
10  documentation. The authors of MySQL hereby grant you an additional
11  permission to link the program and your derivative works with the
12  separately licensed software that they have included with MySQL.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License, version 2.0, for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22 
23 #ifndef MAP_HELPERS_INCLUDED
24 #define MAP_HELPERS_INCLUDED
25 
26 #include <map>
27 #include <memory>
28 #include <string>
29 #include <type_traits>
30 #include <unordered_map>
31 #include <unordered_set>
32 #include <utility>
33 
34 #include "m_ctype.h"
35 #include "my_inttypes.h"
36 #include "sql/malloc_allocator.h"
37 #include "sql/mem_root_allocator.h"
38 #include "template_utils.h"
39 
40 /**
41  Some useful helpers for associative arrays with MySQL-specific semantics.
42 */
43 
44 /**
45  For unordered_map<Key, T*> or unordered_map<Key, unique_ptr<T>>, does
46  find() and returns nullptr if the element was not found.
47 
48  It is not possible to distinguish between "not found" and "found, but
49  contained nullptr" in this case. Thus, you should normally prefer checking
50  against container.end() yourself.
51 */
52 template <class Container, class Key>
53 static inline auto find_or_nullptr(const Container &container, const Key &key) {
54  const auto it = container.find(key);
55  if constexpr (std::is_pointer_v<typename Container::mapped_type>) {
56  return it == container.end() ? nullptr : it->second;
57  } else {
58  return it == container.end() ? nullptr : it->second.get();
59  }
60 }
61 
62 /**
63  For unordered_multimap<Key, Value>, erase the first specific element that
64  matches _both_ the given key and value.
65 */
66 template <class Container, class Value>
67 typename Container::iterator erase_specific_element(
68  Container *container, const typename Container::key_type &key,
69  const Value &value) {
70  auto it_range = container->equal_range(key);
71  for (auto it = it_range.first; it != it_range.second; ++it) {
72  if constexpr (std::is_pointer_v<typename Container::mapped_type>) {
73  if (it->second == value) return container->erase(it);
74  } else {
75  // For when the container holds unique_ptr elements.
76  if (it->second.get() == value) return container->erase(it);
77  }
78  }
79  return container->end();
80 }
81 /**
82  std::unique_ptr, but with a custom delete function.
83  Normally, it is more efficient to have a deleter class instead,
84  but this allows you to have a unique_ptr to a forward-declared class,
85  so it keeps include dependencies down somewhat.
86 */
87 template <class T>
88 using unique_ptr_with_deleter = std::unique_ptr<T, void (*)(T *)>;
89 
91  void operator()(void *ptr) const { my_free(ptr); }
92 };
93 
94 /** std::unique_ptr, but with my_free as deleter. */
95 template <class T>
96 using unique_ptr_my_free = std::unique_ptr<T, My_free_deleter>;
97 
98 struct Free_deleter {
99  void operator()(void *ptr) const { free(ptr); }
100 };
101 
102 /** std::unique_ptr, but with free as deleter. */
103 template <class T>
104 using unique_ptr_free = std::unique_ptr<T, Free_deleter>;
105 
106 /** A Hasher that hashes std::strings according to a MySQL collation. */
108  public:
109  explicit Collation_hasher(const CHARSET_INFO *cs_arg)
110  : cs(cs_arg), hash_sort(cs->coll->hash_sort) {}
111 
112  size_t operator()(const std::string &s) const {
113  uint64 nr1 = 1, nr2 = 4;
114  hash_sort(cs, pointer_cast<const uchar *>(s.data()), s.size(), &nr1, &nr2);
115  return nr1;
116  }
117 
118  private:
119  const CHARSET_INFO *cs;
120  decltype(cs->coll->hash_sort) hash_sort;
121 };
122 
123 /** A KeyEqual that compares std::strings according to a MySQL collation. */
125  public:
126  explicit Collation_key_equal(const CHARSET_INFO *cs_arg)
127  : cs(cs_arg), strnncollsp(cs->coll->strnncollsp) {}
128 
129  size_t operator()(const std::string &a, const std::string &b) const {
130  return strnncollsp(cs, pointer_cast<const uchar *>(a.data()), a.size(),
131  pointer_cast<const uchar *>(b.data()), b.size()) == 0;
132  }
133 
134  private:
135  const CHARSET_INFO *cs;
136  decltype(cs->coll->strnncollsp) strnncollsp;
137 };
138 
139 /**
140  std::unordered_map, but with my_malloc, so that you can track the memory
141  used using PSI memory keys.
142 */
143 template <class Key, class Value, class Hash = std::hash<Key>,
144  class KeyEqual = std::equal_to<Key>>
146  : public std::unordered_map<Key, Value, Hash, KeyEqual,
147  Malloc_allocator<std::pair<const Key, Value>>> {
148  public:
149  /*
150  In theory, we should be allowed to send in the allocator only, but GCC 4.8
151  is missing several unordered_map constructors, so let's give in everything.
152  */
154  : std::unordered_map<Key, Value, Hash, KeyEqual,
155  Malloc_allocator<std::pair<const Key, Value>>>(
156  /*bucket_count=*/10, Hash(), KeyEqual(),
157  Malloc_allocator<>(psi_key)) {}
158 };
159 
160 /**
161  std::unordered_set, but with my_malloc, so that you can track the memory
162  used using PSI memory keys.
163 */
164 template <class Key, class Hash = std::hash<Key>,
165  class KeyEqual = std::equal_to<Key>>
167  : public std::unordered_set<Key, Hash, KeyEqual, Malloc_allocator<Key>> {
168  public:
169  /*
170  In theory, we should be allowed to send in the allocator only, but GCC 4.8
171  is missing several unordered_set constructors, so let's give in everything.
172  */
174  : std::unordered_set<Key, Hash, KeyEqual, Malloc_allocator<Key>>(
175  /*bucket_count=*/10, Hash(), KeyEqual(),
176  Malloc_allocator<>(psi_key)) {}
177 };
178 
179 /**
180  std::unordered_multimap, but with my_malloc, so that you can track the memory
181  used using PSI memory keys.
182 */
183 template <class Key, class Value, class Hash = std::hash<Key>,
184  class KeyEqual = std::equal_to<Key>>
186  : public std::unordered_multimap<
187  Key, Value, Hash, KeyEqual,
188  Malloc_allocator<std::pair<const Key, Value>>> {
189  public:
190  /*
191  In theory, we should be allowed to send in the allocator only, but GCC 4.8
192  is missing several unordered_multimap constructors, so let's give in
193  everything.
194  */
196  : std::unordered_multimap<Key, Value, Hash, KeyEqual,
197  Malloc_allocator<std::pair<const Key, Value>>>(
198  /*bucket_count=*/10, Hash(), KeyEqual(),
199  Malloc_allocator<>(psi_key)) {}
200 };
201 
202 /**
203  std::unordered_map, but with my_malloc and collation-aware comparison.
204 */
205 template <class Key, class Value>
207  : public std::unordered_map<Key, Value, Collation_hasher,
208  Collation_key_equal,
209  Malloc_allocator<std::pair<const Key, Value>>> {
210  public:
212  : std::unordered_map<Key, Value, Collation_hasher, Collation_key_equal,
213  Malloc_allocator<std::pair<const Key, Value>>>(
214  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
215  Malloc_allocator<>(psi_key)) {}
216 };
217 
218 /**
219  std::unordered_multimap, but with my_malloc and collation-aware comparison.
220 */
221 template <class Key, class Value>
223  : public std::unordered_multimap<
224  Key, Value, Collation_hasher, Collation_key_equal,
225  Malloc_allocator<std::pair<const Key, Value>>> {
226  public:
228  : std::unordered_multimap<Key, Value, Collation_hasher,
230  Malloc_allocator<std::pair<const Key, Value>>>(
231  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
232  Malloc_allocator<>(psi_key)) {}
233 };
234 
235 /**
236  std::unordered_set, but with my_malloc and collation-aware comparison.
237 */
238 template <class Key>
240  : public std::unordered_set<Key, Collation_hasher, Collation_key_equal,
241  Malloc_allocator<Key>> {
242  public:
246  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
247  Malloc_allocator<>(psi_key)) {}
248  collation_unordered_set(std::initializer_list<Key> il, CHARSET_INFO *cs,
249  PSI_memory_key psi_key)
252  il, /*bucket_count=*/10, Collation_hasher(cs),
253  Collation_key_equal(cs), Malloc_allocator<>(psi_key)) {}
254 };
255 
256 /** std::unordered_set, but allocated on a MEM_ROOT. */
257 template <class Key, class Hash = std::hash<Key>,
258  class KeyEqual = std::equal_to<Key>>
260  : public std::unordered_set<Key, Hash, KeyEqual, Mem_root_allocator<Key>> {
261  public:
262  /*
263  In theory, we should be allowed to send in the allocator only, but GCC 4.8
264  is missing several unordered_set constructors, so let's give in everything.
265  */
267  : std::unordered_set<Key, Hash, KeyEqual, Mem_root_allocator<Key>>(
268  /*bucket_count=*/10, Hash(), KeyEqual(),
270 };
271 
272 /**
273  std::unordered_map, but allocated on a MEM_ROOT.
274 */
275 template <class Key, class Value, class Hash = std::hash<Key>,
276  class KeyEqual = std::equal_to<Key>>
278  : public std::unordered_map<
279  Key, Value, Hash, KeyEqual,
280  Mem_root_allocator<std::pair<const Key, Value>>> {
281  public:
282  explicit mem_root_unordered_map(MEM_ROOT *mem_root, Hash hash = Hash())
283  : std::unordered_map<Key, Value, Hash, KeyEqual,
284  Mem_root_allocator<std::pair<const Key, Value>>>(
285  /*bucket_count=*/10, hash, KeyEqual(),
286  Mem_root_allocator<std::pair<const Key, Value>>(mem_root)) {}
287 };
288 
289 /**
290  std::unordered_map, but collation aware and allocated on a MEM_ROOT.
291 */
292 template <class Key, class Value>
294  : public std::unordered_map<
295  Key, Value, Collation_hasher, Collation_key_equal,
296  Mem_root_allocator<std::pair<const Key, Value>>> {
297  public:
299  : std::unordered_map<Key, Value, Collation_hasher, Collation_key_equal,
300  Mem_root_allocator<std::pair<const Key, Value>>>(
301  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
302  Mem_root_allocator<std::pair<const Key, Value>>(mem_root)) {}
303 };
304 
305 #endif // MAP_HELPERS_INCLUDED
A Hasher that hashes std::strings according to a MySQL collation.
Definition: map_helpers.h:107
decltype(cs->coll->hash_sort) hash_sort
Definition: map_helpers.h:120
Collation_hasher(const CHARSET_INFO *cs_arg)
Definition: map_helpers.h:109
const CHARSET_INFO * cs
Definition: map_helpers.h:119
size_t operator()(const std::string &s) const
Definition: map_helpers.h:112
A KeyEqual that compares std::strings according to a MySQL collation.
Definition: map_helpers.h:124
Collation_key_equal(const CHARSET_INFO *cs_arg)
Definition: map_helpers.h:126
size_t operator()(const std::string &a, const std::string &b) const
Definition: map_helpers.h:129
const CHARSET_INFO * cs
Definition: map_helpers.h:135
Malloc_allocator is a C++ STL memory allocator based on my_malloc/my_free.
Definition: malloc_allocator.h:62
Mem_root_allocator is a C++ STL memory allocator based on MEM_ROOT.
Definition: mem_root_allocator.h:67
std::unordered_map, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:209
collation_unordered_map(const CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:211
std::unordered_multimap, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:225
collation_unordered_multimap(CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:227
std::unordered_set, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:241
collation_unordered_set(std::initializer_list< Key > il, CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:248
collation_unordered_set(CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:243
std::unordered_map, but with my_malloc, so that you can track the memory used using PSI memory keys.
Definition: map_helpers.h:147
malloc_unordered_map(PSI_memory_key psi_key)
Definition: map_helpers.h:153
std::unordered_multimap, but with my_malloc, so that you can track the memory used using PSI memory k...
Definition: map_helpers.h:188
malloc_unordered_multimap(PSI_memory_key psi_key)
Definition: map_helpers.h:195
std::unordered_set, but with my_malloc, so that you can track the memory used using PSI memory keys.
Definition: map_helpers.h:167
malloc_unordered_set(PSI_memory_key psi_key)
Definition: map_helpers.h:173
std::unordered_map, but collation aware and allocated on a MEM_ROOT.
Definition: map_helpers.h:296
mem_root_collation_unordered_map(const CHARSET_INFO *cs, MEM_ROOT *mem_root)
Definition: map_helpers.h:298
std::unordered_map, but allocated on a MEM_ROOT.
Definition: map_helpers.h:280
mem_root_unordered_map(MEM_ROOT *mem_root, Hash hash=Hash())
Definition: map_helpers.h:282
std::unordered_set, but allocated on a MEM_ROOT.
Definition: map_helpers.h:260
mem_root_unordered_set(MEM_ROOT *mem_root)
Definition: map_helpers.h:266
static MEM_ROOT mem_root
Definition: client_plugin.cc:109
Dialog Client Authentication nullptr
Definition: dialog.cc:352
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:48
#define free(A)
Definition: lexyy.cc:915
A better implementation of the UNIX ctype(3) library.
Container::iterator erase_specific_element(Container *container, const typename Container::key_type &key, const Value &value)
For unordered_multimap<Key, Value>, erase the first specific element that matches both the given key ...
Definition: map_helpers.h:67
std::unique_ptr< T, Free_deleter > unique_ptr_free
std::unique_ptr, but with free as deleter.
Definition: map_helpers.h:104
std::unique_ptr< T, My_free_deleter > unique_ptr_my_free
std::unique_ptr, but with my_free as deleter.
Definition: map_helpers.h:96
std::unique_ptr< T, void(*)(T *)> unique_ptr_with_deleter
std::unique_ptr, but with a custom delete function.
Definition: map_helpers.h:88
static auto find_or_nullptr(const Container &container, const Key &key)
Some useful helpers for associative arrays with MySQL-specific semantics.
Definition: map_helpers.h:53
static int key_type
Definition: mi_test1.cc:38
Some integer typedefs for easier portability.
uint64_t uint64
Definition: my_inttypes.h:68
void my_free(void *ptr)
Frees the memory pointed by the ptr.
Definition: my_memory.cc:80
Definition: atomics_array.h:38
Definition: commit_order_queue.h:33
std::string_view Key
The key type for the hash structure in HashJoinRowBuffer.
Definition: hash_join_buffer.h:107
Definition: varlen_sort.h:183
std::unordered_set< Key, std::hash< Key >, std::equal_to< Key >, ut::allocator< Key > > unordered_set
Definition: ut0new.h:2167
const string value("\"Value\"")
required string key
Definition: replication_asynchronous_connection_failover.proto:59
Definition: m_ctype.h:354
Definition: map_helpers.h:98
void operator()(void *ptr) const
Definition: map_helpers.h:99
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:78
Definition: map_helpers.h:90
void operator()(void *ptr) const
Definition: map_helpers.h:91