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