/// class besides some cosmetic cleanliness. Example usage:
/// alignOf<int>() returns the alignment of an int.
template <typename T>
-inline unsigned alignOf() { return AlignOf<T>::Alignment; }
+LLVM_CONSTEXPR inline unsigned alignOf() { return AlignOf<T>::Alignment; }
/// \struct AlignedCharArray
/// \brief Helper for building an aligned character array type.
return (Value + Align - 1 - Skew) / Align * Align + Skew;
}
+/// Returns the next integer (mod 2**64) that is greater than or equal to
+/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
+template <uint64_t Align>
+LLVM_CONSTEXPR inline uint64_t alignTo(uint64_t Value) {
+ static_assert(Align != 0u, "Align must be non-zero");
+ return (Value + Align - 1) / Align * Align;
+}
+
+/// \c alignTo for contexts where a constant expression is required.
+/// \sa alignTo
+///
+/// \todo FIXME: remove when \c LLVM_CONSTEXPR becomes really \c constexpr
+template <uint64_t Align>
+struct AlignTo {
+ static_assert(Align != 0u, "Align must be non-zero");
+ template <uint64_t Value>
+ struct from_value {
+ static const uint64_t value = (Value + Align - 1) / Align * Align;
+ };
+};
+
/// Returns the largest uint64_t less than or equal to \p Value and is
/// \p Skew mod \p Align. \p Align must be non-zero
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
typename... MoreTys>
-struct TrailingObjectsImpl {
+class TrailingObjectsImpl {
// The main template definition is never used -- the two
// specializations cover all possibilities.
};
template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
typename NextTy, typename... MoreTys>
-struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
- MoreTys...>
+class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
+ MoreTys...>
: public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
MoreTys...> {
typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
ParentType;
- // Ensure the methods we inherit are not hidden.
- using ParentType::getTrailingObjectsImpl;
- using ParentType::additionalSizeToAllocImpl;
+ struct RequiresRealignment {
+ static const bool value =
+ llvm::AlignOf<PrevTy>::Alignment < llvm::AlignOf<NextTy>::Alignment;
+ };
static LLVM_CONSTEXPR bool requiresRealignment() {
- return llvm::AlignOf<PrevTy>::Alignment < llvm::AlignOf<NextTy>::Alignment;
+ return RequiresRealignment::value;
}
+protected:
+ // Ensure the inherited getTrailingObjectsImpl is not hidden.
+ using ParentType::getTrailingObjectsImpl;
+
// These two functions are helper functions for
// TrailingObjects::getTrailingObjects. They recurse to the left --
// the result for each type in the list of trailing types depends on
static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl(
size_t SizeSoFar, size_t Count1,
typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
- return additionalSizeToAllocImpl(
+ return ParentType::additionalSizeToAllocImpl(
(requiresRealignment()
- ? llvm::alignTo(SizeSoFar, llvm::alignOf<NextTy>())
+ ? llvm::alignTo<llvm::AlignOf<NextTy>::Alignment>(SizeSoFar)
: SizeSoFar) +
sizeof(NextTy) * Count1,
MoreCounts...);
}
+
+ // additionalSizeToAllocImpl for contexts where a constant expression is
+ // required.
+ // FIXME: remove when LLVM_CONSTEXPR becomes really constexpr
+ template <size_t SizeSoFar, size_t Count1, size_t... MoreCounts>
+ struct AdditionalSizeToAllocImpl {
+ static_assert(sizeof...(MoreTys) == sizeof...(MoreCounts),
+ "Number of counts do not match number of types");
+ static const size_t value = ParentType::template AdditionalSizeToAllocImpl<
+ (RequiresRealignment::value
+ ? llvm::AlignTo<llvm::AlignOf<NextTy>::Alignment>::
+ template from_value<SizeSoFar>::value
+ : SizeSoFar) +
+ sizeof(NextTy) * Count1,
+ MoreCounts...>::value;
+ };
};
// The base case of the TrailingObjectsImpl inheritance recursion,
// when there's no more trailing types.
template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
-struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
+class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
: public TrailingObjectsAligner<Align> {
+protected:
// This is a dummy method, only here so the "using" doesn't fail --
// it will never be called, because this function recurses backwards
// up the inheritance chain to subclasses.
return SizeSoFar;
}
+ // additionalSizeToAllocImpl for contexts where a constant expression is
+ // required.
+ // FIXME: remove when LLVM_CONSTEXPR becomes really constexpr
+ template <size_t SizeSoFar> struct AdditionalSizeToAllocImpl {
+ static const size_t value = SizeSoFar;
+ };
+
template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
};
BaseTy, TrailingTys...> {
template <int A, typename B, typename T, typename P, typename... M>
- friend struct trailing_objects_internal::TrailingObjectsImpl;
+ friend class trailing_objects_internal::TrailingObjectsImpl;
template <typename... Tys> class Foo {};
return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
}
+ // totalSizeToAlloc for contexts where a constant expression is required.
+ // FIXME: remove when LLVM_CONSTEXPR becomes really constexpr
+ template <typename... Tys> struct TotalSizeToAlloc {
+ static_assert(
+ std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value,
+ "Arguments to TotalSizeToAlloc do not match with TrailingObjects");
+ template <size_t... Counts> struct with_counts {
+ static_assert(sizeof...(TrailingTys) == sizeof...(Counts),
+ "Number of counts do not match number of types");
+ static const size_t value =
+ sizeof(BaseTy) +
+ ParentType::template AdditionalSizeToAllocImpl<0, Counts...>::value;
+ };
+ };
+
/// A type where its ::with_counts template member has a ::type member
/// suitable for use as uninitialized storage for an object with the given
/// trailing object counts. The template arguments are similar to those
/// \endcode
template <typename... Tys> struct FixedSizeStorage {
template <size_t... Counts> struct with_counts {
- enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
+ enum {
+ Size = TotalSizeToAlloc<Tys...>::template with_counts<Counts...>::value
+ };
typedef llvm::AlignedCharArray<
llvm::AlignOf<BaseTy>::Alignment, Size
> type;
unsigned numShorts() const { return NumShorts; }
// Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
using TrailingObjects::totalSizeToAlloc;
using TrailingObjects::additionalSizeToAlloc;
using TrailingObjects::getTrailingObjects;
}
// Pull some protected members in as public, for testability.
+ template <typename... Ty>
+ using FixedSizeStorage = TrailingObjects::FixedSizeStorage<Ty...>;
+
using TrailingObjects::totalSizeToAlloc;
using TrailingObjects::additionalSizeToAlloc;
using TrailingObjects::getTrailingObjects;
EXPECT_EQ(Class1::additionalSizeToAlloc<short>(1), sizeof(short));
EXPECT_EQ(Class1::additionalSizeToAlloc<short>(3), sizeof(short) * 3);
+ EXPECT_EQ(
+ llvm::alignOf<Class1>(),
+ llvm::alignOf<Class1::FixedSizeStorage<short>::with_counts<1>::type>());
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<1>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(1),
+ llvm::alignOf<Class1>()));
EXPECT_EQ(Class1::totalSizeToAlloc<short>(1), sizeof(Class1) + sizeof(short));
+
+ EXPECT_EQ(
+ llvm::alignOf<Class1>(),
+ llvm::alignOf<Class1::FixedSizeStorage<short>::with_counts<3>::type>());
+ EXPECT_EQ(sizeof(Class1::FixedSizeStorage<short>::with_counts<3>::type),
+ llvm::alignTo(Class1::totalSizeToAlloc<short>(3),
+ llvm::alignOf<Class1>()));
EXPECT_EQ(Class1::totalSizeToAlloc<short>(3),
sizeof(Class1) + sizeof(short) * 3);
EXPECT_EQ((Class2::additionalSizeToAlloc<double, short>(3, 1)),
sizeof(double) * 3 + sizeof(short));
+ EXPECT_EQ(
+ llvm::alignOf<Class2>(),
+ (llvm::alignOf<
+ Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type>()));
+ EXPECT_EQ(
+ sizeof(Class2::FixedSizeStorage<double, short>::with_counts<1, 1>::type),
+ llvm::alignTo(Class2::totalSizeToAlloc<double, short>(1, 1),
+ llvm::alignOf<Class2>()));
EXPECT_EQ((Class2::totalSizeToAlloc<double, short>(1, 1)),
sizeof(Class2) + sizeof(double) + sizeof(short));
EXPECT_EQ((Class3::additionalSizeToAlloc<double, short, bool>(1, 1, 3)),
sizeof(double) + sizeof(short) + 3 * sizeof(bool));
EXPECT_EQ(sizeof(Class3), llvm::alignTo(1, llvm::alignOf<double>()));
+
+ EXPECT_EQ(llvm::alignOf<Class3>(),
+ (llvm::alignOf<Class3::FixedSizeStorage<
+ double, short, bool>::with_counts<1, 1, 3>::type>()));
+ EXPECT_EQ(
+ sizeof(Class3::FixedSizeStorage<double, short,
+ bool>::with_counts<1, 1, 3>::type),
+ llvm::alignTo(Class3::totalSizeToAlloc<double, short, bool>(1, 1, 3),
+ llvm::alignOf<Class3>()));
+
std::unique_ptr<char[]> P(new char[1000]);
Class3 *C = reinterpret_cast<Class3 *>(P.get());
EXPECT_EQ(C->getTrailingObjects<double>(), reinterpret_cast<double *>(C + 1));
EXPECT_EQ((Class4::additionalSizeToAlloc<char, long>(1, 1)),
llvm::alignTo(sizeof(long) + 1, llvm::alignOf<long>()));
EXPECT_EQ(sizeof(Class4), llvm::alignTo(1, llvm::alignOf<long>()));
+
+ EXPECT_EQ(
+ llvm::alignOf<Class4>(),
+ (llvm::alignOf<
+ Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type>()));
+ EXPECT_EQ(
+ sizeof(Class4::FixedSizeStorage<char, long>::with_counts<1, 1>::type),
+ llvm::alignTo(Class4::totalSizeToAlloc<char, long>(1, 1),
+ llvm::alignOf<Class4>()));
+
std::unique_ptr<char[]> P(new char[1000]);
Class4 *C = reinterpret_cast<Class4 *>(P.get());
EXPECT_EQ(C->getTrailingObjects<char>(), reinterpret_cast<char *>(C + 1));