123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- #pragma once
- #include <c10/macros/Macros.h>
- #include <c10/util/Exception.h>
- #include <c10/util/in_place.h>
- #include <type_traits>
- namespace c10 {
- /// MaybeOwnedTraits<T> describes how to borrow from T. Here is how we
- /// can implement borrowing from an arbitrary type T using a raw
- /// pointer to const:
- template <typename T>
- struct MaybeOwnedTraitsGenericImpl {
- using owned_type = T;
- using borrow_type = const T*;
- static borrow_type createBorrow(const owned_type& from) {
- return &from;
- }
- static void assignBorrow(borrow_type& lhs, borrow_type rhs) {
- lhs = rhs;
- }
- static void destroyBorrow(borrow_type& /*toDestroy*/) {}
- static const owned_type& referenceFromBorrow(const borrow_type& borrow) {
- return *borrow;
- }
- static const owned_type* pointerFromBorrow(const borrow_type& borrow) {
- return borrow;
- }
- static bool debugBorrowIsValid(const borrow_type& borrow) {
- return borrow != nullptr;
- }
- };
- /// It is possible to eliminate the extra layer of indirection for
- /// borrows for some types that we control. For examples, see
- /// intrusive_ptr.h and TensorBody.h.
- template <typename T>
- struct MaybeOwnedTraits;
- // Explicitly enable MaybeOwned<shared_ptr<T>>, rather than allowing
- // MaybeOwned to be used for any type right away.
- template <typename T>
- struct MaybeOwnedTraits<std::shared_ptr<T>>
- : public MaybeOwnedTraitsGenericImpl<std::shared_ptr<T>> {};
- /// A smart pointer around either a borrowed or owned T. When
- /// constructed with borrowed(), the caller MUST ensure that the
- /// borrowed-from argument outlives this MaybeOwned<T>. Compare to
- /// Rust's std::borrow::Cow
- /// (https://doc.rust-lang.org/std/borrow/enum.Cow.html), but note
- /// that it is probably not suitable for general use because C++ has
- /// no borrow checking. Included here to support
- /// Tensor::expect_contiguous.
- template <typename T>
- class MaybeOwned final {
- using borrow_type = typename MaybeOwnedTraits<T>::borrow_type;
- using owned_type = typename MaybeOwnedTraits<T>::owned_type;
- bool isBorrowed_;
- union {
- borrow_type borrow_;
- owned_type own_;
- };
- /// Don't use this; use borrowed() instead.
- explicit MaybeOwned(const owned_type& t)
- : isBorrowed_(true), borrow_(MaybeOwnedTraits<T>::createBorrow(t)) {}
- /// Don't use this; use owned() instead.
- explicit MaybeOwned(T&& t) noexcept(
- std::is_nothrow_move_constructible<T>::value)
- : isBorrowed_(false), own_(std::move(t)) {}
- /// Don't use this; use owned() instead.
- template <class... Args>
- explicit MaybeOwned(in_place_t, Args&&... args)
- : isBorrowed_(false), own_(std::forward<Args>(args)...) {}
- public:
- explicit MaybeOwned() : isBorrowed_(true), borrow_() {}
- // Copying a borrow yields another borrow of the original, as with a
- // T*. Copying an owned T yields another owned T for safety: no
- // chains of borrowing by default! (Note you could get that behavior
- // with MaybeOwned<T>::borrowed(*rhs) if you wanted it.)
- MaybeOwned(const MaybeOwned& rhs) : isBorrowed_(rhs.isBorrowed_) {
- if (C10_LIKELY(rhs.isBorrowed_)) {
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- } else {
- new (&own_) T(rhs.own_);
- }
- }
- MaybeOwned& operator=(const MaybeOwned& rhs) {
- if (this == &rhs) {
- return *this;
- }
- if (C10_UNLIKELY(!isBorrowed_)) {
- if (rhs.isBorrowed_) {
- own_.~T();
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- isBorrowed_ = true;
- } else {
- own_ = rhs.own_;
- }
- } else {
- if (C10_LIKELY(rhs.isBorrowed_)) {
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- } else {
- MaybeOwnedTraits<T>::destroyBorrow(borrow_);
- new (&own_) T(rhs.own_);
- isBorrowed_ = false;
- }
- }
- TORCH_INTERNAL_ASSERT_DEBUG_ONLY(isBorrowed_ == rhs.isBorrowed_);
- return *this;
- }
- MaybeOwned(MaybeOwned&& rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value)
- : isBorrowed_(rhs.isBorrowed_) {
- if (C10_LIKELY(rhs.isBorrowed_)) {
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- } else {
- new (&own_) T(std::move(rhs.own_));
- }
- }
- MaybeOwned& operator=(MaybeOwned&& rhs) noexcept(
- std::is_nothrow_move_assignable<T>::value) {
- if (this == &rhs) {
- return *this;
- }
- if (C10_UNLIKELY(!isBorrowed_)) {
- if (rhs.isBorrowed_) {
- own_.~T();
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- isBorrowed_ = true;
- } else {
- own_ = std::move(rhs.own_);
- }
- } else {
- if (C10_LIKELY(rhs.isBorrowed_)) {
- MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
- } else {
- MaybeOwnedTraits<T>::destroyBorrow(borrow_);
- new (&own_) T(std::move(rhs.own_));
- isBorrowed_ = false;
- }
- }
- TORCH_INTERNAL_ASSERT_DEBUG_ONLY(isBorrowed_ == rhs.isBorrowed_);
- return *this;
- }
- static MaybeOwned borrowed(const T& t) {
- return MaybeOwned(t);
- }
- static MaybeOwned owned(T&& t) noexcept(
- std::is_nothrow_move_constructible<T>::value) {
- return MaybeOwned(std::move(t));
- }
- template <class... Args>
- static MaybeOwned owned(in_place_t, Args&&... args) {
- return MaybeOwned(in_place, std::forward<Args>(args)...);
- }
- ~MaybeOwned() {
- if (C10_UNLIKELY(!isBorrowed_)) {
- own_.~T();
- } else {
- MaybeOwnedTraits<T>::destroyBorrow(borrow_);
- }
- }
- // This is an implementation detail! You should know what you're doing
- // if you are testing this. If you just want to guarantee ownership move
- // this into a T
- bool unsafeIsBorrowed() const {
- return isBorrowed_;
- }
- const T& operator*() const& {
- if (isBorrowed_) {
- TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
- MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
- }
- return C10_LIKELY(isBorrowed_)
- ? MaybeOwnedTraits<T>::referenceFromBorrow(borrow_)
- : own_;
- }
- const T* operator->() const {
- if (isBorrowed_) {
- TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
- MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
- }
- return C10_LIKELY(isBorrowed_)
- ? MaybeOwnedTraits<T>::pointerFromBorrow(borrow_)
- : &own_;
- }
- // If borrowed, copy the underlying T. If owned, move from
- // it. borrowed/owned state remains the same, and either we
- // reference the same borrow as before or we are an owned moved-from
- // T.
- T operator*() && {
- if (isBorrowed_) {
- TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
- MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
- return MaybeOwnedTraits<T>::referenceFromBorrow(borrow_);
- } else {
- return std::move(own_);
- }
- }
- };
- } // namespace c10
|