This commit is contained in:
Timur A. Fatkhullin 2025-09-29 19:02:04 +03:00
parent 98c46c2b8c
commit c5aa3dc495
2 changed files with 123 additions and 1 deletions

View File

@ -38,5 +38,6 @@ set(ASIBFM700_LIB_SRC asibfm700_common.h asibfm700_servocontroller.h asibfm700_s
set(ASIBFM700_LIB asibfm700mount) set(ASIBFM700_LIB asibfm700mount)
add_library(${ASIBFM700_LIB} STATIC ${ASIBFM700_LIB_SRC} 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) target_link_libraries(${ASIBFM700_LIB} PRIVATE mcc)

View File

@ -0,0 +1,121 @@
#pragma once
/**/
#include <unordered_map>
#include <mcc_utils.h>
namespace asibfm700
{
// configuration record:
// keyword
// value
// conversion function (deserializer)
template <typename T>
concept config_record_c = requires(T t) {
requires std::same_as<decltype(t.key), std::string_view>; // keyword
t.value; // value
// method to convert from string to value
{ t.cnv_func(std::declval<std::string_view>(), std::declval<decltype(t.value)&>()) } -> std::convertible_to<bool>;
};
// table of records (std::tuple<config_record_c...>)
//
template <typename T>
concept config_table_c = requires(T t) { []<config_record_c... Ts>(std::tuple<Ts...>) {}(t); };
template <config_table_c TabT>
class ConfigTable
{
protected:
TabT _cfgTable;
std::array<size_t, std::tuple_size_v<TabT>> _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]<size_t... Is>(std::index_sequence<Is...>) {
return std::array{mcc::utils::FNV1aHash(std::get<Is>(_cfgTable).key)...};
}(std::make_index_sequence<std::tuple_size_v<TabT>>());
}
virtual ~ConfigTable() = default;
std::error_code parse(std::ranges::contiguous_range auto const& buffer)
requires std::same_as<std::remove_cvref_t<std::ranges::range_value_t<decltype(buffer)>>, 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 <typename T>
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]<size_t... Is>(std::index_sequence<Is...>) {
return ([&kptr, vptr, this]() {
if constexpr (std::convertible_to<decltype(std::get<Is>(_cfgTable).value), T>) {
if (keyExists(mcc::utils::FNV1aHash(*kptr))) {
*vptr = std::get<Is>(_cfgTable).value;
return true;
}
}
return false;
}() || ...);
}(std::make_index_sequence<std::tuple_size_v<TabT>>());
}
};
} // namespace asibfm700