Back to home page

EIC code displayed by LXR

 
 

    


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