Warning, /include/gsl/pointers is written in an unsupported language. File is not indexed.
0001 ///////////////////////////////////////////////////////////////////////////////
0002 //
0003 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
0004 //
0005 // This code is licensed under the MIT License (MIT).
0006 //
0007 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0008 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0009 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0010 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0011 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0012 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0013 // THE SOFTWARE.
0014 //
0015 ///////////////////////////////////////////////////////////////////////////////
0016
0017 #ifndef GSL_POINTERS_H
0018 #define GSL_POINTERS_H
0019
0020 #include <gsl/assert> // for Ensures, Expects
0021
0022 #include <algorithm> // for forward
0023 #include <cstddef> // for ptrdiff_t, nullptr_t, size_t
0024 #include <memory> // for shared_ptr, unique_ptr
0025 #include <system_error> // for hash
0026 #include <type_traits> // for enable_if_t, is_convertible, is_assignable
0027
0028 #if !defined(GSL_NO_IOSTREAMS)
0029 #include <iosfwd> // for ostream
0030 #endif // !defined(GSL_NO_IOSTREAMS)
0031
0032 namespace gsl
0033 {
0034
0035 namespace details
0036 {
0037 template <typename T, typename = void>
0038 struct is_comparable_to_nullptr : std::false_type
0039 {
0040 };
0041
0042 template <typename T>
0043 struct is_comparable_to_nullptr<
0044 T,
0045 std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
0046 : std::true_type
0047 {
0048 };
0049 } // namespace details
0050
0051 //
0052 // GSL.owner: ownership pointers
0053 //
0054 using std::shared_ptr;
0055 using std::unique_ptr;
0056
0057 //
0058 // owner
0059 //
0060 // owner<T> is designed as a bridge for code that must deal directly with owning pointers for some
0061 // reason
0062 //
0063 // T must be a pointer type
0064 // - disallow construction from any type other than pointer type
0065 //
0066 template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
0067 using owner = T;
0068
0069 //
0070 // not_null
0071 //
0072 // Restricts a pointer or smart pointer to only hold non-null values.
0073 //
0074 // Has zero size overhead over T.
0075 //
0076 // If T is a pointer (i.e. T == U*) then
0077 // - allow construction from U*
0078 // - disallow construction from nullptr_t
0079 // - disallow default construction
0080 // - ensure construction from null U* fails
0081 // - allow implicit conversion to U*
0082 //
0083 template <class T>
0084 class not_null
0085 {
0086 public:
0087 static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
0088
0089 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0090 constexpr not_null(U&& u) : ptr_(std::forward<U>(u))
0091 {
0092 Expects(ptr_ != nullptr);
0093 }
0094
0095 template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
0096 constexpr not_null(T u) : ptr_(std::move(u))
0097 {
0098 Expects(ptr_ != nullptr);
0099 }
0100
0101 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0102 constexpr not_null(const not_null<U>& other) : not_null(other.get())
0103 {}
0104
0105 not_null(const not_null& other) = default;
0106 not_null& operator=(const not_null& other) = default;
0107 constexpr std::conditional_t<std::is_copy_constructible<T>::value, T, const T&> get() const
0108 {
0109 Ensures(ptr_ != nullptr);
0110 return ptr_;
0111 }
0112
0113 constexpr operator T() const { return get(); }
0114 constexpr decltype(auto) operator->() const { return get(); }
0115 constexpr decltype(auto) operator*() const { return *get(); }
0116
0117 // prevents compilation when someone attempts to assign a null pointer constant
0118 not_null(std::nullptr_t) = delete;
0119 not_null& operator=(std::nullptr_t) = delete;
0120
0121 // unwanted operators...pointers only point to single objects!
0122 not_null& operator++() = delete;
0123 not_null& operator--() = delete;
0124 not_null operator++(int) = delete;
0125 not_null operator--(int) = delete;
0126 not_null& operator+=(std::ptrdiff_t) = delete;
0127 not_null& operator-=(std::ptrdiff_t) = delete;
0128 void operator[](std::ptrdiff_t) const = delete;
0129
0130 private:
0131 T ptr_;
0132 };
0133
0134 template <class T>
0135 auto make_not_null(T&& t) noexcept
0136 {
0137 return not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
0138 }
0139
0140 #if !defined(GSL_NO_IOSTREAMS)
0141 template <class T>
0142 std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
0143 {
0144 os << val.get();
0145 return os;
0146 }
0147 #endif // !defined(GSL_NO_IOSTREAMS)
0148
0149 template <class T, class U>
0150 auto operator==(const not_null<T>& lhs,
0151 const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
0152 -> decltype(lhs.get() == rhs.get())
0153 {
0154 return lhs.get() == rhs.get();
0155 }
0156
0157 template <class T, class U>
0158 auto operator!=(const not_null<T>& lhs,
0159 const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
0160 -> decltype(lhs.get() != rhs.get())
0161 {
0162 return lhs.get() != rhs.get();
0163 }
0164
0165 template <class T, class U>
0166 auto operator<(const not_null<T>& lhs,
0167 const not_null<U>& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
0168 -> decltype(lhs.get() < rhs.get())
0169 {
0170 return lhs.get() < rhs.get();
0171 }
0172
0173 template <class T, class U>
0174 auto operator<=(const not_null<T>& lhs,
0175 const not_null<U>& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
0176 -> decltype(lhs.get() <= rhs.get())
0177 {
0178 return lhs.get() <= rhs.get();
0179 }
0180
0181 template <class T, class U>
0182 auto operator>(const not_null<T>& lhs,
0183 const not_null<U>& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
0184 -> decltype(lhs.get() > rhs.get())
0185 {
0186 return lhs.get() > rhs.get();
0187 }
0188
0189 template <class T, class U>
0190 auto operator>=(const not_null<T>& lhs,
0191 const not_null<U>& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
0192 -> decltype(lhs.get() >= rhs.get())
0193 {
0194 return lhs.get() >= rhs.get();
0195 }
0196
0197 // more unwanted operators
0198 template <class T, class U>
0199 std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
0200 template <class T>
0201 not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
0202 template <class T>
0203 not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
0204 template <class T>
0205 not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
0206
0207 } // namespace gsl
0208
0209 namespace std
0210 {
0211 template <class T>
0212 struct hash<gsl::not_null<T>>
0213 {
0214 std::size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value.get()); }
0215 };
0216
0217 } // namespace std
0218
0219 namespace gsl
0220 {
0221
0222 //
0223 // strict_not_null
0224 //
0225 // Restricts a pointer or smart pointer to only hold non-null values,
0226 //
0227 // - provides a strict (i.e. explicit constructor from T) wrapper of not_null
0228 // - to be used for new code that wishes the design to be cleaner and make not_null
0229 // checks intentional, or in old code that would like to make the transition.
0230 //
0231 // To make the transition from not_null, incrementally replace not_null
0232 // by strict_not_null and fix compilation errors
0233 //
0234 // Expect to
0235 // - remove all unneeded conversions from raw pointer to not_null and back
0236 // - make API clear by specifying not_null in parameters where needed
0237 // - remove unnecessary asserts
0238 //
0239 template <class T>
0240 class strict_not_null : public not_null<T>
0241 {
0242 public:
0243 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0244 constexpr explicit strict_not_null(U&& u) : not_null<T>(std::forward<U>(u))
0245 {}
0246
0247 template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
0248 constexpr explicit strict_not_null(T u) : not_null<T>(u)
0249 {}
0250
0251 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0252 constexpr strict_not_null(const not_null<U>& other) : not_null<T>(other)
0253 {}
0254
0255 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0256 constexpr strict_not_null(const strict_not_null<U>& other) : not_null<T>(other)
0257 {}
0258
0259 strict_not_null(strict_not_null&& other) = default;
0260 strict_not_null(const strict_not_null& other) = default;
0261 strict_not_null& operator=(const strict_not_null& other) = default;
0262 strict_not_null& operator=(const not_null<T>& other)
0263 {
0264 not_null<T>::operator=(other);
0265 return *this;
0266 }
0267
0268 // prevents compilation when someone attempts to assign a null pointer constant
0269 strict_not_null(std::nullptr_t) = delete;
0270 strict_not_null& operator=(std::nullptr_t) = delete;
0271
0272 // unwanted operators...pointers only point to single objects!
0273 strict_not_null& operator++() = delete;
0274 strict_not_null& operator--() = delete;
0275 strict_not_null operator++(int) = delete;
0276 strict_not_null operator--(int) = delete;
0277 strict_not_null& operator+=(std::ptrdiff_t) = delete;
0278 strict_not_null& operator-=(std::ptrdiff_t) = delete;
0279 void operator[](std::ptrdiff_t) const = delete;
0280 };
0281
0282 // more unwanted operators
0283 template <class T, class U>
0284 std::ptrdiff_t operator-(const strict_not_null<T>&, const strict_not_null<U>&) = delete;
0285 template <class T>
0286 strict_not_null<T> operator-(const strict_not_null<T>&, std::ptrdiff_t) = delete;
0287 template <class T>
0288 strict_not_null<T> operator+(const strict_not_null<T>&, std::ptrdiff_t) = delete;
0289 template <class T>
0290 strict_not_null<T> operator+(std::ptrdiff_t, const strict_not_null<T>&) = delete;
0291
0292 template <class T>
0293 auto make_strict_not_null(T&& t) noexcept
0294 {
0295 return strict_not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
0296 }
0297
0298 #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
0299
0300 // deduction guides to prevent the ctad-maybe-unsupported warning
0301 template <class T>
0302 not_null(T) -> not_null<T>;
0303 template <class T>
0304 strict_not_null(T) -> strict_not_null<T>;
0305
0306 #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
0307
0308 } // namespace gsl
0309
0310 namespace std
0311 {
0312 template <class T>
0313 struct hash<gsl::strict_not_null<T>>
0314 {
0315 std::size_t operator()(const gsl::strict_not_null<T>& value) const
0316 {
0317 return hash<T>{}(value.get());
0318 }
0319 };
0320
0321 } // namespace std
0322
0323 #endif // GSL_POINTERS_H