Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented cloning_ptr #202

Merged
merged 5 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
306 changes: 304 additions & 2 deletions include/sparrow_v01/utils/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,312 @@

#pragma once

#include <compare>
#include <concepts>
#include <memory>

namespace sparrow
{
inline int dummy()
/**
* Matches types that provide a `clone` method.
*
* This concept checks if a type provides a `clone` method that
* returns a pointer convertible to a pointer to the type.
*
* @tparam T The type to check
*/
template <class T>
concept clonable = requires(const T* t)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that you dont need a pointer here, you could use a reference too.

{
{ t->clone() } -> std::convertible_to<T*>;
};

/**
* @brief smart pointer behaving like a deep copiable std::unique_ptr.
Klaim marked this conversation as resolved.
Show resolved Hide resolved
*
* `cloning_ptr` owns and manages another object through a pointer, like
* `std::unique_ptr`. The difference with `std::unique_ptr` is that
Klaim marked this conversation as resolved.
Show resolved Hide resolved
* `cloning_ptr`calls the `clone` method of the managed object upon copy.
*
* @tparam T The type of the object managed by the `cloning_ptr`. It must
* satisfy the `clonable` concept.
*/
template <clonable T>
class cloning_ptr
{
public:

using self_type = cloning_ptr<T>;
using internal_pointer = std::unique_ptr<T>;
Klaim marked this conversation as resolved.
Show resolved Hide resolved
using pointer = typename internal_pointer::pointer;
using element_type = typename internal_pointer::element_type;

// Value semantic

constexpr cloning_ptr() noexcept = default;
constexpr cloning_ptr(std::nullptr_t) noexcept;
explicit constexpr cloning_ptr(pointer p) noexcept;

constexpr ~cloning_ptr() = default;

constexpr cloning_ptr(const self_type& rhs) noexcept;
constexpr cloning_ptr(self_type&& rhs) noexcept = default;

template <class U>
requires std::convertible_to<U*, T*>
constexpr cloning_ptr(const cloning_ptr<U>& rhs) noexcept;

template <class U>
requires std::convertible_to<
typename cloning_ptr<U>::pointer,
typename cloning_ptr<T>::pointer>
constexpr cloning_ptr(cloning_ptr<U>&& rhs) noexcept;

constexpr self_type& operator=(const self_type&) noexcept;
constexpr self_type& operator=(self_type&&) noexcept = default;
constexpr self_type& operator=(std::nullptr_t) noexcept;

template <class U>
requires std::convertible_to<
typename cloning_ptr<U>::pointer,
typename cloning_ptr<T>::pointer>
constexpr self_type& operator=(const cloning_ptr<U>& rhs) noexcept;

template <class U>
requires std::convertible_to<
typename cloning_ptr<U>::pointer,
typename cloning_ptr<T>::pointer>
constexpr self_type& operator=(cloning_ptr<U>&& rhs) noexcept;

// Modifiers

constexpr pointer release() noexcept;
constexpr void reset(pointer ptr = pointer()) noexcept;
void swap(self_type&) noexcept;

// Observers

constexpr pointer get() const noexcept;

constexpr explicit operator bool() const noexcept;

constexpr std::add_lvalue_reference_t<T>
operator*() const noexcept(noexcept(*std::declval<pointer>()));

constexpr pointer operator->() const noexcept;

private:

constexpr internal_pointer& ptr_impl() noexcept;
constexpr const internal_pointer& ptr_impl() const noexcept;

internal_pointer m_data;
};

template <class T>
void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept;

template <class T1, class T2>
requires std::equality_comparable_with<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
constexpr
bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;

template <class T1, class T2>
requires std::three_way_comparable_with<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
constexpr
std::compare_three_way_result_t<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept;

template <class T>
constexpr
bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;

template <class T>
requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
constexpr
std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept;

/******************************
* cloning_ptr implementation *
******************************/

template <clonable T>
constexpr cloning_ptr<T>::cloning_ptr(std::nullptr_t) noexcept
: m_data(nullptr)
{
}

template <clonable T>
constexpr cloning_ptr<T>::cloning_ptr(pointer p) noexcept
: m_data(p)
{
}

template <clonable T>
constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr& rhs) noexcept
: m_data(rhs->clone())
{
}

template <clonable T>
template <class U>
//requires std::convertible_to<typename cloning_ptr<U>::pointer, typename cloning_ptr<T>::pointer>
requires std::convertible_to<U*, T*>
constexpr cloning_ptr<T>::cloning_ptr(const cloning_ptr<U>& rhs) noexcept
: m_data(rhs->clone())
{
}

