From 49734de1c4fe0ffaf4e0a9c89d1ea7bf546b5670 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 16 Jul 2026 19:10:32 +0300 Subject: [PATCH] ... --- examples/device_exam.cpp | 15 +++- include/adclib/adclib_device.h | 155 +++++++++++++++++++++++++++------ 2 files changed, 141 insertions(+), 29 deletions(-) diff --git a/examples/device_exam.cpp b/examples/device_exam.cpp index f4d2f62..36c4ed9 100644 --- a/examples/device_exam.cpp +++ b/examples/device_exam.cpp @@ -6,7 +6,7 @@ using namespace adc; int main() { - std::string id1 = "1", id2 = "2"; + std::string id1 = "1", id2 = "2", id3 = "str"; int i = 10; double d = 8.1; @@ -32,6 +32,19 @@ int main() std::println("add RO-attr with id='{}' (val={})", id2, d); dev.addAttr(id2, [&d]() -> adc_result_t { return d; }, nullptr); + std::println("add RW-attr with id='{}' (val={})", id3, s); + dev.addAttr( + id3, [&s]() -> adc_result_t { return s; }, + [&s](std::string const& sv) -> adc_error_t { + s = sv; + return {}; + }, + [&s](adc_result_t const&) -> adc_result_t { return s.c_str(); }, + [&s](adc_result_t const& p) -> adc_result_t { + s = p.value(); + return s; + }); + std::print("get '{}'-attr value as native int:\t", id1); adc_result_t ri = dev[id1]; if (ri) { diff --git a/include/adclib/adclib_device.h b/include/adclib/adclib_device.h index 61633bb..d208eab 100644 --- a/include/adclib/adclib_device.h +++ b/include/adclib/adclib_device.h @@ -119,10 +119,38 @@ concept adclib_attr_setter_c = // deduce value type from getter and setter template -using snplib_attr_value_deduced_t = - std::conditional_t, - std::conditional_t, void, snplib::snplib_func_arg1_t>, - typename std::invoke_result_t::value_type>; +using adclib_attr_value_deduced_t = std::conditional_t< + std::is_null_pointer_v, + std::conditional_t, void, std::remove_cvref_t>>, + typename std::invoke_result_t::value_type>; + + +template +struct adclib_is_deduced_void_t { + static constexpr bool value = std::is_void_v>; +}; + +// conversional function signature: +// "from": adc_result_t func(const adc_result_t&) +// "to": adc_result_t func(const adc_result_t&) +template +concept adclib_attr_conv_from_func_c = + std::same_as || + (std::invocable&> && !std::is_void_v&>>); + +template +concept adclib_attr_conv_to_func_c = std::same_as || + (snplib::snplib_callable_c && (snplib::snplib_func_traits_t::arity == 1) && + std::same_as, typename snplib::snplib_func_traits_t::ret_t>); + +template CONV_FROM_T, adclib_attr_conv_to_func_c CONV_TO_T> +using adclib_attr_user_deduced_t = + std::conditional_t, + std::conditional_t, + void, + std::remove_cvref_t>>, + typename snplib::snplib_func_traits_t::ret_t>; + template DEV_ID_T = std::string, @@ -136,31 +164,32 @@ protected: std::function()> getter{}; std::function setter{}; - template - requires(requires(VT v, UT u) { v = u; } && !std::same_as) - attr_t& operator=(attr_t const& other) - { - if (other.getter) { - getter = [&other]() -> adc_result_t { - auto val = other.getter(); - if (val) { - return static_cast(val.value()); - } + // template + // requires(requires(VT v, UT u) { v = u; } && !std::same_as) + // attr_t& operator=(attr_t const& other) + // { + // std::println("ATTR::operator="); + // if (other.getter) { + // getter = [&other]() -> adc_result_t { + // auto val = other.getter(); + // if (val) { + // return static_cast(val.value()); + // } - return std::unexpected(val.error()); - }; - } else { // write-only attribute - getter = nullptr; - } + // return std::unexpected(val.error()); + // }; + // } else { // write-only attribute + // getter = nullptr; + // } - if (other.setter) { - setter = [&other](VT const& v) { return other.setter(static_cast(v)); }; - } else { // read-only attribute - setter = nullptr; - } + // if (other.setter) { + // setter = [&other](VT const& v) { return other.setter(static_cast(v)); }; + // } else { // read-only attribute + // setter = nullptr; + // } - return *this; - } + // return *this; + // } template requires requires(VT v, UT u) { v = u; } @@ -315,7 +344,7 @@ public: template void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple = std::tuple<>{}) { - using v_t = snplib_attr_value_deduced_t; + using v_t = adclib_attr_value_deduced_t; static_assert(!std::is_void_v, "Getter and setter cannot be nullptr_t at the same time!"); if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { @@ -326,9 +355,79 @@ public: std::tuple...>{}); } + template + requires(sizeof...(FuncTs) > 1) + void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, FuncTs&&... cnv_pairs) + { + static constexpr size_t NFUNCS = sizeof...(FuncTs); + + static_assert(NFUNCS % 2 == 0, "Number of conversional functions must be an even!"); + + using v_t = adclib_attr_value_deduced_t; + static_assert(!std::is_void_v, "Getter and setter cannot be nullptr_t at the same time!"); + + auto from_cnv_func = [](adclib_attr_conv_from_func_c auto&& conv_from, + adclib_attr_conv_to_func_c auto&& conv_to) { + using u_t = adclib_attr_user_deduced_t; + + return [conv_from_cap = std::forward(conv_from), + conv_to_cap = + std::forward(conv_to)](attr_t const& attr) mutable -> attr_t { + return attr_t{.getter = [&attr, conv_from_cap_cap = std::forward( + conv_from_cap)]() mutable -> adc_result_t { + return conv_from_cap_cap(attr.getter()); + }, + .setter = [&attr, conv_to_cap_cap = std::forward( + conv_to_cap)](u_t const& uv) mutable -> adc_error_t { + auto val = conv_to_cap_cap(uv); + if (val) { + return attr.setter(val.value()); + } else { + return std::unexpected(val.error()); + } + }}; + }; + }; + + auto to_cnv_func = [id, this](adclib_attr_conv_from_func_c auto&& conv_from, + adclib_attr_conv_to_func_c auto&& conv_to) { + using u_t = adclib_attr_user_deduced_t; + + return [id, this](attr_t const&) -> attr_t { return _attrs.template get>(id); }; + }; + + std::apply([this](auto&&... args) { _attrs.pushWithCnv(std::forward(args)...); }, + std::tuple_cat(std::forward_as_tuple(id, getter, setter), + [... cnv_pairs_cap = std::forward(cnv_pairs), from_cnv_func, to_cnv_func, id, + this](std::index_sequence) mutable { + auto&& tp = std::forward_as_tuple(std::forward(cnv_pairs_cap)...); + + // static_assert( + // std::disjunction_v, + // std::tuple_element_t>...>, + // "Getter and setter cannot be nullptr_t at the same time!"); + + // return std::forward_as_tuple( + // [](attr_t const& av) + // -> adclib_attr_value_deduced_t, + // std::tuple_element_t> + // {}...); + + return std::forward_as_tuple( + from_cnv_func(std::get(tp), std::get(tp))..., + to_cnv_func(std::get(tp), std::get(tp))...); + // (from_cnv_func(std::get(tp), std::get(tp)), + // to_cnv_func(std::get(tp), std::get(tp)))...); + }(std::make_index_sequence{}))); + } + // add attribute of one of arithmetic type template - requires std::is_arithmetic_v> + requires std::is_arithmetic_v> void addArithAttr(ATTR_ID_T id, GT&& getter, ST&& setter) { addAttr(std::move(id), std::forward(getter), std::forward(setter), AdcGenericDevice::arithmetic_types);