blob: e15383ed5adc6911261a99347fd5526110b10d42 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_
#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_
#include <utility>
#include "base/check.h"
#include "components/performance_manager/public/graph/node_state.h"
namespace performance_manager {
// Helper classes for setting properties and invoking observer callbacks based
// on the value change. This is templated on the observer type to allow
// easy testing.
//
// Objects of NodeImplType are expected to fulfill the contract:
//
// IterableCollection GetObservers() const;
// bool NodeImplType::CanSetProperty() const;
// bool NodeImplType::CanSetAndNotifyProperty() const;
//
// These are used in DCHECKs to assert that properties are only being modified
// at appropriate moments. If your code is blowing up in one of these DCHECKS
// you are trying to change a property while a node is being added or removed
// from the graph. When adding to the graph property changes should be done in a
// separate posted task. When removing from the graph, they should simply not be
// done. See class comments on node observers, NodeState, and NodeBase for full
// details.
template <typename NodeImplType, typename NodeType, typename ObserverType>
class ObservedPropertyImpl {
public:
// Helper class for node properties that represent measurements that are taken
// periodically, and for which a notification should be sent every time a
// new sample is recorded, even if identical in value to the last.
template <typename PropertyType,
void (ObserverType::*NotifyFunctionPtr)(const NodeType*)>
class NotifiesAlways {
public:
NotifiesAlways() = default;
template <typename U = PropertyType>
explicit NotifiesAlways(U&& initial_value)
: value_(std::forward<U>(initial_value)) {}
~NotifiesAlways() = default;
// Sets the property and sends a notification.
template <typename U = PropertyType>
void SetAndNotify(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetAndNotifyProperty());
value_ = std::forward<U>(value);
for (auto* observer : node->GetObservers())
((observer)->*(NotifyFunctionPtr))(node);
}
// Sets the property without sending a notification.
template <typename U = PropertyType>
void Set(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetProperty());
value_ = std::forward<U>(value);
}
const PropertyType& value() const { return value_; }
private:
PropertyType value_;
};
// Helper class for node properties that represent states, for which
// notifications should only be sent when the value of the property actually
// changes. Calls to SetAndMaybeNotify do not notify if the provided value is
// the same as the current value.
template <typename PropertyType,
void (ObserverType::*NotifyFunctionPtr)(const NodeType*)>
class NotifiesOnlyOnChanges {
public:
NotifiesOnlyOnChanges() = default;
template <typename U = PropertyType>
explicit NotifiesOnlyOnChanges(U&& initial_value)
: value_(std::forward<U>(initial_value)) {}
~NotifiesOnlyOnChanges() = default;
// Sets the property and sends a notification if needed. Returns true if a
// notification was sent, false otherwise.
template <typename U = PropertyType>
bool SetAndMaybeNotify(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetAndNotifyProperty());
if (value_ == value)
return false;
value_ = std::forward<U>(value);
for (auto* observer : node->GetObservers())
((observer)->*(NotifyFunctionPtr))(node);
return true;
}
// Sets the property without sending a notification.
template <typename U = PropertyType>
void Set(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetProperty());
value_ = std::forward<U>(value);
}
const PropertyType& value() const { return value_; }
private:
PropertyType value_;
};
// Same as NotifiesOnlyOnChanges, but provides the previous value when
// notifying observers.
// TODO(chrisha): When C++17 is available, deduce PreviousValueType via use of
// an 'auto' placeholder non-type template parameter helper.
template <typename PropertyType,
typename PreviousValueType,
void (ObserverType::*NotifyFunctionPtr)(
const NodeType* node,
PreviousValueType previous_value)>
class NotifiesOnlyOnChangesWithPreviousValue {
public:
NotifiesOnlyOnChangesWithPreviousValue() = default;
template <typename U = PropertyType>
explicit NotifiesOnlyOnChangesWithPreviousValue(U&& initial_value)
: value_(std::forward<U>(initial_value)) {}
~NotifiesOnlyOnChangesWithPreviousValue() = default;
// Sets the property and sends a notification if needed. Returns true if a
// notification was sent, false otherwise.
template <typename U = PropertyType>
bool SetAndMaybeNotify(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetAndNotifyProperty());
if (value_ == value)
return false;
PropertyType previous_value = std::move(value_);
value_ = std::forward<U>(value);
for (auto* observer : node->GetObservers())
((observer)->*(NotifyFunctionPtr))(node, previous_value);
return true;
}
// Sets the property without sending a notification.
template <typename U = PropertyType>
void Set(NodeImplType* node, U&& value) {
// If your code is blowing up here see the class comment!
DCHECK(node->CanSetProperty());
value_ = std::forward<U>(value);
}
const PropertyType& value() const { return value_; }
private:
PropertyType value_;
};
};
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_PROPERTIES_H_