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 <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