libpqxx  7.8.1
strconv.hxx
1 /* String conversion definitions.
2  *
3  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead.
4  *
5  * Copyright (c) 2000-2023, 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_STRCONV
12 #define PQXX_H_STRCONV
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <algorithm>
19 #include <cstring>
20 #include <limits>
21 #include <sstream>
22 #include <stdexcept>
23 #include <typeinfo>
24 
25 #if __has_include(<charconv>)
26 # include <charconv>
27 #endif
28 
29 #if defined(PQXX_HAVE_RANGES) && __has_include(<ranges>)
30 # include <ranges>
31 #endif
32 
33 #include "pqxx/except.hxx"
34 #include "pqxx/util.hxx"
35 #include "pqxx/zview.hxx"
36 
37 
38 namespace pqxx::internal
39 {
41 PQXX_LIBEXPORT std::string demangle_type_name(char const[]);
42 } // namespace pqxx::internal
43 
44 
45 namespace pqxx
46 {
71 
73 
81 template<typename TYPE>
82 std::string const type_name{internal::demangle_type_name(typeid(TYPE).name())};
83 
84 
86 
92 template<typename TYPE, typename ENABLE = void> struct nullness
93 {
95  static bool has_null;
96 
98  static bool always_null;
99 
101  static bool is_null(TYPE const &value);
102 
104 
109  [[nodiscard]] static TYPE null();
110 };
111 
112 
114 template<typename TYPE> struct no_null
115 {
117 
127  static constexpr bool has_null = false;
128 
130 
133  static constexpr bool always_null = false;
134 
136 
140  [[nodiscard]] static constexpr bool is_null(TYPE const &) noexcept
141  {
142  return false;
143  }
144 };
145 
146 
148 
154 template<typename TYPE> struct string_traits
155 {
157 
160  static constexpr bool converts_to_string{false};
161 
163 
166  static constexpr bool converts_from_string{false};
167 
169 
188  [[nodiscard]] static inline zview
189  to_buf(char *begin, char *end, TYPE const &value);
190 
192  /* @warning A null value has no string representation. Do not pass a null.
193  *
194  * Writes value's string representation into the buffer, starting exactly at
195  * @c begin, and ensuring a trailing zero. Returns the address just beyond
196  * the trailing zero, so the caller could use it as the @c begin for another
197  * call to @c into_buf writing a next value.
198  */
199  static inline char *into_buf(char *begin, char *end, TYPE const &value);
200 
202 
207  [[nodiscard]] static inline TYPE from_string(std::string_view text);
208 
209  // C++20: Can we make these all constexpr?
211 
215  [[nodiscard]] static inline std::size_t
216  size_buffer(TYPE const &value) noexcept;
217 
218  // TODO: Move is_unquoted_string into the traits after all?
219 };
220 
221 
223 
239 template<typename TYPE> [[noreturn]] void oops_forbidden_conversion() noexcept;
240 
241 
243 
248 template<typename TYPE> struct forbidden_conversion
249 {
250  static constexpr bool converts_to_string{false};
251  static constexpr bool converts_from_string{false};
252  [[noreturn]] static zview to_buf(char *, char *, TYPE const &)
253  {
254  oops_forbidden_conversion<TYPE>();
255  }
256  [[noreturn]] static char *into_buf(char *, char *, TYPE const &)
257  {
258  oops_forbidden_conversion<TYPE>();
259  }
260  [[noreturn]] static TYPE from_string(std::string_view)
261  {
262  oops_forbidden_conversion<TYPE>();
263  }
264  [[noreturn]] static std::size_t size_buffer(TYPE const &) noexcept
265  {
266  oops_forbidden_conversion<TYPE>();
267  }
268 };
269 
270 
272 
288 template<> struct string_traits<char> : forbidden_conversion<char>
289 {};
290 
291 
293 
307 template<>
308 struct string_traits<unsigned char> : forbidden_conversion<unsigned char>
309 {};
310 
311 
313 
327 template<>
328 struct string_traits<signed char> : forbidden_conversion<signed char>
329 {};
330 
331 
333 
338 template<> struct string_traits<std::byte> : forbidden_conversion<std::byte>
339 {};
340 
341 
343 template<typename ENUM>
344 struct nullness<ENUM, std::enable_if_t<std::is_enum_v<ENUM>>> : no_null<ENUM>
345 {};
346 
347 
348 // C++20: Concepts for "converts from string" & "converts to string."
349 } // namespace pqxx
350 
351 
352 namespace pqxx::internal
353 {
355 
364 template<typename ENUM> struct enum_traits
365 {
366  using impl_type = std::underlying_type_t<ENUM>;
368 
369  static constexpr bool converts_to_string{true};
370  static constexpr bool converts_from_string{true};
371 
372  [[nodiscard]] static constexpr zview
373  to_buf(char *begin, char *end, ENUM const &value)
374  {
375  return impl_traits::to_buf(begin, end, to_underlying(value));
376  }
377 
378  static constexpr char *into_buf(char *begin, char *end, ENUM const &value)
379  {
380  return impl_traits::into_buf(begin, end, to_underlying(value));
381  }
382 
383  [[nodiscard]] static ENUM from_string(std::string_view text)
384  {
385  return static_cast<ENUM>(impl_traits::from_string(text));
386  }
387 
388  [[nodiscard]] static std::size_t size_buffer(ENUM const &value) noexcept
389  {
390  return impl_traits::size_buffer(to_underlying(value));
391  }
392 
393 private:
394  // C++23: Replace with std::to_underlying.
395  static constexpr impl_type to_underlying(ENUM const &value) noexcept
396  {
397  return static_cast<impl_type>(value);
398  }
399 };
400 } // namespace pqxx::internal
401 
402 
403 // We used to inline type_name<ENUM>, but this triggered a "double free" error
404 // on program exit, when libpqxx was built as a shared library on Debian with
405 // gcc 12.
406 
408 
419 #define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
420  template<> struct string_traits<ENUM> : pqxx::internal::enum_traits<ENUM> \
421  {}; \
422  template<> inline std::string_view const type_name<ENUM> \
423  { \
424 # ENUM \
425  }
426 
427 
428 namespace pqxx
429 {
431 
443 template<typename TYPE>
444 [[nodiscard]] inline TYPE from_string(std::string_view text)
445 {
447 }
448 
449 
451 
457 template<>
458 [[nodiscard]] inline std::string_view from_string(std::string_view text)
459 {
460  return text;
461 }
462 
463 
465 
472 template<typename T> inline void from_string(std::string_view text, T &value)
473 {
474  value = from_string<T>(text);
475 }
476 
477 
479 
484 template<typename TYPE> inline std::string to_string(TYPE const &value);
485 
486 
488 
495 template<typename... TYPE>
496 [[nodiscard]] inline std::vector<std::string_view>
497 to_buf(char *here, char const *end, TYPE... value)
498 {
499  return {[&here, end](auto v) {
500  auto begin = here;
501  here = string_traits<decltype(v)>::into_buf(begin, end, v);
502  // Exclude the trailing zero out of the string_view.
503  auto len{static_cast<std::size_t>(here - begin) - 1};
504  return std::string_view{begin, len};
505  }(value)...};
506 }
507 
509 
512 template<typename TYPE>
513 inline void into_string(TYPE const &value, std::string &out);
514 
515 
517 template<typename TYPE>
518 [[nodiscard]] inline constexpr bool is_null(TYPE const &value) noexcept
519 {
520  return nullness<strip_t<TYPE>>::is_null(value);
521 }
522 
523 
525 
528 template<typename... TYPE>
529 [[nodiscard]] inline std::size_t size_buffer(TYPE const &...value) noexcept
530 {
531  return (string_traits<strip_t<TYPE>>::size_buffer(value) + ...);
532 }
533 
534 
536 
542 template<typename TYPE> inline constexpr bool is_sql_array{false};
543 
544 
546 
558 template<typename TYPE> inline constexpr bool is_unquoted_safe{false};
559 
560 
562 template<typename T> inline constexpr char array_separator{','};
563 
564 
566 
573 template<typename TYPE> inline constexpr format param_format(TYPE const &)
574 {
575  return format::text;
576 }
577 
578 
580 
589 template<typename TYPE>
590 inline zview generic_to_buf(char *begin, char *end, TYPE const &value)
591 {
592  using traits = string_traits<TYPE>;
593  // The trailing zero does not count towards the zview's size, so subtract 1
594  // from the result we get from into_buf().
595  if (is_null(value))
596  return {};
597  else
598  return {begin, traits::into_buf(begin, end, value) - begin - 1};
599 }
600 
601 
602 #if defined(PQXX_HAVE_CONCEPTS)
603 
610 template<class TYPE>
611 concept binary = std::ranges::contiguous_range<TYPE> and
612  std::is_same_v<strip_t<value_type<TYPE>>, std::byte>;
613 #endif
614 
615 } // namespace pqxx
616 
617 
618 #include "pqxx/internal/conversions.hxx"
619 #endif
static TYPE from_string(std::string_view text)
Parse a string representation of a TYPE value.
Definition: strconv.cxx:740
static char * into_buf(char *, char *, TYPE const &)
Definition: strconv.hxx:256
Traits class for use in string conversions.
Definition: strconv.hxx:154
static constexpr bool always_null
Are all values of this type null?
Definition: strconv.hxx:133
static constexpr char * into_buf(char *begin, char *end, ENUM const &value)
Definition: strconv.hxx:378
void into_string(TYPE const &value, std::string &out)
Convert a value to a readable string that PostgreSQL will understand.
Internal items for libpqxx' own use. Do not use these yourself.
Definition: composite.hxx:83
constexpr bool is_sql_array
Does this type translate to an SQL array?
Definition: strconv.hxx:542
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:32
static bool is_null(TYPE const &value)
Is value a null?
static constexpr bool converts_from_string
Definition: strconv.hxx:370
constexpr bool is_unquoted_safe
Can we use this type in arrays and composite types without quoting them?
Definition: strconv.hxx:558
constexpr char array_separator
Element separator between SQL array elements of this type.
Definition: strconv.hxx:562
static bool always_null
Is this type always null?
Definition: strconv.hxx:98
std::underlying_type_t< ENUM > impl_type
Definition: strconv.hxx:366
static std::size_t size_buffer(TYPE const &value) noexcept
Estimate how much buffer space is needed to represent value.
Traits describing a type's "null value," if any.
Definition: strconv.hxx:92
static std::size_t size_buffer(ENUM const &value) noexcept
Definition: strconv.hxx:388
STL namespace.
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
static constexpr zview to_buf(char *begin, char *end, ENUM const &value)
Definition: strconv.hxx:373
std::string const type_name
A human-readable name for a type, used in error messages and such.
Definition: strconv.hxx:82
std::remove_cv_t< std::remove_reference_t< TYPE >> strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:91
zview generic_to_buf(char *begin, char *end, TYPE const &value)
Implement string_traits::to_buf by calling into_buf.
Definition: strconv.hxx:590
T from_string(field const &value)
Convert a field's value to type T.
Definition: field.hxx:520
static constexpr bool is_null(TYPE const &) noexcept
Does a given value correspond to an SQL null value?
Definition: strconv.hxx:140
static constexpr bool converts_from_string
Is conversion from string_view to TYPE supported?
Definition: strconv.hxx:166
static ENUM from_string(std::string_view text)
Definition: strconv.hxx:383
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.
static std::size_t size_buffer(TYPE const &) noexcept
Definition: strconv.hxx:264
String traits for a forbidden type conversion.
Definition: strconv.hxx:248
constexpr format param_format(TYPE const &)
What's the preferred format for passing non-null parameters of this type?
Definition: strconv.hxx:573
std::string demangle_type_name(char const [])
Attempt to demangle std::type_info::name() to something human-readable.
Definition: strconv.cxx:230
static bool has_null
Does this type have a null value?
Definition: strconv.hxx:95
static TYPE from_string(std::string_view)
Definition: strconv.hxx:260
format
Format code: is data text or binary?
Definition: types.hxx:80
Helper class for defining enum conversions.
Definition: strconv.hxx:364
static TYPE null()
Return a null value.
static constexpr bool converts_to_string
Is conversion from TYPE to strings supported?
Definition: strconv.hxx:160
std::vector< std::string_view > to_buf(char *here, char const *end, TYPE...value)
Convert multiple values to strings inside a single buffer.
Definition: strconv.hxx:497
static constexpr bool has_null
Does TYPE have a "built-in null value"?
Definition: strconv.hxx:127
std::size_t size_buffer(TYPE const &...value) noexcept
Estimate how much buffer space is needed to represent values as a string.
Definition: strconv.hxx:529
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:549
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:518
void oops_forbidden_conversion() noexcept
Nonexistent function to indicate a disallowed type conversion.
static zview to_buf(char *, char *, TYPE const &)
Definition: strconv.hxx:252
static zview to_buf(char *begin, char *end, TYPE const &value)
Return a string_view representing value, plus terminating zero.
static constexpr bool converts_to_string
Definition: strconv.hxx:369
Nullness traits describing a type which does not have a null value.
Definition: strconv.hxx:114