From a5d95afb96eb9a3b65d82f5f84bf8e4a4fb4c8ac Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Fri, 28 Aug 2026 21:12:55 +0200 Subject: clang-format C++ sources --- server/src/sqlite3.cppm | 486 +++++++++++++++++++++++++++--------------------- 1 file changed, 270 insertions(+), 216 deletions(-) (limited to 'server/src/sqlite3.cppm') diff --git a/server/src/sqlite3.cppm b/server/src/sqlite3.cppm index f226c6b..70f58c0 100644 --- a/server/src/sqlite3.cppm +++ b/server/src/sqlite3.cppm @@ -9,249 +9,303 @@ import :util; namespace routemon::sqlite3 { - class mutex_guard { - explicit mutex_guard(::sqlite3_mutex* mut) noexcept : mut_{mut} { - ::sqlite3_mutex_enter(mut_); - } - - friend auto do_guarded(::sqlite3_mutex* mut, std::invocable auto f) -> decltype(f(std::declval())); - - public: - mutex_guard(mutex_guard const&) = delete; - ~mutex_guard() { - ::sqlite3_mutex_leave(mut_); - } - - private: - ::sqlite3_mutex* mut_; - }; - - auto do_guarded(::sqlite3_mutex* mut, std::invocable auto f) -> decltype(f(std::declval())) { - return f(mutex_guard{mut}); +class mutex_guard +{ + explicit mutex_guard(::sqlite3_mutex* mut) noexcept : mut_{mut} + { + ::sqlite3_mutex_enter(mut_); } - auto do_guarded(::sqlite3* dbc, std::invocable auto f) -> decltype(f(std::declval())) { - return do_guarded(::sqlite3_db_mutex(dbc), f); + friend auto + do_guarded(::sqlite3_mutex* mut, std::invocable auto f) + -> decltype(f(std::declval())); + +public: + mutex_guard(mutex_guard const&) = delete; + ~mutex_guard() { ::sqlite3_mutex_leave(mut_); } + +private: + ::sqlite3_mutex* mut_; +}; + +auto do_guarded(::sqlite3_mutex* mut, std::invocable auto f) + -> decltype(f(std::declval())) +{ + return f(mutex_guard{mut}); +} + +auto do_guarded(::sqlite3* dbc, std::invocable auto f) + -> decltype(f(std::declval())) +{ + return do_guarded(::sqlite3_db_mutex(dbc), f); +} + +class error : public std::exception +{ + int code_; + std::string message_; + +public: + explicit error(mutex_guard const&, int code, ::sqlite3* dbc) + : code_{code}, message_{::sqlite3_errmsg(dbc)} + { } - class error : public std::exception { - int code_; - std::string message_; - - public: - explicit error(mutex_guard const&, int code, ::sqlite3* dbc) - : code_{code}, message_{::sqlite3_errmsg(dbc)} - {} - - explicit error(int code) - : code_{code}, message_{::sqlite3_errstr(code)} - {} - - [[nodiscard]] auto what() const noexcept -> char const* override { - return message_.c_str(); - } - - [[nodiscard]] auto code() const noexcept -> int { - return code_; - } - }; - - template concept C> - concept optional_of = requires { - typename T::value_type; - requires std::same_as>; - requires C; - }; - - template - concept scannable_prim = - std::same_as || - std::same_as || - std::same_as; - - template - concept scannable = scannable_prim || optional_of; - - class statement { - ::sqlite3_stmt* stmt_; - - public: - explicit statement(::sqlite3_stmt* stmt) : stmt_{stmt} {} - statement(statement const&) = delete; - statement(statement&& s) noexcept { - stmt_ = s.stmt_; - s.stmt_ = nullptr; - } - ~statement() { - ::sqlite3_finalize(stmt_); - } - auto get() -> ::sqlite3_stmt* { - return stmt_; - } - }; - - class row_reader { - statement stmt_; + explicit error(int code) : code_{code}, message_{::sqlite3_errstr(code)} {} - explicit row_reader(statement stmt) : stmt_{std::move(stmt)} {} + [[nodiscard]] auto what() const noexcept -> char const* override + { + return message_.c_str(); + } - friend class connection; + [[nodiscard]] auto code() const noexcept -> int { return code_; } +}; + +template concept C> +concept optional_of = requires { + typename T::value_type; + requires std::same_as>; + requires C; +}; + +template +concept scannable_prim = std::same_as || std::same_as + || std::same_as; + +template +concept scannable = scannable_prim || optional_of; + +class statement +{ + ::sqlite3_stmt* stmt_; + +public: + explicit statement(::sqlite3_stmt* stmt) : stmt_{stmt} {} + statement(statement const&) = delete; + statement(statement&& s) noexcept + { + stmt_ = s.stmt_; + s.stmt_ = nullptr; + } + ~statement() { ::sqlite3_finalize(stmt_); } + auto get() -> ::sqlite3_stmt* { return stmt_; } +}; + +class row_reader +{ + statement stmt_; + + explicit row_reader(statement stmt) : stmt_{std::move(stmt)} {} + + friend class connection; + + void scan(int col, std::string& s) + { + if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_TEXT) + throw std::invalid_argument{"invalid type for scan"}; + unsigned char const* chs = ::sqlite3_column_text(stmt_.get(), col); + auto size = util::size_from_int(::sqlite3_column_bytes(stmt_.get(), col)); + if (!size.has_value()) + throw std::logic_error{"unexpected negative amount of bytes in column"}; + s = std::string{reinterpret_cast(chs), *size}; + } - void scan(int col, std::string& s) { - if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_TEXT) - throw std::invalid_argument{"invalid type for scan"}; - unsigned char const* chs = ::sqlite3_column_text(stmt_.get(), col); - auto size = util::size_from_int(::sqlite3_column_bytes(stmt_.get(), col)); - if (!size.has_value()) - throw std::logic_error{"unexpected negative amount of bytes in column"}; - s = std::string{reinterpret_cast(chs), *size}; - } + void scan(int col, double& v) + { + if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_FLOAT) + throw std::invalid_argument{"invalid type for scan"}; + v = ::sqlite3_column_double(stmt_.get(), col); + } - void scan(int col, double& v) { - if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_FLOAT) - throw std::invalid_argument{"invalid type for scan"}; - v = ::sqlite3_column_double(stmt_.get(), col); - } + void scan(int col, std::int64_t& v) + { + if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_INTEGER) + throw std::invalid_argument{"invalid type for scan"}; + v = ::sqlite3_column_int64(stmt_.get(), col); + } - void scan(int col, std::int64_t& v) { - if (::sqlite3_column_type(stmt_.get(), col) != SQLITE_INTEGER) - throw std::invalid_argument{"invalid type for scan"}; - v = ::sqlite3_column_int64(stmt_.get(), col); + void scan(int col, optional_of auto& v) + { + if (::sqlite3_column_type(stmt_.get(), col) == SQLITE_NULL) + { + v.reset(); } - - void scan(int col, optional_of auto& v) { - if (::sqlite3_column_type(stmt_.get(), col) == SQLITE_NULL) { - v.reset(); - } else { - typename std::remove_cvref_t::value_type tmp; - scan(col, tmp); - v = std::move(tmp); - } + else + { + typename std::remove_cvref_t::value_type tmp; + scan(col, tmp); + v = std::move(tmp); } + } - public: - auto next() -> bool { - ::sqlite3* dbc = ::sqlite3_db_handle(stmt_.get()); - return do_guarded(dbc, [&](auto const& guard) -> bool { - auto const s = ::sqlite3_step(stmt_.get()); - if (s == SQLITE_ROW) - return true; - if (s == SQLITE_DONE) - return false; - throw error{guard, s, dbc}; - }); - } +public: + auto next() -> bool + { + ::sqlite3* dbc = ::sqlite3_db_handle(stmt_.get()); + return do_guarded( + dbc, + [&](auto const& guard) -> bool + { + auto const s = ::sqlite3_step(stmt_.get()); + if (s == SQLITE_ROW) + return true; + if (s == SQLITE_DONE) + return false; + throw error{guard, s, dbc}; + }); + } - auto scan(scannable auto&... args) -> void { - auto const ncols = util::size_from_int(::sqlite3_data_count(stmt_.get())); - if (!ncols.has_value()) - throw std::logic_error{"got unexpected negative amount of columns"}; - if (sizeof...(args) > *ncols) - throw std::invalid_argument{"more scanning arguments provided than columns in result set"}; - auto col = 0; (..., scan(col++, args)); - } + auto scan(scannable auto&... args) -> void + { + auto const ncols = util::size_from_int(::sqlite3_data_count(stmt_.get())); + if (!ncols.has_value()) + throw std::logic_error{"got unexpected negative amount of columns"}; + if (sizeof...(args) > *ncols) + throw std::invalid_argument{ + "more scanning arguments provided than columns in result set" + }; + auto col = 0; + (..., scan(col++, args)); + } - auto scan_single(scannable auto&... args) -> void { - if (!next()) - throw std::logic_error{"no row in result set"}; - scan(args...); - if (next()) { - throw std::logic_error{"more than one row in result set"}; - } + auto scan_single(scannable auto&... args) -> void + { + if (!next()) + throw std::logic_error{"no row in result set"}; + scan(args...); + if (next()) + { + throw std::logic_error{"more than one row in result set"}; } - }; - - class binder { - statement& stmt_; - - explicit binder(statement& stmt) : stmt_{stmt} {} - - friend class connection; - - public: - auto text(std::string const& param_name, std::string_view str) -> void { - int const i = ::sqlite3_bind_parameter_index(stmt_.get(), param_name.c_str()); - if (i == 0) - throw std::invalid_argument{std::format("bind: no parameter with name {} found", param_name)}; - auto str_size = util::int_from_size(str.size()); - if (!str_size.has_value()) - throw std::invalid_argument{"bind: provided text is too long"}; - if (auto s = ::sqlite3_bind_text(stmt_.get(), i, str.data(), *str_size, SQLITE_TRANSIENT); s != SQLITE_OK) { - throw error{s}; - } + } +}; + +class binder +{ + statement& stmt_; + + explicit binder(statement& stmt) : stmt_{stmt} {} + + friend class connection; + +public: + auto text(std::string const& param_name, std::string_view str) -> void + { + int const i = + ::sqlite3_bind_parameter_index(stmt_.get(), param_name.c_str()); + if (i == 0) + throw std::invalid_argument{std::format( + "bind: no parameter with name {} found", param_name)}; + auto str_size = util::int_from_size(str.size()); + if (!str_size.has_value()) + throw std::invalid_argument{"bind: provided text is too long"}; + if (auto s = ::sqlite3_bind_text( + stmt_.get(), i, str.data(), *str_size, SQLITE_TRANSIENT); + s != SQLITE_OK) + { + throw error{s}; } + } - static auto noop(binder&) -> void {} - }; + static auto noop(binder&) -> void {} +}; - export class connection { - ::sqlite3* dbc_; - ::sqlite3_mutex* mut_; +export class connection +{ + ::sqlite3* dbc_; + ::sqlite3_mutex* mut_; - explicit connection(::sqlite3* dbc) : dbc_{dbc}, mut_{::sqlite3_db_mutex(dbc)} {} + explicit connection(::sqlite3* dbc) : dbc_{dbc}, mut_{::sqlite3_db_mutex(dbc)} + { + } - friend auto open(std::string const& filename) -> connection; + friend auto open(std::string const& filename) -> connection; - public: - connection(connection const&) = delete; - connection(connection&& c) noexcept { - dbc_ = c.dbc_; - mut_ = c.mut_; - c.dbc_ = nullptr; - c.mut_ = nullptr; - } +public: + connection(connection const&) = delete; + connection(connection&& c) noexcept + { + dbc_ = c.dbc_; + mut_ = c.mut_; + c.dbc_ = nullptr; + c.mut_ = nullptr; + } - [[nodiscard]] auto query(std::string const& sql, std::function const& bf = binder::noop) -> row_reader { - ::sqlite3_stmt* pstmt = nullptr; - char const* sql_tail = nullptr; - auto sql_size = util::int_from_size(sql.size()); - if (!sql_size.has_value() || *sql_size >= std::numeric_limits::max() - 1) - throw std::invalid_argument{"provided input text too large"}; - do_guarded(mut_, [&](auto const& guard) -> void { - if (auto s = ::sqlite3_prepare_v2(dbc_, sql.data(), *sql_size + 1, &pstmt, &sql_tail); s != SQLITE_OK) { - if (pstmt != nullptr) { - // Use contract_assert when having a compiler with contracts available - ::sqlite3_finalize(pstmt); - throw std::logic_error{"expected stmt to be null after failed preparation"}; + [[nodiscard]] auto query( + std::string const& sql, + std::function const& bf = binder::noop) -> row_reader + { + ::sqlite3_stmt* pstmt = nullptr; + char const* sql_tail = nullptr; + auto sql_size = util::int_from_size(sql.size()); + if (!sql_size.has_value() + || *sql_size >= std::numeric_limits::max() - 1) + throw std::invalid_argument{"provided input text too large"}; + do_guarded( + mut_, + [&](auto const& guard) -> void + { + if (auto s = ::sqlite3_prepare_v2( + dbc_, sql.data(), *sql_size + 1, &pstmt, &sql_tail); + s != SQLITE_OK) + { + if (pstmt != nullptr) + { + // Use contract_assert when having a compiler with + // contracts available + ::sqlite3_finalize(pstmt); + throw std::logic_error{ + "expected stmt to be null after failed preparation" + }; + } + throw error{guard, s, dbc_}; } - throw error{guard, s, dbc_}; - } - }); - if (!pstmt) - throw std::invalid_argument{"provided input text contains no SQL"}; - auto stmt = statement{pstmt}; - if (sql_tail && std::strlen(sql_tail) > 0) - throw std::invalid_argument{"provided input text contains more than one SQL statement"}; - auto b = binder{stmt}; bf(b); - return row_reader{std::move(stmt)}; - } + }); + if (!pstmt) + throw std::invalid_argument{"provided input text contains no SQL"}; + auto stmt = statement{pstmt}; + if (sql_tail && std::strlen(sql_tail) > 0) + throw std::invalid_argument{ + "provided input text contains more than one SQL statement" + }; + auto b = binder{stmt}; + bf(b); + return row_reader{std::move(stmt)}; + } - auto exec(std::string const& sql, std::function const& bf = binder::noop) -> void { - auto reader = query(sql, bf); - while (reader.next()); - } + auto exec( + std::string const& sql, + std::function const& bf = binder::noop) -> void + { + auto reader = query(sql, bf); + while (reader.next()) + ; + } - ~connection() { - std::ignore = ::sqlite3_close(std::exchange(dbc_, nullptr)); + ~connection() { std::ignore = ::sqlite3_close(std::exchange(dbc_, nullptr)); } +}; + +export auto open(std::string const& filename) -> connection +{ + ::sqlite3* dbc = nullptr; + auto s = ::sqlite3_open_v2( + filename.c_str(), &dbc, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX + | SQLITE_OPEN_EXRESCODE, + nullptr); + if (s != SQLITE_OK) + { + if (dbc) + { + do_guarded( + dbc, [&](auto const& guard) -> void { throw error{guard, s, dbc}; }); } - }; - - export auto open(std::string const& filename) -> connection { - ::sqlite3* dbc = nullptr; - auto s = ::sqlite3_open_v2(filename.c_str(), &dbc, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | - SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_EXRESCODE, - nullptr); - if (s != SQLITE_OK) { - if (dbc) { - do_guarded(dbc, [&](auto const& guard) -> void { - throw error{guard, s, dbc}; - }); - } else { - throw error{s}; - } + else + { + throw error{s}; } - return connection{dbc}; } + return connection{dbc}; +} } // namespace routemon::sqlite3 -- cgit v1.3