diff --git a/asibfm700/CMakeLists.txt b/asibfm700/CMakeLists.txt index e9dc4b4..1890fe6 100644 --- a/asibfm700/CMakeLists.txt +++ b/asibfm700/CMakeLists.txt @@ -38,5 +38,6 @@ set(ASIBFM700_LIB_SRC asibfm700_common.h asibfm700_servocontroller.h asibfm700_s set(ASIBFM700_LIB asibfm700mount) add_library(${ASIBFM700_LIB} STATIC ${ASIBFM700_LIB_SRC} - asibfm700_mount.h asibfm700_mount.cpp) + asibfm700_mount.h asibfm700_mount.cpp + asibfm700_configfile.h) target_link_libraries(${ASIBFM700_LIB} PRIVATE mcc) diff --git a/asibfm700/asibfm700_configfile.h b/asibfm700/asibfm700_configfile.h new file mode 100644 index 0000000..5446646 --- /dev/null +++ b/asibfm700/asibfm700_configfile.h @@ -0,0 +1,121 @@ +#pragma once + +/**/ + +#include + +#include + +namespace asibfm700 +{ + + +// configuration record: +// keyword +// value +// conversion function (deserializer) +template +concept config_record_c = requires(T t) { + requires std::same_as; // keyword + t.value; // value + // method to convert from string to value + { t.cnv_func(std::declval(), std::declval()) } -> std::convertible_to; +}; + + +// table of records (std::tuple) +// +template +concept config_table_c = requires(T t) { [](std::tuple) {}(t); }; + + +template +class ConfigTable +{ +protected: + TabT _cfgTable; + + std::array> _keyHashes{}; + + bool keyExists(size_t hash) + { + for (auto& h : _keyHashes) { + if (h == hash) { + return true; + } + } + + return false; + } + +public: + static constexpr char COMMENT_SYMBOL = '#'; + static constexpr char KEY_VALUE_DELIM = '='; + static constexpr char VALUE_VALUE_DELIM = ','; + + ConfigTable(const TabT& init_cfg) : _cfgTable(init_cfg) + { + _keyHashes = [this](std::index_sequence) { + return std::array{mcc::utils::FNV1aHash(std::get(_cfgTable).key)...}; + }(std::make_index_sequence>()); + } + + virtual ~ConfigTable() = default; + + + std::error_code parse(std::ranges::contiguous_range auto const& buffer) + requires std::same_as>, char> + { + std::string_view sv, curr_buffer{buffer.begin(), buffer.end()}; + + do { + auto r = std::ranges::find(curr_buffer, '\n'); + + sv = mcc::utils::trimSpaces(std::string_view(curr_buffer.begin(), r), mcc::utils::TrimType::TRIM_LEFT); + + if (sv.size()) { + if (sv[0] == COMMENT_SYMBOL) { // comment string + continue; + } + + auto it = std::ranges::find(sv, KEY_VALUE_DELIM); + if (it == sv.begin()) { // empty key! skip! + continue; + } + + auto key = mcc::utils::trimSpaces(std::string_view{sv.begin(), it}, mcc::utils::TrimType::TRIM_RIGHT); + if (!keyExists(mcc::utils::FNV1aHash(key))) { + } + + } // only spaces + + curr_buffer = {++r, buffer.end()}; + } while (!curr_buffer.empty()); + + return {}; + } + + + template + bool value(mcc::traits::mcc_input_char_range auto const& key, T& val) + { + const auto* kptr = &key; + const auto* vptr = &val; + + return [kptr, vptr, this](std::index_sequence) { + return ([&kptr, vptr, this]() { + if constexpr (std::convertible_to(_cfgTable).value), T>) { + if (keyExists(mcc::utils::FNV1aHash(*kptr))) { + *vptr = std::get(_cfgTable).value; + return true; + } + } + + return false; + }() || ...); + }(std::make_index_sequence>()); + } +}; + + +} // namespace asibfm700