libpqxx
The C++ client library for PostgreSQL
separated_list.hxx
Go to the documentation of this file.
1 /* Helper similar to Python's `str.join()`.
2  *
3  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/separated_list instead.
4  *
5  * Copyright (c) 2000-2026, 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_SEPARATED_LIST_HXX
12 #define PQXX_SEPARATED_LIST_HXX
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <numeric>
19 
20 #include "pqxx/strconv.hxx"
21 
22 // TODO: Optimise buffer allocation using random_access_range/iterator.
23 // C++23: Use std::ranges::views::join_with()?
24 namespace pqxx
25 {
30 
32 
40 template<std::forward_iterator ITER, typename ACCESS>
41 [[nodiscard]] inline std::string separated_list(
42  std::string_view sep, ITER begin, ITER end, ACCESS access, ctx c = {})
43 {
44  if (end == begin)
45  return {};
46  auto next{begin};
47  ++next;
48  if (next == end)
49  return to_string(access(begin), c);
50 
51  // From here on, we've got at least 2 elements -- meaning that we need sep.
52 
53  std::size_t budget{0};
54  for (ITER cnt{begin}; cnt != end; ++cnt)
55  budget += pqxx::size_buffer(access(cnt));
56  budget +=
57  static_cast<std::size_t>(std::distance(begin, end)) * std::size(sep);
58 
59  std::string result;
60  result.resize(budget);
61 
62  char *const data{result.data()};
63  char *stop{data + budget};
64  std::size_t here{pqxx::into_buf({data, stop}, access(begin))};
65  for (++begin; begin != end; ++begin)
66  {
67  here = pqxx::internal::copy_chars<false>(sep, result, here, sl::current());
68  here += pqxx::into_buf({data + here, stop}, access(begin));
69  }
70  result.resize(here);
71  return result;
72 }
73 
74 
76 template<std::forward_iterator ITER>
77 [[nodiscard]] inline std::string
78 separated_list(std::string_view sep, ITER begin, ITER end, ctx c = {})
79 {
80  return separated_list(sep, begin, end, [](ITER i) { return *i; }, c);
81 }
82 
83 
85 template<std::ranges::range CONTAINER>
86 [[nodiscard]] inline std::string
87 separated_list(std::string_view sep, CONTAINER &&con, ctx c = {})
88 {
89  return separated_list(sep, std::begin(con), std::end(con), c);
90 }
91 
92 
94 template<typename TUPLE, std::size_t INDEX = 0, typename ACCESS>
95 [[nodiscard]] inline std::string separated_list(
96  std::string_view sep, TUPLE const &t, ACCESS const &access, ctx c = {})
97 {
98  std::string out{to_string(access(&std::get<INDEX>(t)), c)};
99  if constexpr (INDEX < std::tuple_size<TUPLE>::value - 1)
100  {
101  out.append(sep);
102  out.append(separated_list<TUPLE, INDEX + 1>(sep, t, access, c));
103  }
104  return out;
105 }
106 
107 template<typename TUPLE, std::size_t INDEX = 0>
108 [[nodiscard]] inline std::string
109 separated_list(std::string_view sep, TUPLE const &t, ctx c = {})
110 {
111  return separated_list(sep, t, [](TUPLE const &tup) { return *tup; }, c);
112 }
114 } // namespace pqxx
115 #endif
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
PQXX_LIBEXPORT std::string to_string(field_ref const &value, ctx)
Convert a field_ref to a string.
Definition: field.hxx:891
constexpr 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:399
std::string separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access, ctx c={})
Represent sequence of values as a string, joined by a given separator.
Definition: separated_list.hxx:41
std::size_t into_buf(std::span< char > buf, TYPE const &value, ctx c={})
Write an SQL representation of value into buf.
Definition: strconv.hxx:454
conversion_context const & ctx
Convenience alias: const reference to a pqxx::conversion_context.
Definition: strconv.hxx:201