157 lines · cpp
1//===- unittest/ADT/IntrusiveRefCntPtrTest.cpp ----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/IntrusiveRefCntPtr.h"10#include "gtest/gtest.h"11 12namespace llvm {13 14namespace {15int NumInstances = 0;16template <template <typename> class Base>17struct SimpleRefCounted : Base<SimpleRefCounted<Base>> {18 SimpleRefCounted() { ++NumInstances; }19 SimpleRefCounted(const SimpleRefCounted &RHS) : Base<SimpleRefCounted>(RHS) {20 ++NumInstances;21 }22 ~SimpleRefCounted() { --NumInstances; }23};24} // anonymous namespace25 26template <typename T> struct IntrusiveRefCntPtrTest : testing::Test {};27 28using IntrusiveRefCntTypes =29 ::testing::Types<SimpleRefCounted<RefCountedBase>,30 SimpleRefCounted<ThreadSafeRefCountedBase>>;31TYPED_TEST_SUITE(IntrusiveRefCntPtrTest, IntrusiveRefCntTypes, );32 33TYPED_TEST(IntrusiveRefCntPtrTest, RefCountedBaseCopyDoesNotLeak) {34 EXPECT_EQ(0, NumInstances);35 {36 TypeParam *S1 = new TypeParam;37 IntrusiveRefCntPtr<TypeParam> R1 = S1;38 TypeParam *S2 = new TypeParam(*S1);39 IntrusiveRefCntPtr<TypeParam> R2 = S2;40 EXPECT_EQ(2, NumInstances);41 }42 EXPECT_EQ(0, NumInstances);43}44 45TYPED_TEST(IntrusiveRefCntPtrTest, InteropsWithUniquePtr) {46 EXPECT_EQ(0, NumInstances);47 {48 auto S1 = std::make_unique<TypeParam>();49 IntrusiveRefCntPtr<TypeParam> R1 = std::move(S1);50 EXPECT_EQ(1, NumInstances);51 EXPECT_EQ(S1, nullptr);52 }53 EXPECT_EQ(0, NumInstances);54}55 56TYPED_TEST(IntrusiveRefCntPtrTest, MakeIntrusiveRefCnt) {57 EXPECT_EQ(0, NumInstances);58 {59 auto S1 = makeIntrusiveRefCnt<TypeParam>();60 auto S2 = makeIntrusiveRefCnt<const TypeParam>();61 EXPECT_EQ(2, NumInstances);62 static_assert(63 std::is_same<decltype(S1), IntrusiveRefCntPtr<TypeParam>>::value,64 "Non-const type mismatch");65 static_assert(66 std::is_same<decltype(S2), IntrusiveRefCntPtr<const TypeParam>>::value,67 "Const type mismatch");68 }69 EXPECT_EQ(0, NumInstances);70}71 72struct InterceptRefCounted : public RefCountedBase<InterceptRefCounted> {73 InterceptRefCounted(bool *Released, bool *Retained)74 : Released(Released), Retained(Retained) {}75 bool * const Released;76 bool * const Retained;77};78template <> struct IntrusiveRefCntPtrInfo<InterceptRefCounted> {79 static void retain(InterceptRefCounted *I) {80 *I->Retained = true;81 I->Retain();82 }83 static void release(InterceptRefCounted *I) {84 *I->Released = true;85 I->Release();86 }87};88TEST(IntrusiveRefCntPtr, UsesTraitsToRetainAndRelease) {89 bool Released = false;90 bool Retained = false;91 {92 InterceptRefCounted *I = new InterceptRefCounted(&Released, &Retained);93 IntrusiveRefCntPtr<InterceptRefCounted> R = I;94 }95 EXPECT_TRUE(Released);96 EXPECT_TRUE(Retained);97}98 99// Test that the generic constructors use SFINAE to disable invalid100// conversions.101struct X : RefCountedBase<X> {};102struct Y : X {};103struct Z : RefCountedBase<Z> {};104static_assert(105 !std::is_convertible_v<IntrusiveRefCntPtr<X> &&, IntrusiveRefCntPtr<Y>>,106 "X&& -> Y should be rejected with SFINAE");107static_assert(!std::is_convertible_v<const IntrusiveRefCntPtr<X> &,108 IntrusiveRefCntPtr<Y>>,109 "const X& -> Y should be rejected with SFINAE");110static_assert(!std::is_convertible_v<std::unique_ptr<X>, IntrusiveRefCntPtr<Y>>,111 "X -> Y should be rejected with SFINAE");112static_assert(113 !std::is_convertible_v<IntrusiveRefCntPtr<X> &&, IntrusiveRefCntPtr<Z>>,114 "X&& -> Z should be rejected with SFINAE");115static_assert(!std::is_convertible_v<const IntrusiveRefCntPtr<X> &,116 IntrusiveRefCntPtr<Z>>,117 "const X& -> Z should be rejected with SFINAE");118static_assert(!std::is_convertible_v<std::unique_ptr<X>, IntrusiveRefCntPtr<Z>>,119 "X -> Z should be rejected with SFINAE");120 121TEST(IntrusiveRefCntPtr, InteropsWithConvertible) {122 // Check converting constructors and operator=.123 auto Y1 = makeIntrusiveRefCnt<Y>();124 auto Y2 = makeIntrusiveRefCnt<Y>();125 auto Y3 = makeIntrusiveRefCnt<Y>();126 auto Y4 = makeIntrusiveRefCnt<Y>();127 const void *P1 = Y1.get();128 const void *P2 = Y2.get();129 const void *P3 = Y3.get();130 const void *P4 = Y4.get();131 IntrusiveRefCntPtr<X> X1 = std::move(Y1);132 IntrusiveRefCntPtr<X> X2 = Y2;133 IntrusiveRefCntPtr<X> X3;134 IntrusiveRefCntPtr<X> X4;135 X3 = std::move(Y3);136 X4 = Y4;137 EXPECT_EQ(P1, X1.get());138 EXPECT_EQ(P2, X2.get());139 EXPECT_EQ(P3, X3.get());140 EXPECT_EQ(P4, X4.get());141}142 143TEST(IntrusiveRefCntPtrTest, Unique) {144 IntrusiveRefCntPtr<X> X1;145 EXPECT_EQ(X1.useCount(), 0u);146 X1 = new X();147 EXPECT_EQ(X1.useCount(), 1u);148 {149 IntrusiveRefCntPtr<X> X2 = X1;150 EXPECT_EQ(X1.useCount(), 2u);151 EXPECT_EQ(X2.useCount(), 2u);152 }153 EXPECT_EQ(X1.useCount(), 1u);154}155 156} // end namespace llvm157