Index: llvm/include/llvm/ADT/OwnedOrBorrowed.h =================================================================== --- /dev/null +++ llvm/include/llvm/ADT/OwnedOrBorrowed.h @@ -0,0 +1,99 @@ +//===- llvm/ADT/OwnedOrBorrowed.h - Owned or borrowed smart ptr -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the OwnedOrBorrowed template class that is essentially +// a variant of a unique_ptr and a T&. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_OWNEDORBORROWED_H +#define LLVM_ADT_OWNEDORBORROWED_H + +#include + +namespace llvm { +template class OwnedOrBorrowed { + std::unique_ptr Owned; + T *Borrowed; + +public: + OwnedOrBorrowed() : Borrowed(nullptr) {} + + explicit OwnedOrBorrowed(T &Ref) : Borrowed(&Ref) {} + explicit OwnedOrBorrowed(std::unique_ptr Ptr) + : Owned(std::move(Ptr)), Borrowed(Owned.get()) {} + + OwnedOrBorrowed(OwnedOrBorrowed &&Other) = default; + + OwnedOrBorrowed &operator=(OwnedOrBorrowed &&Other) = default; + + T &operator*() { return *Borrowed; } + const T &operator*() const { return *Borrowed; } + + T *operator->() { return Borrowed; } + const T *operator->() const { return Borrowed; } +}; + +template +bool operator<(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed < R.Borrowed; +} + +template +bool operator<=(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed <= R.Borrowed; +} + +template +bool operator>(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed > R.Borrowed; +} + +template +bool operator>=(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed >= R.Borrowed; +} + +template +bool operator==(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed == R.Borrowed; +} + +template +bool operator!=(const OwnedOrBorrowed &L, const OwnedOrBorrowed &R) { + return L.Borrowed != R.Borrowed; +} + +template bool operator<(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed < R.Borrowed; +} + +template bool operator<=(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed <= R.Borrowed; +} + +template bool operator>(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed > R.Borrowed; +} + +template bool operator>=(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed >= R.Borrowed; +} + +template bool operator==(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed == R.Borrowed; +} + +template bool operator!=(const OwnedOrBorrowed &L, const T *R) { + return L.Borrowed != R.Borrowed; +} + +} // end namespace llvm + +#endif // LLVM_ADT_OWNEDORBORROWED_H Index: llvm/unittests/ADT/CMakeLists.txt =================================================================== --- llvm/unittests/ADT/CMakeLists.txt +++ llvm/unittests/ADT/CMakeLists.txt @@ -39,6 +39,7 @@ MappedIteratorTest.cpp MapVectorTest.cpp OptionalTest.cpp + OwnedOrBorrowedTest.cpp PackedVectorTest.cpp PointerEmbeddedIntTest.cpp PointerIntPairTest.cpp Index: llvm/unittests/ADT/OwnedOrBorrowedTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/ADT/OwnedOrBorrowedTest.cpp @@ -0,0 +1,87 @@ +//===- llvm/ADT/OwnedOrBorrowed.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the OwnedOrBorrowed template class that is essentially +// a variant of a unique_ptr and a T&. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/OwnedOrBorrowed.h" +#include "gtest/gtest.h" + +using namespace llvm; + +struct Foo { + Foo(bool &D, bool &M, int &N) : D(D), M(M), N(N) {} + ~Foo() { D = true; } + Foo(Foo &&F) : D(F.D), M(F.M), N(F.N) { M = true; } + + bool &D; + bool &M; + + int &N; +}; + +TEST(OwnedOrBorrowedTest, Borrowed) { + bool D = false, M = false; + int N = 42; + { + Foo F(D, M, N); + { + OwnedOrBorrowed A; + { + OwnedOrBorrowed B(F); + EXPECT_EQ(42, B->N); + EXPECT_EQ(42, (*B).N); + ++B->N; + A = std::move(B); + } + EXPECT_FALSE(D); + EXPECT_FALSE(M); + + EXPECT_EQ(43, A->N); + EXPECT_EQ(43, (*A).N); + ++A->N; + } + EXPECT_FALSE(D); + EXPECT_FALSE(M); + + EXPECT_EQ(44, F.N); + } + EXPECT_TRUE(D); + EXPECT_FALSE(M); +} + +TEST(OwnedOrBorrowedTest, Owned) { + bool D = false, M = false; + int N = 42; + + { + std::unique_ptr F = llvm::make_unique(D, M, N); + { + OwnedOrBorrowed A; + { + OwnedOrBorrowed B(std::move(F)); + EXPECT_EQ(42, B->N); + EXPECT_EQ(42, (*B).N); + ++B->N; + A = std::move(B); + } + EXPECT_FALSE(D); + EXPECT_FALSE(M); + + EXPECT_EQ(43, A->N); + EXPECT_EQ(43, (*A).N); + ++A->N; + } + EXPECT_TRUE(D); + EXPECT_FALSE(M); + EXPECT_EQ(44, N); + } +}