00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef LUX_MEMORY_H
00024 #define LUX_MEMORY_H
00025
00026
00027
00028 #include <boost/serialization/split_member.hpp>
00029 #include <boost/cstdint.hpp>
00030 using boost::int8_t;
00031
00032 namespace lux
00033 {
00034
00035 #if !defined(LUX_ALIGNMENT)
00036 #ifdef LUX_USE_SSE
00037 #define LUX_ALIGNMENT 16
00038 #endif
00039 #endif
00040
00041 #ifndef L1_CACHE_LINE_SIZE
00042 #define L1_CACHE_LINE_SIZE 64
00043 #endif
00044
00045 template<class T> inline T *AllocAligned(size_t size, std::size_t N = L1_CACHE_LINE_SIZE)
00046 {
00047 return static_cast<T *>(memalign(N, size * sizeof(T)));
00048 }
00049 template<class T> inline void FreeAligned(T *ptr)
00050 {
00051 #if defined(WIN32) && !defined(__CYGWIN__) // NOBOOK
00052 _aligned_free(ptr);
00053 #else // NOBOOK
00054 free(ptr);
00055 #endif // NOBOOK
00056 }
00057
00058 template <typename T, std::size_t N = 16> class AlignedAllocator
00059 {
00060 public:
00061 typedef T value_type;
00062 typedef std::size_t size_type;
00063 typedef std::ptrdiff_t difference_type;
00064
00065 typedef T *pointer;
00066 typedef const T *const_pointer;
00067
00068 typedef T &reference;
00069 typedef const T &const_reference;
00070
00071 public:
00072 inline AlignedAllocator() throw() { }
00073
00074 template <typename T2> inline AlignedAllocator(const AlignedAllocator<T2, N> &) throw () { }
00075
00076 inline ~AlignedAllocator() throw() { }
00077
00078 inline pointer adress(reference r) { return &r; }
00079
00080 inline const_pointer adress(const_reference r) const { return &r; }
00081
00082 inline pointer allocate(size_type n)
00083 {
00084 return AllocAligned<value_type>(n, N);
00085 }
00086
00087 inline void deallocate(pointer p, size_type)
00088 {
00089 FreeAligned(p);
00090 }
00091
00092 inline void construct(pointer p, const value_type &wert)
00093 {
00094 new (p) value_type(wert);
00095 }
00096
00097 inline void destroy(pointer p)
00098 {
00099 p->~value_type();
00100 }
00101
00102 inline size_type max_size() const throw()
00103 {
00104 return size_type(-1) / sizeof(value_type);
00105 }
00106
00107 template <typename T2> struct rebind
00108 {
00109 typedef AlignedAllocator<T2, N> other;
00110 };
00111 };
00112
00113 #define P_CLASS_ATTR __attribute__
00114 #define P_CLASS_ATTR __attribute__
00115
00116 #if defined(WIN32) && !defined(__CYGWIN__) // NOBOOK
00117 class __declspec(align(16)) Aligned16 {
00118 #else // NOBOOK
00119 class Aligned16 {
00120 #endif // NOBOOK
00121 public:
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 void *operator new(size_t s) { return AllocAligned<char>(s, 16); }
00133
00134 void *operator new (size_t s, void *q) { return q; }
00135
00136 void operator delete(void *p) { FreeAligned(p); }
00137 #if defined(WIN32) && !defined(__CYGWIN__) // NOBOOK
00138 } ;
00139 #else // NOBOOK
00140 } __attribute__ ((aligned(16)));
00141 #endif // NOBOOK
00142
00143
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 class MemoryArena {
00184 public:
00185
00186 MemoryArena(size_t bs = 32768) {
00187 blockSize = bs;
00188 curBlockPos = 0;
00189 currentBlock = lux::AllocAligned<int8_t>(blockSize);
00190 }
00191 ~MemoryArena() {
00192 lux::FreeAligned(currentBlock);
00193 for (size_t i = 0; i < usedBlocks.size(); ++i)
00194 lux::FreeAligned(usedBlocks[i]);
00195 for (size_t i = 0; i < availableBlocks.size(); ++i)
00196 lux::FreeAligned(availableBlocks[i]);
00197 }
00198 void *Alloc(size_t sz) {
00199
00200 #if defined(LUX_ALIGNMENT)
00201 sz = ((sz + (LUX_ALIGNMENT-1)) & (~(LUX_ALIGNMENT-1)));
00202 #else
00203 sz = ((sz + 7) & (~7));
00204 #endif
00205 if (curBlockPos + sz > blockSize) {
00206
00207 usedBlocks.push_back(currentBlock);
00208 if (availableBlocks.size() > 0 && sz <= blockSize) {
00209 currentBlock = availableBlocks.back();
00210 availableBlocks.pop_back();
00211 } else {
00212 currentBlock = lux::AllocAligned<int8_t>(max(sz, blockSize));
00213 }
00214 curBlockPos = 0;
00215 }
00216 void *ret = currentBlock + curBlockPos;
00217 curBlockPos += sz;
00218 return ret;
00219 }
00220 void FreeAll() {
00221 curBlockPos = 0;
00222 while (usedBlocks.size() > 0) {
00223 availableBlocks.push_back(usedBlocks.back());
00224 usedBlocks.pop_back();
00225 }
00226 }
00227 private:
00228
00229 size_t curBlockPos, blockSize;
00230 int8_t *currentBlock;
00231 vector<int8_t *> usedBlocks, availableBlocks;
00232 };
00233
00234 template<class T, int logBlockSize> class BlockedArray {
00235 public:
00236 friend class boost::serialization::access;
00237
00238 BlockedArray () {}
00239 BlockedArray(const BlockedArray &b, const T *d = NULL)
00240 {
00241 uRes = b.uRes;
00242 vRes = b.vRes;
00243 uBlocks = RoundUp(uRes) >> logBlockSize;
00244 int nAlloc = RoundUp(uRes) * RoundUp(vRes);
00245 data = lux::AllocAligned<T>(nAlloc);
00246 for (int i = 0; i < nAlloc; ++i)
00247 new (&data[i]) T(b.data[i]);
00248 if (d) {
00249 for (int v = 0; v < b.vRes; ++v) {
00250 for (int u = 0; u < b.uRes; ++u)
00251 (*this)(u, v) = d[v * uRes + u];
00252 }
00253 }
00254 }
00255 BlockedArray(int nu, int nv, const T *d = NULL) {
00256 uRes = nu;
00257 vRes = nv;
00258 uBlocks = RoundUp(uRes) >> logBlockSize;
00259 int nAlloc = RoundUp(uRes) * RoundUp(vRes);
00260 data = lux::AllocAligned<T>(nAlloc);
00261 for (int i = 0; i < nAlloc; ++i)
00262 new (&data[i]) T();
00263 if (d) {
00264 for (int v = 0; v < nv; ++v) {
00265 for (int u = 0; u < nu; ++u)
00266 (*this)(u, v) = d[v * uRes + u];
00267 }
00268 }
00269 }
00270 int BlockSize() const { return 1 << logBlockSize; }
00271 int RoundUp(int x) const {
00272 return (x + BlockSize() - 1) & ~(BlockSize() - 1);
00273 }
00274 int uSize() const { return uRes; }
00275 int vSize() const { return vRes; }
00276 ~BlockedArray() {
00277 for (int i = 0; i < uRes * vRes; ++i)
00278 data[i].~T();
00279 lux::FreeAligned(data);
00280 }
00281 int Block(int a) const { return a >> logBlockSize; }
00282 int Offset(int a) const { return (a & (BlockSize() - 1)); }
00283 T &operator()(int u, int v) {
00284 int bu = Block(u), bv = Block(v);
00285 int ou = Offset(u), ov = Offset(v);
00286 int offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
00287 offset += BlockSize() * ov + ou;
00288 return data[offset];
00289 }
00290 const T &operator()(int u, int v) const {
00291 int bu = Block(u), bv = Block(v);
00292 int ou = Offset(u), ov = Offset(v);
00293 int offset = BlockSize() * BlockSize() * (uBlocks * bv + bu);
00294 offset += BlockSize() * ov + ou;
00295 return data[offset];
00296 }
00297 void GetLinearArray(T *a) const {
00298 for (int v = 0; v < vRes; ++v) {
00299 for (int u = 0; u < uRes; ++u)
00300 *a++ = (*this)(u, v);
00301 }
00302 }
00303
00304 private:
00305
00306 T *data;
00307 int uRes, vRes, uBlocks;
00308
00309 template<class Archive> void save(Archive & ar, const unsigned int version) const
00310 {
00311 ar & uRes;
00312 ar & vRes;
00313 ar & uBlocks;
00314
00315 int nAlloc = RoundUp(uRes) * RoundUp(vRes);
00316 for (int i = 0; i < nAlloc; ++i)
00317 ar & data[i];
00318 }
00319
00320 template<class Archive> void load(Archive & ar, const unsigned int version)
00321 {
00322 ar & uRes;
00323 ar & vRes;
00324 ar & uBlocks;
00325
00326 int nAlloc = RoundUp(uRes) * RoundUp(vRes);
00327 data = lux::AllocAligned<T>(nAlloc);
00328 for (int i = 0; i < nAlloc; ++i)
00329 ar & data[i];
00330 }
00331 BOOST_SERIALIZATION_SPLIT_MEMBER()
00332 };
00333
00334 #endif // LUX_MEMORY_H
00335