/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace folly { namespace detail { template struct is_not_null_helper : std::false_type {}; template struct is_not_null_helper> : std::true_type {}; template struct is_not_null : is_not_null_helper>> {}; template inline constexpr bool is_not_null_v = is_not_null::value; template >> auto maybeUnwrap(T&& t) { return std::forward(t); } template auto maybeUnwrap(const not_null_base& t) { return t.unwrap(); } template auto maybeUnwrap(not_null_base&& t) { return std::move(t).unwrap(); } template struct maybe_unwrap_not_null { using type = T; }; template struct maybe_unwrap_not_null { using type = const typename maybe_unwrap_not_null::type; }; template struct maybe_unwrap_not_null { using type = typename maybe_unwrap_not_null::type&; }; template struct maybe_unwrap_not_null { using type = typename maybe_unwrap_not_null::type&&; }; template struct maybe_unwrap_not_null> { using type = PtrT; }; template struct is_not_null_convertible : std::is_convertible< typename maybe_unwrap_not_null::type, typename maybe_unwrap_not_null::type> {}; template struct is_not_null_nothrow_constructible : std::integral_constant< bool, is_not_null_v && std::is_nothrow_constructible_v> {}; struct secret_guaranteed_not_null : guaranteed_not_null_provider { static guaranteed_not_null get() { return guaranteed_not_null_provider::guaranteed_not_null(); } }; // In order to be able to cast from not_null to ToT: // - It must not already be castable, otherwise the compiler will raise an // ambiguity error // - PtrT must be castable to ToT template struct is_not_null_castable : std::integral_constant< bool, std::is_convertible_v && !std::is_convertible_v&, ToT>> {}; template struct is_not_null_move_castable : std::integral_constant< bool, std::is_convertible_v && !std::is_convertible_v&&, ToT>> {}; template () == nullptr)> inline std::true_type is_comparable_to_nullptr_fn(const T&) { return {}; } inline std::false_type is_comparable_to_nullptr_fn(...) { return {}; } template constexpr bool is_comparable_to_nullptr_v = decltype(is_comparable_to_nullptr_fn(*std::declval()))::value; } // namespace detail template template not_null_base::not_null_base(U&& u, private_tag) : ptr_(detail::maybeUnwrap(std::forward(u))) { if constexpr (!detail::is_not_null_v) { throw_if_null(); } } template not_null_base::not_null_base( PtrT&& ptr, guaranteed_not_null_provider::guaranteed_not_null) noexcept : ptr_(std::move(ptr)) {} template template not_null_base::not_null_base(U&& u, implicit_tag) noexcept( detail::is_not_null_nothrow_constructible::value) : not_null_base(std::forward(u), private_tag{}) {} template template not_null_base::not_null_base(U&& u, implicit_tag) noexcept( detail::is_not_null_nothrow_constructible::value) : not_null_base(std::forward(u), private_tag{}) {} template typename not_null_base::element_type& not_null_base::operator*() const noexcept { return *unwrap(); } template const PtrT& not_null_base::operator->() const noexcept { return unwrap(); } template not_null_base::operator const PtrT&() const& noexcept { return unwrap(); } template not_null_base::operator PtrT&&() && noexcept { return std::move(*this).unwrap(); } template template not_null_base::operator U() const& noexcept( std::is_nothrow_constructible_v) { if constexpr (detail::is_not_null_v) { return U(*this); } return U(unwrap()); } template template not_null_base::operator U() && noexcept( std::is_nothrow_constructible_v) { if constexpr (detail::is_not_null_v) { return U(std::move(*this)); } return U(std::move(*this).unwrap()); } template void not_null_base::swap(not_null_base& other) noexcept { mutable_unwrap().swap(other.mutable_unwrap()); } template const PtrT& not_null_base::unwrap() const& noexcept { if constexpr (folly::kIsDebug) { terminate_if_null(ptr_); } return ptr_; } template PtrT&& not_null_base::unwrap() && noexcept { if constexpr (folly::kIsDebug) { terminate_if_null(ptr_); } return std::move(ptr_); } template PtrT& not_null_base::mutable_unwrap() noexcept { return const_cast(const_cast(*this).unwrap()); } template void not_null_base::throw_if_null() const { throw_if_null(ptr_); } template template void not_null_base::throw_if_null(const T& ptr) { if (ptr == nullptr) { folly::throw_exception("non_null is null"); } } template template void not_null_base::terminate_if_null(const T& ptr) { if (ptr == nullptr) { folly::terminate_with( "not_null internal pointer is null"); } } template template Deleter&& not_null_base::forward_or_throw_if_null(Deleter&& deleter) { if constexpr (detail::is_comparable_to_nullptr_v) { if (deleter == nullptr) { folly::throw_exception( "non_null deleter is null"); } } return std::forward(deleter); } /** * not_null> specialization. */ template not_null>::not_null(pointer p, const Deleter& d) : not_null_base>( std::unique_ptr( std::move(p).unwrap(), this->forward_or_throw_if_null(d)), guaranteed_not_null_provider::guaranteed_not_null()) {} template not_null>::not_null(pointer p, Deleter&& d) : not_null_base>( std::unique_ptr( std::move(p).unwrap(), this->forward_or_throw_if_null(std::move(d))), guaranteed_not_null_provider::guaranteed_not_null()) {} template void not_null>::reset(pointer ptr) noexcept { this->mutable_unwrap().reset(ptr.unwrap()); } template typename not_null>::pointer not_null>::get() const noexcept { return pointer( this->unwrap().get(), guaranteed_not_null_provider::guaranteed_not_null()); } template Deleter& not_null>::get_deleter() noexcept { return this->mutable_unwrap().get_deleter(); } template const Deleter& not_null>::get_deleter() const noexcept { return this->unwrap().get_deleter(); } template not_null_unique_ptr make_not_null_unique(Args&&... args) { return not_null_unique_ptr( std::make_unique(std::forward(args)...), detail::secret_guaranteed_not_null::get()); } /** * not_null> specialization. */ template template not_null>::not_null(U* ptr, Deleter d) : not_null_base>(std::shared_ptr( ptr, this->forward_or_throw_if_null(std::move(d)))) {} template template not_null>::not_null(not_null ptr, Deleter d) : not_null_base>( std::shared_ptr( ptr.unwrap(), this->forward_or_throw_if_null(std::move(d))), guaranteed_not_null_provider::guaranteed_not_null()) {} template template not_null>::not_null( const std::shared_ptr& r, not_null ptr) noexcept : not_null_base>( std::shared_ptr(r, ptr.unwrap()), guaranteed_not_null_provider::guaranteed_not_null()) {} template template not_null>::not_null( const not_null>& r, not_null ptr) noexcept : not_null_base>( std::shared_ptr(r.unwrap(), ptr.unwrap()), guaranteed_not_null_provider::guaranteed_not_null()) {} template template not_null>::not_null( std::shared_ptr&& r, not_null ptr) noexcept : not_null_base>( std::shared_ptr(std::move(r), ptr.unwrap()), guaranteed_not_null_provider::guaranteed_not_null()) {} template template not_null>::not_null( not_null>&& r, not_null ptr) noexcept : not_null_base>( std::shared_ptr(std::move(r).unwrap(), ptr.unwrap()), guaranteed_not_null_provider::guaranteed_not_null()) {} template template void not_null>::reset(U* ptr) { this->throw_if_null(ptr); this->mutable_unwrap().reset(ptr); } template template void not_null>::reset(not_null ptr) noexcept { this->mutable_unwrap().reset(ptr.unwrap()); } template template void not_null>::reset(U* ptr, Deleter d) { this->throw_if_null(ptr); this->mutable_unwrap().reset( ptr, this->forward_or_throw_if_null(std::move(d))); } template template void not_null>::reset(not_null ptr, Deleter d) { this->mutable_unwrap().reset( ptr.unwrap(), this->forward_or_throw_if_null(std::move(d))); } template typename not_null>::pointer not_null>::get() const noexcept { return pointer( this->unwrap().get(), guaranteed_not_null_provider::guaranteed_not_null()); } template long not_null>::use_count() const noexcept { return this->unwrap().use_count(); } template template bool not_null>::owner_before( const std::shared_ptr& other) const noexcept { return this->unwrap().owner_before(other); } template template bool not_null>::owner_before( const not_null>& other) const noexcept { return this->unwrap().owner_before(other.unwrap()); } template not_null_shared_ptr make_not_null_shared(Args&&... args) { return not_null_shared_ptr( std::make_shared(std::forward(args)...), detail::secret_guaranteed_not_null::get()); } template not_null_shared_ptr allocate_not_null_shared( const Alloc& alloc, Args&&... args) { return not_null_shared_ptr( std::allocate_shared( alloc, std::forward(args)...), detail::secret_guaranteed_not_null::get()); } /** * Comparators. */ #define FB_NOT_NULL_MK_OP(op) \ template \ bool operator op(const not_null& lhs, const T& rhs) { \ return lhs.unwrap() op rhs; \ } \ template \ bool operator op(const T& lhs, const not_null& rhs) { \ return lhs op rhs.unwrap(); \ } FB_NOT_NULL_MK_OP(==) FB_NOT_NULL_MK_OP(!=) FB_NOT_NULL_MK_OP(<) FB_NOT_NULL_MK_OP(<=) FB_NOT_NULL_MK_OP(>) FB_NOT_NULL_MK_OP(>=) #undef FB_NOT_NULL_MK_OP /** * Output. */ template std::basic_ostream& operator<<( std::basic_ostream& os, const not_null& ptr) { return os << ptr.unwrap(); } /** * Swap */ template void swap(not_null& lhs, not_null& rhs) noexcept { lhs.swap(rhs); } /** * Getters */ template Deleter* get_deleter(const not_null_shared_ptr& ptr) { return std::get_deleter(ptr.unwrap()); } /** * Casting */ template not_null_shared_ptr static_pointer_cast(const not_null_shared_ptr& r) { auto p = std::static_pointer_cast(r.unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } template not_null_shared_ptr static_pointer_cast(not_null_shared_ptr&& r) { auto p = std::static_pointer_cast(std::move(r).unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } template std::shared_ptr dynamic_pointer_cast(const not_null_shared_ptr& r) { return std::dynamic_pointer_cast(r.unwrap()); } template std::shared_ptr dynamic_pointer_cast(not_null_shared_ptr&& r) { return std::dynamic_pointer_cast(std::move(r).unwrap()); } template not_null_shared_ptr const_pointer_cast(const not_null_shared_ptr& r) { auto p = std::const_pointer_cast(r.unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } template not_null_shared_ptr const_pointer_cast(not_null_shared_ptr&& r) { auto p = std::const_pointer_cast(std::move(r).unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } template not_null_shared_ptr reinterpret_pointer_cast( const not_null_shared_ptr& r) { auto p = std::reinterpret_pointer_cast(r.unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } template not_null_shared_ptr reinterpret_pointer_cast(not_null_shared_ptr&& r) { auto p = std::reinterpret_pointer_cast(std::move(r).unwrap()); return not_null_shared_ptr( std::move(p), detail::secret_guaranteed_not_null::get()); } } // namespace folly