From f035796241b1620391d52f74911730f0449d89fd Mon Sep 17 00:00:00 2001 From: Alexej Doronin Date: Mon, 14 Oct 2024 12:15:32 +0200 Subject: [PATCH] Fix incorrect field names when mising :: and normal notations --- .gitignore | 5 +++++ include/describe/describe.hpp | 38 ++++++++++++++++++++--------------- test/attributes.cpp | 11 ---------- test/basic.cpp | 19 ++++++++++-------- test/templates.cpp | 10 ++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 259148f..4979708 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,8 @@ *.exe *.out *.app + +build/ +.vscode/ +.vs/ +*.user \ No newline at end of file diff --git a/include/describe/describe.hpp b/include/describe/describe.hpp index 388e2cb..b26d0ea 100644 --- a/include/describe/describe.hpp +++ b/include/describe/describe.hpp @@ -32,9 +32,11 @@ template constexpr size_t count() { return ((1 * (methods == T::is_method)) + ... + 0); } -constexpr std::string_view next_name(std::string_view& src) { + +inline constexpr std::string_view next_name(std::string_view& src) { auto resStart = src.find("::"); - resStart = resStart == std::string_view::npos ? src.find_first_not_of(" ") : resStart + 2; + auto noColons = resStart == std::string_view::npos || src.find_first_of(',') < resStart; + resStart = noColons ? src.find_first_not_of(' ') : resStart + 2; auto resEnd = src.find_first_of(" \t\n\r,", resStart); auto result = src.substr(resStart, resEnd - resStart); src = src.substr(src.find_first_of(',', resEnd) + 1); @@ -54,7 +56,7 @@ auto get_attr(Attrs) { if constexpr (std::is_base_of_v) { return Tag{}; } else { - return get_attr(Attrs{}); + return detail::get_attr(Attrs{}); } } @@ -68,13 +70,17 @@ template struct pack_idx : pack_idx struct pack_idx<0, Head, Ts...> {using type = Head;}; } //detail -template struct Field { +template +struct Field +{ static_assert(std::is_member_pointer_v || std::is_enum_v, - "Field can only be used with &_::members or enums"); + "Field can only be used with &_::members or enums"); std::string_view name; static constexpr auto value = field; using type = typename decltype(detail::get_memptr_type(field))::type; static constexpr auto is_method = std::is_member_function_pointer_v; + static constexpr auto is_function = std::is_function_v; + static constexpr auto is_plain = std::is_member_object_pointer_v; static constexpr auto is_enum = std::is_enum_v; using cls = typename decltype(detail::get_memptr_class(field))::type; template static constexpr auto&& get(T&& obj) noexcept { @@ -110,16 +116,16 @@ struct Description : protected Fields... template constexpr void for_each(F&& f) const { (static_cast(f(static_cast(*this))), ...); } - template static constexpr size_t index_of(Field) { + template static constexpr size_t index_of(Field) noexcept { size_t result = npos; size_t count = size_t(-1); ((count++, std::is_same_v, Fields> && (result = count)), ...); return result; } - template static constexpr size_t index_of() { + template static constexpr size_t index_of() noexcept { return index_of(Field{}); } - constexpr size_t index_of(std::string_view name) const { + constexpr size_t index_of(std::string_view name) const noexcept { size_t result = npos; size_t count = size_t(-1); ((count++, (static_cast(*this).name == name) && (result = count)), ...); @@ -180,8 +186,8 @@ struct is_described : std::false_type {}; template struct is_described{})) ->>: std::true_type {}; + std::void_t{})) + >>: std::true_type {}; template constexpr auto is_described_v = is_described::value; @@ -230,28 +236,28 @@ friend constexpr auto GetDescription(::describe::Tag); #define DESCRIBE(cls, ...) \ inline constexpr auto GetDescription(::describe::Tag) { using _ [[maybe_unused]] = cls; \ -return _D_DESCRIBE(cls, __VA_ARGS__)(#cls, #__VA_ARGS__);} + return _D_DESCRIBE(cls, __VA_ARGS__)(#cls, #__VA_ARGS__);} #define DESCRIBE_INHERIT(cls, parent, ...) \ inline constexpr auto GetDescription(::describe::Tag) { using _ = cls; \ -return _D_DESCRIBE(cls, __VA_ARGS__)(::describe::Get(), #cls, #__VA_ARGS__);} + return _D_DESCRIBE(cls, __VA_ARGS__)(::describe::Get(), #cls, #__VA_ARGS__);} #define DESCRIBE_TEMPL_CLASS(...) \ inline constexpr auto GetDescription(::describe::Tag<__VA_ARGS__>) { \ -using _ = __VA_ARGS__; constexpr std::string_view _clsName = #__VA_ARGS__; + using _ = __VA_ARGS__; constexpr std::string_view _clsName = #__VA_ARGS__; #define DESCRIBE_TEMPL_FIELDS(...) \ -return _D_DESCRIBE(_, __VA_ARGS__)(_clsName, #__VA_ARGS__); } + return _D_DESCRIBE(_, __VA_ARGS__)(_clsName, #__VA_ARGS__); } //! @achtung @warning THESE Should always be the same for all Translation Units #define DESCRIBE_ATTRS(cls, ...) \ inline constexpr auto GetAttrs(::describe::Tag) { \ -return ::describe::Attrs<__VA_ARGS__>{};} + return ::describe::Attrs<__VA_ARGS__>{};} //! @achtung @warning THESE Should always be the same for all Translation Units #define DESCRIBE_FIELD_ATTRS(cls, field, ...) \ inline constexpr auto GetAttrs(::describe::Tag, ::describe::Field<&cls::field>) { \ -return ::describe::Attrs<__VA_ARGS__>{}; } + return ::describe::Attrs<__VA_ARGS__>{}; } // Utils template diff --git a/test/attributes.cpp b/test/attributes.cpp index 31cd988..e5a1739 100644 --- a/test/attributes.cpp +++ b/test/attributes.cpp @@ -33,15 +33,4 @@ static_assert(std::is_same_v>); using all = describe::get_attrs_t; static_assert(std::is_same_v>>); -// Fields inherit attributes from class -constexpr auto a = describe::Get().get<0>(); -using all_a = describe::get_attrs_t; -static_assert(std::is_same_v); - -// Unless specified for field individually -struct custom {}; - -constexpr auto b = describe::Get().get<0>(); -using all_b = describe::get_attrs_t; -static_assert(std::is_same_v); diff --git a/test/basic.cpp b/test/basic.cpp index 751278c..7a86911 100644 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -9,7 +9,8 @@ struct Data { } }; -DESCRIBE(Data, &_::a, &_::b, &_::method) +constexpr auto r = &Data::a; //rename field +DESCRIBE(Data, r, &_::b, &_::method) constexpr auto desc = describe::Get(); static_assert(desc.all_count == 3); @@ -17,13 +18,11 @@ static_assert(desc.fields_count == 2); static_assert(desc.methods_count == 1); void print_fields(const Data& d) { + std::cout << desc.name << ": "; desc.for_each_field([&](auto f) { - std::cout << f.name << ": " << f.get(d) << ", "; + std::cout << f.name << " -> " << f.get(d) << ", "; }); -} - -void test_print() { - print_fields(Data{1, 2}); // -> a: 1, b: 2, + std::cout << std::endl; } enum Enum {foo, bar, baz,}; @@ -34,14 +33,18 @@ DESCRIBE(ClEnum, _::bim, _::bam, _::bom) // enum classes are supported template void print_enum() { - describe::Get().for_each_field([&](auto f) { + constexpr auto desc = describe::Get(); + std::cout << desc.name << ": "; + desc.for_each_field([&](auto f) { using underlying = std::underlying_type_t; - std::cout << f.name << ": " << underlying(f.value) << ", "; + std::cout << f.name << " -> " << underlying(f.value) << ", "; }); + std::cout << std::endl; } int main(int argc, char *argv[]) { + print_fields(Data{1, 2}); // -> a: 1, b: 2, print_enum(); //-> foo: 0, bar: 1, baz: 2 print_enum(); //-> bim: 0, bam: 1, bom: 2 } diff --git a/test/templates.cpp b/test/templates.cpp index 7fc2f61..ffbc380 100644 --- a/test/templates.cpp +++ b/test/templates.cpp @@ -15,9 +15,8 @@ DESCRIBE(test::Data, &_::a, &_::b) } constexpr auto desc = describe::Get>(); -static_assert(desc.name == "Data"); -static_assert(desc.ns == "test"); -constexpr auto B = desc.get<1>(); +static_assert(desc.name == "test::Data"); +constexpr auto B = describe::by_index<1>(desc); static_assert(std::is_same_v); @@ -28,10 +27,9 @@ template struct sum { // DESCRIBE_CLASS(...) DESCRIBE_FIELDS(...) pair for multi-param templates template -DESCRIBE_CLASS(sum) -DESCRIBE_FIELDS(&_::as_int) +DESCRIBE_TEMPL_CLASS(sum) +DESCRIBE_TEMPL_FIELDS(&_::as_int) constexpr auto sum_desc = describe::Get>(); static_assert(sum_desc.name == "sum"); -static_assert(sum_desc.ns == "");