diff options
| -rw-r--r-- | CMakeLists.txt | 17 | ||||
| -rw-r--r-- | lib/binding.cpp | 249 | ||||
| -rw-r--r-- | lib/binding.h | 82 | ||||
| -rw-r--r-- | lib/database.cpp | 123 | ||||
| -rw-r--r-- | lib/database.h | 61 | ||||
| -rw-r--r-- | lib/form.cpp | 52 | ||||
| -rw-r--r-- | lib/form.h | 26 | ||||
| -rw-r--r-- | lib/frame.cpp | 9 | ||||
| -rw-r--r-- | lib/frame.h | 10 | ||||
| -rw-r--r-- | lib/notion.cpp | 16 | ||||
| -rw-r--r-- | lib/notion.h | 118 | ||||
| -rw-r--r-- | lib/part.cpp | 350 | ||||
| -rw-r--r-- | lib/part.h | 97 | ||||
| -rw-r--r-- | lib/pronunciation.cpp | 24 | ||||
| -rw-r--r-- | lib/pronunciation.h | 22 | ||||
| -rw-r--r-- | lib/query.h | 107 | ||||
| -rw-r--r-- | lib/statement.cpp | 621 | ||||
| -rw-r--r-- | lib/statement.h | 96 | ||||
| -rw-r--r-- | lib/token.cpp | 495 | ||||
| -rw-r--r-- | lib/token.h | 76 | ||||
| -rw-r--r-- | lib/word.cpp | 85 | ||||
| -rw-r--r-- | lib/word.h | 50 | ||||
| m--------- | vendor/hkutil | 0 |
23 files changed, 866 insertions, 1920 deletions
| diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dd2792..2adad19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -6,11 +6,24 @@ pkg_check_modules(sqlite3 sqlite3>=3.8.3 REQUIRED) | |||
| 6 | 6 | ||
| 7 | set(CMAKE_BUILD_TYPE Debug) | 7 | set(CMAKE_BUILD_TYPE Debug) |
| 8 | 8 | ||
| 9 | include_directories( | 9 | add_library(verbly |
| 10 | lib/filter.cpp | ||
| 11 | lib/field.cpp | ||
| 12 | lib/notion.cpp | ||
| 13 | lib/word.cpp | ||
| 14 | lib/frame.cpp | ||
| 15 | lib/part.cpp | ||
| 16 | lib/form.cpp | ||
| 17 | lib/pronunciation.cpp | ||
| 18 | lib/statement.cpp | ||
| 19 | lib/database.cpp | ||
| 20 | lib/token.cpp) | ||
| 21 | |||
| 22 | target_include_directories(verbly PUBLIC | ||
| 23 | lib | ||
| 10 | vendor/hkutil | 24 | vendor/hkutil |
| 11 | vendor/hkutil/vendor) | 25 | vendor/hkutil/vendor) |
| 12 | 26 | ||
| 13 | add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/part.cpp) | ||
| 14 | set_property(TARGET verbly PROPERTY CXX_STANDARD 11) | 27 | set_property(TARGET verbly PROPERTY CXX_STANDARD 11) |
| 15 | set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) | 28 | set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) |
| 16 | target_link_libraries(verbly ${sqlite3_LIBRARIES}) | 29 | target_link_libraries(verbly ${sqlite3_LIBRARIES}) |
| diff --git a/lib/binding.cpp b/lib/binding.cpp deleted file mode 100644 index 0b58785..0000000 --- a/lib/binding.cpp +++ /dev/null | |||
| @@ -1,249 +0,0 @@ | |||
| 1 | #include "binding.h" | ||
| 2 | #include <stdexcept> | ||
| 3 | #include <utility> | ||
| 4 | |||
| 5 | namespace verbly { | ||
| 6 | |||
| 7 | binding::binding(const binding& other) | ||
| 8 | { | ||
| 9 | type_ = other.type_; | ||
| 10 | |||
| 11 | switch (type_) | ||
| 12 | { | ||
| 13 | case type::integer: | ||
| 14 | { | ||
| 15 | integer_ = other.integer_; | ||
| 16 | |||
| 17 | break; | ||
| 18 | } | ||
| 19 | |||
| 20 | case type::string: | ||
| 21 | { | ||
| 22 | new(&string_) std::string(other.string_); | ||
| 23 | |||
| 24 | break; | ||
| 25 | } | ||
| 26 | |||
| 27 | case type::field: | ||
| 28 | { | ||
| 29 | new(&field_.table_) std::string(other.field_.table_); | ||
| 30 | new(&field_.column_) std::string(other.field_.column_); | ||
| 31 | |||
| 32 | break; | ||
| 33 | } | ||
| 34 | |||
| 35 | case type::invalid: | ||
| 36 | { | ||
| 37 | break; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | binding::binding(binding&& other) : binding() | ||
| 43 | { | ||
| 44 | swap(*this, other); | ||
| 45 | } | ||
| 46 | |||
| 47 | binding& binding::operator=(binding other) | ||
| 48 | { | ||
| 49 | swap(*this, other); | ||
| 50 | |||
| 51 | return *this; | ||
| 52 | } | ||
| 53 | |||
| 54 | void swap(binding& first, binding& second) | ||
| 55 | { | ||
| 56 | using type = binding::type; | ||
| 57 | |||
| 58 | type tempType = first.type_; | ||
| 59 | int tempInteger; | ||
| 60 | std::string tempString; | ||
| 61 | std::string tempTable; | ||
| 62 | std::string tempColumn; | ||
| 63 | |||
| 64 | switch (first.type_) | ||
| 65 | { | ||
| 66 | case type::integer: | ||
| 67 | { | ||
| 68 | tempInteger = first.integer_; | ||
| 69 | |||
| 70 | break; | ||
| 71 | } | ||
| 72 | |||
| 73 | case type::string: | ||
| 74 | { | ||
| 75 | tempString = std::move(tempString); | ||
| 76 | |||
| 77 | break; | ||
| 78 | } | ||
| 79 | |||
| 80 | case type::field: | ||
| 81 | { | ||
| 82 | tempTable = std::move(first.field_.table_); | ||
| 83 | tempColumn = std::move(first.field_.column_); | ||
| 84 | |||
| 85 | break; | ||
| 86 | } | ||
| 87 | |||
| 88 | case type::invalid: | ||
| 89 | { | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | first.~binding(); | ||
| 95 | |||
| 96 | first.type_ = second.type_; | ||
| 97 | |||
| 98 | switch (second.type_) | ||
| 99 | { | ||
| 100 | case type::integer: | ||
| 101 | { | ||
| 102 | first.integer_ = second.integer_; | ||
| 103 | |||
| 104 | break; | ||
| 105 | } | ||
| 106 | |||
| 107 | case type::string: | ||
| 108 | { | ||
| 109 | new(&first.string_) std::string(std::move(second.string_)); | ||
| 110 | |||
| 111 | break; | ||
| 112 | } | ||
| 113 | |||
| 114 | case type::field: | ||
| 115 | { | ||
| 116 | new(&first.field_.table_) std::string(std::move(second.field_.table_)); | ||
| 117 | new(&first.field_.column_) std::string(std::move(second.field_.column_)); | ||
| 118 | |||
| 119 | break; | ||
| 120 | } | ||
| 121 | |||
| 122 | case type::invalid: | ||
| 123 | { | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | second.~binding(); | ||
| 129 | |||
| 130 | second.type_ = tempType; | ||
| 131 | |||
| 132 | switch (tempType) | ||
| 133 | { | ||
| 134 | case type::integer: | ||
| 135 | { | ||
| 136 | second.integer_ = tempInteger; | ||
| 137 | |||
| 138 | break; | ||
| 139 | } | ||
| 140 | |||
| 141 | case type::string: | ||
| 142 | { | ||
| 143 | new(&second.string_) std::string(std::move(tempString)); | ||
| 144 | |||
| 145 | break; | ||
| 146 | } | ||
| 147 | |||
| 148 | case type::field: | ||
| 149 | { | ||
| 150 | new(&first.field_.table_) std::string(std::move(tempTable)); | ||
| 151 | new(&first.field_.column_) std::string(std::move(tempColumn)); | ||
| 152 | |||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | case type::invalid: | ||
| 157 | { | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | binding::~binding() | ||
| 164 | { | ||
| 165 | switch (type_) | ||
| 166 | { | ||
| 167 | case type::string: | ||
| 168 | { | ||
| 169 | using string_type = std::string; | ||
| 170 | string_.~string_type(); | ||
| 171 | |||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | case type::field: | ||
| 176 | { | ||
| 177 | using string_type = std::string; | ||
| 178 | field_.table_.~string_type(); | ||
| 179 | field_.column_.~string_type(); | ||
| 180 | |||
| 181 | break; | ||
| 182 | } | ||
| 183 | |||
| 184 | case type::integer: | ||
| 185 | case type::invalid: | ||
| 186 | { | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | binding::binding(int arg) : | ||
| 193 | type_(type::integer), | ||
| 194 | integer_(arg) | ||
| 195 | { | ||
| 196 | } | ||
| 197 | |||
| 198 | int binding::getInteger() const | ||
| 199 | { | ||
| 200 | if (type_ != type::integer) | ||
| 201 | { | ||
| 202 | throw std::domain_error("binding::getInteger called on non-integer binding"); | ||
| 203 | } | ||
| 204 | |||
| 205 | return integer_; | ||
| 206 | } | ||
| 207 | |||
| 208 | binding::binding(std::string arg) : type_(type::string) | ||
| 209 | { | ||
| 210 | new(&string_) std::string(std::move(arg)); | ||
| 211 | } | ||
| 212 | |||
| 213 | std::string binding::getString() const | ||
| 214 | { | ||
| 215 | if (type_ != type::string) | ||
| 216 | { | ||
| 217 | throw std::domain_error("binding::getString called on non-string binding"); | ||
| 218 | } | ||
| 219 | |||
| 220 | return string_; | ||
| 221 | } | ||
| 222 | |||
| 223 | binding::binding(std::string table, std::string column) : type_(type::field) | ||
| 224 | { | ||
| 225 | new(&field_.table_) std::string(std::move(table)); | ||
| 226 | new(&field_.column_) std::string(std::move(column)); | ||
| 227 | } | ||
| 228 | |||
| 229 | std::string binding::getTable() const | ||
| 230 | { | ||
| 231 | if (type_ != type::field) | ||
| 232 | { | ||
| 233 | throw std::domain_error("binding::getTable called on non-field binding"); | ||
| 234 | } | ||
| 235 | |||
| 236 | return field_.table_; | ||
| 237 | } | ||
| 238 | |||
| 239 | std::string binding::getColumn() const | ||
| 240 | { | ||
| 241 | if (type_ != type::field) | ||
| 242 | { | ||
| 243 | throw std::domain_error("binding::getColumn called on non-field binding"); | ||
| 244 | } | ||
| 245 | |||
| 246 | return field_.column_; | ||
| 247 | } | ||
| 248 | |||
| 249 | }; | ||
| diff --git a/lib/binding.h b/lib/binding.h deleted file mode 100644 index 5da1e71..0000000 --- a/lib/binding.h +++ /dev/null | |||
| @@ -1,82 +0,0 @@ | |||
| 1 | #ifndef BINDING_H_CAE0B18E | ||
| 2 | #define BINDING_H_CAE0B18E | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | |||
| 6 | namespace verbly { | ||
| 7 | |||
| 8 | class binding { | ||
| 9 | public: | ||
| 10 | enum class type { | ||
| 11 | invalid, | ||
| 12 | integer, | ||
| 13 | string, | ||
| 14 | field | ||
| 15 | }; | ||
| 16 | |||
| 17 | // Default constructor | ||
| 18 | |||
| 19 | binding() | ||
| 20 | { | ||
| 21 | } | ||
| 22 | |||
| 23 | // Copy and move constructors | ||
| 24 | |||
| 25 | binding(const binding& other); | ||
| 26 | binding(binding&& other); | ||
| 27 | |||
| 28 | // Assignment | ||
| 29 | |||
| 30 | binding& operator=(binding other); | ||
| 31 | |||
| 32 | // Swap | ||
| 33 | |||
| 34 | friend void swap(binding& first, binding& second); | ||
| 35 | |||
| 36 | // Destructor | ||
| 37 | |||
| 38 | ~binding(); | ||
| 39 | |||
| 40 | // Generic accessors | ||
| 41 | |||
| 42 | type getType() const | ||
| 43 | { | ||
| 44 | return type_; | ||
| 45 | } | ||
| 46 | |||
| 47 | // Integer | ||
| 48 | |||
| 49 | binding(int arg); | ||
| 50 | |||
| 51 | int getInteger() const; | ||
| 52 | |||
| 53 | // String | ||
| 54 | |||
| 55 | binding(std::string arg); | ||
| 56 | |||
| 57 | std::string getString() const; | ||
| 58 | |||
| 59 | // Field | ||
| 60 | |||
| 61 | binding(std::string table, std::string column); | ||
| 62 | |||
| 63 | std::string getTable() const; | ||
| 64 | std::string getColumn() const; | ||
| 65 | |||
| 66 | private: | ||
| 67 | |||
| 68 | union { | ||
| 69 | int integer_; | ||
| 70 | std::string string_; | ||
| 71 | struct { | ||
| 72 | std::string table_; | ||
| 73 | std::string column_; | ||
| 74 | } field_; | ||
| 75 | }; | ||
| 76 | |||
| 77 | type type_ = type::invalid; | ||
| 78 | }; | ||
| 79 | |||
| 80 | }; | ||
| 81 | |||
| 82 | #endif /* end of include guard: BINDING_H_CAE0B18E */ | ||
| diff --git a/lib/database.cpp b/lib/database.cpp index fe64763..96eed45 100644 --- a/lib/database.cpp +++ b/lib/database.cpp | |||
| @@ -1,48 +1,19 @@ | |||
| 1 | #include "database.h" | 1 | #include "database.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include <stdexcept> | ||
| 4 | #include <sstream> | 2 | #include <sstream> |
| 5 | #include "query.h" | 3 | #include "query.h" |
| 6 | #include "version.h" | 4 | #include "version.h" |
| 7 | 5 | ||
| 8 | namespace verbly { | 6 | namespace verbly { |
| 9 | 7 | ||
| 10 | database::database(std::string path) | 8 | database::database( |
| 9 | std::string path) : | ||
| 10 | ppdb_(std::move(path), hatkirby::dbmode::read) | ||
| 11 | { | 11 | { |
| 12 | if (sqlite3_open_v2(path.c_str(), &ppdb_, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) | 12 | hatkirby::row version = |
| 13 | { | 13 | ppdb_.queryFirst("SELECT major, minor FROM version"); |
| 14 | // We still have to free the resources allocated. In the event that | ||
| 15 | // allocation failed, ppdb will be null and sqlite3_close_v2 will just | ||
| 16 | // ignore it. | ||
| 17 | std::string errmsg(sqlite3_errmsg(ppdb_)); | ||
| 18 | sqlite3_close_v2(ppdb_); | ||
| 19 | |||
| 20 | throw database_error("Could not open verbly datafile", errmsg); | ||
| 21 | } | ||
| 22 | |||
| 23 | std::string queryString = "SELECT major, minor FROM version"; | ||
| 24 | |||
| 25 | sqlite3_stmt* ppstmt; | ||
| 26 | if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK) | ||
| 27 | { | ||
| 28 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 29 | sqlite3_finalize(ppstmt); | ||
| 30 | |||
| 31 | throw database_error("Error reading database version", errorMsg); | ||
| 32 | } | ||
| 33 | |||
| 34 | if (sqlite3_step(ppstmt) != SQLITE_ROW) | ||
| 35 | { | ||
| 36 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 37 | sqlite3_finalize(ppstmt); | ||
| 38 | |||
| 39 | throw database_error("Error reading database version", errorMsg); | ||
| 40 | } | ||
| 41 | 14 | ||
| 42 | major_ = sqlite3_column_int(ppstmt, 0); | 15 | major_ = mpark::get<int>(version[0]); |
| 43 | minor_ = sqlite3_column_int(ppstmt, 1); | 16 | minor_ = mpark::get<int>(version[1]); |
| 44 | |||
| 45 | sqlite3_finalize(ppstmt); | ||
| 46 | 17 | ||
| 47 | if (major_ != DATABASE_MAJOR_VERSION) | 18 | if (major_ != DATABASE_MAJOR_VERSION) |
| 48 | { | 19 | { |
| @@ -50,28 +21,6 @@ namespace verbly { | |||
| 50 | } | 21 | } |
| 51 | } | 22 | } |
| 52 | 23 | ||
| 53 | database::database(database&& other) : database() | ||
| 54 | { | ||
| 55 | swap(*this, other); | ||
| 56 | } | ||
| 57 | |||
| 58 | database& database::operator=(database&& other) | ||
| 59 | { | ||
| 60 | swap(*this, other); | ||
| 61 | |||
| 62 | return *this; | ||
| 63 | } | ||
| 64 | |||
| 65 | void swap(database& first, database& second) | ||
| 66 | { | ||
| 67 | std::swap(first.ppdb_, second.ppdb_); | ||
| 68 | } | ||
| 69 | |||
| 70 | database::~database() | ||
| 71 | { | ||
| 72 | sqlite3_close_v2(ppdb_); | ||
| 73 | } | ||
| 74 | |||
| 75 | query<notion> database::notions(filter where, order sortOrder, int limit) const | 24 | query<notion> database::notions(filter where, order sortOrder, int limit) const |
| 76 | { | 25 | { |
| 77 | return query<notion>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); | 26 | return query<notion>(*this, ppdb_, std::move(where), std::move(sortOrder), limit); |
| @@ -104,65 +53,35 @@ namespace verbly { | |||
| 104 | 53 | ||
| 105 | std::set<std::string> database::selrestrs(int partId) const | 54 | std::set<std::string> database::selrestrs(int partId) const |
| 106 | { | 55 | { |
| 107 | std::string queryString = "SELECT selrestr FROM selrestrs WHERE part_id = ?"; | 56 | std::vector<hatkirby::row> rows = |
| 108 | 57 | ppdb_.queryAll( | |
| 109 | sqlite3_stmt* ppstmt; | 58 | "SELECT selrestr FROM selrestrs WHERE part_id = ?", |
| 110 | if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK) | 59 | { partId }); |
| 111 | { | ||
| 112 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 113 | sqlite3_finalize(ppstmt); | ||
| 114 | |||
| 115 | throw database_error("Error preparing query", errorMsg); | ||
| 116 | } | ||
| 117 | |||
| 118 | if (sqlite3_bind_int(ppstmt, 1, partId) != SQLITE_OK) | ||
| 119 | { | ||
| 120 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 121 | sqlite3_finalize(ppstmt); | ||
| 122 | |||
| 123 | throw database_error("Error binding value to query", errorMsg); | ||
| 124 | } | ||
| 125 | 60 | ||
| 126 | std::set<std::string> result; | 61 | std::set<std::string> result; |
| 127 | while (sqlite3_step(ppstmt) == SQLITE_ROW) | 62 | |
| 63 | for (hatkirby::row& r : rows) | ||
| 128 | { | 64 | { |
| 129 | result.insert(reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0))); | 65 | result.emplace(std::move(mpark::get<std::string>(r[0]))); |
| 130 | } | 66 | } |
| 131 | 67 | ||
| 132 | sqlite3_finalize(ppstmt); | ||
| 133 | |||
| 134 | return result; | 68 | return result; |
| 135 | } | 69 | } |
| 136 | 70 | ||
| 137 | std::set<std::string> database::synrestrs(int partId) const | 71 | std::set<std::string> database::synrestrs(int partId) const |
| 138 | { | 72 | { |
| 139 | std::string queryString = "SELECT synrestr FROM synrestrs WHERE part_id = ?"; | 73 | std::vector<hatkirby::row> rows = |
| 140 | 74 | ppdb_.queryAll( | |
| 141 | sqlite3_stmt* ppstmt; | 75 | "SELECT synrestr FROM synrestrs WHERE part_id = ?", |
| 142 | if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK) | 76 | { partId }); |
| 143 | { | ||
| 144 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 145 | sqlite3_finalize(ppstmt); | ||
| 146 | |||
| 147 | throw database_error("Error preparing query", errorMsg); | ||
| 148 | } | ||
| 149 | |||
| 150 | if (sqlite3_bind_int(ppstmt, 1, partId) != SQLITE_OK) | ||
| 151 | { | ||
| 152 | std::string errorMsg = sqlite3_errmsg(ppdb_); | ||
| 153 | sqlite3_finalize(ppstmt); | ||
| 154 | |||
| 155 | throw database_error("Error binding value to query", errorMsg); | ||
| 156 | } | ||
| 157 | 77 | ||
| 158 | std::set<std::string> result; | 78 | std::set<std::string> result; |
| 159 | while (sqlite3_step(ppstmt) == SQLITE_ROW) | 79 | |
| 80 | for (hatkirby::row& r : rows) | ||
| 160 | { | 81 | { |
| 161 | result.insert(reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0))); | 82 | result.emplace(std::move(mpark::get<std::string>(r[0]))); |
| 162 | } | 83 | } |
| 163 | 84 | ||
| 164 | sqlite3_finalize(ppstmt); | ||
| 165 | |||
| 166 | return result; | 85 | return result; |
| 167 | } | 86 | } |
| 168 | 87 | ||
| diff --git a/lib/database.h b/lib/database.h index efb54e1..83c4c1c 100644 --- a/lib/database.h +++ b/lib/database.h | |||
| @@ -1,11 +1,10 @@ | |||
| 1 | #ifndef DATABASE_H_0B0A47D2 | 1 | #ifndef DATABASE_H_0B0A47D1 |
| 2 | #define DATABASE_H_0B0A47D2 | 2 | #define DATABASE_H_0B0A47D1 |
| 3 | 3 | ||
| 4 | #include <string> | 4 | #include <string> |
| 5 | #include <exception> | ||
| 6 | #include <stdexcept> | 5 | #include <stdexcept> |
| 7 | #include <list> | ||
| 8 | #include <set> | 6 | #include <set> |
| 7 | #include <hkutil/database.h> | ||
| 9 | #include "notion.h" | 8 | #include "notion.h" |
| 10 | #include "word.h" | 9 | #include "word.h" |
| 11 | #include "frame.h" | 10 | #include "frame.h" |
| @@ -14,8 +13,6 @@ | |||
| 14 | #include "pronunciation.h" | 13 | #include "pronunciation.h" |
| 15 | #include "order.h" | 14 | #include "order.h" |
| 16 | 15 | ||
| 17 | struct sqlite3; | ||
| 18 | |||
| 19 | namespace verbly { | 16 | namespace verbly { |
| 20 | 17 | ||
| 21 | template <typename Object> | 18 | template <typename Object> |
| @@ -28,24 +25,6 @@ namespace verbly { | |||
| 28 | 25 | ||
| 29 | explicit database(std::string path); | 26 | explicit database(std::string path); |
| 30 | 27 | ||
| 31 | // Disable copying | ||
| 32 | |||
| 33 | database(const database& other) = delete; | ||
| 34 | database& operator=(const database& other) = delete; | ||
| 35 | |||
| 36 | // Move constructor and move assignment | ||
| 37 | |||
| 38 | database(database&& other); | ||
| 39 | database& operator=(database&& other); | ||
| 40 | |||
| 41 | // Swap | ||
| 42 | |||
| 43 | friend void swap(database& first, database& second); | ||
| 44 | |||
| 45 | // Destructor | ||
| 46 | |||
| 47 | ~database(); | ||
| 48 | |||
| 49 | // Information | 28 | // Information |
| 50 | 29 | ||
| 51 | int getMajorVersion() const | 30 | int getMajorVersion() const |
| @@ -60,17 +39,35 @@ namespace verbly { | |||
| 60 | 39 | ||
| 61 | // Queries | 40 | // Queries |
| 62 | 41 | ||
| 63 | query<notion> notions(filter where, order sortOrder = {}, int limit = 1) const; | 42 | query<notion> notions( |
| 43 | filter where, | ||
| 44 | order sortOrder = {}, | ||
| 45 | int limit = 1) const; | ||
| 64 | 46 | ||
| 65 | query<word> words(filter where, order sortOrder = {}, int limit = 1) const; | 47 | query<word> words( |
| 48 | filter where, | ||
| 49 | order sortOrder = {}, | ||
| 50 | int limit = 1) const; | ||
| 66 | 51 | ||
| 67 | query<frame> frames(filter where, order sortOrder = {}, int limit = 1) const; | 52 | query<frame> frames( |
| 53 | filter where, | ||
| 54 | order sortOrder = {}, | ||
| 55 | int limit = 1) const; | ||
| 68 | 56 | ||
| 69 | query<part> parts(filter where, order sortOrder = {}, int limit = 1) const; | 57 | query<part> parts( |
| 58 | filter where, | ||
| 59 | order sortOrder = {}, | ||
| 60 | int limit = 1) const; | ||
| 70 | 61 | ||
| 71 | query<form> forms(filter where, order sortOrder = {}, int limit = 1) const; | 62 | query<form> forms( |
| 63 | filter where, | ||
| 64 | order sortOrder = {}, | ||
| 65 | int limit = 1) const; | ||
| 72 | 66 | ||
| 73 | query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const; | 67 | query<pronunciation> pronunciations( |
| 68 | filter where, | ||
| 69 | order sortOrder = {}, | ||
| 70 | int limit = 1) const; | ||
| 74 | 71 | ||
| 75 | std::set<std::string> selrestrs(int partId) const; | 72 | std::set<std::string> selrestrs(int partId) const; |
| 76 | 73 | ||
| @@ -78,9 +75,7 @@ namespace verbly { | |||
| 78 | 75 | ||
| 79 | private: | 76 | private: |
| 80 | 77 | ||
| 81 | database() = default; | 78 | mutable hatkirby::database ppdb_; |
| 82 | |||
| 83 | sqlite3* ppdb_ = nullptr; | ||
| 84 | 79 | ||
| 85 | int major_; | 80 | int major_; |
| 86 | int minor_; | 81 | int minor_; |
| diff --git a/lib/form.cpp b/lib/form.cpp index b2c424d..4983274 100644 --- a/lib/form.cpp +++ b/lib/form.cpp | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | #include "form.h" | 1 | #include "form.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include <algorithm> | 2 | #include <algorithm> |
| 4 | #include "filter.h" | 3 | #include "filter.h" |
| 5 | #include "database.h" | 4 | #include "database.h" |
| @@ -24,29 +23,15 @@ namespace verbly { | |||
| 24 | return field::joinThroughWhere(object::form, "form_id", object::word, "lemmas_forms", "lemma_id", "category", static_cast<int>(category)); | 23 | return field::joinThroughWhere(object::form, "form_id", object::word, "lemmas_forms", "lemma_id", "category", static_cast<int>(category)); |
| 25 | } | 24 | } |
| 26 | 25 | ||
| 27 | form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 26 | form::form(const database& db, hatkirby::row row) : valid_(true) |
| 28 | { | 27 | { |
| 29 | id_ = sqlite3_column_int(row, 0); | 28 | id_ = mpark::get<int>(row[0]); |
| 30 | text_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 1))); | 29 | text_ = mpark::get<std::string>(row[1]); |
| 31 | complexity_ = sqlite3_column_int(row, 2); | 30 | complexity_ = mpark::get<int>(row[2]); |
| 32 | proper_ = (sqlite3_column_int(row, 3) == 1); | 31 | proper_ = (mpark::get<int>(row[3]) == 1); |
| 33 | length_ = sqlite3_column_int(row, 4); | 32 | length_ = mpark::get<int>(row[4]); |
| 34 | } | ||
| 35 | |||
| 36 | const std::vector<pronunciation>& form::getPronunciations() const | ||
| 37 | { | ||
| 38 | if (!valid_) | ||
| 39 | { | ||
| 40 | throw std::domain_error("Bad access to uninitialized form"); | ||
| 41 | } | ||
| 42 | |||
| 43 | if (!initializedPronunciations_) | ||
| 44 | { | ||
| 45 | pronunciations_ = db_->pronunciations(pronunciation::forms %= *this, pronunciation::id, -1).all(); | ||
| 46 | initializedPronunciations_ = true; | ||
| 47 | } | ||
| 48 | 33 | ||
| 49 | return pronunciations_; | 34 | pronunciations_ = db.pronunciations(*this, pronunciation::id, -1).all(); |
| 50 | } | 35 | } |
| 51 | 36 | ||
| 52 | bool form::startsWithVowelSound() const | 37 | bool form::startsWithVowelSound() const |
| @@ -56,17 +41,24 @@ namespace verbly { | |||
| 56 | throw std::domain_error("Bad access to uninitialized form"); | 41 | throw std::domain_error("Bad access to uninitialized form"); |
| 57 | } | 42 | } |
| 58 | 43 | ||
| 59 | const std::vector<pronunciation>& pronunciations = getPronunciations(); | 44 | if (!pronunciations_.empty()) |
| 60 | if (!pronunciations.empty()) | ||
| 61 | { | 45 | { |
| 62 | return std::any_of(std::begin(pronunciations), std::end(pronunciations), [] (const pronunciation& p) { | 46 | return std::any_of( |
| 63 | return p.getPhonemes().front().find_first_of("012") != std::string::npos; | 47 | std::begin(pronunciations_), |
| 64 | }); | 48 | std::end(pronunciations_), |
| 49 | [] (const pronunciation& p) { | ||
| 50 | return p.getPhonemes().front().find_first_of("012") != | ||
| 51 | std::string::npos; | ||
| 52 | }); | ||
| 65 | } else { | 53 | } else { |
| 66 | // If the word is not in CMUDICT, fall back to checking whether the first letter is a vowel. | 54 | // If the word is not in CMUDICT, fall back to checking whether the first |
| 67 | // Not perfect but will work in most cases. | 55 | // letter is a vowel. Not perfect but will work in most cases. |
| 68 | char ch = std::tolower(text_.front()); | 56 | char ch = std::tolower(text_.front()); |
| 69 | return (ch == 'a') || (ch == 'e') || (ch == 'i') || (ch == 'o') || (ch == 'u'); | 57 | return (ch == 'a') || |
| 58 | (ch == 'e') || | ||
| 59 | (ch == 'i') || | ||
| 60 | (ch == 'o') || | ||
| 61 | (ch == 'u'); | ||
| 70 | } | 62 | } |
| 71 | } | 63 | } |
| 72 | 64 | ||
| diff --git a/lib/form.h b/lib/form.h index 479672f..b365943 100644 --- a/lib/form.h +++ b/lib/form.h | |||
| @@ -5,12 +5,11 @@ | |||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <stdexcept> | 7 | #include <stdexcept> |
| 8 | #include <hkutil/database.h> | ||
| 8 | #include "field.h" | 9 | #include "field.h" |
| 9 | #include "pronunciation.h" | 10 | #include "pronunciation.h" |
| 10 | #include "filter.h" | 11 | #include "filter.h" |
| 11 | 12 | ||
| 12 | struct sqlite3_stmt; | ||
| 13 | |||
| 14 | namespace verbly { | 13 | namespace verbly { |
| 15 | 14 | ||
| 16 | class database; | 15 | class database; |
| @@ -24,7 +23,7 @@ namespace verbly { | |||
| 24 | 23 | ||
| 25 | // Construct from database | 24 | // Construct from database |
| 26 | 25 | ||
| 27 | form(const database& db, sqlite3_stmt* row); | 26 | form(const database& db, hatkirby::row row); |
| 28 | 27 | ||
| 29 | // Accessors | 28 | // Accessors |
| 30 | 29 | ||
| @@ -43,7 +42,7 @@ namespace verbly { | |||
| 43 | return id_; | 42 | return id_; |
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | std::string getText() const | 45 | const std::string& getText() const |
| 47 | { | 46 | { |
| 48 | if (!valid_) | 47 | if (!valid_) |
| 49 | { | 48 | { |
| @@ -83,7 +82,15 @@ namespace verbly { | |||
| 83 | return length_; | 82 | return length_; |
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | const std::vector<pronunciation>& getPronunciations() const; | 85 | const std::vector<pronunciation>& getPronunciations() const |
| 86 | { | ||
| 87 | if (!valid_) | ||
| 88 | { | ||
| 89 | throw std::domain_error("Bad access to uninitialized form"); | ||
| 90 | } | ||
| 91 | |||
| 92 | return pronunciations_; | ||
| 93 | } | ||
| 87 | 94 | ||
| 88 | // Convenience | 95 | // Convenience |
| 89 | 96 | ||
| @@ -130,19 +137,14 @@ namespace verbly { | |||
| 130 | static const field pronunciations; | 137 | static const field pronunciations; |
| 131 | 138 | ||
| 132 | private: | 139 | private: |
| 133 | bool valid_ = false; | ||
| 134 | 140 | ||
| 141 | bool valid_ = false; | ||
| 135 | int id_; | 142 | int id_; |
| 136 | std::string text_; | 143 | std::string text_; |
| 137 | int complexity_; | 144 | int complexity_; |
| 138 | bool proper_; | 145 | bool proper_; |
| 139 | int length_; | 146 | int length_; |
| 140 | 147 | std::vector<pronunciation> pronunciations_; | |
| 141 | const database* db_; | ||
| 142 | |||
| 143 | mutable bool initializedPronunciations_ = false; | ||
| 144 | mutable std::vector<pronunciation> pronunciations_; | ||
| 145 | |||
| 146 | }; | 148 | }; |
| 147 | 149 | ||
| 148 | }; | 150 | }; |
| diff --git a/lib/frame.cpp b/lib/frame.cpp index 2351973..51d6936 100644 --- a/lib/frame.cpp +++ b/lib/frame.cpp | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | #include "frame.h" | 1 | #include "frame.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include "database.h" | 2 | #include "database.h" |
| 4 | #include "query.h" | 3 | #include "query.h" |
| 5 | 4 | ||
| @@ -24,11 +23,11 @@ namespace verbly { | |||
| 24 | return field::joinWhere(object::frame, "frame_id", object::part, "part_index", index); | 23 | return field::joinWhere(object::frame, "frame_id", object::part, "part_index", index); |
| 25 | } | 24 | } |
| 26 | 25 | ||
| 27 | frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 26 | frame::frame(const database& db, hatkirby::row row) : valid_(true) |
| 28 | { | 27 | { |
| 29 | id_ = sqlite3_column_int(row, 0); | 28 | id_ = mpark::get<int>(row[0]); |
| 30 | groupId_ = sqlite3_column_int(row, 1); | 29 | groupId_ = mpark::get<int>(row[1]); |
| 31 | length_ = sqlite3_column_int(row, 2); | 30 | length_ = mpark::get<int>(row[2]); |
| 32 | 31 | ||
| 33 | parts_ = db.parts(*this, verbly::part::index, -1).all(); | 32 | parts_ = db.parts(*this, verbly::part::index, -1).all(); |
| 34 | } | 33 | } |
| diff --git a/lib/frame.h b/lib/frame.h index 5fa6c6b..3de1931 100644 --- a/lib/frame.h +++ b/lib/frame.h | |||
| @@ -3,12 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | #include <stdexcept> | 4 | #include <stdexcept> |
| 5 | #include <list> | 5 | #include <list> |
| 6 | #include <hkutil/database.h> | ||
| 6 | #include "field.h" | 7 | #include "field.h" |
| 7 | #include "filter.h" | 8 | #include "filter.h" |
| 8 | #include "part.h" | 9 | #include "part.h" |
| 9 | 10 | ||
| 10 | struct sqlite3_stmt; | ||
| 11 | |||
| 12 | namespace verbly { | 11 | namespace verbly { |
| 13 | 12 | ||
| 14 | class database; | 13 | class database; |
| @@ -22,7 +21,7 @@ namespace verbly { | |||
| 22 | 21 | ||
| 23 | // Construct from database | 22 | // Construct from database |
| 24 | 23 | ||
| 25 | frame(const database& db, sqlite3_stmt* row); | 24 | frame(const database& db, hatkirby::row row); |
| 26 | 25 | ||
| 27 | // Accessors | 26 | // Accessors |
| 28 | 27 | ||
| @@ -101,15 +100,12 @@ namespace verbly { | |||
| 101 | static field parts(int index); | 100 | static field parts(int index); |
| 102 | 101 | ||
| 103 | private: | 102 | private: |
| 104 | bool valid_ = false; | ||
| 105 | 103 | ||
| 104 | bool valid_ = false; | ||
| 106 | int id_; | 105 | int id_; |
| 107 | int groupId_; | 106 | int groupId_; |
| 108 | int length_; | 107 | int length_; |
| 109 | std::vector<part> parts_; | 108 | std::vector<part> parts_; |
| 110 | |||
| 111 | const database* db_; | ||
| 112 | |||
| 113 | }; | 109 | }; |
| 114 | 110 | ||
| 115 | }; | 111 | }; |
| diff --git a/lib/notion.cpp b/lib/notion.cpp index c227b46..733c852 100644 --- a/lib/notion.cpp +++ b/lib/notion.cpp | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include "notion.h" | 1 | #include "notion.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include <sstream> | 2 | #include <sstream> |
| 3 | #include <hkutil/database.h> | ||
| 4 | 4 | ||
| 5 | namespace verbly { | 5 | namespace verbly { |
| 6 | 6 | ||
| @@ -58,21 +58,21 @@ namespace verbly { | |||
| 58 | const field notion::preposition_group_field::isA = field::joinField(object::notion, "notion_id", "is_a"); | 58 | const field notion::preposition_group_field::isA = field::joinField(object::notion, "notion_id", "is_a"); |
| 59 | const field notion::preposition_group_field::groupNameField = field::stringField("is_a", "groupname"); | 59 | const field notion::preposition_group_field::groupNameField = field::stringField("is_a", "groupname"); |
| 60 | 60 | ||
| 61 | notion::notion(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 61 | notion::notion(const database& db, hatkirby::row row) : valid_(true) |
| 62 | { | 62 | { |
| 63 | id_ = sqlite3_column_int(row, 0); | 63 | id_ = mpark::get<int>(row[0]); |
| 64 | partOfSpeech_ = static_cast<part_of_speech>(sqlite3_column_int(row, 1)); | 64 | partOfSpeech_ = static_cast<part_of_speech>(mpark::get<int>(row[1])); |
| 65 | 65 | ||
| 66 | if (sqlite3_column_type(row, 2) != SQLITE_NULL) | 66 | if (!mpark::holds_alternative<std::nullptr_t>(row[2])) |
| 67 | { | 67 | { |
| 68 | hasWnid_ = true; | 68 | hasWnid_ = true; |
| 69 | wnid_ = sqlite3_column_int(row, 2); | 69 | wnid_ = mpark::get<int>(row[2]); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | if (sqlite3_column_type(row, 3) != SQLITE_NULL) | 72 | if (!mpark::holds_alternative<std::nullptr_t>(row[3])) |
| 73 | { | 73 | { |
| 74 | hasNumOfImages_ = true; | 74 | hasNumOfImages_ = true; |
| 75 | numOfImages_ = sqlite3_column_int(row, 3); | 75 | numOfImages_ = mpark::get<int>(row[3]); |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | 78 | ||
| diff --git a/lib/notion.h b/lib/notion.h index 5388e17..63afd2f 100644 --- a/lib/notion.h +++ b/lib/notion.h | |||
| @@ -3,120 +3,119 @@ | |||
| 3 | 3 | ||
| 4 | #include <stdexcept> | 4 | #include <stdexcept> |
| 5 | #include <string> | 5 | #include <string> |
| 6 | #include <hkutil/database.h> | ||
| 6 | #include "field.h" | 7 | #include "field.h" |
| 7 | #include "filter.h" | 8 | #include "filter.h" |
| 8 | 9 | ||
| 9 | struct sqlite3_stmt; | ||
| 10 | |||
| 11 | namespace verbly { | 10 | namespace verbly { |
| 12 | 11 | ||
| 13 | class database; | 12 | class database; |
| 14 | 13 | ||
| 15 | class notion { | 14 | class notion { |
| 16 | public: | 15 | public: |
| 17 | 16 | ||
| 18 | // Default constructor | 17 | // Default constructor |
| 19 | 18 | ||
| 20 | notion() = default; | 19 | notion() = default; |
| 21 | 20 | ||
| 22 | // Construct from database | 21 | // Construct from database |
| 23 | 22 | ||
| 24 | notion(const database& db, sqlite3_stmt* row); | 23 | notion(const database& db, hatkirby::row row); |
| 25 | 24 | ||
| 26 | // Accessors | 25 | // Accessors |
| 27 | 26 | ||
| 28 | bool isValid() const | 27 | bool isValid() const |
| 29 | { | 28 | { |
| 30 | return valid_; | 29 | return valid_; |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | int getId() const | 32 | int getId() const |
| 34 | { | 33 | { |
| 35 | if (!valid_) | 34 | if (!valid_) |
| 36 | { | 35 | { |
| 37 | throw std::domain_error("Bad access to uninitialized notion"); | 36 | throw std::domain_error("Bad access to uninitialized notion"); |
| 38 | } | 37 | } |
| 39 | 38 | ||
| 40 | return id_; | 39 | return id_; |
| 41 | } | 40 | } |
| 42 | 41 | ||
| 43 | part_of_speech getPartOfSpeech() const | 42 | part_of_speech getPartOfSpeech() const |
| 44 | { | 43 | { |
| 45 | if (!valid_) | 44 | if (!valid_) |
| 46 | { | 45 | { |
| 47 | throw std::domain_error("Bad access to uninitialized notion"); | 46 | throw std::domain_error("Bad access to uninitialized notion"); |
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | return partOfSpeech_; | 49 | return partOfSpeech_; |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | bool hasWnid() const | 52 | bool hasWnid() const |
| 54 | { | 53 | { |
| 55 | if (!valid_) | 54 | if (!valid_) |
| 56 | { | 55 | { |
| 57 | throw std::domain_error("Bad access to uninitialized notion"); | 56 | throw std::domain_error("Bad access to uninitialized notion"); |
| 58 | } | 57 | } |
| 59 | 58 | ||
| 60 | return hasWnid_; | 59 | return hasWnid_; |
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | int getWnid() const | 62 | int getWnid() const |
| 64 | { | 63 | { |
| 65 | if (!valid_) | 64 | if (!valid_) |
| 66 | { | 65 | { |
| 67 | throw std::domain_error("Bad access to uninitialized notion"); | 66 | throw std::domain_error("Bad access to uninitialized notion"); |
| 68 | } | 67 | } |
| 69 | 68 | ||
| 70 | if (!hasWnid_) | 69 | if (!hasWnid_) |
| 71 | { | 70 | { |
| 72 | throw std::domain_error("Notion has no wnid"); | 71 | throw std::domain_error("Notion has no wnid"); |
| 73 | } | 72 | } |
| 74 | 73 | ||
| 75 | return wnid_; | 74 | return wnid_; |
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | bool hasNumOfImages() const | 77 | bool hasNumOfImages() const |
| 79 | { | 78 | { |
| 80 | if (!valid_) | 79 | if (!valid_) |
| 81 | { | 80 | { |
| 82 | throw std::domain_error("Bad access to uninitialized notion"); | 81 | throw std::domain_error("Bad access to uninitialized notion"); |
| 83 | } | 82 | } |
| 84 | 83 | ||
| 85 | return hasNumOfImages_; | 84 | return hasNumOfImages_; |
| 86 | } | 85 | } |
| 87 | 86 | ||
| 88 | int getNumOfImages() const | 87 | int getNumOfImages() const |
| 89 | { | 88 | { |
| 90 | if (!valid_) | 89 | if (!valid_) |
| 91 | { | 90 | { |
| 92 | throw std::domain_error("Bad access to uninitialized notion"); | 91 | throw std::domain_error("Bad access to uninitialized notion"); |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | if (!hasNumOfImages_) | 94 | if (!hasNumOfImages_) |
| 96 | { | 95 | { |
| 97 | throw std::domain_error("Notion does not have a number of images"); | 96 | throw std::domain_error("Notion does not have a number of images"); |
| 98 | } | 97 | } |
| 99 | 98 | ||
| 100 | return numOfImages_; | 99 | return numOfImages_; |
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | // Convenience | 102 | // Convenience |
| 104 | 103 | ||
| 105 | std::string getImageNetUrl() const; | 104 | std::string getImageNetUrl() const; |
| 106 | 105 | ||
| 107 | // Type info | 106 | // Type info |
| 108 | 107 | ||
| 109 | static const object objectType; | 108 | static const object objectType; |
| 110 | 109 | ||
| 111 | static const std::list<std::string> select; | 110 | static const std::list<std::string> select; |
| 112 | 111 | ||
| 113 | // Query fields | 112 | // Query fields |
| 114 | 113 | ||
| 115 | static const field id; | 114 | static const field id; |
| 116 | static const field partOfSpeech; | 115 | static const field partOfSpeech; |
| 117 | static const field wnid; | 116 | static const field wnid; |
| 118 | static const field numOfImages; | 117 | static const field numOfImages; |
| 119 | 118 | ||
| 120 | operator filter() const | 119 | operator filter() const |
| 121 | { | 120 | { |
| 122 | if (!valid_) | 121 | if (!valid_) |
| @@ -126,7 +125,7 @@ namespace verbly { | |||
| 126 | 125 | ||
| 127 | return (id == id_); | 126 | return (id == id_); |
| 128 | } | 127 | } |
| 129 | 128 | ||
| 130 | filter operator!() const | 129 | filter operator!() const |
| 131 | { | 130 | { |
| 132 | if (!valid_) | 131 | if (!valid_) |
| @@ -138,78 +137,75 @@ namespace verbly { | |||
| 138 | } | 137 | } |
| 139 | 138 | ||
| 140 | // Relationships with other objects | 139 | // Relationships with other objects |
| 141 | 140 | ||
| 142 | static const field words; | 141 | static const field words; |
| 143 | 142 | ||
| 144 | // Relationships with self | 143 | // Relationships with self |
| 145 | 144 | ||
| 146 | static const field hypernyms; | 145 | static const field hypernyms; |
| 147 | static const field hyponyms; | 146 | static const field hyponyms; |
| 148 | 147 | ||
| 149 | static const field fullHypernyms; | 148 | static const field fullHypernyms; |
| 150 | static const field fullHyponyms; | 149 | static const field fullHyponyms; |
| 151 | 150 | ||
| 152 | static const field instances; | 151 | static const field instances; |
| 153 | static const field classes; | 152 | static const field classes; |
| 154 | 153 | ||
| 155 | static const field memberMeronyms; | 154 | static const field memberMeronyms; |
| 156 | static const field memberHolonyms; | 155 | static const field memberHolonyms; |
| 157 | 156 | ||
| 158 | static const field fullMemberMeronyms; | 157 | static const field fullMemberMeronyms; |
| 159 | static const field fullMemberHolonyms; | 158 | static const field fullMemberHolonyms; |
| 160 | 159 | ||
| 161 | static const field partMeronyms; | 160 | static const field partMeronyms; |
| 162 | static const field partHolonyms; | 161 | static const field partHolonyms; |
| 163 | 162 | ||
| 164 | static const field fullPartMeronyms; | 163 | static const field fullPartMeronyms; |
| 165 | static const field fullPartHolonyms; | 164 | static const field fullPartHolonyms; |
| 166 | 165 | ||
| 167 | static const field substanceMeronyms; | 166 | static const field substanceMeronyms; |
| 168 | static const field substanceHolonyms; | 167 | static const field substanceHolonyms; |
| 169 | 168 | ||
| 170 | static const field fullSubstanceMeronyms; | 169 | static const field fullSubstanceMeronyms; |
| 171 | static const field fullSubstanceHolonyms; | 170 | static const field fullSubstanceHolonyms; |
| 172 | 171 | ||
| 173 | static const field variants; | 172 | static const field variants; |
| 174 | static const field attributes; | 173 | static const field attributes; |
| 175 | 174 | ||
| 176 | static const field similarAdjectives; | 175 | static const field similarAdjectives; |
| 177 | 176 | ||
| 178 | static const field entails; | 177 | static const field entails; |
| 179 | static const field entailedBy; | 178 | static const field entailedBy; |
| 180 | 179 | ||
| 181 | static const field causes; | 180 | static const field causes; |
| 182 | static const field effects; | 181 | static const field effects; |
| 183 | 182 | ||
| 184 | // Preposition group relationship | 183 | // Preposition group relationship |
| 185 | 184 | ||
| 186 | class preposition_group_field { | 185 | class preposition_group_field { |
| 187 | public: | 186 | public: |
| 188 | 187 | ||
| 189 | filter operator==(std::string groupName) const; | 188 | filter operator==(std::string groupName) const; |
| 190 | 189 | ||
| 191 | private: | 190 | private: |
| 192 | 191 | ||
| 193 | static const field isA; | 192 | static const field isA; |
| 194 | static const field groupNameField; | 193 | static const field groupNameField; |
| 195 | }; | 194 | }; |
| 196 | 195 | ||
| 197 | static const preposition_group_field prepositionGroups; | 196 | static const preposition_group_field prepositionGroups; |
| 198 | 197 | ||
| 199 | private: | 198 | private: |
| 199 | |||
| 200 | bool valid_ = false; | 200 | bool valid_ = false; |
| 201 | |||
| 202 | int id_; | 201 | int id_; |
| 203 | part_of_speech partOfSpeech_; | 202 | part_of_speech partOfSpeech_; |
| 204 | bool hasWnid_ = false; | 203 | bool hasWnid_ = false; |
| 205 | int wnid_; | 204 | int wnid_; |
| 206 | bool hasNumOfImages_ = false; | 205 | bool hasNumOfImages_ = false; |
| 207 | int numOfImages_; | 206 | int numOfImages_; |
| 208 | |||
| 209 | const database* db_; | ||
| 210 | |||
| 211 | }; | 207 | }; |
| 212 | 208 | ||
| 213 | }; | 209 | }; |
| 214 | 210 | ||
| 215 | #endif /* end of include guard: NOTION_H_FD1C7646 */ | 211 | #endif /* end of include guard: NOTION_H_FD1C7646 */ |
| diff --git a/lib/part.cpp b/lib/part.cpp index e7e467b..bd8501a 100644 --- a/lib/part.cpp +++ b/lib/part.cpp | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include "part.h" | 1 | #include "part.h" |
| 2 | #include <stdexcept> | 2 | #include <stdexcept> |
| 3 | #include <sqlite3.h> | ||
| 4 | #include <hkutil/string.h> | 3 | #include <hkutil/string.h> |
| 5 | #include "database.h" | 4 | #include "database.h" |
| 6 | 5 | ||
| @@ -26,15 +25,19 @@ namespace verbly { | |||
| 26 | const part::selrestr_field part::selrestrs = {}; | 25 | const part::selrestr_field part::selrestrs = {}; |
| 27 | const part::synrestr_field part::synrestrs = {}; | 26 | const part::synrestr_field part::synrestrs = {}; |
| 28 | 27 | ||
| 29 | part part::createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs) | 28 | part part::createNounPhrase( |
| 29 | std::string role, | ||
| 30 | std::set<std::string> selrestrs, | ||
| 31 | std::set<std::string> synrestrs) | ||
| 30 | { | 32 | { |
| 31 | part p(part_type::noun_phrase); | 33 | return part { |
| 32 | 34 | part_type::noun_phrase, | |
| 33 | new(&p.noun_phrase_.role) std::string(std::move(role)); | 35 | np_type { |
| 34 | new(&p.noun_phrase_.selrestrs) std::set<std::string>(std::move(selrestrs)); | 36 | std::move(role), |
| 35 | new(&p.noun_phrase_.synrestrs) std::set<std::string>(std::move(synrestrs)); | 37 | std::move(selrestrs), |
| 36 | 38 | std::move(synrestrs) | |
| 37 | return p; | 39 | } |
| 40 | }; | ||
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | part part::createVerb() | 43 | part part::createVerb() |
| @@ -44,12 +47,13 @@ namespace verbly { | |||
| 44 | 47 | ||
| 45 | part part::createPreposition(std::vector<std::string> choices, bool literal) | 48 | part part::createPreposition(std::vector<std::string> choices, bool literal) |
| 46 | { | 49 | { |
| 47 | part p(part_type::preposition); | 50 | return part { |
| 48 | 51 | part_type::preposition, | |
| 49 | new(&p.preposition_.choices) std::vector<std::string>(std::move(choices)); | 52 | prep_type { |
| 50 | p.preposition_.literal = literal; | 53 | std::move(choices), |
| 51 | 54 | literal | |
| 52 | return p; | 55 | } |
| 56 | }; | ||
| 53 | } | 57 | } |
| 54 | 58 | ||
| 55 | part part::createAdjective() | 59 | part part::createAdjective() |
| @@ -64,83 +68,53 @@ namespace verbly { | |||
| 64 | 68 | ||
| 65 | part part::createLiteral(std::string value) | 69 | part part::createLiteral(std::string value) |
| 66 | { | 70 | { |
| 67 | part p(part_type::literal); | 71 | return part { |
| 68 | 72 | part_type::literal, | |
| 69 | new(&p.literal_) std::string(std::move(value)); | 73 | std::move(value) |
| 70 | 74 | }; | |
| 71 | return p; | ||
| 72 | } | 75 | } |
| 73 | 76 | ||
| 74 | part::part(const database& db, sqlite3_stmt* row) | 77 | part::part(const database& db, hatkirby::row row) |
| 75 | { | 78 | { |
| 76 | int id = sqlite3_column_int(row, 0); | 79 | int id = mpark::get<int>(row[0]); |
| 77 | 80 | ||
| 78 | type_ = static_cast<part_type>(sqlite3_column_int(row, 3)); | 81 | type_ = static_cast<part_type>(mpark::get<int>(row[3])); |
| 79 | 82 | ||
| 80 | switch (type_) | 83 | switch (type_) |
| 81 | { | 84 | { |
| 82 | case part_type::noun_phrase: | 85 | case part_type::noun_phrase: |
| 83 | { | 86 | { |
| 84 | new(&noun_phrase_.role) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 4))); | 87 | variant_ = np_type { |
| 85 | new(&noun_phrase_.selrestrs) std::set<std::string>(db.selrestrs(id)); | 88 | mpark::get<std::string>(row[4]), |
| 86 | new(&noun_phrase_.synrestrs) std::set<std::string>(db.synrestrs(id)); | 89 | db.selrestrs(id), |
| 90 | db.synrestrs(id) | ||
| 91 | }; | ||
| 87 | 92 | ||
| 88 | break; | 93 | break; |
| 89 | } | 94 | } |
| 90 | 95 | ||
| 91 | case part_type::preposition: | 96 | case part_type::preposition: |
| 92 | { | 97 | { |
| 93 | std::string serializedChoices(reinterpret_cast<const char*>(sqlite3_column_blob(row, 5))); | 98 | hatkirby::blob_type raw = |
| 94 | new(&preposition_.choices) std::vector<std::string>(hatkirby::split<std::vector<std::string>>(serializedChoices, ",")); | 99 | mpark::get<hatkirby::blob_type>(row[5]); |
| 95 | |||
| 96 | preposition_.literal = (sqlite3_column_int(row, 6) == 1); | ||
| 97 | |||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | case part_type::literal: | ||
| 102 | { | ||
| 103 | new(&literal_) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 7))); | ||
| 104 | 100 | ||
| 105 | break; | 101 | std::string serializedChoices( |
| 106 | } | 102 | std::begin(raw), |
| 103 | std::end(raw)); | ||
| 107 | 104 | ||
| 108 | case part_type::verb: | 105 | variant_ = prep_type { |
| 109 | case part_type::adjective: | 106 | hatkirby::split<std::vector<std::string>>( |
| 110 | case part_type::adverb: | 107 | std::move(serializedChoices), |
| 111 | case part_type::invalid: | 108 | ","), |
| 112 | { | 109 | (mpark::get<int>(row[6]) == 1) |
| 113 | break; | 110 | }; |
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | part::part(const part& other) | ||
| 119 | { | ||
| 120 | type_ = other.type_; | ||
| 121 | |||
| 122 | switch (type_) | ||
| 123 | { | ||
| 124 | case part_type::noun_phrase: | ||
| 125 | { | ||
| 126 | new(&noun_phrase_.role) std::string(other.noun_phrase_.role); | ||
| 127 | new(&noun_phrase_.selrestrs) std::set<std::string>(other.noun_phrase_.selrestrs); | ||
| 128 | new(&noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs); | ||
| 129 | |||
| 130 | break; | ||
| 131 | } | ||
| 132 | |||
| 133 | case part_type::preposition: | ||
| 134 | { | ||
| 135 | new(&preposition_.choices) std::vector<std::string>(other.preposition_.choices); | ||
| 136 | preposition_.literal = other.preposition_.literal; | ||
| 137 | 111 | ||
| 138 | break; | 112 | break; |
| 139 | } | 113 | } |
| 140 | 114 | ||
| 141 | case part_type::literal: | 115 | case part_type::literal: |
| 142 | { | 116 | { |
| 143 | new(&literal_) std::string(other.literal_); | 117 | variant_ = mpark::get<std::string>(row[7]); |
| 144 | 118 | ||
| 145 | break; | 119 | break; |
| 146 | } | 120 | } |
| @@ -155,256 +129,74 @@ namespace verbly { | |||
| 155 | } | 129 | } |
| 156 | } | 130 | } |
| 157 | 131 | ||
| 158 | part::part(part&& other) : part() | 132 | const std::string& part::getNounRole() const |
| 159 | { | 133 | { |
| 160 | swap(*this, other); | 134 | if (type_ != part_type::noun_phrase) |
| 161 | } | ||
| 162 | |||
| 163 | part& part::operator=(part other) | ||
| 164 | { | ||
| 165 | swap(*this, other); | ||
| 166 | |||
| 167 | return *this; | ||
| 168 | } | ||
| 169 | |||
| 170 | void swap(part& first, part& second) | ||
| 171 | { | ||
| 172 | using type = part_type; | ||
| 173 | |||
| 174 | type tempType = first.type_; | ||
| 175 | std::string tempRole; | ||
| 176 | std::set<std::string> tempSelrestrs; | ||
| 177 | std::set<std::string> tempSynrestrs; | ||
| 178 | std::vector<std::string> tempChoices; | ||
| 179 | bool tempPrepLiteral; | ||
| 180 | std::string tempLiteralValue; | ||
| 181 | |||
| 182 | switch (tempType) | ||
| 183 | { | ||
| 184 | case type::noun_phrase: | ||
| 185 | { | ||
| 186 | tempRole = std::move(first.noun_phrase_.role); | ||
| 187 | tempSelrestrs = std::move(first.noun_phrase_.selrestrs); | ||
| 188 | tempSynrestrs = std::move(first.noun_phrase_.synrestrs); | ||
| 189 | |||
| 190 | break; | ||
| 191 | } | ||
| 192 | |||
| 193 | case type::preposition: | ||
| 194 | { | ||
| 195 | tempChoices = std::move(first.preposition_.choices); | ||
| 196 | tempPrepLiteral = first.preposition_.literal; | ||
| 197 | |||
| 198 | break; | ||
| 199 | } | ||
| 200 | |||
| 201 | case type::literal: | ||
| 202 | { | ||
| 203 | tempLiteralValue = std::move(first.literal_); | ||
| 204 | |||
| 205 | break; | ||
| 206 | } | ||
| 207 | |||
| 208 | case type::verb: | ||
| 209 | case type::adjective: | ||
| 210 | case type::adverb: | ||
| 211 | case type::invalid: | ||
| 212 | { | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | first.~part(); | ||
| 218 | |||
| 219 | first.type_ = second.type_; | ||
| 220 | |||
| 221 | switch (first.type_) | ||
| 222 | { | 135 | { |
| 223 | case type::noun_phrase: | 136 | throw std::domain_error("part is not a noun phrase"); |
| 224 | { | ||
| 225 | new(&first.noun_phrase_.role) std::string(std::move(second.noun_phrase_.role)); | ||
| 226 | new(&first.noun_phrase_.selrestrs) std::set<std::string>(std::move(second.noun_phrase_.selrestrs)); | ||
| 227 | new(&first.noun_phrase_.synrestrs) std::set<std::string>(std::move(second.noun_phrase_.synrestrs)); | ||
| 228 | |||
| 229 | break; | ||
| 230 | } | ||
| 231 | |||
| 232 | case type::preposition: | ||
| 233 | { | ||
| 234 | new(&first.preposition_.choices) std::vector<std::string>(std::move(second.preposition_.choices)); | ||
| 235 | first.preposition_.literal = second.preposition_.literal; | ||
| 236 | |||
| 237 | break; | ||
| 238 | } | ||
| 239 | |||
| 240 | case type::literal: | ||
| 241 | { | ||
| 242 | new(&first.literal_) std::string(std::move(second.literal_)); | ||
| 243 | |||
| 244 | break; | ||
| 245 | } | ||
| 246 | |||
| 247 | case type::verb: | ||
| 248 | case type::adjective: | ||
| 249 | case type::adverb: | ||
| 250 | case type::invalid: | ||
| 251 | { | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | } | 137 | } |
| 255 | 138 | ||
| 256 | second.~part(); | 139 | return mpark::get<np_type>(variant_).role; |
| 257 | |||
| 258 | second.type_ = tempType; | ||
| 259 | |||
| 260 | switch (second.type_) | ||
| 261 | { | ||
| 262 | case type::noun_phrase: | ||
| 263 | { | ||
| 264 | new(&second.noun_phrase_.role) std::string(std::move(tempRole)); | ||
| 265 | new(&second.noun_phrase_.selrestrs) std::set<std::string>(std::move(tempSelrestrs)); | ||
| 266 | new(&second.noun_phrase_.synrestrs) std::set<std::string>(std::move(tempSynrestrs)); | ||
| 267 | |||
| 268 | break; | ||
| 269 | } | ||
| 270 | |||
| 271 | case type::preposition: | ||
| 272 | { | ||
| 273 | new(&second.preposition_.choices) std::vector<std::string>(std::move(tempChoices)); | ||
| 274 | second.preposition_.literal = tempPrepLiteral; | ||
| 275 | |||
| 276 | break; | ||
| 277 | } | ||
| 278 | |||
| 279 | case type::literal: | ||
| 280 | { | ||
| 281 | new(&second.literal_) std::string(std::move(tempLiteralValue)); | ||
| 282 | |||
| 283 | break; | ||
| 284 | } | ||
| 285 | |||
| 286 | case type::verb: | ||
| 287 | case type::adjective: | ||
| 288 | case type::adverb: | ||
| 289 | case type::invalid: | ||
| 290 | { | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } | 140 | } |
| 295 | 141 | ||
| 296 | part::~part() | 142 | const std::set<std::string>& part::getNounSelrestrs() const |
| 297 | { | 143 | { |
| 298 | switch (type_) | 144 | if (type_ != part_type::noun_phrase) |
| 299 | { | 145 | { |
| 300 | case part_type::noun_phrase: | 146 | throw std::domain_error("part is not a noun phrase"); |
| 301 | { | ||
| 302 | using string_type = std::string; | ||
| 303 | using set_type = std::set<std::string>; | ||
| 304 | |||
| 305 | noun_phrase_.role.~string_type(); | ||
| 306 | noun_phrase_.selrestrs.~set_type(); | ||
| 307 | noun_phrase_.synrestrs.~set_type(); | ||
| 308 | |||
| 309 | break; | ||
| 310 | } | ||
| 311 | |||
| 312 | case part_type::preposition: | ||
| 313 | { | ||
| 314 | using vector_type = std::vector<std::string>; | ||
| 315 | |||
| 316 | preposition_.choices.~vector_type(); | ||
| 317 | |||
| 318 | break; | ||
| 319 | } | ||
| 320 | |||
| 321 | case part_type::literal: | ||
| 322 | { | ||
| 323 | using string_type = std::string; | ||
| 324 | |||
| 325 | literal_.~string_type(); | ||
| 326 | |||
| 327 | break; | ||
| 328 | } | ||
| 329 | |||
| 330 | case part_type::verb: | ||
| 331 | case part_type::adjective: | ||
| 332 | case part_type::adverb: | ||
| 333 | case part_type::invalid: | ||
| 334 | { | ||
| 335 | break; | ||
| 336 | } | ||
| 337 | } | 147 | } |
| 338 | } | ||
| 339 | 148 | ||
| 340 | std::string part::getNounRole() const | 149 | return mpark::get<np_type>(variant_).selrestrs; |
| 341 | { | ||
| 342 | if (type_ == part_type::noun_phrase) | ||
| 343 | { | ||
| 344 | return noun_phrase_.role; | ||
| 345 | } else { | ||
| 346 | throw std::domain_error("part::getNounRole is only valid for noun phrase parts"); | ||
| 347 | } | ||
| 348 | } | 150 | } |
| 349 | 151 | ||
| 350 | std::set<std::string> part::getNounSelrestrs() const | 152 | const std::set<std::string>& part::getNounSynrestrs() const |
| 351 | { | 153 | { |
| 352 | if (type_ == part_type::noun_phrase) | 154 | if (type_ != part_type::noun_phrase) |
| 353 | { | 155 | { |
| 354 | return noun_phrase_.selrestrs; | 156 | throw std::domain_error("part is not a noun phrase"); |
| 355 | } else { | ||
| 356 | throw std::domain_error("part::getNounSelrestrs is only valid for noun phrase parts"); | ||
| 357 | } | 157 | } |
| 358 | } | ||
| 359 | 158 | ||
| 360 | std::set<std::string> part::getNounSynrestrs() const | 159 | return mpark::get<np_type>(variant_).synrestrs; |
| 361 | { | ||
| 362 | if (type_ == part_type::noun_phrase) | ||
| 363 | { | ||
| 364 | return noun_phrase_.synrestrs; | ||
| 365 | } else { | ||
| 366 | throw std::domain_error("part::getNounSynrestrs is only valid for noun phrase parts"); | ||
| 367 | } | ||
| 368 | } | 160 | } |
| 369 | 161 | ||
| 370 | bool part::nounHasSynrestr(std::string synrestr) const | 162 | bool part::nounHasSynrestr(std::string synrestr) const |
| 371 | { | 163 | { |
| 372 | if (type_ != part_type::noun_phrase) | 164 | if (type_ != part_type::noun_phrase) |
| 373 | { | 165 | { |
| 374 | throw std::domain_error("part::nounHasSynrestr is only valid for noun phrase parts"); | 166 | throw std::domain_error("part is not a noun phrase"); |
| 375 | } | 167 | } |
| 376 | 168 | ||
| 377 | return (noun_phrase_.synrestrs.count(synrestr) == 1); | 169 | return mpark::get<np_type>(variant_).synrestrs.count(synrestr); |
| 378 | } | 170 | } |
| 379 | 171 | ||
| 380 | std::vector<std::string> part::getPrepositionChoices() const | 172 | const std::vector<std::string>& part::getPrepositionChoices() const |
| 381 | { | 173 | { |
| 382 | if (type_ == part_type::preposition) | 174 | if (type_ != part_type::preposition) |
| 383 | { | 175 | { |
| 384 | return preposition_.choices; | 176 | throw std::domain_error("part is not a preposition"); |
| 385 | } else { | ||
| 386 | throw std::domain_error("part::getPrepositionChoices is only valid for preposition parts"); | ||
| 387 | } | 177 | } |
| 178 | |||
| 179 | return mpark::get<prep_type>(variant_).choices; | ||
| 388 | } | 180 | } |
| 389 | 181 | ||
| 390 | bool part::isPrepositionLiteral() const | 182 | bool part::isPrepositionLiteral() const |
| 391 | { | 183 | { |
| 392 | if (type_ == part_type::preposition) | 184 | if (type_ != part_type::preposition) |
| 393 | { | 185 | { |
| 394 | return preposition_.literal; | 186 | throw std::domain_error("part is not a preposition"); |
| 395 | } else { | ||
| 396 | throw std::domain_error("part::isPrepositionLiteral is only valid for preposition parts"); | ||
| 397 | } | 187 | } |
| 188 | |||
| 189 | return mpark::get<prep_type>(variant_).literal; | ||
| 398 | } | 190 | } |
| 399 | 191 | ||
| 400 | std::string part::getLiteralValue() const | 192 | const std::string& part::getLiteralValue() const |
| 401 | { | 193 | { |
| 402 | if (type_ == part_type::literal) | 194 | if (type_ != part_type::literal) |
| 403 | { | 195 | { |
| 404 | return literal_; | 196 | throw std::domain_error("part is not a literal"); |
| 405 | } else { | ||
| 406 | throw std::domain_error("part::getLiteralValue is only valid for literal parts"); | ||
| 407 | } | 197 | } |
| 198 | |||
| 199 | return mpark::get<std::string>(variant_); | ||
| 408 | } | 200 | } |
| 409 | 201 | ||
| 410 | filter part::synrestr_field::operator%=(std::string synrestr) const | 202 | filter part::synrestr_field::operator%=(std::string synrestr) const |
| diff --git a/lib/part.h b/lib/part.h index 456bad0..7783a61 100644 --- a/lib/part.h +++ b/lib/part.h | |||
| @@ -5,12 +5,12 @@ | |||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | #include <set> | 6 | #include <set> |
| 7 | #include <list> | 7 | #include <list> |
| 8 | #include <hkutil/database.h> | ||
| 9 | #include <variant.hpp> | ||
| 8 | #include "field.h" | 10 | #include "field.h" |
| 9 | #include "filter.h" | 11 | #include "filter.h" |
| 10 | #include "enums.h" | 12 | #include "enums.h" |
| 11 | 13 | ||
| 12 | struct sqlite3_stmt; | ||
| 13 | |||
| 14 | namespace verbly { | 14 | namespace verbly { |
| 15 | 15 | ||
| 16 | class database; | 16 | class database; |
| @@ -20,11 +20,16 @@ namespace verbly { | |||
| 20 | 20 | ||
| 21 | // Static factories | 21 | // Static factories |
| 22 | 22 | ||
| 23 | static part createNounPhrase(std::string role, std::set<std::string> selrestrs, std::set<std::string> synrestrs); | 23 | static part createNounPhrase( |
| 24 | std::string role, | ||
| 25 | std::set<std::string> selrestrs, | ||
| 26 | std::set<std::string> synrestrs); | ||
| 24 | 27 | ||
| 25 | static part createVerb(); | 28 | static part createVerb(); |
| 26 | 29 | ||
| 27 | static part createPreposition(std::vector<std::string> choices, bool literal); | 30 | static part createPreposition( |
| 31 | std::vector<std::string> choices, | ||
| 32 | bool literal); | ||
| 28 | 33 | ||
| 29 | static part createAdjective(); | 34 | static part createAdjective(); |
| 30 | 35 | ||
| @@ -32,41 +37,12 @@ namespace verbly { | |||
| 32 | 37 | ||
| 33 | static part createLiteral(std::string value); | 38 | static part createLiteral(std::string value); |
| 34 | 39 | ||
| 35 | // Default constructor | ||
| 36 | |||
| 37 | part() | ||
| 38 | { | ||
| 39 | } | ||
| 40 | |||
| 41 | // Construct from database | 40 | // Construct from database |
| 42 | 41 | ||
| 43 | part(const database& db, sqlite3_stmt* row); | 42 | part(const database& db, hatkirby::row row); |
| 44 | |||
| 45 | // Copy and move constructors | ||
| 46 | |||
| 47 | part(const part& other); | ||
| 48 | |||
| 49 | part(part&& other); | ||
| 50 | |||
| 51 | // Assignment | ||
| 52 | |||
| 53 | part& operator=(part other); | ||
| 54 | |||
| 55 | // Swap | ||
| 56 | |||
| 57 | friend void swap(part& first, part& second); | ||
| 58 | |||
| 59 | // Destructor | ||
| 60 | |||
| 61 | ~part(); | ||
| 62 | 43 | ||
| 63 | // General accessors | 44 | // General accessors |
| 64 | 45 | ||
| 65 | bool isValid() const | ||
| 66 | { | ||
| 67 | return (type_ != part_type::invalid); | ||
| 68 | } | ||
| 69 | |||
| 70 | part_type getType() const | 46 | part_type getType() const |
| 71 | { | 47 | { |
| 72 | return type_; | 48 | return type_; |
| @@ -74,23 +50,23 @@ namespace verbly { | |||
| 74 | 50 | ||
| 75 | // Noun phrase accessors | 51 | // Noun phrase accessors |
| 76 | 52 | ||
| 77 | std::string getNounRole() const; | 53 | const std::string& getNounRole() const; |
| 78 | 54 | ||
| 79 | std::set<std::string> getNounSelrestrs() const; | 55 | const std::set<std::string>& getNounSelrestrs() const; |
| 80 | 56 | ||
| 81 | std::set<std::string> getNounSynrestrs() const; | 57 | const std::set<std::string>& getNounSynrestrs() const; |
| 82 | 58 | ||
| 83 | bool nounHasSynrestr(std::string synrestr) const; | 59 | bool nounHasSynrestr(std::string synrestr) const; |
| 84 | 60 | ||
| 85 | // Preposition accessors | 61 | // Preposition accessors |
| 86 | 62 | ||
| 87 | std::vector<std::string> getPrepositionChoices() const; | 63 | const std::vector<std::string>& getPrepositionChoices() const; |
| 88 | 64 | ||
| 89 | bool isPrepositionLiteral() const; | 65 | bool isPrepositionLiteral() const; |
| 90 | 66 | ||
| 91 | // Literal accessors | 67 | // Literal accessors |
| 92 | 68 | ||
| 93 | std::string getLiteralValue() const; | 69 | const std::string& getLiteralValue() const; |
| 94 | 70 | ||
| 95 | // Type info | 71 | // Type info |
| 96 | 72 | ||
| @@ -123,7 +99,7 @@ namespace verbly { | |||
| 123 | }; | 99 | }; |
| 124 | 100 | ||
| 125 | static const selrestr_field selrestrs; | 101 | static const selrestr_field selrestrs; |
| 126 | 102 | ||
| 127 | class synrestr_field { | 103 | class synrestr_field { |
| 128 | public: | 104 | public: |
| 129 | 105 | ||
| @@ -139,29 +115,36 @@ namespace verbly { | |||
| 139 | 115 | ||
| 140 | private: | 116 | private: |
| 141 | 117 | ||
| 142 | // Private constructors | ||
| 143 | |||
| 144 | part(part_type t) : type_(t) | ||
| 145 | { | ||
| 146 | } | ||
| 147 | |||
| 148 | // Data | 118 | // Data |
| 149 | 119 | ||
| 150 | union { | 120 | struct np_type { |
| 151 | struct { | 121 | std::string role; |
| 152 | std::string role; | 122 | std::set<std::string> selrestrs; |
| 153 | std::set<std::string> selrestrs; | 123 | std::set<std::string> synrestrs; |
| 154 | std::set<std::string> synrestrs; | 124 | }; |
| 155 | } noun_phrase_; | 125 | |
| 156 | struct { | 126 | struct prep_type { |
| 157 | std::vector<std::string> choices; | 127 | std::vector<std::string> choices; |
| 158 | bool literal; | 128 | bool literal; |
| 159 | } preposition_; | ||
| 160 | std::string literal_; | ||
| 161 | }; | 129 | }; |
| 162 | 130 | ||
| 131 | using variant_type = | ||
| 132 | mpark::variant< | ||
| 133 | mpark::monostate, | ||
| 134 | np_type, | ||
| 135 | prep_type, | ||
| 136 | std::string>; | ||
| 137 | |||
| 138 | variant_type variant_; | ||
| 139 | |||
| 163 | part_type type_ = part_type::invalid; | 140 | part_type type_ = part_type::invalid; |
| 164 | 141 | ||
| 142 | // Private constructors | ||
| 143 | |||
| 144 | part(part_type t, variant_type v = {}) : type_(t), variant_(v) | ||
| 145 | { | ||
| 146 | } | ||
| 147 | |||
| 165 | }; | 148 | }; |
| 166 | 149 | ||
| 167 | }; | 150 | }; |
| diff --git a/lib/pronunciation.cpp b/lib/pronunciation.cpp index 1f36899..3aef815 100644 --- a/lib/pronunciation.cpp +++ b/lib/pronunciation.cpp | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | #include "pronunciation.h" | 1 | #include "pronunciation.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include <hkutil/string.h> | 2 | #include <hkutil/string.h> |
| 4 | #include "form.h" | 3 | #include "form.h" |
| 5 | #include "word.h" | 4 | #include "word.h" |
| @@ -22,22 +21,27 @@ namespace verbly { | |||
| 22 | const field pronunciation::rhymes_field::rhymeJoin = field::joinField(object::pronunciation, "rhyme", object::pronunciation); | 21 | const field pronunciation::rhymes_field::rhymeJoin = field::joinField(object::pronunciation, "rhyme", object::pronunciation); |
| 23 | const pronunciation::rhymes_field pronunciation::rhymes = {}; | 22 | const pronunciation::rhymes_field pronunciation::rhymes = {}; |
| 24 | 23 | ||
| 25 | pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 24 | pronunciation::pronunciation( |
| 25 | const database& db, | ||
| 26 | hatkirby::row row) : | ||
| 27 | valid_(true) | ||
| 26 | { | 28 | { |
| 27 | id_ = sqlite3_column_int(row, 0); | 29 | id_ = mpark::get<int>(row[0]); |
| 28 | 30 | ||
| 29 | std::string phonemesStr(reinterpret_cast<const char*>(sqlite3_column_text(row, 1))); | 31 | phonemes_ = |
| 30 | phonemes_ = hatkirby::split<std::vector<std::string>>(phonemesStr, " "); | 32 | hatkirby::split<std::vector<std::string>>( |
| 33 | mpark::get<std::string>(row[1]), | ||
| 34 | " "); | ||
| 31 | 35 | ||
| 32 | syllables_ = sqlite3_column_int(row, 2); | 36 | syllables_ = mpark::get<int>(row[2]); |
| 33 | stress_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 3))); | 37 | stress_ = mpark::get<std::string>(row[3]); |
| 34 | 38 | ||
| 35 | if (sqlite3_column_type(row, 5) != SQLITE_NULL) | 39 | if (!mpark::holds_alternative<std::nullptr_t>(row[5])) |
| 36 | { | 40 | { |
| 37 | hasRhyme_ = true; | 41 | hasRhyme_ = true; |
| 38 | 42 | ||
| 39 | prerhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 4))); | 43 | prerhyme_ = mpark::get<std::string>(row[4]); |
| 40 | rhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 5))); | 44 | rhyme_ = mpark::get<std::string>(row[5]); |
| 41 | } | 45 | } |
| 42 | } | 46 | } |
| 43 | 47 | ||
| diff --git a/lib/pronunciation.h b/lib/pronunciation.h index 73329e4..cd241bd 100644 --- a/lib/pronunciation.h +++ b/lib/pronunciation.h | |||
| @@ -4,11 +4,10 @@ | |||
| 4 | #include <stdexcept> | 4 | #include <stdexcept> |
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <hkutil/database.h> | ||
| 7 | #include "field.h" | 8 | #include "field.h" |
| 8 | #include "filter.h" | 9 | #include "filter.h" |
| 9 | 10 | ||
| 10 | struct sqlite3_stmt; | ||
| 11 | |||
| 12 | namespace verbly { | 11 | namespace verbly { |
| 13 | 12 | ||
| 14 | class form; | 13 | class form; |
| @@ -24,7 +23,7 @@ namespace verbly { | |||
| 24 | 23 | ||
| 25 | // Construct from database | 24 | // Construct from database |
| 26 | 25 | ||
| 27 | pronunciation(const database& db, sqlite3_stmt* row); | 26 | pronunciation(const database& db, hatkirby::row row); |
| 28 | 27 | ||
| 29 | // Accessors | 28 | // Accessors |
| 30 | 29 | ||
| @@ -63,7 +62,7 @@ namespace verbly { | |||
| 63 | return syllables_; | 62 | return syllables_; |
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | std::string getStress() const | 65 | const std::string& getStress() const |
| 67 | { | 66 | { |
| 68 | if (!valid_) | 67 | if (!valid_) |
| 69 | { | 68 | { |
| @@ -83,7 +82,7 @@ namespace verbly { | |||
| 83 | return hasRhyme_; | 82 | return hasRhyme_; |
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | std::string getPrerhyme() const | 85 | const std::string& getPrerhyme() const |
| 87 | { | 86 | { |
| 88 | if (!valid_) | 87 | if (!valid_) |
| 89 | { | 88 | { |
| @@ -98,7 +97,7 @@ namespace verbly { | |||
| 98 | return prerhyme_; | 97 | return prerhyme_; |
| 99 | } | 98 | } |
| 100 | 99 | ||
| 101 | std::string getRhyme() const | 100 | const std::string& getRhyme() const |
| 102 | { | 101 | { |
| 103 | if (!valid_) | 102 | if (!valid_) |
| 104 | { | 103 | { |
| @@ -167,8 +166,11 @@ namespace verbly { | |||
| 167 | static const rhymes_field rhymes; | 166 | static const rhymes_field rhymes; |
| 168 | 167 | ||
| 169 | private: | 168 | private: |
| 170 | bool valid_ = false; | ||
| 171 | 169 | ||
| 170 | static const field prerhyme; | ||
| 171 | static const field rhyme; | ||
| 172 | |||
| 173 | bool valid_ = false; | ||
| 172 | int id_; | 174 | int id_; |
| 173 | std::vector<std::string> phonemes_; | 175 | std::vector<std::string> phonemes_; |
| 174 | int syllables_; | 176 | int syllables_; |
| @@ -176,12 +178,6 @@ namespace verbly { | |||
| 176 | bool hasRhyme_ = false; | 178 | bool hasRhyme_ = false; |
| 177 | std::string prerhyme_; | 179 | std::string prerhyme_; |
| 178 | std::string rhyme_; | 180 | std::string rhyme_; |
| 179 | |||
| 180 | const database* db_; | ||
| 181 | |||
| 182 | static const field prerhyme; | ||
| 183 | static const field rhyme; | ||
| 184 | |||
| 185 | }; | 181 | }; |
| 186 | 182 | ||
| 187 | }; | 183 | }; |
| diff --git a/lib/query.h b/lib/query.h index 0f490ed..65b4e9d 100644 --- a/lib/query.h +++ b/lib/query.h | |||
| @@ -5,10 +5,8 @@ | |||
| 5 | #include <stdexcept> | 5 | #include <stdexcept> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <list> | 7 | #include <list> |
| 8 | #include <sqlite3.h> | 8 | #include <hkutil/database.h> |
| 9 | #include <iostream> | ||
| 10 | #include "statement.h" | 9 | #include "statement.h" |
| 11 | #include "binding.h" | ||
| 12 | #include "order.h" | 10 | #include "order.h" |
| 13 | 11 | ||
| 14 | namespace verbly { | 12 | namespace verbly { |
| @@ -16,7 +14,10 @@ namespace verbly { | |||
| 16 | class database_error : public std::logic_error { | 14 | class database_error : public std::logic_error { |
| 17 | public: | 15 | public: |
| 18 | 16 | ||
| 19 | database_error(std::string msg, std::string sqlMsg) : std::logic_error(msg + " (" + sqlMsg + ")") | 17 | database_error( |
| 18 | std::string msg, | ||
| 19 | std::string sqlMsg) : | ||
| 20 | std::logic_error(msg + " (" + sqlMsg + ")") | ||
| 20 | { | 21 | { |
| 21 | } | 22 | } |
| 22 | }; | 23 | }; |
| @@ -25,107 +26,57 @@ namespace verbly { | |||
| 25 | class query { | 26 | class query { |
| 26 | public: | 27 | public: |
| 27 | 28 | ||
| 28 | query(const database& db, sqlite3* ppdb, filter queryFilter, order sortOrder, int limit) : db_(&db) | 29 | query( |
| 30 | const database& db, | ||
| 31 | hatkirby::database& ppdb, | ||
| 32 | filter queryFilter, | ||
| 33 | order sortOrder, | ||
| 34 | int limit) : | ||
| 35 | db_(db), | ||
| 36 | ppdb_(ppdb) | ||
| 29 | { | 37 | { |
| 30 | if ((sortOrder.getType() == order::type::field) | 38 | if ((sortOrder.getType() == order::type::field) |
| 31 | && (sortOrder.getSortField().getObject() != Object::objectType)) | 39 | && (sortOrder.getSortField().getObject() != Object::objectType)) |
| 32 | { | 40 | { |
| 33 | throw std::invalid_argument("Can only sort query by a field in the result table"); | 41 | throw std::invalid_argument( |
| 42 | "Can only sort query by a field in the result table"); | ||
| 34 | } | 43 | } |
| 35 | 44 | ||
| 36 | statement stmt(Object::objectType, std::move(queryFilter)); | 45 | statement stmt(Object::objectType, std::move(queryFilter)); |
| 37 | 46 | ||
| 38 | std::string queryString = stmt.getQueryString(Object::select, std::move(sortOrder), limit); | 47 | queryString_ = |
| 39 | std::list<binding> bindings = stmt.getBindings(); | 48 | stmt.getQueryString(Object::select, std::move(sortOrder), limit); |
| 40 | 49 | ||
| 41 | if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) | 50 | bindings_ = stmt.getBindings(); |
| 42 | { | ||
| 43 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
| 44 | sqlite3_finalize(ppstmt_); | ||
| 45 | |||
| 46 | throw database_error("Error preparing query", errorMsg); | ||
| 47 | } | ||
| 48 | |||
| 49 | int i = 1; | ||
| 50 | for (const binding& value : bindings) | ||
| 51 | { | ||
| 52 | switch (value.getType()) | ||
| 53 | { | ||
| 54 | case binding::type::integer: | ||
| 55 | { | ||
| 56 | if (sqlite3_bind_int(ppstmt_, i, value.getInteger()) != SQLITE_OK) | ||
| 57 | { | ||
| 58 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
| 59 | sqlite3_finalize(ppstmt_); | ||
| 60 | |||
| 61 | throw database_error("Error binding value to query", errorMsg); | ||
| 62 | } | ||
| 63 | |||
| 64 | break; | ||
| 65 | } | ||
| 66 | |||
| 67 | case binding::type::string: | ||
| 68 | { | ||
| 69 | if (sqlite3_bind_text(ppstmt_, i, value.getString().c_str(), value.getString().length(), SQLITE_TRANSIENT) != SQLITE_OK) | ||
| 70 | { | ||
| 71 | std::string errorMsg = sqlite3_errmsg(ppdb); | ||
| 72 | sqlite3_finalize(ppstmt_); | ||
| 73 | |||
| 74 | throw database_error("Error binding value to query", errorMsg); | ||
| 75 | } | ||
| 76 | |||
| 77 | break; | ||
| 78 | } | ||
| 79 | |||
| 80 | case binding::type::invalid: | ||
| 81 | { | ||
| 82 | throw std::logic_error("Cannot use invalid bindings"); | ||
| 83 | } | ||
| 84 | |||
| 85 | case binding::type::field: | ||
| 86 | { | ||
| 87 | throw std::logic_error("Compare field binding made it past statement generation"); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | i++; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | ~query() | ||
| 96 | { | ||
| 97 | sqlite3_finalize(ppstmt_); | ||
| 98 | } | 51 | } |
| 99 | 52 | ||
| 100 | std::vector<Object> all() const | 53 | std::vector<Object> all() const |
| 101 | { | 54 | { |
| 55 | std::vector<hatkirby::row> rows = | ||
| 56 | ppdb_.queryAll(queryString_, bindings_); | ||
| 57 | |||
| 102 | std::vector<Object> result; | 58 | std::vector<Object> result; |
| 103 | 59 | ||
| 104 | while (sqlite3_step(ppstmt_) == SQLITE_ROW) | 60 | for (hatkirby::row& r : rows) |
| 105 | { | 61 | { |
| 106 | result.emplace_back(*db_, ppstmt_); | 62 | result.emplace_back(db_, std::move(r)); |
| 107 | } | 63 | } |
| 108 | 64 | ||
| 109 | sqlite3_reset(ppstmt_); | ||
| 110 | |||
| 111 | return result; | 65 | return result; |
| 112 | } | 66 | } |
| 113 | 67 | ||
| 114 | Object first() const | 68 | Object first() const |
| 115 | { | 69 | { |
| 116 | std::vector<Object> results = all(); | 70 | return { db_, ppdb_.queryFirst(queryString_, bindings_) }; |
| 117 | if (!results.empty()) | ||
| 118 | { | ||
| 119 | return results.front(); | ||
| 120 | } else { | ||
| 121 | throw std::logic_error("query returned empty dataset"); | ||
| 122 | } | ||
| 123 | } | 71 | } |
| 124 | 72 | ||
| 125 | private: | 73 | private: |
| 126 | const database* db_; | ||
| 127 | sqlite3_stmt* ppstmt_; | ||
| 128 | 74 | ||
| 75 | const database& db_; | ||
| 76 | hatkirby::database& ppdb_; | ||
| 77 | |||
| 78 | std::string queryString_; | ||
| 79 | std::list<hatkirby::binding> bindings_; | ||
| 129 | }; | 80 | }; |
| 130 | 81 | ||
| 131 | }; | 82 | }; |
| diff --git a/lib/statement.cpp b/lib/statement.cpp index ac83084..669dc2a 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp | |||
| @@ -133,19 +133,19 @@ namespace verbly { | |||
| 133 | return queryStream.str(); | 133 | return queryStream.str(); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | std::list<binding> statement::getBindings() const | 136 | std::list<hatkirby::binding> statement::getBindings() const |
| 137 | { | 137 | { |
| 138 | std::list<binding> result; | 138 | std::list<hatkirby::binding> result; |
| 139 | 139 | ||
| 140 | for (const with& w : withs_) | 140 | for (const with& w : withs_) |
| 141 | { | 141 | { |
| 142 | for (binding value : w.getCondition().flattenBindings()) | 142 | for (hatkirby::binding value : w.getCondition().flattenBindings()) |
| 143 | { | 143 | { |
| 144 | result.push_back(std::move(value)); | 144 | result.push_back(std::move(value)); |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | for (binding value : topCondition_.flattenBindings()) | 148 | for (hatkirby::binding value : topCondition_.flattenBindings()) |
| 149 | { | 149 | { |
| 150 | result.push_back(std::move(value)); | 150 | result.push_back(std::move(value)); |
| 151 | } | 151 | } |
| @@ -203,77 +203,152 @@ namespace verbly { | |||
| 203 | { | 203 | { |
| 204 | case filter::comparison::is_null: | 204 | case filter::comparison::is_null: |
| 205 | { | 205 | { |
| 206 | return condition(topTable_, clause.getField().getColumn(), true); | 206 | return { |
| 207 | topTable_, | ||
| 208 | clause.getField().getColumn(), | ||
| 209 | true | ||
| 210 | }; | ||
| 207 | } | 211 | } |
| 208 | 212 | ||
| 209 | case filter::comparison::is_not_null: | 213 | case filter::comparison::is_not_null: |
| 210 | { | 214 | { |
| 211 | return condition(topTable_, clause.getField().getColumn(), false); | 215 | return { |
| 216 | topTable_, | ||
| 217 | clause.getField().getColumn(), | ||
| 218 | false | ||
| 219 | }; | ||
| 212 | } | 220 | } |
| 213 | 221 | ||
| 214 | case filter::comparison::int_equals: | 222 | case filter::comparison::int_equals: |
| 215 | { | 223 | { |
| 216 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getIntegerArgument()); | 224 | return { |
| 225 | topTable_, | ||
| 226 | clause.getField().getColumn(), | ||
| 227 | condition::comparison::equals, | ||
| 228 | clause.getIntegerArgument() | ||
| 229 | }; | ||
| 217 | } | 230 | } |
| 218 | 231 | ||
| 219 | case filter::comparison::int_does_not_equal: | 232 | case filter::comparison::int_does_not_equal: |
| 220 | { | 233 | { |
| 221 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getIntegerArgument()); | 234 | return { |
| 235 | topTable_, | ||
| 236 | clause.getField().getColumn(), | ||
| 237 | condition::comparison::does_not_equal, | ||
| 238 | clause.getIntegerArgument() | ||
| 239 | }; | ||
| 222 | } | 240 | } |
| 223 | 241 | ||
| 224 | case filter::comparison::int_is_at_least: | 242 | case filter::comparison::int_is_at_least: |
| 225 | { | 243 | { |
| 226 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_least, clause.getIntegerArgument()); | 244 | return { |
| 245 | topTable_, | ||
| 246 | clause.getField().getColumn(), | ||
| 247 | condition::comparison::is_at_least, | ||
| 248 | clause.getIntegerArgument() | ||
| 249 | }; | ||
| 227 | } | 250 | } |
| 228 | 251 | ||
| 229 | case filter::comparison::int_is_greater_than: | 252 | case filter::comparison::int_is_greater_than: |
| 230 | { | 253 | { |
| 231 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_greater_than, clause.getIntegerArgument()); | 254 | return { |
| 255 | topTable_, | ||
| 256 | clause.getField().getColumn(), | ||
| 257 | condition::comparison::is_greater_than, | ||
| 258 | clause.getIntegerArgument() | ||
| 259 | }; | ||
| 232 | } | 260 | } |
| 233 | 261 | ||
| 234 | case filter::comparison::int_is_at_most: | 262 | case filter::comparison::int_is_at_most: |
| 235 | { | 263 | { |
| 236 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_most, clause.getIntegerArgument()); | 264 | return { |
| 265 | topTable_, | ||
| 266 | clause.getField().getColumn(), | ||
| 267 | condition::comparison::is_at_most, | ||
| 268 | clause.getIntegerArgument() | ||
| 269 | }; | ||
| 237 | } | 270 | } |
| 238 | 271 | ||
| 239 | case filter::comparison::int_is_less_than: | 272 | case filter::comparison::int_is_less_than: |
| 240 | { | 273 | { |
| 241 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_less_than, clause.getIntegerArgument()); | 274 | return { |
| 275 | topTable_, | ||
| 276 | clause.getField().getColumn(), | ||
| 277 | condition::comparison::is_less_than, | ||
| 278 | clause.getIntegerArgument() | ||
| 279 | }; | ||
| 242 | } | 280 | } |
| 243 | 281 | ||
| 244 | case filter::comparison::boolean_equals: | 282 | case filter::comparison::boolean_equals: |
| 245 | { | 283 | { |
| 246 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getBooleanArgument() ? 1 : 0); | 284 | return { |
| 285 | topTable_, | ||
| 286 | clause.getField().getColumn(), | ||
| 287 | condition::comparison::equals, | ||
| 288 | clause.getBooleanArgument() ? 1 : 0 | ||
| 289 | }; | ||
| 247 | } | 290 | } |
| 248 | 291 | ||
| 249 | case filter::comparison::string_equals: | 292 | case filter::comparison::string_equals: |
| 250 | { | 293 | { |
| 251 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getStringArgument()); | 294 | return { |
| 295 | topTable_, | ||
| 296 | clause.getField().getColumn(), | ||
| 297 | condition::comparison::equals, | ||
| 298 | clause.getStringArgument() | ||
| 299 | }; | ||
| 252 | } | 300 | } |
| 253 | 301 | ||
| 254 | case filter::comparison::string_does_not_equal: | 302 | case filter::comparison::string_does_not_equal: |
| 255 | { | 303 | { |
| 256 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getStringArgument()); | 304 | return { |
| 305 | topTable_, | ||
| 306 | clause.getField().getColumn(), | ||
| 307 | condition::comparison::does_not_equal, | ||
| 308 | clause.getStringArgument() | ||
| 309 | }; | ||
| 257 | } | 310 | } |
| 258 | 311 | ||
| 259 | case filter::comparison::string_is_like: | 312 | case filter::comparison::string_is_like: |
| 260 | { | 313 | { |
| 261 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_like, clause.getStringArgument()); | 314 | return { |
| 315 | topTable_, | ||
| 316 | clause.getField().getColumn(), | ||
| 317 | condition::comparison::is_like, | ||
| 318 | clause.getStringArgument() | ||
| 319 | }; | ||
| 262 | } | 320 | } |
| 263 | 321 | ||
| 264 | case filter::comparison::string_is_not_like: | 322 | case filter::comparison::string_is_not_like: |
| 265 | { | 323 | { |
| 266 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument()); | 324 | return { |
| 325 | topTable_, | ||
| 326 | clause.getField().getColumn(), | ||
| 327 | condition::comparison::is_not_like, | ||
| 328 | clause.getStringArgument() | ||
| 329 | }; | ||
| 267 | } | 330 | } |
| 268 | 331 | ||
| 269 | case filter::comparison::field_equals: | 332 | case filter::comparison::field_equals: |
| 270 | { | 333 | { |
| 271 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject()); | 334 | return { |
| 335 | topTable_, | ||
| 336 | clause.getField().getColumn(), | ||
| 337 | condition::comparison::equals, | ||
| 338 | field_binding {"", clause.getCompareField().getColumn()}, | ||
| 339 | clause.getCompareField().getObject() | ||
| 340 | }; | ||
| 272 | } | 341 | } |
| 273 | 342 | ||
| 274 | case filter::comparison::field_does_not_equal: | 343 | case filter::comparison::field_does_not_equal: |
| 275 | { | 344 | { |
| 276 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject()); | 345 | return { |
| 346 | topTable_, | ||
| 347 | clause.getField().getColumn(), | ||
| 348 | condition::comparison::does_not_equal, | ||
| 349 | field_binding {"", clause.getCompareField().getColumn()}, | ||
| 350 | clause.getCompareField().getObject() | ||
| 351 | }; | ||
| 277 | } | 352 | } |
| 278 | 353 | ||
| 279 | case filter::comparison::matches: | 354 | case filter::comparison::matches: |
| @@ -680,206 +755,19 @@ namespace verbly { | |||
| 680 | << j.getJoinColumn(); | 755 | << j.getJoinColumn(); |
| 681 | } | 756 | } |
| 682 | 757 | ||
| 683 | statement::condition::condition(const condition& other) | ||
| 684 | { | ||
| 685 | type_ = other.type_; | ||
| 686 | |||
| 687 | switch (type_) | ||
| 688 | { | ||
| 689 | case type::empty: | ||
| 690 | { | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | |||
| 694 | case type::singleton: | ||
| 695 | { | ||
| 696 | new(&singleton_.table_) std::string(other.singleton_.table_); | ||
| 697 | new(&singleton_.column_) std::string(other.singleton_.column_); | ||
| 698 | singleton_.comparison_ = other.singleton_.comparison_; | ||
| 699 | new(&singleton_.value_) binding(other.singleton_.value_); | ||
| 700 | singleton_.parentObject_ = other.singleton_.parentObject_; | ||
| 701 | |||
| 702 | break; | ||
| 703 | } | ||
| 704 | |||
| 705 | case type::group: | ||
| 706 | { | ||
| 707 | new(&group_.children_) std::list<condition>(other.group_.children_); | ||
| 708 | group_.orlogic_ = other.group_.orlogic_; | ||
| 709 | |||
| 710 | break; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | } | ||
| 714 | |||
| 715 | statement::condition::condition(condition&& other) : condition() | ||
| 716 | { | ||
| 717 | swap(*this, other); | ||
| 718 | } | ||
| 719 | |||
| 720 | statement::condition& statement::condition::operator=(condition other) | ||
| 721 | { | ||
| 722 | swap(*this, other); | ||
| 723 | |||
| 724 | return *this; | ||
| 725 | } | ||
| 726 | |||
| 727 | void swap(statement::condition& first, statement::condition& second) | ||
| 728 | { | ||
| 729 | using type = statement::condition::type; | ||
| 730 | using condition = statement::condition; | ||
| 731 | |||
| 732 | type tempType = first.type_; | ||
| 733 | std::string tempTable; | ||
| 734 | std::string tempColumn; | ||
| 735 | condition::comparison tempComparison; | ||
| 736 | binding tempBinding; | ||
| 737 | object tempParentObject; | ||
| 738 | std::list<condition> tempChildren; | ||
| 739 | bool tempOrlogic; | ||
| 740 | |||
| 741 | switch (tempType) | ||
| 742 | { | ||
| 743 | case type::empty: | ||
| 744 | { | ||
| 745 | break; | ||
| 746 | } | ||
| 747 | |||
| 748 | case type::singleton: | ||
| 749 | { | ||
| 750 | tempTable = std::move(first.singleton_.table_); | ||
| 751 | tempColumn = std::move(first.singleton_.column_); | ||
| 752 | tempComparison = first.singleton_.comparison_; | ||
| 753 | tempBinding = std::move(first.singleton_.value_); | ||
| 754 | tempParentObject = first.singleton_.parentObject_; | ||
| 755 | |||
| 756 | break; | ||
| 757 | } | ||
| 758 | |||
| 759 | case type::group: | ||
| 760 | { | ||
| 761 | tempChildren = std::move(first.group_.children_); | ||
| 762 | tempOrlogic = first.group_.orlogic_; | ||
| 763 | |||
| 764 | break; | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | first.~condition(); | ||
| 769 | |||
| 770 | first.type_ = second.type_; | ||
| 771 | |||
| 772 | switch (first.type_) | ||
| 773 | { | ||
| 774 | case type::empty: | ||
| 775 | { | ||
| 776 | break; | ||
| 777 | } | ||
| 778 | |||
| 779 | case type::singleton: | ||
| 780 | { | ||
| 781 | new(&first.singleton_.table_) std::string(std::move(second.singleton_.table_)); | ||
| 782 | new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_)); | ||
| 783 | first.singleton_.comparison_ = second.singleton_.comparison_; | ||
| 784 | new(&first.singleton_.value_) binding(std::move(second.singleton_.value_)); | ||
| 785 | first.singleton_.parentObject_ = second.singleton_.parentObject_; | ||
| 786 | |||
| 787 | break; | ||
| 788 | } | ||
| 789 | |||
| 790 | case type::group: | ||
| 791 | { | ||
| 792 | new(&first.group_.children_) std::list<condition>(std::move(second.group_.children_)); | ||
| 793 | first.group_.orlogic_ = second.group_.orlogic_; | ||
| 794 | |||
| 795 | break; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | second.~condition(); | ||
| 800 | |||
| 801 | second.type_ = tempType; | ||
| 802 | |||
| 803 | switch (second.type_) | ||
| 804 | { | ||
| 805 | case type::empty: | ||
| 806 | { | ||
| 807 | break; | ||
| 808 | } | ||
| 809 | |||
| 810 | case type::singleton: | ||
| 811 | { | ||
| 812 | new(&second.singleton_.table_) std::string(std::move(tempTable)); | ||
| 813 | new(&second.singleton_.column_) std::string(std::move(tempColumn)); | ||
| 814 | second.singleton_.comparison_ = tempComparison; | ||
| 815 | new(&second.singleton_.value_) binding(std::move(tempBinding)); | ||
| 816 | second.singleton_.parentObject_ = tempParentObject; | ||
| 817 | |||
| 818 | break; | ||
| 819 | } | ||
| 820 | |||
| 821 | case type::group: | ||
| 822 | { | ||
| 823 | new(&second.group_.children_) std::list<condition>(std::move(tempChildren)); | ||
| 824 | second.group_.orlogic_ = tempOrlogic; | ||
| 825 | |||
| 826 | break; | ||
| 827 | } | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | statement::condition::~condition() | ||
| 832 | { | ||
| 833 | switch (type_) | ||
| 834 | { | ||
| 835 | case type::empty: | ||
| 836 | { | ||
| 837 | break; | ||
| 838 | } | ||
| 839 | |||
| 840 | case type::singleton: | ||
| 841 | { | ||
| 842 | using string_type = std::string; | ||
| 843 | |||
| 844 | singleton_.table_.~string_type(); | ||
| 845 | singleton_.column_.~string_type(); | ||
| 846 | singleton_.value_.~binding(); | ||
| 847 | |||
| 848 | break; | ||
| 849 | } | ||
| 850 | |||
| 851 | case type::group: | ||
| 852 | { | ||
| 853 | using list_type = std::list<condition>; | ||
| 854 | |||
| 855 | group_.children_.~list_type(); | ||
| 856 | |||
| 857 | break; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | } | ||
| 861 | |||
| 862 | statement::condition::condition() : type_(type::empty) | ||
| 863 | { | ||
| 864 | } | ||
| 865 | |||
| 866 | statement::condition::condition( | 758 | statement::condition::condition( |
| 867 | std::string table, | 759 | std::string table, |
| 868 | std::string column, | 760 | std::string column, |
| 869 | bool isNull) : | 761 | bool isNull) : |
| 870 | type_(type::singleton) | 762 | type_(type::singleton), |
| 763 | variant_(singleton_type { | ||
| 764 | std::move(table), | ||
| 765 | std::move(column), | ||
| 766 | isNull ? comparison::is_null : comparison::is_not_null, | ||
| 767 | {}, | ||
| 768 | object::undefined | ||
| 769 | }) | ||
| 871 | { | 770 | { |
| 872 | new(&singleton_.table_) std::string(std::move(table)); | ||
| 873 | new(&singleton_.column_) std::string(std::move(column)); | ||
| 874 | |||
| 875 | if (isNull) | ||
| 876 | { | ||
| 877 | singleton_.comparison_ = comparison::is_null; | ||
| 878 | } else { | ||
| 879 | singleton_.comparison_ = comparison::is_not_null; | ||
| 880 | } | ||
| 881 | |||
| 882 | singleton_.parentObject_ = object::undefined; | ||
| 883 | } | 771 | } |
| 884 | 772 | ||
| 885 | statement::condition::condition( | 773 | statement::condition::condition( |
| @@ -888,201 +776,210 @@ namespace verbly { | |||
| 888 | comparison comp, | 776 | comparison comp, |
| 889 | binding value, | 777 | binding value, |
| 890 | object parentObject) : | 778 | object parentObject) : |
| 891 | type_(type::singleton) | 779 | type_(type::singleton), |
| 780 | variant_(singleton_type { | ||
| 781 | std::move(table), | ||
| 782 | std::move(column), | ||
| 783 | comp, | ||
| 784 | std::move(value), | ||
| 785 | parentObject | ||
| 786 | }) | ||
| 892 | { | 787 | { |
| 893 | new(&singleton_.table_) std::string(std::move(table)); | ||
| 894 | new(&singleton_.column_) std::string(std::move(column)); | ||
| 895 | singleton_.comparison_ = comp; | ||
| 896 | new(&singleton_.value_) binding(std::move(value)); | ||
| 897 | singleton_.parentObject_ = parentObject; | ||
| 898 | } | 788 | } |
| 899 | 789 | ||
| 900 | std::string statement::condition::toSql(bool toplevel, bool debug) const | 790 | std::string statement::condition::toSql(bool toplevel, bool debug) const |
| 901 | { | 791 | { |
| 792 | std::ostringstream sql; | ||
| 793 | |||
| 902 | switch (type_) | 794 | switch (type_) |
| 903 | { | 795 | { |
| 904 | case type::empty: | 796 | case type::empty: |
| 905 | { | 797 | { |
| 906 | return ""; | 798 | break; |
| 907 | } | 799 | } |
| 908 | 800 | ||
| 909 | case type::singleton: | 801 | case type::singleton: |
| 910 | { | 802 | { |
| 911 | switch (singleton_.comparison_) | 803 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 804 | |||
| 805 | sql << singleton.table << "." << singleton.column; | ||
| 806 | |||
| 807 | switch (singleton.comparison) | ||
| 912 | { | 808 | { |
| 913 | case comparison::equals: | 809 | case comparison::equals: |
| 810 | case comparison::does_not_equal: | ||
| 914 | { | 811 | { |
| 915 | if (debug) | 812 | if (singleton.comparison == comparison::equals) |
| 916 | { | 813 | { |
| 917 | switch (singleton_.value_.getType()) | 814 | sql << " = "; |
| 918 | { | ||
| 919 | case binding::type::string: | ||
| 920 | { | ||
| 921 | return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; | ||
| 922 | } | ||
| 923 | |||
| 924 | case binding::type::integer: | ||
| 925 | { | ||
| 926 | return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); | ||
| 927 | } | ||
| 928 | |||
| 929 | case binding::type::field: | ||
| 930 | { | ||
| 931 | return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 932 | } | ||
| 933 | |||
| 934 | case binding::type::invalid: | ||
| 935 | { | ||
| 936 | throw std::logic_error("Invalid binding in statement generation"); | ||
| 937 | } | ||
| 938 | } | ||
| 939 | } else { | 815 | } else { |
| 940 | if (singleton_.value_.getType() == binding::type::field) | 816 | sql << " != "; |
| 941 | { | ||
| 942 | return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 943 | } else { | ||
| 944 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | ||
| 945 | } | ||
| 946 | } | 817 | } |
| 947 | } | ||
| 948 | 818 | ||
| 949 | case comparison::does_not_equal: | 819 | if (mpark::holds_alternative<field_binding>(singleton.value)) |
| 950 | { | 820 | { |
| 951 | if (debug) | 821 | sql << std::get<0>(mpark::get<field_binding>(singleton.value)) |
| 822 | << "." | ||
| 823 | << std::get<1>(mpark::get<field_binding>(singleton.value)); | ||
| 824 | } else if (debug) | ||
| 952 | { | 825 | { |
| 953 | switch (singleton_.value_.getType()) | 826 | if (mpark::holds_alternative<std::string>(singleton.value)) |
| 954 | { | 827 | { |
| 955 | case binding::type::string: | 828 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 956 | { | ||
| 957 | return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; | ||
| 958 | } | ||
| 959 | |||
| 960 | case binding::type::integer: | ||
| 961 | { | ||
| 962 | return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); | ||
| 963 | } | ||
| 964 | |||
| 965 | case binding::type::field: | ||
| 966 | { | ||
| 967 | return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 968 | } | ||
| 969 | |||
| 970 | case binding::type::invalid: | ||
| 971 | { | ||
| 972 | throw std::logic_error("Invalid binding in statement generation"); | ||
| 973 | } | ||
| 974 | } | 829 | } |
| 975 | } else { | 830 | else if (mpark::holds_alternative<int>(singleton.value)) |
| 976 | if (singleton_.value_.getType() == binding::type::field) | ||
| 977 | { | 831 | { |
| 978 | return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | 832 | sql << mpark::get<int>(singleton.value); |
| 979 | } else { | ||
| 980 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | ||
| 981 | } | 833 | } |
| 834 | } else { | ||
| 835 | sql << "?"; | ||
| 982 | } | 836 | } |
| 837 | |||
| 838 | break; | ||
| 983 | } | 839 | } |
| 984 | 840 | ||
| 985 | case comparison::is_greater_than: | 841 | case comparison::is_greater_than: |
| 986 | { | 842 | { |
| 843 | sql << " > "; | ||
| 844 | |||
| 987 | if (debug) | 845 | if (debug) |
| 988 | { | 846 | { |
| 989 | return singleton_.table_ + "." + singleton_.column_ + " > " + std::to_string(singleton_.value_.getInteger()); | 847 | sql << mpark::get<int>(singleton.value); |
| 990 | } else { | 848 | } else { |
| 991 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | 849 | sql << "?"; |
| 992 | } | 850 | } |
| 851 | |||
| 852 | break; | ||
| 993 | } | 853 | } |
| 994 | 854 | ||
| 995 | case comparison::is_at_most: | 855 | case comparison::is_at_most: |
| 996 | { | 856 | { |
| 857 | sql << " <= "; | ||
| 858 | |||
| 997 | if (debug) | 859 | if (debug) |
| 998 | { | 860 | { |
| 999 | return singleton_.table_ + "." + singleton_.column_ + " <= " + std::to_string(singleton_.value_.getInteger()); | 861 | sql << mpark::get<int>(singleton.value); |
| 1000 | } else { | 862 | } else { |
| 1001 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | 863 | sql << "?"; |
| 1002 | } | 864 | } |
| 865 | |||
| 866 | break; | ||
| 1003 | } | 867 | } |
| 1004 | 868 | ||
| 1005 | case comparison::is_less_than: | 869 | case comparison::is_less_than: |
| 1006 | { | 870 | { |
| 871 | sql << " < "; | ||
| 872 | |||
| 1007 | if (debug) | 873 | if (debug) |
| 1008 | { | 874 | { |
| 1009 | return singleton_.table_ + "." + singleton_.column_ + " < " + std::to_string(singleton_.value_.getInteger()); | 875 | sql << mpark::get<int>(singleton.value); |
| 1010 | } else { | 876 | } else { |
| 1011 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | 877 | sql << "?"; |
| 1012 | } | 878 | } |
| 879 | |||
| 880 | break; | ||
| 1013 | } | 881 | } |
| 1014 | 882 | ||
| 1015 | case comparison::is_at_least: | 883 | case comparison::is_at_least: |
| 1016 | { | 884 | { |
| 885 | sql << " >= "; | ||
| 886 | |||
| 1017 | if (debug) | 887 | if (debug) |
| 1018 | { | 888 | { |
| 1019 | return singleton_.table_ + "." + singleton_.column_ + " >= " + std::to_string(singleton_.value_.getInteger()); | 889 | sql << mpark::get<int>(singleton.value); |
| 1020 | } else { | 890 | } else { |
| 1021 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | 891 | sql << "?"; |
| 1022 | } | 892 | } |
| 893 | |||
| 894 | break; | ||
| 1023 | } | 895 | } |
| 1024 | 896 | ||
| 1025 | case comparison::is_like: | 897 | case comparison::is_like: |
| 1026 | { | 898 | { |
| 899 | sql << " LIKE "; | ||
| 900 | |||
| 1027 | if (debug) | 901 | if (debug) |
| 1028 | { | 902 | { |
| 1029 | return singleton_.table_ + "." + singleton_.column_ + " LIKE \"" + singleton_.value_.getString() + "\""; | 903 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 1030 | } else { | 904 | } else { |
| 1031 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | 905 | sql << "?"; |
| 1032 | } | 906 | } |
| 907 | |||
| 908 | break; | ||
| 1033 | } | 909 | } |
| 1034 | 910 | ||
| 1035 | case comparison::is_not_like: | 911 | case comparison::is_not_like: |
| 1036 | { | 912 | { |
| 913 | sql << " NOT LIKE "; | ||
| 914 | |||
| 1037 | if (debug) | 915 | if (debug) |
| 1038 | { | 916 | { |
| 1039 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE \"" + singleton_.value_.getString() + "\""; | 917 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 1040 | } else { | 918 | } else { |
| 1041 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | 919 | sql << "?"; |
| 1042 | } | 920 | } |
| 921 | |||
| 922 | break; | ||
| 1043 | } | 923 | } |
| 1044 | 924 | ||
| 1045 | case comparison::is_not_null: | 925 | case comparison::is_not_null: |
| 1046 | { | 926 | { |
| 1047 | return singleton_.table_ + "." + singleton_.column_ + " IS NOT NULL"; | 927 | sql << " IS NOT NULL"; |
| 928 | |||
| 929 | break; | ||
| 1048 | } | 930 | } |
| 1049 | 931 | ||
| 1050 | case comparison::is_null: | 932 | case comparison::is_null: |
| 1051 | { | 933 | { |
| 1052 | return singleton_.table_ + "." + singleton_.column_ + " IS NULL"; | 934 | sql << " IS NULL"; |
| 935 | |||
| 936 | break; | ||
| 1053 | } | 937 | } |
| 1054 | } | 938 | } |
| 939 | |||
| 940 | break; | ||
| 1055 | } | 941 | } |
| 1056 | 942 | ||
| 1057 | case type::group: | 943 | case type::group: |
| 1058 | { | 944 | { |
| 945 | const group_type& group = mpark::get<group_type>(variant_); | ||
| 946 | |||
| 1059 | std::list<std::string> clauses; | 947 | std::list<std::string> clauses; |
| 1060 | for (const condition& cond : group_.children_) | 948 | for (const condition& cond : group.children) |
| 1061 | { | 949 | { |
| 1062 | clauses.push_back(cond.toSql(false, debug)); | 950 | clauses.push_back(cond.toSql(false, debug)); |
| 1063 | } | 951 | } |
| 1064 | 952 | ||
| 1065 | if (clauses.empty()) | 953 | if (clauses.size() == 1) |
| 1066 | { | 954 | { |
| 1067 | return ""; | 955 | sql << clauses.front(); |
| 1068 | } else if (clauses.size() == 1) | 956 | } else if (!clauses.empty()) |
| 1069 | { | 957 | { |
| 1070 | return clauses.front(); | 958 | if (!toplevel) |
| 1071 | } else { | 959 | { |
| 1072 | std::string result = hatkirby::implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | 960 | sql << "("; |
| 961 | } | ||
| 962 | |||
| 963 | sql << | ||
| 964 | hatkirby::implode( | ||
| 965 | std::begin(clauses), | ||
| 966 | std::end(clauses), | ||
| 967 | group.orlogic ? " OR " : " AND "); | ||
| 1073 | 968 | ||
| 1074 | if (toplevel) | 969 | if (!toplevel) |
| 1075 | { | 970 | { |
| 1076 | return result; | 971 | sql << ")"; |
| 1077 | } else { | ||
| 1078 | return "(" + result + ")"; | ||
| 1079 | } | 972 | } |
| 1080 | } | 973 | } |
| 974 | |||
| 975 | break; | ||
| 1081 | } | 976 | } |
| 1082 | } | 977 | } |
| 978 | |||
| 979 | return sql.str(); | ||
| 1083 | } | 980 | } |
| 1084 | 981 | ||
| 1085 | std::list<binding> statement::condition::flattenBindings() const | 982 | std::list<hatkirby::binding> statement::condition::flattenBindings() const |
| 1086 | { | 983 | { |
| 1087 | switch (type_) | 984 | switch (type_) |
| 1088 | { | 985 | { |
| @@ -1093,39 +990,27 @@ namespace verbly { | |||
| 1093 | 990 | ||
| 1094 | case type::singleton: | 991 | case type::singleton: |
| 1095 | { | 992 | { |
| 1096 | if (singleton_.value_.getType() == binding::type::field) | 993 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 994 | |||
| 995 | if (mpark::holds_alternative<std::string>(singleton.value)) | ||
| 1097 | { | 996 | { |
| 1098 | return {}; | 997 | return {{ mpark::get<std::string>(singleton.value) }}; |
| 998 | } else if (mpark::holds_alternative<int>(singleton.value)) | ||
| 999 | { | ||
| 1000 | return {{ mpark::get<int>(singleton.value) }}; | ||
| 1099 | } else { | 1001 | } else { |
| 1100 | switch (singleton_.comparison_) | 1002 | return {}; |
| 1101 | { | ||
| 1102 | case comparison::equals: | ||
| 1103 | case comparison::does_not_equal: | ||
| 1104 | case comparison::is_greater_than: | ||
| 1105 | case comparison::is_at_most: | ||
| 1106 | case comparison::is_less_than: | ||
| 1107 | case comparison::is_at_least: | ||
| 1108 | case comparison::is_like: | ||
| 1109 | case comparison::is_not_like: | ||
| 1110 | { | ||
| 1111 | return {singleton_.value_}; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | case comparison::is_not_null: | ||
| 1115 | case comparison::is_null: | ||
| 1116 | { | ||
| 1117 | return {}; | ||
| 1118 | } | ||
| 1119 | } | ||
| 1120 | } | 1003 | } |
| 1121 | } | 1004 | } |
| 1122 | 1005 | ||
| 1123 | case type::group: | 1006 | case type::group: |
| 1124 | { | 1007 | { |
| 1125 | std::list<binding> bindings; | 1008 | const group_type& group = mpark::get<group_type>(variant_); |
| 1126 | for (const condition& cond : group_.children_) | 1009 | |
| 1010 | std::list<hatkirby::binding> bindings; | ||
| 1011 | for (const condition& cond : group.children) | ||
| 1127 | { | 1012 | { |
| 1128 | for (binding value : cond.flattenBindings()) | 1013 | for (hatkirby::binding value : cond.flattenBindings()) |
| 1129 | { | 1014 | { |
| 1130 | bindings.push_back(std::move(value)); | 1015 | bindings.push_back(std::move(value)); |
| 1131 | } | 1016 | } |
| @@ -1136,22 +1021,24 @@ namespace verbly { | |||
| 1136 | } | 1021 | } |
| 1137 | } | 1022 | } |
| 1138 | 1023 | ||
| 1139 | statement::condition::condition(bool orlogic) : type_(type::group) | 1024 | statement::condition::condition( |
| 1025 | bool orlogic) : | ||
| 1026 | type_(type::group), | ||
| 1027 | variant_(group_type { {}, orlogic }) | ||
| 1140 | { | 1028 | { |
| 1141 | new(&group_.children_) std::list<condition>(); | ||
| 1142 | group_.orlogic_ = orlogic; | ||
| 1143 | } | 1029 | } |
| 1144 | 1030 | ||
| 1145 | statement::condition& statement::condition::operator+=(condition n) | 1031 | statement::condition& statement::condition::operator+=(condition n) |
| 1146 | { | 1032 | { |
| 1147 | if (type_ == type::group) | 1033 | if (type_ != type::group) |
| 1148 | { | 1034 | { |
| 1149 | group_.children_.push_back(std::move(n)); | ||
| 1150 | |||
| 1151 | return *this; | ||
| 1152 | } else { | ||
| 1153 | throw std::domain_error("Cannot add condition to non-group condition"); | 1035 | throw std::domain_error("Cannot add condition to non-group condition"); |
| 1154 | } | 1036 | } |
| 1037 | |||
| 1038 | group_type& group = mpark::get<group_type>(variant_); | ||
| 1039 | group.children.emplace_back(std::move(n)); | ||
| 1040 | |||
| 1041 | return *this; | ||
| 1155 | } | 1042 | } |
| 1156 | 1043 | ||
| 1157 | statement::condition& statement::condition::operator&=(condition n) | 1044 | statement::condition& statement::condition::operator&=(condition n) |
| @@ -1187,14 +1074,17 @@ namespace verbly { | |||
| 1187 | return *this; | 1074 | return *this; |
| 1188 | } | 1075 | } |
| 1189 | 1076 | ||
| 1190 | const std::list<statement::condition>& statement::condition::getChildren() const | 1077 | const std::list<statement::condition>& statement::condition::getChildren() |
| 1078 | const | ||
| 1191 | { | 1079 | { |
| 1192 | if (type_ == type::group) | 1080 | if (type_ != type::group) |
| 1193 | { | 1081 | { |
| 1194 | return group_.children_; | ||
| 1195 | } else { | ||
| 1196 | throw std::domain_error("Cannot get children of non-group condition"); | 1082 | throw std::domain_error("Cannot get children of non-group condition"); |
| 1197 | } | 1083 | } |
| 1084 | |||
| 1085 | const group_type& group = mpark::get<group_type>(variant_); | ||
| 1086 | |||
| 1087 | return group.children; | ||
| 1198 | } | 1088 | } |
| 1199 | 1089 | ||
| 1200 | statement::condition statement::condition::flatten() const | 1090 | statement::condition statement::condition::flatten() const |
| @@ -1209,17 +1099,27 @@ namespace verbly { | |||
| 1209 | 1099 | ||
| 1210 | case type::group: | 1100 | case type::group: |
| 1211 | { | 1101 | { |
| 1212 | condition result(group_.orlogic_); | 1102 | const group_type& group = mpark::get<group_type>(variant_); |
| 1213 | 1103 | ||
| 1214 | for (const condition& child : group_.children_) | 1104 | condition result(group.orlogic); |
| 1105 | |||
| 1106 | for (const condition& child : group.children) | ||
| 1215 | { | 1107 | { |
| 1216 | condition newChild = child.flatten(); | 1108 | condition newChild = child.flatten(); |
| 1217 | 1109 | ||
| 1218 | if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) | 1110 | if (newChild.type_ == type::group) |
| 1219 | { | 1111 | { |
| 1220 | for (condition subChild : std::move(newChild.group_.children_)) | 1112 | group_type& childGroup = |
| 1113 | mpark::get<group_type>(newChild.variant_); | ||
| 1114 | |||
| 1115 | if (childGroup.orlogic == group.orlogic) | ||
| 1221 | { | 1116 | { |
| 1222 | result += std::move(subChild); | 1117 | for (condition subChild : std::move(childGroup.children)) |
| 1118 | { | ||
| 1119 | result += std::move(subChild); | ||
| 1120 | } | ||
| 1121 | } else { | ||
| 1122 | result += std::move(newChild); | ||
| 1223 | } | 1123 | } |
| 1224 | } else { | 1124 | } else { |
| 1225 | result += std::move(newChild); | 1125 | result += std::move(newChild); |
| @@ -1231,7 +1131,9 @@ namespace verbly { | |||
| 1231 | } | 1131 | } |
| 1232 | } | 1132 | } |
| 1233 | 1133 | ||
| 1234 | statement::condition statement::condition::resolveCompareFields(object context, std::string tableName) const | 1134 | statement::condition statement::condition::resolveCompareFields( |
| 1135 | object context, | ||
| 1136 | std::string tableName) const | ||
| 1235 | { | 1137 | { |
| 1236 | switch (type_) | 1138 | switch (type_) |
| 1237 | { | 1139 | { |
| @@ -1242,9 +1144,20 @@ namespace verbly { | |||
| 1242 | 1144 | ||
| 1243 | case type::singleton: | 1145 | case type::singleton: |
| 1244 | { | 1146 | { |
| 1245 | if ((singleton_.parentObject_ != object::undefined) && (singleton_.parentObject_ == context)) | 1147 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 1148 | |||
| 1149 | if (singleton.parentObject != object::undefined && | ||
| 1150 | singleton.parentObject == context) | ||
| 1246 | { | 1151 | { |
| 1247 | return condition(singleton_.table_, singleton_.column_, singleton_.comparison_, {tableName, singleton_.value_.getColumn()}); | 1152 | return { |
| 1153 | singleton.table, | ||
| 1154 | singleton.column, | ||
| 1155 | singleton.comparison, | ||
| 1156 | field_binding { | ||
| 1157 | tableName, | ||
| 1158 | std::get<1>(mpark::get<field_binding>(singleton.value)) | ||
| 1159 | } | ||
| 1160 | }; | ||
| 1248 | } else { | 1161 | } else { |
| 1249 | return *this; | 1162 | return *this; |
| 1250 | } | 1163 | } |
| @@ -1252,8 +1165,10 @@ namespace verbly { | |||
| 1252 | 1165 | ||
| 1253 | case type::group: | 1166 | case type::group: |
| 1254 | { | 1167 | { |
| 1255 | condition result(group_.orlogic_); | 1168 | const group_type& group = mpark::get<group_type>(variant_); |
| 1256 | for (const condition& cond : group_.children_) | 1169 | |
| 1170 | condition result(group.orlogic); | ||
| 1171 | for (const condition& cond : group.children) | ||
| 1257 | { | 1172 | { |
| 1258 | result += cond.resolveCompareFields(context, tableName); | 1173 | result += cond.resolveCompareFields(context, tableName); |
| 1259 | } | 1174 | } |
| diff --git a/lib/statement.h b/lib/statement.h index 2fadf05..6c2e42e 100644 --- a/lib/statement.h +++ b/lib/statement.h | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | #include <string> | 4 | #include <string> |
| 5 | #include <list> | 5 | #include <list> |
| 6 | #include <map> | 6 | #include <map> |
| 7 | #include <set> | 7 | #include <hkutil/database.h> |
| 8 | #include "binding.h" | 8 | #include <variant.hpp> |
| 9 | #include "enums.h" | 9 | #include "enums.h" |
| 10 | #include "field.h" | 10 | #include "field.h" |
| 11 | #include "filter.h" | 11 | #include "filter.h" |
| @@ -15,14 +15,28 @@ namespace verbly { | |||
| 15 | class filter; | 15 | class filter; |
| 16 | class order; | 16 | class order; |
| 17 | 17 | ||
| 18 | using field_binding = | ||
| 19 | std::tuple<std::string, std::string>; | ||
| 20 | |||
| 21 | using binding = | ||
| 22 | mpark::variant< | ||
| 23 | mpark::monostate, | ||
| 24 | std::string, | ||
| 25 | int, | ||
| 26 | field_binding>; | ||
| 27 | |||
| 18 | class statement { | 28 | class statement { |
| 19 | public: | 29 | public: |
| 20 | 30 | ||
| 21 | statement(object context, filter queryFilter); | 31 | statement(object context, filter queryFilter); |
| 22 | 32 | ||
| 23 | std::string getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug = false) const; | 33 | std::string getQueryString( |
| 34 | std::list<std::string> select, | ||
| 35 | order sortOrder, | ||
| 36 | int limit, | ||
| 37 | bool debug = false) const; | ||
| 24 | 38 | ||
| 25 | std::list<binding> getBindings() const; | 39 | std::list<hatkirby::binding> getBindings() const; |
| 26 | 40 | ||
| 27 | private: | 41 | private: |
| 28 | 42 | ||
| @@ -108,23 +122,6 @@ namespace verbly { | |||
| 108 | is_null | 122 | is_null |
| 109 | }; | 123 | }; |
| 110 | 124 | ||
| 111 | // Copy and move constructors | ||
| 112 | |||
| 113 | condition(const condition& other); | ||
| 114 | condition(condition&& other); | ||
| 115 | |||
| 116 | // Assignment | ||
| 117 | |||
| 118 | condition& operator=(condition other); | ||
| 119 | |||
| 120 | // Swap | ||
| 121 | |||
| 122 | friend void swap(condition& first, condition& second); | ||
| 123 | |||
| 124 | // Destructor | ||
| 125 | |||
| 126 | ~condition(); | ||
| 127 | |||
| 128 | // Accessors | 125 | // Accessors |
| 129 | 126 | ||
| 130 | type getType() const | 127 | type getType() const |
| @@ -134,13 +131,21 @@ namespace verbly { | |||
| 134 | 131 | ||
| 135 | // Empty | 132 | // Empty |
| 136 | 133 | ||
| 137 | condition(); | 134 | condition() = default; |
| 138 | 135 | ||
| 139 | // Singleton | 136 | // Singleton |
| 140 | 137 | ||
| 141 | condition(std::string table, std::string column, bool isNull); | 138 | condition( |
| 139 | std::string table, | ||
| 140 | std::string column, | ||
| 141 | bool isNull); | ||
| 142 | 142 | ||
| 143 | condition(std::string table, std::string column, comparison comp, binding value, object parentObject = object::undefined); | 143 | condition( |
| 144 | std::string table, | ||
| 145 | std::string column, | ||
| 146 | comparison comp, | ||
| 147 | binding value, | ||
| 148 | object parentObject = object::undefined); | ||
| 144 | 149 | ||
| 145 | // Group | 150 | // Group |
| 146 | 151 | ||
| @@ -156,30 +161,39 @@ namespace verbly { | |||
| 156 | 161 | ||
| 157 | std::string toSql(bool toplevel, bool debug = false) const; | 162 | std::string toSql(bool toplevel, bool debug = false) const; |
| 158 | 163 | ||
| 159 | std::list<binding> flattenBindings() const; | 164 | std::list<hatkirby::binding> flattenBindings() const; |
| 160 | 165 | ||
| 161 | condition flatten() const; | 166 | condition flatten() const; |
| 162 | 167 | ||
| 163 | condition resolveCompareFields(object context, std::string tableName) const; | 168 | condition resolveCompareFields( |
| 169 | object context, | ||
| 170 | std::string tableName) const; | ||
| 164 | 171 | ||
| 165 | private: | 172 | private: |
| 166 | union { | 173 | |
| 167 | struct { | 174 | struct singleton_type { |
| 168 | std::string table_; | 175 | std::string table; |
| 169 | std::string column_; | 176 | std::string column; |
| 170 | comparison comparison_; | 177 | comparison comparison; |
| 171 | binding value_; | 178 | binding value; |
| 172 | object parentObject_; | 179 | object parentObject; |
| 173 | } singleton_; | ||
| 174 | struct { | ||
| 175 | std::list<condition> children_; | ||
| 176 | bool orlogic_; | ||
| 177 | } group_; | ||
| 178 | }; | 180 | }; |
| 179 | type type_; | ||
| 180 | }; | ||
| 181 | 181 | ||
| 182 | friend void swap(condition& first, condition& second); | 182 | struct group_type { |
| 183 | std::list<condition> children; | ||
| 184 | bool orlogic; | ||
| 185 | }; | ||
| 186 | |||
| 187 | using variant_type = | ||
| 188 | mpark::variant< | ||
| 189 | mpark::monostate, | ||
| 190 | singleton_type, | ||
| 191 | group_type>; | ||
| 192 | |||
| 193 | variant_type variant_; | ||
| 194 | |||
| 195 | type type_ = type::empty; | ||
| 196 | }; | ||
| 183 | 197 | ||
| 184 | class with { | 198 | class with { |
| 185 | public: | 199 | public: |
| diff --git a/lib/token.cpp b/lib/token.cpp index 7b1d1fa..b3c7062 100644 --- a/lib/token.cpp +++ b/lib/token.cpp | |||
| @@ -5,322 +5,43 @@ | |||
| 5 | 5 | ||
| 6 | namespace verbly { | 6 | namespace verbly { |
| 7 | 7 | ||
| 8 | token::token(const token& other) | 8 | bool token::isComplete() const |
| 9 | { | ||
| 10 | type_ = other.type_; | ||
| 11 | |||
| 12 | switch (type_) | ||
| 13 | { | ||
| 14 | case type::word: | ||
| 15 | { | ||
| 16 | new(&word_.word_) word(other.word_.word_); | ||
| 17 | word_.category_ = other.word_.category_; | ||
| 18 | |||
| 19 | break; | ||
| 20 | } | ||
| 21 | |||
| 22 | case type::literal: | ||
| 23 | { | ||
| 24 | new(&literal_) std::string(other.literal_); | ||
| 25 | |||
| 26 | break; | ||
| 27 | } | ||
| 28 | |||
| 29 | case type::part: | ||
| 30 | { | ||
| 31 | new(&part_) part(other.part_); | ||
| 32 | |||
| 33 | break; | ||
| 34 | } | ||
| 35 | |||
| 36 | case type::fillin: | ||
| 37 | { | ||
| 38 | new(&fillin_) std::set<std::string>(other.fillin_); | ||
| 39 | |||
| 40 | break; | ||
| 41 | } | ||
| 42 | |||
| 43 | case type::utterance: | ||
| 44 | { | ||
| 45 | new(&utterance_) std::list<token>(other.utterance_); | ||
| 46 | |||
| 47 | break; | ||
| 48 | } | ||
| 49 | |||
| 50 | case type::transform: | ||
| 51 | { | ||
| 52 | transform_.type_ = other.transform_.type_; | ||
| 53 | new(&transform_.strParam_) std::string(other.transform_.strParam_); | ||
| 54 | new(&transform_.strParam2_) std::string(other.transform_.strParam2_); | ||
| 55 | transform_.casingParam_ = other.transform_.casingParam_; | ||
| 56 | new(&transform_.inner_) std::unique_ptr<token>(new token(*other.transform_.inner_)); | ||
| 57 | |||
| 58 | break; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | token::token(token&& other) : token() | ||
| 64 | { | ||
| 65 | swap(*this, other); | ||
| 66 | } | ||
| 67 | |||
| 68 | token& token::operator=(token other) | ||
| 69 | { | ||
| 70 | swap(*this, other); | ||
| 71 | |||
| 72 | return *this; | ||
| 73 | } | ||
| 74 | |||
| 75 | void swap(token& first, token& second) | ||
| 76 | { | ||
| 77 | using type = token::type; | ||
| 78 | using transform_type = token::transform_type; | ||
| 79 | using casing = token::casing; | ||
| 80 | |||
| 81 | type tempType = first.type_; | ||
| 82 | word tempWord; | ||
| 83 | inflection tempCategory; | ||
| 84 | std::string tempLiteral; | ||
| 85 | part tempPart; | ||
| 86 | std::set<std::string> tempFillin; | ||
| 87 | std::list<token> tempUtterance; | ||
| 88 | transform_type tempTransformType; | ||
| 89 | std::string tempTransformStrParam; | ||
| 90 | std::string tempTransformStrParam2; | ||
| 91 | casing tempTransformCasingParam; | ||
| 92 | std::unique_ptr<token> tempTransformInner; | ||
| 93 | |||
| 94 | switch (tempType) | ||
| 95 | { | ||
| 96 | case type::word: | ||
| 97 | { | ||
| 98 | tempWord = std::move(first.word_.word_); | ||
| 99 | tempCategory = first.word_.category_; | ||
| 100 | |||
| 101 | break; | ||
| 102 | } | ||
| 103 | |||
| 104 | case type::literal: | ||
| 105 | { | ||
| 106 | tempLiteral = std::move(first.literal_); | ||
| 107 | |||
| 108 | break; | ||
| 109 | } | ||
| 110 | |||
| 111 | case type::part: | ||
| 112 | { | ||
| 113 | tempPart = std::move(first.part_); | ||
| 114 | |||
| 115 | break; | ||
| 116 | } | ||
| 117 | |||
| 118 | case type::fillin: | ||
| 119 | { | ||
| 120 | tempFillin = std::move(first.fillin_); | ||
| 121 | |||
| 122 | break; | ||
| 123 | } | ||
| 124 | |||
| 125 | case type::utterance: | ||
| 126 | { | ||
| 127 | tempUtterance = std::move(first.utterance_); | ||
| 128 | |||
| 129 | break; | ||
| 130 | } | ||
| 131 | |||
| 132 | case type::transform: | ||
| 133 | { | ||
| 134 | tempTransformType = first.transform_.type_; | ||
| 135 | tempTransformStrParam = std::move(first.transform_.strParam_); | ||
| 136 | tempTransformStrParam2 = std::move(first.transform_.strParam2_); | ||
| 137 | tempTransformCasingParam = first.transform_.casingParam_; | ||
| 138 | tempTransformInner = std::move(first.transform_.inner_); | ||
| 139 | |||
| 140 | break; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | first.~token(); | ||
| 145 | |||
| 146 | first.type_ = second.type_; | ||
| 147 | |||
| 148 | switch (first.type_) | ||
| 149 | { | ||
| 150 | case type::word: | ||
| 151 | { | ||
| 152 | new(&first.word_.word_) word(std::move(second.word_.word_)); | ||
| 153 | first.word_.category_ = second.word_.category_; | ||
| 154 | |||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | case type::literal: | ||
| 159 | { | ||
| 160 | new(&first.literal_) std::string(std::move(second.literal_)); | ||
| 161 | |||
| 162 | break; | ||
| 163 | } | ||
| 164 | |||
| 165 | case type::part: | ||
| 166 | { | ||
| 167 | new(&first.part_) part(std::move(second.part_)); | ||
| 168 | |||
| 169 | break; | ||
| 170 | } | ||
| 171 | |||
| 172 | case type::fillin: | ||
| 173 | { | ||
| 174 | new(&first.fillin_) std::set<std::string>(std::move(second.fillin_)); | ||
| 175 | |||
| 176 | break; | ||
| 177 | } | ||
| 178 | |||
| 179 | case type::utterance: | ||
| 180 | { | ||
| 181 | new(&first.utterance_) std::list<token>(std::move(second.utterance_)); | ||
| 182 | |||
| 183 | break; | ||
| 184 | } | ||
| 185 | |||
| 186 | case type::transform: | ||
| 187 | { | ||
| 188 | first.transform_.type_ = second.transform_.type_; | ||
| 189 | new(&first.transform_.strParam_) std::string(std::move(second.transform_.strParam_)); | ||
| 190 | new(&first.transform_.strParam2_) std::string(std::move(second.transform_.strParam2_)); | ||
| 191 | first.transform_.casingParam_ = second.transform_.casingParam_; | ||
| 192 | new(&first.transform_.inner_) std::unique_ptr<token>(std::move(second.transform_.inner_)); | ||
| 193 | |||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | second.~token(); | ||
| 199 | |||
| 200 | second.type_ = tempType; | ||
| 201 | |||
| 202 | switch (second.type_) | ||
| 203 | { | ||
| 204 | case type::word: | ||
| 205 | { | ||
| 206 | new(&second.word_.word_) word(std::move(tempWord)); | ||
| 207 | second.word_.category_ = tempCategory; | ||
| 208 | |||
| 209 | break; | ||
| 210 | } | ||
| 211 | |||
| 212 | case type::literal: | ||
| 213 | { | ||
| 214 | new(&second.literal_) std::string(std::move(tempLiteral)); | ||
| 215 | |||
| 216 | break; | ||
| 217 | } | ||
| 218 | |||
| 219 | case type::part: | ||
| 220 | { | ||
| 221 | new(&second.part_) part(std::move(tempPart)); | ||
| 222 | |||
| 223 | break; | ||
| 224 | } | ||
| 225 | |||
| 226 | case type::fillin: | ||
| 227 | { | ||
| 228 | new(&second.fillin_) std::set<std::string>(std::move(tempFillin)); | ||
| 229 | |||
| 230 | break; | ||
| 231 | } | ||
| 232 | |||
| 233 | case type::utterance: | ||
| 234 | { | ||
| 235 | new(&second.utterance_) std::list<token>(std::move(tempUtterance)); | ||
| 236 | |||
| 237 | break; | ||
| 238 | } | ||
| 239 | |||
| 240 | case type::transform: | ||
| 241 | { | ||
| 242 | second.transform_.type_ = tempTransformType; | ||
| 243 | new(&second.transform_.strParam_) std::string(std::move(tempTransformStrParam)); | ||
| 244 | new(&second.transform_.strParam2_) std::string(std::move(tempTransformStrParam2)); | ||
| 245 | second.transform_.casingParam_ = tempTransformCasingParam; | ||
| 246 | new(&second.transform_.inner_) std::unique_ptr<token>(std::move(tempTransformInner)); | ||
| 247 | |||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | token::~token() | ||
| 254 | { | 9 | { |
| 255 | switch (type_) | 10 | switch (type_) |
| 256 | { | 11 | { |
| 257 | case type::word: | 12 | case type::word: |
| 258 | { | ||
| 259 | word_.word_.~word(); | ||
| 260 | |||
| 261 | break; | ||
| 262 | } | ||
| 263 | |||
| 264 | case type::literal: | 13 | case type::literal: |
| 265 | { | 14 | { |
| 266 | using string_type = std::string; | 15 | return true; |
| 267 | literal_.~string_type(); | ||
| 268 | |||
| 269 | break; | ||
| 270 | } | 16 | } |
| 271 | 17 | ||
| 272 | case type::part: | 18 | case type::part: |
| 273 | { | ||
| 274 | part_.~part(); | ||
| 275 | |||
| 276 | break; | ||
| 277 | } | ||
| 278 | |||
| 279 | case type::fillin: | 19 | case type::fillin: |
| 280 | { | 20 | { |
| 281 | using set_type = std::set<std::string>; | 21 | return false; |
| 282 | fillin_.~set_type(); | ||
| 283 | |||
| 284 | break; | ||
| 285 | } | 22 | } |
| 286 | 23 | ||
| 287 | case type::utterance: | 24 | case type::utterance: |
| 288 | { | 25 | { |
| 289 | using list_type = std::list<token>; | 26 | const utterance_type& utterance = mpark::get<utterance_type>(variant_); |
| 290 | utterance_.~list_type(); | ||
| 291 | 27 | ||
| 292 | break; | 28 | return std::all_of( |
| 29 | std::begin(utterance), | ||
| 30 | std::end(utterance), | ||
| 31 | [] (const token& tkn) { | ||
| 32 | return tkn.isComplete(); | ||
| 33 | }); | ||
| 293 | } | 34 | } |
| 294 | 35 | ||
| 295 | case type::transform: | 36 | case type::transform: |
| 296 | { | 37 | { |
| 297 | using string_type = std::string; | 38 | const transform_type& transform = mpark::get<transform_type>(variant_); |
| 298 | using ptr_type = std::unique_ptr<token>; | ||
| 299 | |||
| 300 | transform_.strParam_.~string_type(); | ||
| 301 | transform_.strParam2_.~string_type(); | ||
| 302 | transform_.inner_.~ptr_type(); | ||
| 303 | 39 | ||
| 304 | break; | 40 | return transform.inner->isComplete(); |
| 305 | } | 41 | } |
| 306 | } | 42 | } |
| 307 | } | 43 | } |
| 308 | 44 | ||
| 309 | bool token::isComplete() const | ||
| 310 | { | ||
| 311 | switch (type_) | ||
| 312 | { | ||
| 313 | case type::word: return true; | ||
| 314 | case type::literal: return true; | ||
| 315 | case type::part: return false; | ||
| 316 | case type::fillin: return false; | ||
| 317 | case type::utterance: return std::all_of(std::begin(utterance_), std::end(utterance_), [] (const token& tkn) { | ||
| 318 | return tkn.isComplete(); | ||
| 319 | }); | ||
| 320 | case type::transform: return transform_.inner_->isComplete(); | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | std::string token::compile() const | 45 | std::string token::compile() const |
| 325 | { | 46 | { |
| 326 | return compileHelper(" ", false, casing::normal); | 47 | return compileHelper(" ", false, casing::normal); |
| @@ -335,8 +56,9 @@ namespace verbly { | |||
| 335 | { | 56 | { |
| 336 | case type::word: | 57 | case type::word: |
| 337 | { | 58 | { |
| 338 | const form& wordForm = word_.word_.getInflections(word_.category_) | 59 | const word_type& w = mpark::get<word_type>(variant_); |
| 339 | .front(); | 60 | |
| 61 | const form& wordForm = w.value.getInflections(w.category).front(); | ||
| 340 | 62 | ||
| 341 | std::string result = wordForm.getText(); | 63 | std::string result = wordForm.getText(); |
| 342 | 64 | ||
| @@ -381,13 +103,12 @@ namespace verbly { | |||
| 381 | } | 103 | } |
| 382 | } | 104 | } |
| 383 | 105 | ||
| 384 | |||
| 385 | return result; | 106 | return result; |
| 386 | } | 107 | } |
| 387 | 108 | ||
| 388 | case type::literal: | 109 | case type::literal: |
| 389 | { | 110 | { |
| 390 | std::string result = literal_; | 111 | std::string result = mpark::get<literal_type>(variant_); |
| 391 | 112 | ||
| 392 | if (indefiniteArticle && std::isalpha(result[0])) | 113 | if (indefiniteArticle && std::isalpha(result[0])) |
| 393 | { | 114 | { |
| @@ -435,14 +156,19 @@ namespace verbly { | |||
| 435 | return result; | 156 | return result; |
| 436 | } | 157 | } |
| 437 | 158 | ||
| 438 | case type::part: throw std::domain_error("Cannot compile incomplete token"); | 159 | case type::part: |
| 439 | case type::fillin: throw std::domain_error("Cannot compile incomplete token"); | 160 | case type::fillin: |
| 161 | { | ||
| 162 | throw std::domain_error("Cannot compile incomplete token"); | ||
| 163 | } | ||
| 440 | 164 | ||
| 441 | case type::utterance: | 165 | case type::utterance: |
| 442 | { | 166 | { |
| 167 | const utterance_type& utterance = mpark::get<utterance_type>(variant_); | ||
| 168 | |||
| 443 | bool first = true; | 169 | bool first = true; |
| 444 | std::list<std::string> compiled; | 170 | std::list<std::string> compiled; |
| 445 | for (const token& tkn : utterance_) | 171 | for (const token& tkn : utterance) |
| 446 | { | 172 | { |
| 447 | casing propagateCasing = capitalization; | 173 | casing propagateCasing = capitalization; |
| 448 | if ((capitalization == casing::capitalize) && (!first)) | 174 | if ((capitalization == casing::capitalize) && (!first)) |
| @@ -458,58 +184,70 @@ namespace verbly { | |||
| 458 | first = false; | 184 | first = false; |
| 459 | } | 185 | } |
| 460 | 186 | ||
| 461 | return hatkirby::implode(std::begin(compiled), std::end(compiled), separator); | 187 | return hatkirby::implode( |
| 188 | std::begin(compiled), | ||
| 189 | std::end(compiled), | ||
| 190 | separator); | ||
| 462 | } | 191 | } |
| 463 | 192 | ||
| 464 | case type::transform: | 193 | case type::transform: |
| 465 | { | 194 | { |
| 466 | switch (transform_.type_) | 195 | const transform_type& transform = mpark::get<transform_type>(variant_); |
| 196 | |||
| 197 | switch (transform.type) | ||
| 467 | { | 198 | { |
| 468 | case transform_type::separator: | 199 | case transform_mode::separator: |
| 469 | { | 200 | { |
| 470 | return transform_.inner_->compileHelper( | 201 | return transform.inner->compileHelper( |
| 471 | transform_.strParam_, indefiniteArticle, capitalization); | 202 | transform.strParam, |
| 203 | indefiniteArticle, | ||
| 204 | capitalization); | ||
| 472 | } | 205 | } |
| 473 | 206 | ||
| 474 | case transform_type::punctuation: | 207 | case transform_mode::punctuation: |
| 475 | { | 208 | { |
| 476 | return transform_.inner_->compileHelper( | 209 | return transform.inner->compileHelper( |
| 477 | separator, indefiniteArticle, capitalization) | 210 | separator, |
| 478 | + transform_.strParam_; | 211 | indefiniteArticle, |
| 212 | capitalization) + transform.strParam; | ||
| 479 | } | 213 | } |
| 480 | 214 | ||
| 481 | case transform_type::indefinite_article: | 215 | case transform_mode::indefinite_article: |
| 482 | { | 216 | { |
| 483 | return transform_.inner_->compileHelper( | 217 | return transform.inner->compileHelper( |
| 484 | separator, true, capitalization); | 218 | separator, |
| 219 | true, | ||
| 220 | capitalization); | ||
| 485 | } | 221 | } |
| 486 | 222 | ||
| 487 | case transform_type::capitalize: | 223 | case transform_mode::capitalize: |
| 488 | { | 224 | { |
| 489 | return transform_.inner_->compileHelper( | 225 | return transform.inner->compileHelper( |
| 490 | separator, | 226 | separator, |
| 491 | indefiniteArticle, | 227 | indefiniteArticle, |
| 492 | transform_.casingParam_); | 228 | transform.casingParam); |
| 493 | } | 229 | } |
| 494 | 230 | ||
| 495 | case transform_type::quote: | 231 | case transform_mode::quote: |
| 496 | { | 232 | { |
| 497 | return transform_.strParam_ + | 233 | return transform.strParam + |
| 498 | transform_.inner_->compileHelper( | 234 | transform.inner->compileHelper( |
| 499 | separator, | 235 | separator, |
| 500 | indefiniteArticle, | 236 | indefiniteArticle, |
| 501 | capitalization) + | 237 | capitalization) + |
| 502 | transform_.strParam2_; | 238 | transform.strParam2; |
| 503 | } | 239 | } |
| 504 | } | 240 | } |
| 505 | } | 241 | } |
| 506 | } | 242 | } |
| 507 | } | 243 | } |
| 508 | 244 | ||
| 509 | token::token(word arg, inflection category) : type_(type::word) | 245 | token::token( |
| 246 | word arg, | ||
| 247 | inflection category) : | ||
| 248 | type_(type::word), | ||
| 249 | variant_(word_type { std::move(arg), category }) | ||
| 510 | { | 250 | { |
| 511 | new(&word_.word_) word(std::move(arg)); | ||
| 512 | word_.category_ = category; | ||
| 513 | } | 251 | } |
| 514 | 252 | ||
| 515 | const word& token::getWord() const | 253 | const word& token::getWord() const |
| @@ -519,7 +257,7 @@ namespace verbly { | |||
| 519 | throw std::domain_error("Token is not a word"); | 257 | throw std::domain_error("Token is not a word"); |
| 520 | } | 258 | } |
| 521 | 259 | ||
| 522 | return word_.word_; | 260 | return mpark::get<word_type>(variant_).value; |
| 523 | } | 261 | } |
| 524 | 262 | ||
| 525 | token token::inflect(inflection category) const | 263 | token token::inflect(inflection category) const |
| @@ -529,46 +267,57 @@ namespace verbly { | |||
| 529 | throw std::domain_error("Token is not a word"); | 267 | throw std::domain_error("Token is not a word"); |
| 530 | } | 268 | } |
| 531 | 269 | ||
| 532 | return token(word_.word_, category); | 270 | return { |
| 271 | mpark::get<word_type>(variant_).value, | ||
| 272 | category | ||
| 273 | }; | ||
| 533 | } | 274 | } |
| 534 | 275 | ||
| 535 | token::token(std::string arg) : type_(type::literal) | 276 | token::token( |
| 277 | std::string arg) : | ||
| 278 | type_(type::literal), | ||
| 279 | variant_(std::move(arg)) | ||
| 536 | { | 280 | { |
| 537 | new(&literal_) std::string(std::move(arg)); | ||
| 538 | } | 281 | } |
| 539 | 282 | ||
| 540 | token::token(const char* arg) : token(std::string(arg)) | 283 | token::token( |
| 284 | const char* arg) : | ||
| 285 | token(std::string(arg)) | ||
| 541 | { | 286 | { |
| 542 | } | 287 | } |
| 543 | 288 | ||
| 544 | std::string token::getLiteral() const | 289 | const std::string& token::getLiteral() const |
| 545 | { | 290 | { |
| 546 | if (type_ != type::literal) | 291 | if (type_ != type::literal) |
| 547 | { | 292 | { |
| 548 | throw std::domain_error("Token is not a literal"); | 293 | throw std::domain_error("Token is not a literal"); |
| 549 | } | 294 | } |
| 550 | 295 | ||
| 551 | return literal_; | 296 | return mpark::get<literal_type>(variant_); |
| 552 | } | 297 | } |
| 553 | 298 | ||
| 554 | token::token(part arg) : type_(type::part) | 299 | token::token( |
| 300 | part arg) : | ||
| 301 | type_(type::part), | ||
| 302 | variant_(std::move(arg)) | ||
| 555 | { | 303 | { |
| 556 | new(&part_) part(std::move(arg)); | ||
| 557 | } | 304 | } |
| 558 | 305 | ||
| 559 | part token::getPart() const | 306 | const part& token::getPart() const |
| 560 | { | 307 | { |
| 561 | if (type_ != type::part) | 308 | if (type_ != type::part) |
| 562 | { | 309 | { |
| 563 | throw std::domain_error("Token is not a part"); | 310 | throw std::domain_error("Token is not a part"); |
| 564 | } | 311 | } |
| 565 | 312 | ||
| 566 | return part_; | 313 | return mpark::get<part>(variant_); |
| 567 | } | 314 | } |
| 568 | 315 | ||
| 569 | token::token(std::set<std::string> synrestrs) : type_(type::fillin) | 316 | token::token( |
| 317 | std::set<std::string> synrestrs) : | ||
| 318 | type_(type::fillin), | ||
| 319 | variant_(std::move(synrestrs)) | ||
| 570 | { | 320 | { |
| 571 | new(&fillin_) std::set<std::string>(std::move(synrestrs)); | ||
| 572 | } | 321 | } |
| 573 | 322 | ||
| 574 | const std::set<std::string>& token::getSynrestrs() const | 323 | const std::set<std::string>& token::getSynrestrs() const |
| @@ -578,7 +327,7 @@ namespace verbly { | |||
| 578 | throw std::domain_error("Token is not a fillin"); | 327 | throw std::domain_error("Token is not a fillin"); |
| 579 | } | 328 | } |
| 580 | 329 | ||
| 581 | return fillin_; | 330 | return mpark::get<fillin_type>(variant_); |
| 582 | } | 331 | } |
| 583 | 332 | ||
| 584 | bool token::hasSynrestr(std::string synrestr) const | 333 | bool token::hasSynrestr(std::string synrestr) const |
| @@ -588,7 +337,7 @@ namespace verbly { | |||
| 588 | throw std::domain_error("Token is not a fillin"); | 337 | throw std::domain_error("Token is not a fillin"); |
| 589 | } | 338 | } |
| 590 | 339 | ||
| 591 | return (fillin_.count(synrestr) == 1); | 340 | return mpark::get<fillin_type>(variant_).count(synrestr); |
| 592 | } | 341 | } |
| 593 | 342 | ||
| 594 | void token::addSynrestr(std::string synrestr) | 343 | void token::addSynrestr(std::string synrestr) |
| @@ -598,22 +347,28 @@ namespace verbly { | |||
| 598 | throw std::domain_error("Token is not a fillin"); | 347 | throw std::domain_error("Token is not a fillin"); |
| 599 | } | 348 | } |
| 600 | 349 | ||
| 601 | fillin_.insert(std::move(synrestr)); | 350 | fillin_type& fillin = mpark::get<fillin_type>(variant_); |
| 351 | fillin.insert(std::move(synrestr)); | ||
| 602 | } | 352 | } |
| 603 | 353 | ||
| 604 | token::token() : type_(type::utterance) | 354 | token::token() : |
| 355 | type_(type::utterance), | ||
| 356 | variant_(utterance_type {}) | ||
| 605 | { | 357 | { |
| 606 | new(&utterance_) std::list<token>(); | ||
| 607 | } | 358 | } |
| 608 | 359 | ||
| 609 | token::token(std::vector<part> parts) : type_(type::utterance) | 360 | token::token( |
| 361 | std::vector<part> parts) : | ||
| 362 | type_(type::utterance), | ||
| 363 | variant_(utterance_type { std::begin(parts), std::end(parts) }) | ||
| 610 | { | 364 | { |
| 611 | new(&utterance_) std::list<token>(std::begin(parts), std::end(parts)); | ||
| 612 | } | 365 | } |
| 613 | 366 | ||
| 614 | token::token(std::initializer_list<token> parts) : type_(type::utterance) | 367 | token::token( |
| 368 | std::initializer_list<token> parts) : | ||
| 369 | type_(type::utterance), | ||
| 370 | variant_(utterance_type { std::move(parts) }) | ||
| 615 | { | 371 | { |
| 616 | new(&utterance_) std::list<token>(std::move(parts)); | ||
| 617 | } | 372 | } |
| 618 | 373 | ||
| 619 | token::iterator token::begin() | 374 | token::iterator token::begin() |
| @@ -623,7 +378,7 @@ namespace verbly { | |||
| 623 | throw std::domain_error("Token is not an utterance"); | 378 | throw std::domain_error("Token is not an utterance"); |
| 624 | } | 379 | } |
| 625 | 380 | ||
| 626 | return std::begin(utterance_); | 381 | return std::begin(mpark::get<utterance_type>(variant_)); |
| 627 | } | 382 | } |
| 628 | 383 | ||
| 629 | token::const_iterator token::begin() const | 384 | token::const_iterator token::begin() const |
| @@ -633,7 +388,7 @@ namespace verbly { | |||
| 633 | throw std::domain_error("Token is not an utterance"); | 388 | throw std::domain_error("Token is not an utterance"); |
| 634 | } | 389 | } |
| 635 | 390 | ||
| 636 | return std::begin(utterance_); | 391 | return std::begin(mpark::get<utterance_type>(variant_)); |
| 637 | } | 392 | } |
| 638 | 393 | ||
| 639 | token::iterator token::end() | 394 | token::iterator token::end() |
| @@ -643,7 +398,7 @@ namespace verbly { | |||
| 643 | throw std::domain_error("Token is not an utterance"); | 398 | throw std::domain_error("Token is not an utterance"); |
| 644 | } | 399 | } |
| 645 | 400 | ||
| 646 | return std::end(utterance_); | 401 | return std::end(mpark::get<utterance_type>(variant_)); |
| 647 | } | 402 | } |
| 648 | 403 | ||
| 649 | token::const_iterator token::end() const | 404 | token::const_iterator token::end() const |
| @@ -653,7 +408,7 @@ namespace verbly { | |||
| 653 | throw std::domain_error("Token is not an utterance"); | 408 | throw std::domain_error("Token is not an utterance"); |
| 654 | } | 409 | } |
| 655 | 410 | ||
| 656 | return std::end(utterance_); | 411 | return std::end(mpark::get<utterance_type>(variant_)); |
| 657 | } | 412 | } |
| 658 | 413 | ||
| 659 | token& token::operator<<(token arg) | 414 | token& token::operator<<(token arg) |
| @@ -663,35 +418,36 @@ namespace verbly { | |||
| 663 | throw std::domain_error("Token is not an utterance"); | 418 | throw std::domain_error("Token is not an utterance"); |
| 664 | } | 419 | } |
| 665 | 420 | ||
| 666 | utterance_.push_back(std::move(arg)); | 421 | utterance_type& utterance = mpark::get<utterance_type>(variant_); |
| 422 | utterance.push_back(std::move(arg)); | ||
| 667 | 423 | ||
| 668 | return *this; | 424 | return *this; |
| 669 | } | 425 | } |
| 670 | 426 | ||
| 671 | token token::separator(std::string param, token inner) | 427 | token token::separator(std::string param, token inner) |
| 672 | { | 428 | { |
| 673 | return token(transform_type::separator, std::move(param), "", std::move(inner)); | 429 | return token(transform_mode::separator, std::move(param), "", std::move(inner)); |
| 674 | } | 430 | } |
| 675 | 431 | ||
| 676 | token token::punctuation(std::string param, token inner) | 432 | token token::punctuation(std::string param, token inner) |
| 677 | { | 433 | { |
| 678 | return token(transform_type::punctuation, std::move(param), "", std::move(inner)); | 434 | return token(transform_mode::punctuation, std::move(param), "", std::move(inner)); |
| 679 | } | 435 | } |
| 680 | 436 | ||
| 681 | token token::indefiniteArticle(token inner) | 437 | token token::indefiniteArticle(token inner) |
| 682 | { | 438 | { |
| 683 | return token(transform_type::indefinite_article, "", "", std::move(inner)); | 439 | return token(transform_mode::indefinite_article, "", "", std::move(inner)); |
| 684 | } | 440 | } |
| 685 | 441 | ||
| 686 | token token::capitalize(casing param, token inner) | 442 | token token::capitalize(casing param, token inner) |
| 687 | { | 443 | { |
| 688 | return token(transform_type::capitalize, param, std::move(inner)); | 444 | return token(transform_mode::capitalize, param, std::move(inner)); |
| 689 | } | 445 | } |
| 690 | 446 | ||
| 691 | token token::quote(std::string opening, std::string closing, token inner) | 447 | token token::quote(std::string opening, std::string closing, token inner) |
| 692 | { | 448 | { |
| 693 | return token( | 449 | return token( |
| 694 | transform_type::quote, | 450 | transform_mode::quote, |
| 695 | std::move(opening), | 451 | std::move(opening), |
| 696 | std::move(closing), | 452 | std::move(closing), |
| 697 | std::move(inner)); | 453 | std::move(inner)); |
| @@ -704,7 +460,7 @@ namespace verbly { | |||
| 704 | throw std::domain_error("Invalid access on non-tranform token"); | 460 | throw std::domain_error("Invalid access on non-tranform token"); |
| 705 | } | 461 | } |
| 706 | 462 | ||
| 707 | return *transform_.inner_; | 463 | return *mpark::get<transform_type>(variant_).inner; |
| 708 | } | 464 | } |
| 709 | 465 | ||
| 710 | const token& token::getInnerToken() const | 466 | const token& token::getInnerToken() const |
| @@ -714,33 +470,38 @@ namespace verbly { | |||
| 714 | throw std::domain_error("Invalid access on non-tranform token"); | 470 | throw std::domain_error("Invalid access on non-tranform token"); |
| 715 | } | 471 | } |
| 716 | 472 | ||
| 717 | return *transform_.inner_; | 473 | return *mpark::get<transform_type>(variant_).inner; |
| 718 | } | 474 | } |
| 719 | 475 | ||
| 720 | token::token( | 476 | token::token( |
| 721 | transform_type type, | 477 | transform_mode type, |
| 722 | std::string param1, | 478 | std::string param1, |
| 723 | std::string param2, | 479 | std::string param2, |
| 724 | token inner) : | 480 | token inner) : |
| 725 | type_(type::transform) | 481 | type_(type::transform), |
| 482 | variant_(transform_type { | ||
| 483 | type, | ||
| 484 | std::move(param1), | ||
| 485 | std::move(param2), | ||
| 486 | casing::normal, | ||
| 487 | new token(std::move(inner)) | ||
| 488 | }) | ||
| 726 | { | 489 | { |
| 727 | transform_.type_ = type; | ||
| 728 | new(&transform_.strParam_) std::string(std::move(param1)); | ||
| 729 | new(&transform_.strParam2_) std::string(std::move(param2)); | ||
| 730 | new(&transform_.inner_) std::unique_ptr<token>(new token(std::move(inner))); | ||
| 731 | } | 490 | } |
| 732 | 491 | ||
| 733 | token::token( | 492 | token::token( |
| 734 | transform_type type, | 493 | transform_mode type, |
| 735 | casing param, | 494 | casing param, |
| 736 | token inner) : | 495 | token inner) : |
| 737 | type_(type::transform) | 496 | type_(type::transform), |
| 497 | variant_(transform_type { | ||
| 498 | type, | ||
| 499 | {}, | ||
| 500 | {}, | ||
| 501 | param, | ||
| 502 | new token(std::move(inner)) | ||
| 503 | }) | ||
| 738 | { | 504 | { |
| 739 | transform_.type_ = type; | ||
| 740 | new(&transform_.strParam_) std::string(); | ||
| 741 | new(&transform_.strParam2_) std::string(); | ||
| 742 | transform_.casingParam_ = param; | ||
| 743 | new(&transform_.inner_) std::unique_ptr<token>(new token(std::move(inner))); | ||
| 744 | } | 505 | } |
| 745 | 506 | ||
| 746 | std::ostream& operator<<(std::ostream& os, token::type type) | 507 | std::ostream& operator<<(std::ostream& os, token::type type) |
| diff --git a/lib/token.h b/lib/token.h index ae7bf96..910a465 100644 --- a/lib/token.h +++ b/lib/token.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <string> | 5 | #include <string> |
| 6 | #include <list> | 6 | #include <list> |
| 7 | #include <set> | 7 | #include <set> |
| 8 | #include <variant.hpp> | ||
| 9 | #include <hkutil/recptr.h> | ||
| 8 | #include "enums.h" | 10 | #include "enums.h" |
| 9 | #include "word.h" | 11 | #include "word.h" |
| 10 | #include "part.h" | 12 | #include "part.h" |
| @@ -22,23 +24,6 @@ namespace verbly { | |||
| 22 | transform | 24 | transform |
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| 25 | // Copy & move constructors | ||
| 26 | |||
| 27 | token(const token& other); | ||
| 28 | token(token&& other); | ||
| 29 | |||
| 30 | // Assignment operator | ||
| 31 | |||
| 32 | token& operator=(token other); | ||
| 33 | |||
| 34 | // Swap | ||
| 35 | |||
| 36 | friend void swap(token& first, token& second); | ||
| 37 | |||
| 38 | // Destructor | ||
| 39 | |||
| 40 | ~token(); | ||
| 41 | |||
| 42 | // Accessors | 27 | // Accessors |
| 43 | 28 | ||
| 44 | type getType() const | 29 | type getType() const |
| @@ -52,7 +37,8 @@ namespace verbly { | |||
| 52 | 37 | ||
| 53 | bool isEmpty() const | 38 | bool isEmpty() const |
| 54 | { | 39 | { |
| 55 | return ((type_ == type::utterance) && (utterance_.empty())); | 40 | return (type_ == type::utterance && |
| 41 | mpark::get<utterance_type>(variant_).empty()); | ||
| 56 | } | 42 | } |
| 57 | 43 | ||
| 58 | // Word | 44 | // Word |
| @@ -68,13 +54,13 @@ namespace verbly { | |||
| 68 | token(std::string arg); | 54 | token(std::string arg); |
| 69 | token(const char* arg); | 55 | token(const char* arg); |
| 70 | 56 | ||
| 71 | std::string getLiteral() const; | 57 | const std::string& getLiteral() const; |
| 72 | 58 | ||
| 73 | // Part | 59 | // Part |
| 74 | 60 | ||
| 75 | token(part arg); | 61 | token(part arg); |
| 76 | 62 | ||
| 77 | part getPart() const; | 63 | const part& getPart() const; |
| 78 | 64 | ||
| 79 | // Fillin | 65 | // Fillin |
| 80 | 66 | ||
| @@ -128,7 +114,7 @@ namespace verbly { | |||
| 128 | bool indefiniteArticle, | 114 | bool indefiniteArticle, |
| 129 | casing capitalization) const; | 115 | casing capitalization) const; |
| 130 | 116 | ||
| 131 | enum class transform_type { | 117 | enum class transform_mode { |
| 132 | separator, | 118 | separator, |
| 133 | punctuation, | 119 | punctuation, |
| 134 | indefinite_article, | 120 | indefinite_article, |
| @@ -137,34 +123,46 @@ namespace verbly { | |||
| 137 | }; | 123 | }; |
| 138 | 124 | ||
| 139 | token( | 125 | token( |
| 140 | transform_type type, | 126 | transform_mode type, |
| 141 | std::string param1, | 127 | std::string param1, |
| 142 | std::string param2, | 128 | std::string param2, |
| 143 | token inner); | 129 | token inner); |
| 144 | 130 | ||
| 145 | token( | 131 | token( |
| 146 | transform_type type, | 132 | transform_mode type, |
| 147 | casing param, | 133 | casing param, |
| 148 | token inner); | 134 | token inner); |
| 149 | 135 | ||
| 150 | union { | 136 | struct word_type { |
| 151 | struct { | 137 | word value; |
| 152 | word word_; | 138 | inflection category; |
| 153 | inflection category_; | ||
| 154 | } word_; | ||
| 155 | std::string literal_; | ||
| 156 | part part_; | ||
| 157 | std::set<std::string> fillin_; | ||
| 158 | std::list<token> utterance_; | ||
| 159 | struct { | ||
| 160 | transform_type type_; | ||
| 161 | std::string strParam_; | ||
| 162 | std::string strParam2_; | ||
| 163 | casing casingParam_; | ||
| 164 | std::unique_ptr<token> inner_; | ||
| 165 | } transform_; | ||
| 166 | }; | 139 | }; |
| 140 | |||
| 141 | using literal_type = std::string; | ||
| 142 | |||
| 143 | using fillin_type = std::set<std::string>; | ||
| 144 | |||
| 145 | using utterance_type = std::list<token>; | ||
| 146 | |||
| 147 | struct transform_type { | ||
| 148 | transform_mode type; | ||
| 149 | std::string strParam; | ||
| 150 | std::string strParam2; | ||
| 151 | casing casingParam; | ||
| 152 | hatkirby::recptr<token> inner; | ||
| 153 | }; | ||
| 154 | |||
| 155 | using variant_type = | ||
| 156 | mpark::variant< | ||
| 157 | word_type, | ||
| 158 | literal_type, | ||
| 159 | part, | ||
| 160 | fillin_type, | ||
| 161 | utterance_type, | ||
| 162 | transform_type>; | ||
| 163 | |||
| 167 | type type_; | 164 | type type_; |
| 165 | variant_type variant_; | ||
| 168 | }; | 166 | }; |
| 169 | 167 | ||
| 170 | std::ostream& operator<<(std::ostream& os, token::type type); | 168 | std::ostream& operator<<(std::ostream& os, token::type type); |
| diff --git a/lib/word.cpp b/lib/word.cpp index 6f0fe22..60657ba 100644 --- a/lib/word.cpp +++ b/lib/word.cpp | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | #include "word.h" | 1 | #include "word.h" |
| 2 | #include <sqlite3.h> | ||
| 3 | #include "form.h" | 2 | #include "form.h" |
| 4 | #include "util.h" | 3 | #include "util.h" |
| 5 | #include "database.h" | 4 | #include "database.h" |
| @@ -45,89 +44,27 @@ namespace verbly { | |||
| 45 | return field::joinThroughWhere(object::word, "lemma_id", object::form, "lemmas_forms", "form_id", "category", static_cast<int>(category)); | 44 | return field::joinThroughWhere(object::word, "lemma_id", object::form, "lemmas_forms", "form_id", "category", static_cast<int>(category)); |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) | 47 | word::word(const database& db, hatkirby::row row) : db_(db), valid_(true) |
| 49 | { | 48 | { |
| 50 | id_ = sqlite3_column_int(row, 0); | 49 | id_ = mpark::get<int>(row[0]); |
| 51 | notionId_ = sqlite3_column_int(row, 1); | ||
| 52 | lemmaId_ = sqlite3_column_int(row, 2); | ||
| 53 | 50 | ||
| 54 | if (sqlite3_column_type(row, 3) != SQLITE_NULL) | 51 | notion_ = db.notions(notion::id == mpark::get<int>(row[1])).first(); |
| 55 | { | ||
| 56 | hasTagCount_ = true; | ||
| 57 | tagCount_ = sqlite3_column_int(row, 3); | ||
| 58 | } | ||
| 59 | |||
| 60 | if (sqlite3_column_type(row, 4) != SQLITE_NULL) | ||
| 61 | { | ||
| 62 | adjectivePosition_ = static_cast<positioning>(sqlite3_column_int(row, 4)); | ||
| 63 | } | ||
| 64 | |||
| 65 | if (sqlite3_column_type(row, 5) != SQLITE_NULL) | ||
| 66 | { | ||
| 67 | hasGroup_ = true; | ||
| 68 | groupId_ = sqlite3_column_int(row, 5); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | const notion& word::getNotion() const | ||
| 73 | { | ||
| 74 | if (!valid_) | ||
| 75 | { | ||
| 76 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 77 | } | ||
| 78 | 52 | ||
| 79 | if (!notion_.isValid()) | 53 | if (!mpark::holds_alternative<std::nullptr_t>(row[3])) |
| 80 | { | 54 | { |
| 81 | notion_ = db_->notions(notion::id == notionId_).first(); | 55 | hasTagCount_ = true; |
| 82 | } | 56 | tagCount_ = mpark::get<int>(row[3]); |
| 83 | |||
| 84 | return notion_; | ||
| 85 | } | ||
| 86 | |||
| 87 | bool word::hasFrames() const | ||
| 88 | { | ||
| 89 | if (!valid_) | ||
| 90 | { | ||
| 91 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 92 | } | ||
| 93 | |||
| 94 | if (!hasGroup_) | ||
| 95 | { | ||
| 96 | return false; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (!initializedFrames_) | ||
| 100 | { | ||
| 101 | initializeFrames(); | ||
| 102 | } | ||
| 103 | |||
| 104 | return !frames_.empty(); | ||
| 105 | } | ||
| 106 | |||
| 107 | const std::vector<frame>& word::getFrames() const | ||
| 108 | { | ||
| 109 | if (!valid_) | ||
| 110 | { | ||
| 111 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 112 | } | 57 | } |
| 113 | 58 | ||
| 114 | if (!hasGroup_) | 59 | if (!mpark::holds_alternative<std::nullptr_t>(row[4])) |
| 115 | { | 60 | { |
| 116 | throw std::domain_error("Word does not have a group"); | 61 | adjectivePosition_ = static_cast<positioning>(mpark::get<int>(row[4])); |
| 117 | } | 62 | } |
| 118 | 63 | ||
| 119 | if (!initializedFrames_) | 64 | if (!mpark::holds_alternative<std::nullptr_t>(row[5])) |
| 120 | { | 65 | { |
| 121 | initializeFrames(); | 66 | frames_ = db.frames(*this).all(); |
| 122 | } | 67 | } |
| 123 | |||
| 124 | return frames_; | ||
| 125 | } | ||
| 126 | |||
| 127 | void word::initializeFrames() const | ||
| 128 | { | ||
| 129 | initializedFrames_ = true; | ||
| 130 | frames_ = db_->frames(*this, {}, -1).all(); | ||
| 131 | } | 68 | } |
| 132 | 69 | ||
| 133 | const form& word::getBaseForm() const | 70 | const form& word::getBaseForm() const |
| @@ -167,7 +104,7 @@ namespace verbly { | |||
| 167 | 104 | ||
| 168 | void word::initializeForm(inflection infl) const | 105 | void word::initializeForm(inflection infl) const |
| 169 | { | 106 | { |
| 170 | forms_[infl] = db_->forms(form::words(infl) %= *this, verbly::form::id, -1).all(); | 107 | forms_[infl] = db_.forms(form::words(infl) %= *this, verbly::form::id, -1).all(); |
| 171 | } | 108 | } |
| 172 | 109 | ||
| 173 | filter word::synonyms_field::operator%=(filter joinCondition) const | 110 | filter word::synonyms_field::operator%=(filter joinCondition) const |
| diff --git a/lib/word.h b/lib/word.h index 8c8de51..f52cc4d 100644 --- a/lib/word.h +++ b/lib/word.h | |||
| @@ -3,14 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | #include <stdexcept> | 4 | #include <stdexcept> |
| 5 | #include <map> | 5 | #include <map> |
| 6 | #include <hkutil/database.h> | ||
| 6 | #include "field.h" | 7 | #include "field.h" |
| 7 | #include "filter.h" | 8 | #include "filter.h" |
| 8 | #include "notion.h" | 9 | #include "notion.h" |
| 9 | #include "frame.h" | 10 | #include "frame.h" |
| 10 | #include "form.h" | 11 | #include "form.h" |
| 11 | 12 | ||
| 12 | struct sqlite3_stmt; | ||
| 13 | |||
| 14 | namespace verbly { | 13 | namespace verbly { |
| 15 | 14 | ||
| 16 | class database; | 15 | class database; |
| @@ -24,7 +23,7 @@ namespace verbly { | |||
| 24 | 23 | ||
| 25 | // Construct from database | 24 | // Construct from database |
| 26 | 25 | ||
| 27 | word(const database& db, sqlite3_stmt* row); | 26 | word(const database& db, hatkirby::row row); |
| 28 | 27 | ||
| 29 | // Accessors | 28 | // Accessors |
| 30 | 29 | ||
| @@ -93,11 +92,35 @@ namespace verbly { | |||
| 93 | return adjectivePosition_; | 92 | return adjectivePosition_; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | const notion& getNotion() const; | 95 | const notion& getNotion() const |
| 96 | { | ||
| 97 | if (!valid_) | ||
| 98 | { | ||
| 99 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 100 | } | ||
| 97 | 101 | ||
| 98 | bool hasFrames() const; | 102 | return notion_; |
| 103 | } | ||
| 99 | 104 | ||
| 100 | const std::vector<frame>& getFrames() const; | 105 | bool hasFrames() const |
| 106 | { | ||
| 107 | if (!valid_) | ||
| 108 | { | ||
| 109 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 110 | } | ||
| 111 | |||
| 112 | return !frames_.empty(); | ||
| 113 | } | ||
| 114 | |||
| 115 | const std::vector<frame>& getFrames() const | ||
| 116 | { | ||
| 117 | if (!valid_) | ||
| 118 | { | ||
| 119 | throw std::domain_error("Bad access to uninitialized word"); | ||
| 120 | } | ||
| 121 | |||
| 122 | return frames_; | ||
| 123 | } | ||
| 101 | 124 | ||
| 102 | const form& getBaseForm() const; | 125 | const form& getBaseForm() const; |
| 103 | 126 | ||
| @@ -181,26 +204,17 @@ namespace verbly { | |||
| 181 | private: | 204 | private: |
| 182 | 205 | ||
| 183 | void initializeForm(inflection category) const; | 206 | void initializeForm(inflection category) const; |
| 184 | void initializeFrames() const; | ||
| 185 | 207 | ||
| 186 | bool valid_ = false; | 208 | bool valid_ = false; |
| 187 | |||
| 188 | int id_; | 209 | int id_; |
| 189 | bool hasTagCount_ = false; | 210 | bool hasTagCount_ = false; |
| 190 | int tagCount_; | 211 | int tagCount_; |
| 191 | positioning adjectivePosition_ = positioning::undefined; | 212 | positioning adjectivePosition_ = positioning::undefined; |
| 192 | int notionId_; | 213 | notion notion_; |
| 193 | int lemmaId_; | 214 | std::vector<frame> frames_; |
| 194 | bool hasGroup_ = false; | ||
| 195 | int groupId_; | ||
| 196 | |||
| 197 | const database* db_; | ||
| 198 | |||
| 199 | mutable notion notion_; | ||
| 200 | mutable bool initializedFrames_ = false; | ||
| 201 | mutable std::vector<frame> frames_; | ||
| 202 | mutable std::map<inflection, std::vector<form>> forms_; | 215 | mutable std::map<inflection, std::vector<form>> forms_; |
| 203 | 216 | ||
| 217 | const database& db_; | ||
| 204 | }; | 218 | }; |
| 205 | 219 | ||
| 206 | }; | 220 | }; |
| diff --git a/vendor/hkutil b/vendor/hkutil | |||
| Subproject b430eb58654298d17492a36c7bcda9f803a327f | Subproject a9a5996310bb33207d3338f353aab97b9ed3a5e | ||
