diff options
Diffstat (limited to 'bindings/cpp/include/serd/detail')
-rw-r--r-- | bindings/cpp/include/serd/detail/Copyable.hpp | 106 | ||||
-rw-r--r-- | bindings/cpp/include/serd/detail/Wrapper.hpp | 138 |
2 files changed, 244 insertions, 0 deletions
diff --git a/bindings/cpp/include/serd/detail/Copyable.hpp b/bindings/cpp/include/serd/detail/Copyable.hpp new file mode 100644 index 00000000..5a5b5cde --- /dev/null +++ b/bindings/cpp/include/serd/detail/Copyable.hpp @@ -0,0 +1,106 @@ +// Copyright 2019-2021 David Robillard <d@drobilla.net> +// 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 <cstddef> +#include <memory> +#include <type_traits> +#include <utility> + +namespace serd { +namespace detail { + +/** + @addtogroup serdpp_detail + @{ +*/ + +/// Copy function for an allocator-managed C object +template<class T> +using CopyFunc = Mutable<T>* (*)(ZixAllocator*, const T*); + +/// Equality comparison function for C objects +template<class T> +using EqualsFunc = bool (*)(const T*, const T*); + +template<class T, CopyFunc<T> copy_func> +typename std::enable_if_t<std::is_const<T>::value, T>* +copy_cobj(const T* ptr) +{ + return ptr; // Constant wrapper, do not copy +} + +template<class T, CopyFunc<T> copy_func> +typename std::enable_if_t<!std::is_const<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<class T, class Deleter, CopyFunc<T> copy, EqualsFunc<T> equals> +class Copyable : public Wrapper<T, Deleter> +{ +public: + using Base = Wrapper<T, Deleter>; + + explicit Copyable(T* ptr) + : Base{ptr} + {} + + Copyable(const Copyable& wrapper) + : Base(copy_cobj<T, copy>(wrapper.cobj())) + {} + + template<class U, class UDeleter> + explicit Copyable(const Copyable<U, UDeleter, copy, equals>& wrapper) + : Base(copy_cobj<T, copy>(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<T, Deleter>(copy_cobj<T, copy>(wrapper.cobj())); + } + return *this; + } + + template<class U, class UDeleter, Mutable<T>* UCopy(ZixAllocator*, const T*)> + bool operator==(const Copyable<U, UDeleter, UCopy, equals>& wrapper) const + { + return equals(this->cobj(), wrapper.cobj()); + } + + template<class U, class UDeleter, Mutable<T>* UCopy(ZixAllocator*, const T*)> + bool operator!=(const Copyable<U, UDeleter, UCopy, equals>& wrapper) const + { + return !operator==(wrapper); + } +}; + +/** + @} +*/ + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_COPYABLE_HPP diff --git a/bindings/cpp/include/serd/detail/Wrapper.hpp b/bindings/cpp/include/serd/detail/Wrapper.hpp new file mode 100644 index 00000000..887e6643 --- /dev/null +++ b/bindings/cpp/include/serd/detail/Wrapper.hpp @@ -0,0 +1,138 @@ +// Copyright 2019-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef SERD_DETAIL_WRAPPER_HPP +#define SERD_DETAIL_WRAPPER_HPP + +// IWYU pragma: no_include "serd/serd.h" + +#include <cstddef> +#include <memory> +#include <type_traits> +#include <utility> + +namespace serd { + +/// Utility template for a mutable type which removes const if necessary +template<class T> +class Optional; + +/// Detail namespace +namespace detail { + +/** + @defgroup serdpp_detail API Details + Internal C++ wrapper details that should not be used directly by clients. + @ingroup serdpp + @{ +*/ + +/// Utility template for a mutable type which removes const if necessary +template<class T> +using Mutable = typename std::remove_const_t<T>; + +/// Generic C++ wrapper for a C object +template<class T, class Deleter> +class Wrapper +{ +public: + using CType = T; + + explicit Wrapper(T* ptr) + : _ptr{ptr, Deleter{}} + {} + + Wrapper(T* ptr, Deleter deleter) + : _ptr{ptr, std::move(deleter)} + {} + + explicit Wrapper(std::unique_ptr<T, Deleter> ptr) + : _ptr{std::move(ptr)} + {} + + Wrapper(Wrapper&&) noexcept = default; + Wrapper& operator=(Wrapper&&) noexcept = default; + + Wrapper(const Wrapper&) = delete; + Wrapper& operator=(const Wrapper&) = delete; + + ~Wrapper() = default; + + /// Return a pointer to the underlying C object + T* cobj() { return _ptr.get(); } + + /// Return a pointer to the underlying C object + const T* cobj() const { return _ptr.get(); } + +protected: + friend class Optional<T>; + + explicit Wrapper(std::nullptr_t) + : _ptr{nullptr} + {} + + void reset() { _ptr.reset(); } + + std::unique_ptr<T, Deleter> _ptr; +}; + +/// Free function for an object that can free itself +template<class T> +using StandaloneFreeFunc = void(Mutable<T>*); + +/// Free function for an object managed via an allocator +template<class T> +using AllocatedFreeFunc = void(ZixAllocator*, Mutable<T>*); + +/** + Simple overhead-free deleter for a C object. + + Can be used with const or mutable pointers, but only mutable pointers will + be freed. In other words, mutability implies ownership, and this can not + handle unowned mutable pointers. + + @ingroup serdpp_detail +*/ +template<class T, StandaloneFreeFunc<T> free> +struct StandaloneDeleter { + template<class = std::enable_if<!std::is_const<T>::value>> + void operator()(Mutable<T>* const ptr) + { + free(ptr); + } + + template<class = std::enable_if<std::is_const<T>::value>> + void operator()(const T*) + {} +}; + +/** + Simple overhead-free deleter for a C object. + + Can be used with const or mutable pointers, but only mutable pointers will + be freed. In other words, mutability implies ownership, and this can not + handle unowned mutable pointers. + + @ingroup serdpp_detail +*/ +template<class T, AllocatedFreeFunc<T> free> +struct AllocatedDeleter { + template<class = std::enable_if<!std::is_const<T>::value>> + void operator()(Mutable<T>* const ptr) + { + free(nullptr, ptr); + } + + template<class = std::enable_if<std::is_const<T>::value>> + void operator()(const T*) + {} +}; + +/** + @} +*/ + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_WRAPPER_HPP |