Created
July 11, 2016 16:37
-
-
Save PolarNick239/6729534723966a7ad35208ecc896eff5 to your computer and use it in GitHub Desktop.
Aligned allocator useful for constructing SSE intrinsics-friendly std::vector<type128, AlignedAllocator<type128, 16> >.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstddef> | |
#include <stdexcept> | |
#include <emmintrin.h> | |
#ifndef _MSC_VER | |
#include <mm_malloc.h> | |
#endif | |
class type128 { | |
public: | |
type128() {} | |
type128(const __m128i &value) { | |
*this = value; | |
} | |
operator const __m128i & () const { | |
return *reinterpret_cast<const __m128i *>(bytes); | |
} | |
operator __m128i & () { | |
return *reinterpret_cast<__m128i *>(bytes); | |
} | |
type128& operator=(const __m128i& value) { | |
*reinterpret_cast<__m128i *>(bytes) = value; | |
return *this; | |
} | |
private: | |
char bytes[16]; | |
}; | |
/** | |
* Allocator for aligned data. | |
* | |
* Code taken from: | |
* https://gist.github.com/donny-dont/1471329 | |
* | |
* Modified from the Mallocator from Stephan T. Lavavej. | |
* <http://blogs.msdn.com/b/vcblog/archive/2008/08/28/the-mallocator.aspx> | |
*/ | |
template <typename T, std::size_t Alignment> | |
class AlignedAllocator | |
{ | |
public: | |
// The following will be the same for virtually all allocators. | |
typedef T * pointer; | |
typedef const T * const_pointer; | |
typedef T& reference; | |
typedef const T& const_reference; | |
typedef T value_type; | |
typedef std::size_t size_type; | |
typedef ptrdiff_t difference_type; | |
T * address(T& r) const | |
{ | |
return &r; | |
} | |
const T * address(const T& s) const | |
{ | |
return &s; | |
} | |
std::size_t max_size() const | |
{ | |
// The following has been carefully written to be independent of | |
// the definition of size_t and to avoid signed/unsigned warnings. | |
return (static_cast<std::size_t>(0) - static_cast<std::size_t>(1)) / sizeof(T); | |
} | |
// The following must be the same for all allocators. | |
template <typename U> | |
struct rebind | |
{ | |
typedef AlignedAllocator<U, Alignment> other; | |
} ; | |
bool operator!=(const AlignedAllocator& other) const | |
{ | |
return !(*this == other); | |
} | |
void construct(T * const p, const T& t) const | |
{ | |
void * const pv = static_cast<void *>(p); | |
new (pv) T(t); | |
} | |
void destroy(T * const p) const | |
{ | |
p->~T(); | |
} | |
// Returns true if and only if storage allocated from *this | |
// can be deallocated from other, and vice versa. | |
// Always returns true for stateless allocators. | |
bool operator==(const AlignedAllocator& other) const | |
{ | |
return true; | |
} | |
// Default constructor, copy constructor, rebinding constructor, and destructor. | |
// Empty for stateless allocators. | |
AlignedAllocator() { } | |
AlignedAllocator(const AlignedAllocator&) { } | |
template <typename U> AlignedAllocator(const AlignedAllocator<U, Alignment>&) { } | |
~AlignedAllocator() { } | |
// The following will be different for each allocator. | |
T * allocate(const std::size_t n) const | |
{ | |
// The return value of allocate(0) is unspecified. | |
// Mallocator returns NULL in order to avoid depending | |
// on malloc(0)'s implementation-defined behavior | |
// (the implementation can define malloc(0) to return NULL, | |
// in which case the bad_alloc check below would fire). | |
// All allocators can return NULL in this case. | |
if (n == 0) { | |
return NULL; | |
} | |
// All allocators should contain an integer overflow check. | |
// The Standardization Committee recommends that std::length_error | |
// be thrown in the case of integer overflow. | |
if (n > max_size()) | |
{ | |
throw std::length_error("AlignedAllocator<T>::allocate() - Integer overflow."); | |
} | |
// Mallocator wraps malloc(). | |
void * const pv = _mm_malloc(n * sizeof(T), Alignment); | |
// Allocators should throw std::bad_alloc in the case of memory allocation failure. | |
if (pv == NULL) | |
{ | |
throw std::bad_alloc(); | |
} | |
return static_cast<T *>(pv); | |
} | |
void deallocate(T * const p, const std::size_t n) const | |
{ | |
_mm_free(p); | |
} | |
// The following will be the same for all allocators that ignore hints. | |
template <typename U> | |
T * allocate(const std::size_t n, const U * /* const hint */) const | |
{ | |
return allocate(n); | |
} | |
// Allocators are not required to be assignable, so | |
// all allocators should have a private unimplemented | |
// assignment operator. Note that this will trigger the | |
// off-by-default (enabled under /Wall) warning C4626 | |
// "assignment operator could not be generated because a | |
// base class assignment operator is inaccessible" within | |
// the STL headers, but that warning is useless. | |
private: | |
AlignedAllocator& operator=(const AlignedAllocator&); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment