1
0
forked from cheng/wallet

removed a the redundantly explicit std::uniques

from display_wallet.h and display_wallet.cpp

They are now all wrapped in the long promised
and long forgotten wrapper class.

Long, long ago, I intended to implement the Pimpl idiom,
but these days std::unique takes care of all that work for
you.  You just wrap your low level pimple class in a high
level wrapper whose base class is an std_unique_ptr to
to an instance of your low level class.
This commit is contained in:
Cheng 2023-11-11 22:27:59 +00:00
parent f819b98d9e
commit ffa392b922
No known key found for this signature in database
GPG Key ID: 571C3A9C3B9E6FCA
6 changed files with 87 additions and 34 deletions

View File

@ -150,6 +150,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="../src/app.cpp" /> <ClCompile Include="../src/app.cpp" />
<ClCompile Include="../src/display_wallet.cpp" /> <ClCompile Include="../src/display_wallet.cpp" />
<ClCompile Include="../src/db_accessors.cpp" />
<ClCompile Include="../src/frame.cpp" /> <ClCompile Include="../src/frame.cpp" />
<ClCompile Include="../src/ILog.cpp" /> <ClCompile Include="../src/ILog.cpp" />
<ClCompile Include="../src/ISqlit3Impl.cpp"> <ClCompile Include="../src/ISqlit3Impl.cpp">

View File

@ -1,13 +1,8 @@
#pragma once #pragma once
#include "ILog.h" #include "ILog.h"
// this is pure virtual interface base class between sqlite3, which speaks only C and utf8 char[] // this is an interface base class between sqlite3, which speaks only C and utf8 char[]
// and wxWidgets which speaks only C++ and unicode strings. // and wxWidgets which speaks only C++ and unicode strings.
// Usage: Call the factory function std::shared_ptr<ISqlite3> sqlite3_open(const char *) to get a shared
// pointer to the // Sqlite3 database object. Then call the factory function
// sqlite3_prepare(std::shared_ptr<ISqlite3>, const char *) to get a unique pointer to
// a compiled SQL statement
// Its primary purpose is to avoid code that needs both the wxWidgets header files, // Its primary purpose is to avoid code that needs both the wxWidgets header files,
// and the sqlite3.h header file. // and the sqlite3.h header file.
// //
@ -25,8 +20,6 @@
// substantially more difficult in C++14, because one is effectively rolling one's own // substantially more difficult in C++14, because one is effectively rolling one's own
// unique pointer. // unique pointer.
// //
// It is therefore easier to implement a pure virtual base class with a virtual destructor and
// factory function that returns a smart pointer to a member of the derived implementation
// //
/* This code is at a low level abstraction, because it provides low level C++ interface to inherently low level C /* This code is at a low level abstraction, because it provides low level C++ interface to inherently low level C
It is intended to be wrapped in higher level code that does not know about the nuts and bolts of sqlite3, but which supports throwing, templated functions, and all that.*/ It is intended to be wrapped in higher level code that does not know about the nuts and bolts of sqlite3, but which supports throwing, templated functions, and all that.*/

45
src/db_accessors.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "stdafx.h"
namespace ro {
static constexpr char SrcFilename[]{ "src/db_accessors.cpp" };
dbconnect::dbconnect(const wxFileName& filename) {
if (!filename.IsOk() || !filename.HasName() || !filename.HasExt()) throw
MyException("unexpected file name", __LINE__, __func__, SrcFilename);
if (!filename.FileExists())throw MyException(
std::string(filename.GetFullPath().ToUTF8()) + " does not exist.",
__LINE__, __func__, SrcFilename);
this->reset(Sqlite3_open(filename.GetFullPath().ToUTF8()));
}
// move constructor
dbconnect::dbconnect(dbconnect&& p) noexcept :std::unique_ptr<ISqlite3>(p.release()) {
}
// Move assignment
dbconnect& dbconnect::operator=(dbconnect&& p) noexcept {
std::unique_ptr<ISqlite3>::reset(p.release());
return *this;
}
sql::sql(const std::unique_ptr<ISqlite3>& p, const char* sz) :
std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p.get(), sz)) {
}
// move constructor
sql::sql(sql&& p) noexcept :std::unique_ptr<Icompiled_sql>(p.release()) {
}
// Move assignment
sql& sql::operator=(sql&& p) noexcept {
std::unique_ptr<Icompiled_sql>::reset(p.release());
return *this;
}
sql::sql(Icompiled_sql* p) :
std::unique_ptr<Icompiled_sql>(p) {
}
sql::sql(std::unique_ptr<Icompiled_sql>&& p) :
std::unique_ptr<Icompiled_sql>(p.release()) {
}
}

