blob: ef54e140a1559e9ab426f9dd486f4ad165a3fe0d [file] [log] [blame]
// Copyright 2020 The Chromium 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 CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_SHARED_VECTOR_H_
#define CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_SHARED_VECTOR_H_
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/policy/messaging_layer/util/status.h"
#include "chrome/browser/policy/messaging_layer/util/statusor.h"
namespace reporting {
// SharedVector wraps a |std::vector| and ensures access happens on a
// SequencedTaskRunner.
template <typename VectorType>
class SharedVector
: public base::RefCountedThreadSafe<SharedVector<VectorType>> {
public:
static scoped_refptr<SharedVector<VectorType>> Create() {
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner{
base::ThreadPool::CreateSequencedTaskRunner({})};
return base::WrapRefCounted(
new SharedVector<VectorType>(sequenced_task_runner));
}
void PushBack(VectorType item,
base::OnceCallback<void()> push_back_complete_cb) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SharedVector::OnPushBack, this, std::move(item),
std::move(push_back_complete_cb)));
}
// Erase will call erase on all elements that return true for the
// |predicate_cb|.
void Erase(base::RepeatingCallback<bool(const VectorType&)> predicate_cb,
base::OnceCallback<void(size_t)> remove_complete_cb) {
sequenced_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SharedVector::OnErase, this, std::move(predicate_cb),
std::move(remove_complete_cb)));
}
// Provided as the nearest equivalent to std::vector::find. A regular find
// operation may be invalid by the time a caller is notified of its existence.
// |predicate_cb| is called on each element. If |predicate_cb| returns true
// |found_cb| is called on the same element, ending the search.
// |not_found_cb| is called if no elements return true.
void ExecuteIfFound(
base::RepeatingCallback<bool(const VectorType&)> predicate_cb,
base::OnceCallback<void(VectorType&)> found_cb,
base::OnceCallback<void()> not_found_cb) {
sequenced_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&SharedVector::OnExecuteIfFound, this,
std::move(predicate_cb), std::move(found_cb),
std::move(not_found_cb)));
}
// Iterates over each element in |vector_|, and calls |predicate_cb|. If
// |predicate_cb| returns true, |element_executor| will be called on the same
// element and iteration will continue. At the end of iteration
// |execute_complete_cb| will be called.
// A default |predicate_cb| is provided that always returns true.
void ExecuteOnEachElement(
base::RepeatingCallback<void(VectorType&)> element_executor,
base::OnceCallback<void()> execute_complete_cb,
base::RepeatingCallback<bool(const VectorType&)> predicate_cb =
base::BindRepeating([](const VectorType&) { return true; })) {
sequenced_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&SharedVector::OnExecuteOnEachElement, this,
std::move(element_executor),
std::move(execute_complete_cb),
std::move(predicate_cb)));
}
protected:
virtual ~SharedVector() = default;
private:
friend class base::RefCountedThreadSafe<SharedVector<VectorType>>;
explicit SharedVector(
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner)
: sequenced_task_runner_(sequenced_task_runner) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
void OnPushBack(VectorType item,
base::OnceCallback<void()> push_back_complete_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
vector_.push_back(std::move(item));
base::ThreadPool::PostTask(
FROM_HERE, {base::TaskPriority::BEST_EFFORT},
base::BindOnce(
[](base::OnceCallback<void()> push_back_complete_cb) {
std::move(push_back_complete_cb).Run();
},
std::move(push_back_complete_cb)));
}
void OnErase(base::RepeatingCallback<bool(const VectorType&)> predicate_cb,
base::OnceCallback<void(size_t)> remove_complete_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
size_t number_erased = 0;
for (auto it = vector_.begin(); it != vector_.end();) {
if (predicate_cb.Run(*it)) {
it = vector_.erase(it);
number_erased++;
} else {
it++;
}
}
base::ThreadPool::PostTask(
FROM_HERE, {base::TaskPriority::BEST_EFFORT},
base::BindOnce(
[](base::OnceCallback<void(size_t)> remove_complete_cb,
size_t number_erased) {
std::move(remove_complete_cb).Run(number_erased);
},
std::move(remove_complete_cb), number_erased));
}
void OnExecuteIfFound(
base::RepeatingCallback<bool(const VectorType&)> predicate_cb,
base::OnceCallback<void(VectorType&)> found_cb,
base::OnceCallback<void()> not_found_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (VectorType& element : vector_) {
if (predicate_cb.Run(element)) {
std::move(found_cb).Run(element);
return;
}
}
base::ThreadPool::PostTask(FROM_HERE, {base::TaskPriority::BEST_EFFORT},
base::BindOnce(
[](base::OnceCallback<void()> not_found_cb) {
std::move(not_found_cb).Run();
},
std::move(not_found_cb)));
}
void OnExecuteOnEachElement(
base::RepeatingCallback<void(VectorType&)> element_executor,
base::OnceCallback<void()> execute_complete_cb,
base::RepeatingCallback<bool(const VectorType&)> predicate_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (VectorType& element : vector_) {
if (predicate_cb.Run(element)) {
element_executor.Run(element);
} else {
break;
}
}
std::move(execute_complete_cb).Run();
}
std::vector<VectorType> vector_;
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
};
} // namespace reporting
#endif // CHROME_BROWSER_POLICY_MESSAGING_LAYER_UTIL_SHARED_VECTOR_H_