blob: 866a1627ebdd255bdb81df3b283cae0fa3e3cab1 [file] [log] [blame]
// Copyright 2017 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 LIB_CALLBACK_MANAGED_CONTAINER_H_
#define LIB_CALLBACK_MANAGED_CONTAINER_H_
#include <memory>
#include <utility>
#include <vector>
#include <lib/fit/defer.h>
#include <lib/fit/function.h>
#include "lib/fxl/logging.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace callback {
// ManagedContainer is a heterogeneous container that allows to share ownership
// of any added element between the container and the returned managed element.
// The element will be deleted as soon as either the container or the returned
// managed element is deleted.
//
// Example usage:
//
// ManagedContainer container;
//
// E element;
// auto managed_element = container.Manage(std::move(element));
//
// From here, |element| can be accessed through |managed_element| and will be
// deleted when either |container| or |managed_element| is deleted. In
// particular, |*managed_element| must not be accessed after |container| is
// deleted, but |managed_element| itself can outlive |container|.
class ManagedContainer {
public:
ManagedContainer();
~ManagedContainer();
template <typename E>
class ManagedElement {
public:
ManagedElement(E* element, fit::closure cleanup)
: element_(element), auto_cleanup_(std::move(cleanup)) {}
ManagedElement(ManagedElement<E>&& other) noexcept = default;
ManagedElement& operator=(ManagedElement<E>&& other) noexcept = default;
E* get() const { return element_; }
E& operator*() const { return *element_; }
E* operator->() const { return element_; }
void reset() { auto_cleanup_.call(); }
private:
E* element_;
fit::deferred_action<fit::closure> auto_cleanup_;
};
// Manage() takes an object |element| as input, and returns a ManagedElement.
// The |ManagedElement| acts as a pointer to |element|. |element| will be
// deleted when either the returned object or the container itself is deleted.
// The returned ManagedElement must not be dereferenced after the container
// has been deleted.
template <typename E>
ManagedElement<E> Manage(E element) {
auto typed_element = std::make_unique<TypedElement<E>>(std::move(element));
E* result = typed_element->element();
fit::closure cleanup = ManageElement(std::move(typed_element));
return ManagedElement<E>(result, std::move(cleanup));
}
size_t empty() { return managed_elements_.empty(); }
void set_on_empty(fit::closure on_empty) { on_empty_ = std::move(on_empty); }
private:
class Element {
public:
Element() {}
virtual ~Element() {}
private:
FXL_DISALLOW_COPY_AND_ASSIGN(Element);
};
template <typename A>
class TypedElement : public Element {
public:
explicit TypedElement(A element) : element_(std::move(element)) {}
A* element() { return &element_; }
private:
A element_;
};
fit::closure ManageElement(std::unique_ptr<Element> element);
void CheckEmpty();
std::vector<std::unique_ptr<Element>> managed_elements_;
fit::closure on_empty_;
fxl::WeakPtrFactory<ManagedContainer> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(ManagedContainer);
};
} // namespace callback
#endif // LIB_CALLBACK_MANAGED_CONTAINER_H_