diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a7f527..097d879 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,7 @@ PRIVATE yycc/carton/binstore/types.cpp yycc/carton/binstore/setting.cpp yycc/carton/binstore/configuration.cpp - #yycc/carton/binstore/storage.cpp + yycc/carton/binstore/storage.cpp ) target_sources(YYCCommonplace PUBLIC @@ -110,7 +110,7 @@ FILES yycc/carton/binstore/serializer.hpp yycc/carton/binstore/setting.hpp yycc/carton/binstore/configuration.hpp - #yycc/carton/binstore/storage.hpp + yycc/carton/binstore/storage.hpp yycc/carton/fft.hpp ) # Setup header infomations diff --git a/src/yycc/carton/binstore/serializer.hpp b/src/yycc/carton/binstore/serializer.hpp index d84c637..f71a184 100644 --- a/src/yycc/carton/binstore/serializer.hpp +++ b/src/yycc/carton/binstore/serializer.hpp @@ -48,6 +48,7 @@ namespace yycc::carton::binstore::serializer { auto TMax = std::numeric_limits::max(), auto TDefault = static_cast(0)> struct IntegralSerDes { + IntegralSerDes() = default; YYCC_DEFAULT_COPY_MOVE(IntegralSerDes) static_assert(TMin <= TMax); @@ -82,6 +83,11 @@ namespace yycc::carton::binstore::serializer { auto TMax = std::numeric_limits::max(), auto TDefault = static_cast(0)> struct FloatingPointSerDes { + FloatingPointSerDes() { + // TODO: Remove this and make it "= default" when 3 common STL make std::isfinite become constexpr. + if (!std::isfinite(TMin)) throw std::logic_error("invalid float minimum value."); + if (!std::isfinite(TMax)) throw std::logic_error("invalid float maximum value."); + } YYCC_DEFAULT_COPY_MOVE(FloatingPointSerDes) // TODO: Use static_assert once 3 common STL make this become constexpr. @@ -116,6 +122,7 @@ namespace yycc::carton::binstore::serializer { template struct BoolSerDes { + BoolSerDes() = default; YYCC_DEFAULT_COPY_MOVE(BoolSerDes) using ValueType = bool; @@ -140,6 +147,7 @@ namespace yycc::carton::binstore::serializer { }; struct StringSerDes { + StringSerDes() = default; YYCC_DEFAULT_COPY_MOVE(StringSerDes) using ValueType = std::u8string; diff --git a/src/yycc/carton/binstore/storage.cpp b/src/yycc/carton/binstore/storage.cpp index aa5858d..8967a24 100644 --- a/src/yycc/carton/binstore/storage.cpp +++ b/src/yycc/carton/binstore/storage.cpp @@ -1,13 +1,72 @@ #include "storage.hpp" +#include + +#define TYPES ::yycc::carton::binstore::types +#define CFG ::yycc::carton::binstore::configuration +#define SERDES ::yycc::carton::binstore::serializer namespace yycc::carton::binstore::storage { #pragma region Storage Class - Storage::Storage() {} + Storage::Storage(CFG::Configuration&& cfg) : cfg(std::move(cfg)), raws() {} Storage::~Storage() {} + TYPES::BinstoreResult Storage::load_from_file(const std::filesystem::path& fpath, LoadStrategy strategy) { + std::ifstream fs(fpath, std::ios::binary); + if (fs.is_open()) { + auto rv = this->load(fs, strategy); + fs.close(); + return rv; + } else { + return std::unexpected(TYPES::BinstoreError::Io); + } + } + + TYPES::BinstoreResult Storage::load(std::istream& s, LoadStrategy strategy) { + return TYPES::BinstoreResult(); + } + + TYPES::BinstoreResult Storage::save_into_file(const std::filesystem::path& fpath) { + std::ofstream fs(fpath, std::ios::binary); + if (fs.is_open()) { + auto rv = this->save(fs); + fs.close(); + return rv; + } else { + return std::unexpected(TYPES::BinstoreError::Io); + } + } + + TYPES::BinstoreResult Storage::save(std::ostream& s) { + return TYPES::BinstoreResult(); + } + + bool Storage::has_setting(TYPES::Token token) const { + return this->cfg.get_settings().has_setting(token); + } + + bool Storage::is_setting_stored(TYPES::Token token) const { + if (!this->has_setting(token)) throw std::logic_error("given setting token is invalid"); + return this->raws.contains(token); + } + + const TYPES::ByteArray& Storage::get_raw_value(TYPES::Token token) const { + if (!this->has_setting(token)) throw std::logic_error("given setting token is invalid"); + auto finder = this->raws.find(token); + if (finder != this->raws.end()) { + return finder->second; + } else { + throw std::logic_error("given setting has not been stored yet"); + } + } + + void Storage::set_raw_value(TYPES::Token token, TYPES::ByteArray&& ba) { + if (!this->has_setting(token)) throw std::logic_error("given setting token is invalid"); + this->raws.insert_or_assign(token, std::move(ba)); + } + #pragma endregion } // namespace yycc::carton::binstore::storage diff --git a/src/yycc/carton/binstore/storage.hpp b/src/yycc/carton/binstore/storage.hpp index 9c81efc..aed898f 100644 --- a/src/yycc/carton/binstore/storage.hpp +++ b/src/yycc/carton/binstore/storage.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types #define NS_YYCC_BINSTORE_CFG ::yycc::carton::binstore::configuration @@ -44,19 +45,6 @@ namespace yycc::carton::binstore::storage { AcceptAll, }; - /// @brief The operation result state when getting setting's value. - enum class GetValueState { - Ok, ///< Successfully load value from raw part. We return it. - Default, ///< Given setting is not presented. We create it from its default value and return. - Reset, ///< Can not read from raw part. We reset it in its default value and return. - }; - - /// @brief The operation result state when setting setting's value. - enum class SetValueState { - Ok, ///< Successfully set value. - Reset, ///< Given value is not meet the requirement of this setting and its value was reset into default value. - }; - class Storage { private: /** @@ -65,81 +53,129 @@ namespace yycc::carton::binstore::storage { * Valus is its stored value in raw data format. */ std::map raws; - NS_YYCC_BINSTORE_CFG::Configuration configuration; ///< The configuration associated with this storage. + NS_YYCC_BINSTORE_CFG::Configuration cfg; ///< The configuration associated with this storage. public: - Storage(); + Storage(NS_YYCC_BINSTORE_CFG::Configuration&& cfg); ~Storage(); + YYCC_DEFAULT_COPY_MOVE(Storage) public: NS_YYCC_BINSTORE_TYPES::BinstoreResult load_from_file(const std::filesystem::path& fpath, LoadStrategy strategy); - NS_YYCC_BINSTORE_TYPES::BinstoreResult load_from_io(std::istream& s, LoadStrategy strategy); + NS_YYCC_BINSTORE_TYPES::BinstoreResult load(std::istream& s, LoadStrategy strategy); NS_YYCC_BINSTORE_TYPES::BinstoreResult save_into_file(const std::filesystem::path& fpath); - NS_YYCC_BINSTORE_TYPES::BinstoreResult save_into_io(std::ostream& s); - /** - * @brief Reset all values of setting to their default value. - * @details Please note that all stored value will be wiped before assign them with default value.65 - */ - void reset(); + NS_YYCC_BINSTORE_TYPES::BinstoreResult save(std::ostream& s); private: - bool has_value(NS_YYCC_BINSTORE_TYPES::Token token) const; + /** + * @brief Check whether given token is a valid token to registered settings. + * @param[in] token Token for checking. + * @return True if it is a registered setting, otherwise false. + */ + bool has_setting(NS_YYCC_BINSTORE_TYPES::Token token) const; + /** + * @brief Check whether given token is stored in raw value dictionary. + * @param[in] token Token for checking. + * @return True if it is stored, otherwise false. + * @exception std::logic_error Given token is not point to a registered setting. + */ + bool is_setting_stored(NS_YYCC_BINSTORE_TYPES::Token token) const; + /** + * @brief Get raw value of given setting. + * @param[in] token Token for fetching. + * @return The const reference to given setting's raw data. + * @exception std::logic_error Given token is not point to a registered setting. + * @exception std::logic_error Given token pointed to setting is not stored yet. + */ const NS_YYCC_BINSTORE_TYPES::ByteArray& get_raw_value(NS_YYCC_BINSTORE_TYPES::Token token) const; + /** + * @brief Set raw value for given setting. + * @param[in] token Token for setting. + * @param[in] ba The right-value raw value for setting. + * @exception std::logic_error Given token is not point to a registered setting. + */ void set_raw_value(NS_YYCC_BINSTORE_TYPES::Token token, NS_YYCC_BINSTORE_TYPES::ByteArray&& ba); public: + /** + * @brief Reset given setting into default value. + * @tparam T The SerDes applied to this setting. + * @param[in] token Token to setting for resetting. + * @param[in] serdes Optional SerDes passed if it can not be constructed from default ctor. + */ template - NS_YYCC_BINSTORE_TYPES::BinstoreResult>> get_value( - NS_YYCC_BINSTORE_TYPES::Token token, const T& serdes = T{}) { - // If we have value, we fetch it first - if (this->has_value(token)) { + void reset_value(NS_YYCC_BINSTORE_TYPES::Token token, const T& serdes = T{}) { + // Check whether has this setting. + if (!has_setting(token)) throw std::logic_error("given setting token is invalid"); + // Reset it. + auto ba = serdes.reset(); + this->set_raw_value(token, std::move(ba)); + } + /** + * @brief Get given setting's value. + * @tparam T The SerDes applied to this setting. + * @param[in] token Token to setting for fetching value. + * @param[in] serdes Optional SerDes passed if it can not be constructed from default ctor. + * @return Fetched value. If there is no such setting before or fail to deserialize underlying data, + * Default value will be forcely set before the return of this function. + */ + template + NS_YYCC_BINSTORE_SERDES::SerDesValueType get_value(NS_YYCC_BINSTORE_TYPES::Token token, const T& serdes = T{}) { + // Check whether has this setting. + if (!has_setting(token)) throw std::logic_error("given setting token is invalid"); + + // If we have stored raw value, we fetch it first. + if (this->is_setting_stored(token)) { // Get raw value. const auto& ba = this->get_raw_value(token); // Try to deserialize it. auto value = serdes.deserialize(raw_value); // If the result is okey, return it. if (value.has_value()) { - return std::make_pair(GetValueState::Ok, std::move(value.value())); + return value.value(); } // Otherwise we need reset it into default value. } - // If we do not have this setting, - // or we need reset it into default value, - // we need execute following code. - // First decide the return state. - GetValueState state = this->has_value(token) ? GetValueState::Reset : GetValueState::Default; - { - // Fetch the default raw data. - auto ba = serdes.reset(); - // Set it for this setting. - this->set_raw_value(token, std::move(ba)); - } - // The get it and deserialize it. + // If we do not have this setting, or we need reset it into default value + // due to failed deserialization, we need execute following code. + // Reset its value first + this->reset_value(token, serdes); + // The re-fetch its raw value and deserialize it. const auto& ba = this->get_raw_value(token); auto value = serdes.deserialize(ba); - // Default must can be deserialized. + // Default value must can be deserialized. // If not, throw exception. if (value.has_value()) { - return std::make_pair(state, std::move(value)); + return value.value(); } else { - throw std::logic_error("default value can not be deserialized"); + throw std::logic_error("default value must can be deserialized"); } } + /** + * @brief Set given setting's value. + * @tparam T The SerDes applied to this setting. + * @param[in] token Token to setting for setting value. + * @param[in] value The value to set. + * @param[in] serdes Optional SerDes passed if it can not be constructed from default ctor. + * @return True if the setting was set to your given value, + * otherwise false, the value was set as default value because given value can not be serialized. + */ template - NS_YYCC_BINSTORE_TYPES::BinstoreResult set_value(NS_YYCC_BINSTORE_TYPES::Token token, - const NS_YYCC_BINSTORE_SERDES::SerDesValueType& value, - const T& serdes = T{}) { - // First we try assign it. - { - // Convert it into raw format. - auto ba = serdes.serialize(value); - // If we can not serialize it, we need reset it into default value. - // Otherwise assign it and return. - if (ba.has_value()) { - this->set_raw_value(token, ) - } - } + bool set_value(NS_YYCC_BINSTORE_TYPES::Token token, + const NS_YYCC_BINSTORE_SERDES::SerDesValueType& value, + const T& serdes = T{}) { + // Check whether has this setting. + if (!has_setting(token)) throw std::logic_error("given setting token is invalid"); + + // We try to serialize given value first. + auto rv_ser = serdes.serialize(value); + // If we can serialize it, we directly use it,' + // otherwise we need fetch it from default value. + auto success_ser = rv_ser.has_value(); + auto ba = success_ser ? std::move(rv_ser.value()) : serdes.reset(); + // Assign it to setting's raw value. + this->set_raw_value(token, std::move(ba)); } };