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 13using namespace llvm; 14 15namespace { 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. 19class Class1 final : protected TrailingObjects<Class1, short> { 20 friend TrailingObjects; 21 22 unsigned NumShorts; 23 24protected: 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 32public: 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 using TrailingObjects::totalSizeToAlloc; 45 using TrailingObjects::additionalSizeToAlloc; 46 using TrailingObjects::getTrailingObjects; 47}; 48 49// Here, there are two singular optional object types appended. Note 50// that the alignment of Class2 is automatically increased to account 51// for the alignment requirements of the trailing objects. 52class Class2 final : protected TrailingObjects<Class2, double, short> { 53 friend TrailingObjects; 54 55 bool HasShort, HasDouble; 56 57protected: 58 size_t numTrailingObjects(OverloadToken<short>) const { 59 return HasShort ? 1 : 0; 60 } 61 size_t numTrailingObjects(OverloadToken<double>) const { 62 return HasDouble ? 1 : 0; 63 } 64 65 Class2(bool HasShort, bool HasDouble) 66 : HasShort(HasShort), HasDouble(HasDouble) {} 67 68public: 69 static Class2 *create(short S = 0, double D = 0.0) { 70 bool HasShort = S != 0; 71 bool HasDouble = D != 0.0; 72 73 void *Mem = 74 ::operator new(totalSizeToAlloc<double, short>(HasDouble, HasShort)); 75 Class2 *C = new (Mem) Class2(HasShort, HasDouble); 76 if (HasShort) 77 *C->getTrailingObjects<short>() = S; 78 if (HasDouble) 79 *C->getTrailingObjects<double>() = D; 80 return C; 81 } 82 void operator delete(void *p) { ::operator delete(p); } 83 84 short getShort() const { 85 if (!HasShort) 86 return 0; 87 return *getTrailingObjects<short>(); 88 } 89 90 double getDouble() const { 91 if (!HasDouble) 92 return 0.0; 93 return *getTrailingObjects<double>(); 94 } 95 96 // Pull some protected members in as public, for testability. 97 using TrailingObjects::totalSizeToAlloc; 98 using TrailingObjects::additionalSizeToAlloc; 99 using TrailingObjects::getTrailingObjects; 100}; 101 102TEST(TrailingObjects, OneArg) { 103 int arr[] = {1, 2, 3}; 104 Class1 *C = Class1::create(arr, 3); 105 EXPECT_EQ(sizeof(Class1), sizeof(unsigned)); 106 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short)); 107 EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3); 108 109 EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short)); 110 EXPECT_EQ(Class1::totalSizeToAlloc<short>(3), 111 sizeof(Class1) + sizeof(short) * 3); 112 113 EXPECT_EQ(C->getTrailingObjects<short>(), reinterpret_cast<short *>(C + 1)); 114 EXPECT_EQ(C->get(0), 1); 115 EXPECT_EQ(C->get(2), 3); 116 delete C; 117} 118 119TEST(TrailingObjects, TwoArg) { 120 Class2 *C1 = Class2::create(4); 121 Class2 *C2 = Class2::create(0, 4.2); 122 123 EXPECT_EQ(sizeof(Class2), 124 llvm::alignTo(sizeof(bool) * 2, llvm::alignOf<double>())); 125 EXPECT_EQ(llvm::alignOf<Class2>(), llvm::alignOf<double>()); 126 127 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(1, 0)), 128 sizeof(double)); 129 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(0, 1)), 130 sizeof(short)); 131 EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)), 132 sizeof(double) * 3 + sizeof(short)); 133 134 EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)), 135 sizeof(Class2) + sizeof(double) + sizeof(short)); 136 137 EXPECT_EQ(C1->getDouble(), 0); 138 EXPECT_EQ(C1->getShort(), 4); 139 EXPECT_EQ(C1->getTrailingObjects<double>(), 140 reinterpret_cast<double *>(C1 + 1)); 141 EXPECT_EQ(C1->getTrailingObjects<short>(), reinterpret_cast<short *>(C1 + 1)); 142 143 EXPECT_EQ(C2->getDouble(), 4.2); 144 EXPECT_EQ(C2->getShort(), 0); 145 EXPECT_EQ(C2->getTrailingObjects<double>(), 146 reinterpret_cast<double *>(C2 + 1)); 147 EXPECT_EQ(C2->getTrailingObjects<short>(), 148 reinterpret_cast<short *>(reinterpret_cast<double *>(C2 + 1) + 1)); 149 delete C1; 150 delete C2; 151} 152 153// This test class is not trying to be a usage demo, just asserting 154// that three args does actually work too (it's the same code as 155// handles the second arg, so it's basically covered by the above, but 156// just in case..) 157class Class3 final : public TrailingObjects<Class3, double, short, bool> { 158 friend TrailingObjects; 159 160 size_t numTrailingObjects(OverloadToken<double>) const { return 1; } 161 size_t numTrailingObjects(OverloadToken<short>) const { return 1; } 162}; 163 164TEST(TrailingObjects, ThreeArg) { 165 EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)), 166 sizeof(double) + sizeof(short) + 3 * sizeof(bool)); 167 EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, llvm::alignOf<double>())); 168 std::unique_ptr<char[]> P(new char[1000]); 169 Class3 *C = reinterpret_cast<Class3 *>(P.get()); 170 EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1)); 171 EXPECT_EQ(C->getTrailingObjects<short>(), 172 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1)); 173 EXPECT_EQ( 174 C->getTrailingObjects<bool>(), 175 reinterpret_cast<bool *>( 176 reinterpret_cast<short *>(reinterpret_cast<double *>(C + 1) + 1) + 177 1)); 178} 179 180class Class4 final : public TrailingObjects<Class4, char, long> { 181 friend TrailingObjects; 182 size_t numTrailingObjects(OverloadToken<char>) const { return 1; } 183}; 184 185TEST(TrailingObjects, Realignment) { 186 EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)), 187 llvm::alignTo(sizeof(long) + 1, llvm::alignOf<long>())); 188 EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, llvm::alignOf<long>())); 189 std::unique_ptr<char[]> P(new char[1000]); 190 Class4 *C = reinterpret_cast<Class4 *>(P.get()); 191 EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1)); 192 EXPECT_EQ(C->getTrailingObjects<long>(), 193 reinterpret_cast<long *>(llvm::alignAddr( 194 reinterpret_cast<char *>(C + 1) + 1, llvm::alignOf<long>()))); 195} 196} 197