diff options
author | David Robillard <d@drobilla.net> | 2018-06-16 10:26:47 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-01-28 21:57:29 -0500 |
commit | 8b1ad067d9450b4c9c4384b6bf2859c70a6b0cce (patch) | |
tree | 2a5cc8b0031658a472c44b8fd8e95cb583d24fc7 /bindings/cpp/include/serd/detail | |
parent | 3f74afa8c0e60a778566db975894044c67a3b386 (diff) | |
download | serd-8b1ad067d9450b4c9c4384b6bf2859c70a6b0cce.tar.gz serd-8b1ad067d9450b4c9c4384b6bf2859c70a6b0cce.tar.bz2 serd-8b1ad067d9450b4c9c4384b6bf2859c70a6b0cce.zip |
[WIP] Add C++ bindings
Diffstat (limited to 'bindings/cpp/include/serd/detail')
-rw-r--r-- | bindings/cpp/include/serd/detail/Copyable.hpp | 236 | ||||
-rw-r--r-- | bindings/cpp/include/serd/detail/DynamicWrapper.hpp | 74 | ||||
-rw-r--r-- | bindings/cpp/include/serd/detail/StaticWrapper.hpp | 97 | ||||
-rw-r--r-- | bindings/cpp/include/serd/detail/Wrapper.hpp | 99 |
4 files changed, 506 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..7b1604d7 --- /dev/null +++ b/bindings/cpp/include/serd/detail/Copyable.hpp @@ -0,0 +1,236 @@ +/* + Copyright 2019-2021 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_DETAIL_COPYABLE_HPP +#define SERD_DETAIL_COPYABLE_HPP + +// IWYU pragma: no_include "serd/serd.h" + +#include "serd/detail/DynamicWrapper.hpp" +#include "serd/detail/StaticWrapper.hpp" +#include "serd/detail/Wrapper.hpp" + +#include <cstddef> +#include <memory> +#include <type_traits> +#include <utility> + +namespace serd { +namespace detail { + +/** + @addtogroup serdpp_detail + @{ +*/ + +/// Copy function for a C object +template<class T> +using CopyFunc = T* (*)(const T*); + +template<class T, std::remove_const_t<T>* Copy(SerdAllocator*, const T*)> +typename std::enable_if_t<std::is_const<T>::value, T>* +copy(const T* ptr) +{ + return ptr; // Making a view (const reference), do not copy +} + +template<class T, std::remove_const_t<T>* Copy(SerdAllocator*, const T*)> +typename std::enable_if_t<!std::is_const<T>::value, T>* +copy(const T* ptr) +{ + return ptr ? Copy(nullptr, ptr) : nullptr; // Making a 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, + Mutable<T>* Copy(SerdAllocator*, const T*), + bool Equals(const T*, const T*), + void Free(Mutable<T>*)> +class StaticCopyable : public StaticWrapper<T, Free> +{ +public: + using Deleter = StaticDeleter<T, Free>; + using Base = StaticWrapper<T, Free>; + + explicit StaticCopyable(T* ptr) + : Base{ptr} + {} + + StaticCopyable(const StaticCopyable& wrapper) + : Base(copy<T, Copy>(wrapper.cobj())) + {} + + template<class U, void UFree(Mutable<U>*)> + explicit StaticCopyable(const StaticCopyable<U, Copy, Equals, UFree>& wrapper) + : Base(copy<T, Copy>(wrapper.cobj())) + {} + + StaticCopyable(StaticCopyable&&) noexcept = default; + ~StaticCopyable() noexcept = default; + + StaticCopyable& operator=(StaticCopyable&&) noexcept = default; + + StaticCopyable& operator=(const StaticCopyable& wrapper) + { + if (&wrapper != this) { + this->_ptr = std::unique_ptr<T, Deleter>(copy<T, Copy>(wrapper.cobj())); + } + return *this; + } + + template<class U> + bool operator==(const StaticCopyable<U, Copy, Equals, Free>& wrapper) const + { + return Equals(this->cobj(), wrapper.cobj()); + } + + template<class U> + bool operator!=(const StaticCopyable<U, Copy, Equals, Free>& wrapper) const + { + return !operator==(wrapper); + } +}; + +/** + 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, + Mutable<T>* Copy(SerdAllocator*, const T*), + bool Equals(const T*, const T*), + void Free(SerdAllocator*, Mutable<T>*)> +class StaticAllocatedCopyable : public StaticAllocatedWrapper<T, Free> +{ +public: + using Deleter = StaticAllocatedDeleter<T, Free>; + using Base = StaticAllocatedWrapper<T, Free>; + + explicit StaticAllocatedCopyable(T* ptr) + : Base{ptr} + {} + + StaticAllocatedCopyable(const StaticAllocatedCopyable& wrapper) + : Base(copy<T, Copy>(wrapper.cobj())) + {} + + template<class U, void UFree(SerdAllocator*, Mutable<U>*)> + explicit StaticAllocatedCopyable( + const StaticAllocatedCopyable<U, Copy, Equals, UFree>& wrapper) + : Base(copy<T, Copy>(wrapper.cobj())) + {} + + StaticAllocatedCopyable(StaticAllocatedCopyable&&) noexcept = default; + ~StaticAllocatedCopyable() noexcept = default; + + StaticAllocatedCopyable& operator=(StaticAllocatedCopyable&&) noexcept = + default; + + StaticAllocatedCopyable& operator=(const StaticAllocatedCopyable& wrapper) + { + if (&wrapper != this) { + this->_ptr = std::unique_ptr<T, Deleter>(copy<T, Copy>(wrapper.cobj())); + } + return *this; + } + + template<class U> + bool operator==( + const StaticAllocatedCopyable<U, Copy, Equals, Free>& wrapper) const + { + return Equals(this->cobj(), wrapper.cobj()); + } + + template<class U> + bool operator!=( + const StaticAllocatedCopyable<U, Copy, Equals, Free>& wrapper) const + { + return !operator==(wrapper); + } +}; + +/** + Wrapper for a "dynamic" copyable C object. + + This wraps objects that require dynamic tracking of the ownership. +*/ +template<class T, + Mutable<T>* Copy(SerdAllocator*, const T*), + bool Equals(const T*, const T*), + void Free(Mutable<T>*)> +class DynamicCopyable : public Wrapper<T, DynamicDeleter<T, Free>> +{ +public: + using Deleter = DynamicDeleter<T, Free>; + using Base = Wrapper<T, Deleter>; + + explicit DynamicCopyable(std::unique_ptr<T, Deleter> ptr) + : Base{std::move(ptr)} + {} + + DynamicCopyable(const DynamicCopyable& wrapper) + : Base{Copy(nullptr /* FIXME */, wrapper.cobj()), Ownership::owned} + {} + + DynamicCopyable(DynamicCopyable&&) noexcept = default; + DynamicCopyable& operator=(DynamicCopyable&&) noexcept = default; + + ~DynamicCopyable() noexcept = default; + + DynamicCopyable& operator=(const DynamicCopyable& wrapper) + { + if (&wrapper != this) { + this->_ptr = std::unique_ptr<T, Deleter>( + Copy(nullptr /* FIXME */, wrapper.cobj()), Ownership::owned); + } + + return *this; + } + + template<class U> + bool operator==(const DynamicCopyable<U, Copy, Equals, Free>& wrapper) const + { + return Equals(this->cobj(), wrapper.cobj()); + } + + template<class U> + bool operator!=(const DynamicCopyable<U, Copy, Equals, Free>& wrapper) const + { + return !operator==(wrapper); + } + +protected: + explicit DynamicCopyable(std::nullptr_t) + : Base(nullptr) + {} +}; + +/** + @} +*/ + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_COPYABLE_HPP diff --git a/bindings/cpp/include/serd/detail/DynamicWrapper.hpp b/bindings/cpp/include/serd/detail/DynamicWrapper.hpp new file mode 100644 index 00000000..6b3c898a --- /dev/null +++ b/bindings/cpp/include/serd/detail/DynamicWrapper.hpp @@ -0,0 +1,74 @@ +/* + Copyright 2019-2021 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_DETAIL_DYNAMICWRAPPER_HPP +#define SERD_DETAIL_DYNAMICWRAPPER_HPP + +// IWYU pragma: no_include "serd/serd.h" + +#include "serd/detail/Wrapper.hpp" + +#include <type_traits> + +namespace serd { +namespace detail { + +/** + Ownership for `DynamicDeleter`. + + @ingroup serdpp_detail +*/ +enum class Ownership { + owned, ///< This pointer owns the data and must delete it + view, ///< This pointer is just a view and must not delete the data +}; + +/** + Deleter for a C object that can handle dynamic ownership. + + Unlike StaticDeleter, this can be used to handle non-owned references to + mutable objects, at the cost of an extra word for tracking the ownership + (since constness in the type can't convey this information). + + @ingroup serdpp_detail +*/ +template<class T, void Free(Mutable<T>*)> +struct DynamicDeleter { + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + DynamicDeleter(const Ownership ownership) + : _ownership{ownership} + {} + + template<class = std::enable_if<!std::is_const<T>::value>> + void operator()(Mutable<T>* const ptr) + { + if (_ownership == Ownership::owned) { + Free(ptr); + } + } + + template<class = std::enable_if<std::is_const<T>::value>> + void operator()(const T*) + {} + +private: + Ownership _ownership; +}; + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_DYNAMICWRAPPER_HPP diff --git a/bindings/cpp/include/serd/detail/StaticWrapper.hpp b/bindings/cpp/include/serd/detail/StaticWrapper.hpp new file mode 100644 index 00000000..9ca82118 --- /dev/null +++ b/bindings/cpp/include/serd/detail/StaticWrapper.hpp @@ -0,0 +1,97 @@ +/* + Copyright 2019-2021 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_DETAIL_STATICWRAPPER_HPP +#define SERD_DETAIL_STATICWRAPPER_HPP + +// IWYU pragma: no_include "serd/serd.h" + +#include "serd/detail/Wrapper.hpp" + +#include <type_traits> + +namespace serd { +namespace detail { + +/** + 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, void Free(Mutable<T>*)> +struct StaticDeleter { + 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 wrapper for a C object that can free itself +template<class T, void Free(std::remove_const_t<T>*)> +class StaticWrapper : public Wrapper<T, StaticDeleter<T, Free>> +{ +public: + explicit StaticWrapper(T* const ptr) + : Wrapper<T, StaticDeleter<T, Free>>{ptr} + {} +}; + +/** + 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, void Free(SerdAllocator*, Mutable<T>*)> +struct StaticAllocatedDeleter { + 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*) + {} +}; + +/// Simple overhead-free wrapper for a C object that uses an allocator +template<class T, void Free(SerdAllocator*, std::remove_const_t<T>*)> +class StaticAllocatedWrapper + : public Wrapper<T, StaticAllocatedDeleter<T, Free>> +{ +public: + explicit StaticAllocatedWrapper(T* const ptr) + : Wrapper<T, StaticAllocatedDeleter<T, Free>>{ptr} + {} +}; + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_STATICWRAPPER_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..39426775 --- /dev/null +++ b/bindings/cpp/include/serd/detail/Wrapper.hpp @@ -0,0 +1,99 @@ +/* + Copyright 2019-2021 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#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 Serd C++ 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; +}; + +/** + @} +*/ + +} // namespace detail +} // namespace serd + +#endif // SERD_DETAIL_WRAPPER_HPP |