View File

@ -15,26 +15,43 @@ namespace ro {
static_assert(is_sqlite3_field_type<int>::value); static_assert(is_sqlite3_field_type<int>::value);
//Owns a database connection and closes it when it is deconstructed
//Has move semantics
class dbconnect : public std::unique_ptr<ISqlite3> {
public:
dbconnect(const wxFileName&); //And here we wrap our Cish implementation in C++ish implementation
dbconnect() = delete;
~dbconnect() = default; //Our base class takes care of it
// copy constructor
dbconnect(const dbconnect& a) = delete; //Move semantics
// move constructor
dbconnect(dbconnect&& p) noexcept;
// copy assignment
dbconnect& operator=(const dbconnect) = delete; //Move semantics
// Move assignment
dbconnect& operator=(dbconnect&& p) noexcept;
};
//Owns a compiled sql statement and destroys it when it is deconstructed. //Owns a compiled sql statement and destroys it when it is deconstructed.
//Has move semantics. //Has move semantics.
class sql : public std::unique_ptr<Icompiled_sql> { class sql : public std::unique_ptr<Icompiled_sql> {
public: public:
class monostate {}; class monostate {};
sql() = delete;
sql(ISqlite3* p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p, sz)) {} sql(ISqlite3* p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p, sz)) {}
sql(const std::unique_ptr<ISqlite3>& p, const char* sz) :std::unique_ptr<Icompiled_sql>(sqlite3_prepare(p.get(), sz)) {} sql(const std::unique_ptr<ISqlite3>& p, const char* sz);
// copy constructor // copy constructor
sql(const sql& a) = delete; sql(const sql& a) = delete;
// move constructor // move constructor
sql(sql&& p) noexcept :std::unique_ptr<Icompiled_sql>(p.release()) { } sql(sql&& p) noexcept;
// copy assignment // copy assignment
sql& operator=(const sql) = delete; sql& operator=(const sql) = delete;
// Move assignment // Move assignment
sql& operator=(sql&& p) noexcept { sql& operator=(sql&& p) noexcept;
std::unique_ptr<Icompiled_sql>::reset(p.release()); sql(Icompiled_sql* p);
} sql(std::unique_ptr<Icompiled_sql>&& p);
sql(Icompiled_sql* p) :std::unique_ptr<Icompiled_sql>(p) {}
sql(std::unique_ptr<Icompiled_sql>&& p) :std::unique_ptr<Icompiled_sql>(p.release()) { }
~sql() = default; ~sql() = default;
template <typename T>auto column(int i) const { template <typename T>auto column(int i) const {
if constexpr (ro::blob_type<T>) { if constexpr (ro::blob_type<T>) {
auto st = (*this)->Isqlite3_column_blob(i); auto st = (*this)->Isqlite3_column_blob(i);

View File

@ -1,23 +1,19 @@
#include "stdafx.h" #include "stdafx.h"
using ro::base58; using ro::base58;
static constexpr char SrcFilename[]{ "src/display_wallet.cpp" }; static constexpr char SrcFilename[]{ "src/display_wallet.cpp" };
display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) : display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) :
wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, wxT("Wallet")), wxPanel(parent, myID_WALLET_UI, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, wxT("Wallet")),
m_db(nullptr), m_DisplayWalletEditMenu(1) m_db(walletfile), m_DisplayWalletEditMenu(1),
m_read_names_and_keys(m_db, R"|(SELECT * FROM "UserZookoIDs"; )|"),
m_read_from_misc(m_db),
m_find_position(m_db, R"|( SELECT COUNT(*) FROM UserZookoIDs WHERE LOWER("name")<LOWER(?1) AND "name"<?1;)|")
{ {
wxLogMessage(wxT("Loading %s"), walletfile.GetFullPath()); wxLogMessage(wxT("Loading %s"), walletfile.GetFullPath());
try { try {
if (!walletfile.IsOk() || !walletfile.HasName() || !walletfile.HasExt()) throw MyException("unexpected file name", __LINE__, __func__, SrcFilename); if (!m_read_from_misc(1) || m_read_from_misc.value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException(sz_unrecognizable_wallet_file_format);
if (!walletfile.FileExists())throw MyException( if (!m_read_from_misc(2) || m_read_from_misc.value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0 || !m_read_from_misc(4))throw MyException(sz_unrecognized_wallet_schema);
walletfile.GetFullPath().append(" does not exist.").ToUTF8(), m_MasterSecret= *(m_read_from_misc.value<ristretto255::scalar>());
__LINE__, __func__, SrcFilename);
m_db.reset(Sqlite3_open(walletfile.GetFullPath().ToUTF8()));
m_insert_name.reset(new sql_insert_name(m_db));
m_read_from_misc.reset(new sql_read_from_misc(m_db));
m_read_names_and_keys.reset(new ro::sql(m_db, R"|(SELECT * FROM "UserZookoIDs" )|"));
if (!(*m_read_from_misc)(1) || m_read_from_misc->value<int64_t>() != WALLET_FILE_IDENTIFIER)throw MyException(sz_unrecognizable_wallet_file_format);
if (!(*m_read_from_misc)(2) || m_read_from_misc->value<int64_t>() != WALLET_FILE_SCHEMA_VERSION_0_0 || !(*m_read_from_misc)(4))throw MyException(sz_unrecognized_wallet_schema);
m_MasterSecret= *(m_read_from_misc->value<ristretto255::scalar>());
ILogMessage(std::format("\t\tmaster secret: #{}", ro::base58(m_MasterSecret).operator const char* ()).c_str()); ILogMessage(std::format("\t\tmaster secret: #{}", ro::base58(m_MasterSecret).operator const char* ()).c_str());
if(!m_MasterSecret.valid()) throw MyException(sz_cold_wallets_not_yet_implemented, __LINE__, __func__, SrcFilename); if(!m_MasterSecret.valid()) throw MyException(sz_cold_wallets_not_yet_implemented, __LINE__, __func__, SrcFilename);
auto sizer = new wxBoxSizer(wxHORIZONTAL); auto sizer = new wxBoxSizer(wxHORIZONTAL);
@ -102,10 +98,10 @@ void display_wallet::refresh_from_database() {
m_lsizer->Clear(true); m_lsizer->Clear(true);
m_rsizer->Clear(true); m_rsizer->Clear(true);
try { try {
m_read_names_and_keys->reset(); m_read_names_and_keys.reset();
while (m_read_names_and_keys->step() == Icompiled_sql::ROW) { while (m_read_names_and_keys.step() == Icompiled_sql::ROW) {
std::string name = m_read_names_and_keys->column<const char*>(0); std::string name = m_read_names_and_keys.column<const char*>(0);
auto pubkey = *(m_read_names_and_keys->column<ristretto255::point>(1)); auto pubkey = *(m_read_names_and_keys.column<ristretto255::point>(1));
if (m_MasterSecret(name).timesBase() != pubkey)throw MyException(std::string(sz_public_key_of) + name + sz_fails_to_correspond); if (m_MasterSecret(name).timesBase() != pubkey)throw MyException(std::string(sz_public_key_of) + name + sz_fails_to_correspond);
m_lSizer->Add( m_lSizer->Add(
new wxStaticText( new wxStaticText(

View File

@ -6,10 +6,11 @@ public:
~display_wallet(); ~display_wallet();
private: private:
typedef MenuLink<display_wallet> MenuLink; typedef MenuLink<display_wallet> MenuLink;
std::unique_ptr<ISqlite3> m_db; ro::dbconnect m_db;
std::unique_ptr <sql_read_from_misc> m_read_from_misc; sql_read_from_misc m_read_from_misc;
std::unique_ptr <ro::sql> m_read_names_and_keys; ro::sql m_read_names_and_keys;
std::unique_ptr <sql_insert_name> m_insert_name; std::unique_ptr <sql_insert_name> m_insert_name;
ro::sql m_find_position;
ristretto255::CMasterSecret m_MasterSecret; ristretto255::CMasterSecret m_MasterSecret;
wxBoxSizer* m_lSizer; wxBoxSizer* m_lSizer;