| 1 | //! @file reflection.hpp |
| 2 | //! @author ryftchen |
| 3 | //! @brief The declarations (reflection) in the utility module. |
| 4 | //! @version 0.1.0 |
| 5 | //! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved. |
| 6 | |
| 7 | #pragma once |
| 8 | |
| 9 | #include <string_view> |
| 10 | #include <tuple> |
| 11 | |
| 12 | //! @brief Convert target string for reflection. |
| 13 | #define REFLECTION_STR(str) \ |
| 14 | ( \ |
| 15 | []() consteval \ |
| 16 | { \ |
| 17 | constexpr std::basic_string_view refl = str; \ |
| 18 | return utility::reflection::Reflect::String< \ |
| 19 | utility::reflection::Reflect::ReflStr<typename decltype(refl)::value_type, refl.size()>{refl}>{}; \ |
| 20 | }()) |
| 21 | |
| 22 | //! @brief The utility module. |
| 23 | namespace utility // NOLINT(modernize-concat-nested-namespaces) |
| 24 | { |
| 25 | //! @brief Static-reflection-related functions in the utility module. |
| 26 | namespace reflection |
| 27 | { |
| 28 | //! @brief Brief function description. |
| 29 | //! @return function description (module_function) |
| 30 | inline static const char* description() noexcept |
| 31 | { |
| 32 | return "UTIL_REFLECTION" ; |
| 33 | } |
| 34 | extern const char* version() noexcept; |
| 35 | |
| 36 | //! @brief Reflection. |
| 37 | class Reflect |
| 38 | { |
| 39 | public: |
| 40 | //! @brief Custom string type wrapper. |
| 41 | //! @tparam Char - type of character in string |
| 42 | //! @tparam Size - string size |
| 43 | template <typename Char, std::size_t Size> |
| 44 | class ReflStr |
| 45 | { |
| 46 | public: |
| 47 | //! @brief Alias for the value type. |
| 48 | using ValueType = Char; |
| 49 | //! @brief Construct a new ReflStr object. |
| 50 | //! @param str - target string |
| 51 | consteval explicit ReflStr(const std::basic_string_view<ValueType> str) |
| 52 | { |
| 53 | for (std::size_t i = 0; i < size; ++i) |
| 54 | { |
| 55 | data[i] = str[i]; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | //! @brief String data. |
| 60 | ValueType data[Size + 1]{}; |
| 61 | //! @brief String size. |
| 62 | static constexpr std::size_t size{Size}; |
| 63 | }; |
| 64 | |
| 65 | //! @brief Custom string. |
| 66 | //! @tparam Str - custom string with wrapper |
| 67 | template <ReflStr Str> |
| 68 | class String |
| 69 | { |
| 70 | public: |
| 71 | //! @brief Alias for the character. |
| 72 | using Char = typename decltype(Str)::ValueType; |
| 73 | //! @brief Check whether it is the custom string type. |
| 74 | //! @tparam Chars - type of target string |
| 75 | //! @return be custom string type or not |
| 76 | template <typename Chars> |
| 77 | static consteval bool is(const Chars& /*str*/ = {}) |
| 78 | { |
| 79 | return std::is_same_v<Chars, String>; |
| 80 | } |
| 81 | //! @brief Get the string data. |
| 82 | //! @return string data |
| 83 | static consteval auto data() { return Str.data; } |
| 84 | //! @brief Get the string size. |
| 85 | //! @return string size |
| 86 | static consteval auto size() { return Str.size; } |
| 87 | //! @brief Get the string for view only. |
| 88 | //! @return string data for view only |
| 89 | static consteval std::basic_string_view<Char> view() { return Str.data; } |
| 90 | }; |
| 91 | |
| 92 | //! @brief Finding by condition. |
| 93 | //! @tparam Lit - type of string literal |
| 94 | //! @tparam Func - type of callable function |
| 95 | //! @param lit - string literal |
| 96 | //! @param func - callable function |
| 97 | //! @param seq - sequences related to arguments |
| 98 | //! @return value index |
| 99 | template <typename Lit, typename Func> |
| 100 | static constexpr std::size_t findIf(const Lit& lit, Func&& func, const std::index_sequence<>& seq); |
| 101 | //! @brief Finding by condition. |
| 102 | //! @tparam Lit - type of string literal |
| 103 | //! @tparam Func - type of callable function |
| 104 | //! @tparam I0 - current index of elements |
| 105 | //! @tparam Is - indices of sequence related to elements |
| 106 | //! @param lit - string literal |
| 107 | //! @param func - callable function |
| 108 | //! @param seq - sequence related to elements |
| 109 | //! @return value index |
| 110 | template <typename Lit, typename Func, std::size_t I0, std::size_t... Is> |
| 111 | static constexpr std::size_t findIf(const Lit& lit, Func&& func, const std::index_sequence<I0, Is...>& seq); |
| 112 | //! @brief Calculate accumulation. |
| 113 | //! @tparam Lit - type of string literal |
| 114 | //! @tparam Func - type of callable function |
| 115 | //! @tparam Ret - type of return value |
| 116 | //! @param lit - string literal |
| 117 | //! @param func - callable function |
| 118 | //! @param ret - return value |
| 119 | //! @param seq - sequences related to arguments |
| 120 | //! @return result of accumulation |
| 121 | template <typename Lit, typename Func, typename Ret> |
| 122 | static constexpr auto acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<>& seq); |
| 123 | //! @brief Calculate accumulation. |
| 124 | //! @tparam Lit - type of string literal |
| 125 | //! @tparam Func - type of callable function |
| 126 | //! @tparam Ret - type of return value |
| 127 | //! @tparam I0 - current index of elements |
| 128 | //! @tparam Is - indices of sequence related to elements |
| 129 | //! @param lit - string literal |
| 130 | //! @param func - callable function |
| 131 | //! @param ret - return value |
| 132 | //! @param seq - sequence related to elements |
| 133 | //! @return result of accumulation |
| 134 | template <typename Lit, typename Func, typename Ret, std::size_t I0, std::size_t... Is> |
| 135 | static constexpr auto acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<I0, Is...>& seq); |
| 136 | //! @brief Calculate accumulation by the DFS algorithm. |
| 137 | //! @tparam Depth - degree of depth |
| 138 | //! @tparam Info - type of type information |
| 139 | //! @tparam Ret - type of return value |
| 140 | //! @tparam Func - type of callable function |
| 141 | //! @param info - type information |
| 142 | //! @param func - callable function |
| 143 | //! @param ret - return value |
| 144 | //! @return result of the accumulation |
| 145 | template <std::size_t Depth, typename Info, typename Ret, typename Func> |
| 146 | static constexpr auto dfsAcc(const Info& info, Func&& func, Ret ret); |
| 147 | //! @brief Traverse the variable of node v in the DFS algorithm. |
| 148 | //! @tparam Info - type of type information |
| 149 | //! @tparam Obj - type of object to be traversed |
| 150 | //! @tparam Func - type of callable function |
| 151 | //! @param info - type information |
| 152 | //! @param obj - object to be traversed |
| 153 | //! @param func - callable function |
| 154 | template <typename Info, typename Obj, typename Func> |
| 155 | static constexpr void varInNodeV(const Info& info, Obj&& obj, Func&& func); |
| 156 | }; |
| 157 | |
| 158 | template <typename Lit, typename Func> |
| 159 | constexpr std::size_t Reflect::findIf(const Lit& /*lit*/, Func&& /*func*/, const std::index_sequence<>& /*seq*/) |
| 160 | { |
| 161 | return -1; |
| 162 | } |
| 163 | |
| 164 | template <typename Lit, typename Func, std::size_t I0, std::size_t... Is> |
| 165 | constexpr std::size_t Reflect::findIf(const Lit& lit, Func&& func, const std::index_sequence<I0, Is...>& /*seq*/) |
| 166 | { |
| 167 | return func(lit.template get<I0>()) ? I0 : findIf(lit, std::forward<Func>(func), std::index_sequence<Is...>{}); |
| 168 | } |
| 169 | |
| 170 | template <typename Lit, typename Func, typename Ret> |
| 171 | constexpr auto Reflect::acc(const Lit& /*lit*/, Func&& /*func*/, Ret ret, const std::index_sequence<>& /*seq*/) |
| 172 | { |
| 173 | return ret; |
| 174 | } |
| 175 | |
| 176 | template <typename Lit, typename Func, typename Ret, std::size_t I0, std::size_t... Is> |
| 177 | constexpr auto Reflect::acc(const Lit& lit, Func&& func, Ret ret, const std::index_sequence<I0, Is...>& /*seq*/) |
| 178 | { |
| 179 | return acc( |
| 180 | lit, std::forward<Func>(func), func(std::move(ret), lit.template get<I0>()), std::index_sequence<Is...>{}); |
| 181 | } |
| 182 | |
| 183 | template <std::size_t Depth, typename Info, typename Ret, typename Func> |
| 184 | constexpr auto Reflect::dfsAcc(const Info& info, Func&& func, Ret ret) |
| 185 | { |
| 186 | return info.bases.accumulate( |
| 187 | std::move(ret), |
| 188 | [&](const auto ret, const auto base) |
| 189 | { |
| 190 | if constexpr (base.isVirtual) |
| 191 | { |
| 192 | return dfsAcc<Depth + 1>(base.info, std::forward<Func>(func), ret); |
| 193 | } |
| 194 | else |
| 195 | { |
| 196 | return dfsAcc<Depth + 1>( |
| 197 | base.info, std::forward<Func>(func), std::forward<Func>(func)(ret, base.info, Depth + 1)); |
| 198 | } |
| 199 | }); |
| 200 | } |
| 201 | |
| 202 | template <typename Info, typename Obj, typename Func> |
| 203 | constexpr void Reflect::varInNodeV(const Info& /*info*/, Obj&& obj, Func&& func) |
| 204 | { |
| 205 | Info::fields.forEach( |
| 206 | [&](const auto fld) |
| 207 | { |
| 208 | using Fld = std::decay_t<decltype(fld)>; |
| 209 | if constexpr (!Fld::isStatic && !Fld::isFunction) |
| 210 | { |
| 211 | std::forward<Func>(func)(fld, std::forward<Obj>(obj).*(fld.value)); |
| 212 | } |
| 213 | }); |
| 214 | Info::bases.forEach( |
| 215 | [&](const auto base) |
| 216 | { |
| 217 | if constexpr (!base.isVirtual) |
| 218 | { |
| 219 | varInNodeV(base.info, base.info.forward(std::forward<Obj>(obj)), std::forward<Func>(func)); |
| 220 | } |
| 221 | }); |
| 222 | } |
| 223 | |
| 224 | //! @brief Base class of named value. |
| 225 | //! @tparam Name - type of name |
| 226 | template <typename Name> |
| 227 | struct NamedValueBase |
| 228 | { |
| 229 | //! @brief Alias for the name type. |
| 230 | using NameType = Name; |
| 231 | //! @brief Value name. |
| 232 | static constexpr std::string_view name{NameType::view()}; |
| 233 | }; |
| 234 | |
| 235 | //! @brief Specialization for named value. |
| 236 | //! @tparam Name - type of name |
| 237 | //! @tparam Value - type of target value |
| 238 | template <typename Name, typename Value> |
| 239 | struct NamedValue : public NamedValueBase<Name> |
| 240 | { |
| 241 | //! @brief Construct a new NamedValue object. |
| 242 | //! @param val - target value |
| 243 | constexpr explicit NamedValue(const Value val) : value{val} {} |
| 244 | |
| 245 | //! @brief The operator (==) overloading of NamedValue struct. |
| 246 | //! @tparam RHS - type of right-hand side |
| 247 | //! @param rhs - right-hand side |
| 248 | //! @return be equal or not |
| 249 | template <typename RHS> |
| 250 | constexpr bool operator==(const RHS& rhs) const |
| 251 | { |
| 252 | if constexpr (std::is_same_v<Value, RHS>) |
| 253 | { |
| 254 | return value == rhs; |
| 255 | } |
| 256 | else |
| 257 | { |
| 258 | return false; |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | //! @brief Named value. |
| 263 | Value value{}; |
| 264 | //! @brief Flag to indicate whether it has a value. |
| 265 | static constexpr bool hasValue{true}; |
| 266 | }; |
| 267 | |
| 268 | //! @brief Specialization for named value. |
| 269 | //! @tparam Name - type of name |
| 270 | template <typename Name> |
| 271 | struct NamedValue<Name, void> : public NamedValueBase<Name> |
| 272 | { |
| 273 | //! @brief The operator (==) overloading of NamedValue struct. |
| 274 | //! @tparam RHS - type of right-hand side |
| 275 | //! @return be equal or not |
| 276 | template <typename RHS> |
| 277 | constexpr bool operator==(const RHS& /*rhs*/) const |
| 278 | { |
| 279 | return false; |
| 280 | } |
| 281 | |
| 282 | //! @brief Flag to indicate whether it has a value. |
| 283 | static constexpr bool hasValue{false}; |
| 284 | }; |
| 285 | |
| 286 | //! @brief The list of elements. |
| 287 | //! @tparam Es - type of list of elements |
| 288 | template <typename... Es> |
| 289 | class Elements |
| 290 | { |
| 291 | public: |
| 292 | //! @brief Construct a new Elements object. |
| 293 | //! @param es - list of elements |
| 294 | constexpr explicit Elements(const Es... es) : elems{es...} {} |
| 295 | |
| 296 | //! @brief Size of list of the elements. |
| 297 | static constexpr std::size_t size{sizeof...(Es)}; |
| 298 | //! @brief Accumulating. |
| 299 | //! @tparam Init - type of initial accumulation |
| 300 | //! @tparam Func - type of callable function |
| 301 | //! @param init - initial accumulation |
| 302 | //! @param func - callable function |
| 303 | //! @return result of accumulation |
| 304 | template <typename Init, typename Func> |
| 305 | constexpr auto accumulate(Init init, Func&& func) const; |
| 306 | //! @brief Iteration. |
| 307 | //! @tparam Func - type of callable function |
| 308 | //! @param func - callable function |
| 309 | template <typename Func> |
| 310 | constexpr void forEach(Func&& func) const; |
| 311 | //! @brief Check whether it contains the custom string. |
| 312 | //! @tparam Str - type of custom string |
| 313 | //! @param name - value name |
| 314 | //! @return contains or not |
| 315 | template <typename Str> |
| 316 | static constexpr bool contains(const Str& name = {}); |
| 317 | //! @brief Finding by condition. |
| 318 | //! @tparam Func - type of callable function |
| 319 | //! @param func - callable function |
| 320 | //! @return value index |
| 321 | template <typename Func> |
| 322 | constexpr std::size_t findIf(Func&& func) const; |
| 323 | //! @brief Finding. |
| 324 | //! @tparam Str - type of custom string |
| 325 | //! @param name - value name |
| 326 | //! @return value index |
| 327 | template <typename Str> |
| 328 | constexpr const auto& find(const Str& name = {}) const; |
| 329 | //! @brief Finding by value. |
| 330 | //! @tparam Value - type of target value |
| 331 | //! @param val - target value |
| 332 | //! @return value index |
| 333 | template <typename Value> |
| 334 | constexpr std::size_t findValue(const Value& val) const; |
| 335 | //! @brief Get the pointer of value by name. |
| 336 | //! @tparam Value - type of value |
| 337 | //! @tparam Str - type of custom string |
| 338 | //! @param name - value name |
| 339 | //! @return pointer of value |
| 340 | template <typename Value, typename Str> |
| 341 | constexpr const Value* valuePtrOfName(const Str& name) const; |
| 342 | //! @brief Get the reference of value by name. |
| 343 | //! @tparam Value - type of value |
| 344 | //! @tparam Str - type of custom string |
| 345 | //! @param name - value name |
| 346 | //! @return reference of value |
| 347 | template <typename Value, typename Str> |
| 348 | constexpr const Value& valueOfName(const Str& name) const; |
| 349 | //! @brief Get the name by value. |
| 350 | //! @tparam Value - type of target value |
| 351 | //! @tparam Char - type of character in custom string |
| 352 | //! @param val - target value |
| 353 | //! @return value name |
| 354 | template <typename Value, typename Char = char> |
| 355 | constexpr auto nameOfValue(const Value& val) const; |
| 356 | //! @brief Push operation of the element. |
| 357 | //! @tparam Elem - type of target element |
| 358 | //! @param elem - target element |
| 359 | //! @return position after pushing |
| 360 | template <typename Elem> |
| 361 | constexpr auto push(const Elem& elem) const; |
| 362 | //! @brief Insert operation of the element. |
| 363 | //! @tparam Elem - type of target element |
| 364 | //! @param elem - target element |
| 365 | //! @return position after inserting |
| 366 | template <typename Elem> |
| 367 | constexpr auto insert(const Elem& elem) const; |
| 368 | //! @brief Get the value. |
| 369 | //! @tparam Idx - value index |
| 370 | //! @return target value |
| 371 | template <std::size_t Idx> |
| 372 | constexpr const auto& get() const; |
| 373 | |
| 374 | private: |
| 375 | //! @brief Element list. |
| 376 | const std::tuple<Es...> elems{}; |
| 377 | }; |
| 378 | |
| 379 | template <typename... Es> |
| 380 | template <typename Init, typename Func> |
| 381 | constexpr auto Elements<Es...>::accumulate(Init init, Func&& func) const |
| 382 | { |
| 383 | return Reflect::acc(*this, std::forward<Func>(func), std::move(init), std::make_index_sequence<size>{}); |
| 384 | } |
| 385 | |
| 386 | template <typename... Es> |
| 387 | template <typename Func> |
| 388 | constexpr void Elements<Es...>::forEach(Func&& func) const |
| 389 | { |
| 390 | accumulate( |
| 391 | 0, |
| 392 | [&](const auto /*func*/, const auto fld) |
| 393 | { |
| 394 | std::forward<Func>(func)(fld); |
| 395 | return 0; |
| 396 | }); |
| 397 | } |
| 398 | |
| 399 | template <typename... Es> |
| 400 | template <typename Str> |
| 401 | constexpr bool Elements<Es...>::contains(const Str& /*name*/) |
| 402 | { |
| 403 | return (Es::NameType::template is<Str>() || ...); |
| 404 | } |
| 405 | |
| 406 | template <typename... Es> |
| 407 | template <typename Func> |
| 408 | constexpr std::size_t Elements<Es...>::findIf(Func&& func) const |
| 409 | { |
| 410 | return Reflect::findIf(*this, std::forward<Func>(func), std::make_index_sequence<size>{}); |
| 411 | } |
| 412 | |
| 413 | template <typename... Es> |
| 414 | template <typename Str> |
| 415 | constexpr const auto& Elements<Es...>::find(const Str& /*name*/) const |
| 416 | { |
| 417 | constexpr std::size_t index = []() constexpr |
| 418 | { |
| 419 | constexpr decltype(Str::view()) names[]{Es::name...}; |
| 420 | for (std::size_t i = 0; i < size; ++i) |
| 421 | { |
| 422 | if (Str::view() == names[i]) |
| 423 | { |
| 424 | return i; |
| 425 | } |
| 426 | } |
| 427 | return static_cast<std::size_t>(-1); |
| 428 | }(); |
| 429 | return get<index>(); |
| 430 | } |
| 431 | |
| 432 | template <typename... Es> |
| 433 | template <typename Value> |
| 434 | constexpr std::size_t Elements<Es...>::findValue(const Value& val) const |
| 435 | { |
| 436 | return findIf([&val](const auto& elem) { return elem == val; }); |
| 437 | } |
| 438 | |
| 439 | template <typename... Es> |
| 440 | template <typename Value, typename Str> |
| 441 | constexpr const Value* Elements<Es...>::valuePtrOfName(const Str& name) const |
| 442 | { |
| 443 | return accumulate( |
| 444 | nullptr, |
| 445 | [&name](const auto ret, const auto& elem) |
| 446 | { |
| 447 | if constexpr (std::is_same_v<Value, decltype(elem.value)>) |
| 448 | { |
| 449 | return (elem.name == name) ? &elem.value : ret; |
| 450 | } |
| 451 | else |
| 452 | { |
| 453 | return ret; |
| 454 | } |
| 455 | }); |
| 456 | } |
| 457 | |
| 458 | template <typename... Es> |
| 459 | template <typename Value, typename Str> |
| 460 | constexpr const Value& Elements<Es...>::valueOfName(const Str& name) const |
| 461 | { |
| 462 | return *valuePtrOfName<Value>(name); |
| 463 | } |
| 464 | |
| 465 | template <typename... Es> |
| 466 | template <typename Value, typename Char> |
| 467 | constexpr auto Elements<Es...>::nameOfValue(const Value& val) const |
| 468 | { |
| 469 | return accumulate( |
| 470 | std::basic_string_view<Char>{}, |
| 471 | [&val](const auto ret, const auto& elem) { return (elem == val) ? elem.name : ret; }); |
| 472 | } |
| 473 | |
| 474 | template <typename... Es> |
| 475 | template <typename Elem> |
| 476 | constexpr auto Elements<Es...>::push(const Elem& elem) const |
| 477 | { |
| 478 | return std::apply([&elem](const auto&... es) { return Elements<Es..., Elem>{es..., elem}; }, elems); |
| 479 | } |
| 480 | |
| 481 | template <typename... Es> |
| 482 | template <typename Elem> |
| 483 | constexpr auto Elements<Es...>::insert(const Elem& elem) const |
| 484 | { |
| 485 | if constexpr ((std::is_same_v<Es, Elem> || ...)) |
| 486 | { |
| 487 | return *this; |
| 488 | } |
| 489 | else |
| 490 | { |
| 491 | return push(elem); |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | template <typename... Es> |
| 496 | template <std::size_t Idx> |
| 497 | constexpr const auto& Elements<Es...>::get() const |
| 498 | { |
| 499 | return std::get<Idx>(elems); |
| 500 | } |
| 501 | |
| 502 | //! @brief Attribute in class. |
| 503 | //! @tparam Name - type of name |
| 504 | //! @tparam Value - type of target value |
| 505 | template <typename Name, typename Value> |
| 506 | struct Attr : public NamedValue<Name, Value> |
| 507 | { |
| 508 | //! @brief Construct a new Attr object. |
| 509 | //! @param val - target value |
| 510 | constexpr Attr(const Name /*name*/, const Value val) : NamedValue<Name, Value>{val} {} |
| 511 | }; |
| 512 | |
| 513 | //! @brief Attribute in class. |
| 514 | //! @tparam Name - type of name |
| 515 | template <typename Name> |
| 516 | struct Attr<Name, void> : public NamedValue<Name, void> |
| 517 | { |
| 518 | //! @brief Construct a new Attr object. |
| 519 | constexpr explicit Attr(const Name /*name*/) {} |
| 520 | }; |
| 521 | |
| 522 | //! @brief The list of attributes. |
| 523 | //! @tparam As - type of list of attributes |
| 524 | template <typename... As> |
| 525 | struct AttrList : public Elements<As...> |
| 526 | { |
| 527 | //! @brief Construct a new AttrList object. |
| 528 | //! @param as - list of attributes |
| 529 | constexpr explicit AttrList(const As... as) : Elements<As...>{as...} {} |
| 530 | }; |
| 531 | |
| 532 | //! @brief Base class of trait. |
| 533 | //! @tparam IsStat - whether it is static |
| 534 | //! @tparam IsFunc - whether it is a function |
| 535 | template <bool IsStat, bool IsFunc> |
| 536 | struct TraitBase |
| 537 | { |
| 538 | //! @brief Flag to indicate whether it is static. |
| 539 | static constexpr bool isStatic{IsStat}; |
| 540 | //! @brief Flag to indicate whether it is a function. |
| 541 | static constexpr bool isFunction{IsFunc}; |
| 542 | }; |
| 543 | |
| 544 | //! @brief Specialization for trait. |
| 545 | //! @tparam Value - type of target value |
| 546 | template <typename Value> |
| 547 | struct Trait : public TraitBase<true, false> |
| 548 | { |
| 549 | }; |
| 550 | |
| 551 | //! @brief Specialization for trait. |
| 552 | //! @tparam Obj - type of target object |
| 553 | //! @tparam Value - type of target value |
| 554 | template <typename Obj, typename Value> |
| 555 | struct Trait<Value Obj::*> : public TraitBase<false, std::is_function_v<Value>> |
| 556 | { |
| 557 | }; |
| 558 | |
| 559 | //! @brief Specialization for trait. |
| 560 | //! @tparam Value - type of target value |
| 561 | template <typename Value> |
| 562 | struct Trait<Value*> : public TraitBase<true, std::is_function_v<Value>> |
| 563 | { |
| 564 | }; |
| 565 | |
| 566 | //! @brief Field in class. |
| 567 | //! @tparam Name - type of name |
| 568 | //! @tparam Value - type of target value |
| 569 | //! @tparam Attrs - type of list of attributes |
| 570 | template <typename Name, typename Value, typename Attrs> |
| 571 | struct Field : public Trait<Value>, public NamedValue<Name, Value> |
| 572 | { |
| 573 | //! @brief Construct a new Field object. |
| 574 | //! @param val - target value |
| 575 | //! @param as - list of attributes |
| 576 | constexpr Field(const Name /*name*/, const Value val, const Attrs as = {}) : NamedValue<Name, Value>{val}, attrs{as} |
| 577 | { |
| 578 | } |
| 579 | |
| 580 | //! @brief Attribute list. |
| 581 | const Attrs attrs{}; |
| 582 | }; |
| 583 | |
| 584 | //! @brief The list of fields. |
| 585 | //! @tparam Fs - type of list of fields |
| 586 | template <typename... Fs> |
| 587 | struct FieldList : public Elements<Fs...> |
| 588 | { |
| 589 | //! @brief Construct a new FieldList object. |
| 590 | //! @param fs - list of fields |
| 591 | constexpr explicit FieldList(const Fs... fs) : Elements<Fs...>{fs...} {} |
| 592 | }; |
| 593 | |
| 594 | //! @brief Type information. |
| 595 | //! @tparam UDT - type of user defined data |
| 596 | template <typename UDT> |
| 597 | struct TypeInfo; |
| 598 | |
| 599 | //! @brief Public base class. |
| 600 | //! @tparam UDT - type of user defined data |
| 601 | //! @tparam IsVirtual - whether it is virtual base class |
| 602 | template <typename UDT, bool IsVirtual = false> |
| 603 | struct Base |
| 604 | { |
| 605 | //! @brief Type information. |
| 606 | static constexpr auto info{TypeInfo<UDT>{}}; |
| 607 | //! @brief Flag to indicate whether it is virtual base class. |
| 608 | static constexpr bool isVirtual{IsVirtual}; |
| 609 | }; |
| 610 | |
| 611 | //! @brief The list of public base classes. |
| 612 | //! @tparam Bs - type of list of public base classes |
| 613 | template <typename... Bs> |
| 614 | struct BaseList : public Elements<Bs...> |
| 615 | { |
| 616 | //! @brief Construct a new BaseList object. |
| 617 | //! @param bs - list of public base classes |
| 618 | constexpr explicit BaseList(const Bs... bs) : Elements<Bs...>{bs...} {} |
| 619 | }; |
| 620 | |
| 621 | //! @brief The list of type informations. |
| 622 | //! @tparam Ts - type of list of type informations |
| 623 | template <typename... Ts> |
| 624 | struct TypeInfoList : public Elements<Ts...> |
| 625 | { |
| 626 | //! @brief Construct a new TypeInfoList object. |
| 627 | //! @param ts - list of type informations |
| 628 | constexpr explicit TypeInfoList(const Ts... ts) : Elements<Ts...>{ts...} {} |
| 629 | }; |
| 630 | |
| 631 | //! @brief The base class that includes the implementation of type information. |
| 632 | //! @tparam Info - type of type information |
| 633 | //! @tparam Bs - type of list of public base classes |
| 634 | template <typename Info, typename... Bs> |
| 635 | class TypeInfoImpl |
| 636 | { |
| 637 | public: |
| 638 | //! @brief Alias for the type. |
| 639 | using Type = Info; |
| 640 | //! @brief Public base class list. |
| 641 | static constexpr BaseList bases{Bs{}...}; |
| 642 | |
| 643 | //! @brief Forward cast from derived object to base object. |
| 644 | //! @tparam Derived - type of derived object |
| 645 | //! @param self - derived object |
| 646 | //! @return base object |
| 647 | template <typename Derived> |
| 648 | static constexpr auto&& forward(Derived&& self); |
| 649 | //! @brief Get all virtual base objects. |
| 650 | //! @return accumulation of virtual base class |
| 651 | static constexpr auto virtualBases(); |
| 652 | //! @brief Accumulating by the DFS algorithm. |
| 653 | //! @tparam Ret - type of return value |
| 654 | //! @tparam Func - type of callable function |
| 655 | //! @param ret - type of return value |
| 656 | //! @param func - callable function |
| 657 | //! @return result of accumulation |
| 658 | template <typename Ret, typename Func> |
| 659 | static constexpr auto dfsAcc(Ret ret, Func&& func); |
| 660 | //! @brief Iteration in the DFS algorithm. |
| 661 | //! @tparam Func - type of callable function |
| 662 | //! @param func - callable function |
| 663 | template <typename Func> |
| 664 | static constexpr void dfsForEach(Func&& func); |
| 665 | //! @brief Iteration variable only. |
| 666 | //! @tparam Obj - type of object to be traversed |
| 667 | //! @tparam Func - type of callable function |
| 668 | //! @param obj - object to be traversed |
| 669 | //! @param func - callable function |
| 670 | template <typename Obj, typename Func> |
| 671 | static constexpr void forEachVarOf(Obj&& obj, Func&& func); |
| 672 | }; |
| 673 | |
| 674 | template <typename Info, typename... Bs> |
| 675 | template <typename Derived> |
| 676 | constexpr auto&& TypeInfoImpl<Info, Bs...>::forward(Derived&& self) |
| 677 | { |
| 678 | if constexpr (std::is_same_v<std::decay_t<Derived>, Derived>) |
| 679 | { |
| 680 | return static_cast<Type&&>(std::forward<Derived>(self)); |
| 681 | } |
| 682 | else if constexpr (std::is_same_v<std::decay_t<Derived>&, Derived>) |
| 683 | { |
| 684 | return static_cast<Type&>(std::forward<Derived>(self)); |
| 685 | } |
| 686 | else |
| 687 | { |
| 688 | return static_cast<const std::decay_t<Derived>&>(std::forward<Derived>(self)); |
| 689 | } |
| 690 | } |
| 691 | |
| 692 | template <typename Info, typename... Bs> |
| 693 | constexpr auto TypeInfoImpl<Info, Bs...>::virtualBases() |
| 694 | { |
| 695 | return bases.accumulate( |
| 696 | Elements<>{}, |
| 697 | [](const auto acc, const auto base) |
| 698 | { |
| 699 | auto concat = base.info.virtualBases().accumulate( |
| 700 | acc, [](const auto acc, const auto base) { return acc.insert(base); }); |
| 701 | if constexpr (!base.isVirtual) |
| 702 | { |
| 703 | return concat; |
| 704 | } |
| 705 | else |
| 706 | { |
| 707 | return concat.insert(base.info); |
| 708 | } |
| 709 | }); |
| 710 | } |
| 711 | |
| 712 | template <typename Info, typename... Bs> |
| 713 | template <typename Ret, typename Func> |
| 714 | constexpr auto TypeInfoImpl<Info, Bs...>::dfsAcc(Ret ret, Func&& func) |
| 715 | { |
| 716 | return Reflect::dfsAcc<0>( |
| 717 | TypeInfo<Type>{}, |
| 718 | std::forward<Func>(func), |
| 719 | virtualBases().accumulate( |
| 720 | std::forward<Func>(func)(std::move(ret), TypeInfo<Type>{}, 0), |
| 721 | [&](const auto acc, const auto vb) { return std::forward<Func>(func)(std::move(acc), vb, 1); })); |
| 722 | } |
| 723 | |
| 724 | template <typename Info, typename... Bs> |
| 725 | template <typename Func> |
| 726 | constexpr void TypeInfoImpl<Info, Bs...>::dfsForEach(Func&& func) |
| 727 | { |
| 728 | dfsAcc( |
| 729 | 0, |
| 730 | [&](const auto /*func*/, const auto info, const auto der) |
| 731 | { |
| 732 | std::forward<Func>(func)(info, der); |
| 733 | return 0; |
| 734 | }); |
| 735 | } |
| 736 | |
| 737 | template <typename Info, typename... Bs> |
| 738 | template <typename Obj, typename Func> |
| 739 | constexpr void TypeInfoImpl<Info, Bs...>::forEachVarOf(Obj&& obj, Func&& func) |
| 740 | { |
| 741 | virtualBases().forEach( |
| 742 | [&](const auto vb) |
| 743 | { |
| 744 | vb.fields.forEach( |
| 745 | [&](const auto fld) |
| 746 | { |
| 747 | using Fld = std::decay_t<decltype(fld)>; |
| 748 | if constexpr (!Fld::isStatic && !Fld::isFunction) |
| 749 | { |
| 750 | std::forward<Func>(func)(fld, std::forward<Obj>(obj).*(fld.value)); |
| 751 | } |
| 752 | }); |
| 753 | }); |
| 754 | Reflect::varInNodeV(TypeInfo<Type>{}, std::forward<Obj>(obj), std::forward<Func>(func)); |
| 755 | } |
| 756 | |
| 757 | //! @brief Attribute in class. |
| 758 | //! @tparam Name - type of name |
| 759 | template <typename Name> |
| 760 | Attr(Name) -> Attr<Name, void>; |
| 761 | |
| 762 | //! @brief Field in class. |
| 763 | //! @tparam Name - type of name |
| 764 | //! @tparam Value - type of target value |
| 765 | template <typename Name, typename Value> |
| 766 | Field(Name, Value) -> Field<Name, Value, AttrList<>>; |
| 767 | } // namespace reflection |
| 768 | } // namespace utility |
| 769 | |