// This file is part of Eigen, a lightweight C++ template library // for linear algebra. Eigen itself is part of the KDE project. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_MEMORY_H #define EIGEN_MEMORY_H #if defined(EIGEN_VECTORIZE) && !defined(_MSC_VER) // it seems we cannot assume posix_memalign is defined in the stdlib header extern "C" int posix_memalign (void **, size_t, size_t) throw (); #endif /** \internal * Static array automatically aligned if the total byte size is a multiple of 16 */ template struct ei_aligned_array { EIGEN_ALIGN_128 T array[Size]; ei_aligned_array() { #ifdef EIGEN_VECTORIZE // we only want this assertion if EIGEN_VECTORIZE is defined. // indeed, if it's not defined then WithAlignedOperatorNew is empty and hence there's not much point // requiring the user to inherit it! Would be best practice, but we already decided at several places // to only do special alignment if vectorization is enabled. ei_assert((reinterpret_cast(array) & 0xf) == 0 && "this assertion is explained here: http://eigen.tuxfamily.org/api/UnalignedArrayAssert.html **** READ THIS WEB PAGE !!! ****"); #endif } }; template struct ei_aligned_array { T array[Size]; }; struct ei_byte_forcing_aligned_malloc { unsigned char c; // sizeof must be 1. }; template struct ei_force_aligned_malloc { enum { ret = 0 }; }; template<> struct ei_force_aligned_malloc { enum { ret = 1 }; }; /** \internal allocates \a size * sizeof(\a T) bytes. If vectorization is enabled and T is such that a packet * containts more than one T, then the returned pointer is guaranteed to have 16 bytes alignment. * On allocation error, the returned pointer is undefined, but if exceptions are enabled then a std::bad_alloc is thrown. */ template inline T* ei_aligned_malloc(size_t size) { T* result; #ifdef EIGEN_VECTORIZE if(ei_packet_traits::size>1 || ei_force_aligned_malloc::ret) { #ifdef _MSC_VER result = static_cast(_aligned_malloc(size*sizeof(T), 16)); #ifdef EIGEN_EXCEPTIONS const int failed = (result == 0); #endif #else // not MSVC #ifdef EIGEN_EXCEPTIONS const int failed = #endif posix_memalign(reinterpret_cast(&result), 16, size*sizeof(T)); #endif #ifdef EIGEN_EXCEPTIONS if(failed) throw std::bad_alloc(); #endif } else #endif result = new T[size]; // here we really want a new, not a malloc. Justification: if the user uses Eigen on // some fancy scalar type such as multiple-precision numbers, and this type has a custom operator new, // then we want to honor this operator new! Anyway this type won't have vectorization so the vectorizing path // is irrelevant here. Yes, we should say somewhere in the docs that if the user uses a custom scalar type then // he can't have both vectorization and a custom operator new on his scalar type. return result; } /** \internal free memory allocated with ei_aligned_malloc */ template inline void ei_aligned_free(T* ptr) { #ifdef EIGEN_VECTORIZE if (ei_packet_traits::size>1 || ei_force_aligned_malloc::ret) #ifdef _MSC_VER _aligned_free(ptr); #else free(ptr); #endif else #endif delete[] ptr; } /** \internal \returns the number of elements which have to be skipped such that data are 16 bytes aligned */ template inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset) { typedef typename ei_packet_traits::type Packet; const int PacketSize = ei_packet_traits::size; const int PacketAlignedMask = PacketSize-1; const bool Vectorized = PacketSize>1; return Vectorized ? std::min( (PacketSize - (int((size_t(ptr)/sizeof(Scalar))) & PacketAlignedMask)) & PacketAlignedMask, maxOffset) : 0; } /** \internal * ei_alloc_stack(TYPE,SIZE) allocates sizeof(TYPE)*SIZE bytes on the stack if sizeof(TYPE)*SIZE is * smaller than EIGEN_STACK_ALLOCATION_LIMIT. Otherwise the memory is allocated using the operator new. * Data allocated with ei_alloc_stack \b must be freed by calling ei_free_stack(PTR,TYPE,SIZE). * \code * float * data = ei_alloc_stack(float,array.size()); * // ... * ei_free_stack(data,float,array.size()); * \endcode */ #ifdef __linux__ # define ei_alloc_stack(TYPE,SIZE) ((sizeof(TYPE)*(SIZE)>16000000) ? new TYPE[SIZE] : (TYPE*)alloca(sizeof(TYPE)*(SIZE))) # define ei_free_stack(PTR,TYPE,SIZE) if (sizeof(TYPE)*SIZE>16000000) delete[] PTR #else # define ei_alloc_stack(TYPE,SIZE) new TYPE[SIZE] # define ei_free_stack(PTR,TYPE,SIZE) delete[] PTR #endif /** \class WithAlignedOperatorNew * * \brief Enforces instances of inherited classes to be 16 bytes aligned when allocated with operator new * * When Eigen's explicit vectorization is enabled, Eigen assumes that some fixed sizes types are aligned * on a 16 bytes boundary. Those include all Matrix types having a sizeof multiple of 16 bytes, e.g.: * - Vector2d, Vector4f, Vector4i, Vector4d, * - Matrix2d, Matrix4f, Matrix4i, Matrix4d, * - etc. * When an object is statically allocated, the compiler will automatically and always enforces 16 bytes * alignment of the data when needed. However some troubles might appear when data are dynamically allocated. * Let's pick an example: * \code * struct Foo { * char dummy; * Vector4f some_vector; * }; * Foo obj1; // static allocation * obj1.some_vector = Vector4f(..); // => OK * * Foo *pObj2 = new Foo; // dynamic allocation * pObj2->some_vector = Vector4f(..); // => !! might segfault !! * \endcode * Here, the problem is that operator new is not aware of the compile time alignment requirement of the * type Vector4f (and hence of the type Foo). Therefore "new Foo" does not necessarily returns a 16 bytes * aligned pointer. The purpose of the class WithAlignedOperatorNew is exactly to overcome this issue by * overloading the operator new to return aligned data when the vectorization is enabled. * Here is a similar safe example: * \code * struct Foo : WithAlignedOperatorNew { * char dummy; * Vector4f some_vector; * }; * Foo *pObj2 = new Foo; // dynamic allocation * pObj2->some_vector = Vector4f(..); // => SAFE ! * \endcode * * \sa class ei_new_allocator */ struct WithAlignedOperatorNew { #ifdef EIGEN_VECTORIZE void *operator new(size_t size) throw() { return ei_aligned_malloc(size); } void *operator new[](size_t size) throw() { return ei_aligned_malloc(size); } void operator delete(void * ptr) { ei_aligned_free(static_cast(ptr)); } void operator delete[](void * ptr) { ei_aligned_free(static_cast(ptr)); } #endif }; template struct ei_with_aligned_operator_new : WithAlignedOperatorNew {}; template struct ei_with_aligned_operator_new {}; /** \class ei_new_allocator * * \brief stl compatible allocator to use with with fixed-size vector and matrix types * * STL allocator simply wrapping operators new[] and delete[]. Unlike GCC's default new_allocator, * ei_new_allocator call operator new on the type \a T and not the general new operator ignoring * overloaded version of operator new. * * Example: * \code * // Vector4f requires 16 bytes alignment: * std::vector > dataVec4; * // Vector3f does not require 16 bytes alignment, no need to use Eigen's allocator: * std::vector dataVec3; * * struct Foo : WithAlignedOperatorNew { * char dummy; * Vector4f some_vector; * }; * std::vector > dataFoo; * \endcode * * \sa class WithAlignedOperatorNew */ template class ei_new_allocator { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; template struct rebind { typedef ei_new_allocator other; }; T* address(T& ref) const { return &ref; } const T* address(const T& ref) const { return &ref; } T* allocate(size_t size, const void* = 0) { return new T[size]; } void deallocate(T* ptr, size_t) { delete[] ptr; } size_t max_size() const { return size_t(-1) / sizeof(T); } // FIXME I'm note sure about this construction... void construct(T* ptr, const T& refObj) { ::new(ptr) T(refObj); } void destroy(T* ptr) { ptr->~T(); } }; #endif // EIGEN_MEMORY_H