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