handle/copyable: Implement copyable handle
This is a generic handle type that holds a resource and uses RAII to
call a user defined function when the resource is copied or destroyed.
Tested:
Built and run through unit tests.
Change-Id: I3d23544b2e7c8d8c6686effc03b3b7433ea18bf5
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/Makefile.am b/src/Makefile.am
index 57af82a..d45007e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,8 @@
libstdplus_la_SOURCES =
libstdplus_la_LIBADD = $(COMMON_LIBS)
+nobase_include_HEADERS += stdplus/handle/copyable.hpp
+
nobase_include_HEADERS += stdplus/handle/managed.hpp
nobase_include_HEADERS += stdplus/signal.hpp
diff --git a/src/meson.build b/src/meson.build
index 6b1fea9..a6ff714 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -20,5 +20,6 @@
subdir: 'stdplus')
install_headers(
+ 'stdplus/handle/copyable.hpp',
'stdplus/handle/managed.hpp',
subdir: 'stdplus/handle')
diff --git a/src/stdplus/handle/copyable.hpp b/src/stdplus/handle/copyable.hpp
new file mode 100644
index 0000000..df383db
--- /dev/null
+++ b/src/stdplus/handle/copyable.hpp
@@ -0,0 +1,112 @@
+#pragma once
+#include <optional>
+#include <stdplus/handle/managed.hpp>
+#include <utility>
+
+namespace stdplus
+{
+
+/** @brief Similar to the Managed Handle, but also allows for copying
+ * and performs an operation during that copy.
+ */
+template <typename T, typename... As>
+struct Copyable
+{
+ template <void (*drop)(T&&, As&...), T (*ref)(const T&, As&...)>
+ class Handle : public Managed<T, As...>::template Handle<drop>
+ {
+ public:
+ using MHandle = typename Managed<T, As...>::template Handle<drop>;
+
+ /** @brief Creates a handle referencing the object
+ *
+ * @param[in] maybeV - Optional object being managed
+ */
+ template <typename... Vs>
+ constexpr explicit Handle(const std::optional<T>& maybeV, Vs&&... vs) :
+ MHandle(std::nullopt, std::forward<Vs>(vs)...)
+ {
+ reset(maybeV);
+ }
+ template <typename... Vs>
+ constexpr explicit Handle(const T& maybeV, Vs&&... vs) :
+ MHandle(std::nullopt, std::forward<Vs>(vs)...)
+ {
+ reset(maybeV);
+ }
+
+ /** @brief Creates a handle owning the object
+ *
+ * @param[in] maybeV - Maybe the object being managed
+ */
+ template <typename... Vs>
+ constexpr explicit Handle(std::optional<T>&& maybeV,
+ Vs&&... vs) noexcept :
+ MHandle(std::move(maybeV), std::forward<Vs>(vs)...)
+ {
+ }
+ template <typename... Vs>
+ constexpr explicit Handle(T&& maybeV, Vs&&... vs) noexcept :
+ MHandle(std::move(maybeV), std::forward<Vs>(vs)...)
+ {
+ }
+
+ constexpr Handle(const Handle& other) : MHandle(std::nullopt, other.as)
+ {
+ reset(other.maybe_value());
+ }
+
+ constexpr Handle(Handle&& other) noexcept : MHandle(std::move(other))
+ {
+ }
+
+ constexpr Handle& operator=(const Handle& other)
+ {
+ if (this != &other)
+ {
+ reset();
+ this->as = other.as;
+ reset(other.maybe_value());
+ }
+ return *this;
+ }
+
+ constexpr Handle& operator=(Handle&& other) noexcept
+ {
+ MHandle::operator=(std::move(other));
+ return *this;
+ }
+
+ using MHandle::reset;
+
+ /** @brief Resets the managed value to a new value
+ * Takes a new reference on the value
+ *
+ * @param[in] maybeV - Maybe the new value
+ */
+ constexpr void reset(const std::optional<T>& maybeV)
+ {
+ if (maybeV)
+ {
+ reset(doRef(*maybeV, std::index_sequence_for<As...>()));
+ }
+ else
+ {
+ reset(std::nullopt);
+ }
+ }
+ constexpr void reset(const T& maybeV)
+ {
+ reset(doRef(maybeV, std::index_sequence_for<As...>()));
+ }
+
+ private:
+ template <size_t... Indices>
+ T doRef(const T& v, std::index_sequence<Indices...>)
+ {
+ return ref(v, std::get<Indices>(this->as)...);
+ }
+ };
+};
+
+} // namespace stdplus