about summary refs log tree commit diff stats
path: root/generator
diff options
context:
space:
mode:
Diffstat (limited to 'generator')
-rw-r--r--generator/CMakeLists.txt8
-rw-r--r--generator/database.cpp173
-rw-r--r--generator/database.h73
-rw-r--r--generator/field.cpp193
-rw-r--r--generator/field.h76
-rw-r--r--generator/generator.cpp27
-rw-r--r--generator/generator.h4
-rw-r--r--generator/progress.h56
8 files changed, 22 insertions, 588 deletions
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)
4find_package(PkgConfig) 4find_package(PkgConfig)
5pkg_check_modules(sqlite3 sqlite3 REQUIRED) 5pkg_check_modules(sqlite3 sqlite3 REQUIRED)
6 6
7include_directories(${sqlite3_INCLUDE_DIR} vendor/json) 7include_directories(
8add_executable(generator mood.cpp database.cpp field.cpp generator.cpp main.cpp) 8 ${sqlite3_INCLUDE_DIR}
9 vendor/json
10 ../vendor/hkutil)
11
12add_executable(generator mood.cpp generator.cpp main.cpp)
9set_property(TARGET generator PROPERTY CXX_STANDARD 11) 13set_property(TARGET generator PROPERTY CXX_STANDARD 11)
10set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON) 14set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON)
11target_link_libraries(generator ${sqlite3_LIBRARIES}) 15target_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
11namespace 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
8struct sqlite3;
9
10namespace 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
5namespace 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
6namespace 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
12namespace cadence { 11namespace 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
8namespace cadence { 8namespace 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
6namespace 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 */