libpqxx  7.6.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-2021, 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 "pqxx/compiler-public.hxx"
15 #include "pqxx/internal/compiler-internal-pre.hxx"
16 
17 #include <cctype>
18 #include <cstdio>
19 #include <functional>
20 #include <iterator>
21 #include <limits>
22 #include <memory>
23 #include <stdexcept>
24 #include <string>
25 #include <string_view>
26 #include <type_traits>
27 #include <typeinfo>
28 #include <vector>
29 
30 #if __has_include(<version>)
31 # include <version>
32 #endif
33 
34 #include "pqxx/except.hxx"
35 #include "pqxx/internal/encodings.hxx"
36 #include "pqxx/types.hxx"
37 #include "pqxx/version.hxx"
38 
39 
41 namespace pqxx
42 {}
43 
44 #include <pqxx/internal/libpq-forward.hxx>
45 
46 
48 namespace pqxx::internal
49 {
51 
54 [[nodiscard]] inline std::string cat2(std::string_view x, std::string_view y)
55 {
56  std::string buf;
57  auto const xs{std::size(x)}, ys{std::size(y)};
58  buf.resize(xs + ys);
59  x.copy(std::data(buf), xs);
60  y.copy(std::data(buf) + xs, ys);
61  return buf;
62 }
63 } // namespace pqxx::internal
64 
65 
66 namespace pqxx
67 {
68 using namespace std::literals;
69 
71 template<typename... T> inline void ignore_unused(T &&...) {}
72 
73 
75 
78 template<typename TO, typename FROM>
79 inline TO check_cast(FROM value, std::string_view description)
80 {
81  static_assert(std::is_arithmetic_v<FROM>);
82  static_assert(std::is_arithmetic_v<TO>);
83  static_assert(std::is_integral_v<FROM> == std::is_integral_v<TO>);
84 
85  // The rest of this code won't quite work for bool, but bool is trivially
86  // convertible to other arithmetic types as far as I can see.
87  if constexpr (std::is_same_v<FROM, bool>)
88  return static_cast<TO>(value);
89 
90  // Depending on our "if constexpr" conditions, this parameter may not be
91  // needed. Some compilers will warn.
92  ignore_unused(description);
93 
94  using from_limits = std::numeric_limits<decltype(value)>;
95  using to_limits = std::numeric_limits<TO>;
96  if constexpr (std::is_signed_v<FROM>)
97  {
98  if constexpr (std::is_signed_v<TO>)
99  {
100  if (value < to_limits::lowest())
101  throw range_error{internal::cat2("Cast underflow: "sv, description)};
102  }
103  else
104  {
105  // FROM is signed, but TO is not. Treat this as a special case, because
106  // there may not be a good broader type in which the compiler can even
107  // perform our check.
108  if (value < 0)
110  "Casting negative value to unsigned type: "sv, description)};
111  }
112  }
113  else
114  {
115  // No need to check: the value is unsigned so can't fall below the range
116  // of the TO type.
117  }
118 
119  if constexpr (std::is_integral_v<FROM>)
120  {
121  using unsigned_from = std::make_unsigned_t<FROM>;
122  using unsigned_to = std::make_unsigned_t<TO>;
123  constexpr auto from_max{static_cast<unsigned_from>((from_limits::max)())};
124  constexpr auto to_max{static_cast<unsigned_to>((to_limits::max)())};
125  if constexpr (from_max > to_max)
126  {
127  if (static_cast<unsigned_from>(value) > to_max)
128  throw range_error{internal::cat2("Cast overflow: "sv, description)};
129  }
130  }
131  else if constexpr ((from_limits::max)() > (to_limits::max)())
132  {
133  if (value > (to_limits::max)())
134  throw range_error{internal::cat2("Cast overflow: ", description)};
135  }
136 
137  return static_cast<TO>(value);
138 }
139 
140 
162 inline PQXX_PRIVATE void check_version()
163 {
164  // There is no particular reason to do this here in @c connection, except
165  // to ensure that every meaningful libpqxx client will execute it. The call
166  // must be in the execution path somewhere or the compiler won't try to link
167  // it. We can't use it to initialise a global or class-static variable,
168  // because a smart compiler might resolve it at compile time.
169  //
170  // On the other hand, we don't want to make a useless function call too
171  // often for performance reasons. A local static variable is initialised
172  // only on the definition's first execution. Compilers will be well
173  // optimised for this behaviour, so there's a minimal one-time cost.
174  static auto const version_ok{internal::PQXX_VERSION_CHECK()};
175  ignore_unused(version_ok);
176 }
177 
178 
180 
182 struct PQXX_LIBEXPORT thread_safety_model
183 {
185  bool safe_libpq = false;
186 
188 
194  bool safe_kerberos = false;
195 
197  std::string description;
198 };
199 
200 
202 [[nodiscard]] PQXX_LIBEXPORT thread_safety_model describe_thread_safety();
203 
204 
205 #if defined(PQXX_HAVE_CONCEPTS)
206 # define PQXX_POTENTIAL_BINARY_ARG pqxx::potential_binary
207 #else
208 # define PQXX_POTENTIAL_BINARY_ARG typename
209 #endif
210 
212 
229 template<PQXX_POTENTIAL_BINARY_ARG TYPE>
230 std::basic_string_view<std::byte> binary_cast(TYPE const &data)
231 {
232  static_assert(sizeof(value_type<TYPE>) == 1);
233  return std::basic_string_view<std::byte>{
234  reinterpret_cast<std::byte const *>(
235  const_cast<strip_t<decltype(*std::data(data))> const *>(
236  std::data(data))),
237  std::size(data)};
238 }
239 
240 
241 #if defined(PQXX_HAVE_CONCEPTS)
242 template<typename CHAR>
243 concept char_sized = (sizeof(CHAR) == 1);
244 # define PQXX_CHAR_SIZED_ARG char_sized
245 #else
246 # define PQXX_CHAR_SIZED_ARG typename
247 #endif
248 
250 
257 template<PQXX_CHAR_SIZED_ARG CHAR, typename SIZE>
258 std::basic_string_view<std::byte> binary_cast(CHAR const *data, SIZE size)
259 {
260  static_assert(sizeof(CHAR) == 1);
261  return std::basic_string_view<std::byte>{
262  reinterpret_cast<std::byte const *>(data),
263  check_cast<std::size_t>(size, "binary data size")};
264 }
265 
266 
268 constexpr oid oid_none{0};
269 } // namespace pqxx
270 
271 
273 
282 namespace pqxx::internal
283 {
284 using namespace std::literals;
285 
286 
288 
290 [[nodiscard]] std::string
291 describe_object(std::string_view class_name, std::string_view name);
292 
293 
295 
307  void const *old_guest, std::string_view old_class, std::string_view old_name,
308  void const *new_guest, std::string_view new_class,
309  std::string_view new_name);
310 
311 
313 
317  void const *old_guest, std::string_view old_class, std::string_view old_name,
318  void const *new_guest, std::string_view new_class,
319  std::string_view new_name);
320 
321 
323 
326 constexpr std::size_t size_esc_bin(std::size_t binary_bytes) noexcept
327 {
328  return 2 + (2 * binary_bytes) + 1;
329 }
330 
331 
333 
335 constexpr std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept
336 {
337  return (escaped_bytes - 2) / 2;
338 }
339 
340 
341 // TODO: Use actual binary type for "data".
343 
348 void PQXX_LIBEXPORT
349 esc_bin(std::basic_string_view<std::byte> binary_data, char buffer[]) noexcept;
350 
351 
353 std::string PQXX_LIBEXPORT
354 esc_bin(std::basic_string_view<std::byte> binary_data);
355 
356 
358 void PQXX_LIBEXPORT
359 unesc_bin(std::string_view escaped_data, std::byte buffer[]);
360 
361 
363 std::basic_string<std::byte>
364  PQXX_LIBEXPORT unesc_bin(std::string_view escaped_data);
365 
366 
368 template<typename T> auto ssize(T const &c)
369 {
370 #if defined(__cpp_lib_ssize) && __cplusplus >= __cpp_lib_ssize
371  return std::ssize(c);
372 #else
373  using signed_t = std::make_signed_t<decltype(std::size(c))>;
374  return static_cast<signed_t>(std::size(c));
375 #endif // __cpp_lib_ssize
376 }
377 
378 
380 
383 void PQXX_LIBEXPORT wait_for(unsigned int microseconds);
384 } // namespace pqxx::internal
385 
386 #include "pqxx/internal/compiler-internal-post.hxx"
387 #endif
decltype(*std::begin(std::declval< CONTAINER >())) value_type
The type of a container&#39;s elements.
Definition: types.hxx:103
int PQXX_VERSION_CHECK() noexcept
Library version check stub.
Definition: version.cxx:18
std::string description
A human-readable description of any thread-safety issues.
Definition: util.hxx:197
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:368
thread_safety_model describe_thread_safety()
Describe thread safety available in this build.
Definition: util.cxx:52
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
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:79
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
void esc_bin(std::basic_string_view< std::byte > binary_data, char buffer[]) noexcept
Hex-escape binary data into a buffer.
Definition: util.cxx:145
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:192
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:268
void check_version()
Definition: util.hxx:162
void unesc_bin(std::string_view escaped_data, std::byte buffer[])
Reconstitute binary data from its escaped version.
Definition: util.cxx:176
std::string cat2(std::string_view x, std::string_view y)
Efficiently concatenate two strings.
Definition: util.hxx:54
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:97
void ignore_unused(T &&...)
Suppress compiler warning about an unused item.
Definition: util.hxx:71
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:70
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:230
void wait_for(unsigned int microseconds)
Wait.
Definition: util.cxx:215
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:326
Descriptor of library&#39;s thread-safety model.
Definition: util.hxx:182
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:80
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:335
Internal items for libpqxx&#39; own use. Do not use these yourself.
Definition: composite.hxx:73