searchable.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*!
  2. @file
  3. Forward declares `boost::hana::Searchable`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
  9. #define BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP
  10. #include <boost/hana/config.hpp>
  11. namespace boost { namespace hana {
  12. //! @ingroup group-concepts
  13. //! @defgroup group-Searchable Searchable
  14. //! The `Searchable` concept represents structures that can be searched.
  15. //!
  16. //! Intuitively, a `Searchable` is any structure, finite or infinite,
  17. //! containing elements that can be searched using a predicate. Sometimes,
  18. //! `Searchable`s will associate keys to values; one can search for a key
  19. //! with a predicate, and the value associated to it is returned. This
  20. //! gives rise to map-like data structures. Other times, the elements of
  21. //! the structure that are searched (i.e. those to which the predicate is
  22. //! applied) are the same that are returned, which gives rise to set-like
  23. //! data structures. In general, we will refer to the _keys_ of a
  24. //! `Searchable` structure as those elements that are used for searching,
  25. //! and to the _values_ of a `Searchable` as those elements that are
  26. //! returned when a search is successful. As was explained, there is no
  27. //! requirement that both notions differ, and it is often useful to have
  28. //! keys and values coincide (think about `std::set`).
  29. //!
  30. //! Some methods like `any_of`, `all_of` and `none_of` allow simple queries
  31. //! to be performed on the keys of the structure, while other methods like
  32. //! `find` and `find_if` make it possible to find the value associated
  33. //! to a key. The most specific method should always be used if one
  34. //! cares about performance, because it is usually the case that heavy
  35. //! optimizations can be performed in more specific methods. For example,
  36. //! an associative data structure implemented as a hash table will be much
  37. //! faster to access using `find` than `find_if`, because in the second
  38. //! case it will have to do a linear search through all the entries.
  39. //! Similarly, using `contains` will likely be much faster than `any_of`
  40. //! with an equivalent predicate.
  41. //!
  42. //! > __Insight__\n
  43. //! > In a lazy evaluation context, any `Foldable` can also become a model
  44. //! > of `Searchable` because we can search lazily through the structure
  45. //! > with `fold_right`. However, in the context of C++, some `Searchable`s
  46. //! > can not be folded; think for example of an infinite set.
  47. //!
  48. //!
  49. //! Minimal complete definition
  50. //! ---------------------------
  51. //! `find_if` and `any_of`
  52. //!
  53. //! When `find_if` and `any_of` are provided, the other functions are
  54. //! implemented according to the laws explained below.
  55. //!
  56. //! @note
  57. //! We could implement `any_of(xs, pred)` by checking whether
  58. //! `find_if(xs, pred)` is an empty `optional` or not, and then reduce
  59. //! the minimal complete definition to `find_if`. However, this is not
  60. //! done because that implementation requires the predicate of `any_of`
  61. //! to return a compile-time `Logical`, which is more restrictive than
  62. //! what we have right now.
  63. //!
  64. //!
  65. //! Laws
  66. //! ----
  67. //! In order for the semantics of the methods to be consistent, some
  68. //! properties must be satisfied by any model of the `Searchable` concept.
  69. //! Rigorously, for any `Searchable`s `xs` and `ys` and any predicate `p`,
  70. //! the following laws should be satisfied:
  71. //! @code
  72. //! any_of(xs, p) <=> !all_of(xs, negated p)
  73. //! <=> !none_of(xs, p)
  74. //!
  75. //! contains(xs, x) <=> any_of(xs, equal.to(x))
  76. //!
  77. //! find(xs, x) == find_if(xs, equal.to(x))
  78. //! find_if(xs, always(false_)) == nothing
  79. //!
  80. //! is_subset(xs, ys) <=> all_of(xs, [](auto x) { return contains(ys, x); })
  81. //! is_disjoint(xs, ys) <=> none_of(xs, [](auto x) { return contains(ys, x); })
  82. //! @endcode
  83. //!
  84. //! Additionally, if all the keys of the `Searchable` are `Logical`s,
  85. //! the following laws should be satisfied:
  86. //! @code
  87. //! any(xs) <=> any_of(xs, id)
  88. //! all(xs) <=> all_of(xs, id)
  89. //! none(xs) <=> none_of(xs, id)
  90. //! @endcode
  91. //!
  92. //!
  93. //! Concrete models
  94. //! ---------------
  95. //! `hana::map`, `hana::optional`, `hana::range`, `hana::set`,
  96. //! `hana::string`, `hana::tuple`
  97. //!
  98. //!
  99. //! Free model for builtin arrays
  100. //! -----------------------------
  101. //! Builtin arrays whose size is known can be searched as-if they were
  102. //! homogeneous tuples. However, since arrays can only hold objects of
  103. //! a single type and the predicate to `find_if` must return a compile-time
  104. //! `Logical`, the `find_if` method is fairly useless. For similar reasons,
  105. //! the `find` method is also fairly useless. This model is provided mainly
  106. //! because of the `any_of` method & friends, which are both useful and
  107. //! compile-time efficient.
  108. //!
  109. //!
  110. //! Structure preserving functions
  111. //! ------------------------------
  112. //! Given two `Searchables` `S1` and `S2`, a function
  113. //! @f$ f : S_1(X) \to S_2(X) @f$ is said to preserve the `Searchable`
  114. //! structure if for all `xs` of data type `S1(X)` and predicates
  115. //! @f$ \mathtt{pred} : X \to Bool @f$ (for a `Logical` `Bool`),
  116. //! @code
  117. //! any_of(xs, pred) if and only if any_of(f(xs), pred)
  118. //! find_if(xs, pred) == find_if(f(xs), pred)
  119. //! @endcode
  120. //!
  121. //! This is really just a generalization of the following, more intuitive
  122. //! requirements. For all `xs` of data type `S1(X)` and `x` of data type
  123. //! `X`,
  124. //! @code
  125. //! x ^in^ xs if and only if x ^in^ f(xs)
  126. //! find(xs, x) == find(f(xs), x)
  127. //! @endcode
  128. //!
  129. //! These requirements can be understood as saying that `f` does not
  130. //! change the content of `xs`, although it may reorder elements.
  131. //! As usual, such a structure-preserving transformation is said to
  132. //! be an embedding if it is also injective, i.e. if it is a lossless
  133. //! transformation.
  134. template <typename S>
  135. struct Searchable;
  136. }} // end namespace boost::hana
  137. #endif // !BOOST_HANA_FWD_CONCEPT_SEARCHABLE_HPP