Line data Source code
1 : #pragma once 2 : 3 : #include "absl/types/optional.h" // required for absl::nullopt 4 : 5 : namespace Envoy { 6 : 7 : // Helper class to make it easier to work with optional references, allowing: 8 : // foo(OptRef<T> t) { 9 : // if (t.has_value()) { 10 : // t->method(); 11 : // } 12 : // } 13 : // 14 : // Using absl::optional directly you must write optref.value().method() which is 15 : // a bit more awkward. 16 : // 17 : // This class also consumes less memory -- e.g. 8 bytes for a pointer rather 18 : // than 16 bytes for a pointer plus a bool with alignment padding. 19 : template <class T> struct OptRef { 20 26096 : OptRef(T& t) : ptr_(&t) {} 21 23981 : OptRef() : ptr_(nullptr) {} 22 5485 : OptRef(absl::nullopt_t) : ptr_(nullptr) {} 23 : 24 : /** 25 : * Copy constructor that allows conversion. 26 : */ 27 1579 : template <class From> explicit OptRef(OptRef<From> rhs) : ptr_(rhs.ptr()) {} 28 : 29 : /** 30 : * Assignment that allows conversion. 31 : */ 32 : template <class From> OptRef<T>& operator=(OptRef<From> rhs) { 33 : ptr_ = rhs.ptr(); 34 : return *this; 35 : } 36 : 37 : /** 38 : * Helper to call a const method on T. The caller is responsible for ensuring 39 : * has_value() is true. 40 : */ 41 15404 : T* operator->() const { return ptr_; } 42 : 43 : /** 44 : * Helper to convert a OptRef into a pointer. If the optional is not set, returns a nullptr. 45 : */ 46 4966 : T* ptr() const { return ptr_; } 47 : 48 : /** 49 : * Helper to convert a OptRef into a ref. Behavior if !has_value() is undefined. 50 : */ 51 1466 : T& ref() const { return *ptr_; } // NOLINT(clang-analyzer-core.uninitialized.UndefReturn) 52 : 53 : /** 54 : * Helper to dereference an OptRef. Behavior if !has_value() is undefined. 55 : */ 56 2990 : T& operator*() const { return *ptr_; } // NOLINT(clang-analyzer-core.uninitialized.UndefReturn) 57 : 58 : /** 59 : * @return true if the object has a value. 60 : */ 61 39163 : bool has_value() const { return ptr_ != nullptr; } 62 : 63 : /** 64 : * @return true if the object has a value. 65 : */ 66 714 : bool operator!() const { return ptr_ == nullptr; } 67 7684 : operator bool() const { return ptr_ != nullptr; } 68 : 69 : /** 70 : * Copies the OptRef into an optional<T>. To use this, T must supply 71 : * an assignment operator. 72 : * 73 : * It is OK to copy an unset object -- it will result in an optional where 74 : * has_value() is false. 75 : * 76 : * @return an optional copy of the referenced object (or nullopt). 77 : */ 78 0 : absl::optional<T> copy() const { 79 0 : absl::optional<T> ret; 80 0 : if (has_value()) { 81 0 : ret = *ptr_; 82 0 : } 83 0 : return ret; 84 0 : } 85 : 86 : /** 87 : * Places a reference to the an object into the OptRef. 88 : * 89 : * @param ref the object to be referenced. 90 : */ 91 0 : void emplace(T& ref) { ptr_ = &ref; } 92 : 93 : /** 94 : * The value method has no intrinsic value to OptRef, but is left here for 95 : * compatibility reasons. This is used in call-sites which would be needed if 96 : * they were using optional<reference_wrapper<T>> directly without 97 : * OptRef. Having this function makes it easier upgrade to using OptRef 98 : * without having to change all call-sites. 99 : * 100 : * This must be called with has_value() true. 101 : * 102 : * @return a reference_wrapper around the value. 103 : */ 104 : std::reference_wrapper<const T> value() const { return std::reference_wrapper<T>(*ptr_); } 105 5010 : std::reference_wrapper<T> value() { return std::reference_wrapper<T>(*ptr_); } 106 : 107 : /** 108 : * Clears any current reference. 109 : */ 110 0 : void reset() { ptr_ = nullptr; } 111 : 112 : private: 113 : T* ptr_; 114 : }; 115 : 116 : /** 117 : * Constructs an OptRef<T> from the provided reference. 118 : * @param ref the reference to wrap 119 : * @return OptRef<T> the wrapped reference 120 : */ 121 475 : template <class T> OptRef<T> makeOptRef(T& ref) { return {ref}; } 122 : 123 : /** 124 : * Constructs an OptRef<T> from the provided pointer. 125 : * @param ptr the pointer to wrap 126 : * @return OptRef<T> the wrapped pointer, or absl::nullopt if the pointer is nullptr 127 : */ 128 20390 : template <class T> OptRef<T> makeOptRefFromPtr(T* ptr) { 129 20390 : if (ptr == nullptr) { 130 12919 : return {}; 131 12919 : } 132 : 133 7471 : return {*ptr}; 134 20390 : } 135 : 136 : // Overloads for comparing OptRef against absl::nullopt. 137 0 : template <class T> bool operator!=(const OptRef<T>& optref, absl::nullopt_t) { 138 0 : return optref.has_value(); 139 0 : } 140 : template <class T> bool operator!=(absl::nullopt_t, const OptRef<T>& optref) { 141 : return optref.has_value(); 142 : } 143 : template <class T> bool operator==(const OptRef<T>& optref, absl::nullopt_t) { 144 : return !optref.has_value(); 145 : } 146 : template <class T> bool operator==(absl::nullopt_t, const OptRef<T>& optref) { 147 : return !optref.has_value(); 148 : } 149 : 150 : } // namespace Envoy