Skip to content

Commit 696289d

Browse files
Made sure that we can get field names from structs declared inside functions or unnamed namespaces; #46
1 parent 30adc5c commit 696289d

10 files changed

+215
-46
lines changed

include/rfl/internal/bind_to_tuple.hpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef RFL_INTERNAL_BIND_TO_TUPLE_HELPER_HPP_
2-
#define RFL_INTERNAL_BIND_TO_TUPLE_HELPER_HPP_
1+
#ifndef RFL_INTERNAL_BIND_TO_TUPLE_HPP_
2+
#define RFL_INTERNAL_BIND_TO_TUPLE_HPP_
33

44
#include <cstddef>
55
#include <iostream>
@@ -13,17 +13,6 @@
1313
namespace rfl {
1414
namespace internal {
1515

16-
template <class T>
17-
constexpr auto tuple_view(T&);
18-
19-
template <class T, typename F>
20-
constexpr auto bind_to_tuple(T& _t, const F& _f) {
21-
auto view = tuple_view(_t);
22-
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
23-
return std::make_tuple(_f(std::get<Is>(view))...);
24-
}(std::make_index_sequence<std::tuple_size_v<decltype(view)>>());
25-
}
26-
2716
template <std::size_t n>
2817
struct tuple_view_helper {
2918
template <class T>
@@ -598,6 +587,15 @@ constexpr auto tuple_view(T& t) {
598587
return tuple_view_helper<num_fields<T>>::tuple_view(t);
599588
}
600589

590+
template <class T, typename F>
591+
constexpr auto bind_to_tuple(T& _t, const F& _f) {
592+
auto view = tuple_view(_t);
593+
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
594+
return std::make_tuple(_f(std::get<Is>(view))...);
595+
}
596+
(std::make_index_sequence<std::tuple_size_v<decltype(view)>>());
597+
}
598+
601599
} // namespace internal
602600
} // namespace rfl
603601

include/rfl/internal/fake_object.hpp

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#ifndef RFL_INTERNAL_GETFAKEOBJECT_HPP_
2+
#define RFL_INTERNAL_GETFAKEOBJECT_HPP_
3+
4+
namespace rfl {
5+
namespace internal {
6+
7+
#if __GNUC__
8+
#ifndef __clang__
9+
#pragma GCC system_header
10+
#endif
11+
#endif
12+
13+
#ifdef __clang__
14+
#pragma clang diagnostic push
15+
#pragma clang diagnostic ignored "-Wundefined-var-template"
16+
#pragma clang diagnostic ignored "-Wundefined-internal"
17+
#endif
18+
19+
#ifdef _MSC_VER
20+
#pragma warning(push)
21+
#pragma warning(disable : 7631)
22+
#endif
23+
24+
template <class T>
25+
struct wrapper {
26+
const T value;
27+
static const wrapper<T> report_if_you_see_a_link_error_with_this_object;
28+
};
29+
30+
template <class T>
31+
consteval const T& get_fake_object() noexcept {
32+
return wrapper<T>::report_if_you_see_a_link_error_with_this_object.value;
33+
}
34+
35+
#ifdef __clang__
36+
#pragma clang diagnostic pop
37+
#endif
38+
39+
#ifdef _MSC_VER
40+
#pragma warning(pop)
41+
#endif
42+
43+
} // namespace internal
44+
} // namespace rfl
45+
46+
#endif

include/rfl/internal/get_field_names.hpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
#include <utility>
1212

1313
#include "../Literal.hpp"
14-
#include "fake_object.hpp"
14+
#include "bind_fake_object_to_tuple.hpp"
15+
#include "get_fake_object.hpp"
1516
#include "is_flatten_field.hpp"
1617
#include "is_rename.hpp"
1718
#include "num_fields.hpp"
18-
#include "to_ptr_tuple.hpp"
1919

2020
#if __GNUC__
2121
#ifndef __clang__
@@ -41,29 +41,29 @@ constexpr auto wrap(const T& arg) noexcept {
4141
return Wrapper{arg};
4242
}
4343

44-
template <auto ptr>
44+
template <class T, auto ptr>
4545
consteval auto get_field_name_str_view() {
4646
const auto func_name =
4747
std::string_view{std::source_location::current().function_name()};
4848
#if defined(__clang__)
49-
const auto split = func_name.substr(0, func_name.find("}]"));
49+
const auto split = func_name.substr(0, func_name.size() - 2);
5050
return split.substr(split.find_last_of(".") + 1);
5151
#elif defined(__GNUC__)
52-
const auto split = func_name.substr(0, func_name.find(")}"));
52+
const auto split = func_name.substr(0, func_name.size() - 2);
5353
return split.substr(split.find_last_of(":") + 1);
5454
#elif defined(_MSC_VER)
55-
const auto split = func_name.substr(0, func_name.find_last_of("}"));
56-
return split.substr(split.find_last_of(">") + 1);
55+
const auto split = func_name.substr(0, func_name.size() - 7);
56+
return split.substr(split.find("value->") + 7);
5757
#else
5858
static_assert(false,
5959
"You are using an unsupported compiler. Please use GCC, Clang "
6060
"or MSVC or switch to the rfl::Field-syntax.");
6161
#endif
6262
}
6363

