File indexing completed on 2024-05-12 04:44:32

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 #ifndef CONSTPROPAGATINGUNIQUEPOINTER_H
0005 #define CONSTPROPAGATINGUNIQUEPOINTER_H
0006 
0007 #include "importexport.h"
0008 #include <memory>
0009 
0010 namespace PerceptualColor
0011 {
0012 /** @internal
0013  *
0014  * @brief A <tt>const</tt> propagating <tt>std::unique_ptr</tt>
0015  *
0016  * With normal <tt>std::unique_ptr</tt> pointers (and also with raw
0017  * C++ pointers), within <tt>const</tt> functions you can do non-const
0018  * operations <em>on objects that a pointer points to</em>.
0019  *
0020  * <em>This</em> pointer type is different: It propagates the constness of
0021  * the object members and propagates them to the call through the pointer;
0022  * it will trigger a compiler error if non-cost access to object members
0023  * or methods is done from within const functions. Apart from that, it
0024  * behaves like <tt>std::unique_ptr</tt>.
0025  *
0026  * Think of this template as a simple alternative to
0027  * <tt>std::experimental::propagate_const&lt; std::unique_ptr&lt;T&gt; &gt;</tt>
0028  *
0029  * Example code:
0030  * @snippet testconstpropagatinguniquepointer.cpp example
0031  *
0032  * Currently, move-assignment is not supported. Use
0033  * <tt>std::unique_prt::reset()</tt> instead. As there is no
0034  * support for deleters anyway, this should be equivalent.
0035  *
0036  * @note A @ref ConstPropagatingUniquePointer pointer variable itself
0037  * may not be const! @internal (Otherwise, this would make <tt>const</tt>
0038  * <em>all</em> access even to non-const functions of the pointed
0039  * object.) @endinternal
0040  *
0041  * @internal
0042  *
0043  * @sa @ref ConstPropagatingRawPointer
0044  *
0045  * This class inherits privately <tt>std::shared_ptr</tt> and not
0046  * <tt>std::unique_ptr</tt> because the latter will not compile on
0047  * the MSVC compiler when used with incomplete types, which is however
0048  * necessary for usage within @ref pimpl.
0049  *
0050  * @note This class could be replaced in the future by <tt>
0051  * <a href="https://en.cppreference.com/w/cpp/experimental/propagate_const">
0052  * std::experimental::propagate_const</a></tt> if this one ever becomes
0053  * part of the C++ standard. (Experimental features however are optional
0054  * for compilers, so not all of them implement them. Furthermore, they
0055  * can still change. Therefore, we cannot use experimental features here.)
0056  *
0057  * @todo Would it be better to include (or link to)
0058  * https://github.com/jbcoe/propagate_const instead of having our own
0059  * implementation? Or remove propagate_const header from this library? */
0060 // NOTE No PERCEPTUALCOLOR_IMPORTEXPORT for generic template definitions!
0061 template<typename T>
0062 class ConstPropagatingUniquePointer : private std::shared_ptr<T>
0063 {
0064 public:
0065     /** @brief Default constructor
0066      *
0067      * Creates a pointer that points to <tt>nullptr</tt>. */
0068     explicit ConstPropagatingUniquePointer()
0069         : std::shared_ptr<T>(nullptr)
0070     {
0071     }
0072 
0073     /** @brief Constructor
0074      *
0075      * @param pointerToObject Object to which to point */
0076     explicit ConstPropagatingUniquePointer(T *pointerToObject)
0077         : std::shared_ptr<T>(pointerToObject)
0078     {
0079     }
0080 
0081     /** @brief Default destructor
0082      *
0083      * This destructor is not marked as <tt>override</tt> because the
0084      * base class’s destructor is not virtual.*/
0085     ~ConstPropagatingUniquePointer() noexcept = default;
0086 
0087     // No copy/move assignment or constructor.
0088     ConstPropagatingUniquePointer(const ConstPropagatingUniquePointer &) = delete;
0089     ConstPropagatingUniquePointer(ConstPropagatingUniquePointer &&) = delete;
0090     ConstPropagatingUniquePointer &operator=(const ConstPropagatingUniquePointer &) = delete; // clazy:exclude=function-args-by-value
0091     ConstPropagatingUniquePointer &operator=(ConstPropagatingUniquePointer &&) = delete;
0092 
0093     /** @brief Non-const pointer operator
0094      *
0095      * @returns Non-const pointer operator */
0096     [[nodiscard]] T *operator->()
0097     {
0098         // cppcheck-suppress CastIntegerToAddressAtReturn // false positive
0099         return std::shared_ptr<T>::operator->();
0100     }
0101 
0102     /** @brief Const pointer operator
0103      *
0104      * @returns Const pointer */
0105     [[nodiscard]] const T *operator->() const
0106     {
0107         // cppcheck-suppress CastIntegerToAddressAtReturn // false positive
0108         return std::shared_ptr<T>::operator->();
0109     }
0110 
0111     /** @brief Non-const dereference operator
0112      *
0113      * @returns Non-const dereference operator */
0114     [[nodiscard]] T &operator*()
0115     {
0116         // cppcheck-suppress returnTempReference // false positive
0117         return std::shared_ptr<T>::operator*();
0118     }
0119 
0120     /** @brief Const dereference operator
0121      *
0122      * @returns Const dereference operator */
0123     [[nodiscard]] const T &operator*() const
0124     {
0125         // cppcheck-suppress returnTempReference // false positive
0126         return std::shared_ptr<T>::operator*();
0127     }
0128 
0129     /** @brief Deletes the previously managed object (if any) and starts
0130      * to manage a new object.
0131      *
0132      * @param newObject The new object that will be managed. Can be
0133      * <tt>nullptr</tt> to not manage any object anymore. */
0134     void reset(T *newObject = nullptr)
0135     {
0136         std::shared_ptr<T>::reset(newObject);
0137     }
0138 
0139     /** @brief Swaps the managed objects.
0140      *
0141      * @param other Another @ref ConstPropagatingUniquePointer object to
0142      * swap the managed object with. */
0143     void swap(ConstPropagatingUniquePointer &other)
0144     {
0145         std::shared_ptr<T>::swap(other);
0146     }
0147 
0148     /** @brief Returns a pointer to the managed object or <tt>nullptr</tt> if
0149      * no object is owned.
0150      *
0151      * @returns A pointer to the managed object or <tt>nullptr</tt> if
0152      * no object is owned. */
0153     [[nodiscard]] T *get()
0154     {
0155         // cppcheck-suppress CastIntegerToAddressAtReturn // false positive
0156         return std::shared_ptr<T>::get();
0157     }
0158 };
0159 
0160 } // namespace PerceptualColor
0161 
0162 #endif // CONSTPROPAGATINGUNIQUEPOINTER_H