OpenKalman
compares_with.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2019-2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_COORDINATE_COMPARES_WITH_HPP
17 #define OPENKALMAN_COORDINATE_COMPARES_WITH_HPP
18 
24 
26 {
27  namespace detail
28  {
29  template<auto comp, bool op_is_and = false, typename...Ords>
30  constexpr bool
31  do_comps(Ords...ords)
32  {
33  if constexpr (op_is_and) return (... and stdex::invoke(comp, ords));
34  else return (... or stdex::invoke(comp, ords));
35  }
36 
37 
38  constexpr std::size_t
39  inc_bank(std::size_t bank, std::size_t inc)
40  {
41  return (bank == stdex::dynamic_extent or inc == stdex::dynamic_extent) ? stdex::dynamic_extent : bank + inc;
42  }
43 
44 
45 #ifdef __cpp_concepts
46  template<typename A, typename B>
47 #else
48  template<typename A, typename B, typename = void>
49 #endif
50  struct same_descriptors : std::false_type {};
51 
52 #ifdef __cpp_concepts
53  template<typename A, typename B> requires
54  std::bool_constant<internal::get_descriptor_hash_code(A{}) == internal::get_descriptor_hash_code(B{})>::value
56 #else
57  template<typename A, typename B>
58  struct same_descriptors<A, B, std::enable_if_t<
59  std::bool_constant<internal::get_descriptor_hash_code(A{}) == internal::get_descriptor_hash_code(B{})>::value>>
60 #endif
61  : std::true_type {};
62 
63 
64 #ifdef __cpp_concepts
65  template<typename A, typename B>
66 #else
67  template<typename A, typename B, typename = void>
68 #endif
69  struct different_descriptors : std::false_type {};
70 
71 #ifdef __cpp_concepts
72  template<typename A, typename B> requires
73  std::bool_constant<internal::get_descriptor_hash_code(A{}) != internal::get_descriptor_hash_code(B{})>::value
75 #else
76  template<typename A, typename B>
77  struct different_descriptors<A, B, std::enable_if_t<
78  std::bool_constant<internal::get_descriptor_hash_code(A{}) != internal::get_descriptor_hash_code(B{})>::value>>
79 #endif
80  : std::true_type {};
81 
82 
83  template<typename A, typename B, auto comp, applicability app,
84  std::size_t ia = 0, std::size_t ib = 0, std::size_t abank = 0, std::size_t bbank = 0>
85  constexpr bool
86  compares_with_iter()
87  {
89 
90  if constexpr (ia < collections::size_of_v<A>)
91  {
92  using Ai = std::decay_t<collections::collection_element_t<ia, A>>;
93  constexpr bool ae = euclidean_pattern<Ai>;
94  constexpr std::size_t dim_Ai = dimension_of_v<Ai>;
95  if constexpr (ib < collections::size_of_v<B>)
96  {
97  using Bi = std::decay_t<collections::collection_element_t<ib, B>>;
98  constexpr bool be = euclidean_pattern<Bi>;
99  constexpr std::size_t dim_Bi = dimension_of_v<Bi>;
100 
101  if constexpr (ae and be)
102  {
103  return compares_with_iter<A, B, comp, app, ia + 1, ib + 1, inc_bank(abank, dim_Ai), bbank + dim_Bi>();
104  }
105  else if constexpr (ae)
106  {
107  return compares_with_iter<A, B, comp, app, ia + 1, ib, inc_bank(abank, dim_Ai), bbank>();
108  }
109  else if constexpr (be)
110  {
111  return compares_with_iter<A, B, comp, app, ia, ib + 1, abank, inc_bank(bbank, dim_Bi)>();
112  }
113  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
114  {
115  return app == applicability::permitted and do_comps<comp>(partial_ordering::equivalent, partial_ordering::unordered);
116  }
117  else if constexpr (abank != bbank)
118  {
119  return do_comps<comp>(partial_ordering::unordered);
120  }
121  else if constexpr (same_descriptors<Ai, Bi>::value)
122  {
123  return compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
124  }
125  else if constexpr (different_descriptors<Ai, Bi>::value)
126  {
127  return do_comps<comp>(partial_ordering::unordered);
128  }
129  else if constexpr (do_comps<comp>(partial_ordering::equivalent))
130  {
131  return app == applicability::permitted and
132  compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
133  }
134  else if constexpr (do_comps<comp>(partial_ordering::unordered))
135  {
136  return app == applicability::permitted or
137  compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
138  }
139  else if constexpr (do_comps<comp>(partial_ordering::less))
140  {
141  return app == applicability::permitted and
142  (dim_Ai == stdex::dynamic_extent or dim_Ai == 0) and
143  compares_with_iter<A, B, comp, app, ia + 1, ib + 1, dim_Ai, dim_Bi>();
144  }
145  else //if constexpr (do_comps<comp>(partial_ordering::greater))
146  {
147  return app == applicability::permitted and
148  (dim_Bi == stdex::dynamic_extent or dim_Bi == 0) and
149  compares_with_iter<A, B, comp, app, ia + 1, ib + 1, dim_Ai, dim_Bi>();
150  }
151  }
152  else if constexpr (euclidean_pattern<Ai>)
153  {
154  return compares_with_iter<A, B, comp, app, ia + 1, ib, inc_bank(abank, dim_Ai), bbank>();
155  }
156  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
157  {
158  return (dim_Ai != stdex::dynamic_extent and do_comps<comp>(partial_ordering::unordered)) or
159  (app == applicability::permitted and (dim_Ai == stdex::dynamic_extent or do_comps<comp>(partial_ordering::greater)));
160  }
161  else if (abank >= bbank)
162  {
163  return do_comps<comp>(partial_ordering::greater);
164  }
165  else if constexpr (dim_Ai == stdex::dynamic_extent)
166  {
167  return app == applicability::permitted and
168  ( do_comps<comp>(partial_ordering::unordered, partial_ordering::greater, partial_ordering::equivalent) or
169  (do_comps<comp>(partial_ordering::less) and bbank > 0));
170  }
171  else
172  {
173  return do_comps<comp>(partial_ordering::unordered);
174  }
175  }
176  else if constexpr (ib < collections::size_of_v<B>) // ia >= collections::size_of_v<A>
177  {
178  using Bi = std::decay_t<collections::collection_element_t<ib, B>>;
179  constexpr std::size_t dim_Bi = dimension_of_v<Bi>;
180 
181  if constexpr (euclidean_pattern<Bi>)
182  {
183  return compares_with_iter<A, B, comp, app, ia, ib + 1, abank, inc_bank(bbank, dim_Bi)>();
184  }
185  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
186  {
187  return (dim_Bi != stdex::dynamic_extent and do_comps<comp>(partial_ordering::unordered)) or
188  (app == applicability::permitted and (dim_Bi == stdex::dynamic_extent or do_comps<comp>(partial_ordering::less)));
189  }
190  else if (abank <= bbank)
191  {
192  return do_comps<comp>(partial_ordering::less);
193  }
194  else if constexpr (dim_Bi == stdex::dynamic_extent)
195  {
196  return app == applicability::permitted and
197  ( do_comps<comp>(partial_ordering::unordered, partial_ordering::less, partial_ordering::equivalent) or
198  (do_comps<comp>(partial_ordering::greater) and abank > 0));
199  }
200  else
201  {
202  return do_comps<comp>(partial_ordering::unordered);
203  }
204  }
205  else if constexpr (abank != stdex::dynamic_extent and bbank != stdex::dynamic_extent)
206  {
207  return do_comps<comp>(stdex::compare_three_way{}(abank, bbank));
208  }
209  else if constexpr (abank == 0)
210  {
211  return do_comps<comp, app == applicability::guaranteed>(partial_ordering::less, partial_ordering::equivalent);
212  }
213  else if constexpr (bbank == 0)
214  {
215  return do_comps<comp, app == applicability::guaranteed>(partial_ordering::greater, partial_ordering::equivalent);
216  }
217  else if constexpr (abank != stdex::dynamic_extent or bbank != stdex::dynamic_extent)
218  {
219  return app == applicability::permitted and do_comps<comp>(partial_ordering::less, partial_ordering::greater, partial_ordering::equivalent);
220  }
221  else
222  {
223  return app == applicability::permitted;
224  }
225  }
226 
227 
228  template<typename T, typename U, auto comp, applicability a>
229  constexpr bool
231  {
235 
236  if constexpr (descriptor<T>)
237  {
238  return compares_with_impl<std::tuple<stdex::unwrap_ref_decay_t<T>>, U, comp, a>();
239  }
240  else if constexpr (descriptor<U>)
241  {
242  return compares_with_impl<T, std::tuple<stdex::unwrap_ref_decay_t<U>>, comp, a>();
243  }
244 
248 
249  else if constexpr (not values::fixed<dimension_of<T>> and not values::fixed<dimension_of<U>>)
250  {
251  using DT = stdex::ranges::range_value_t<T>;
252  using DU = stdex::ranges::range_value_t<U>;
253  if constexpr ((euclidean_pattern<DT> and euclidean_pattern<DU>))
254  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
255  else if constexpr (dimension_of_v<DT> == 0 or dimension_of_v<DU> == 0)
256  return values::size_compares_with<dimension_of<DT>, dimension_of<DU>, comp, a>;
257  else if constexpr (dimension_of_v<DT> == stdex::dynamic_extent or dimension_of_v<DU> == stdex::dynamic_extent)
258  return a == applicability::permitted;
259  else if constexpr (compares_with_impl<DT, DU, &stdex::is_eq, a>())
260  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
261  else
262  return false;
263  }
264  else if constexpr (not values::fixed<dimension_of<T>>) // and values::fixed<dimension_of<U>>
265  {
266  using DT = stdex::ranges::range_value_t<T>;
267  if constexpr (euclidean_pattern<DT> and euclidean_pattern<U>)
268  {
269  return detail::do_comps<comp>(stdex::partial_ordering::greater);
270  }
271  else if constexpr (dimension_of_v<U> == 0)
272  {
273  if constexpr (dimension_of_v<DT> == stdex::dynamic_extent)
274  return detail::do_comps<comp, a == applicability::guaranteed>(
275  stdex::partial_ordering::greater, stdex::partial_ordering::equivalent);
276  else
277  return detail::do_comps<comp>(stdex::partial_ordering::greater);
278  }
279  else if constexpr (dimension_of_v<DT> == stdex::dynamic_extent)
280  {
281  return a == applicability::permitted;
282  }
283  else if constexpr (dimension_of_v<U> == stdex::dynamic_extent)
284  {
285  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
286  return true;
287  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
288  return compares_with_impl<DT, stdex::ranges::range_value_t<U>, &stdex::is_eq, a>();
289  else
290  return false;
291  }
292  else // U has a fixed dimension and size
293  {
294  return compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U> + 1, DT>, U, comp, a>();
295  }
296  }
297  else if constexpr (not values::fixed<dimension_of<U>>) // and values::fixed<dimension_of<T>>
298  {
299  using DU = stdex::ranges::range_value_t<U>;
300  if constexpr (euclidean_pattern<T> and euclidean_pattern<DU>)
301  {
302  return detail::do_comps<comp>(stdex::partial_ordering::less);
303  }
304  else if constexpr (not values::fixed<dimension_of<DU>>)
305  {
306  return a == applicability::permitted;
307  }
308  else if constexpr (dimension_of_v<T> == 0)
309  {
310  if constexpr (dimension_of_v<DU> == stdex::dynamic_extent)
311  return detail::do_comps<comp, a == applicability::guaranteed>(
312  stdex::partial_ordering::less, stdex::partial_ordering::equivalent);
313  else
314  return detail::do_comps<comp>(stdex::partial_ordering::less);
315  }
316  else if constexpr (dimension_of_v<DU> == stdex::dynamic_extent)
317  {
318  return a == applicability::permitted;
319  }
320  else if constexpr (dimension_of_v<T> == stdex::dynamic_extent)
321  {
322  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
323  return true;
324  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
325  return compares_with_impl<stdex::ranges::range_value_t<T>, DU, &stdex::is_eq, a>();
326  else
327  return false;
328  }
329  else // T has a fixed dimension and size
330  {
331  return compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T> + 1, DU>, comp, a>();
332  }
333  }
334 
338 
339  else if constexpr (dimension_of_v<T> == 0 and dimension_of_v<U> == 0)
340  {
341  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
342  }
343  else if constexpr (dimension_of_v<T> == 0 and collections::size_of_v<U> == stdex::dynamic_extent)
344  {
345  return detail::do_comps<comp, a == applicability::guaranteed>(stdex::partial_ordering::less, stdex::partial_ordering::equivalent);
346  }
347  else if constexpr (dimension_of_v<U> == 0 and collections::size_of_v<T> == stdex::dynamic_extent)
348  {
349  return detail::do_comps<comp, a == applicability::guaranteed>(stdex::partial_ordering::greater, stdex::partial_ordering::equivalent);
350  }
351  else if constexpr (collections::size_of_v<T> != stdex::dynamic_extent and collections::size_of_v<U> != stdex::dynamic_extent)
352  {
354  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
355  else
356  return detail::compares_with_iter<T, U, comp, a>();
357  }
358  else if constexpr (collections::size_of_v<T> != stdex::dynamic_extent) // collections::size_of_v<U> == stdex::dynamic_extent
359  {
360  using DU = stdex::ranges::range_value_t<U>;
361  if constexpr (dimension_of_v<DU> == 0)
362  {
363  return detail::do_comps<comp>(stdex::partial_ordering::greater);
364  }
365  else if constexpr (dimension_of_v<T> != stdex::dynamic_extent and dimension_of_v<DU> != stdex::dynamic_extent)
366  {
367  if constexpr (euclidean_pattern<T> and euclidean_pattern<DU>)
368  {
369  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
370  return a == applicability::permitted or dimension_of_v<T> % dimension_of_v<DU> != 0;
371  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less, stdex::partial_ordering::greater))
372  return a == applicability::permitted;
373  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::equivalent))
374  return a == applicability::permitted and dimension_of_v<T> % dimension_of_v<DU> == 0;
375  else
376  return a == applicability::permitted;
377  }
378  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
379  {
380  return a == applicability::permitted or
381  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, comp, a>();
382  }
383  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
384  {
385  return a == applicability::permitted;
386  }
387  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
388  {
389  return a == applicability::permitted and
390  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, &stdex::is_eq, a>();
391  }
392  else
393  {
394  return a == applicability::permitted and
395  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, comp, a>();
396  }
397  }
398  else
399  {
400  return a == applicability::permitted;
401  }
402  }
403  else if constexpr (collections::size_of_v<U> != stdex::dynamic_extent) // collections::size_of_v<T> == stdex::dynamic_extent
404  {
405  using DT = stdex::ranges::range_value_t<T>;
406  if constexpr (dimension_of_v<DT> == 0)
407  {
408  return detail::do_comps<comp>(stdex::partial_ordering::less);
409  }
410  else if constexpr (dimension_of_v<DT> != stdex::dynamic_extent and dimension_of_v<U> != stdex::dynamic_extent)
411  {
412  if constexpr (euclidean_pattern<DT> and euclidean_pattern<U>)
413  {
414  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
415  return a == applicability::permitted or dimension_of_v<U> % dimension_of_v<DT> != 0;
416  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less, stdex::partial_ordering::greater))
417  return a == applicability::permitted;
418  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::equivalent))
419  return a == applicability::permitted and dimension_of_v<U> % dimension_of_v<DT> == 0;
420  else
421  return a == applicability::permitted;
422  }
423  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
424  {
425  return a == applicability::permitted or
426  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, comp, a>();
427  }
428  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
429  {
430  return a == applicability::permitted;
431  }
432  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
433  {
434  return a == applicability::permitted and
435  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, &stdex::is_eq, a>();
436  }
437  else
438  {
439  return a == applicability::permitted and
440  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, comp, a>();
441  }
442  }
443  else
444  {
445  return a == applicability::permitted;
446  }
447  }
448  else // if constexpr (collections::size_of_v<T> == stdex::dynamic_extent and collections::size_of_v<U> == stdex::dynamic_extent)
449  {
450  return a == applicability::permitted;
451  }
452  }
453 
454  }
455 
456 
471  template<typename T, typename U, auto comp = &stdex::is_eq, applicability a = applicability::guaranteed>
472 #ifdef __cpp_concepts
473  concept compares_with =
474 #else
475  constexpr bool compares_with =
476 #endif
477  pattern<T> and pattern<U> and
478  std::is_invocable_r_v<bool, decltype(comp), stdex::partial_ordering> and
479  detail::compares_with_impl<T, U, comp, a>();
480 
481 
482 }
483 
484 #endif
Definition: comparison.hpp:104
Definition for coordinates::dynamic_pattern.
applicability
The applicability of a concept, trait, or restraint.
Definition: constants.hpp:35
The concept, trait, or restraint is permitted, but whether it applies is not necessarily known at com...
Definition: comparison.hpp:176
The size of a sized object (including a collection).
Definition: size_of.hpp:33
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definition for coordinates::pattern.
The size of a coordinates::pattern.
Definition: dimension_of.hpp:36
The namespace for features relating to coordinates::pattern object.
Definition: compares_with.hpp:25
Inclusion file for collections.
constexpr bool compares_with_impl()
Definition: compares_with.hpp:230
Definition of coordinates::compare_three_way.
constexpr bool fixed
T is a value that is determinable at compile time.
Definition: fixed.hpp:66
constexpr bool compares_with
Compares two coordinates::pattern objects.
Definition: compares_with.hpp:475
Definition for collections::common_descriptor_type.