blob: 20f86756aeb6a314efb6f783dc23c9dd1fc5265a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PERIDOT_BIN_LEDGER_CACHE_LAZY_VALUE_H_
#define PERIDOT_BIN_LEDGER_CACHE_LAZY_VALUE_H_
#include <functional>
#include <vector>
#include <lib/fit/function.h>
namespace cache {
// Implements a self-populating lazy value.
//
// This class allows to setup a lazy value that will be generated asynchronously
// the first time it is requested.
//
// V is the type of the lazy value. V must be default-constructible and either
// copyable or movable.
// S is the type of the success status for the data generator.
template <typename V, typename S>
class LazyValue {
public:
// Constructor.
//
// |ok_status| is the success status of the generator.
// |generator| generates the value. It takes a callback to returns its result.
// It must return |ok_status| as a status when the request is successful.
// Any other return value is considered a failure.
LazyValue(S ok_status,
fit::function<void(fit::function<void(S, V)>)> generator)
: ok_status_(ok_status),
generator_(std::move(generator)),
value_set_(false) {}
// Retrieves the value and returns it to |callback|.
//
// If the value is cached, |callback| will be called synchronously. Otherwise,
// |generator| will be called, and depending on its implementation, |callback|
// might be called synchronously or not.
void Get(fit::function<void(S, const V&)> callback) {
if (value_set_) {
callback(ok_status_, value_);
return;
}
requests_.push_back(std::move(callback));
if (requests_.size() == 1) {
generator_([this](S status, V value) {
auto callbacks = std::move(requests_);
requests_.clear();
if (status == ok_status_) {
value_ = std::move(value);
value_set_ = true;
}
for (const auto& callback : callbacks) {
callback(status, value_);
}
});
}
}
private:
S ok_status_;
fit::function<void(fit::function<void(S, V)>)> generator_;
V value_;
bool value_set_;
std::vector<fit::function<void(S, const V&)>> requests_;
};
} // namespace cache
#endif // PERIDOT_BIN_LEDGER_CACHE_LAZY_VALUE_H_