Skip to content

Commit

Permalink
Merge branch 'iox-eclipse-iceoryx#298-add-unique-ptr-implementation' …
Browse files Browse the repository at this point in the history
…into iox-eclipse-iceoryx#218-improve-pub-sub-api
  • Loading branch information
orecham committed Sep 29, 2020
2 parents 61dc7ef + ccf1252 commit 9359acb
Show file tree
Hide file tree
Showing 3 changed files with 415 additions and 70 deletions.
61 changes: 39 additions & 22 deletions iceoryx_utils/include/iceoryx_utils/cxx/unique_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,66 @@
#define IOX_UTILS_CXX_UNIQUE_PTR_HPP

#include "iceoryx_utils/cxx/function_ref.hpp"
#include <functional>

namespace iox
{
namespace cxx
{

///
/// @brief The unique_ptr class is a heap-less unique ptr implementation, unlike the STL.
/// @details To avoid using the heap, deleters are not managed by the pointer itself, and instead must be provided as
/// function references ('cxx:function_ref'). The functions must exist at least as long as the pointers that use them.
///
/// @todo document how it differs to STL
/// Also unlike the STL implementation, the deleters are not encoded in the unique_ptr type, allowing unique_ptr instances
/// with different deleters to be stored in the same containers.
///
template <typename T>
class unique_ptr
{
public:
using ptr_t = T*;

unique_ptr() = delete;

///
/// @brief unique_ptr Creates an empty unique ptr that owns nothing. Can be passed ownership later via reset.
///
unique_ptr(std::function<void(T*)>&& deleter) noexcept;
unique_ptr(function_ref<void(T*)>&& deleter) noexcept;

///
/// @brief unique_ptr Creates a unique pointer that takes ownership of an object.
/// @details A deleter must always be provided as no default can be provided given that no head is used.
/// The unique_ptr must know how to delete the managed object when pointer out of scope.
/// @details A deleter must always be provided as no default can be provided given that no heap is used.
/// The unique_ptr must know how to delete the managed object when the pointer goes out of scope.
/// @param ptr The raw pointer to the object to be managed.
/// @param deleter The deleter function for cleaning up the managed object.
/// @param deleter The deleter function for cleaning up the managed object. As cxx:function_ref used for the deleter
/// is non-owning the user needs to care about the lifetime of the callable!
///
unique_ptr(ptr_t ptr, std::function<void(T*)>&& deleter) noexcept;
unique_ptr(T* const ptr, function_ref<void(T*)>&& deleter) noexcept;

unique_ptr(std::nullptr_t) noexcept;

// Not copy-able to ensure uniqueness.
unique_ptr(const unique_ptr& other) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

unique_ptr(unique_ptr&& rhs) noexcept;
unique_ptr& operator=(unique_ptr&& rhs) noexcept;

///
/// Automatically deletes the owned object on destruction.
/// Automatically deletes the managed object on destruction.
///
~unique_ptr() noexcept;


unique_ptr<T>& operator=(std::nullptr_t) noexcept;

///
/// @brief operator -> Transparent access to the managed object.
/// @return
///
T* operator->() noexcept;

///
/// Return the stored pointer.
/// @brief operator -> Transparent access to the managed object.
/// @return
///
ptr_t operator->() noexcept;
const T* operator->() const noexcept;

///
/// @brief operator bool Returns true if it points to something.
Expand All @@ -76,33 +87,39 @@ class unique_ptr
/// @details The unique_ptr retains ownership, therefore the "borrowed" pointer must not be deleted.
/// @return Pointer to managed object or nullptr if none owned.
///
ptr_t get() const noexcept;
T* get() noexcept;

///
/// @brief get Retrieve the underlying raw pointer.
/// @details The unique_ptr retains ownership, therefore the "borrowed" pointer must not be deleted.
/// @return Pointer to managed object or nullptr if none owned.
///
const T* get() const noexcept;

///
/// @brief release Release ownership of the underlying pointer.
/// @return Pointer to the managed object or nullptr if none owned.
///
ptr_t release() noexcept;
T* release() noexcept;

///
/// @brief reset Reset the unique pointer to take ownership of the given pointer.
/// @details Any previously owned objects will be deleted. If no pointer given then points to nullptr.
/// @param ptr Pointer to object to take ownership on.
///
void reset(ptr_t ptr = nullptr) noexcept;
void reset(T* const ptr = nullptr) noexcept;

///
/// @brief swap Swaps object ownership with another unique_ptr.
/// @brief swap Swaps object ownership with another unique_ptr (incl. deleters)
/// @param other The unique_ptr with which to swap owned objects.
///
void swap(unique_ptr& other) noexcept;

private:
ptr_t m_ptr = nullptr;
std::function<void(T* const)> m_deleter;
T* m_ptr = nullptr;
function_ref<void(T* const)> m_deleter;
};


} // namespace cxx
} // namespace iox

