2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <folly/ThreadLocal.h>
19 #include <folly/experimental/observer/detail/Core.h>
20 #include <folly/experimental/observer/detail/Observer-pre.h>
26 * Observer - a library which lets you create objects which track updates of
27 * their dependencies and get re-computed when any of the dependencies changes.
30 * Given an Observer, you can get a snapshot of the current version of the
33 * Observer<int> myObserver = ...;
34 * Snapshot<int> mySnapshot = myObserver.getSnapshot();
36 * Snapshot<int> mySnapshot = *myObserver;
38 * Snapshot will hold a view of the object, even if object in the Observer
42 * What makes Observer powerful is its ability to track updates to other
43 * Observers. Imagine we have two separate Observers A and B which hold
46 * Observer<int> observerA = ...;
47 * Observer<int> observerB = ...;
49 * To compute a sum of A and B we can create a new Observer which would track
50 * updates to A and B and re-compute the sum only when necessary.
52 * Observer<int> sumObserver = makeObserver(
53 * [observerA, observerB] {
54 * int a = **observerA;
55 * int b = **observerB;
59 * int sum = **sumObserver;
61 * Notice that a + b will be only called when either a or b is changed. Getting
62 * a snapshot from sumObserver won't trigger any re-computation.
65 * TLObserver is very similar to Observer, but it also keeps a thread-local
66 * cache for the observed object.
68 * Observer<int> observer = ...;
69 * TLObserver<int> tlObserver(observer);
70 * auto& snapshot = *tlObserver;
73 * See ObserverCreator class if you want to wrap any existing subscription API
74 * in an Observer object.
82 const T& operator*() const {
86 const T* operator->() const {
90 const T* get() const {
95 * Return the version of the observed object.
97 size_t getVersion() const {
102 friend class Observer<T>;
105 const observer_detail::Core& core,
106 std::shared_ptr<const T> data,
108 : data_(std::move(data)), version_(version), core_(&core) {
112 std::shared_ptr<const T> data_;
114 const observer_detail::Core* core_;
117 template <typename T>
120 explicit Observer(observer_detail::Core::Ptr core);
122 Snapshot<T> getSnapshot() const;
123 Snapshot<T> operator*() const {
124 return getSnapshot();
128 * Check if we have a newer version of the observed object than the snapshot.
129 * Snapshot should have been originally from this Observer.
131 bool needRefresh(const Snapshot<T>& snapshot) const {
132 DCHECK_EQ(core_.get(), snapshot.core_);
133 return snapshot.getVersion() < core_->getVersionLastChange();
137 template <typename Observable, typename Traits>
138 friend class ObserverCreator;
140 observer_detail::Core::Ptr core_;
144 * makeObserver(...) creates a new Observer<T> object given a functor to
145 * compute it. The functor can return T or std::shared_ptr<const T>.
147 * makeObserver(...) blocks until the initial version of Observer is computed.
148 * If creator functor fails (throws or returns a nullptr) during this first
149 * call, the exception is re-thrown by makeObserver(...).
151 * For all subsequent updates if creator functor fails (throws or returs a
152 * nullptr), the Observer (and all its dependents) is not updated.
154 template <typename F>
155 Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator);
157 template <typename F>
158 Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(F&& creator);
160 template <typename T>
163 explicit TLObserver(Observer<T> observer);
164 TLObserver(const TLObserver<T>& other);
166 const Snapshot<T>& getSnapshotRef() const;
167 const Snapshot<T>& operator*() const {
168 return getSnapshotRef();
172 Observer<T> observer_;
173 folly::ThreadLocal<Snapshot<T>> snapshot_;
177 * Same as makeObserver(...), but creates TLObserver.
179 template <typename T>
180 TLObserver<T> makeTLObserver(Observer<T> observer) {
181 return TLObserver<T>(std::move(observer));
184 template <typename F>
185 auto makeTLObserver(F&& creator) {
186 return makeTLObserver(makeObserver(std::forward<F>(creator)));
189 template <typename T, bool CacheInThreadLocal>
190 struct ObserverTraits {};
192 template <typename T>
193 struct ObserverTraits<T, false> {
194 using type = Observer<T>;
197 template <typename T>
198 struct ObserverTraits<T, true> {
199 using type = TLObserver<T>;
202 template <typename T, bool CacheInThreadLocal>
203 using ObserverT = typename ObserverTraits<T, CacheInThreadLocal>::type;
207 #include <folly/experimental/observer/Observer-inl.h>