MySQL 9.6.0
Source Code Documentation
buffer_interface.h
Go to the documentation of this file.
1// Copyright (c) 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 MYSQL_RANGES_BUFFER_INTERFACE_H
25#define MYSQL_RANGES_BUFFER_INTERFACE_H
26
27/// @file
28/// Experimental API header
29
30#include <cassert> // assert
31#include <cstddef> // ptrdiff_t
32#include <cstring> // memcmp
33#include <string_view> // string_view
34#include "mysql/meta/is_charlike.h" // Is_charlike
35#include "mysql/utils/char_cast.h" // uchar_cast
36
37/// @addtogroup GroupLibsMysqlRanges
38/// @{
39
41/// Top of the hierarchy
42class Buffer_base {};
43} // namespace mysql::ranges::detail
44
45namespace mysql::ranges {
46
47// NOLINTBEGIN(performance-enum-size): silence clang-tidy's pointless hint
49
50enum class Enable_hash { no, yes };
51// NOLINTEND(performance-enum-size)
52
53/// CRTP base class that provides a rich API for classes that behave like byte
54/// buffers. This turns a subclass that implements `size()` and `data()` members
55/// into a `std::ranges::range`, defines the same members that
56/// `std::view_interface` defines, enables comparisons and hashes, and for any
57/// member that uses `char *`, provides alternative members that use `unsigned
58/// char *` and `std::byte`.
59///
60/// The subclass should implement the following member functions:
61/// @code
62/// size_t size() const;
63/// char *data();
64/// const char *data() const;
65/// @endcode
66///
67/// This class provides the members:
68/// - `string_view`: Return an `std::string_view`.
69/// - `[u|b]data`: Return data as `unsigned char *` or `std::byte *`.
70/// - `[c][u|b]begin`/`[c][u|b]end`: Return (const) begin/end pointers
71/// as `char *`, `unsigned char *`, or `std::byte *`.
72/// - `operator[]`: Return the n'th element.
73/// - `ssize`: Return the size as a signed integer (`std::ptrdiff_t`).
74/// - `empty`: Return `size() == 0`.
75/// - `operator bool`: return `size() != 0`.
76/// Optionally, the following free functions are provided:
77/// - `operator==`, `operator!=`, and `operator<=>`.
78/// - `std::hash`.
79///
80/// The following alternative prototypes are allowed:
81/// @code
82/// char *data() const;
83/// @endcode
84/// I.e., the data may be non-const even if the buffer object is const. This is
85/// useful when the buffer object does not own the data.
86///
87/// @tparam Self_tp Subclass.
88///
89/// @tparam equality_algorithm_tp Determines if and how operators ==, !=, <, >,
90/// <=, >=, and <=> are implemented: `lexicographic` compares strings
91/// lexicographically, for example, "a" < "aa" < "b"; `fast` compares the length
92/// first, and compares lexicographically only when the lengths are equal, for
93/// example, "a" < "b" < "aa"; `none` does not implement comparison at all.
94/// Default is `lexicographic`.
95///
96/// @tparam enable_hash_tp If `yes`, enable `std::hash<Self_tp>`. Default is
97/// `yes`.
98template <class Self_tp,
99 Equality_algorithm equality_algorithm_tp =
101 Enable_hash enable_hash_tp = Enable_hash::yes>
103 public:
104 static constexpr auto equality_algorithm = equality_algorithm_tp;
105 static constexpr bool equality_enabled =
107 static constexpr bool hash_enabled = (enable_hash_tp == Enable_hash::yes);
108
109 // ==== Size members ====
110
111 /// Return true if `size() != 0`.
112 [[nodiscard]] explicit operator bool() const { return !self().empty(); }
113
114 /// Return true if `size() == 0`.
115 [[nodiscard]] bool operator!() const { return self().empty(); }
116
117 /// Return true if `size() == 0`.
118 [[nodiscard]] bool empty() const { return self().size() == 0; }
119
120 /// Return the size as `std::ptrdiff_t`.
121 [[nodiscard]] std::ptrdiff_t ssize() const {
122 return std::ptrdiff_t(self().size());
123 }
124
125 // ==== data members ====
126
127 /// Return the data buffer as `unsigned char *`.
128 [[nodiscard]] auto *udata() {
129 return mysql::utils::uchar_cast(self().data());
130 }
131
132 /// Return the data buffer as `const unsigned char *` or `unsigned char *`,
133 /// const-ness inherited from `Self_t::data() const`.
134 [[nodiscard]] auto *udata() const {
135 return mysql::utils::uchar_cast(self().data());
136 }
137
138 /// Return the data buffer as `std::byte *`.
139 [[nodiscard]] auto *bdata() { return mysql::utils::byte_cast(self().data()); }
140
141 /// Return the data buffer as `const std::byte *` or `std::byte *`, const-ness
142 /// inherited from `Self_t::data() const`.
143 [[nodiscard]] auto *bdata() const {
144 return mysql::utils::byte_cast(self().data());
145 }
146
147 // ==== string_view member ====
148
149 [[nodiscard]] std::string_view string_view() const {
150 return {self().data(), self().size()};
151 }
152
153 // ==== begin members ====
154
155 /// Return the begin as `char *`.
156 [[nodiscard]] auto *begin() { return self().data(); }
157
158 /// Return the begin as `const char *` or `char *`, const-ness inherited from
159 /// `Self_t::data() const`.
160 [[nodiscard]] auto *begin() const { return self().data(); }
161
162 /// Return the begin as `const char *` or `char *`, const-ness inherited from
163 /// `Self_t::data() const`.
164 [[nodiscard]] auto *cbegin() const { return self().data(); }
165
166 /// Return the begin as `unsigned char *`.
167 [[nodiscard]] auto *ubegin() { return udata(); }
168
169 /// Return the begin as `const unsigned char *` or `unsigned char *`,
170 /// const-ness inherited from `Self_t::data() const`.
171 [[nodiscard]] auto *ubegin() const { return udata(); }
172
173 /// Return the begin as `const unsigned char *` or `unsigned char *`,
174 /// const-ness inherited from `Self_t::data() const`.
175 [[nodiscard]] auto *cubegin() const { return udata(); }
176
177 /// Return the begin as `std::byte *`.
178 [[nodiscard]] auto *bbegin() { return udata(); }
179
180 /// Return the begin as `const std::byte *` or `std::byte *`, const-ness
181 /// inherited from `Self_t::data() const`.
182 [[nodiscard]] auto *bbegin() const { return udata(); }
183
184 /// Return the begin as `const std::byte *` or `std::byte *`, const-ness
185 /// inherited from `Self_t::data() const`.
186 [[nodiscard]] auto *cbbegin() const { return udata(); }
187
188 // ==== end members ====
189
190 /// Return the end as `char *`.
191 [[nodiscard]] auto *end() { return self().data() + self().size(); }
192
193 /// Return the end as `const char *` or `char *`, const-ness inherited from
194 /// `Self_t::data() const`.
195 [[nodiscard]] auto *end() const { return self().data() + self().size(); }
196
197 /// Return the end as `const char *` or `char *`, const-ness inherited from
198 /// `Self_t::data() const`.
199 [[nodiscard]] auto *cend() const { return self().data() + self().size(); }
200
201 /// Return the end as `unsigned char *`.
202 [[nodiscard]] auto *uend() { return udata() + self().size(); }
203
204 /// Return the end as `const unsigned char *` or `unsigned char *`, const-ness
205 /// inherited from `Self_t::data() const`.
206 [[nodiscard]] auto *uend() const { return udata() + self().size(); }
207
208 /// Return the end as `const unsigned char *` or `unsigned char *`, const-ness
209 /// inherited from `Self_t::data() const`.
210 [[nodiscard]] auto *cuend() const { return udata() + self().size(); }
211
212 /// Return the end as `std::byte *`.
213 [[nodiscard]] auto *bend() { return udata() + self().size(); }
214
215 /// Return the end as `const std::byte *` or `std::byte *`, const-ness
216 /// inherited from `Self_t::data() const`.
217 [[nodiscard]] auto *bend() const { return udata() + self().size(); }
218
219 /// Return the end as `const std::byte *` or or `std::byte *`, const-ness
220 /// inherited from `Self_t::data() const`.
221 [[nodiscard]] auto *cbend() const { return udata() + self().size(); }
222
223 // ==== operator[] ====
224
225 /// Return reference the n'th element.
226 [[nodiscard]] char &operator[](std::ptrdiff_t n) {
227 assert(n >= 0);
228 assert(n < self().size());
229 return self().data()[n];
230 }
231
232 /// Return the n'th element, const-ness inherited from `Self_t::data() const`.
233 [[nodiscard]] char operator[](std::ptrdiff_t n) const {
234 assert(n >= 0);
235 assert(n < self().size());
236 return self().data()[n];
237 }
238
239 private:
240 [[nodiscard]] Self_tp &self() { return static_cast<Self_tp &>(*this); }
241 [[nodiscard]] const Self_tp &self() const {
242 return static_cast<const Self_tp &>(*this);
243 }
244}; // class Buffer_interface
245
246/// Enable fast comparison operators for `Buffer_interface` subclasses.
247template <std::derived_from<detail::Buffer_base> Buffer_t>
248 requires(Buffer_t::equality_algorithm == Equality_algorithm::fast)
249inline auto operator<=>(const Buffer_t &left, const Buffer_t &right) {
250 auto size_cmp = left.size() <=> right.size();
251 if (size_cmp != 0) return size_cmp;
252 return std::memcmp(left.data(), right.data(), left.size()) <=> 0;
253}
254
255/// Enable lexicographic comparison operators for `Buffer_interface` subclasses.
256template <std::derived_from<detail::Buffer_base> Buffer_t>
257 requires(Buffer_t::equality_algorithm == Equality_algorithm::lexicographic)
258inline auto operator<=>(const Buffer_t &left, const Buffer_t &right) {
259 return left.string_view() <=> right.string_view();
260}
261
262/// Enable operator== for `Buffer_interface` subclasses.
263template <std::derived_from<detail::Buffer_base> Buffer_t>
264 requires Buffer_t::equality_enabled
265inline bool operator==(const Buffer_t &left, const Buffer_t &right) {
266 if (left.size() != right.size()) return false;
267 return std::memcmp(left.data(), right.data(), left.size()) == 0;
268}
269
270/// Enable operator!= for `Buffer_interface` subclasses.
271template <std::derived_from<detail::Buffer_base> Buffer_t>
272 requires Buffer_t::equality_enabled
273inline bool operator!=(const Buffer_t &left, const Buffer_t &right) {
274 return !(left == right);
275}
276
277} // namespace mysql::ranges
278
279/// Define std::hash<T> where T is a subclass of `Buffer_interface`.
280//
281// The recommended way to do this is to use a syntax that places the namespace
282// as a name qualifier, like `struct std::hash<Gtid_t>`, rather than enclose the
283// entire struct in a namespace block.
284//
285// However, gcc 11.4.0 on ARM has a bug that makes it produce "error:
286// redefinition of 'struct std::hash<_Tp>'" when using that syntax. See
287// https://godbolt.org/z/xo1v8rf6n vs https://godbolt.org/z/GzvrMese1 .
288//
289// Todo: Switch to the recommended syntax once we drop support for compilers
290// having this bug.
291//
292// clang-tidy warns when not using the recommended syntax
293// NOLINTBEGIN(cert-dcl58-cpp)
294namespace std {
295template <std::derived_from<mysql::ranges::detail::Buffer_base> Buffer_t>
296 requires Buffer_t::hash_enabled
297struct hash<Buffer_t> {
298 std::size_t operator()(const Buffer_t &object) const {
299 return std::hash<std::string_view>{}(object.string_view());
300 }
301};
302} // namespace std
303// NOLINTEND(cert-dcl58-cpp)
304
305// addtogroup GroupLibsMysqlRanges
306/// @}
307
308#endif // ifndef MYSQL_RANGES_BUFFER_INTERFACE_H
Experimental API header.
CRTP base class that provides a rich API for classes that behave like byte buffers.
Definition: buffer_interface.h:102
bool empty() const
Return true if size() == 0.
Definition: buffer_interface.h:118
auto * cbegin() const
Return the begin as const char * or char *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:164
auto * ubegin() const
Return the begin as const unsigned char * or unsigned char *, const-ness inherited from Self_t::data(...
Definition: buffer_interface.h:171
bool operator!() const
Return true if size() == 0.
Definition: buffer_interface.h:115
auto * end() const
Return the end as const char * or char *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:195
static constexpr auto equality_algorithm
Definition: buffer_interface.h:104
auto * end()
Return the end as char *.
Definition: buffer_interface.h:191
auto * cbend() const
Return the end as const std::byte * or or std::byte *, const-ness inherited from Self_t::data() const...
Definition: buffer_interface.h:221
static constexpr bool hash_enabled
Definition: buffer_interface.h:107
auto * ubegin()
Return the begin as unsigned char *.
Definition: buffer_interface.h:167
auto * bend() const
Return the end as const std::byte * or std::byte *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:217
std::ptrdiff_t ssize() const
Return the size as std::ptrdiff_t.
Definition: buffer_interface.h:121
auto * bdata() const
Return the data buffer as const std::byte * or std::byte *, const-ness inherited from Self_t::data() ...
Definition: buffer_interface.h:143
static constexpr bool equality_enabled
Definition: buffer_interface.h:105
char & operator[](std::ptrdiff_t n)
Return reference the n'th element.
Definition: buffer_interface.h:226
auto * uend()
Return the end as unsigned char *.
Definition: buffer_interface.h:202
std::string_view string_view() const
Definition: buffer_interface.h:149
auto * bend()
Return the end as std::byte *.
Definition: buffer_interface.h:213
auto * bbegin() const
Return the begin as const std::byte * or std::byte *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:182
auto * udata()
Return the data buffer as unsigned char *.
Definition: buffer_interface.h:128
auto * begin() const
Return the begin as const char * or char *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:160
auto * uend() const
Return the end as const unsigned char * or unsigned char *, const-ness inherited from Self_t::data() ...
Definition: buffer_interface.h:206
auto * bbegin()
Return the begin as std::byte *.
Definition: buffer_interface.h:178
auto * cend() const
Return the end as const char * or char *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:199
auto * cuend() const
Return the end as const unsigned char * or unsigned char *, const-ness inherited from Self_t::data() ...
Definition: buffer_interface.h:210
auto * bdata()
Return the data buffer as std::byte *.
Definition: buffer_interface.h:139
auto * cubegin() const
Return the begin as const unsigned char * or unsigned char *, const-ness inherited from Self_t::data(...
Definition: buffer_interface.h:175
auto * cbbegin() const
Return the begin as const std::byte * or std::byte *, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:186
char operator[](std::ptrdiff_t n) const
Return the n'th element, const-ness inherited from Self_t::data() const.
Definition: buffer_interface.h:233
auto * udata() const
Return the data buffer as const unsigned char * or unsigned char *, const-ness inherited from Self_t:...
Definition: buffer_interface.h:134
auto * begin()
Return the begin as char *.
Definition: buffer_interface.h:156
Top of the hierarchy.
Definition: buffer_interface.h:42
Experimental API header.
void right(std::string *to_trim)
Definition: trim.h:41
void left(std::string *to_trim)
Definition: trim.h:35
Definition: buffer_interface.h:40
Definition: buffer_interface.h:40
::equality_enabled bool operator==(const Buffer_t &left, const Buffer_t &right)
Enable operator== for Buffer_interface subclasses.
Definition: buffer_interface.h:265
::equality_enabled bool operator!=(const Buffer_t &left, const Buffer_t &right)
Enable operator!= for Buffer_interface subclasses.
Definition: buffer_interface.h:273
Equality_algorithm
Definition: buffer_interface.h:48
Enable_hash
Definition: buffer_interface.h:50
auto operator<=>(const Buffer_t &left, const Buffer_t &right)
Enable fast comparison operators for Buffer_interface subclasses.
Definition: buffer_interface.h:249
decltype(auto) uchar_cast(Type_t &&value)
Shorthand for char_cast<unsigned char>.
Definition: char_cast.h:65
decltype(auto) byte_cast(Type_t &&value)
Shorthand for char_cast<std::byte>.
Definition: char_cast.h:71
size_t size(const char *const c)
Definition: base64.h:46
Define std::hash<Gtid>.
Definition: gtid.h:355
std::size_t operator()(const Buffer_t &object) const
Definition: buffer_interface.h:298
int n
Definition: xcom_base.cc:509