SPARK  0.1.0
A general purpose game engine written in C++.
Loading...
Searching...
No Matches
Rtti.h
1#pragma once
2
3#include "boost/preprocessor/stringize.hpp"
4#include "boost/preprocessor/punctuation/comma_if.hpp"
5#include "boost/preprocessor/punctuation/remove_parens.hpp"
6#include "boost/preprocessor/seq/elem.hpp"
7#include "boost/preprocessor/seq/for_each_i.hpp"
8#include "boost/preprocessor/seq/for_each_product.hpp"
9#include "boost/preprocessor/seq/pop_front.hpp"
10#include "boost/preprocessor/variadic/to_seq.hpp"
11
12#include <array>
13#include <vector>
14
15namespace spark::rtti::details
16{
17 namespace globals
18 {
24 template <std::size_t N>
25 constexpr bool validate_rtti_name(const std::array<char, N> name)
26 {
27 auto is_number = [](const char c) { return c >= '0' && c <= '9'; };
28 auto is_uppercase = [](const char c) { return c >= 'A' && c <= 'Z'; };
29 auto is_lowercase = [](const char c) { return c >= 'a' && c <= 'z'; };
30 auto is_other = [](const char c) { return c == '_' || c == ':' || c == ',' || c == '*' || c == '&' || c == '<' || c == '>'; };
31
32 for (const char c : name)
33 {
34 if (c == '\0') // If we find the null character, the string is complete and valid
35 return true;
36 if (!is_number(c) && !is_uppercase(c) && !is_lowercase(c) && !is_other(c))
37 return false;
38 }
39 return false; // We did not find the null character, the string is invalid
40 }
41
48 template <std::size_t N>
49 constexpr auto convert_to_rtti_name(const char (&s)[N])
50 {
51 std::array<char, N> res = {};
52 std::size_t i = 0;
53 for (auto c : s)
54 if (c != ' ')
55 res[i++] = c;
56 return res;
57 }
58 }
59
60 template <typename T>
62
63 template <typename... ParentTypes>
65 {
66 static std::vector<RttiBase*> exec()
67 {
68 return {&ParentTypes::classRtti()...};
69 }
70 };
71
72 template <>
74 {
75 static std::vector<RttiBase*> exec()
76 {
77 return {};
78 }
79 };
80}
81
85#define DETAILS_DECLARE_SPARK_RTTI(...) \
86public: \
87 using ThisRttiType = spark::rtti::Rtti<__VA_ARGS__>; \
88 static ThisRttiType& classRtti() \
89 { \
90 return ThisRttiType::instance(); \
91 } \
92 spark::rtti::RttiBase& rttiInstance() const override \
93 { \
94 /* Returns the instance of the first type in the variadic arguments */ \
95 return BOOST_PP_SEQ_ELEM(0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))::classRtti(); \
96 }
97
101#define DETAILS_SPARK_RTTI_REGISTER_NAME(ClassName) \
102 template <> \
103 struct spark::rtti::details::GetClassName<BOOST_PP_REMOVE_PARENS(ClassName)> \
104 { \
105 constexpr static auto exec() \
106 { \
107 /* Takes any type, remove spaces and put it as string */ \
108 constexpr auto name = globals::convert_to_rtti_name(BOOST_PP_STRINGIZE(BOOST_PP_REMOVE_PARENS(ClassName))); \
109 static_assert(globals::validate_rtti_name(name)); \
110 return name; \
111 } \
112 };
113
123#define DETAILS_SPARK_RTTI_TPL_COMMA_CHOICE(r, data, i, elem) BOOST_PP_COMMA_IF(i) elem
124
132#define DETAILS_SPARK_RTTI_REGISTER_TPL_LOOP(r, Tokens) DETAILS_SPARK_RTTI_REGISTER_NAME((BOOST_PP_SEQ_HEAD(Tokens) < BOOST_PP_SEQ_FOR_EACH_I(DETAILS_SPARK_RTTI_TPL_COMMA_CHOICE, _, BOOST_PP_SEQ_POP_FRONT(Tokens)) >))
133
137#define DETAILS_SPARK_RTTI_REGISTER_TPL(ClassName, ...) BOOST_PP_SEQ_FOR_EACH_PRODUCT(DETAILS_SPARK_RTTI_REGISTER_TPL_LOOP, ((ClassName))BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))