Skip to content

Commit 399e50e

Browse files
committed
Use C++17 feature constexpr if to simplify pgsql code
Also adds a crucial std::decay_t<> which makes sure this works for all sorts of types.
1 parent ae35b32 commit 399e50e

File tree

2 files changed

+43
-51
lines changed

2 files changed

+43
-51
lines changed

src/pgsql.hpp

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -122,51 +122,6 @@ class pg_result_t
122122
std::unique_ptr<PGresult, pg_result_deleter_t> m_result;
123123
};
124124

125-
// Do not use anonymous namespace in header file
126-
// https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL59-CPP.+Do+not+define+an+unnamed+namespace+in+a+header+file
127-
namespace detail {
128-
129-
/**
130-
* Helper for pg_conn_t::exec_prepared() function. All parameters to
131-
* that function are given to the exec_arg::to_str function which will
132-
* pass through string-like parameters and convert other parameters to
133-
* strings.
134-
*/
135-
template <typename T>
136-
struct exec_arg
137-
{
138-
constexpr static std::size_t const buffers_needed = 1;
139-
static char const *to_str(std::vector<std::string> *data, T param)
140-
{
141-
return data->emplace_back(fmt::to_string(std::forward<T>(param)))
142-
.c_str();
143-
}
144-
};
145-
146-
template <>
147-
struct exec_arg<char const *>
148-
{
149-
constexpr static std::size_t const buffers_needed = 0;
150-
static char const *to_str(std::vector<std::string> * /*data*/,
151-
char const *param) noexcept
152-
{
153-
return param;
154-
}
155-
};
156-
157-
template <>
158-
struct exec_arg<std::string const &>
159-
{
160-
constexpr static std::size_t const buffers_needed = 0;
161-
static char const *to_str(std::vector<std::string> * /*data*/,
162-
std::string const &param) noexcept
163-
{
164-
return param.c_str();
165-
}
166-
};
167-
168-
} // namespace detail
169-
170125
/**
171126
* PostgreSQL connection.
172127
*
@@ -258,6 +213,39 @@ class pg_conn_t
258213
int *param_lengths, int *param_formats,
259214
int result_format) const;
260215

216+
/**
217+
* Helper for pg_conn_t::exec_prepared_with_result_format() function. Used
218+
* to find out how many buffers we need. Must always be in sync with the
219+
* to_str() function below.
220+
*/
221+
template <typename T>
222+
static constexpr std::size_t buffers_needed() noexcept
223+
{
224+
if constexpr (std::is_same_v<T, char const *>) {
225+
return 0;
226+
} else if constexpr (std::is_same_v<T, std::string>) {
227+
return 0;
228+
}
229+
return 1;
230+
}
231+
232+
/**
233+
* Helper for pg_conn_t::exec_prepared_with_result_format() function. All
234+
* parameters to that function are given to the to_str() function which
235+
* will pass through string-like parameters and convert other parameters to
236+
* strings.
237+
*/
238+
template <typename T>
239+
static char const *to_str(std::vector<std::string> *data, T const &param)
240+
{
241+
if constexpr (std::is_same_v<T, char const *>) {
242+
return param;
243+
} else if constexpr (std::is_same_v<T, std::string>) {
244+
return param.c_str();
245+
}
246+
return data->emplace_back(fmt::to_string(param)).c_str();
247+
}
248+
261249
/**
262250
* Run the named prepared SQL statement and return the results.
263251
*
@@ -279,16 +267,16 @@ class pg_conn_t
279267
// so that pointers into the strings in that vector remain valid
280268
// after new parameters have been added.
281269
constexpr auto const total_buffers_needed =
282-
(0 + ... + detail::exec_arg<TArgs>::buffers_needed);
270+
(0 + ... + buffers_needed<std::decay_t<TArgs>>());
283271
std::vector<std::string> exec_params;
284272
exec_params.reserve(total_buffers_needed);
285273

286274
// This array holds the pointers to all parameter strings, either
287275
// to the original string parameters or to the recently converted
288276
// in the exec_params vector.
289277
std::array<char const *, sizeof...(params)> param_ptrs = {
290-
detail::exec_arg<TArgs>::to_str(&exec_params,
291-
std::forward<TArgs>(params))...};
278+
to_str<std::decay_t<TArgs>>(&exec_params,
279+
std::forward<TArgs>(params))...};
292280

293281
return exec_prepared_internal(stmt, sizeof...(params),
294282
param_ptrs.data(), nullptr, nullptr,

tests/test-pgsql.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,17 @@ TEST_CASE("exec_prepared with single string parameters should work")
8383
TEST_CASE("exec_prepared with string parameters should work")
8484
{
8585
auto conn = db.db().connect();
86-
conn.exec("PREPARE test(int, int, int) AS SELECT $1 + $2 + $3");
86+
conn.exec("PREPARE test(int, int, int, int, int)"
87+
" AS SELECT $1 + $2 + $3 + $4 + $5");
8788

88-
auto const result = conn.exec_prepared("test", "1", "2", std::string{"3"});
89+
std::string a{"4"}; // NOLINT(misc-const-correctness)
90+
std::string const b{"5"};
91+
auto const result =
92+
conn.exec_prepared("test", "1", "2", std::string{"3"}, a, b);
8993
REQUIRE(result.status() == PGRES_TUPLES_OK);
9094
REQUIRE(result.num_fields() == 1);
9195
REQUIRE(result.num_tuples() == 1);
92-
REQUIRE(result.get(0, 0) == "6");
96+
REQUIRE(result.get(0, 0) == "15");
9397
}
9498

9599
TEST_CASE("exec_prepared with non-string parameters should work")

0 commit comments

Comments
 (0)