MySQL  8.0.18
Source Code Documentation
map_helpers.h
Go to the documentation of this file.
1 /* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
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/memroot_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  -> typename std::enable_if<
56  typename Container::value_type::second_type>::type {
57  const auto it = container.find(key);
58  if (it == container.end())
59  return nullptr;
60  else
61  return it->second;
62 }
63 
64 template <class Container, class Key>
65 static inline auto find_or_nullptr(const Container &container, const Key &key)
66  -> typename std::enable_if<
67  std::is_pointer<
68  typename Container::value_type::second_type::pointer>::value,
69  typename Container::value_type::second_type::pointer>::type {
70  const auto it = container.find(key);
71  if (it == container.end())
72  return nullptr;
73  else
74  return it->second.get();
75 }
76 
77 /**
78  For unordered_multimap<Key, Value>, erase the first specific element that
79  matches _both_ the given key and value.
80 */
81 template <class Container>
82 typename Container::iterator erase_specific_element(
83  Container *container, const typename Container::key_type &key,
84  const typename Container::value_type::second_type &value) {
85  auto it_range = container->equal_range(key);
86  for (auto it = it_range.first; it != it_range.second; ++it) {
87  if (it->second == value) return container->erase(it);
88  }
89  return container->end();
90 }
91 
92 /**
93  Same as regular erase_specific_element(), but for the case where the
94  container holds unique_ptr elements.
95 */
96 template <class Container>
97 static inline auto erase_specific_element(
98  Container *container, const typename Container::key_type &key,
99  typename Container::value_type::second_type::pointer value) ->
100  typename std::enable_if<
101  std::is_pointer<
102  typename Container::value_type::second_type::pointer>::value,
103  typename Container::iterator>::type {
104  auto it_range = container->equal_range(key);
105  for (auto it = it_range.first; it != it_range.second; ++it) {
106  if (it->second.get() == value) return container->erase(it);
107  }
108  return container->end();
109 }
110 
111 /**
112  std::unique_ptr, but with a custom delete function.
113  Normally, it is more efficient to have a deleter class instead,
114  but this allows you to have a unique_ptr to a forward-declared class,
115  so it keeps include dependencies down somewhat.
116 */
117 template <class T>
118 using unique_ptr_with_deleter = std::unique_ptr<T, void (*)(T *)>;
119 
121  void operator()(void *ptr) const { my_free(ptr); }
122 };
123 
124 /** std::unique_ptr, but with my_free as deleter. */
125 template <class T>
126 using unique_ptr_my_free = std::unique_ptr<T, My_free_deleter>;
127 
128 struct Free_deleter {
129  void operator()(void *ptr) const { free(ptr); }
130 };
131 
132 /** std::unique_ptr, but with free as deleter. */
133 template <class T>
134 using unique_ptr_free = std::unique_ptr<T, Free_deleter>;
135 
136 /** A Hasher that hashes std::strings according to a MySQL collation. */
138  public:
139  explicit Collation_hasher(const CHARSET_INFO *cs_arg)
140  : cs(cs_arg), hash_sort(cs->coll->hash_sort) {}
141 
142  size_t operator()(const std::string &s) const {
143  uint64 nr1 = 1, nr2 = 4;
144  hash_sort(cs, pointer_cast<const uchar *>(s.data()), s.size(), &nr1, &nr2);
145  return nr1;
146  }
147 
148  private:
149  const CHARSET_INFO *cs;
150  decltype(cs->coll->hash_sort) hash_sort;
151 };
152 
153 /** A KeyEqual that compares std::strings according to a MySQL collation. */
155  public:
156  explicit Collation_key_equal(const CHARSET_INFO *cs_arg)
157  : cs(cs_arg), strnncollsp(cs->coll->strnncollsp) {}
158 
159  size_t operator()(const std::string &a, const std::string &b) const {
160  return strnncollsp(cs, pointer_cast<const uchar *>(a.data()), a.size(),
161  pointer_cast<const uchar *>(b.data()), b.size()) == 0;
162  }
163 
164  private:
165  const CHARSET_INFO *cs;
166  decltype(cs->coll->strnncollsp) strnncollsp;
167 };
168 
169 /**
170  std::unordered_map, but with my_malloc, so that you can track the memory
171  used using PSI memory keys.
172 */
173 template <class Key, class Value, class Hash = std::hash<Key>,
174  class KeyEqual = std::equal_to<Key>>
176  : public std::unordered_map<Key, Value, Hash, KeyEqual,
177  Malloc_allocator<std::pair<const Key, Value>>> {
178  public:
179  /*
180  In theory, we should be allowed to send in the allocator only, but GCC 4.8
181  is missing several unordered_map constructors, so let's give in everything.
182  */
184  : std::unordered_map<Key, Value, Hash, KeyEqual,
185  Malloc_allocator<std::pair<const Key, Value>>>(
186  /*bucket_count=*/10, Hash(), KeyEqual(),
187  Malloc_allocator<>(psi_key)) {}
188 };
189 
190 /**
191  std::unordered_set, but with my_malloc, so that you can track the memory
192  used using PSI memory keys.
193 */
194 template <class Key, class Hash = std::hash<Key>,
195  class KeyEqual = std::equal_to<Key>>
197  : public std::unordered_set<Key, Hash, KeyEqual, Malloc_allocator<Key>> {
198  public:
199  /*
200  In theory, we should be allowed to send in the allocator only, but GCC 4.8
201  is missing several unordered_set constructors, so let's give in everything.
202  */
204  : std::unordered_set<Key, Hash, KeyEqual, Malloc_allocator<Key>>(
205  /*bucket_count=*/10, Hash(), KeyEqual(),
206  Malloc_allocator<>(psi_key)) {}
207 };
208 
209 /**
210  std::unordered_multimap, but with my_malloc, so that you can track the memory
211  used using PSI memory keys.
212 */
213 template <class Key, class Value, class Hash = std::hash<Key>,
214  class KeyEqual = std::equal_to<Key>>
216  : public std::unordered_multimap<
217  Key, Value, Hash, KeyEqual,
218  Malloc_allocator<std::pair<const Key, Value>>> {
219  public:
220  /*
221  In theory, we should be allowed to send in the allocator only, but GCC 4.8
222  is missing several unordered_multimap constructors, so let's give in
223  everything.
224  */
226  : std::unordered_multimap<Key, Value, Hash, KeyEqual,
227  Malloc_allocator<std::pair<const Key, Value>>>(
228  /*bucket_count=*/10, Hash(), KeyEqual(),
229  Malloc_allocator<>(psi_key)) {}
230 };
231 
232 /**
233  std::unordered_map, but with my_malloc and collation-aware comparison.
234 */
235 template <class Key, class Value>
237  : public std::unordered_map<Key, Value, Collation_hasher,
238  Collation_key_equal,
239  Malloc_allocator<std::pair<const Key, Value>>> {
240  public:
242  : std::unordered_map<Key, Value, Collation_hasher, Collation_key_equal,
243  Malloc_allocator<std::pair<const Key, Value>>>(
244  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
245  Malloc_allocator<>(psi_key)) {}
246 };
247 
248 /**
249  std::unordered_multimap, but with my_malloc and collation-aware comparison.
250 */
251 template <class Key, class Value>
253  : public std::unordered_multimap<
254  Key, Value, Collation_hasher, Collation_key_equal,
255  Malloc_allocator<std::pair<const Key, Value>>> {
256  public:
258  : std::unordered_multimap<Key, Value, Collation_hasher,
260  Malloc_allocator<std::pair<const Key, Value>>>(
261  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
262  Malloc_allocator<>(psi_key)) {}
263 };
264 
265 /**
266  std::unordered_set, but with my_malloc and collation-aware comparison.
267 */
268 template <class Key>
270  : public std::unordered_set<Key, Collation_hasher, Collation_key_equal,
271  Malloc_allocator<Key>> {
272  public:
274  : std::unordered_set<Key, Collation_hasher, Collation_key_equal,
275  Malloc_allocator<Key>>(
276  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
277  Malloc_allocator<>(psi_key)) {}
278  collation_unordered_set(std::initializer_list<Key> il, CHARSET_INFO *cs,
279  PSI_memory_key psi_key)
280  : std::unordered_set<Key, Collation_hasher, Collation_key_equal,
281  Malloc_allocator<Key>>(
282  il, /*bucket_count=*/10, Collation_hasher(cs),
283  Collation_key_equal(cs), Malloc_allocator<>(psi_key)) {}
284 };
285 
286 /** std::unordered_set, but allocated on a MEM_ROOT. */
287 template <class Key, class Hash = std::hash<Key>,
288  class KeyEqual = std::equal_to<Key>>
290  : public std::unordered_set<Key, Hash, KeyEqual, Memroot_allocator<Key>> {
291  public:
292  /*
293  In theory, we should be allowed to send in the allocator only, but GCC 4.8
294  is missing several unordered_set constructors, so let's give in everything.
295  */
297  : std::unordered_set<Key, Hash, KeyEqual, Memroot_allocator<Key>>(
298  /*bucket_count=*/10, Hash(), KeyEqual(),
299  Memroot_allocator<Key>(mem_root)) {}
300 };
301 
302 /**
303  std::unordered_map, but allocated on a MEM_ROOT.
304 */
305 template <class Key, class Value, class Hash = std::hash<Key>,
306  class KeyEqual = std::equal_to<Key>>
308  : public std::unordered_map<
309  Key, Value, Hash, KeyEqual,
310  Memroot_allocator<std::pair<const Key, Value>>> {
311  public:
313  : std::unordered_map<Key, Value, Hash, KeyEqual,
314  Memroot_allocator<std::pair<const Key, Value>>>(
315  /*bucket_count=*/10, Hash(), KeyEqual(),
316  Memroot_allocator<std::pair<const Key, Value>>(mem_root)) {}
317 };
318 
319 // std::unordered_multimap, but allocated on a MEM_ROOT.
320 template <class Key, class Value, class Hash,
321  class KeyEqual = std::equal_to<Key>>
323  : public std::unordered_multimap<
324  Key, Value, Hash, KeyEqual,
325  Memroot_allocator<std::pair<const Key, Value>>> {
326  public:
328  : std::unordered_multimap<Key, Value, Hash, KeyEqual,
329  Memroot_allocator<std::pair<const Key, Value>>>(
330  /*bucket_count=*/10, hash, KeyEqual(),
331  Memroot_allocator<std::pair<const Key, Value>>(mem_root)) {}
332 };
333 
334 /**
335  std::unordered_map, but collation aware and allocated on a MEM_ROOT.
336 */
337 template <class Key, class Value>
339  : public std::unordered_map<
340  Key, Value, Collation_hasher, Collation_key_equal,
341  Memroot_allocator<std::pair<const Key, Value>>> {
342  public:
344  : std::unordered_map<Key, Value, Collation_hasher, Collation_key_equal,
345  Memroot_allocator<std::pair<const Key, Value>>>(
346  /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs),
347  Memroot_allocator<std::pair<const Key, Value>>(mem_root)) {}
348 };
349 
350 #endif // MAP_HELPERS_INCLUDED
std::unique_ptr< T, void(*)(T *)> unique_ptr_with_deleter
std::unique_ptr, but with a custom delete function.
Definition: map_helpers.h:118
unsigned char uchar
Definition: my_inttypes.h:51
#define free(A)
Definition: fts0ast.h:42
Container::iterator erase_specific_element(Container *container, const typename Container::key_type &key, const typename Container::value_type::second_type &value)
For unordered_multimap<Key, Value>, erase the first specific element that matches both the given key ...
Definition: map_helpers.h:82
void operator()(void *ptr) const
Definition: map_helpers.h:129
collation_unordered_set(CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:273
T pointer_cast(void *p)
Casts from one pointer type, to another, without using reinterpret_cast or C-style cast: foo f; bar *...
Definition: template_utils.h:70
std::unordered_map, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:236
Some integer typedefs for easier portability.
std::unique_ptr< T, My_free_deleter > unique_ptr_my_free
std::unique_ptr, but with my_free as deleter.
Definition: map_helpers.h:126
memroot_unordered_multimap(MEM_ROOT *mem_root, Hash hash)
Definition: map_helpers.h:327
const CHARSET_INFO * cs
Definition: map_helpers.h:165
static int key_type
Definition: mi_test1.cc:38
static auto find_or_nullptr(const Container &container, const Key &key) -> typename std::enable_if< std::is_pointer< typename Container::value_type::second_type >::value, typename Container::value_type::second_type >::type
Some useful helpers for associative arrays with MySQL-specific semantics.
Definition: map_helpers.h:53
std::unordered_set, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:269
Definition: varlen_sort.h:182
int(* strnncollsp)(const CHARSET_INFO *, const uchar *, size_t, const uchar *, size_t)
Compare the two strings under the pad rules given by the collation.
Definition: m_ctype.h:190
memroot_unordered_map(MEM_ROOT *mem_root)
Definition: map_helpers.h:312
void my_free(void *ptr)
Frees the memory pointed by the ptr.
Definition: my_memory.cc:81
MY_COLLATION_HANDLER * coll
Definition: m_ctype.h:392
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:46
size_t operator()(const std::string &a, const std::string &b) const
Definition: map_helpers.h:159
void(* hash_sort)(const CHARSET_INFO *cs, const uchar *key, size_t len, uint64 *nr1, uint64 *nr2)
Compute a sort hash for the given key.
Definition: m_ctype.h:256
Definition: map_helpers.h:120
collation_unordered_multimap(CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:257
std::unordered_map, but with my_malloc, so that you can track the memory used using PSI memory keys...
Definition: map_helpers.h:175
Collation_hasher(const CHARSET_INFO *cs_arg)
Definition: map_helpers.h:139
Definition: map_helpers.h:322
memroot_collation_unordered_map(const CHARSET_INFO *cs, MEM_ROOT *mem_root)
Definition: map_helpers.h:343
std::unique_ptr< T, Free_deleter > unique_ptr_free
std::unique_ptr, but with free as deleter.
Definition: map_helpers.h:134
std::unordered_multimap, but with my_malloc, so that you can track the memory used using PSI memory k...
Definition: map_helpers.h:215
Collation_key_equal(const CHARSET_INFO *cs_arg)
Definition: map_helpers.h:156
std::unordered_multimap, but with my_malloc and collation-aware comparison.
Definition: map_helpers.h:252
Definition: m_ctype.h:359
uint32_t hash(const void *key, size_t length, const uint32_t initval)
Definition: hash.c:121
static const char * key
Definition: suite_stubs.c:14
static MEM_ROOT mem_root
Definition: client_plugin.cc:107
collation_unordered_set(std::initializer_list< Key > il, CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:278
int type
Definition: http_common.h:411
const CHARSET_INFO * cs
Definition: map_helpers.h:149
size_t operator()(const std::string &s) const
Definition: map_helpers.h:142
Definition: map_helpers.h:128
malloc_unordered_map(PSI_memory_key psi_key)
Definition: map_helpers.h:183
container
Following are enums defining column IDs indexing into each of three system tables.
Definition: innodb_config.h:78
malloc_unordered_set(PSI_memory_key psi_key)
Definition: map_helpers.h:203
collation_unordered_map(const CHARSET_INFO *cs, PSI_memory_key psi_key)
Definition: map_helpers.h:241
A Hasher that hashes std::strings according to a MySQL collation.
Definition: map_helpers.h:137
A better implementation of the UNIX ctype(3) library.
malloc_unordered_multimap(PSI_memory_key psi_key)
Definition: map_helpers.h:225
std::unordered_map, but collation aware and allocated on a MEM_ROOT.
Definition: map_helpers.h:338
const string value("\alue\)
A KeyEqual that compares std::strings according to a MySQL collation.
Definition: map_helpers.h:154
std::unordered_set, but with my_malloc, so that you can track the memory used using PSI memory keys...
Definition: map_helpers.h:196
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:77
std::unordered_set, but allocated on a MEM_ROOT.
Definition: map_helpers.h:289
Malloc_allocator is a C++ STL memory allocator based on my_malloc/my_free.
Definition: malloc_allocator.h:62
std::unordered_map, but allocated on a MEM_ROOT.
Definition: map_helpers.h:307
memroot_unordered_set(MEM_ROOT *mem_root)
Definition: map_helpers.h:296
uint64_t uint64
Definition: my_inttypes.h:68
void operator()(void *ptr) const
Definition: map_helpers.h:121
decltype(cs->coll->hash_sort) hash_sort
Definition: map_helpers.h:150
Memroot_allocator is a C++ STL memory allocator based on MEM_ROOT.
Definition: equi_height.h:92