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 "./assert" // for Ensures, Expects
0021 #include "./util" // for GSL_DEPRECATED
0022
0023 #include <cstddef> // for ptrdiff_t, nullptr_t, size_t
0024 #include <functional> // for less, greater
0025 #include <memory> // for shared_ptr, unique_ptr, hash
0026 #include <type_traits> // for enable_if_t, is_convertible, is_assignable
0027 #include <utility> // for declval, forward
0028
0029 #if !defined(GSL_NO_IOSTREAMS)
0030 #include <iosfwd> // for ostream
0031 #endif // !defined(GSL_NO_IOSTREAMS)
0032
0033 namespace gsl
0034 {
0035
0036 namespace details
0037 {
0038 template <typename T, typename = void>
0039 struct is_comparable_to_nullptr : std::false_type
0040 {
0041 };
0042
0043 template <typename T>
0044 struct is_comparable_to_nullptr<
0045 T,
0046 std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
0047 : std::true_type
0048 {
0049 };
0050
0051 // Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value
0052 // of type T.
0053 //
0054 // Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-in)
0055 template<typename T>
0056 using value_or_reference_return_t = std::conditional_t<
0057 sizeof(T) < 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
0058 const T,
0059 const T&>;
0060
0061 } // namespace details
0062
0063 //
0064 // GSL.owner: ownership pointers
0065 //
0066 template <typename... Ts>
0067 using shared_ptr GSL_DEPRECATED("Use std::shared_ptr instead") = std::shared_ptr<Ts...>;
0068
0069 template <typename... Ts>
0070 using unique_ptr GSL_DEPRECATED("Use std::unique_ptr instead") = std::unique_ptr<Ts...>;
0071
0072 //
0073 // owner
0074 //
0075 // `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory.
0076 // Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used
0077 // as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers.
0078 //
0079 // T must be a pointer type
0080 // - disallow construction from any type other than pointer type
0081 //
0082 template <class T, std::enable_if_t<std::is_pointer<T>::value, bool> = true>
0083 using owner = T;
0084
0085 //
0086 // not_null
0087 //
0088 // Restricts a pointer or smart pointer to only hold non-null values.
0089 //
0090 // Has zero size overhead over T.
0091 //
0092 // If T is a pointer (i.e. T == U*) then
0093 // - allow construction from U*
0094 // - disallow construction from nullptr_t
0095 // - disallow default construction
0096 // - ensure construction from null U* fails
0097 // - allow implicit conversion to U*
0098 //
0099 template <class T>
0100 class not_null
0101 {
0102 public:
0103 static_assert(details::is_comparable_to_nullptr<T>::value, "T cannot be compared to nullptr.");
0104
0105 using element_type = T;
0106
0107 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0108 constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
0109 {
0110 Expects(ptr_ != nullptr);
0111 }
0112
0113 template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
0114 constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
0115 {
0116 Expects(ptr_ != nullptr);
0117 }
0118
0119 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0120 constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
0121 {}
0122
0123 not_null(const not_null& other) = default;
0124 not_null& operator=(const not_null& other) = default;
0125 constexpr details::value_or_reference_return_t<T> get() const
0126 noexcept(noexcept(details::value_or_reference_return_t<T>(std::declval<T&>())))
0127 {
0128 return ptr_;
0129 }
0130
0131 constexpr operator T() const { return get(); }
0132 constexpr decltype(auto) operator->() const { return get(); }
0133 constexpr decltype(auto) operator*() const { return *get(); }
0134
0135 // prevents compilation when someone attempts to assign a null pointer constant
0136 not_null(std::nullptr_t) = delete;
0137 not_null& operator=(std::nullptr_t) = delete;
0138
0139 // unwanted operators...pointers only point to single objects!
0140 not_null& operator++() = delete;
0141 not_null& operator--() = delete;
0142 not_null operator++(int) = delete;
0143 not_null operator--(int) = delete;
0144 not_null& operator+=(std::ptrdiff_t) = delete;
0145 not_null& operator-=(std::ptrdiff_t) = delete;
0146 void operator[](std::ptrdiff_t) const = delete;
0147
0148 void swap(not_null<T>& other) { std::swap(ptr_, other.ptr_); }
0149
0150 private:
0151 T ptr_;
0152 };
0153
0154 template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
0155 void swap(not_null<T>& a, not_null<T>& b)
0156 {
0157 a.swap(b);
0158 }
0159
0160 template <class T>
0161 auto make_not_null(T&& t) noexcept
0162 {
0163 return not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
0164 }
0165
0166 #if !defined(GSL_NO_IOSTREAMS)
0167 template <class T>
0168 std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
0169 {
0170 os << val.get();
0171 return os;
0172 }
0173 #endif // !defined(GSL_NO_IOSTREAMS)
0174
0175 template <class T, class U>
0176 auto operator==(const not_null<T>& lhs,
0177 const not_null<U>& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
0178 -> decltype(lhs.get() == rhs.get())
0179 {
0180 return lhs.get() == rhs.get();
0181 }
0182
0183 template <class T, class U>
0184 auto operator!=(const not_null<T>& lhs,
0185 const not_null<U>& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
0186 -> decltype(lhs.get() != rhs.get())
0187 {
0188 return lhs.get() != rhs.get();
0189 }
0190
0191 template <class T, class U>
0192 auto operator<(const not_null<T>& lhs,
0193 const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
0194 -> decltype(std::less<>{}(lhs.get(), rhs.get()))
0195 {
0196 return std::less<>{}(lhs.get(), rhs.get());
0197 }
0198
0199 template <class T, class U>
0200 auto operator<=(const not_null<T>& lhs,
0201 const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
0202 -> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
0203 {
0204 return std::less_equal<>{}(lhs.get(), rhs.get());
0205 }
0206
0207 template <class T, class U>
0208 auto operator>(const not_null<T>& lhs,
0209 const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
0210 -> decltype(std::greater<>{}(lhs.get(), rhs.get()))
0211 {
0212 return std::greater<>{}(lhs.get(), rhs.get());
0213 }
0214
0215 template <class T, class U>
0216 auto operator>=(const not_null<T>& lhs,
0217 const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
0218 -> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
0219 {
0220 return std::greater_equal<>{}(lhs.get(), rhs.get());
0221 }
0222
0223 // more unwanted operators
0224 template <class T, class U>
0225 std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
0226 template <class T>
0227 not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
0228 template <class T>
0229 not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
0230 template <class T>
0231 not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
0232
0233
0234 template <class T, class U = decltype(std::declval<const T&>().get()), bool = std::is_default_constructible<std::hash<U>>::value>
0235 struct not_null_hash
0236 {
0237 std::size_t operator()(const T& value) const { return std::hash<U>{}(value.get()); }
0238 };
0239
0240 template <class T, class U>
0241 struct not_null_hash<T, U, false>
0242 {
0243 not_null_hash() = delete;
0244 not_null_hash(const not_null_hash&) = delete;
0245 not_null_hash& operator=(const not_null_hash&) = delete;
0246 };
0247
0248 } // namespace gsl
0249
0250 namespace std
0251 {
0252 template <class T>
0253 struct hash<gsl::not_null<T>> : gsl::not_null_hash<gsl::not_null<T>>
0254 {
0255 };
0256
0257 } // namespace std
0258
0259 namespace gsl
0260 {
0261
0262 //
0263 // strict_not_null
0264 //
0265 // Restricts a pointer or smart pointer to only hold non-null values,
0266 //
0267 // - provides a strict (i.e. explicit constructor from T) wrapper of not_null
0268 // - to be used for new code that wishes the design to be cleaner and make not_null
0269 // checks intentional, or in old code that would like to make the transition.
0270 //
0271 // To make the transition from not_null, incrementally replace not_null
0272 // by strict_not_null and fix compilation errors
0273 //
0274 // Expect to
0275 // - remove all unneeded conversions from raw pointer to not_null and back
0276 // - make API clear by specifying not_null in parameters where needed
0277 // - remove unnecessary asserts
0278 //
0279 template <class T>
0280 class strict_not_null : public not_null<T>
0281 {
0282 public:
0283 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0284 constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::forward<U>(u))
0285 {}
0286
0287 template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
0288 constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::move(u))
0289 {}
0290
0291 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0292 constexpr strict_not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
0293 {}
0294
0295 template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
0296 constexpr strict_not_null(const strict_not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
0297 {}
0298
0299 // To avoid invalidating the "not null" invariant, the contained pointer is actually copied
0300 // instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions.
0301 strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
0302 strict_not_null(const strict_not_null& other) = default;
0303 strict_not_null& operator=(const strict_not_null& other) = default;
0304 strict_not_null& operator=(const not_null<T>& other)
0305 {
0306 not_null<T>::operator=(other);
0307 return *this;
0308 }
0309
0310 // prevents compilation when someone attempts to assign a null pointer constant
0311 strict_not_null(std::nullptr_t) = delete;
0312 strict_not_null& operator=(std::nullptr_t) = delete;
0313
0314 // unwanted operators...pointers only point to single objects!
0315 strict_not_null& operator++() = delete;
0316 strict_not_null& operator--() = delete;
0317 strict_not_null operator++(int) = delete;
0318 strict_not_null operator--(int) = delete;
0319 strict_not_null& operator+=(std::ptrdiff_t) = delete;
0320 strict_not_null& operator-=(std::ptrdiff_t) = delete;
0321 void operator[](std::ptrdiff_t) const = delete;
0322 };
0323
0324 // more unwanted operators
0325 template <class T, class U>
0326 std::ptrdiff_t operator-(const strict_not_null<T>&, const strict_not_null<U>&) = delete;
0327 template <class T>
0328 strict_not_null<T> operator-(const strict_not_null<T>&, std::ptrdiff_t) = delete;
0329 template <class T>
0330 strict_not_null<T> operator+(const strict_not_null<T>&, std::ptrdiff_t) = delete;
0331 template <class T>
0332 strict_not_null<T> operator+(std::ptrdiff_t, const strict_not_null<T>&) = delete;
0333
0334 template <class T>
0335 auto make_strict_not_null(T&& t) noexcept
0336 {
0337 return strict_not_null<std::remove_cv_t<std::remove_reference_t<T>>>{std::forward<T>(t)};
0338 }
0339
0340 #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
0341
0342 // deduction guides to prevent the ctad-maybe-unsupported warning
0343 template <class T>
0344 not_null(T) -> not_null<T>;
0345 template <class T>
0346 strict_not_null(T) -> strict_not_null<T>;
0347
0348 #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
0349
0350 } // namespace gsl
0351
0352 namespace std
0353 {
0354 template <class T>
0355 struct hash<gsl::strict_not_null<T>> : gsl::not_null_hash<gsl::strict_not_null<T>>
0356 {
0357 };
0358
0359 } // namespace std
0360
0361 #endif // GSL_POINTERS_H