#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