task_traits_extension.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2018 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_TASK_TASK_TRAITS_EXTENSION_H_
  5. #define BASE_TASK_TASK_TRAITS_EXTENSION_H_
  6. #include <stdint.h>
  7. #include <array>
  8. #include <tuple>
  9. #include <utility>
  10. #include "base/base_export.h"
  11. #include "base/traits_bag.h"
  12. namespace base {
  13. // Embedders can attach additional traits to a TaskTraits object in a way that
  14. // is opaque to base. These extension traits can then be specified along the
  15. // base traits when constructing the TaskTraits object. They are then stored and
  16. // propagated with the TaskTraits object.
  17. //
  18. // To support constexpr-compatible construction, extension traits are stored in
  19. // a fixed-size byte array in the TaskTraits object and serialized into and
  20. // parsed from this storage by an embedder-provided extension class and
  21. // MakeTaskTraitsExtension() template function. The embedder can later access
  22. // the extension traits via TaskTraits::GetExtension<[ExtensionClass]>().
  23. //
  24. // A TaskTraits extension class needs to specify publicly:
  25. // (1) -- static constexpr uint8_t kExtensionId.
  26. // This field's value identifies the type of the extension uniquely within
  27. // each process. The embedder is responsible for ensuring uniqueness and
  28. // can assign values between kFirstEmbedderExtensionId and kMaxExtensionId
  29. // of TaskTraitsExtensionStorage::ExtensionId.
  30. // (2) -- static const [ExtensionClass] Parse(
  31. // -- const base::TaskTraitsExtensionStorage& extension).
  32. // Parses and constructs an extension object from the provided storage.
  33. //
  34. // For each TaskTraits extension class, the embedder has to provide a
  35. // corresponding MakeTaskTraitsExtension definition inside the same namespace
  36. // as its extension traits:
  37. // (3) -- template <...>
  38. // -- constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
  39. // -- ArgTypes... args).
  40. // Constructs and serializes an extension with the given arguments into
  41. // a TaskTraitsExtensionStorage and returns it. When the extension is used,
  42. // all traits, including the base ones, are passed to this function in
  43. // order make sure TaskTraits constructor only participates in overload
  44. // resolution if all traits are valid. As such, this function should only
  45. // accept valid task traits recognised by the extension and the base task
  46. // traits.
  47. //
  48. // EXAMPLE (see also base/task/test_task_traits_extension.h):
  49. // --------
  50. //
  51. // namespace my_embedder {
  52. // enum class MyExtensionTrait {kMyValue1, kMyValue2};
  53. //
  54. // class MyTaskTraitsExtension {
  55. // public:
  56. // static constexpr uint8_t kExtensionId =
  57. // TaskTraitsExtensionStorage::kFirstEmbedderExtensionId;
  58. //
  59. // struct ValidTrait : public TaskTraits::ValidTrait {
  60. // // Accept base traits in MakeTaskTraitsExtension (see above).
  61. // using TaskTraits::ValidTrait::ValidTrait;
  62. //
  63. // ValidTrait(MyExtensionTrait);
  64. // };
  65. //
  66. // using MyExtensionTraitFilter =
  67. // trait_helpers::EnumTraitFilter<MyExtensionTrait, MyExtensionTrait::kA>;
  68. //
  69. // // Constructor that accepts only valid traits as specified by ValidTraits.
  70. // template <class... ArgTypes,
  71. // class CheckArgumentsAreValid = std::enable_if_t<
  72. // base::trait_helpers::AreValidTraits<
  73. // ValidTrait, ArgTypes...>::value>>
  74. // constexpr MyTaskTraitsExtension(ArgTypes... args)
  75. // : my_trait_(trait_helpers::GetTraitFromArgList<MyExtensionTraitFilter>(
  76. // args...)) {}
  77. //
  78. // // Serializes MyTaskTraitsExtension into a storage object and returns it.
  79. // constexpr base::TaskTraitsExtensionStorage Serialize() const {
  80. // // Note: can't use reinterpret_cast or placement new because neither are
  81. // // constexpr-compatible.
  82. // return {kExtensionId, {{static_cast<uint8_t>(my_trait_)}}};
  83. // }
  84. //
  85. // // Creates a MyTaskTraitsExtension by parsing it from a storage object.
  86. // static const MyTaskTraitsExtension Parse(
  87. // const base::TaskTraitsExtensionStorage& extension) {
  88. // return MyTaskTraitsExtension(
  89. // static_cast<MyExtensionTrait>(extension.data[0]));
  90. // }
  91. //
  92. // constexpr MyExtensionTrait my_trait() const { return my_trait_; }
  93. //
  94. // private:
  95. // MyExtensionTrait my_trait_;
  96. // };
  97. //
  98. // // Creates a MyTaskTraitsExtension for the provided |args| and serializes it
  99. // // into |extension|. Accepts only valid arguments for the
  100. // // MyTaskTraitsExtension() constructor.
  101. // template <class... ArgTypes,
  102. // class = std::enable_if_t<
  103. // base::trait_helpers::AreValidTraits<
  104. // MyTaskTraitsExtension::ValidTrait, ArgTypes...>::value>>
  105. // constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
  106. // ArgTypes... args) {
  107. // return MyTaskTraitsExtension(args...).Serialize();
  108. // }
  109. // } // namespace my_embedder
  110. //
  111. // // Construction of TaskTraits with extension traits.
  112. // constexpr TaskTraits t1 = {my_embedder::MyExtensionTrait::kValueB};
  113. // constexpr TaskTraits t2 = {base::MayBlock(),
  114. // my_embedder::MyExtensionTrait::kValueA};
  115. //
  116. // // Extension traits can also be specified directly when posting a task.
  117. // base::PostTask(FROM_HERE,
  118. // {my_embedder::MyExtensionTrait::kValueB},
  119. // base::BindOnce(...));
  120. // Stores extension traits opaquely inside a fixed-size data array. We store
  121. // this data directly (rather than in a separate object on the heap) to support
  122. // constexpr-compatible TaskTraits construction.
  123. struct BASE_EXPORT TaskTraitsExtensionStorage {
  124. // Size in bytes.
  125. // Keep in sync with org.chromium.base.task.TaskTraits.EXTENSION_STORAGE_SIZE
  126. static constexpr size_t kStorageSize = 8;
  127. inline constexpr TaskTraitsExtensionStorage();
  128. inline constexpr TaskTraitsExtensionStorage(
  129. uint8_t extension_id_in,
  130. const std::array<uint8_t, kStorageSize>& data_in);
  131. inline constexpr TaskTraitsExtensionStorage(
  132. uint8_t extension_id_in,
  133. std::array<uint8_t, kStorageSize>&& data_in);
  134. inline constexpr TaskTraitsExtensionStorage(
  135. const TaskTraitsExtensionStorage& other);
  136. inline TaskTraitsExtensionStorage& operator=(
  137. const TaskTraitsExtensionStorage& other) = default;
  138. inline bool operator==(const TaskTraitsExtensionStorage& other) const;
  139. enum ExtensionId : uint8_t {
  140. // Keep in sync with org.chromium.base.task.TaskTraits.INVALID_EXTENSION_ID
  141. kInvalidExtensionId = 0,
  142. // The embedder is responsible for assigning the remaining values uniquely.
  143. kFirstEmbedderExtensionId = 1,
  144. // Maximum number of extension types is artificially limited to support
  145. // super efficient TaskExecutor lookup in post_task.cc.
  146. // Keep in sync with org.chromium.base.TaskTraits.MAX_EXTENSION_ID
  147. kMaxExtensionId = 4
  148. };
  149. // Identifies the type of extension. See ExtensionId enum above.
  150. uint8_t extension_id;
  151. // Serialized extension data.
  152. std::array<uint8_t, kStorageSize> data;
  153. };
  154. // TODO(https://crbug.com/874482): These constructors need to be "inline" but
  155. // defined outside the class above, because the chromium-style clang plugin
  156. // doesn't exempt constexpr constructors at the moment.
  157. inline constexpr TaskTraitsExtensionStorage::TaskTraitsExtensionStorage()
  158. : extension_id(kInvalidExtensionId), data{} {}
  159. inline constexpr TaskTraitsExtensionStorage::TaskTraitsExtensionStorage(
  160. uint8_t extension_id_in,
  161. const std::array<uint8_t, kStorageSize>& data_in)
  162. : extension_id(extension_id_in), data(data_in) {}
  163. inline constexpr TaskTraitsExtensionStorage::TaskTraitsExtensionStorage(
  164. uint8_t extension_id_in,
  165. std::array<uint8_t, kStorageSize>&& data_in)
  166. : extension_id(extension_id_in), data(std::move(data_in)) {}
  167. inline constexpr TaskTraitsExtensionStorage::TaskTraitsExtensionStorage(
  168. const TaskTraitsExtensionStorage& other) = default;
  169. namespace trait_helpers {
  170. // Helper class whose constructor tests if an extension accepts a list of
  171. // argument types.
  172. struct TaskTraitsExtension {
  173. template <class... ArgTypes,
  174. class CheckCanMakeExtension =
  175. decltype(MakeTaskTraitsExtension(std::declval<ArgTypes>()...))>
  176. constexpr TaskTraitsExtension(ArgTypes... args) {}
  177. };
  178. // Tests that that a trait extension accepts all |ArgsTypes...|.
  179. template <class... ArgTypes>
  180. using AreValidTraitsForExtension =
  181. std::is_constructible<TaskTraitsExtension, ArgTypes...>;
  182. // Helper function that returns the TaskTraitsExtensionStorage of a
  183. // serialized extension created with |args...| if there are arguments that are
  184. // not valid base traits, or a default constructed TaskTraitsExtensionStorage
  185. // otherwise.
  186. template <class... ArgTypes>
  187. constexpr TaskTraitsExtensionStorage GetTaskTraitsExtension(
  188. std::true_type base_traits,
  189. ArgTypes... args) {
  190. return TaskTraitsExtensionStorage();
  191. }
  192. template <class... ArgTypes>
  193. constexpr TaskTraitsExtensionStorage GetTaskTraitsExtension(
  194. std::false_type base_traits,
  195. ArgTypes... args) {
  196. return MakeTaskTraitsExtension(args...);
  197. }
  198. } // namespace trait_helpers
  199. // TODO(eseckler): Default the comparison operator once C++20 arrives.
  200. inline bool TaskTraitsExtensionStorage::operator==(
  201. const TaskTraitsExtensionStorage& other) const {
  202. static_assert(
  203. 9 == sizeof(TaskTraitsExtensionStorage),
  204. "Update comparison operator when TaskTraitsExtensionStorage changes");
  205. return extension_id == other.extension_id && data == other.data;
  206. }
  207. } // namespace base
  208. #endif // BASE_TASK_TASK_TRAITS_EXTENSION_H_