// Copyright 2019-2021 David Robillard // SPDX-License-Identifier: ISC #ifndef SERD_DETAIL_COPYABLE_HPP #define SERD_DETAIL_COPYABLE_HPP // IWYU pragma: no_include "serd/serd.h" #include "serd/detail/Wrapper.hpp" #include #include #include #include namespace serd { namespace detail { /** @addtogroup serdpp_detail @{ */ /// Copy function for an allocator-managed C object template using CopyFunc = Mutable* (*)(ZixAllocator*, const T*); /// Equality comparison function for C objects template using EqualsFunc = bool (*)(const T*, const T*); template copy_func> typename std::enable_if_t::value, T>* copy_cobj(const T* ptr) { return ptr; // Constant wrapper, do not copy } template copy_func> typename std::enable_if_t::value, T>* copy_cobj(const T* ptr) { return ptr ? copy_func(nullptr, ptr) : nullptr; // Mutable wrapper, copy } /** Generic wrapper for a "basic" copyable object. This wraps objects with simple ownership semantics where a const pointer is never owned, and a mutable pointer is owned. This has no space overhead compared to a raw pointer since the ownership is encoded in the type. */ template copy, EqualsFunc equals> class Copyable : public Wrapper { public: using Base = Wrapper; explicit Copyable(T* ptr) : Base{ptr} {} Copyable(const Copyable& wrapper) : Base(copy_cobj(wrapper.cobj())) {} template explicit Copyable(const Copyable& wrapper) : Base(copy_cobj(wrapper.cobj())) {} Copyable(Copyable&&) noexcept = default; Copyable& operator=(Copyable&&) noexcept = default; ~Copyable() noexcept = default; Copyable& operator=(const Copyable& wrapper) { if (&wrapper != this) { this->_ptr = std::unique_ptr(copy_cobj(wrapper.cobj())); } return *this; } template* UCopy(ZixAllocator*, const T*)> bool operator==(const Copyable& wrapper) const { return equals(this->cobj(), wrapper.cobj()); } template* UCopy(ZixAllocator*, const T*)> bool operator!=(const Copyable& wrapper) const { return !operator==(wrapper); } }; /** @} */ } // namespace detail } // namespace serd #endif // SERD_DETAIL_COPYABLE_HPP