libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
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-2024, 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#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 <numeric>
20
21#include "pqxx/strconv.hxx"
22
23// C++20: Simplify using std::ranges::range.
24// C++20: Optimise buffer allocation using random_access_range/iterator.
25// C++23: Use std::join_with().
26// TODO: Or just use std formatting?
27// TODO: Can we pass separators at compile time?
28namespace pqxx
29{
34
36
44template<typename ITER, typename ACCESS>
45[[nodiscard]] inline std::string
46separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access)
47{
48 if (end == begin)
49 return {};
50 auto next{begin};
51 ++next;
52 if (next == end)
53 return to_string(access(begin));
54
55 // From here on, we've got at least 2 elements -- meaning that we need sep.
56 using elt_type = strip_t<decltype(access(begin))>;
57 using traits = string_traits<elt_type>;
58
59 std::size_t budget{0};
60 for (ITER cnt{begin}; cnt != end; ++cnt)
61 budget += traits::size_buffer(access(cnt));
62 budget +=
63 static_cast<std::size_t>(std::distance(begin, end)) * std::size(sep);
64
65 std::string result;
66 result.resize(budget);
67
68 char *const data{result.data()};
69 char *here{data};
70 char *stop{data + budget};
71 here = traits::into_buf(here, stop, access(begin)) - 1;
72 for (++begin; begin != end; ++begin)
73 {
74 here += sep.copy(here, std::size(sep));
75 here = traits::into_buf(here, stop, access(begin)) - 1;
76 }
77 result.resize(static_cast<std::size_t>(here - data));
78 return result;
79}
80
81
83template<typename ITER>
84[[nodiscard]] inline std::string
85separated_list(std::string_view sep, ITER begin, ITER end)
86{
87 return separated_list(sep, begin, end, [](ITER i) { return *i; });
88}
89
90
91// C++20: Use a concept.
93template<typename CONTAINER>
94[[nodiscard]] inline auto
95separated_list(std::string_view sep, CONTAINER const &c)
96 /*
97 Always std::string; necessary because SFINAE doesn't work with the
98 contents of function bodies, so the check for iterability has to be in
99 the signature.
100 */
101 -> typename std::enable_if<
102 (not std::is_void<decltype(std::begin(c))>::value and
103 not std::is_void<decltype(std::end(c))>::value),
104 std::string>::type
105{
106 return separated_list(sep, std::begin(c), std::end(c));
107}
108
109
111template<
112 typename TUPLE, std::size_t INDEX = 0, typename ACCESS,
113 typename std::enable_if<
114 (INDEX == std::tuple_size<TUPLE>::value - 1), int>::type = 0>
115[[nodiscard]] inline std::string separated_list(
116 std::string_view /* sep */, TUPLE const &t, ACCESS const &access)
117{
118 return to_string(access(&std::get<INDEX>(t)));
119}
120
121template<
122 typename TUPLE, std::size_t INDEX = 0, typename ACCESS,
123 typename std::enable_if<
124 (INDEX < std::tuple_size<TUPLE>::value - 1), int>::type = 0>
125[[nodiscard]] inline std::string
126separated_list(std::string_view sep, TUPLE const &t, ACCESS const &access)
127{
128 std::string out{to_string(access(&std::get<INDEX>(t)))};
129 out.append(sep);
130 out.append(separated_list<TUPLE, INDEX + 1>(sep, t, access));
131 return out;
132}
133
134template<
135 typename TUPLE, std::size_t INDEX = 0,
136 typename std::enable_if<
137 (INDEX <= std::tuple_size<TUPLE>::value), int>::type = 0>
138[[nodiscard]] inline std::string
139separated_list(std::string_view sep, TUPLE const &t)
140{
141 // TODO: Optimise allocation.
142 return separated_list(sep, t, [](TUPLE const &tup) { return *tup; });
143}
145} // namespace pqxx
146#endif
Result set containing data returned by a query or command.
Definition result.hxx:73
The home of all libpqxx classes, functions, templates, etc.
Definition array.cxx:27
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:46
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition types.hxx:78
Traits class for use in string conversions.
Definition strconv.hxx:153