diff options
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | cadence.cpp | 58 | ||||
| -rw-r--r-- | generator/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | generator/database.cpp | 173 | ||||
| -rw-r--r-- | generator/database.h | 73 | ||||
| -rw-r--r-- | generator/field.cpp | 193 | ||||
| -rw-r--r-- | generator/field.h | 76 | ||||
| -rw-r--r-- | generator/generator.cpp | 27 | ||||
| -rw-r--r-- | generator/generator.h | 4 | ||||
| -rw-r--r-- | generator/progress.h | 56 | ||||
| -rw-r--r-- | util.h | 74 | ||||
| m--------- | vendor/hkutil | 0 |
13 files changed, 41 insertions, 707 deletions
| diff --git a/.gitmodules b/.gitmodules index e1d506f..b51cbff 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | [submodule "vendor/libtwittercpp"] | 1 | [submodule "vendor/libtwittercpp"] |
| 2 | path = vendor/libtwittercpp | 2 | path = vendor/libtwittercpp |
| 3 | url = https://github.com/hatkirby/libtwittercpp | 3 | url = https://github.com/hatkirby/libtwittercpp |
| 4 | [submodule "vendor/hkutil"] | ||
| 5 | path = vendor/hkutil | ||
| 6 | url = git@github.com:hatkirby/hkutil | ||
| diff --git a/CMakeLists.txt b/CMakeLists.txt index 4345e90..a64833d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -10,7 +10,8 @@ add_subdirectory(vendor/libtwittercpp) | |||
| 10 | include_directories( | 10 | include_directories( |
| 11 | ${sqlite3_INCLUDE_DIR} | 11 | ${sqlite3_INCLUDE_DIR} |
| 12 | vendor/libtwittercpp/src | 12 | vendor/libtwittercpp/src |
| 13 | ${yaml-cpp_INCLUDE_DIRS}) | 13 | ${yaml-cpp_INCLUDE_DIRS} |
| 14 | vendor/hkutil) | ||
| 14 | 15 | ||
| 15 | add_executable(cadence cadence.cpp) | 16 | add_executable(cadence cadence.cpp) |
| 16 | set_property(TARGET cadence PROPERTY CXX_STANDARD 11) | 17 | set_property(TARGET cadence PROPERTY CXX_STANDARD 11) |
| diff --git a/cadence.cpp b/cadence.cpp index 80e4a05..704f946 100644 --- a/cadence.cpp +++ b/cadence.cpp | |||
| @@ -10,7 +10,8 @@ | |||
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | #include <random> | 11 | #include <random> |
| 12 | #include <list> | 12 | #include <list> |
| 13 | #include "util.h" | 13 | #include <hkutil/string.h> |
| 14 | #include <hkutil/database.h> | ||
| 14 | 15 | ||
| 15 | const std::vector<std::string> moods = {"party", "chill", "crazy", "happy", "sad", "instrumental", "vocal"}; | 16 | const std::vector<std::string> moods = {"party", "chill", "crazy", "happy", "sad", "instrumental", "vocal"}; |
| 16 | 17 | ||
| @@ -72,19 +73,9 @@ int main(int argc, char** argv) | |||
| 72 | std::mt19937 random_engine{random_device()}; | 73 | std::mt19937 random_engine{random_device()}; |
| 73 | 74 | ||
| 74 | // Connect to the AcousticBrainz data file. | 75 | // Connect to the AcousticBrainz data file. |
| 75 | sqlite3* ppdb = nullptr; | 76 | hatkirby::database abdb( |
| 76 | 77 | config["acoustic_datafile"].as<std::string>(), | |
| 77 | if (sqlite3_open_v2(config["acoustic_datafile"].as<std::string>().c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) | 78 | hatkirby::dbmode::read); |
| 78 | { | ||
| 79 | // We still have to free the resources allocated. In the event that | ||
| 80 | // allocation failed, ppdb will be null and sqlite3_close_v2 will just | ||
| 81 | // ignore it. | ||
| 82 | sqlite3_close_v2(ppdb); | ||
| 83 | |||
| 84 | std::cout << "Could not open acoustic datafile." << std::endl; | ||
| 85 | |||
| 86 | return 1; | ||
| 87 | } | ||
| 88 | 79 | ||
| 89 | for (;;) | 80 | for (;;) |
| 90 | { | 81 | { |
| @@ -92,36 +83,15 @@ int main(int argc, char** argv) | |||
| 92 | 83 | ||
| 93 | std::string mood = moods[std::uniform_int_distribution<int>(0, moods.size()-1)(random_engine)]; | 84 | std::string mood = moods[std::uniform_int_distribution<int>(0, moods.size()-1)(random_engine)]; |
| 94 | 85 | ||
| 95 | std::string songTitle; | 86 | hatkirby::row song = |
| 96 | std::string songArtist; | 87 | abdb.queryFirst( |
| 97 | 88 | "SELECT title, artist FROM songs WHERE category = ? ORDER BY RANDOM() LIMIT 1", | |
| 98 | sqlite3_stmt* ppstmt; | 89 | { mood }); |
| 99 | std::string query = "SELECT title, artist FROM songs WHERE category = ? ORDER BY RANDOM() LIMIT 1"; | ||
| 100 | |||
| 101 | if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) | ||
| 102 | { | ||
| 103 | std::cout << "Error reading from acoustic datafile:" << std::endl; | ||
| 104 | std::cout << sqlite3_errmsg(ppdb) << std::endl; | ||
| 105 | |||
| 106 | return 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | sqlite3_bind_text(ppstmt, 1, mood.c_str(), mood.length(), SQLITE_TRANSIENT); | ||
| 110 | |||
| 111 | if (sqlite3_step(ppstmt) == SQLITE_ROW) | ||
| 112 | { | ||
| 113 | songTitle = reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0)); | ||
| 114 | songArtist = reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 1)); | ||
| 115 | } else { | ||
| 116 | std::cout << "Error reading from acoustic datafile:" << std::endl; | ||
| 117 | std::cout << sqlite3_errmsg(ppdb) << std::endl; | ||
| 118 | |||
| 119 | return 1; | ||
| 120 | } | ||
| 121 | 90 | ||
| 122 | sqlite3_finalize(ppstmt); | 91 | std::string songTitle = mpark::get<std::string>(song[0]); |
| 92 | std::string songArtist = mpark::get<std::string>(song[1]); | ||
| 123 | 93 | ||
| 124 | std::string action = "{" + cadence::uppercase(mood) + "}"; | 94 | std::string action = "{" + hatkirby::uppercase(mood) + "}"; |
| 125 | int tknloc; | 95 | int tknloc; |
| 126 | while ((tknloc = action.find("{")) != std::string::npos) | 96 | while ((tknloc = action.find("{")) != std::string::npos) |
| 127 | { | 97 | { |
| @@ -182,13 +152,13 @@ int main(int argc, char** argv) | |||
| 182 | }); | 152 | }); |
| 183 | } else if (isupper(token[0]) && !isupper(token[1])) | 153 | } else if (isupper(token[0]) && !isupper(token[1])) |
| 184 | { | 154 | { |
| 185 | auto words = cadence::split<std::list<std::string>>(result, " "); | 155 | auto words = hatkirby::split<std::list<std::string>>(result, " "); |
| 186 | for (auto& word : words) | 156 | for (auto& word : words) |
| 187 | { | 157 | { |
| 188 | word[0] = std::toupper(word[0]); | 158 | word[0] = std::toupper(word[0]); |
| 189 | } | 159 | } |
| 190 | 160 | ||
| 191 | finalresult = cadence::implode(std::begin(words), std::end(words), " "); | 161 | finalresult = hatkirby::implode(std::begin(words), std::end(words), " "); |
| 192 | } else { | 162 | } else { |
| 193 | finalresult = result; | 163 | finalresult = result; |
| 194 | } | 164 | } |
| diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index af023c4..dffbe0e 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt | |||
| @@ -4,8 +4,12 @@ project (generator) | |||
| 4 | find_package(PkgConfig) | 4 | find_package(PkgConfig) |
| 5 | pkg_check_modules(sqlite3 sqlite3 REQUIRED) | 5 | pkg_check_modules(sqlite3 sqlite3 REQUIRED) |
| 6 | 6 | ||
| 7 | include_directories(${sqlite3_INCLUDE_DIR} vendor/json) | 7 | include_directories( |
| 8 | add_executable(generator mood.cpp database.cpp field.cpp generator.cpp main.cpp) | 8 | ${sqlite3_INCLUDE_DIR} |
| 9 | vendor/json | ||
| 10 | ../vendor/hkutil) | ||
| 11 | |||
| 12 | add_executable(generator mood.cpp generator.cpp main.cpp) | ||
| 9 | set_property(TARGET generator PROPERTY CXX_STANDARD 11) | 13 | set_property(TARGET generator PROPERTY CXX_STANDARD 11) |
| 10 | set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON) | 14 | set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON) |
| 11 | target_link_libraries(generator ${sqlite3_LIBRARIES}) | 15 | target_link_libraries(generator ${sqlite3_LIBRARIES}) |
| diff --git a/generator/database.cpp b/generator/database.cpp deleted file mode 100644 index b46a0d1..0000000 --- a/generator/database.cpp +++ /dev/null | |||
| @@ -1,173 +0,0 @@ | |||
| 1 | #include "database.h" | ||
| 2 | #include <sqlite3.h> | ||
| 3 | #include <cassert> | ||
| 4 | #include <fstream> | ||
| 5 | #include <stdexcept> | ||
| 6 | #include <cstdio> | ||
| 7 | #include <sstream> | ||
| 8 | #include "field.h" | ||
| 9 | #include "../util.h" | ||
| 10 | |||
| 11 | namespace cadence { | ||
| 12 | namespace generator { | ||
| 13 | |||
| 14 | sqlite3_error::sqlite3_error( | ||
| 15 | const std::string& what, | ||
| 16 | const std::string& db_err) : | ||
| 17 | what_(what + " (" + db_err + ")"), | ||
| 18 | db_err_(db_err) | ||
| 19 | { | ||
| 20 | } | ||
| 21 | |||
| 22 | const char* sqlite3_error::what() const noexcept | ||
| 23 | { | ||
| 24 | return what_.c_str(); | ||
| 25 | } | ||
| 26 | |||
| 27 | const char* sqlite3_error::db_err() const noexcept | ||
| 28 | { | ||
| 29 | return db_err_.c_str(); | ||
| 30 | } | ||
| 31 | |||
| 32 | database::database(std::string path) | ||
| 33 | { | ||
| 34 | // If there is already a file at this path, overwrite it. | ||
| 35 | if (std::ifstream(path)) | ||
| 36 | { | ||
| 37 | if (std::remove(path.c_str())) | ||
| 38 | { | ||
| 39 | throw std::logic_error("Could not overwrite file at path"); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | if (sqlite3_open_v2(path.c_str(), &ppdb_, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) | ||
| 44 | { | ||
| 45 | // We still have to free the resources allocated. In the event that | ||
| 46 | // allocation failed, ppdb will be null and sqlite3_close_v2 will just | ||
| 47 | // ignore it. | ||
| 48 | std::string errmsg(sqlite3_errmsg(ppdb_)); | ||
| 49 | sqlite3_close_v2(ppdb_); | ||
| 50 | |||
| 51 | throw sqlite3_error("Could not create output datafile", errmsg); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | database::database(database&& other) : database() | ||
| 56 | { | ||
| 57 | swap(*this, other); | ||
| 58 | } | ||
| 59 | |||
| 60 | database& database::operator=(database&& other) | ||
| 61 | { | ||
| 62 | swap(*this, other); | ||
| 63 | |||
| 64 | return *this; | ||
| 65 | } | ||
| 66 | |||
| 67 | void swap(database& first, database& second) | ||
| 68 | { | ||
| 69 | std::swap(first.ppdb_, second.ppdb_); | ||
| 70 | } | ||
| 71 | |||
| 72 | database::~database() | ||
| 73 | { | ||
| 74 | sqlite3_close_v2(ppdb_); | ||
| 75 | } | ||
| 76 | |||
| 77 | void database::runQuery(std::string query) | ||
| 78 | { | ||
| 79 | // This can only happen when doing bad things with move semantics. | ||
| 80 | assert(ppdb_ != nullptr); | ||
| 81 | |||
| 82 | sqlite3_stmt* ppstmt; | ||
| 83 | |||
| 84 | if (sqlite3_prepare_v2(ppdb_, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) | ||
| 85 | { | ||
| 86 | throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_)); | ||
| 87 | } | ||
| 88 | |||
| 89 | int result = sqlite3_step(ppstmt); | ||
| 90 | sqlite3_finalize(ppstmt); | ||
| 91 | |||
| 92 | if (result != SQLITE_DONE) | ||
| 93 | { | ||
| 94 | throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_)); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | void database::insertIntoTable(std::string table, std::list<field> fields) | ||
| 99 | { | ||
| 100 | // This can only happen when doing bad things with move semantics. | ||
| 101 | assert(ppdb_ != nullptr); | ||
| 102 | |||
| 103 | // This shouldn't happen. | ||
| 104 | assert(!fields.empty()); | ||
| 105 | |||
| 106 | std::list<std::string> fieldNames; | ||
| 107 | std::list<std::string> qs; | ||
| 108 | for (field& f : fields) | ||
| 109 | { | ||
| 110 | fieldNames.push_back(f.getName()); | ||
| 111 | qs.push_back("?"); | ||
| 112 | } | ||
| 113 | |||
| 114 | std::ostringstream query; | ||
| 115 | query << "INSERT INTO "; | ||
| 116 | query << table; | ||
| 117 | query << " ("; | ||
| 118 | query << implode(std::begin(fieldNames), std::end(fieldNames), ", "); | ||
| 119 | query << ") VALUES ("; | ||
| 120 | query << implode(std::begin(qs), std::end(qs), ", "); | ||
| 121 | query << ")"; | ||
| 122 | |||
| 123 | std::string query_str = query.str(); | ||
| 124 | |||
| 125 | sqlite3_stmt* ppstmt; | ||
| 126 | |||
| 127 | if (sqlite3_prepare_v2(ppdb_, query_str.c_str(), query_str.length(), &ppstmt, NULL) != SQLITE_OK) | ||
| 128 | { | ||
| 129 | throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_)); | ||
| 130 | } | ||
| 131 | |||
| 132 | int i = 1; | ||
| 133 | for (field& f : fields) | ||
| 134 | { | ||
| 135 | switch (f.getType()) | ||
| 136 | { | ||
| 137 | case field::type::integer: | ||
| 138 | { | ||
| 139 | sqlite3_bind_int(ppstmt, i, f.getInteger()); | ||
| 140 | |||
| 141 | break; | ||
| 142 | } | ||
| 143 | |||
| 144 | case field::type::string: | ||
| 145 | { | ||
| 146 | sqlite3_bind_text(ppstmt, i, f.getString().c_str(), f.getString().length(), SQLITE_TRANSIENT); | ||
| 147 | |||
| 148 | break; | ||
| 149 | } | ||
| 150 | |||
| 151 | case field::type::invalid: | ||
| 152 | { | ||
| 153 | // Fields can only be invalid when doing bad things with move semantics. | ||
| 154 | assert(false); | ||
| 155 | |||
| 156 | break; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | i++; | ||
| 161 | } | ||
| 162 | |||
| 163 | int result = sqlite3_step(ppstmt); | ||
| 164 | sqlite3_finalize(ppstmt); | ||
| 165 | |||
| 166 | if (result != SQLITE_DONE) | ||
| 167 | { | ||
| 168 | throw sqlite3_error("Error writing to database", sqlite3_errmsg(ppdb_)); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | }; | ||
| 173 | }; | ||
| diff --git a/generator/database.h b/generator/database.h deleted file mode 100644 index e4f3ba2..0000000 --- a/generator/database.h +++ /dev/null | |||
| @@ -1,73 +0,0 @@ | |||
| 1 | #ifndef DATABASE_H_0B0A47D2 | ||
| 2 | #define DATABASE_H_0B0A47D2 | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | #include <exception> | ||
| 6 | #include <list> | ||
| 7 | |||
| 8 | struct sqlite3; | ||
| 9 | |||
| 10 | namespace cadence { | ||
| 11 | namespace generator { | ||
| 12 | |||
| 13 | class field; | ||
| 14 | |||
| 15 | class sqlite3_error : public std::exception { | ||
| 16 | public: | ||
| 17 | |||
| 18 | sqlite3_error(const std::string& what, const std::string& db_err); | ||
| 19 | |||
| 20 | const char* what() const noexcept override; | ||
| 21 | const char* db_err() const noexcept; | ||
| 22 | |||
| 23 | private: | ||
| 24 | std::string what_; | ||
| 25 | std::string db_err_; | ||
| 26 | |||
| 27 | }; | ||
| 28 | |||
| 29 | class database { | ||
| 30 | public: | ||
| 31 | |||
| 32 | // Constructor | ||
| 33 | |||
| 34 | explicit database(std::string path); | ||
| 35 | |||
| 36 | // Disable copying | ||
| 37 | |||
| 38 | database(const database& other) = delete; | ||
| 39 | database& operator=(const database& other) = delete; | ||
| 40 | |||
| 41 | // Move constructor and move assignment | ||
| 42 | |||
| 43 | database(database&& other); | ||
| 44 | database& operator=(database&& other); | ||
| 45 | |||
| 46 | // Swap | ||
| 47 | |||
| 48 | friend void swap(database& first, database& second); | ||
| 49 | |||
| 50 | // Destructor | ||
| 51 | |||
| 52 | ~database(); | ||
| 53 | |||
| 54 | // Actions | ||
| 55 | |||
| 56 | void runQuery(std::string query); | ||
| 57 | |||
| 58 | void insertIntoTable(std::string table, std::list<field> fields); | ||
| 59 | |||
| 60 | private: | ||
| 61 | |||
| 62 | database() | ||
| 63 | { | ||
| 64 | } | ||
| 65 | |||
| 66 | sqlite3* ppdb_ = nullptr; | ||
| 67 | |||
| 68 | }; | ||
| 69 | |||
| 70 | }; | ||
| 71 | }; | ||
| 72 | |||
| 73 | #endif /* end of include guard: DATABASE_H_0B0A47D2 */ | ||
| diff --git a/generator/field.cpp b/generator/field.cpp deleted file mode 100644 index 7e7453d..0000000 --- a/generator/field.cpp +++ /dev/null | |||
| @@ -1,193 +0,0 @@ | |||
| 1 | #include "field.h" | ||
| 2 | #include <stdexcept> | ||
| 3 | #include <utility> | ||
| 4 | |||
| 5 | namespace cadence { | ||
| 6 | namespace generator { | ||
| 7 | |||
| 8 | field::field(const field& other) | ||
| 9 | { | ||
| 10 | type_ = other.type_; | ||
| 11 | name_ = other.name_; | ||
| 12 | |||
| 13 | switch (type_) | ||
| 14 | { | ||
| 15 | case type::integer: | ||
| 16 | { | ||
| 17 | integer_ = other.integer_; | ||
| 18 | |||
| 19 | break; | ||
| 20 | } | ||
| 21 | |||
| 22 | case type::string: | ||
| 23 | { | ||
| 24 | new(&string_) std::string(other.string_); | ||
| 25 | |||
| 26 | break; | ||
| 27 | } | ||
| 28 | |||
| 29 | case type::invalid: | ||
| 30 | { | ||
| 31 | break; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | field::field(field&& other) : field() | ||
| 37 | { | ||
| 38 | swap(*this, other); | ||
| 39 | } | ||
| 40 | |||
| 41 | field& field::operator=(field other) | ||
| 42 | { | ||
| 43 | swap(*this, other); | ||
| 44 | |||
| 45 | return *this; | ||
| 46 | } | ||
| 47 | |||
| 48 | void swap(field& first, field& second) | ||
| 49 | { | ||
| 50 | using type = field::type; | ||
| 51 | |||
| 52 | type tempType = first.type_; | ||
| 53 | std::string tempName = std::move(first.name_); | ||
| 54 | int tempInteger; | ||
| 55 | std::string tempString; | ||
| 56 | |||
| 57 | switch (first.type_) | ||
| 58 | { | ||
| 59 | case type::integer: | ||
| 60 | { | ||
| 61 | tempInteger = first.integer_; | ||
| 62 | |||
| 63 | break; | ||
| 64 | } | ||
| 65 | |||
| 66 | case type::string: | ||
| 67 | { | ||
| 68 | tempString = std::move(tempString); | ||
| 69 | |||
| 70 | break; | ||
| 71 | } | ||
| 72 | |||
| 73 | case type::invalid: | ||
| 74 | { | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | first.~field(); | ||
| 80 | |||
| 81 | first.type_ = second.type_; | ||
| 82 | first.name_ = std::move(second.name_); | ||
| 83 | |||
| 84 | switch (second.type_) | ||
| 85 | { | ||
| 86 | case type::integer: | ||
| 87 | { | ||
| 88 | first.integer_ = second.integer_; | ||
| 89 | |||
| 90 | break; | ||
| 91 | } | ||
| 92 | |||
| 93 | case type::string: | ||
| 94 | { | ||
| 95 | new(&first.string_) std::string(std::move(second.string_)); | ||
| 96 | |||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | case type::invalid: | ||
| 101 | { | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | second.~field(); | ||
| 107 | |||
| 108 | second.type_ = tempType; | ||
| 109 | second.name_ = std::move(tempName); | ||
| 110 | |||
| 111 | switch (tempType) | ||
| 112 | { | ||
| 113 | case type::integer: | ||
| 114 | { | ||
| 115 | second.integer_ = tempInteger; | ||
| 116 | |||
| 117 | break; | ||
| 118 | } | ||
| 119 | |||
| 120 | case type::string: | ||
| 121 | { | ||
| 122 | new(&second.string_) std::string(std::move(tempString)); | ||
| 123 | |||
| 124 | break; | ||
| 125 | } | ||
| 126 | |||
| 127 | case type::invalid: | ||
| 128 | { | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | field::~field() | ||
| 135 | { | ||
| 136 | switch (type_) | ||
| 137 | { | ||
| 138 | case type::string: | ||
| 139 | { | ||
| 140 | using string_type = std::string; | ||
| 141 | string_.~string_type(); | ||
| 142 | |||
| 143 | break; | ||
| 144 | } | ||
| 145 | |||
| 146 | case type::integer: | ||
| 147 | case type::invalid: | ||
| 148 | { | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | field::field( | ||
| 155 | std::string name, | ||
| 156 | int arg) : | ||
| 157 | type_(type::integer), | ||
| 158 | name_(name), | ||
| 159 | integer_(arg) | ||
| 160 | { | ||
| 161 | } | ||
| 162 | |||
| 163 | int field::getInteger() const | ||
| 164 | { | ||
| 165 | if (type_ != type::integer) | ||
| 166 | { | ||
| 167 | throw std::domain_error("field::getInteger called on non-integer field"); | ||
| 168 | } | ||
| 169 | |||
| 170 | return integer_; | ||
| 171 | } | ||
| 172 | |||
| 173 | field::field( | ||
| 174 | std::string name, | ||
| 175 | std::string arg) : | ||
| 176 | type_(type::string), | ||
| 177 | name_(name) | ||
| 178 | { | ||
| 179 | new(&string_) std::string(arg); | ||
| 180 | } | ||
| 181 | |||
| 182 | std::string field::getString() const | ||
| 183 | { | ||
| 184 | if (type_ != type::string) | ||
| 185 | { | ||
| 186 | throw std::domain_error("field::getString called on non-string field"); | ||
| 187 | } | ||
| 188 | |||
| 189 | return string_; | ||
| 190 | } | ||
| 191 | |||
| 192 | }; | ||
| 193 | }; | ||
| diff --git a/generator/field.h b/generator/field.h deleted file mode 100644 index 836c079..0000000 --- a/generator/field.h +++ /dev/null | |||
| @@ -1,76 +0,0 @@ | |||
| 1 | #ifndef BINDING_H_CAE0B18E | ||
| 2 | #define BINDING_H_CAE0B18E | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | |||
| 6 | namespace cadence { | ||
| 7 | namespace generator { | ||
| 8 | |||
| 9 | class field { | ||
| 10 | public: | ||
| 11 | enum class type { | ||
| 12 | invalid, | ||
| 13 | integer, | ||
| 14 | string | ||
| 15 | }; | ||
| 16 | |||
| 17 | // Copy and move constructors | ||
| 18 | |||
| 19 | field(const field& other); | ||
| 20 | field(field&& other); | ||
| 21 | |||
| 22 | // Assignment | ||
| 23 | |||
| 24 | field& operator=(field other); | ||
| 25 | |||
| 26 | // Swap | ||
| 27 | |||
| 28 | friend void swap(field& first, field& second); | ||
| 29 | |||
| 30 | // Destructor | ||
| 31 | |||
| 32 | ~field(); | ||
| 33 | |||
| 34 | // Generic accessors | ||
| 35 | |||
| 36 | type getType() const | ||
| 37 | { | ||
| 38 | return type_; | ||
| 39 | } | ||
| 40 | |||
| 41 | std::string getName() const | ||
| 42 | { | ||
| 43 | return name_; | ||
| 44 | } | ||
| 45 | |||
| 46 | // Integer | ||
| 47 | |||
| 48 | field(std::string name, int arg); | ||
| 49 | |||
| 50 | int getInteger() const; | ||
| 51 | |||
| 52 | // String | ||
| 53 | |||
| 54 | field(std::string name, std::string arg); | ||
| 55 | |||
| 56 | std::string getString() const; | ||
| 57 | |||
| 58 | private: | ||
| 59 | |||
| 60 | field() | ||
| 61 | { | ||
| 62 | } | ||
| 63 | |||
| 64 | union { | ||
| 65 | int integer_; | ||
| 66 | std::string string_; | ||
| 67 | }; | ||
| 68 | |||
| 69 | type type_ = type::invalid; | ||
| 70 | std::string name_; | ||
| 71 | }; | ||
| 72 | |||
| 73 | }; | ||
| 74 | }; | ||
| 75 | |||
| 76 | #endif /* end of include guard: BINDING_H_CAE0B18E */ | ||
| diff --git a/generator/generator.cpp b/generator/generator.cpp index 54f5d69..19eba70 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | #include <fstream> | 4 | #include <fstream> |
| 5 | #include <dirent.h> | 5 | #include <dirent.h> |
| 6 | #include <json.hpp> | 6 | #include <json.hpp> |
| 7 | #include "progress.h" | 7 | #include <hkutil/progress.h> |
| 8 | #include "field.h" | 8 | #include <hkutil/string.h> |
| 9 | #include "../util.h" | ||
| 10 | #include "mood.h" | 9 | #include "mood.h" |
| 11 | 10 | ||
| 12 | namespace cadence { | 11 | namespace cadence { |
| @@ -16,7 +15,7 @@ namespace cadence { | |||
| 16 | std::string inputpath, | 15 | std::string inputpath, |
| 17 | std::string outputpath) : | 16 | std::string outputpath) : |
| 18 | inputpath_(inputpath), | 17 | inputpath_(inputpath), |
| 19 | db_(outputpath) | 18 | db_(outputpath, hatkirby::dbmode::create) |
| 20 | { | 19 | { |
| 21 | // Add directory separator to input path | 20 | // Add directory separator to input path |
| 22 | if ((inputpath_.back() != '/') && (inputpath_.back() != '\\')) | 21 | if ((inputpath_.back() != '/') && (inputpath_.back() != '\\')) |
| @@ -61,13 +60,13 @@ namespace cadence { | |||
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | std::string schema = schemaBuilder.str(); | 62 | std::string schema = schemaBuilder.str(); |
| 64 | auto queries = split<std::list<std::string>>(schema, ";"); | 63 | auto queries = hatkirby::split<std::list<std::string>>(schema, ";"); |
| 65 | progress ppgs("Writing database schema...", queries.size()); | 64 | hatkirby::progress ppgs("Writing database schema...", queries.size()); |
| 66 | for (std::string query : queries) | 65 | for (std::string query : queries) |
| 67 | { | 66 | { |
| 68 | if (!queries.empty()) | 67 | if (!queries.empty()) |
| 69 | { | 68 | { |
| 70 | db_.runQuery(query); | 69 | db_.execute(query); |
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | ppgs.update(); | 72 | ppgs.update(); |
| @@ -134,7 +133,9 @@ namespace cadence { | |||
| 134 | 133 | ||
| 135 | void generator::parseData() | 134 | void generator::parseData() |
| 136 | { | 135 | { |
| 137 | progress ppgs("Parsing AcousticBrainz data files...", datafiles_.size()); | 136 | hatkirby::progress ppgs( |
| 137 | "Parsing AcousticBrainz data files...", | ||
| 138 | datafiles_.size()); | ||
| 138 | 139 | ||
| 139 | for (std::string datafile : datafiles_) | 140 | for (std::string datafile : datafiles_) |
| 140 | { | 141 | { |
| @@ -163,12 +164,12 @@ namespace cadence { | |||
| 163 | return left.getProbability() > right.getProbability(); | 164 | return left.getProbability() > right.getProbability(); |
| 164 | }); | 165 | }); |
| 165 | 166 | ||
| 166 | std::list<field> fields; | 167 | std::list<hatkirby::column> columns; |
| 167 | fields.emplace_back("title", jsonData["metadata"]["tags"]["title"][0].get<std::string>()); | 168 | columns.emplace_back("title", jsonData["metadata"]["tags"]["title"][0].get<std::string>()); |
| 168 | fields.emplace_back("artist", jsonData["metadata"]["tags"]["artist"][0].get<std::string>()); | 169 | columns.emplace_back("artist", jsonData["metadata"]["tags"]["artist"][0].get<std::string>()); |
| 169 | fields.emplace_back("category", moods.front().getCategory()); | 170 | columns.emplace_back("category", moods.front().getCategory()); |
| 170 | 171 | ||
| 171 | db_.insertIntoTable("songs", std::move(fields)); | 172 | db_.insertIntoTable("songs", std::move(columns)); |
| 172 | } catch (const std::domain_error& ex) | 173 | } catch (const std::domain_error& ex) |
| 173 | { | 174 | { |
| 174 | // Weird data. Ignore silently. | 175 | // Weird data. Ignore silently. |
| diff --git a/generator/generator.h b/generator/generator.h index dff8eeb..8db6764 100644 --- a/generator/generator.h +++ b/generator/generator.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <string> | 4 | #include <string> |
| 5 | #include <list> | 5 | #include <list> |
| 6 | #include "database.h" | 6 | #include <hkutil/database.h> |
| 7 | 7 | ||
| 8 | namespace cadence { | 8 | namespace cadence { |
| 9 | namespace generator { | 9 | namespace generator { |
| @@ -37,7 +37,7 @@ namespace cadence { | |||
| 37 | 37 | ||
| 38 | // Output | 38 | // Output |
| 39 | 39 | ||
| 40 | database db_; | 40 | hatkirby::database db_; |
| 41 | 41 | ||
| 42 | // Cache | 42 | // Cache |
| 43 | 43 | ||
| diff --git a/generator/progress.h b/generator/progress.h deleted file mode 100644 index e5cc13d..0000000 --- a/generator/progress.h +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | #ifndef PROGRESS_H_A34EF856 | ||
| 2 | #define PROGRESS_H_A34EF856 | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | |||
| 6 | namespace cadence { | ||
| 7 | namespace generator { | ||
| 8 | |||
| 9 | class progress { | ||
| 10 | private: | ||
| 11 | std::string message; | ||
| 12 | int total; | ||
| 13 | int cur = 0; | ||
| 14 | int lprint = 0; | ||
| 15 | |||
| 16 | public: | ||
| 17 | progress(std::string message, int total) : message(message), total(total) | ||
| 18 | { | ||
| 19 | std::cout << message << " 0%" << std::flush; | ||
| 20 | } | ||
| 21 | |||
| 22 | void update(int val) | ||
| 23 | { | ||
| 24 | if (val <= total) | ||
| 25 | { | ||
| 26 | cur = val; | ||
| 27 | } else { | ||
| 28 | cur = total; | ||
| 29 | } | ||
| 30 | |||
| 31 | int pp = cur * 100 / total; | ||
| 32 | if (pp != lprint) | ||
| 33 | { | ||
| 34 | lprint = pp; | ||
| 35 | |||
| 36 | std::cout << "\b\b\b\b" << std::right; | ||
| 37 | std::cout.width(3); | ||
| 38 | std::cout << pp << "%" << std::flush; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | void update() | ||
| 43 | { | ||
| 44 | update(cur+1); | ||
| 45 | } | ||
| 46 | |||
| 47 | ~progress() | ||
| 48 | { | ||
| 49 | std::cout << "\b\b\b\b100%" << std::endl; | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | |||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | #endif /* end of include guard: PROGRESS_H_A34EF856 */ | ||
| diff --git a/util.h b/util.h deleted file mode 100644 index 5d16649..0000000 --- a/util.h +++ /dev/null | |||
| @@ -1,74 +0,0 @@ | |||
| 1 | #ifndef UTIL_H_CED7A66D | ||
| 2 | #define UTIL_H_CED7A66D | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <string> | ||
| 6 | #include <iterator> | ||
| 7 | #include <cctype> | ||
| 8 | #include <sstream> | ||
| 9 | |||
| 10 | namespace cadence { | ||
| 11 | |||
| 12 | inline std::string uppercase(std::string in) | ||
| 13 | { | ||
| 14 | std::string result; | ||
| 15 | std::transform(std::begin(in), std::end(in), std::back_inserter(result), [] (char ch) | ||
| 16 | { | ||
| 17 | return std::toupper(ch); | ||
| 18 | }); | ||
| 19 | |||
| 20 | return result; | ||
| 21 | } | ||
| 22 | |||
| 23 | template <class InputIterator> | ||
| 24 | std::string implode(InputIterator first, InputIterator last, std::string delimiter) | ||
| 25 | { | ||
| 26 | std::stringstream result; | ||
| 27 | |||
| 28 | for (InputIterator it = first; it != last; it++) | ||
| 29 | { | ||
| 30 | if (it != first) | ||
| 31 | { | ||
| 32 | result << delimiter; | ||
| 33 | } | ||
| 34 | |||
| 35 | result << *it; | ||
| 36 | } | ||
| 37 | |||
| 38 | return result.str(); | ||
| 39 | } | ||
| 40 | |||
| 41 | template <class OutputIterator> | ||
| 42 | void split(std::string input, std::string delimiter, OutputIterator out) | ||
| 43 | { | ||
| 44 | while (!input.empty()) | ||
| 45 | { | ||
| 46 | int divider = input.find(delimiter); | ||
| 47 | if (divider == std::string::npos) | ||
| 48 | { | ||
| 49 | *out = input; | ||
| 50 | out++; | ||
| 51 | |||
| 52 | input = ""; | ||
| 53 | } else { | ||
| 54 | *out = input.substr(0, divider); | ||
| 55 | out++; | ||
| 56 | |||
| 57 | input = input.substr(divider+delimiter.length()); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | template <class Container> | ||
| 63 | Container split(std::string input, std::string delimiter) | ||
| 64 | { | ||
| 65 | Container result; | ||
| 66 | |||
| 67 | split(input, delimiter, std::back_inserter(result)); | ||
| 68 | |||
| 69 | return result; | ||
| 70 | } | ||
| 71 | |||
| 72 | }; | ||
| 73 | |||
| 74 | #endif /* end of include guard: UTIL_H_CED7A66D */ | ||
| diff --git a/vendor/hkutil b/vendor/hkutil new file mode 160000 | |||
| Subproject 41f2eb087900d4f2ea95c3e11087cf2c71395ba | |||
