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