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 | |||