aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-07-30 22:09:22 -0700
committerrtk0c <[email protected]>2022-07-30 22:09:22 -0700
commitfbb26deb27909f5603746739822c0d9c338955b9 (patch)
tree848da0f150f923e6650df5d8403870c65e645333
parent4067db383fb17d0580ebdc41e6354a84898e8343 (diff)
Changeset: 88 (untested) replace manual sqlite3_step() calls with SQLiteRunningStatement wrapper
-rw-r--r--source/20-codegen-compiler/CodegenModel.cpp295
-rw-r--r--source/20-codegen-compiler/SQLiteHelper.hpp204
-rw-r--r--source/20-codegen-compiler/main.cpp19
3 files changed, 297 insertions, 221 deletions
diff --git a/source/20-codegen-compiler/CodegenModel.cpp b/source/20-codegen-compiler/CodegenModel.cpp
index da7a5cc..303ad4e 100644
--- a/source/20-codegen-compiler/CodegenModel.cpp
+++ b/source/20-codegen-compiler/CodegenModel.cpp
@@ -1,6 +1,7 @@
#include "CodegenModel.hpp"
#include "CodegenUtils.hpp"
+#include "SQLiteHelper.hpp"
#include <Macros.hpp>
#include <ScopeGuard.hpp>
@@ -34,55 +35,6 @@ public:
#define CURRENT_DATABASE_VERSION 1
constexpr int64_t kGlobalNamespaceId = 1;
-struct SQLiteDatabase {
- sqlite3* database = nullptr;
-
- ~SQLiteDatabase() {
- // NOTE: calling with NULL is a harmless no-op
- int result = sqlite3_close(database);
- assert(result == SQLITE_OK);
- }
-
- operator sqlite3*() const { return database; }
- sqlite3** operator&() { return &database; }
-};
-
-struct SQLiteStatement {
- sqlite3_stmt* stmt = nullptr;
-
- SQLiteStatement(const SQLiteStatement&) = delete;
- SQLiteStatement& operator=(const SQLiteStatement&) = delete;
-
- SQLiteStatement() = default;
-
- SQLiteStatement(sqlite3* database, std::string_view sql) {
- Initialize(database, sql);
- }
-
- ~SQLiteStatement() {
- // NOTE: calling with NULL is a harmless no-op
- // NOTE: we don't care about the error code, because they are returned if the statement has errored in the most recent execution
- // but deleting it will succeeed anyways
- sqlite3_finalize(stmt);
- }
-
- operator sqlite3_stmt*() const { return stmt; }
- sqlite3_stmt** operator&() { return &stmt; }
-
- void Initialize(sqlite3* database, std::string_view sql) {
- int result = sqlite3_prepare(database, sql.data(), sql.size(), &stmt, nullptr);
- assert(result == SQLITE_OK);
- }
-
- bool InitializeLazily(sqlite3* database, std::string_view sql) {
- if (!stmt) {
- Initialize(database, sql);
- return true;
- }
- return false;
- }
-};
-
namespace {
void PrintErrMsgIfPresent(char*& errMsg) {
if (errMsg) {
@@ -273,19 +225,12 @@ COMMIT TRANSACTION;
return rowId;
}
- sqlite3_stmt* stmt = storeNamespaceStmt;
- int64_t parentRowId = FindOrStoreNamespace(ns->container);
- sqlite3_bind_int64(stmt, 1, parentRowId);
- sqlite3_bind_text(stmt, 2, ns->name.c_str(), ns->name.size(), nullptr);
+ SQLiteRunningStatement rt(storeNamespaceStmt);
+ rt.BindArguments(FindOrStoreNamespace(ns->container), ns->name);
- int result = sqlite3_step(stmt);
- DEFER {
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
- };
- assert(result == SQLITE_ROW);
+ rt.StepAndCheck(SQLITE_ROW);
- auto nsId = sqlite3_column_int64(stmt, 0);
+ auto [nsId] = rt.ResultColumns<int64_t>();
return nsId;
}
@@ -299,17 +244,13 @@ COMMIT TRANSACTION;
/// \return Row ID of the file, or 0 if it currently doesn't exist.
int64_t FindFile(std::string_view filename) {
- sqlite3_stmt* stmt = findFileStmt;
- sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), nullptr);
+ SQLiteRunningStatement rt(findFileStmt);
+ rt.BindArguments(filename);
- int result = sqlite3_step(stmt);
- DEFER {
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
- };
+ int result = rt.Step();
if (result == SQLITE_ROW) {
- auto fileId = sqlite3_column_int64(stmt, 0);
+ auto [fileId] = rt.ResultColumns<int64_t>();
return fileId;
} else {
return 0;
@@ -322,17 +263,12 @@ COMMIT TRANSACTION;
return id;
}
- sqlite3_stmt* stmt = storeFileStmt;
- sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), nullptr);
+ SQLiteRunningStatement rt(storeFileStmt);
+ rt.BindArguments(filename);
- int result = sqlite3_step(stmt);
- DEFER {
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
- };
- assert(result == SQLITE_ROW);
+ rt.StepAndCheck(SQLITE_ROW);
- auto fileId = sqlite3_column_int64(stmt, 0);
+ auto [fileId] = rt.ResultColumns<int64_t>();
return fileId;
}
@@ -353,21 +289,13 @@ private:
sqlite3_stmt* stmt = getNamespaceStmt;
int64_t currentNsId = nsId;
while (true) {
- sqlite3_bind_int64(stmt, 1, currentNsId);
-
- int result = sqlite3_step(stmt);
- DEFER {
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
- };
- assert(result == SQLITE_ROW);
+ SQLiteRunningStatement rt(getNamespaceStmt);
+ rt.BindArguments(currentNsId);
- /* 0th column Id */
- int64_t parentNamespaceId = sqlite3_column_int64(stmt, 1);
- auto nameCstr = (const char*)sqlite3_column_text(stmt, 2);
+ rt.StepAndCheck(SQLITE_ROW);
+ auto [id, parentNamespaceId, name] = rt.ResultColumns<int64_t, int64_t, std::string>();
currentNsId = parentNamespaceId;
- std::string name(nameCstr);
fullnameLength += name.size() + 2;
namespaceNames.push_back(std::move(name));
@@ -415,17 +343,12 @@ private:
int64_t FindNamespaceImpl(const DeclNamespace& ns, int64_t parentNsRowId) {
sqlite3_stmt* stmt = findNamespaceStmt;
- sqlite3_bind_int64(stmt, 1, parentNsRowId);
- sqlite3_bind_text(stmt, 2, ns.name.c_str(), ns.name.size(), nullptr);
-
- int result = sqlite3_step(stmt);
- DEFER {
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
- };
+ SQLiteRunningStatement rt(findNamespaceStmt);
+ rt.BindArguments(parentNsRowId, ns.name);
+ int result = rt.Step();
if (result == SQLITE_ROW) {
- int64_t nsId = sqlite3_column_int64(stmt, 0);
+ auto [nsId] = rt.ResultColumns<int64_t>();
return nsId;
} else {
return 0;
@@ -584,11 +507,9 @@ void CodegenArchiveModel::DeleteDeclsRelatedToFile(std::string_view filename) {
m->deleteEnumDeclByFilenameStmt.stmt,
};
for (auto& stmt : stmtList) {
- sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), nullptr);
- int result = sqlite3_step(stmt);
- assert(result == SQLITE_DONE);
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
+ SQLiteRunningStatement rt(stmt);
+ rt.BindArguments(filename);
+ rt.StepUntilDone();
}
m->CommitTransaction();
}
@@ -638,91 +559,67 @@ CodegenRuntimeModel CodegenArchiveModel::Load() const {
robin_hood::unordered_map<int64_t, DeclMemberVariable*> propertiesById;
robin_hood::unordered_map<int64_t, DeclMemberFunction*> methodsById;
- // NOTE: this is basically { initializer; while(true) { body; } } in a short form
- // Load structs
- for (SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructs"sv);;) {
- int result = sqlite3_step(stmt);
- if (result == SQLITE_DONE) {
- break;
- }
+ { // Load structs
+ SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructs"sv);
+ SQLiteRunningStatement rt(stmt);
+ while (true) {
+ int result = rt.StepAndCheckError();
+ if (result == SQLITE_DONE) break;
+ assert(result == SQLITE_ROW);
- if (result == SQLITE_ROW) {
- int64_t id = sqlite3_column_int64(stmt, 9);
- int64_t fileId = sqlite3_column_int64(stmt, 1);
- int64_t nsId = sqlite3_column_int64(stmt, 2);
- std::string_view name((const char*)sqlite3_column_text(stmt, 3));
+ auto [id, fileId, nsId, name] = rt.ResultColumns<int64_t, int64_t, int64_t, std::string_view>();
auto decl = cgModel.AddStruct(m->GetDeclFullName(nsId, name), DeclStruct{});
structsById.try_emplace(id, decl);
-
- continue;
}
-
- // Executing the statement resulted in an error
- assert(false);
}
- // Load struct's base classes
- for (SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructBaseClassRelations");;) {
- int result = sqlite3_step(stmt);
- if (result == SQLITE_DONE) {
- break;
- }
+ { // Load struct's base classes
+ SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructBaseClassRelations");
+ SQLiteRunningStatement rt(stmt);
+ while (true) {
+ int result = rt.StepAndCheckError();
+ if (result == SQLITE_DONE) break;
+ assert(result == SQLITE_ROW);
- if (result == SQLITE_ROW) {
- int64_t structId = sqlite3_column_int64(stmt, 0);
- int64_t parentStructNsId = sqlite3_column_int64(stmt, 1);
- std::string_view parentStructName((const char*)sqlite3_column_text(stmt, 2));
+ auto [structId, parentStructNsId, parentStructName] = rt.ResultColumns<int64_t, int64_t, std::string_view>();
auto declThis = structsById.at(structId);
auto declParent = cgModel.FindStruct(parentStructName); // TODO namespace
declThis->baseClasses.push_back(declParent);
-
- continue;
}
-
- assert(false);
}
- // Load struct properties
- for (SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructProperties"sv);;) {
- int result = sqlite3_step(stmt);
- if (result == SQLITE_DONE) {
- break;
- }
+ { // Load struct properties
+ SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructProperties"sv);
+ SQLiteRunningStatement rt(stmt);
+ while (true) {
+ int result = rt.StepAndCheckError();
+ if (result == SQLITE_DONE) break;
+ assert(result == SQLITE_ROW);
- if (result == SQLITE_ROW) {
// TODO
- continue;
}
-
- assert(false);
}
- // Load struct methods
- for (SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructMethods"sv);;) {
- int result = sqlite3_step(stmt);
- if (result == SQLITE_DONE) {
- break;
- }
+ { // Load struct methods
+ SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructMethods"sv);
+ SQLiteRunningStatement rt(stmt);
+ while (true) {
+ int result = rt.StepAndCheckError();
+ if (result == SQLITE_DONE) break;
+ assert(result == SQLITE_ROW);
- if (result == SQLITE_ROW) {
// TODO
- continue;
}
-
- assert(false);
}
- // Load method params
- for (SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructMethodParameters"sv);;) {
- int result = sqlite3_step(stmt);
- if (result == SQLITE_DONE) {
- break;
- }
+ { // Load method params
+ SQLiteStatement stmt(m->database, "SELECT * FROM DeclStructMethodParameters"sv);
+ SQLiteRunningStatement rt(stmt);
+ while (true) {
+ int result = rt.StepAndCheckError();
+ if (result == SQLITE_DONE) break;
+ assert(result == SQLITE_ROW);
- if (result == SQLITE_ROW) {
// TODO
- continue;
}
-
- assert(false);
}
return cgModel;
@@ -764,40 +661,28 @@ INSERT INTO DeclStructProperties(StructId, Name, Type, GetterName, SetterName, I
VALUES (?1, ?2, ?3, ?4, ?5, ?6)
)"""sv);
- int result;
-
- sqlite3_bind_int64(m->storeStructStmt, 1, m->FindOrStoreNamespace(decl.container));
- sqlite3_bind_text(m->storeStructStmt, 2, decl.name.c_str(), decl.name.size(), nullptr);
- sqlite3_bind_int64(m->storeStructStmt, 3, m->FindOrStoreFile(decl.sourceFile));
- sqlite3_bind_int(m->storeStructStmt, 4, decl.generating);
- result = sqlite3_step(m->storeStructStmt);
- assert(result == SQLITE_ROW);
- int64_t structId = sqlite3_column_int64(m->storeStructStmt, 0);
- sqlite3_reset(m->storeStructStmt);
- sqlite3_clear_bindings(m->storeStructStmt);
+ SQLiteRunningStatement rt(m->storeStructStmt);
+ rt.BindArguments(m->FindOrStoreNamespace(decl.container), decl.name, m->FindOrStoreFile(decl.sourceFile), decl.generating);
+ rt.StepAndCheck(SQLITE_ROW);
+ auto [structId] = rt.ResultColumns<int64_t>();
for (auto& baseClass : decl.baseClasses) {
- sqlite3_bind_int64(m->storeStructBaseClassStmt, 1, structId);
- sqlite3_bind_int64(m->storeStructBaseClassStmt, 2, m->FindOrStoreNamespace(baseClass->container));
- sqlite3_bind_text(m->storeStructBaseClassStmt, 3, baseClass->name.c_str(), baseClass->name.size(), nullptr);
- int result = sqlite3_step(m->storeStructBaseClassStmt);
- assert(result == SQLITE_DONE);
- sqlite3_reset(m->storeStructBaseClassStmt);
- sqlite3_clear_bindings(m->storeStructBaseClassStmt);
+ SQLiteRunningStatement rt(m->storeStructBaseClassStmt);
+ rt.BindArguments(structId, m->FindOrStoreNamespace(baseClass->container), baseClass->name);
+ rt.StepUntilDone();
}
for (auto& property : decl.memberVariables) {
- sqlite3_bind_int64(m->storeStructPropertyStmt, 1, structId);
- sqlite3_bind_text(m->storeStructPropertyStmt, 2, property.name.c_str(), property.name.size(), nullptr);
- sqlite3_bind_text(m->storeStructPropertyStmt, 3, property.type.c_str(), property.type.size(), nullptr);
- sqlite3_bind_text(m->storeStructPropertyStmt, 4, property.getterName.c_str(), property.getterName.size(), nullptr);
- sqlite3_bind_text(m->storeStructPropertyStmt, 5, property.setterName.c_str(), property.setterName.size(), nullptr);
- // Since DeclMemberVariable entries currently only exist if it's marked BRUSSEL_PROPERTY
- sqlite3_bind_int(m->storeStructPropertyStmt, 6, true);
- int result = sqlite3_step(m->storeStructPropertyStmt);
- assert(result == SQLITE_DONE);
- sqlite3_reset(m->storeStructPropertyStmt);
- sqlite3_clear_bindings(m->storeStructPropertyStmt);
+ SQLiteRunningStatement rt(m->storeStructPropertyStmt);
+ rt.BindArguments(
+ structId,
+ property.name,
+ property.type,
+ property.getterName,
+ property.setterName,
+ // Since DeclMemberVariable entries currently only exist if it's marked BRUSSEL_PROPERTY
+ true);
+ rt.StepUntilDone();
}
for (auto& method : decl.memberFunctions) {
@@ -834,24 +719,14 @@ VALUES (?1, ?2, ?3)
ON CONFLICT DO UPDATE SET Value=?3
)"""sv);
- sqlite3_bind_int(m->storeEnumStmt, 1, m->FindOrStoreNamespace(decl.container));
- sqlite3_bind_text(m->storeEnumStmt, 2, decl.name.c_str(), decl.name.size(), nullptr);
- auto eutName = decl.GetUnderlyingTypeName();
- sqlite3_bind_text(m->storeEnumStmt, 3, eutName.data(), eutName.size(), nullptr);
- sqlite3_bind_int64(m->storeEnumStmt, 4, m->FindOrStoreFile(decl.sourceFile));
- int result = sqlite3_step(m->storeEnumStmt);
- assert(result == SQLITE_ROW);
- auto enumId = sqlite3_column_int64(m->storeEnumStmt, 0);
- sqlite3_reset(m->storeEnumStmt);
- sqlite3_clear_bindings(m->storeEnumStmt);
+ SQLiteRunningStatement rt(m->storeEnumStmt);
+ rt.BindArguments(m->FindOrStoreNamespace(decl.container), decl.name, decl.GetUnderlyingTypeName(), m->FindOrStoreFile(decl.sourceFile));
+ rt.StepAndCheck(SQLITE_ROW);
+ auto [enumId] = rt.ResultColumns<int64_t>();
for (auto& elm : decl.elements) {
- sqlite3_bind_int64(m->storeEnumElmStmt, 1, enumId);
- sqlite3_bind_text(m->storeEnumElmStmt, 2, elm.name.c_str(), elm.name.size(), nullptr);
- sqlite3_bind_int64(m->storeEnumElmStmt, 3, elm.value);
- int result = sqlite3_step(m->storeEnumElmStmt);
- assert(result == SQLITE_DONE);
- sqlite3_reset(m->storeEnumElmStmt);
- sqlite3_clear_bindings(m->storeEnumElmStmt);
+ SQLiteRunningStatement rt(m->storeEnumElmStmt);
+ rt.BindArguments(enumId, elm.name, elm.value);
+ rt.StepUntilDone();
}
}
diff --git a/source/20-codegen-compiler/SQLiteHelper.hpp b/source/20-codegen-compiler/SQLiteHelper.hpp
new file mode 100644
index 0000000..c33c2a3
--- /dev/null
+++ b/source/20-codegen-compiler/SQLiteHelper.hpp
@@ -0,0 +1,204 @@
+#pragma once
+
+#include <fmt/format.h>
+#include <sqlite3.h>
+#include <cassert>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <sstream>
+#include <stdexcept>
+#include <string_view>
+#include <tuple>
+#include <type_traits>
+
+struct SQLiteDatabase {
+ sqlite3* database = nullptr;
+
+ ~SQLiteDatabase() {
+ // NOTE: calling with NULL is a harmless no-op
+ int result = sqlite3_close(database);
+ assert(result == SQLITE_OK);
+ }
+
+ operator sqlite3*() const { return database; }
+ sqlite3** operator&() { return &database; }
+};
+
+struct SQLiteStatement {
+ sqlite3_stmt* stmt = nullptr;
+
+ SQLiteStatement(const SQLiteStatement&) = delete;
+ SQLiteStatement& operator=(const SQLiteStatement&) = delete;
+
+ SQLiteStatement() = default;
+
+ SQLiteStatement(sqlite3* database, std::string_view sql) {
+ Initialize(database, sql);
+ }
+
+ ~SQLiteStatement() {
+ // NOTE: calling with NULL is a harmless no-op
+ // NOTE: we don't care about the error code, because they are returned if the statement has errored in the most recent execution
+ // but deleting it will succeeed anyways
+ sqlite3_finalize(stmt);
+ }
+
+ operator sqlite3_stmt*() const { return stmt; }
+ sqlite3_stmt** operator&() { return &stmt; }
+
+ void Initialize(sqlite3* database, std::string_view sql) {
+ int result = sqlite3_prepare_v2(database, sql.data(), sql.size(), &stmt, nullptr);
+ if (result != SQLITE_OK) {
+ auto msg = fmt::format(
+ "Failed to prepare SQLite3 statement, error message: {}",
+ sqlite3_errmsg(sqlite3_db_handle(stmt)));
+ throw std::runtime_error(msg);
+ }
+ }
+
+ bool InitializeLazily(sqlite3* database, std::string_view sql) {
+ if (!stmt) {
+ Initialize(database, sql);
+ return true;
+ }
+ return false;
+ }
+};
+
+struct SQLiteRunningStatement {
+ sqlite3_stmt* stmt;
+
+ SQLiteRunningStatement(sqlite3_stmt* stmt)
+ : stmt{ stmt } {
+ }
+
+ SQLiteRunningStatement(const SQLiteStatement& stmt)
+ : stmt{ stmt.stmt } {
+ }
+
+ ~SQLiteRunningStatement() {
+ sqlite3_clear_bindings(stmt);
+ sqlite3_reset(stmt);
+ }
+
+ void BindArgument(int index, int32_t value) {
+ sqlite3_bind_int(stmt, index, (int)value);
+ }
+
+ void BindArgument(int index, uint32_t value) {
+ sqlite3_bind_int(stmt, index, (int)value);
+ }
+
+ void BindArgument(int index, int64_t value) {
+ sqlite3_bind_int64(stmt, index, value);
+ }
+
+ void BindArgument(int index, uint64_t value) {
+ sqlite3_bind_int64(stmt, index, (int64_t)value);
+ }
+
+ void BindArgument(int index, const char* value) {
+ sqlite3_bind_text(stmt, index, value, -1, nullptr);
+ }
+
+ void BindArgument(int index, std::string_view value) {
+ sqlite3_bind_text(stmt, index, value.data(), value.size(), nullptr);
+ }
+
+ void BindArgument(int index, std::nullptr_t) {
+ // Noop
+ }
+
+ template <typename... Ts>
+ void BindArguments(Ts... args) {
+ // NOTE: SQLite3 argument index starts at 1
+ size_t idx = 1;
+ auto HandleEachArgument = [this, &idx](auto arg) {
+ BindArgument(idx, arg);
+ ++idx;
+ };
+ (HandleEachArgument(std::forward<Ts>(args)), ...);
+ }
+
+ int Step() {
+ return sqlite3_step(stmt);
+ }
+
+ void StepAndCheck(int forErr) {
+ int err = sqlite3_step(stmt);
+ assert(err == forErr);
+ }
+
+ int StepAndCheckError() {
+ int err = sqlite3_step(stmt);
+ if (err != SQLITE_DONE || err != SQLITE_ROW) {
+ auto msg = fmt::format(
+ "Error {} executing SQLite3 statement, error message: {}",
+ sqlite3_errstr(err),
+ sqlite3_errmsg(sqlite3_db_handle(stmt)));
+ throw std::runtime_error(msg);
+ }
+ }
+
+ void StepUntilDone() {
+ while (true) {
+ int err = sqlite3_step(stmt);
+ // SQLITE_OK is never returned for sqlite3_step() //TODO fact check this
+ if (err == SQLITE_DONE) {
+ break;
+ }
+ if (err == SQLITE_ROW) {
+ continue;
+ }
+
+ auto msg = fmt::format(
+ "Error {} executing SQLite3 statement, error message: {}",
+ sqlite3_errstr(err),
+ sqlite3_errmsg(sqlite3_db_handle(stmt)));
+ throw std::runtime_error(msg);
+ }
+ }
+
+ using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
+ using TpFromUnixTimestamp = std::pair<TimePoint, int64_t>;
+ using TpFromDateTime = std::pair<TimePoint, const char*>;
+
+ // TODO replace with overloads?
+ template <typename T>
+ auto ResultColumn(int column) const {
+ if constexpr (std::is_enum_v<T>) {
+ auto value = sqlite3_column_int64(stmt, column);
+ return static_cast<T>(value);
+ } else if constexpr (std::is_same_v<T, int>) {
+ return sqlite3_column_int(stmt, column);
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return sqlite3_column_int64(stmt, column);
+ } else if constexpr (std::is_same_v<T, const char*>) {
+ return (const char*)sqlite3_column_text(stmt, column);
+ } else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>) {
+ auto cstr = (const char*)sqlite3_column_text(stmt, column);
+ return T(cstr);
+ } else if constexpr (std::is_same_v<T, TpFromUnixTimestamp>) {
+ auto unixTimestamp = sqlite3_column_int64(stmt, column);
+ auto chrono = std::chrono::seconds(unixTimestamp);
+ return TimePoint(chrono);
+ } else if constexpr (std::is_same_v<T, TpFromDateTime>) {
+ // TODO wait for libstdc++ and libc++ implement c++20 std::chrono addition
+ static_assert(false && sizeof(T), "Unimplemented");
+ } else {
+ static_assert(false && sizeof(T), "Unknown type");
+ }
+ }
+
+ template <typename... Ts>
+ auto ResultColumns() {
+ // NOTE: SQLite3 column index starts at 0
+ // NOTE: ((size_t)-1) + 1 == 0
+ size_t idx = -1;
+ // NOTE: std::make_tuple() -- variadic template function
+ // std::tuple() -- CTAD constructor
+ // Both of these cause make the comma operator unsequenced, not viable here
+ return std::tuple{ (++idx, ResultColumn<Ts>(idx))... };
+ }
+};
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index 5b82d02..845f2f2 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -229,17 +229,6 @@ TryConsumeDirectiveArgumentList(CodegenLexer& lexer) {
return result;
}
-std::vector<const StbLexerToken*>*
-GetDirectiveArgument(std::vector<std::vector<const StbLexerToken*>>& list, size_t idx, const char* errMsg = nullptr) {
- if (idx < list.size()) {
- if (errMsg) {
- printf("%s", errMsg);
- }
- return &list[idx];
- }
- return nullptr;
-}
-
bool TryConsumeKeyword(CodegenLexer& lexer, CppKeyword keyword) {
auto& token = lexer.Current();
if (token.type == CLEX_id) {
@@ -1360,11 +1349,19 @@ where --output-dir=<path>: the *directory* to write generated contents to. Thi
}
for (auto decl : as.enumsToRevisit) {
+ if (!decl->generating) {
+ continue;
+ }
+
auto& headerOutput = decl->sourceFile->postHeaderOutput;
auto& sourceOutput = decl->sourceFile->postSourceOutput;
GenerateForEnum(headerOutput, sourceOutput, *decl);
}
for (auto decl : as.structsToRevisit) {
+ if (!decl->generating) {
+ continue;
+ }
+
auto& headerOutput = decl->sourceFile->postHeaderOutput;
auto& sourceOutput = decl->sourceFile->postSourceOutput;