64-
template <auto ptr>
64+
template <class T, auto ptr>
6565
consteval auto get_field_name_str_lit() {
66-
constexpr auto name = get_field_name_str_view<ptr>();
66+
constexpr auto name = get_field_name_str_view<T, ptr>();
6767
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
6868
return StringLiteral<sizeof...(Ns) + 1>{name[Ns]...};
6969
};
@@ -73,17 +73,21 @@ consteval auto get_field_name_str_lit() {
7373
template <class T>
7474
auto get_field_names();
7575

76-
template <auto ptr>
76+
template <class T, auto ptr>
7777
auto get_field_name() {
78+
#if defined(__clang__)
7879
using Type = std::remove_cvref_t<std::remove_pointer_t<
7980
typename std::remove_pointer_t<decltype(ptr)>::Type>>;
81+
#else
82+
using Type = std::remove_cvref_t<std::remove_pointer_t<decltype(ptr)>>;
83+
#endif
8084
if constexpr (is_rename_v<Type>) {
8185
using Name = typename Type::Name;
8286
return Name();
8387
} else if constexpr (is_flatten_field_v<Type>) {
8488
return get_field_names<std::remove_cvref_t<typename Type::Type>>();
8589
} else {
86-
return rfl::Literal<get_field_name_str_lit<ptr>()>();
90+
return rfl::Literal<get_field_name_str_lit<T, ptr>()>();
8791
}
8892
}
8993

@@ -114,16 +118,24 @@ template <class T>
114118
#endif
115119
#endif
116120
auto get_field_names() {
117-
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
121+
using Type = std::remove_cvref_t<T>;
122+
if constexpr (std::is_pointer_v<Type>) {
118123
return get_field_names<std::remove_pointer_t<T>>();
119124
} else {
120-
constexpr auto ptr_tuple = to_ptr_tuple(fake_object<T>);
121-
const auto get = [&]<std::size_t... Is>(std::index_sequence<Is...>) {
125+
#if defined(__clang__)
126+
const auto get = []<std::size_t... Is>(std::index_sequence<Is...>) {
122127
return concat_literals(
123-
get_field_name<wrap(std::get<Is>(ptr_tuple))>()...);
128+
get_field_name<Type, wrap(std::get<Is>(
129+
bind_fake_object_to_tuple<T>()))>()...);
124130
};
125-
return get(
126-
std::make_index_sequence<std::tuple_size_v<decltype(ptr_tuple)>>());
131+
#else
132+
const auto get = []<std::size_t... Is>(std::index_sequence<Is...>) {
133+
return concat_literals(
134+
get_field_name<Type,
135+
std::get<Is>(bind_fake_object_to_tuple<T>())>()...);
136+
};
137+
#endif
138+
return get(std::make_index_sequence<num_fields<T>>());
127139
}
128140
}
129141

include/rfl/internal/to_ptr_tuple.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef RFL_INTERNAL_BIND_TO_TUPLE_HPP_
2-
#define RFL_INTERNAL_BIND_TO_TUPLE_HPP_
1+
#ifndef RFL_INTERNAL_TO_PTR_TUPLE_HPP_
2+
#define RFL_INTERNAL_TO_PTR_TUPLE_HPP_
33

44
#include <iostream>
55
#include <tuple>

tests/json/test_inside_function.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include "test_inside_function.hpp"
2+
3+
#include <iostream>
4+
#include <rfl.hpp>
5+
#include <rfl/json.hpp>
6+
#include <source_location>
7+
#include <string>
8+
#include <vector>
9+
10+
#include "write_and_read.hpp"
11+
12+
namespace test_inside_function {
13+
14+
void test() {
15+
std::cout << std::source_location::current().function_name() << std::endl;
16+
17+
using Age = rfl::Validator<unsigned int, rfl::Minimum<0>, rfl::Maximum<130>>;
18+
19+
struct Person {
20+
rfl::Rename<"firstName", std::string> first_name;
21+
rfl::Rename<"lastName", std::string> last_name = "Simpson";
22+
std::string town = "Springfield";
23+
rfl::Timestamp<"%Y-%m-%d"> birthday;
24+
Age age;
25+
rfl::Email email;
26+
std::vector<Person> children;
27+
};
28+
29+
const auto bart = Person{.first_name = "Bart",
30+
.birthday = "1987-04-19",
31+
.age = 10,
32+
.email = "[email protected]"};
33+
34+
const auto lisa = Person{.first_name = "Lisa",
35+
.birthday = "1987-04-19",
36+
.age = 8,
37+
.email = "[email protected]"};
38+
39+
const auto maggie = Person{.first_name = "Maggie",
40+
.birthday = "1987-04-19",
41+
.age = 0,
42+
.email = "[email protected]"};
43+
44+
const auto homer =
45+
Person{.first_name = "Homer",
46+
.birthday = "1987-04-19",
47+
.age = 45,
48+
.email = "[email protected]",
49+
.children = std::vector<Person>({bart, lisa, maggie})};
50+
51+
write_and_read(
52+
homer,
53+
R"({"firstName":"Homer","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":45,"email":"[email protected]","children":[{"firstName":"Bart","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":10,"email":"[email protected]","children":[]},{"firstName":"Lisa","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":8,"email":"[email protected]","children":[]},{"firstName":"Maggie","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":0,"email":"[email protected]","children":[]}]})");
54+
}
55+
} // namespace test_inside_function

tests/json/test_inside_function.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace test_inside_function {
2+
void test();
3+
}
4+

tests/json/test_unnamed_namespace.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
#include "test_unnamed_namespace.hpp"
3+
4+
#include <iostream>
5+
#include <rfl.hpp>
6+
#include <rfl/json.hpp>
7+
#include <source_location>
8+
#include <string>
9+
#include <vector>
10+
11+
#include "write_and_read.hpp"
12+
13+
namespace test_unnamed_namespace {
14+
15+
namespace {
16+
17+
using Age = rfl::Validator<unsigned int, rfl::Minimum<0>, rfl::Maximum<130>>;
18+
19+
struct Person {
20+
rfl::Rename<"firstName", std::string> first_name;
21+
rfl::Rename<"lastName", std::string> last_name = "Simpson";
22+
std::string town = "Springfield";
23+
rfl::Timestamp<"%Y-%m-%d"> birthday;
24+
Age age;
25+
rfl::Email email;
26+
std::vector<Person> children;
27+
};
28+
29+
} // namespace
30+
31+
void test() {
32+
std::cout << std::source_location::current().function_name() << std::endl;
33+
34+
const auto bart = Person{.first_name = "Bart",
35+
.birthday = "1987-04-19",
36+
.age = 10,
37+
.email = "[email protected]"};
38+
39+
const auto lisa = Person{.first_name = "Lisa",
40+
.birthday = "1987-04-19",
41+
.age = 8,
42+
.email = "[email protected]"};
43+
44+
const auto maggie = Person{.first_name = "Maggie",
45+
.birthday = "1987-04-19",
46+
.age = 0,
47+
.email = "[email protected]"};
48+
49+
const auto homer =
50+
Person{.first_name = "Homer",
51+
.birthday = "1987-04-19",
52+
.age = 45,
53+
.email = "[email protected]",
54+
.children = std::vector<Person>({bart, lisa, maggie})};
55+
56+
write_and_read(
57+
homer,
58+
R"({"firstName":"Homer","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":45,"email":"[email protected]","children":[{"firstName":"Bart","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":10,"email":"[email protected]","children":[]},{"firstName":"Lisa","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":8,"email":"[email protected]","children":[]},{"firstName":"Maggie","lastName":"Simpson","town":"Springfield","birthday":"1987-04-19","age":0,"email":"[email protected]","children":[]}]})");
59+
}
60+
} // namespace test_unnamed_namespace

tests/json/test_unnamed_namespace.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace test_unnamed_namespace {
2+
void test();
3+
}
4+

tests/json/tests.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "test_flatten.hpp"
3030
#include "test_flatten_anonymous.hpp"
3131
#include "test_forward_list.hpp"
32+
#include "test_inside_function.hpp"
3233
#include "test_list.hpp"
3334
#include "test_literal.hpp"
3435
#include "test_literal_map.hpp"
@@ -61,6 +62,7 @@
6162
#include "test_timestamp.hpp"
6263
#include "test_unique_ptr.hpp"
6364
#include "test_unique_ptr2.hpp"
65+
#include "test_unnamed_namespace.hpp"
6466
#include "test_unordered_map.hpp"
6567
#include "test_unordered_multimap.hpp"
6668
#include "test_unordered_multiset.hpp"
@@ -111,6 +113,8 @@ int main() {
111113
test_result::test();
112114
test_anonymous_fields::test();
113115
test_monster_example::test();
116+
test_unnamed_namespace::test();
117+
test_inside_function::test();
114118

115119
test_custom_class1::test();
116120
test_custom_class2::test();

0 commit comments

Comments
 (0)