1 // Copyright (c) 2016-2021 Antony Polukhin
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <boost/pfr/functions_for.hpp>
7
8 #include <boost/core/lightweight_test.hpp>
9
10 #include <iostream>
11 #include <typeinfo>
12 #include <tuple>
13 #include <sstream>
14 #include <set>
15 #include <string>
16
17 #include <boost/functional/hash.hpp>
18 #include <unordered_set>
19
20 struct adl_hash {
21 template <class T>
operator ()adl_hash22 std::size_t operator()(const T& val) const {
23 using namespace boost;
24 return hash_value(val);
25 }
26 };
27
28 struct comparable_struct {
29 int i; short s; bool bl; int a,b,c,d,e,f;
30 };
31
BOOST_PFR_FUNCTIONS_FOR(comparable_struct)32 BOOST_PFR_FUNCTIONS_FOR(comparable_struct)
33
34 template <typename Struct>
35 void test_some_comparable_struct() {
36 Struct s1 {0, 1, false, 6,7,8,9,10,11};
37 Struct s2 = s1;
38 Struct s3 {0, 1, false, 6,7,8,9,10,11111};
39 BOOST_TEST_EQ(s1, s2);
40 BOOST_TEST(s1 <= s2);
41 BOOST_TEST(s1 >= s2);
42 BOOST_TEST(!(s1 != s2));
43 BOOST_TEST(!(s1 == s3));
44 BOOST_TEST(s1 != s3);
45 BOOST_TEST(s1 < s3);
46 BOOST_TEST(s3 > s2);
47 BOOST_TEST(s1 <= s3);
48 BOOST_TEST(s3 >= s2);
49
50 std::cout << s1 << std::endl;
51
52 Struct s4;
53 std::stringstream ss;
54 ss.exceptions ( std::ios::failbit);
55 ss << s1;
56 ss >> s4;
57 std::cout << s4 << std::endl;
58 BOOST_TEST_EQ(s1, s4);
59 int i = 1, j = 2;
60 BOOST_TEST_NE(i, j);
61 }
62
test_comparable_struct()63 void test_comparable_struct() {
64 test_some_comparable_struct<comparable_struct>();
65 }
66
operator std::stringempty67 struct empty { operator std::string() { return "empty{}"; } };
BOOST_PFR_FUNCTIONS_FOR(empty)68 BOOST_PFR_FUNCTIONS_FOR(empty)
69
70 void test_empty_struct() {
71 BOOST_TEST_EQ(empty{}, empty{});
72 }
73
74 namespace foo {
75 struct testing { bool b1, b2; int i; };
76 BOOST_PFR_FUNCTIONS_FOR(testing);
77 }
78
79 template <class Comparator>
test_with_contatiners()80 void test_with_contatiners() {
81 std::set<foo::testing, Comparator > t{
82 {true, true, 100},
83 {false, true, 100},
84 {true, false, 100},
85 {true, true, 101}
86 };
87
88 BOOST_TEST(t.find({true, true, 100}) != t.end());
89 BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
90
91 std::unordered_set<foo::testing, adl_hash> us(t.begin(), t.end());
92 BOOST_TEST_EQ(us.size(), t.size());
93 }
94
test_implicit_conversions()95 void test_implicit_conversions() {
96 std::stringstream ss;
97 ss << std::true_type{};
98 BOOST_TEST_EQ(ss.str(), "1"); // Does not breaks implicit conversion
99
100 ss.str("");
101 ss << empty{};
102 BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_FUNCTIONS_FOR
103 }
104
105 namespace {
106
107 struct anonymous_comparable_struct {
108 int i; short s; bool bl; int a,b,c,d,e,f;
109 };
110
111 BOOST_PFR_FUNCTIONS_FOR(anonymous_comparable_struct)
112
113
114 struct other_anonymous_struct {
115 anonymous_comparable_struct a,b;
116 };
117
118 BOOST_PFR_FUNCTIONS_FOR(other_anonymous_struct)
119
120 }
121
122 namespace std {
123 template <>
124 struct hash<anonymous_comparable_struct> {
operator ()std::hash125 std::size_t operator()(const anonymous_comparable_struct& val) const noexcept {
126 return hash_value(val);
127 }
128 };
129 }
130
131 namespace {
132
test_anonymous_comparable_struct()133 void test_anonymous_comparable_struct() {
134 test_some_comparable_struct<anonymous_comparable_struct>();
135 }
136
test_nested_anonymous_comparable_struct()137 void test_nested_anonymous_comparable_struct() {
138 other_anonymous_struct s1{
139 {0, 1, false, 6,7,8,9,10,11},
140 {0, 1, false, 6,7,8,9,10,11},
141 };
142 auto s2 = s1;
143
144 BOOST_TEST_EQ(s1, s2);
145 }
146
147 }
148
main()149 int main() {
150 test_comparable_struct();
151 test_empty_struct();
152 test_with_contatiners<std::less<>>();
153 test_with_contatiners<std::greater<>>();
154 test_implicit_conversions();
155 test_anonymous_comparable_struct();
156 test_nested_anonymous_comparable_struct();
157 return boost::report_errors();
158 }
159
160
161