Expand Down
75 changes: 48 additions & 27 deletions iceoryx_utils/include/iceoryx_utils/internal/cxx/unique_ptr.inl
Original file line number Diff line number Diff line change
@@ -1,38 +1,51 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IOX_UTILS_CXX_UNIQUE_PTR_INL
#define IOX_UTILS_CXX_UNIQUE_PTR_INL

#include "iceoryx_utils/cxx/unique_ptr.hpp"

namespace iox
{
namespace cxx
{

template <typename T>
unique_ptr<T>::unique_ptr(std::function<void(T*)>&& deleter) noexcept
: m_deleter(deleter)
unique_ptr<T>::unique_ptr(T* const ptr, function_ref<void(T*)>&& deleter) noexcept
: m_ptr(ptr)
, m_deleter(std::move(deleter))
{
}

template <typename T>
unique_ptr<T>::unique_ptr(ptr_t ptr, std::function<void(T*)>&& deleter) noexcept
: m_ptr(ptr)
, m_deleter(std::move(deleter))
unique_ptr<T>::unique_ptr(function_ref<void(T*)>&& deleter) noexcept
: unique_ptr(nullptr, std::move(deleter))
{
}

template <typename T>
unique_ptr<T>::unique_ptr(std::nullptr_t) noexcept
unique_ptr<T>& unique_ptr<T>::operator=(std::nullptr_t) noexcept
{
reset();
return *this;
}

template <typename T>
unique_ptr<T>& unique_ptr<T>::operator=(unique_ptr&& rhs) noexcept
{
if (this != &rhs)
{
reset(rhs.m_ptr);
reset(rhs.release());
m_deleter = std::move(rhs.m_deleter);
}
return *this;
Expand All @@ -56,18 +69,30 @@ T* unique_ptr<T>::operator->() noexcept
return get();
}

template <typename T>
const T* unique_ptr<T>::operator->() const noexcept
{
return const_cast<const T*>(get());
}

template <typename T>
unique_ptr<T>::operator bool() const noexcept
{
return get() == ptr_t() ? false : true;
return get() != nullptr ? true : false;
}

template <typename T>
T* unique_ptr<T>::get() const noexcept
T* unique_ptr<T>::get() noexcept
{
return m_ptr;
}

template <typename T>
const T* unique_ptr<T>::get() const noexcept
{
return const_cast<const T*>(m_ptr);
}

template <typename T>
T* unique_ptr<T>::release() noexcept
{
Expand All @@ -77,7 +102,7 @@ T* unique_ptr<T>::release() noexcept
}

template <typename T>
void unique_ptr<T>::reset(T* ptr) noexcept
void unique_ptr<T>::reset(T* const ptr) noexcept
{
if (m_ptr && m_deleter)
{
Expand All @@ -89,23 +114,19 @@ void unique_ptr<T>::reset(T* ptr) noexcept
template <typename T>
void unique_ptr<T>::swap(unique_ptr<T>& other) noexcept
{
if (other)
{
// Release pointers from both instances.
auto thisPtr = release();
auto otherPtr = other.release();
// Set new pointers on both instances.
reset(otherPtr);
other.reset(thisPtr);
}
else
{
reset();
}
}
// release object pointers from both instances
auto thisPtr = release();
auto otherPtr = other.release();

// set new object pointers on both instances
reset(otherPtr);
other.reset(thisPtr);

// Comparison Operators
// move deleters
auto thisDeleter = m_deleter;
m_deleter = other.m_deleter;
other.m_deleter = thisDeleter;
}

template <typename T, typename U>
bool operator==(const unique_ptr<T>& x, const unique_ptr<U>& y)
Expand Down
Loading

0 comments on commit 9359acb

Please sign in to comment.