diff --git a/include/modules/sql.h b/include/modules/sql.h index c529b2f53..e04083f19 100644 --- a/include/modules/sql.h +++ b/include/modules/sql.h @@ -23,46 +23,33 @@ namespace SQL : public Serialize::Data { public: - typedef std::map Map; - Map data; - - ~Data() - { - Clear(); - } - - std::iostream &operator[](const Anope::string &key) override - { - std::stringstream *&ss = data[key]; - if (!ss) - ss = new std::stringstream(); - return *ss; - } + Anope::unordered_map data; size_t Hash() const override { size_t hash = 0; for (const auto &[_, value] : this->data) { - if (!value->str().empty()) - hash ^= Anope::hash_cs()(value->str()); + if (!value.empty()) + hash ^= Anope::hash_cs()(value); } return hash; } - std::map GetData() const + bool LoadInternal(const Anope::string &key, Anope::string &value) override { - std::map d; - for (const auto &[key, value] : this->data) - d[key] = value; - return d; + auto it = this->data.find(key); + if (it == this->data.end()) + return false; + + value = it->second; + return true; } - void Clear() + bool StoreInternal(const Anope::string &key, const Anope::string &value) override { - for (const auto &[_, value] : this->data) - delete value; - this->data.clear(); + this->data[key] = value; + return true; } }; diff --git a/include/serialize.h b/include/serialize.h index 6a2a204ac..aa5a56270 100644 --- a/include/serialize.h +++ b/include/serialize.h @@ -117,7 +117,17 @@ protected: Data() = default; - virtual std::iostream &operator[](const Anope::string &key) = 0; + /** Internal method for loading data from the database. + * @param key The field to get the value of. + * @param value The location to store the retrieved value. + */ + virtual bool LoadInternal(const Anope::string &key, Anope::string &value) = 0; + + /** Internal method for storing data in the database. + * @param key The field to set the value of. + * @param value The value of the field. + */ + virtual bool StoreInternal(const Anope::string &key, const Anope::string &value) = 0; /** Sets the data type of the specified field. This is called automatically from \ref Store. * @param key The field to specify the data type for. @@ -168,7 +178,7 @@ public: else if constexpr (std::is_integral_v && std::is_unsigned_v) SetType(key, DataType::UINT); - this->operator[](key) << value; + StoreInternal(key, Anope::ToString(value)); } /** Tries to load the value of a specific field. @@ -178,7 +188,16 @@ public: template bool TryLoad(const Anope::string& key, T &out) { - return static_cast(this->operator[](key) >> out); + Anope::string out_str; + if (!LoadInternal(key, out_str)) + return false; + + auto out_opt = Anope::TryConvert(out_str); + if (!out_opt) + return false; + + out = out_opt.value(); + return true; } }; diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp index b7ac02244..ba0ff610e 100644 --- a/modules/database/db_flatfile.cpp +++ b/modules/database/db_flatfile.cpp @@ -21,7 +21,6 @@ public: std::fstream *fs; Serializable::Id id = 0; std::map data; - std::stringstream ss; bool read = false; LoadData(std::fstream &fsref) @@ -29,7 +28,7 @@ public: { } - std::iostream &operator[](const Anope::string &key) override + bool LoadInternal(const Anope::string &key, Anope::string &value) override { if (!read) { @@ -51,9 +50,13 @@ public: read = true; } - ss.clear(); - this->ss << this->data[key]; - return this->ss; + value = this->data[key]; + return true; + } + + bool StoreInternal(const Anope::string &key, const Anope::string &value) override + { + return false; // This module can only load data. } size_t Hash() const override diff --git a/modules/database/db_json.cpp b/modules/database/db_json.cpp index 1ede48b09..ec054fe85 100644 --- a/modules/database/db_json.cpp +++ b/modules/database/db_json.cpp @@ -38,7 +38,7 @@ public: Serializable::Id id = 0; // Data in this database entry. - Anope::map data; + Anope::unordered_map data; // Used when writing data. Data(Serialize::Type *s_type, Serializable *obj) @@ -58,7 +58,7 @@ public: if (yyjson_get_type(key) != YYJSON_TYPE_STR) continue; - auto akey = yyjson_get_astr(key); + const auto akey = yyjson_get_astr(key); if (akey.equals_ci("@id")) { this->id = yyjson_get_uint(value); @@ -66,23 +66,28 @@ public: } if (yyjson_is_bool(value)) - data[akey] << yyjson_get_bool(value); + data[akey] = Anope::ToString(yyjson_get_bool(value)); else if (yyjson_is_int(value)) - data[akey] << yyjson_get_int(value); + data[akey] = Anope::ToString(yyjson_get_int(value)); else if (yyjson_is_null(value)) data[akey]; else if (yyjson_is_real(value)) - data[akey] << yyjson_get_real(value); + data[akey] = Anope::ToString(yyjson_get_real(value)); else if (yyjson_is_str(value)) - data[akey] << yyjson_get_astr(value); + data[akey] = Anope::ToString(yyjson_get_astr(value)); else if (yyjson_is_uint(value)) - data[akey] << yyjson_get_uint(value); + data[akey] = Anope::ToString(yyjson_get_uint(value)); } } - std::iostream &operator[](const Anope::string &key) override + bool LoadInternal(const Anope::string &key, Anope::string &value) override { - return data[key]; + auto it = this->data.find(key); + if (it == this->data.end()) + return false; + + value = it->second; + return true; } size_t Hash() const override @@ -96,6 +101,12 @@ public: } return hash; } + + bool StoreInternal(const Anope::string &key, const Anope::string &value) override + { + this->data[key] = value; + return true; + } }; class DBJSON final @@ -318,22 +329,23 @@ private: switch (data.GetType(key)) { case Serialize::DataType::BOOL: - v = yyjson_mut_bool(doc, Anope::Convert(value.str(), false)); + v = yyjson_mut_bool(doc, Anope::Convert(value, false)); break; case Serialize::DataType::FLOAT: - v = yyjson_mut_real(doc, Anope::Convert(value.str(), 0.0)); + v = yyjson_mut_real(doc, Anope::Convert(value, 0.0)); break; case Serialize::DataType::INT: - v = yyjson_mut_int(doc, Anope::Convert(value.str(), 0)); + v = yyjson_mut_int(doc, Anope::Convert(value, 0)); break; case Serialize::DataType::TEXT: { - auto str = value.str(); - v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length()); + v = value.empty() + ? yyjson_mut_null(doc) + : yyjson_mut_strncpy(doc, value.c_str(), value.length()); break; } case Serialize::DataType::UINT: - v = yyjson_mut_uint(doc, Anope::Convert(value.str(), 0)); + v = yyjson_mut_uint(doc, Anope::Convert(value, 0)); break; } diff --git a/modules/database/db_redis.cpp b/modules/database/db_redis.cpp index b15790162..3ba6229b7 100644 --- a/modules/database/db_redis.cpp +++ b/modules/database/db_redis.cpp @@ -24,28 +24,30 @@ class Data final : public Serialize::Data { public: - std::map data; + Anope::unordered_map data; - ~Data() override + bool LoadInternal(const Anope::string &key, Anope::string &value) override { - for (auto &[_, stream] : data) - delete stream; + auto it = this->data.find(key); + if (it == this->data.end()) + return false; + + value = it->second; + return true; } - std::iostream &operator[](const Anope::string &key) override + bool StoreInternal(const Anope::string &key, const Anope::string &value) override { - std::stringstream *&stream = data[key]; - if (!stream) - stream = new std::stringstream(); - return *stream; + this->data[key] = value; + return true; } size_t Hash() const override { size_t hash = 0; for (const auto &[_, value] : this->data) - if (!value->str().empty()) - hash ^= Anope::hash_cs()(value->str()); + if (!value.empty()) + hash ^= Anope::hash_cs()(value); return hash; } }; @@ -311,7 +313,7 @@ void ObjectLoader::OnResult(const Reply &r) const Reply *key = r.multi_bulk[i], *value = r.multi_bulk[i + 1]; - data[key->bulk] << value->bulk; + data.StoreInternal(key->bulk, value->bulk); } Serializable *&obj = st->objects[this->id]; @@ -444,12 +446,12 @@ void Updater::OnResult(const Reply &r) for (const auto &[key, value] : data.data) { args.push_back(key); - args.emplace_back(value->str()); + args.emplace_back(value); std::vector args2; args2.emplace_back("SADD"); - args2.push_back("value:" + this->type + ":" + key + ":" + value->str()); + args2.push_back("value:" + this->type + ":" + key + ":" + value); args2.push_back(Anope::ToString(obj->object_id)); /* Add to value -> object id set */ @@ -544,7 +546,7 @@ void SubscriptionListener::OnResult(const Reply &r) { std::vector args; args.emplace_back("SREM"); - args.push_back("value:" + type + ":" + k + ":" + value->str()); + args.push_back("value:" + type + ":" + k + ":" + value); args.push_back(id); /* Delete value -> object id */ @@ -592,7 +594,7 @@ void ModifiedObject::OnResult(const Reply &r) { std::vector args; args.emplace_back("SREM"); - args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str()); + args.push_back("value:" + st->GetName() + ":" + key + ":" + value); args.push_back(Anope::ToString(this->id)); /* Delete value -> object id */ @@ -607,7 +609,7 @@ void ModifiedObject::OnResult(const Reply &r) const Reply *key = r.multi_bulk[i], *value = r.multi_bulk[i + 1]; - data[key->bulk] << value->bulk; + data.StoreInternal(key->bulk, value->bulk); } obj = st->Unserialize(obj, data); @@ -621,7 +623,7 @@ void ModifiedObject::OnResult(const Reply &r) { std::vector args; args.emplace_back("SADD"); - args.push_back("value:" + st->GetName() + ":" + key + ":" + value->str()); + args.push_back("value:" + st->GetName() + ":" + key + ":" + value); args.push_back(Anope::ToString(obj->object_id)); /* Add to value -> object id set */ diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp index ecdcc39cf..80d460e6e 100644 --- a/modules/database/db_sql.cpp +++ b/modules/database/db_sql.cpp @@ -256,7 +256,7 @@ public: Data data; for (const auto &[key, value] : res.Row(j)) - data[key] << value; + data.StoreInternal(key, value); Serializable *obj = sb->Unserialize(NULL, data); if (obj) diff --git a/modules/database/db_sql_live.cpp b/modules/database/db_sql_live.cpp index ab1d3f0ef..6dfd3e477 100644 --- a/modules/database/db_sql_live.cpp +++ b/modules/database/db_sql_live.cpp @@ -220,7 +220,7 @@ public: Data data; for (const auto &[key, value] : row) - data[key] << value; + data.StoreInternal(key, value); Serializable *s = NULL; auto it = obj->objects.find(id); diff --git a/modules/extra/mysql.cpp b/modules/extra/mysql.cpp index 8bc62ce28..9d9309b35 100644 --- a/modules/extra/mysql.cpp +++ b/modules/extra/mysql.cpp @@ -575,7 +575,7 @@ Query MySQLService::BuildInsert(const Anope::string &table, Serializable::Id id, for (const auto &known_col : this->active_schema[table]) { if (data.data.count(known_col) == 0) - data[known_col] << ""; + data.data[known_col]; } Anope::string query_text = "INSERT INTO `" + table + "` (`id`"; @@ -593,9 +593,7 @@ Query MySQLService::BuildInsert(const Anope::string &table, Serializable::Id id, Query query(query_text); for (auto &[field, value] : data.data) { - Anope::string buf; - *value >> buf; - + auto buf = value; auto escape = true; switch (data.GetType(field)) { diff --git a/modules/extra/sqlite.cpp b/modules/extra/sqlite.cpp index 2a9f413eb..6003c9746 100644 --- a/modules/extra/sqlite.cpp +++ b/modules/extra/sqlite.cpp @@ -311,7 +311,7 @@ Query SQLiteService::BuildInsert(const Anope::string &table, Serializable::Id id for (const auto &known_col : this->active_schema[table]) { if (known_col != "id" && known_col != "timestamp" && data.data.count(known_col) == 0) - data[known_col] << ""; + data.data[known_col]; } Anope::string query_text = "REPLACE INTO `" + table + "` ("; @@ -331,9 +331,7 @@ Query SQLiteService::BuildInsert(const Anope::string &table, Serializable::Id id Query query(query_text); for (auto &[field, value] : data.data) { - Anope::string buf; - *value >> buf; - + auto buf = value; auto escape = true; switch (data.GetType(field)) { diff --git a/modules/rpc/rpc_data.cpp b/modules/rpc/rpc_data.cpp index ae378291b..9f7d7f838 100644 --- a/modules/rpc/rpc_data.cpp +++ b/modules/rpc/rpc_data.cpp @@ -28,11 +28,11 @@ class SaveData final : public Serialize::Data { public: - Anope::map data; + Anope::unordered_map data; - std::iostream &operator[](const Anope::string &key) override + bool LoadInternal(const Anope::string &key, Anope::string &value) override { - return data[key]; + return false; // This module can only store data. } static void Serialize(const Extensible *e, const Serializable *s, RPC::Map &map) @@ -41,32 +41,37 @@ public: Extensible::ExtensibleSerialize(e, s, data); for (const auto &[k, v] : data.data) { - auto vs = v.str(); switch (data.GetType(k)) { case Serialize::DataType::BOOL: - map.Reply(k, Anope::Convert(vs, false)); + map.Reply(k, Anope::Convert(v, false)); break; case Serialize::DataType::FLOAT: - map.Reply(k, Anope::Convert(vs, 0.0)); + map.Reply(k, Anope::Convert(v, 0.0)); break; case Serialize::DataType::INT: - map.Reply(k, Anope::Convert(vs, 0)); + map.Reply(k, Anope::Convert(v, 0)); break; case Serialize::DataType::TEXT: { - if (vs.empty()) + if (v.empty()) map.Reply(k, nullptr); else - map.Reply(k, vs); + map.Reply(k, v); break; } case Serialize::DataType::UINT: - map.Reply(k, Anope::Convert(vs, 0)); + map.Reply(k, Anope::Convert(v, 0)); break; } } } + + bool StoreInternal(const Anope::string &key, const Anope::string &value) override + { + data[key] = value; + return true; + } }; class AnopeListAccountsRPCEvent final