diff --git a/Aligned.hpp b/Aligned.hpp index 28a0ce4..2e5c2be 100644 --- a/Aligned.hpp +++ b/Aligned.hpp @@ -5,74 +5,65 @@ #include #include #include "AlignedBase.hpp" -#include "RoundUp.hpp" + +#define ALIGNED_BYTES_SIZE(T, sizeOfTPaddedToAlignment) sizeof(T) + sizeOfTPaddedToAlignment - 1 +#define ALIGNED_REF(T, bytes, sizeOfTPaddedToAlignment) *reinterpret_cast(uintptr_t(bytes) + (sizeOfTPaddedToAlignment - 1) & ~uintptr_t(sizeOfTPaddedToAlignment - 1)) +#define ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size) sizeof(T) + (sizeOfTPaddedToAlignment * size) - 1 +#define ALIGNED_ARRAY_INDEX(T, bytes, sizeOfTPaddedToAlignment, index) *reinterpret_cast((uintptr_t(bytes) + (sizeOfTPaddedToAlignment - 1) & ~uintptr_t(sizeOfTPaddedToAlignment - 1)) + (sizeOfTPaddedToAlignment * index)) template -class Aligned : AlignedBase { - static const std::size_t SizeOfTPaddedToAlignmentLessOne = RoundUp::value - 1; -protected: - uint8_t bytes[SizeOfTPaddedToAlignmentLessOne + SizeOfTPaddedToAlignmentLessOne + 1]; +class Aligned : AlignedBase { + uint8_t bytes[ALIGNED_BYTES_SIZE(T, SizeOfTPaddedToAlignment)]; public: - class PaddedType { uint8_t bytes[RoundUp::value]; }; Aligned() {} Aligned(T const & value) { ref() = value; } - T & ref() { - return *reinterpret_cast(uintptr_t(bytes) + SizeOfTPaddedToAlignmentLessOne & ~uintptr_t(SizeOfTPaddedToAlignmentLessOne)); - } + T & ref() { return ALIGNED_REF(T, bytes, SizeOfTPaddedToAlignment); } + T const & ref() const { return ref(); } +}; + +template +class Aligned : AlignedBase { + std::unique_ptr const pBytes; +protected: + Aligned(std::size_t alignment, void * ignoredParameterForOverload) : AlignedBase(alignment), pBytes(new uint8_t[alignment + sizeOfTPaddedToAlignment - 1]) {} +public: + Aligned(std::size_t alignment) : AlignedBase(alignment), pBytes(new uint8_t[ALIGNED_BYTES_SIZE(T, sizeOfTPaddedToAlignment)]) {} + Aligned(std::size_t alignment, T const & value) : Aligned(alignment) { ref() = value; } + T & ref() { return ALIGNED_REF(T, pBytes.get(), sizeOfTPaddedToAlignment); } T const & ref() const { return ref(); } }; template -class Aligned : AlignedBase { - static const std::size_t SizeOfTPaddedToAlignment = RoundUp::value; - uint8_t bytes[sizeof(T) + (SizeOfTPaddedToAlignment * Size) - 1]; +class Aligned : AlignedBase { + uint8_t bytes[ALIGNED_ARRAY_BYTES_SIZE(T, SizeOfTPaddedToAlignment, Size)]; public: Aligned() {} - T & operator[](std::size_t index) { - return *reinterpret_cast((uintptr_t(bytes) + (SizeOfTPaddedToAlignment - 1) & ~uintptr_t(SizeOfTPaddedToAlignment - 1)) + (SizeOfTPaddedToAlignment * index)); - } + T & operator[](std::size_t index) { return ALIGNED_ARRAY_INDEX(T, bytes, SizeOfTPaddedToAlignment, index); } T const & operator[](std::size_t index) const { return operator[](index); } }; template -class Aligned : AlignedBase{ - static const std::size_t SizeOfTPaddedToAlignment = RoundUp::value; +class Aligned : AlignedBase { std::unique_ptr const pBytes; - Aligned(); public: - Aligned(std::size_t size) : pBytes(new uint8_t[sizeof(T) + (SizeOfTPaddedToAlignment * size) - 1]) {} - T & operator[](std::size_t index) { - return *reinterpret_cast((uintptr_t(pBytes.get()) + (SizeOfTPaddedToAlignment - 1) & ~uintptr_t(SizeOfTPaddedToAlignment - 1)) + (SizeOfTPaddedToAlignment * index)); - } + Aligned(std::size_t size) : pBytes(new uint8_t[ALIGNED_ARRAY_BYTES_SIZE(T, SizeOfTPaddedToAlignment, size)]) {} + T & operator[](std::size_t index) { return ALIGNED_ARRAY_INDEX(T, pBytes.get(), SizeOfTPaddedToAlignment, index); } T const & operator[](std::size_t index) const { return operator[](index); } }; template -class Aligned : AlignedBase<-1>{ - std::size_t const sizeOfTPaddedToAlignmentLessOne; +class Aligned : AlignedBase { std::unique_ptr const pBytes; -public: - Aligned(std::size_t alignment = AlignedBase::cacheLineSize()) : AlignedBase(alignment), sizeOfTPaddedToAlignmentLessOne(roundUp(sizeof(T), alignment) - 1), pBytes(new uint8_t[sizeof(T) +sizeOfTPaddedToAlignmentLessOne]) {} - Aligned(T const & value, std::size_t alignment) : Aligned(alignment) { ref() = value; } - T & ref() { - return *reinterpret_cast(uintptr_t(pBytes.get()) + sizeOfTPaddedToAlignmentLessOne & ~uintptr_t(sizeOfTPaddedToAlignmentLessOne)); - } - T const & ref() const { return ref(); } -}; - -template -class Aligned : AlignedBase<-1>{ - std::size_t const sizeOfTPaddedToAlignment; - std::unique_ptr const pBytes; Aligned(); public: - Aligned(std::size_t size, std::size_t alignment = AlignedBase::cacheLineSize()) - : AlignedBase<-1>(alignment), - sizeOfTPaddedToAlignment(roundUp(sizeof(T), alignment)), pBytes(new uint8_t[sizeof(T) + (sizeOfTPaddedToAlignment * size) - 1]) {} - T & operator[](std::size_t index) { - return *reinterpret_cast((uintptr_t(pBytes.get()) + (sizeOfTPaddedToAlignment - 1) & ~uintptr_t(sizeOfTPaddedToAlignment - 1)) + (sizeOfTPaddedToAlignment * index)); - } + Aligned(std::size_t alignment, std::size_t size) : AlignedBase(alignment), pBytes(new uint8_t[ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size)]) {} + T & operator[](std::size_t index) { return ALIGNED_ARRAY_INDEX(T, pBytes.get(), sizeOfTPaddedToAlignment, index); } T const & operator[](std::size_t index) const { return operator[](index); } }; +#undef ALIGNED_BYTES_SIZE +#undef ALIGNED_REF +#undef ALIGNED_ARRAY_BYTES_SIZE +#undef ALIGNED_ARRAY_INDEX + #endif \ No newline at end of file diff --git a/AlignedBase.hpp b/AlignedBase.hpp index 982f6b9..3fa0818 100644 --- a/AlignedBase.hpp +++ b/AlignedBase.hpp @@ -3,31 +3,32 @@ #include #include -#include "CacheLineSize/cacheLineSize.h" +#include "RoundUp.hpp" +#include "IsPowerOfTwo.hpp" -#define ALIGNMENT_MUST_BE_A_MULTIPLE_OF_2 "Alignment must be a multiple of 2" +#define ALIGNMENT_MUST_BE_A_POWER_OF_2 "Alignment must be a power of 2" -template +template class AlignedBase { - static_assert(Alignment % 2 == 0, ALIGNMENT_MUST_BE_A_MULTIPLE_OF_2); + static_assert(IsPowerOfTwo::Result, ALIGNMENT_MUST_BE_A_POWER_OF_2); +protected: + static const std::size_t SizeOfTPaddedToAlignment = RoundUp::Result; }; -template<> -class AlignedBase<-1> { +template +class AlignedBase { public: class AlignmentException : public std::exception { - friend class AlignedBase<-1>; - AlignmentException() : std::exception(ALIGNMENT_MUST_BE_A_MULTIPLE_OF_2) {} + friend class AlignedBase; + AlignmentException() : std::exception(ALIGNMENT_MUST_BE_A_POWER_OF_2) {} }; + AlignedBase & operator=(AlignedBase const &) = delete; protected: - AlignedBase(std::size_t alignment) { - if (alignment % 2 != 0) + std::size_t const sizeOfTPaddedToAlignment; + AlignedBase(std::size_t alignment) : sizeOfTPaddedToAlignment(roundUp(sizeof(T), alignment)) { + if (!isPowerOfTwo(alignment)) throw new AlignmentException(); } - static std::size_t cacheLineSize() { - static std::size_t cacheLineSize = cache_line_size(); - return cacheLineSize; - } }; #undef ALIGNMENT_MUST_BE_A_MULTIPLE_OF_2 diff --git a/CacheAligned.hpp b/CacheAligned.hpp new file mode 100644 index 0000000..9843d08 --- /dev/null +++ b/CacheAligned.hpp @@ -0,0 +1,35 @@ +#ifndef CACHEALIGNED_HPP_INCLUDED +#define CACHEALIGNED_HPP_INCLUDED + +#include +#include +#include "CacheAlignedBase.hpp" +#include "Aligned.hpp" +#include "RoundUp.hpp" + +template +class CacheAligned : protected Aligned, CacheAlignedBase { +public: + CacheAligned() : Aligned(cacheLineSize(), nullptr) {} + CacheAligned(T const & value) : CacheAligned() { ref() = value; } + T & ref() { return *reinterpret_cast(&Aligned::ref()); } + T const & ref() const { return ref(); } +}; + +template +class CacheAligned : Aligned, CacheAlignedBase{ +public: + CacheAligned() : Aligned(cacheLineSize(), Size) {} + T & operator[](std::size_t index) { return *reinterpret_cast(&Aligned::operator[](index)); } + T const & operator[](std::size_t index) const { return operator[](index); } +}; + +template +class CacheAligned : Aligned, CacheAlignedBase { +public: + CacheAligned(std::size_t size) : Aligned(cacheLineSize(), size) {} + T & operator[](std::size_t index) { return *reinterpret_cast(&Aligned::operator[](index)); } + T const & operator[](std::size_t index) const { return operator[](index); } +}; + +#endif \ No newline at end of file diff --git a/CacheAlignedBase.hpp b/CacheAlignedBase.hpp new file mode 100644 index 0000000..41e2cf9 --- /dev/null +++ b/CacheAlignedBase.hpp @@ -0,0 +1,15 @@ +#ifndef CACHEALIGNEDBASE_HPP_INCLUDED +#define CACHEALIGNEDBASE_HPP_INCLUDED + +#include +#include "CacheLineSize/cacheLineSize.h" + +class CacheAlignedBase { +protected: + static std::size_t cacheLineSize() { + static std::size_t cacheLineSize = cache_line_size(); + return cacheLineSize; + } +}; + +#endif \ No newline at end of file diff --git a/IsPowerOfTwo.hpp b/IsPowerOfTwo.hpp new file mode 100644 index 0000000..8112c4a --- /dev/null +++ b/IsPowerOfTwo.hpp @@ -0,0 +1,18 @@ +#ifndef ISPOWEROFTWO_HPP_INCLUDED +#define ISPOWEROFTWO_HPP_INCLUDED + +#define ISPOWEROFTWO(x) (x != 0) && ((x & (x - 1)) == 0) + +template +inline bool isPowerOfTwo(T x) { + return ISPOWEROFTWO(x); +} + +template +struct IsPowerOfTwo { + static const bool Result = ISPOWEROFTWO(X); +}; + +#undef ISPOWEROFTWO + +#endif \ No newline at end of file diff --git a/RoundUp.hpp b/RoundUp.hpp index bbd7152..6ea6d8d 100644 --- a/RoundUp.hpp +++ b/RoundUp.hpp @@ -1,14 +1,18 @@ #ifndef ROUNDUP_HPP_INCLUDED #define ROUNDUP_HPP_INCLUDED +#define ROUNDUP(from, to) from + to - 1 - (from - 1) % to + template inline T roundUp(T from, T to) { - return from + to - 1 - (from - 1) % to; + return ROUNDUP(from, to); } -template +template struct RoundUp { - enum { value = From + To - 1 - (From -1) % To }; + static const T Result = ROUNDUP(From, To); }; +#undef ROUNDUP + #endif \ No newline at end of file