diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c716c96..8017b44 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,7 @@ PRIVATE yycc/carton/clap/manual.cpp yycc/carton/clap/parser.cpp yycc/carton/clap/resolver.cpp + yycc/carton/binstore/types.cpp ) target_sources(YYCCommonplace PUBLIC @@ -101,6 +102,8 @@ FILES yycc/carton/clap/validator.hpp yycc/carton/clap/parser.hpp yycc/carton/clap/resolver.hpp + yycc/carton/binstore/types.hpp + yycc/carton/binstore/serializer.hpp yycc/carton/fft.hpp ) # Setup header infomations diff --git a/src/yycc/carton/binstore/kernel.hpp b/src/yycc/carton/binstore/kernel.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/yycc/carton/binstore/serializer.hpp b/src/yycc/carton/binstore/serializer.hpp new file mode 100644 index 0000000..cb2da9a --- /dev/null +++ b/src/yycc/carton/binstore/serializer.hpp @@ -0,0 +1,187 @@ +#pragma once +#include "../../macro/class_copy_move.hpp" +#include "types.hpp" +#include +#include +#include +#include + +#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types + +namespace yycc::carton::binstore::serializer { + + // TODO: Support numeric list and string list SerDes. + + /** + * @brief The concept for checking whether given type is a valid binstore serializer and deserializer (SerDes). + * @details + * A valid SerDes must have a type name or alias called "ValueType" + * indicating the corresponding setting type which read and write with underlying ByteArray. + * Please note that the type of this value must can be placed into \c std::optional. + * + * SerDes must have following 3 functions: + * \li Function named "serialize" will accept an const reference of setting data, + * and convert it into underlying ByteArray format in return value. + * If any error occurs, it will return \c std::nullopt instead. + * \li Function named "deserialize" will do the opposite operation with "serialize". + * It convert ByteArray into setting desired type, or \c std::nullopt if any error occurs. + * \li Function named "reset" will built an ByteArray which holding default value of this option. + * This is usually used when fail to deserialize or there is no such setting. + */ + template + concept SerDes = requires(const T& t, const NS_YYCC_BINSTORE_TYPES::ByteArray& cba) { + // Check whether there is T::ValueType type + typename T::ValueType; + // Check whether there are required member functions and they have correct signatures. + { t.serialize(std::declval()) } -> std::same_as>; + { t.deserialize(cba) } -> std::same_as>; + { t.reset() } -> std::same_as; + }; + + /// @brief A convenient alias to the value type of SerDes. + template + using SerDesValueType = T::ValueType; + + template::min(), + auto TMax = std::numeric_limits::max(), + auto TDefault = static_cast(0)> + struct IntegralSerDes { + YYCC_DEFAULT_COPY_MOVE(IntegralSerDes) + + static_assert(TMin <= TMax); + static_assert(TDefault >= TMin && TDefault <= TMax); + + using ValueType = T; + static constexpr size_t VALUE_SIZE = sizeof(ValueType); + + std::optional serialize(const ValueType& value) const { + if (value > TMax || value < TMin) return std::nullopt; + + NS_YYCC_BINSTORE_TYPES::ByteArray ba; + ba.ResizeData(VALUE_SIZE); + std::memcpy(ba.GetDataPtr(), &value, VALUE_SIZE); + return ba; + } + + std::optional deserialize(const NS_YYCC_BINSTORE_TYPES::ByteArray& ba) const { + if (ba.GetDataSize() != VALUE_SIZE) return std::nullopt; + ValueType value; + std::memcpy(&value, ba.GetDataPtr(), VALUE_SIZE); + + if (value > TMax || value < TMin) return std::nullopt; + return value; + } + + NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(TDefault).value(); } + }; + + template::lowest(), + auto TMax = std::numeric_limits::max(), + auto TDefault = static_cast(0)> + struct FloatingPointSerDes { + YYCC_DEFAULT_COPY_MOVE(FloatingPointSerDes) + + static_assert(std::isfinite(TMin)); + static_assert(std::isfinite(TMax)); + static_assert(TMin <= TMax); + static_assert(TDefault >= TMin && TDefault <= TMax); + + using ValueType = T; + static constexpr size_t VALUE_SIZE = sizeof(ValueType); + + std::optional serialize(const ValueType& value) const { + if (value > TMax || value < TMin) return std::nullopt; + + NS_YYCC_BINSTORE_TYPES::ByteArray ba; + ba.ResizeData(VALUE_SIZE); + std::memcpy(ba.GetDataPtr(), &value, VALUE_SIZE); + return ba; + } + + std::optional deserialize(const NS_YYCC_BINSTORE_TYPES::ByteArray& ba) const { + if (ba.GetDataSize() != VALUE_SIZE) return std::nullopt; + + ValueType value; + std::memcpy(&value, ba.GetDataPtr(), VALUE_SIZE); + if (value > TMax || value < TMin) return std::nullopt; + return value; + } + + NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(TDefault).value(); } + }; + + template + struct BoolSerDes { + YYCC_DEFAULT_COPY_MOVE(BoolSerDes) + + using ValueType = bool; + static constexpr size_t VALUE_SIZE = sizeof(ValueType); + + std::optional serialize(const ValueType& value) const { + NS_YYCC_BINSTORE_TYPES::ByteArray ba; + ba.ResizeData(VALUE_SIZE); + std::memcpy(ba.GetDataPtr(), &value, VALUE_SIZE); + return ba; + } + + std::optional deserialize(const NS_YYCC_BINSTORE_TYPES::ByteArray& ba) const { + if (ba.GetDataSize() != VALUE_SIZE) return std::nullopt; + + ValueType value; + std::memcpy(&value, ba.GetDataPtr(), VALUE_SIZE); + return value; + } + + NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(TDefault).value(); } + }; + + struct StringSerDes { + YYCC_DEFAULT_COPY_MOVE(StringSerDes) + + using ValueType = std::u8string; + using HeaderType = size_t; + static constexpr size_t HEADER_SIZE = sizeof(HeaderType); + + std::optional serialize(const ValueType& value) const { + // Get the size of string + HeaderType length = value.size(); + + // Prepare byte array and allocate size. + NS_YYCC_BINSTORE_TYPES::ByteArray ba; + ba.ResizeData(HEADER_SIZE + length); + + // Copy length first + std::memcpy(ba.GetDataPtr(), &length, HEADER_SIZE); + // Copy string data + std::memcpy(ba.GetDataPtr(HEADER_SIZE), value.data(), length); + + // Okey + return ba; + } + + std::optional deserialize(const NS_YYCC_BINSTORE_TYPES::ByteArray& ba) const { + // Get byte array size + size_t ba_size = ba.GetDataSize(); + // Check whether it has header + if (ba_size < HEADER_SIZE) return std::nullopt; + + // Get header + HeaderType length; + std::memcpy(&length, ba.GetDataPtr(), HEADER_SIZE); + + // Check whether full size is header + length. + if (ba_size != HEADER_SIZE + length) return std::nullopt; + // Prepare result + std::u8string value(length, u8'\0'); + // Read into result + std::memcpy(value.data(), ba.GetDataPtr(HEADER_SIZE), length); + + // Okey + return value; + } + + NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(u8"").value(); } + }; +} // namespace yycc::carton::binstore::serializer diff --git a/src/yycc/carton/binstore/types.cpp b/src/yycc/carton/binstore/types.cpp new file mode 100644 index 0000000..53e11ba --- /dev/null +++ b/src/yycc/carton/binstore/types.cpp @@ -0,0 +1,29 @@ +#include "types.hpp" + +namespace yycc::carton::binstore::types { + +#pragma region ByteArray Class + + ByteArray::ByteArray() : datas() {} + + ByteArray::~ByteArray() {} + + size_t ByteArray::GetDataSize() const { + return this->datas.size(); + } + + void ByteArray::ResizeData(size_t new_size) { + this->datas.resize(new_size); + } + + const void* ByteArray::GetDataPtr(size_t offset) const { + return this->datas.data() + offset; + } + + void* ByteArray::GetDataPtr(size_t offset) { + return this->datas.data() + offset; + } + +#pragma endregion + +} // namespace yycc::carton::binstore::types diff --git a/src/yycc/carton/binstore/types.hpp b/src/yycc/carton/binstore/types.hpp new file mode 100644 index 0000000..0b3f4d2 --- /dev/null +++ b/src/yycc/carton/binstore/types.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "../../macro/class_copy_move.hpp" +#include +#include +#include + +namespace yycc::carton::binstore::types { + + /// @brief All possible error kind occurs in this module. + enum class BinstoreError { + + }; + + /// @brief The result type used in this module. + template + using BinstoreResult = std::expected; + + /// @brief The raw data of setting. + class ByteArray { + public: + ByteArray(); + ~ByteArray(); + YYCC_DEFAULT_COPY_MOVE(ByteArray) + + public: + /** + * @brief Get the length of internal buffer. + * @remarks This is usually used when reading data. + * @return The length of internal buffer. + */ + size_t GetDataSize() const; + /** + * @brief Resize internal buffer to given size. + * @remarks This is usually used when writing data. + * @param[in] new_size The new size of internal buffer. + */ + void ResizeData(size_t new_size); + /** + * @brief Get data pointer to internal buffer for reading. + * @remarks This is usually used when reading data. + * @param[in] offset The offset in byte added to underlying pointer. + * @return The data pointer to internal buffer. + */ + const void* GetDataPtr(size_t offset = 0) const; + /** + * @brief Get data pointer to internal buffer for writing. + * @remarks This is usually used when writing data. + * @param[in] offset The offset in byte added to underlying pointer. + * @return The data pointer to internal buffer. + */ + void* GetDataPtr(size_t offset = 0); + + private: + std::vector datas; ///< The internal buffer. + }; + +} diff --git a/src/yycc/carton/clap.hpp b/src/yycc/carton/clap.hpp index 32f766e..925c2c2 100644 --- a/src/yycc/carton/clap.hpp +++ b/src/yycc/carton/clap.hpp @@ -1,5 +1,7 @@ #pragma once namespace yycc::carton::clap { - + + // TODO: Support multiple arguments for single option. + } diff --git a/src/yycc/carton/clap/validator.hpp b/src/yycc/carton/clap/validator.hpp index 8408b18..385dd98 100644 --- a/src/yycc/carton/clap/validator.hpp +++ b/src/yycc/carton/clap/validator.hpp @@ -16,6 +16,7 @@ namespace yycc::carton::clap::validator { * @details * A valid command line argument validator must have a type name or alias called "ReturnType" * indicating the return value of this validator. + * Please note that the type of this return value must can be placed into \c std::optional. * * And, it also should have an member function called "validate" * which receive const std::string_view& as its only argument,