properties.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright 2019 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 COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_
  5. #define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "components/performance_manager/public/graph/node_state.h"
  9. namespace performance_manager {
  10. // Helper classes for setting properties and invoking observer callbacks based
  11. // on the value change. This is templated on the observer type to allow
  12. // easy testing.
  13. //
  14. // Objects of NodeImplType are expected to fulfill the contract:
  15. //
  16. // IterableCollection GetObservers() const;
  17. // bool NodeImplType::CanSetProperty() const;
  18. // bool NodeImplType::CanSetAndNotifyProperty() const;
  19. //
  20. // These are used in DCHECKs to assert that properties are only being modified
  21. // at appropriate moments. If your code is blowing up in one of these DCHECKS
  22. // you are trying to change a property while a node is being added or removed
  23. // from the graph. When adding to the graph property changes should be done in a
  24. // separate posted task. When removing from the graph, they should simply not be
  25. // done. See class comments on node observers, NodeState, and NodeBase for full
  26. // details.
  27. template <typename NodeImplType, typename NodeType, typename ObserverType>
  28. class ObservedPropertyImpl {
  29. public:
  30. // Helper class for node properties that represent measurements that are taken
  31. // periodically, and for which a notification should be sent every time a
  32. // new sample is recorded, even if identical in value to the last.
  33. template <typename PropertyType,
  34. void (ObserverType::*NotifyFunctionPtr)(const NodeType*)>
  35. class NotifiesAlways {
  36. public:
  37. NotifiesAlways() = default;
  38. template <typename U = PropertyType>
  39. explicit NotifiesAlways(U&& initial_value)
  40. : value_(std::forward<U>(initial_value)) {}
  41. ~NotifiesAlways() = default;
  42. // Sets the property and sends a notification.
  43. template <typename U = PropertyType>
  44. void SetAndNotify(NodeImplType* node, U&& value) {
  45. // If your code is blowing up here see the class comment!
  46. DCHECK(node->CanSetAndNotifyProperty());
  47. value_ = std::forward<U>(value);
  48. for (auto* observer : node->GetObservers())
  49. ((observer)->*(NotifyFunctionPtr))(node);
  50. }
  51. // Sets the property without sending a notification.
  52. template <typename U = PropertyType>
  53. void Set(NodeImplType* node, U&& value) {
  54. // If your code is blowing up here see the class comment!
  55. DCHECK(node->CanSetProperty());
  56. value_ = std::forward<U>(value);
  57. }
  58. const PropertyType& value() const { return value_; }
  59. private:
  60. PropertyType value_;
  61. };
  62. // Helper class for node properties that represent states, for which
  63. // notifications should only be sent when the value of the property actually
  64. // changes. Calls to SetAndMaybeNotify do not notify if the provided value is
  65. // the same as the current value.
  66. template <typename PropertyType,
  67. void (ObserverType::*NotifyFunctionPtr)(const NodeType*)>
  68. class NotifiesOnlyOnChanges {
  69. public:
  70. NotifiesOnlyOnChanges() = default;
  71. template <typename U = PropertyType>
  72. explicit NotifiesOnlyOnChanges(U&& initial_value)
  73. : value_(std::forward<U>(initial_value)) {}
  74. ~NotifiesOnlyOnChanges() = default;
  75. // Sets the property and sends a notification if needed. Returns true if a
  76. // notification was sent, false otherwise.
  77. template <typename U = PropertyType>
  78. bool SetAndMaybeNotify(NodeImplType* node, U&& value) {
  79. // If your code is blowing up here see the class comment!
  80. DCHECK(node->CanSetAndNotifyProperty());
  81. if (value_ == value)
  82. return false;
  83. value_ = std::forward<U>(value);
  84. for (auto* observer : node->GetObservers())
  85. ((observer)->*(NotifyFunctionPtr))(node);
  86. return true;
  87. }
  88. // Sets the property without sending a notification.
  89. template <typename U = PropertyType>
  90. void Set(NodeImplType* node, U&& value) {
  91. // If your code is blowing up here see the class comment!
  92. DCHECK(node->CanSetProperty());
  93. value_ = std::forward<U>(value);
  94. }
  95. const PropertyType& value() const { return value_; }
  96. private:
  97. PropertyType value_;
  98. };
  99. // Same as NotifiesOnlyOnChanges, but provides the previous value when
  100. // notifying observers.
  101. // TODO(chrisha): When C++17 is available, deduce PreviousValueType via use of
  102. // an 'auto' placeholder non-type template parameter helper.
  103. template <typename PropertyType,
  104. typename PreviousValueType,
  105. void (ObserverType::*NotifyFunctionPtr)(
  106. const NodeType* node,
  107. PreviousValueType previous_value)>
  108. class NotifiesOnlyOnChangesWithPreviousValue {
  109. public:
  110. NotifiesOnlyOnChangesWithPreviousValue() = default;
  111. template <typename U = PropertyType>
  112. explicit NotifiesOnlyOnChangesWithPreviousValue(U&& initial_value)
  113. : value_(std::forward<U>(initial_value)) {}
  114. ~NotifiesOnlyOnChangesWithPreviousValue() = default;
  115. // Sets the property and sends a notification if needed. Returns true if a
  116. // notification was sent, false otherwise.
  117. template <typename U = PropertyType>
  118. bool SetAndMaybeNotify(NodeImplType* node, U&& value) {
  119. // If your code is blowing up here see the class comment!
  120. DCHECK(node->CanSetAndNotifyProperty());
  121. if (value_ == value)
  122. return false;
  123. PropertyType previous_value = std::move(value_);
  124. value_ = std::forward<U>(value);
  125. for (auto* observer : node->GetObservers())
  126. ((observer)->*(NotifyFunctionPtr))(node, previous_value);
  127. return true;
  128. }
  129. // Sets the property without sending a notification.
  130. template <typename U = PropertyType>
  131. void Set(NodeImplType* node, U&& value) {
  132. // If your code is blowing up here see the class comment!
  133. DCHECK(node->CanSetProperty());
  134. value_ = std::forward<U>(value);
  135. }
  136. const PropertyType& value() const { return value_; }
  137. private:
  138. PropertyType value_;
  139. };
  140. };
  141. } // namespace performance_manager
  142. #endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_