|
4 | 4 | #include <nlohmann/json.hpp> |
5 | 5 | #include <simdjson.h> |
6 | 6 |
|
| 7 | +#include <concepts> |
7 | 8 | #include <iostream> |
8 | 9 | #include <random> |
9 | 10 | #include <vector> |
10 | 11 |
|
| 12 | +template <auto... Xs, typename F> constexpr void for_values(F &&f) { |
| 13 | + (f.template operator()<Xs>(), ...); |
| 14 | +} |
| 15 | + |
| 16 | +template <auto B, auto E, typename F> constexpr void for_range(F &&f) { |
| 17 | + using t = std::common_type_t<decltype(B), decltype(E)>; |
| 18 | + |
| 19 | + [&f]<auto... Xs>(std::integer_sequence<t, Xs...>) { |
| 20 | + for_values<(B + Xs)...>(f); |
| 21 | + }(std::make_integer_sequence<t, E - B>{}); |
| 22 | +} |
| 23 | + |
| 24 | +template <typename T> consteval auto member_info(int n) { |
| 25 | + return nonstatic_data_members_of(^T)[n]; |
| 26 | +} |
| 27 | + |
11 | 28 | std::mt19937 rng(12345); |
12 | 29 | struct Location { |
13 | 30 | double lat; |
@@ -175,87 +192,25 @@ std::string nlohmann_serialize(const User &user) { |
175 | 192 | return user_json.dump(); |
176 | 193 | } |
177 | 194 |
|
178 | | -bool compare(const User &user1, const User &user2, const std::string &json) { |
179 | | - if (user1.id != user2.id) { |
180 | | - std::cerr << "id mismatch: " << user1.id << " != " << user2.id << " in " |
181 | | - << json << std::endl; |
182 | | - return false; |
183 | | - } |
184 | | - if (user1.email != user2.email) { |
185 | | - std::cerr << "email mismatch: " << user1.email << " != " << user2.email |
186 | | - << " in " << json << std::endl; |
187 | | - return false; |
188 | | - } |
189 | | - if (user1.username != user2.username) { |
190 | | - std::cerr << "username mismatch: " << user1.username |
191 | | - << " != " << user2.username << " in " << json << std::endl; |
192 | | - return false; |
193 | | - } |
194 | | - if (user1.profile.name != user2.profile.name) { |
195 | | - std::cerr << "profile.name mismatch: " << user1.profile.name |
196 | | - << " != " << user2.profile.name << " in " << json << std::endl; |
197 | | - return false; |
198 | | - } |
199 | | - if (user1.profile.company != user2.profile.company) { |
200 | | - std::cerr << "profile.company mismatch: " << user1.profile.company |
201 | | - << " != " << user2.profile.company << " in " << json << std::endl; |
202 | | - return false; |
203 | | - } |
204 | | - if (user1.profile.dob != user2.profile.dob) { |
205 | | - std::cerr << "profile.dob mismatch: " << user1.profile.dob |
206 | | - << " != " << user2.profile.dob << " in " << json << std::endl; |
207 | | - return false; |
208 | | - } |
209 | | - if (user1.profile.address != user2.profile.address) { |
210 | | - std::cerr << "profile.address mismatch: " << user1.profile.address |
211 | | - << " != " << user2.profile.address << " in " << json << std::endl; |
212 | | - return false; |
213 | | - } |
214 | | - if (user1.profile.location.lat != user2.profile.location.lat) { |
215 | | - std::cerr << "profile.location.lat mismatch: " << user1.profile.location.lat |
216 | | - << " != " << user2.profile.location.lat << " in " << json |
217 | | - << std::endl; |
218 | | - return false; |
219 | | - } |
220 | | - if (user1.profile.location.lng != user2.profile.location.lng) { |
221 | | - std::cerr << "profile.location.lng" |
222 | | - << " != " << user2.profile.location.lng << " in " << json |
223 | | - << std::endl; |
224 | | - return false; |
225 | | - } |
226 | | - if (user1.profile.about != user2.profile.about) { |
227 | | - std::cerr << "profile.about mismatch: " << user1.profile.about |
228 | | - << " != " << user2.profile.about << " in " << json << std::endl; |
229 | | - return false; |
230 | | - } |
231 | | - if (user1.apiKey != user2.apiKey) { |
232 | | - std::cerr << "apiKey mismatch" |
233 | | - << " != " << user2.apiKey << " in " << json << std::endl; |
234 | | - return false; |
235 | | - } |
236 | | - if (user1.roles.size() != user2.roles.size()) { |
237 | | - std::cerr << "roles size mismatch: " << user1.roles.size() |
238 | | - << " != " << user2.roles.size() << " in " << json << std::endl; |
239 | | - return false; |
240 | | - } |
241 | | - for (size_t i = 0; i < user1.roles.size(); i++) { |
242 | | - if (user1.roles[i] != user2.roles[i]) { |
243 | | - std::cerr << "roles[" << i << "] mismatch: " << user1.roles[i] |
244 | | - << " != " << user2.roles[i] << " in " << json << std::endl; |
245 | | - return false; |
| 195 | +template <typename T> |
| 196 | +bool compare(const T &user1, const T &user2, const std::string &json) { |
| 197 | + bool result = true; |
| 198 | + for_range<0, nonstatic_data_members_of(^T).size()>([&]<auto i>() { |
| 199 | + constexpr auto mem = member_info<T>(i); |
| 200 | + if constexpr (std::equality_comparable<typename[:type_of(mem):]>) { |
| 201 | + if (user1.[:mem:] != user2.[:mem:]) { |
| 202 | + std::cerr << std::format("{} mismatch: {} != {} in {}\n", identifier_of(mem), |
| 203 | + user1.[:mem:], user2.[:mem:], json); |
| 204 | + result = false; |
| 205 | + } |
| 206 | + } else { |
| 207 | + if (!compare(user1.[:mem:], user2.[:mem:], json)) { |
| 208 | + result = false; |
| 209 | + } |
246 | 210 | } |
247 | | - } |
248 | | - if (user1.createdAt != user2.createdAt) { |
249 | | - std::cerr << "createdAt mismatch: " << user1.createdAt |
250 | | - << " != " << user2.createdAt << " in " << json << std::endl; |
251 | | - return false; |
252 | | - } |
253 | | - if (user1.updatedAt != user2.updatedAt) { |
254 | | - std::cerr << "updatedAt mismatch: " << user1.updatedAt |
255 | | - << " != " << user2.updatedAt << " in " << json << std::endl; |
256 | | - return false; |
257 | | - } |
258 | | - return true; |
| 211 | + }); |
| 212 | + |
| 213 | + return result; |
259 | 214 | } |
260 | 215 |
|
261 | 216 | bool round_trip_nlohmann(const User &user) { |
|
0 commit comments