libpqxx  7.7.0
separated_list.hxx
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-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_SEPARATED_LIST
12 #define PQXX_H_SEPARATED_LIST
13 
14 #include <algorithm>
15 #include <numeric>
16 
17 #include "pqxx/strconv.hxx"
18 
19 // C++20: Simplify using std::ranges::range.
20 // C++20: Optimise buffer allocation using random_access_range/iterator.
21 namespace pqxx
22 {
27 
29 
37 template<typename ITER, typename ACCESS>
38 [[nodiscard]] inline std::string
39 separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access)
40 {
41  if (end == begin)
42  return {};
43  auto next{begin};
44  ++next;
45  if (next == end)
46  return to_string(access(begin));
47 
48  // From here on, we've got at least 2 elements -- meaning that we need sep.
49  using elt_type = strip_t<decltype(access(begin))>;
50  using traits = string_traits<elt_type>;
51 
52  std::size_t budget{0};
53  for (ITER cnt{begin}; cnt != end; ++cnt)
54  budget += traits::size_buffer(access(cnt));
55  budget +=
56  static_cast<std::size_t>(std::distance(begin, end)) * std::size(sep);
57 
58  std::string result;
59  result.resize(budget);
60 
61  char *const data{result.data()};
62  char *here{data};
63  char *stop{data + budget};
64  here = traits::into_buf(here, stop, access(begin)) - 1;
65  for (++begin; begin != end; ++begin)
66  {
67  here += sep.copy(here, std::size(sep));
68  here = traits::into_buf(here, stop, access(begin)) - 1;
69  }
70  result.resize(static_cast<std::size_t>(here - data));
71  return result;
72 }
73 
74 
76 template<typename ITER>
77 [[nodiscard]] inline std::string
78 separated_list(std::string_view sep, ITER begin, ITER end)
79 {
80  return separated_list(sep, begin, end, [](ITER i) { return *i; });
81 }
82 
83 
85 template<typename CONTAINER>
86 [[nodiscard]] inline auto
87 separated_list(std::string_view sep, CONTAINER const &c)
88  /*
89  Always std::string; necessary because SFINAE doesn't work with the
90  contents of function bodies, so the check for iterability has to be in
91  the signature.
92  */
93  -> typename std::enable_if<
94  (not std::is_void<decltype(std::begin(c))>::value and
95  not std::is_void<decltype(std::end(c))>::value),
96  std::string>::type
97 {
98  return separated_list(sep, std::begin(c), std::end(c));
99 }
100 
101 
103 template<
104  typename TUPLE, std::size_t INDEX = 0, typename ACCESS,
105  typename std::enable_if<
106  (INDEX == std::tuple_size<TUPLE>::value - 1), int>::type = 0>
107 [[nodiscard]] inline std::string separated_list(
108  std::string_view /* sep */, TUPLE const &t, ACCESS const &access)
109 {
110  return to_string(access(&std::get<INDEX>(t)));
111 }
112 
113 template<
114  typename TUPLE, std::size_t INDEX = 0, typename ACCESS,
115  typename std::enable_if<
116  (INDEX < std::tuple_size<TUPLE>::value - 1), int>::type = 0>
117 [[nodiscard]] inline std::string
118 separated_list(std::string_view sep, TUPLE const &t, ACCESS const &access)
119 {
120  std::string out{to_string(access(&std::get<INDEX>(t)))};
121  out.append(sep);
122  out.append(separated_list<TUPLE, INDEX + 1>(sep, t, access));
123  return out;
124 }
125 
126 template<
127  typename TUPLE, std::size_t INDEX = 0,
128  typename std::enable_if<
129  (INDEX <= std::tuple_size<TUPLE>::value), int>::type = 0>
130 [[nodiscard]] inline std::string
131 separated_list(std::string_view sep, TUPLE const &t)
132 {
133  // TODO: Optimise allocation.
134  return separated_list(sep, t, [](TUPLE const &tup) { return *tup; });
135 }
137 } // namespace pqxx
138 #endif
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
Result set containing data returned by a query or command.
Definition: result.hxx:67
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:375
std::string separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access)
Represent sequence of values as a string, joined by a given separator.
Definition: separated_list.hxx:39
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:22
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:528
Traits class for use in string conversions.
Definition: strconv.hxx:152