RenderCore/Base/CKNonNull.h (65 lines of code) (raw):

/* * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #pragma once #import <RenderCore/CKDefines.h> #if CK_NOT_SWIFT #import <RenderCore/RCAssert.h> namespace CK { template <typename> class RelaxedNonNull; template <typename> class NonNull; namespace NonNullDetail { template <typename> struct IsNonNull: public std::false_type {}; template <typename Ptr> struct IsNonNull<RelaxedNonNull<Ptr>>: public std::true_type {}; template <typename Ptr> struct IsNonNull<NonNull<Ptr>>: public std::true_type {}; } // NonNullDetail template <typename Ptr> class RelaxedNonNull { public: static_assert(!NonNullDetail::IsNonNull<Ptr>::value, "Pointer is already non-null"); RelaxedNonNull(const Ptr &ptr) :_ptr(ptr) { RCCAssertNotNil(_ptr, @"The pointer can't be nil"); } RelaxedNonNull(Ptr &&ptr) :_ptr(ptr) { RCCAssertNotNil(_ptr, @"The pointer can't be nil"); } template <typename OtherPtr, typename = std::enable_if_t<std::is_convertible<OtherPtr, Ptr>::value>> RelaxedNonNull(const RelaxedNonNull<OtherPtr> &ptr) :_ptr(ptr.operator OtherPtr()) {} // Disallow assignment from nullable auto operator =(const Ptr &) -> RelaxedNonNull & = delete; // Implicit conversion to nullable template <typename U, typename = std::enable_if_t<std::is_convertible<Ptr, U>::value>> operator U () const & { return _ptr; } operator Ptr &&() && { return std::move(_ptr); } // Explicit conversion to nullable auto asNullable() const -> Ptr { return _ptr; } // Passthrough Ptr operator ->() const { return _ptr; } Ptr operator *() const { return _ptr; } template <typename... Args> auto operator ()(Args &&... args) const { return _ptr(std::forward<Args>(args)...); } // Disallow conversion to bool operator bool () const = delete; // Disallow nil literals RelaxedNonNull(std::nullptr_t) = delete; template <typename L, typename R> friend auto operator ==(const RelaxedNonNull<L> &, const RelaxedNonNull<R> &) -> bool; private: Ptr _ptr; }; template <typename L, typename R> auto operator ==(const RelaxedNonNull<L> &lhs, const RelaxedNonNull<R> &rhs) -> bool { return lhs._ptr == rhs._ptr; } template <typename L, typename R> auto operator !=(const RelaxedNonNull<L> &lhs, const RelaxedNonNull<R> &rhs) -> bool { return !(lhs == rhs); } template <typename Ptr> auto operator ==(const RelaxedNonNull<Ptr> &lhs, std::nullptr_t rhs) -> bool = delete; template <typename Ptr> auto operator !=(const RelaxedNonNull<Ptr> &lhs, std::nullptr_t rhs) -> bool = delete; template <typename Ptr> class NonNull final: public RelaxedNonNull<Ptr> { public: // Explicit construction from nullable explicit NonNull(const Ptr &ptr) : RelaxedNonNull<Ptr>{ptr} {} explicit NonNull(Ptr &&ptr) : RelaxedNonNull<Ptr>{std::move(ptr)} {} template <typename OtherPtr, typename = std::enable_if_t<std::is_convertible<OtherPtr, Ptr>::value>> NonNull(const NonNull<OtherPtr> &ptr) : RelaxedNonNull<Ptr>{ptr} {} template <typename OtherPtr, typename = std::enable_if_t<std::is_convertible<OtherPtr, Ptr>::value>> NonNull(const RelaxedNonNull<OtherPtr> &ptr) : RelaxedNonNull<Ptr>{ptr} {} // Disallow nil literals NonNull(std::nullptr_t) = delete; }; template <typename Ptr> auto makeNonNull(Ptr p) { return NonNull<Ptr>{std::move(p)}; } } // namespace CK #endif