1 //=== - llvm/unittest/Support/TrailingObjectsTest.cpp ---------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/TrailingObjects.h" 11 #include "gtest/gtest.h" 12 13 using namespace llvm; 14 15 namespace { 16 // This class, beyond being used by the test case, a nice 17 // demonstration of the intended usage of TrailingObjects, with a 18 // single trailing array. 19 class Class1 final : protected TrailingObjects<Class1, short> { 20 friend TrailingObjects; 21 22 unsigned NumShorts; 23 24 protected: 25 size_t numTrailingObjects(OverloadToken<short>) const { return NumShorts; } 26 27 Class1(int *ShortArray, unsigned NumShorts) : NumShorts(NumShorts) { 28 std::uninitialized_copy(ShortArray, ShortArray + NumShorts, 29 getTrailingObjects<short>()); 30 } 31 32 public: 33 static Class1 *create(int *ShortArray, unsigned NumShorts) { 34 void *Mem = ::operator new(totalSizeToAlloc<short>(NumShorts)); 35 return new (Mem) Class1(ShortArray, NumShorts); 36 } 37 void operator delete(void *p) { ::operator delete(p); } 38 39 short get(unsigned Num) const { return getTrailingObjects<short>()[Num]; } 40 41 unsigned numShorts() const { return NumShorts; } 42 43 // Pull some protected members in as public, for testability. 44 template <typename... Ty> 45 using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>; 46 47 using TrailingObjects::totalSizeToAlloc; 48 using TrailingObjects::additionalSizeToAlloc; 49 using TrailingObjects::getTrailingObjects; 50 }; 51 52 // Here, there are two singular optional object types appended. Note 53 // that the alignment of Class2 is automatically increased to account 54 // for the alignment requirements of the trailing objects. 55 class Class2 final : protected TrailingObjects<Class2, double, short> { 56 friend TrailingObjects; 57 58 bool HasShort, HasDouble; 59 60 protected: 61 size_t numTrailingObjects(OverloadToken<short>) const { 62 return HasShort ? 1 : 0; 63 } 64 size_t numTrailingObjects(OverloadToken<double>) const { 65 return HasDouble ? 1 : 0; 66 } 67 68 Class2(bool HasShort, bool HasDouble) 69 : HasShort(HasShort), HasDouble(HasDouble) {} 70 71 public: 72 static Class2 *create(short S = 0, double D = 0.0) { 73 bool HasShort = S != 0; 74 bool HasDouble = D != 0.0; 75 76 void *Mem = 77 ::operator new(totalSizeToAlloc<double, short>(HasDouble, HasShort)); 78 Class2 *C = new (Mem) Class2(HasShort, HasDouble); 79 if (HasShort) 80 *C->getTrailingObjects<short>() = S; 81 if (HasDouble) 82 *C->getTrailingObjects<double>() = D; 83 return C; 84 } 85 void operator delete(void *p) { ::operator delete(p); } 86 87 short getShort() const { 88 if (!HasShort) 89 return 0; 90 return *getTrailingObjects<short>(); 91 } 92 93 double getDouble() const { 94 if (!HasDouble) 95 return 0.0; 96 return *getTrailingObjects<double>(); 97 } 98 99 // Pull some protected members in as public, for testability. 100 template <typename... Ty> 101 using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>; 102 103 using TrailingObjects::totalSizeToAlloc; 104 using TrailingObjects::additionalSizeToAlloc; 105 using TrailingObjects::getTrailingObjects; 106 }; 107 108 TEST(TrailingObjects, OneArg) { 109 int arr[] = {1, 2, 3}; 110 Class1 *C = Class1::create(arr, 3); 111 EXPECT_EQ(sizeof(Class1), sizeof(unsigned)); 112 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short)); 113 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3); 114 115 EXPECT_EQ( 116 llvm::alignOf<Class1>(), 117 llvm::alignOf<Class1::FixedSizeStorage<short>::with_counts<1>::type>()); 118 EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<1>::type), 119 llvm::alignTo(Class1::totalSizeToAlloc<short>(1), 120 llvm::alignOf<Class1>())); 121 EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short)); 122 123 EXPECT_EQ( 124 llvm::alignOf<Class1>(), 125 llvm::alignOf<Class1::FixedSizeStorage<short>::with_counts<3>::type>()); 126 EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<3>::type), 127 llvm::alignTo(Class1::totalSizeToAlloc<short>(3), 128 llvm::alignOf<Class1>())); 129 EXPECT_EQ(Class1::totalSizeToAlloc<short>(3), 130 sizeof(Class1) + sizeof(short) * 3); 131 132 EXPECT_EQ(C->getTrailingObjects<short>(), reinterpret_cast<short *>(C + 1)); 133 EXPECT_EQ(C->get(0), 1); 134 EXPECT_EQ(C->get(2), 3); 135 delete C; 136 } 137 138 TEST(TrailingObjects, TwoArg) { 139 Class2 *C1 = Class2::create(4); 140 Class2 *C2 = Class2::create(0, 4.2); 141 142 EXPECT_EQ(sizeof(Class2), 143 llvm::alignTo(sizeof(bool) * 2, llvm::alignOf<double>())); 144 EXPECT_EQ(llvm::alignOf<Class2>(), llvm::alignOf<double>()); 145 146 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)), 147 sizeof(double)); 148 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(0, 1)), 149 sizeof(short)); 150 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)), 151 sizeof(double) * 3 + sizeof(short)); 152 153 EXPECT_EQ( 154 llvm::alignOf<Class2>(), 155 (llvm::alignOf< 156 Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type>())); 157 EXPECT_EQ( 158 sizeof(Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type), 159 llvm::alignTo(Class2::totalSizeToAlloc<double, short>(1, 1), 160 llvm::alignOf<Class2>())); 161 EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)), 162 sizeof(Class2) + sizeof(double) + sizeof(short)); 163 164 EXPECT_EQ(C1->getDouble(), 0); 165 EXPECT_EQ(C1->getShort(), 4); 166 EXPECT_EQ(C1->getTrailingObjects<double>(), 167 reinterpret_cast<double *>(C1 + 1)); 168 EXPECT_EQ(C1->getTrailingObjects<short>(), reinterpret_cast<short *>(C1 + 1)); 169 170 EXPECT_EQ(C2->getDouble(), 4.2); 171 EXPECT_EQ(C2->getShort(), 0); 172 EXPECT_EQ(C2->getTrailingObjects<double>(), 173 reinterpret_cast<double *>(C2 + 1)); 174 EXPECT_EQ(C2->getTrailingObjects<short>(), 175 reinterpret_cast<short *>(reinterpret_cast<double *>(C2 + 1) + 1)); 176 delete C1; 177 delete C2; 178 } 179 180 // This test class is not trying to be a usage demo, just asserting 181 // that three args does actually work too (it's the same code as 182 // handles the second arg, so it's basically covered by the above, but 183 // just in case..) 184 class Class3 final : public TrailingObjects<Class3, double, short, bool> { 185 friend TrailingObjects; 186 187 size_t numTrailingObjects(OverloadToken<double>) const { return 1; } 188 size_t numTrailingObjects(OverloadToken<short>) const { return 1; } 189 }; 190 191 TEST(TrailingObjects, ThreeArg) { 192 EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)), 193 sizeof(double) + sizeof(short) + 3 * sizeof(bool)); 194 EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, llvm::alignOf<double>())); 195 196 EXPECT_EQ(llvm::alignOf<Class3>(), 197 (llvm::alignOf<Class3::FixedSizeStorage< 198 double, short, bool>::with_counts<1, 1, 3>::type>())); 199 EXPECT_EQ( 200 sizeof(Class3::FixedSizeStorage<double, short, 201 bool>::with_counts<1, 1, 3>::type), 202 llvm::alignTo(Class3::totalSizeToAlloc<double, short, bool>(1, 1, 3), 203 llvm::alignOf<Class3>())); 204 205 std::unique_ptr<char[]> P(new char[1000]); 206 Class3 *C = reinterpret_cast<Class3 *>(P.get()); 207 EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1)); 208 EXPECT_EQ(C->getTrailingObjects<short>(), 209 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1)); 210 EXPECT_EQ( 211 C->getTrailingObjects<bool>(), 212 reinterpret_cast<bool *>( 213 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1) + 214 1)); 215 } 216 217 class Class4 final : public TrailingObjects<Class4, char, long> { 218 friend TrailingObjects; 219 size_t numTrailingObjects(OverloadToken<char>) const { return 1; } 220 }; 221 222 TEST(TrailingObjects, Realignment) { 223 EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)), 224 llvm::alignTo(sizeof(long) + 1, llvm::alignOf<long>())); 225 EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, llvm::alignOf<long>())); 226 227 EXPECT_EQ( 228 llvm::alignOf<Class4>(), 229 (llvm::alignOf< 230 Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type>())); 231 EXPECT_EQ( 232 sizeof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type), 233 llvm::alignTo(Class4::totalSizeToAlloc<char, long>(1, 1), 234 llvm::alignOf<Class4>())); 235 236 std::unique_ptr<char[]> P(new char[1000]); 237 Class4 *C = reinterpret_cast<Class4 *>(P.get()); 238 EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1)); 239 EXPECT_EQ(C->getTrailingObjects<long>(), 240 reinterpret_cast<long *>(llvm::alignAddr( 241 reinterpret_cast<char *>(C + 1) + 1, llvm::alignOf<long>()))); 242 } 243 } 244