/src/mysql-server/include/template_utils.h
Line | Count | Source |
1 | | /* Copyright (c) 2013, 2025, 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 designed to work 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 either included with |
13 | | the program or referenced in the documentation. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | GNU General Public License, version 2.0, for more details. |
19 | | |
20 | | You should have received a copy of the GNU General Public License |
21 | | along with this program; if not, write to the Free Software |
22 | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
23 | | |
24 | | #ifndef TEMPLATE_UTILS_INCLUDED |
25 | | #define TEMPLATE_UTILS_INCLUDED |
26 | | |
27 | | #include <algorithm> |
28 | | #include <cassert> |
29 | | #include <cctype> |
30 | | #include <cstddef> |
31 | | #include <iterator> |
32 | | #include <type_traits> |
33 | | |
34 | | /** |
35 | | @file include/template_utils.h |
36 | | */ |
37 | | |
38 | | /** |
39 | | Clears a container, but deletes all objects that the elements point to first. |
40 | | @tparam Container_type Container of pointers. |
41 | | */ |
42 | | template <typename Container_type> |
43 | | void delete_container_pointers(Container_type &container) { |
44 | | typename Container_type::iterator it1 = container.begin(); |
45 | | typename Container_type::iterator it2 = container.end(); |
46 | | for (; it1 != it2; ++it1) { |
47 | | delete (*it1); |
48 | | } |
49 | | container.clear(); |
50 | | } |
51 | | |
52 | | /** |
53 | | Clears a container, but frees all objects that the elements point to first. |
54 | | @tparam Container_type Container of pointers. |
55 | | */ |
56 | | template <typename Container_type> |
57 | | void my_free_container_pointers(Container_type &container) { |
58 | | typename Container_type::iterator it1 = container.begin(); |
59 | | typename Container_type::iterator it2 = container.end(); |
60 | | for (; it1 != it2; ++it1) { |
61 | | my_free(*it1); |
62 | | } |
63 | | container.clear(); |
64 | | } |
65 | | |
66 | | /** |
67 | | Casts from one pointer type, to another, without using |
68 | | reinterpret_cast or C-style cast: |
69 | | foo *f; bar *b= pointer_cast<bar*>(f); |
70 | | This avoids having to do: |
71 | | foo *f; bar *b= static_cast<bar*>(static_cast<void*>(f)); |
72 | | */ |
73 | | template <typename T> |
74 | 227k | constexpr T pointer_cast(void *p) { |
75 | 227k | return static_cast<T>(p); |
76 | 227k | } char* pointer_cast<char*>(void*) Line | Count | Source | 74 | 227k | constexpr T pointer_cast(void *p) { | 75 | 227k | return static_cast<T>(p); | 76 | 227k | } |
Unexecuted instantiation: unsigned char* pointer_cast<unsigned char*>(void*) Unexecuted instantiation: unsigned char const* pointer_cast<unsigned char const*>(void*) Unexecuted instantiation: Prealloced_array<fileinfo, 100ul>* pointer_cast<Prealloced_array<fileinfo, 100ul>*>(void*) Unexecuted instantiation: MEM_ROOT* pointer_cast<MEM_ROOT*>(void*) Unexecuted instantiation: char const* pointer_cast<char const*>(void*) Unexecuted instantiation: unsigned char const** pointer_cast<unsigned char const**>(void*) Unexecuted instantiation: unsigned int* pointer_cast<unsigned int*>(void*) |
77 | | |
78 | | template <typename T> |
79 | 2.28k | constexpr T pointer_cast(const void *p) { |
80 | 2.28k | return static_cast<T>(p); |
81 | 2.28k | } Unexecuted instantiation: char const* pointer_cast<char const*>(void const*) unsigned char const* pointer_cast<unsigned char const*>(void const*) Line | Count | Source | 79 | 2.28k | constexpr T pointer_cast(const void *p) { | 80 | 2.28k | return static_cast<T>(p); | 81 | 2.28k | } |
|
82 | | |
83 | | /** |
84 | | Casts from one pointer type to another in a type hierarchy. |
85 | | In debug mode, we verify the cast is indeed legal. |
86 | | |
87 | | @tparam Target The descendent type, must be a pointer type. |
88 | | @tparam Source The parent type. |
89 | | |
90 | | @param arg The pointer to be down-cast. |
91 | | |
92 | | @return A pointer of type Target. |
93 | | */ |
94 | | template <typename Target, typename Source> |
95 | | inline Target down_cast(Source *arg) { |
96 | | static_assert( |
97 | | !std::is_base_of<typename std::remove_pointer<Target>::type, |
98 | | Source>::value, |
99 | | "Do not use down_cast for upcasts; use implicit_cast or nothing"); |
100 | | assert(nullptr != dynamic_cast<Target>(arg)); |
101 | | return static_cast<Target>(arg); |
102 | | } |
103 | | |
104 | | /** |
105 | | Casts from one reference type to another in a type hierarchy. |
106 | | In debug mode, we verify the cast is indeed legal. |
107 | | |
108 | | @tparam Target The descendent type, must be a reference type. |
109 | | @tparam Source The parent type. |
110 | | |
111 | | @param arg The reference to be down-cast. |
112 | | |
113 | | @return A reference of type Target. |
114 | | */ |
115 | | template <typename Target, typename Source> |
116 | | inline Target down_cast(Source &arg) { |
117 | | // We still use the pointer version of dynamic_cast, as the |
118 | | // reference-accepting version throws exceptions, and we don't want to deal |
119 | | // with that. |
120 | | static_assert( |
121 | | !std::is_base_of<typename std::remove_reference<Target>::type, |
122 | | Source>::value, |
123 | | "Do not use down_cast for upcasts; use implicit_cast or nothing"); |
124 | | assert(dynamic_cast<typename std::remove_reference<Target>::type *>(&arg) != |
125 | | nullptr); |
126 | | return static_cast<Target>(arg); |
127 | | } |
128 | | |
129 | | /** |
130 | | Sometimes the compiler insists that types be the same and does not do any |
131 | | implicit conversion. For example: |
132 | | Derived1 *a; |
133 | | Derived2 *b; // Derived1 and 2 are children classes of Base |
134 | | Base *x= cond ? a : b; // Error, need to force a cast. |
135 | | |
136 | | Use: |
137 | | Base *x= cond ? implicit_cast<Base*>(a) : implicit_cast<Base*>(b); |
138 | | static_cast would work too, but would be less safe (allows any |
139 | | pointer-to-pointer conversion, not only up-casts). |
140 | | */ |
141 | | template <typename To> |
142 | | inline To implicit_cast(To x) { |
143 | | return x; |
144 | | } |
145 | | |
146 | | /** |
147 | | Utility to allow returning values from functions which can fail |
148 | | */ |
149 | | template <class VALUE_TYPE> |
150 | | struct ReturnValueOrError { |
151 | | /** Value returned from function in the normal case. */ |
152 | | VALUE_TYPE value; |
153 | | |
154 | | /** True if an error occurred. */ |
155 | | bool error; |
156 | | }; |
157 | | |
158 | | /** |
159 | | Number of elements in a constant C array. |
160 | | */ |
161 | | template <class T, size_t N> |
162 | 46.8k | constexpr size_t array_elements(T (&)[N]) noexcept { |
163 | 46.8k | return N; |
164 | 46.8k | } unsigned long array_elements<SYMBOL const, 848ul>(SYMBOL const (&) [848ul]) Line | Count | Source | 162 | 46.8k | constexpr size_t array_elements(T (&)[N]) noexcept { | 163 | 46.8k | return N; | 164 | 46.8k | } |
Unexecuted instantiation: unsigned long array_elements<PSI_stage_info_v1*, 1ul>(PSI_stage_info_v1* (&) [1ul]) Unexecuted instantiation: unsigned long array_elements<PSI_memory_info_v1, 17ul>(PSI_memory_info_v1 (&) [17ul]) Unexecuted instantiation: unsigned long array_elements<PSI_thread_info_v5, 1ul>(PSI_thread_info_v5 (&) [1ul]) Unexecuted instantiation: unsigned long array_elements<Unidata_decomp, 5722ul>(Unidata_decomp (&) [5722ul]) |
165 | | |
166 | | namespace myu { |
167 | | /** |
168 | | Split a range into sub ranges delimited by elements satisfying a predicate. |
169 | | Examines the elements from first to last, exclusive. Each time an element |
170 | | which satisfies the splitting predicate is encountered, the action argument's |
171 | | operator() is invoked with the starting and past-the-end iterators for the |
172 | | current sub-range, even if this is empty. When iteration is complete, action() |
173 | | is called on the range between the start of the last subrange and last. |
174 | | |
175 | | It must be possible to pass a single element with type const |
176 | | InputIt::value_type to is_split_element. It must be possible to pass two |
177 | | InputIt arguments to action. |
178 | | |
179 | | @param first Beginning of the range to split. |
180 | | @param last End of the range to split. |
181 | | @param pred Callable which will be invoked on each element in |
182 | | turn to determine if it is a splitting element. |
183 | | @param action Callable which will be invoked with the beginning |
184 | | and one-past-the-end iterators for each subrange. |
185 | | */ |
186 | | template <class InputIt, class Pred, class Action> |
187 | | inline void Split(InputIt first, InputIt last, Pred &&pred, Action &&action) { |
188 | | while (first != last) { |
189 | | InputIt split = std::find_if(first, last, std::forward<Pred>(pred)); |
190 | | action(first, split); // Called even for empty subranges, action must |
191 | | // discard if not wanted |
192 | | if (split == last) return; |
193 | | first = split + 1; |
194 | | } |
195 | | } |
196 | | |
197 | | /** |
198 | | Search backwards for the first occurrence of an element which does not satisfy |
199 | | the trimming predicate, and return an InputIt to the element after it. |
200 | | |
201 | | @param first Beginning of the range to search. |
202 | | @param last End of the range to search. |
203 | | @param pred Callable which can be applied to a dereferenced InputIt and which |
204 | | returns true if the element should be trimmed. |
205 | | |
206 | | @returns InputIt referencing the first element of sub range satisfying the |
207 | | trimming predicate at the end of the range. last if no elements |
208 | | satisfy the trimming predicate. |
209 | | */ |
210 | | template <class InputIt, class Pred> |
211 | | inline InputIt FindTrimmedEnd(InputIt first, InputIt last, Pred &&pred) { |
212 | | return std::find_if_not(std::make_reverse_iterator(last), |
213 | | std::make_reverse_iterator(first), |
214 | | std::forward<Pred>(pred)) |
215 | | .base(); |
216 | | } |
217 | | |
218 | | /** |
219 | | Searches for a sub range such that no elements before or after fail to |
220 | | satisfy the trimming predicate. |
221 | | |
222 | | @param first Beginning of the range to search. |
223 | | @param last End of the range to search. |
224 | | @param pred Callable which can be applied to a dereferenced InputIt and which |
225 | | returns true if the element should be trimmed. |
226 | | |
227 | | @returns Pair of iterators denoting the sub range which does not include the |
228 | | leading and trailing sub ranges matching the trimming predicate. |
229 | | {last, last} if all elements match the trimming predicate. |
230 | | */ |
231 | | template <class InputIt, class Pred> |
232 | | inline std::pair<InputIt, InputIt> FindTrimmedRange(InputIt first, InputIt last, |
233 | | Pred &&pred) { |
234 | | InputIt f = std::find_if_not(first, last, std::forward<Pred>(pred)); |
235 | | return {f, FindTrimmedEnd(f, last, std::forward<Pred>(pred))}; |
236 | | } |
237 | | |
238 | | /** Convenience lambdas for common predicates. */ |
239 | | const auto IsSpace = [](char c) { return isspace(c); }; |
240 | | const auto IsComma = [](char c) { return c == ','; }; |
241 | | |
242 | | } // namespace myu |
243 | | #endif // TEMPLATE_UTILS_INCLUDED |