Program Listing for File copyable_unique_ptr.hpp
↰ Return to documentation for file (include/depthai/utility/copyable_unique_ptr.hpp)
#pragma once
/* Portions copyright (c) 2015 Stanford University and the Authors.
Authors: Michael Sherman
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.
(Adapted from Simbody's ClonePtr class.)
(Adapted from Drake copyable_unique_ptr class.)
*/
#include <cstddef>
#include <iostream>
#include <memory>
#include <utility>
namespace dai {
// TODO(SeanCurtis-TRI): Consider extending this to add the Deleter as well.
template <typename T>
class copyable_unique_ptr : public std::unique_ptr<T> {
public:
copyable_unique_ptr() noexcept : std::unique_ptr<T>() {}
explicit copyable_unique_ptr(T* raw) noexcept : std::unique_ptr<T>(raw) {}
explicit copyable_unique_ptr(const T& value) : std::unique_ptr<T>(CopyOrNull(&value)) {}
copyable_unique_ptr(const copyable_unique_ptr& cu_ptr) : std::unique_ptr<T>(CopyOrNull(cu_ptr.get())) {}
template <typename U>
explicit copyable_unique_ptr(const std::unique_ptr<U>& u_ptr) : std::unique_ptr<T>(CopyOrNull(u_ptr.get())) {}
copyable_unique_ptr(copyable_unique_ptr&& cu_ptr) noexcept : std::unique_ptr<T>(cu_ptr.release()) {}
explicit copyable_unique_ptr(std::unique_ptr<T>&& u_ptr) noexcept : std::unique_ptr<T>(u_ptr.release()) {}
template <typename U>
explicit copyable_unique_ptr(std::unique_ptr<U>&& u_ptr) noexcept : std::unique_ptr<T>(u_ptr.release()) {}
copyable_unique_ptr& operator=(T* raw) noexcept {
std::unique_ptr<T>::reset(raw);
return *this;
}
copyable_unique_ptr& operator=(const T& ref) {
std::unique_ptr<T>::reset(CopyOrNull(&ref));
return *this;
}
copyable_unique_ptr& operator=(const copyable_unique_ptr& cu_ptr) {
return operator=(static_cast<const std::unique_ptr<T>&>(cu_ptr));
}
template <typename U>
copyable_unique_ptr& operator=(const copyable_unique_ptr<U>& cu_ptr) {
return operator=(static_cast<const std::unique_ptr<U>&>(cu_ptr));
}
copyable_unique_ptr& operator=(const std::unique_ptr<T>& src) {
if(&src != this) {
// can't be same ptr unless null
DRAKE_DEMAND((get() != src.get()) || !get());
std::unique_ptr<T>::reset(CopyOrNull(src.get()));
}
return *this;
}
template <typename U>
copyable_unique_ptr& operator=(const std::unique_ptr<U>& u_ptr) {
// can't be same ptr unless null
DRAKE_DEMAND((get() != u_ptr.get()) || !get());
std::unique_ptr<T>::reset(CopyOrNull(u_ptr.get()));
return *this;
}
copyable_unique_ptr& operator=(copyable_unique_ptr&& cu_ptr) noexcept {
std::unique_ptr<T>::reset(cu_ptr.release());
return *this;
}
template <typename U>
copyable_unique_ptr& operator=(copyable_unique_ptr<U>&& cu_ptr) noexcept {
std::unique_ptr<T>::reset(cu_ptr.release());
return *this;
}
copyable_unique_ptr& operator=(std::unique_ptr<T>&& u_ptr) noexcept {
std::unique_ptr<T>::reset(u_ptr.release());
return *this;
}
template <typename U>
copyable_unique_ptr& operator=(std::unique_ptr<U>&& u_ptr) noexcept {
std::unique_ptr<T>::reset(u_ptr.release());
return *this;
}
bool empty() const noexcept {
return !(*this);
}
const T* get() const noexcept {
return std::unique_ptr<T>::get();
}
// TODO(SeanCurtis-TRI): Consider adding some debug assertions about whether
// T is const or not. If so, it would be nice to give feedback that calling
// the mutable version makes no sense.
T* get_mutable() noexcept {
return std::unique_ptr<T>::get();
}
// TODO(15344) We need to shore up this const correctness hole. Rather than an
// is-a relationship, we need some alternative relationship that will provide
// the same functionality but not be upcastable. One possibility is to own
// an unique_ptr and forward various APIs. Another is to implement from
// scratch. The current "is-A" relationship was intended so that the
// copyable_unique_ptr could be used where unique_ptrs are used. What would
// the impact of such a change in the relationship be to Drake and Drake
// users?
const T& operator*() const {
return *get();
}
T& operator*() {
return *get_mutable();
}
private:
template <class U>
static T* CopyOrClone(const T* raw, std::true_type) {
return raw->clone().release();
}
template <class U>
static T* CopyOrClone(const T* raw, std::false_type) {
return new T(*raw);
}
// If src is non-null, clone it; otherwise return nullptr.
// If both can_copy() and can_clone() return true, we will prefer the Clone()
// function over the copy constructor.
// The caller has ownership over the return value.
static T* CopyOrNull(const T* raw) {
if(raw == nullptr) {
return nullptr;
}
return CopyOrClone<T>(
raw, std::integral_constant<bool, std::is_same<decltype(std::declval<const T>().clone()), std::unique_ptr<std::remove_const_t<T>>>::value>{});
}
};
template <class charT, class traits, class T>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const copyable_unique_ptr<T>& cu_ptr) {
os << cu_ptr.get();
return os;
}
} // namespace dai