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 CONSTPROPAGATINGRAWPOINTER_H
0005 #define CONSTPROPAGATINGRAWPOINTER_H
0006 
0007 namespace PerceptualColor
0008 {
0009 /** @internal
0010  *
0011  *  @brief A <tt>const</tt> propagating raw pointer
0012  *
0013  * With normal raw C++ pointers (and also with <tt>std::unique_ptr</tt>
0014  * pointers), within <tt>const</tt> functions you can do non-const
0015  * operations <em>on objects that a pointer points to</em>.
0016  *
0017  * <em>This</em> pointer type is different: It propagates the const-ness of
0018  * the object members and propagates them to the call through the pointer;
0019  * it will trigger a compiler error if non-cost access to object members
0020  * or methods is done from within const functions. Apart from that, it
0021  * behaves similar to raw pointers. For compatibility with raw pointers,
0022  * it also casts implicitly to the corresponding raw pointer (but only
0023  * within non-<tt>const</tt> contexts).
0024  *
0025  * Think of this template as a simple alternative to
0026  * <tt>std::experimental::propagate_const&lt; T* &gt;</tt>
0027  *
0028  * Example code:
0029  * @snippet testconstpropagatingrawpointer.cpp example
0030  *
0031  * @note Currently, this class does not implement assignment operators
0032  * or assignment constructors. Once constructed, an instance of
0033  * this class cannot be changed anymore.
0034  *
0035  * @note A @ref ConstPropagatingRawPointer pointer variable itself
0036  * may not be const! (Otherwise, this would make <tt>const</tt>
0037  * <em>all</em> access even to non-const functions of the pointed
0038  * object.)
0039  *
0040  * @sa @ref ConstPropagatingUniquePointer
0041  *
0042  * @note There exist very sophisticated implementations like
0043  * https://github.com/jbcoe/propagate_const but we use nevertheless
0044  * our own light-wise implementation because this seems to be enough
0045  * for our limited use case.
0046  *
0047  * @note This class could be replaced in the future by <tt>
0048  * <a href="https://en.cppreference.com/w/cpp/experimental/propagate_const">
0049  * std::experimental::propagate_const</a></tt> if this one ever becomes
0050  * part of the C++ standard. (Experimental features however are optional
0051  * for compilers, so not all of them implement them. Furthermore, they
0052  * can still change. Therefore, we cannot use experimental features here.) */
0053 template<typename T>
0054 class ConstPropagatingRawPointer final
0055 {
0056 public:
0057     /** @brief Default constructor
0058      *
0059      * Creates a pointer that points to <tt>nullptr</tt>. */
0060     explicit ConstPropagatingRawPointer()
0061         : m_pointer(nullptr)
0062     {
0063     }
0064 
0065     /** @brief Constructor
0066      *
0067      * @param pointer Object to which to point */
0068     explicit ConstPropagatingRawPointer(T *pointer)
0069         : m_pointer(pointer)
0070     {
0071     }
0072 
0073     /** @brief Default destructor */
0074     ~ConstPropagatingRawPointer() noexcept = default;
0075 
0076     /** @brief Non-const pointer operator
0077      *
0078      * @returns Non-const pointer operator */
0079     [[nodiscard]] T *operator->()
0080     {
0081         return m_pointer;
0082     }
0083 
0084     /** @brief Const pointer operator
0085      *
0086      * @returns Const pointer */
0087     [[nodiscard]] const T *operator->() const
0088     {
0089         return m_pointer;
0090     }
0091 
0092     /** @brief Non-const dereference operator
0093      *
0094      * @returns Non-const dereference operator */
0095     [[nodiscard]] T &operator*()
0096     {
0097         return *m_pointer;
0098     }
0099 
0100     /** @brief Const dereference operator
0101      *
0102      * @returns Const dereference operator */
0103     [[nodiscard]] const T &operator*() const
0104     {
0105         return *m_pointer;
0106     }
0107 
0108     /** @brief Cast to a normal raw pointer.
0109      *
0110      * @sa @ref toPointerToConstObject() */
0111     [[nodiscard]] operator T *()
0112     {
0113         return m_pointer;
0114     }
0115 
0116     /** @brief Cast to a normal raw pointer that points to a const object.
0117      *
0118      * @returns Cast to a normal raw pointer that points to a const object.
0119      *
0120      * @sa @ref operator T *() */
0121     // We could provide a const overload to operator T*() instead of
0122     // providing this function with a strange name. But overloading
0123     // operator T* leads to compile errors because of ambiguity
0124     // on GCC and Clang when using this pointer within a “delete” statement.
0125     // That’s confusing, therefore we should avoid it. So given this
0126     // function this different name prevents automatic casts in non-cost
0127     // objects, which also forbids deleting directly pointers of this
0128     // type in non-const contexts, which is nice.
0129     [[nodiscard]] const T *toPointerToConstObject() const
0130     {
0131         return m_pointer;
0132     }
0133 
0134 private:
0135     /** @brief Internal storage for the pointer */
0136     T *m_pointer;
0137 };
0138 
0139 } // namespace PerceptualColor
0140 
0141 #endif // CONSTPROPAGATINGUNIQUEPOINTER_H