template <clonable T>
template <class U>
requires std::convertible_to<typename cloning_ptr<U>::pointer, typename cloning_ptr<T>::pointer>
constexpr cloning_ptr<T>::cloning_ptr(cloning_ptr<U>&& rhs) noexcept

Check failure on line 183 in include/sparrow_v01/utils/memory.hpp

View workflow job for this annotation

GitHub Actions / build

include/sparrow_v01/utils/memory.hpp:183:31 [clang-diagnostic-error]

out-of-line definition of 'cloning_ptr<T>' does not match any declaration in 'cloning_ptr<T>'
: m_data(rhs.release())
{
}

template <clonable T>
constexpr auto cloning_ptr<T>::operator=(const self_type& rhs) noexcept -> self_type&
{
reset(rhs->clone());
return *this;
}

template <clonable T>
constexpr auto cloning_ptr<T>::operator=(std::nullptr_t) noexcept -> self_type&
{
reset(nullptr);
return *this;
}

template <clonable T>
template <class U>
requires std::convertible_to<typename cloning_ptr<U>::pointer, typename cloning_ptr<T>::pointer>
constexpr auto cloning_ptr<T>::operator=(const cloning_ptr<U>& rhs) noexcept -> self_type&

Check failure on line 205 in include/sparrow_v01/utils/memory.hpp

View workflow job for this annotation

GitHub Actions / build

include/sparrow_v01/utils/memory.hpp:205:36 [clang-diagnostic-error]

out-of-line definition of 'operator=' does not match any declaration in 'cloning_ptr<T>'
{
reset(rhs->clone());
return *this;
}

template <clonable T>
template <class U>
requires std::convertible_to<typename cloning_ptr<U>::pointer, typename cloning_ptr<T>::pointer>
constexpr auto cloning_ptr<T>::operator=(cloning_ptr<U>&& rhs) noexcept -> self_type&

Check failure on line 214 in include/sparrow_v01/utils/memory.hpp

View workflow job for this annotation

GitHub Actions / build

include/sparrow_v01/utils/memory.hpp:214:36 [clang-diagnostic-error]

out-of-line definition of 'operator=' does not match any declaration in 'cloning_ptr<T>'
{
reset(rhs.release());
return *this;
}

template <clonable T>
constexpr auto cloning_ptr<T>::release() noexcept -> pointer
{
return ptr_impl().release();
}

template <clonable T>
constexpr void cloning_ptr<T>::reset(pointer ptr) noexcept
{
ptr_impl().reset(ptr);
}

template <clonable T>
void cloning_ptr<T>::swap(self_type& other) noexcept
{
using std::swap;
swap(ptr_impl(), other.ptr_impl());
}

template <clonable T>
constexpr auto cloning_ptr<T>::get() const noexcept -> pointer
{
return ptr_impl().get();
}

template <clonable T>
constexpr cloning_ptr<T>::operator bool() const noexcept
{
return bool(ptr_impl());
}

template <clonable T>
constexpr std::add_lvalue_reference_t<T>
cloning_ptr<T>::operator*() const noexcept(noexcept(*std::declval<pointer>()))
{
return *get();
}

template <clonable T>
constexpr auto cloning_ptr<T>::operator->() const noexcept -> pointer
{
return get();
}

template <clonable T>
constexpr auto cloning_ptr<T>::ptr_impl() noexcept -> internal_pointer&
{
return m_data;
}

template <clonable T>
constexpr auto cloning_ptr<T>::ptr_impl() const noexcept -> const internal_pointer&
{
return m_data;
}

/*********************************
* Free functions implementation *
*********************************/

template <class T>
void swap(cloning_ptr<T>& lhs, cloning_ptr<T>& rhs) noexcept
{
lhs.swap(rhs);
}

template <class T1, class T2>
requires std::equality_comparable_with<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
constexpr
bool operator==(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
{
return lhs.get() == rhs.get();
}

template <class T1, class T2>
requires std::three_way_comparable_with<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
constexpr
std::compare_three_way_result_t<
typename cloning_ptr<T1>::pointer,
typename cloning_ptr<T2>::pointer>
operator<=>(const cloning_ptr<T1>& lhs, const cloning_ptr<T2>& rhs) noexcept
{
return lhs.get() <=> rhs.get();
}

template <class T>
constexpr
bool operator==(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
{
return !lhs;
}

template <class T>
requires std::three_way_comparable<typename cloning_ptr<T>::pointer>
constexpr
std::compare_three_way_result_t<typename cloning_ptr<T>::pointer>
operator<=>(const cloning_ptr<T>& lhs, std::nullptr_t) noexcept
{
return 0;
using pointer = typename cloning_ptr<T>::pointer;
return lhs.get() <=> static_cast<pointer>(nullptr);
}
}
Loading
Loading