libpqxx 7.7.0
util.hxx
1/* Various utility definitions for libpqxx.
2 *
3 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/util instead.
4 *
5 * Copyright (c) 2000-2022, Jeroen T. Vermeulen.
6 *
7 * See COPYING for copyright license. If you did not receive a file called
8 * COPYING with this source code, please notify the distributor of this
9 * mistake, or contact the author.
10 */
11#ifndef PQXX_H_UTIL
12#define PQXX_H_UTIL
13
14#include <cctype>
15#include <cstdio>
16#include <functional>
17#include <iterator>
18#include <limits>
19#include <memory>
20#include <stdexcept>
21#include <string>
22#include <string_view>
23#include <type_traits>
24#include <typeinfo>
25#include <utility>
26#include <vector>
27
28#if __has_include(<version>)
29# include <version>
30#endif
31
32#include "pqxx/except.hxx"
33#include "pqxx/internal/encodings.hxx"
34#include "pqxx/types.hxx"
35#include "pqxx/version.hxx"
36
37
39namespace pqxx
40{}
41
42#include <pqxx/internal/libpq-forward.hxx>
43
44
46namespace pqxx::internal
47{
48
49
50// C++20: Use concept to express LEFT and RIGHT must be integral types.
52template<typename LEFT, typename RIGHT>
53inline constexpr bool cmp_less(LEFT lhs, RIGHT rhs)
54{
55#if defined(PQXX_HAVE_CMP)
56 return std::cmp_less(lhs, rhs);
57#else
58 if constexpr (std::is_signed_v<LEFT> == std::is_signed_v<RIGHT>)
59 return lhs < rhs;
60 else if constexpr (std::is_signed_v<LEFT>)
61 return (lhs <= 0) ? true : (std::make_unsigned_t<LEFT>(lhs) < rhs);
62 else
63 return (rhs <= 0) ? false : (lhs < std::make_unsigned_t<RIGHT>(rhs));
64#endif
65}
66
67
68// C++20: Use concept to express LEFT and RIGHT must be integral types.
70template<typename LEFT, typename RIGHT>
71inline constexpr bool cmp_greater(LEFT lhs, RIGHT rhs)
72{
73#if defined(PQXX_HAVE_CMP)
74 return std::cmp_greater(lhs, rhs);
75#else
76 return cmp_less(rhs, lhs);
77#endif
78}
79
80
81// C++20: Use concept to express LEFT and RIGHT must be integral types.
83template<typename LEFT, typename RIGHT>
84inline constexpr bool cmp_less_equal(LEFT lhs, RIGHT rhs)
85{
86#if defined(PQXX_HAVE_CMP)
87 return std::cmp_less_equal(lhs, rhs);
88#else
89 return not cmp_less(rhs, lhs);
90#endif
91}
92
93
94// C++20: Use concept to express LEFT and RIGHT must be integral types.
96template<typename LEFT, typename RIGHT>
97inline constexpr bool cmp_greater_equal(LEFT lhs, RIGHT rhs)
98{
99#if defined(PQXX_HAVE_CMP)
100 return std::cmp_greater_equal(lhs, rhs);
101#else
102 return not cmp_less(lhs, rhs);
103#endif
104}
105
106
108
111[[nodiscard]] inline std::string cat2(std::string_view x, std::string_view y)
112{
113 std::string buf;
114 auto const xs{std::size(x)}, ys{std::size(y)};
115 buf.resize(xs + ys);
116 x.copy(std::data(buf), xs);
117 y.copy(std::data(buf) + xs, ys);
118 return buf;
119}
120} // namespace pqxx::internal
121
122
123namespace pqxx
124{
125using namespace std::literals;
126
128template<typename... T> inline void ignore_unused(T &&...) {}
129
130
132
135template<typename TO, typename FROM>
136inline TO check_cast(FROM value, std::string_view description)
137{
138 static_assert(std::is_arithmetic_v<FROM>);
139 static_assert(std::is_arithmetic_v<TO>);
140 static_assert(std::is_integral_v<FROM> == std::is_integral_v<TO>);
141
142 // The rest of this code won't quite work for bool, but bool is trivially
143 // convertible to other arithmetic types as far as I can see.
144 if constexpr (std::is_same_v<FROM, bool>)
145 return static_cast<TO>(value);
146
147 // Depending on our "if constexpr" conditions, this parameter may not be
148 // needed. Some compilers will warn.
149 ignore_unused(description);
150
151 using from_limits = std::numeric_limits<decltype(value)>;
152 using to_limits = std::numeric_limits<TO>;
153 if constexpr (std::is_signed_v<FROM>)
154 {
155 if constexpr (std::is_signed_v<TO>)
156 {
157 if (value < to_limits::lowest())
158 throw range_error{internal::cat2("Cast underflow: "sv, description)};
159 }
160 else
161 {
162 // FROM is signed, but TO is not. Treat this as a special case, because
163 // there may not be a good broader type in which the compiler can even
164 // perform our check.
165 if (value < 0)
167 "Casting negative value to unsigned type: "sv, description)};
168 }
169 }
170 else
171 {
172 // No need to check: the value is unsigned so can't fall below the range
173 // of the TO type.
174 }
175
176 if constexpr (std::is_integral_v<FROM>)
177 {
178 using unsigned_from = std::make_unsigned_t<FROM>;
179 using unsigned_to = std::make_unsigned_t<TO>;
180 // C++20: constinit.
181 constexpr auto from_max{static_cast<unsigned_from>((from_limits::max)())};
182 // C++20: constinit.
183 constexpr auto to_max{static_cast<unsigned_to>((to_limits::max)())};
184 if constexpr (from_max > to_max)
185 {
186 if (internal::cmp_greater(value, to_max))
187 throw range_error{internal::cat2("Cast overflow: "sv, description)};
188 }
189 }
190 else if constexpr ((from_limits::max)() > (to_limits::max)())
191 {
192 if (value > (to_limits::max)())
193 throw range_error{internal::cat2("Cast overflow: ", description)};
194 }
195
196 return static_cast<TO>(value);
197}
198
199
221inline PQXX_PRIVATE void check_version()
222{
223 // There is no particular reason to do this here in @ref connection, except
224 // to ensure that every meaningful libpqxx client will execute it. The call
225 // must be in the execution path somewhere or the compiler won't try to link
226 // it. We can't use it to initialise a global or class-static variable,
227 // because a smart compiler might resolve it at compile time.
228 //
229 // On the other hand, we don't want to make a useless function call too
230 // often for performance reasons. A local static variable is initialised
231 // only on the definition's first execution. Compilers will be well
232 // optimised for this behaviour, so there's a minimal one-time cost.
233 static auto const version_ok{internal::PQXX_VERSION_CHECK()};
234 ignore_unused(version_ok);
235}
236
237
239
241struct PQXX_LIBEXPORT thread_safety_model
242{
244 bool safe_libpq = false;
245
247
253 bool safe_kerberos = false;
254
256 std::string description;
257};
258
259
261[[nodiscard]] PQXX_LIBEXPORT thread_safety_model describe_thread_safety();
262
263
264#if defined(PQXX_HAVE_CONCEPTS)
265# define PQXX_POTENTIAL_BINARY_ARG pqxx::potential_binary
266#else
267# define PQXX_POTENTIAL_BINARY_ARG typename
268#endif
269
271
288template<PQXX_POTENTIAL_BINARY_ARG TYPE>
289std::basic_string_view<std::byte> binary_cast(TYPE const &data)
290{
291 static_assert(sizeof(value_type<TYPE>) == 1);
292 return {
293 reinterpret_cast<std::byte const *>(
294 const_cast<strip_t<decltype(*std::data(data))> const *>(
295 std::data(data))),
296 std::size(data)};
297}
298
299
300#if defined(PQXX_HAVE_CONCEPTS)
301template<typename CHAR>
302concept char_sized = (sizeof(CHAR) == 1);
303# define PQXX_CHAR_SIZED_ARG char_sized
304#else
305# define PQXX_CHAR_SIZED_ARG typename
306#endif
307
309
316template<PQXX_CHAR_SIZED_ARG CHAR, typename SIZE>
317std::basic_string_view<std::byte> binary_cast(CHAR const *data, SIZE size)
318{
319 static_assert(sizeof(CHAR) == 1);
320 return {
321 reinterpret_cast<std::byte const *>(data),
322 check_cast<std::size_t>(size, "binary data size")};
323}
324
325
326// C++20: constinit.
328constexpr oid oid_none{0};
329} // namespace pqxx
330
331
333
342namespace pqxx::internal
343{
344using namespace std::literals;
345
346
348
352template<typename CHAR> bool is_digit(CHAR c)
353{
354 return (c >= '0') and (c <= '9');
355}
356
357
359
361[[nodiscard]] std::string
362describe_object(std::string_view class_name, std::string_view name);
363
364
366
378 void const *old_guest, std::string_view old_class, std::string_view old_name,
379 void const *new_guest, std::string_view new_class,
380 std::string_view new_name);
381
382
384
388 void const *old_guest, std::string_view old_class, std::string_view old_name,
389 void const *new_guest, std::string_view new_class,
390 std::string_view new_name);
391
392
394
397constexpr std::size_t size_esc_bin(std::size_t binary_bytes) noexcept
398{
399 return 2 + (2 * binary_bytes) + 1;
400}
401
402
404
406constexpr std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept
407{
408 return (escaped_bytes - 2) / 2;
409}
410
411
412// TODO: Use actual binary type for "data".
414
419void PQXX_LIBEXPORT
420esc_bin(std::basic_string_view<std::byte> binary_data, char buffer[]) noexcept;
421
422
424std::string PQXX_LIBEXPORT
425esc_bin(std::basic_string_view<std::byte> binary_data);
426
427
429void PQXX_LIBEXPORT
430unesc_bin(std::string_view escaped_data, std::byte buffer[]);
431
432
434std::basic_string<std::byte>
435 PQXX_LIBEXPORT unesc_bin(std::string_view escaped_data);
436
437
439template<typename T> auto ssize(T const &c)
440{
441#if defined(__cpp_lib_ssize) && __cplusplus >= __cpp_lib_ssize
442 return std::ssize(c);
443#else
444 using signed_t = std::make_signed_t<decltype(std::size(c))>;
445 return static_cast<signed_t>(std::size(c));
446#endif // __cpp_lib_ssize
447}
448
449
451
454void PQXX_LIBEXPORT wait_for(unsigned int microseconds);
455} // namespace pqxx::internal
456#endif
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:23
void ignore_unused(T &&...)
Suppress compiler warning about an unused item.
Definition: util.hxx:128
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:87
std::basic_string_view< std::byte > binary_cast(TYPE const &data)
Cast binary data to a type that libpqxx will recognise as binary.
Definition: util.hxx:289
thread_safety_model describe_thread_safety()
Describe thread safety available in this build.
Definition: util.cxx:54
void check_version()
Definition: util.hxx:221
decltype(*std::begin(std::declval< CONTAINER >())) value_type
The type of a container's elements.
Definition: types.hxx:103
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:328
TO check_cast(FROM value, std::string_view description)
Cast a numeric value to another type, or throw if it underflows/overflows.
Definition: util.hxx:136
Internal items for libpqxx' own use. Do not use these yourself.
Definition: composite.hxx:80
void unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition: util.cxx:179
constexpr bool cmp_greater_equal(LEFT lhs, RIGHT rhs)
C++20 std::cmp_greater_equal, or workaround if not available.
Definition: util.hxx:97
int PQXX_VERSION_CHECK() noexcept
Library version check stub.
Definition: version.cxx:18
void esc_bin(std::basic_string_view< std::byte > binary_data, char buffer[]) noexcept
Hex-escape binary data into a buffer.
Definition: util.cxx:148
constexpr std::size_t size_esc_bin(std::size_t binary_bytes) noexcept
Compute buffer size needed to escape binary data for use as a BYTEA.
Definition: util.hxx:397
void check_unique_unregister(void const *old_guest, std::string_view old_class, std::string_view old_name, void const *new_guest, std::string_view new_class, std::string_view new_name)
Like check_unique_register, but for un-registering a guest.
Definition: util.cxx:99
void wait_for(unsigned int microseconds)
Wait.
Definition: util.cxx:218
constexpr bool cmp_greater(LEFT lhs, RIGHT rhs)
C++20 std::cmp_greater, or workaround if not available.
Definition: util.hxx:71
constexpr bool cmp_less(LEFT lhs, RIGHT rhs)
C++20 std::cmp_less, or workaround if not available.
Definition: util.hxx:53
void check_unique_register(void const *old_guest, std::string_view old_class, std::string_view old_name, void const *new_guest, std::string_view new_class, std::string_view new_name)
Check validity of registering a new "guest" in a "host.".
Definition: util.cxx:82
std::string describe_object(std::string_view class_name, std::string_view name)
Describe an object for humans, based on class name and optional name.
Definition: util.cxx:72
std::string cat2(std::string_view x, std::string_view y)
Efficiently concatenate two strings.
Definition: util.hxx:111
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:439
bool is_digit(CHAR c)
A safer and more generic replacement for std::isdigit.
Definition: util.hxx:352
constexpr bool cmp_less_equal(LEFT lhs, RIGHT rhs)
C++20 std::cmp_less_equal, or workaround if not available.
Definition: util.hxx:84
constexpr std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept
Compute binary size from the size of its escaped version.
Definition: util.hxx:406
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:190
Descriptor of library's thread-safety model.
Definition: util.hxx:242
std::string description
A human-readable description of any thread-safety issues.
Definition: util.hxx:256