//============================================================================== // // Copyright (c) 2016, 2020 Qualcomm Technologies, Inc. // All Rights Reserved. // Confidential and Proprietary - Qualcomm Technologies, Inc. // //============================================================================== #ifndef _DL_SYSTEM_OPTIONAL_HPP_ #define _DL_SYSTEM_OPTIONAL_HPP_ #include #include #include #include "DlSystem/ZdlExportDefine.hpp" namespace zdl { namespace DlSystem { template /** @addtogroup c_plus_plus_apis C++ @{ */ /** * @brief . * * Class to manage a value that may or may not exist. The boolean value * of the Optional class is true if the object contains a value and false * if it does not contain a value. * * The class must be evaluated and confirmed as true (containing a value) * before being dereferenced. */ class ZDL_EXPORT Optional final { public: enum class LIFECYCLE { NONE = 0, REFERENCE_OWNED = 1, POINTER_OWNED = 2, POINTER_NOT_OWNED = 3 }; struct ReferenceCount { size_t count = 0; void increment() { count++; } size_t decrement() { if (count > 0) { count--; } return count; } }; using U = typename std::remove_pointer::type; /** * The default constructor is set to not have any value, and is * therefore evaluated as false. */ // Do not explicit it so we can return {} Optional() { m_Type = LIFECYCLE::NONE; } /** * Construct an Optional class using an object. * @param[in] Reference to an object v * @param[out] Optional instance of object v */ template Optional (const T& v, typename std::enable_if::value>::type* = 0) : m_Type(LIFECYCLE::REFERENCE_OWNED) { try { m_StoragePtr = new T(v); } catch (...) { m_StoragePtr = nullptr; m_Type = LIFECYCLE::NONE; } } template Optional(U* v, LIFECYCLE type, typename std::enable_if::value>::type* = 0) : m_Type(type) { switch (m_Type) { case LIFECYCLE::POINTER_OWNED: m_StoragePtr = v; m_Count = new ReferenceCount(); m_Count->increment(); break; case LIFECYCLE::POINTER_NOT_OWNED: m_StoragePtr = v; break; case LIFECYCLE::REFERENCE_OWNED: throw std::bad_exception(); case LIFECYCLE::NONE: break; } } Optional(const Optional &other) : m_Type(other.m_Type), m_Count(other.m_Count) { if (isReference()) { m_StoragePtr = new U(*other.m_StoragePtr); } else if (isPointer()) { m_StoragePtr = other.m_StoragePtr; if (isOwned()) { m_Count->increment(); } } } Optional& operator=(const Optional& other) noexcept { Optional tmp(other); swap(std::move(tmp)); return *this; } Optional(Optional&& other) noexcept { swap(std::move(other)); } Optional& operator=(Optional&& other) noexcept { swap(std::move(other)); return *this; } ~Optional() { if (isOwned()) { if (isReference() || (isPointer() && m_Count->decrement() == 0)) { delete m_StoragePtr; delete m_Count; } } } /** * Boolean value of Optional class is only true when there exists a value. */ operator bool() const noexcept { return isValid(); } bool operator!() const noexcept { return !isValid(); } /** * Get reference of Optional object * @warning User must validate Optional has value before. */ const T& operator*() { return this->GetReference(); } /** * Get reference of Optional object * @warning User must validate Optional has value before. */ const T& operator*() const { return this->GetReference(); } operator T&() { return this->GetReference(); } T operator->() { T self = this->GetReference(); return self; } private: void swap(Optional&& other) { m_Type = other.m_Type; m_StoragePtr = other.m_StoragePtr; m_Count = other.m_Count; other.m_Type = LIFECYCLE::NONE; other.m_StoragePtr = nullptr; other.m_Count = nullptr; } template typename std::enable_if::value, const Q&>::type GetReference() const noexcept { if (!isReference()) std::terminate(); return *static_cast(m_StoragePtr); } template typename std::enable_if::value, const Q&>::type GetReference() const noexcept { if (!isPointer()) std::terminate(); return static_cast(m_StoragePtr); } template typename std::enable_if::value, Q&>::type GetReference() noexcept { if (!isReference()) std::terminate(); return *m_StoragePtr; } template typename std::enable_if::value, Q&>::type GetReference() noexcept { if (!isPointer()) std::terminate(); return m_StoragePtr; } bool isPointer() const { return m_Type == LIFECYCLE::POINTER_OWNED || m_Type == LIFECYCLE::POINTER_NOT_OWNED; } bool isOwned() const { return m_Type == LIFECYCLE::REFERENCE_OWNED || m_Type == LIFECYCLE::POINTER_OWNED; } bool isReference() const { return m_Type == LIFECYCLE::REFERENCE_OWNED; } bool isValid() const { return m_Type != LIFECYCLE::NONE; } U* m_StoragePtr = nullptr; LIFECYCLE m_Type; ReferenceCount *m_Count = nullptr; }; } // ns DlSystem } // ns zdl /** @} */ /* end_addtogroup c_plus_plus_apis C++ */ #endif // _DL_SYSTEM_OPTIONAL_HPP_