initializer.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright (c) 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_
  5. #define BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_
  6. #include "base/allocator/dispatcher/configuration.h"
  7. #include "base/allocator/dispatcher/dispatcher.h"
  8. #include "base/allocator/dispatcher/internal/tools.h"
  9. #include <tuple>
  10. #include <utility>
  11. namespace base::allocator::dispatcher {
  12. namespace internal {
  13. // Filter the passed observers and perform initialization of the passed
  14. // dispatcher.
  15. template <size_t CurrentIndex,
  16. typename DispatcherType,
  17. typename CheckObserverPredicate,
  18. typename VerifiedObservers,
  19. typename UnverifiedObservers,
  20. size_t... IndicesToSelect>
  21. inline void DoInitialize(DispatcherType& dispatcher,
  22. CheckObserverPredicate check_observer,
  23. const VerifiedObservers& verified_observers,
  24. const UnverifiedObservers& unverified_observers,
  25. std::index_sequence<IndicesToSelect...> indices) {
  26. if constexpr (CurrentIndex < std::tuple_size<UnverifiedObservers>::value) {
  27. // We still have some items left to handle.
  28. if (check_observer(std::get<CurrentIndex>(unverified_observers))) {
  29. // The current observer is valid. Hence, append the index of the current
  30. // item to the set of indices and head on to the next item.
  31. DoInitialize<CurrentIndex + 1>(
  32. dispatcher, check_observer, verified_observers, unverified_observers,
  33. std::index_sequence<IndicesToSelect..., CurrentIndex>{});
  34. } else {
  35. // The current observer is not valid. Hence, head on to the next item with
  36. // an unaltered list of indices.
  37. DoInitialize<CurrentIndex + 1>(dispatcher, check_observer,
  38. verified_observers, unverified_observers,
  39. indices);
  40. }
  41. } else if constexpr (CurrentIndex ==
  42. std::tuple_size<UnverifiedObservers>::value) {
  43. // So we have met the end of the tuple of observers to verify.
  44. // Hence, we extract the additional valid observers, append to the tuple of
  45. // already verified observers and hand over to the dispatcher.
  46. auto observers = std::tuple_cat(
  47. verified_observers,
  48. std::make_tuple(std::get<IndicesToSelect>(unverified_observers)...));
  49. // Do a final check that neither the maximum total number of observers nor
  50. // the maximum number of optional observers is exceeded.
  51. static_assert(std::tuple_size<decltype(observers)>::value <=
  52. configuration::kMaximumNumberOfObservers);
  53. static_assert(sizeof...(IndicesToSelect) <=
  54. configuration::kMaximumNumberOfOptionalObservers);
  55. dispatcher.Initialize(std::move(observers));
  56. }
  57. }
  58. } // namespace internal
  59. // The result of concatenating two tuple-types.
  60. template <typename... tuples>
  61. using TupleCat = decltype(std::tuple_cat(std::declval<tuples>()...));
  62. // Initializer collects mandatory and optional observers and initializes the
  63. // passed Dispatcher with only the enabled observers.
  64. //
  65. // In some situations, presence of observers depends on runtime. i.e. command
  66. // line parameters or CPU features. With 3 optional observers we already have 8
  67. // different combinations. Initializer takes the job of dealing with all
  68. // combinations from the user. It allows users to pass all observers (including
  69. // nullptr for disabled optional observers) and initializes the Dispatcher with
  70. // only the enabled observers.
  71. //
  72. // Since this process results in a combinatoric explosion, Initializer
  73. // distinguishes between optional and mandatory observers. Mandatory observers
  74. // are not included in the filtering process and must always be enabled (not
  75. // nullptr).
  76. //
  77. // To allow the Initializer to track the number and exact type of observers, it
  78. // is implemented as a templated class which holds information on the types in
  79. // the std::tuples passed as template parameters. Therefore, whenever any type
  80. // observer it set, the initializer changes its type to reflect this.
  81. template <typename MandatoryObservers = std::tuple<>,
  82. typename OptionalObservers = std::tuple<>>
  83. struct BASE_EXPORT Initializer {
  84. Initializer() = default;
  85. Initializer(MandatoryObservers mandatory_observers,
  86. OptionalObservers optional_observers)
  87. : mandatory_observers_(std::move(mandatory_observers)),
  88. optional_observers_(std::move(optional_observers)) {}
  89. // Set the mandatory observers. The number of observers that can be set is
  90. // limited by configuration::maximum_number_of_observers.
  91. template <typename... NewMandatoryObservers,
  92. std::enable_if_t<
  93. internal::LessEqual((sizeof...(NewMandatoryObservers) +
  94. std::tuple_size<OptionalObservers>::value),
  95. configuration::kMaximumNumberOfObservers),
  96. bool> = true>
  97. Initializer<std::tuple<NewMandatoryObservers*...>, OptionalObservers>
  98. SetMandatoryObservers(NewMandatoryObservers*... mandatory_observers) const {
  99. return {std::make_tuple(mandatory_observers...), GetOptionalObservers()};
  100. }
  101. // Add mandatory observers. The number of observers that can be added is
  102. // limited by the current number of observers, see
  103. // configuration::maximum_number_of_observers.
  104. template <typename... AdditionalMandatoryObservers,
  105. std::enable_if_t<internal::LessEqual(
  106. std::tuple_size<MandatoryObservers>::value +
  107. sizeof...(AdditionalMandatoryObservers) +
  108. std::tuple_size<OptionalObservers>::value,
  109. configuration::kMaximumNumberOfObservers),
  110. bool> = true>
  111. Initializer<TupleCat<MandatoryObservers,
  112. std::tuple<AdditionalMandatoryObservers*...>>,
  113. OptionalObservers>
  114. AddMandatoryObservers(
  115. AdditionalMandatoryObservers*... additional_mandatory_observers) const {
  116. return {std::tuple_cat(GetMandatoryObservers(),
  117. std::make_tuple(additional_mandatory_observers...)),
  118. GetOptionalObservers()};
  119. }
  120. // Set the optional observers. The number of observers that can be set is
  121. // limited by configuration::maximum_number_of_optional_observers as well as
  122. // configuration::maximum_number_of_observers.
  123. template <
  124. typename... NewOptionalObservers,
  125. std::enable_if_t<
  126. internal::LessEqual(
  127. sizeof...(NewOptionalObservers),
  128. configuration::kMaximumNumberOfOptionalObservers) &&
  129. internal::LessEqual((sizeof...(NewOptionalObservers) +
  130. std::tuple_size<MandatoryObservers>::value),
  131. configuration::kMaximumNumberOfObservers),
  132. bool> = true>
  133. Initializer<MandatoryObservers, std::tuple<NewOptionalObservers*...>>
  134. SetOptionalObservers(NewOptionalObservers*... optional_observers) const {
  135. return {GetMandatoryObservers(), std::make_tuple(optional_observers...)};
  136. }
  137. // Add optional observers. The number of observers that can be added is
  138. // limited by the current number of optional observers,
  139. // configuration::maximum_number_of_optional_observers as well as
  140. // configuration::maximum_number_of_observers.
  141. template <
  142. typename... AdditionalOptionalObservers,
  143. std::enable_if_t<
  144. internal::LessEqual(
  145. std::tuple_size<OptionalObservers>::value +
  146. sizeof...(AdditionalOptionalObservers),
  147. configuration::kMaximumNumberOfOptionalObservers) &&
  148. internal::LessEqual((std::tuple_size<OptionalObservers>::value +
  149. sizeof...(AdditionalOptionalObservers) +
  150. std::tuple_size<MandatoryObservers>::value),
  151. configuration::kMaximumNumberOfObservers),
  152. bool> = true>
  153. Initializer<
  154. MandatoryObservers,
  155. TupleCat<OptionalObservers, std::tuple<AdditionalOptionalObservers*...>>>
  156. AddOptionalObservers(
  157. AdditionalOptionalObservers*... additional_optional_observers) const {
  158. return {GetMandatoryObservers(),
  159. std::tuple_cat(GetOptionalObservers(),
  160. std::make_tuple(additional_optional_observers...))};
  161. }
  162. // Perform the actual initialization on the passed dispatcher.
  163. // The dispatcher is passed as a template only to provide better testability.
  164. template <typename DispatcherType>
  165. void DoInitialize(DispatcherType& dispatcher) const {
  166. internal::DoInitialize<0>(dispatcher, internal::IsValidObserver{},
  167. GetMandatoryObservers(), GetOptionalObservers(),
  168. {});
  169. }
  170. const MandatoryObservers& GetMandatoryObservers() const {
  171. return mandatory_observers_;
  172. }
  173. const OptionalObservers& GetOptionalObservers() const {
  174. return optional_observers_;
  175. }
  176. private:
  177. MandatoryObservers mandatory_observers_;
  178. OptionalObservers optional_observers_;
  179. };
  180. // Convenience function for creating an empty Initializer.
  181. inline Initializer<> CreateInitializer() {
  182. return {};
  183. }
  184. } // namespace base::allocator::dispatcher
  185. #endif // BASE_ALLOCATOR_DISPATCHER_INITIALIZER_H_