17#include "AUI/Traits/unsafe_declval.h"
19namespace aui::reflect::detail {
27struct lref_constructing {
30 constexpr operator Type&()
const&&
noexcept {
31 return aui::unsafe_declval<Type&>();
35 constexpr operator Type&()
const&
noexcept {
36 return aui::unsafe_declval<Type&>();
43struct rref_constructing {
47 operator Type() const&& noexcept {
48 return aui::unsafe_declval<Type>();
56 class T, std::size_t... I,
class =
typename std::enable_if<std::is_copy_constructible<T>::value>::type>
57constexpr auto enable_if_constructible(std::index_sequence<I...>)
noexcept ->
typename std::add_pointer<
decltype(T {
58 lref_constructing { I }... })>::type;
61 class T, std::size_t... I,
class =
typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
62constexpr auto enable_if_constructible(std::index_sequence<I...>)
noexcept ->
typename std::add_pointer<
decltype(T {
63 rref_constructing { I }... })>::type;
66 class T, std::size_t N,
67 class =
decltype(enable_if_constructible<T>(std::make_integer_sequence<std::size_t, N>()))>
68using enable_if_constructible_t = std::size_t;
75template <
class T, std::
size_t N>
76constexpr auto detect_fields_count_greedy_remember(
long)
noexcept -> detail::enable_if_constructible_t<T, N> {
80template <
class T, std::
size_t N>
81constexpr std::size_t detect_fields_count_greedy_remember(
int)
noexcept {
85using multi_element_range = std::false_type;
86using one_element_range = std::true_type;
88template <std::
size_t Begin, std::
size_t Last>
89using is_one_element_range = std::integral_constant<bool, Begin == Last>;
91template <
class T, std::
size_t Begin, std::
size_t Last>
92constexpr std::size_t detect_fields_count_greedy(detail::one_element_range)
noexcept {
95 "====================> aui::reflect: internal logic error. Please report this issue to the github along with the "
96 "structure you're reflecting.");
97 return detail::detect_fields_count_greedy_remember<T, Begin>(1L);
100template <
class T, std::
size_t Begin, std::
size_t Last>
101constexpr std::size_t detect_fields_count_greedy(detail::multi_element_range)
noexcept {
102 constexpr std::size_t middle = Begin + (Last - Begin) / 2;
103 constexpr std::size_t fields_count_big_range =
104 detail::detect_fields_count_greedy<T, middle + 1, Last>(detail::is_one_element_range<middle + 1, Last> {});
106 constexpr std::size_t small_range_begin = (fields_count_big_range ? 0 : Begin);
107 constexpr std::size_t small_range_last = (fields_count_big_range ? 0 : middle);
108 constexpr std::size_t fields_count_small_range = detail::detect_fields_count_greedy<
109 T, small_range_begin, small_range_last>(detail::is_one_element_range<small_range_begin, small_range_last> {});
110 return fields_count_big_range ? fields_count_big_range : fields_count_small_range;
122template <
class T, std::
size_t Begin, std::
size_t M
iddle>
123constexpr std::size_t detect_fields_count(detail::one_element_range,
long)
noexcept {
126 "====================> aui::reflect: internal logic error. Please report this issue to the github along with the "
127 "structure you're reflecting.");
131template <
class T, std::
size_t Begin, std::
size_t M
iddle>
132constexpr std::size_t detect_fields_count(detail::multi_element_range,
int)
noexcept;
134template <
class T, std::
size_t Begin, std::
size_t M
iddle>
136detect_fields_count(detail::multi_element_range,
long)
noexcept -> detail::enable_if_constructible_t<T, Middle> {
137 constexpr std::size_t next_v = Middle + (Middle - Begin + 1) / 2;
138 return detail::detect_fields_count<T, Middle, next_v>(detail::is_one_element_range<Middle, next_v> {}, 1L);
141template <
class T, std::
size_t Begin, std::
size_t M
iddle>
142constexpr std::size_t detect_fields_count(detail::multi_element_range,
int)
noexcept {
143 constexpr std::size_t next_v = Begin + (Middle - Begin) / 2;
144 return detail::detect_fields_count<T, Begin, next_v>(detail::is_one_element_range<Begin, next_v> {}, 1L);
153template <
class T, std::
size_t N>
154constexpr auto detect_fields_count_dispatch(std::integral_constant<std::size_t, N>,
long,
long)
noexcept ->
155 typename std::enable_if<std::is_array<T>::value, std::size_t>::type {
156 return sizeof(T) /
sizeof(
typename std::remove_all_extents<T>::type);
159template <
class T, std::
size_t N>
161detect_fields_count_dispatch(std::integral_constant<std::size_t, N>,
long,
int)
noexcept ->
decltype(
sizeof(T {})) {
162 constexpr std::size_t middle = N / 2 + 1;
163 return detail::detect_fields_count<T, 0, middle>(detail::multi_element_range {}, 1L);
166template <
class T, std::
size_t N>
167constexpr std::size_t detect_fields_count_dispatch(std::integral_constant<std::size_t, N>,
int,
int)
noexcept {
174 return detail::detect_fields_count_greedy<T, 0, N>(detail::multi_element_range {});
180template <
class Derived,
class U>
181constexpr bool static_assert_non_inherited() noexcept {
183 !std::is_base_of<U, Derived>::value,
"====================> aui::reflect: inherited types are not supported.");
187template <
class Derived>
188struct lref_base_asserting {
189 template <
class Type>
190 constexpr operator Type&()
const&&
191 noexcept(detail::static_assert_non_inherited<Derived, Type>())
193 return aui::unsafe_declval<Type&>();
196 template <
class Type>
197 constexpr operator Type&()
const&
198 noexcept(detail::static_assert_non_inherited<Derived, Type>())
200 return aui::unsafe_declval<Type&>();
204template <
class Derived>
205struct rref_base_asserting {
206 template <
class Type>
207 operator Type() const&&
208 noexcept(detail::static_assert_non_inherited<Derived, Type>())
210 return aui::unsafe_declval<Type>();
215 class T, std::size_t I0, std::size_t... I,
216 class =
typename std::enable_if<std::is_copy_constructible<T>::value>::type>
218assert_first_is_not_base(std::index_sequence<I0, I...>)
noexcept ->
typename std::add_pointer<
decltype(T {
219 lref_base_asserting<T> {}, lref_constructing { I }... })>::type {
224 class T, std::size_t I0, std::size_t... I,
225 class =
typename std::enable_if<!std::is_copy_constructible<T>::value>::type>
227assert_first_is_not_base(std::index_sequence<I0, I...>)
noexcept ->
typename std::add_pointer<
decltype(T {
228 rref_base_asserting<T> {}, rref_constructing { I }... })>::type {
233constexpr void* assert_first_is_not_base(std::index_sequence<>)
noexcept {
246template <
class Clazz>
247constexpr std::size_t fields_count() noexcept {
248 using type = std::remove_cv_t<Clazz>;
251 !std::is_reference<type>::value,
"====================> aui::reflect: attempt to get fields count on a reference.");
254 !std::is_polymorphic<type>::value,
255 "====================> aui::reflect: type must have no virtual function, because otherwise it is not aggregate "
258#ifdef __cpp_lib_is_aggregate
260 std::is_aggregate<type>::value || std::is_scalar<type>::value,
261 "====================> aui::reflect: type must be aggregate initializable.");
264#if defined(_MSC_VER) && (_MSC_VER <= 1920)
266 constexpr std::size_t max_fields_count = (
sizeof(type) * CHAR_BIT >= 1024 ? 1024 :
sizeof(type) * CHAR_BIT);
268 constexpr std::size_t max_fields_count = (
sizeof(type) * CHAR_BIT);
272 constexpr std::size_t result =
273 detail::detect_fields_count_dispatch<type>(std::integral_constant<std::size_t, max_fields_count> {}, 1L, 1L);
275 detail::assert_first_is_not_base<type>(std::make_integer_sequence<std::size_t, result>());
277#ifndef __cpp_lib_is_aggregate
279 is_aggregate_initializable_n<type, result>::value,
280 "====================> aui::reflect: types with user specified constructors (non-aggregate initializable types) "
281 "are not supported.");
285 result != 0 || std::is_empty<type>::value || std::is_fundamental<type>::value || std::is_reference<type>::value,
286 "====================> aui::reflect: if there's no other failed static asserts then something went wrong. Please "
287 "report this issue to the github along with the structure you're reflecting.");