00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef MTL_CONTIGUOUS_MEMORY_BLOCK_INCLUDE
00013 #define MTL_CONTIGUOUS_MEMORY_BLOCK_INCLUDE
00014
00015 #include <cassert>
00016 #include <algorithm>
00017 #include <boost/static_assert.hpp>
00018 #include <boost/numeric/mtl/mtl_fwd.hpp>
00019 #include <boost/numeric/mtl/utility/tag.hpp>
00020 #include <boost/numeric/mtl/matrix/dimension.hpp>
00021 #include <boost/numeric/mtl/detail/index.hpp>
00022 #include <boost/numeric/mtl/operation/clone.hpp>
00023
00024
00025
00026 namespace mtl { namespace detail {
00027 using std::size_t;
00028
00029
00030
00031
00032 #ifndef MTL_ALIGNMENT_LIMIT
00033 # define MTL_ALIGNMENT_LIMIT 1024
00034 #endif
00035
00036
00037 #ifndef MTL_ALIGNMENT
00038 # define MTL_ALIGNMENT 128
00039 #endif
00040
00041
00042
00043 template <unsigned Size>
00044 struct size_helper
00045 {
00046 typedef size_helper self;
00047
00048 size_helper() {}
00049 explicit size_helper(std::size_t size)
00050 {
00051 set_size(size);
00052 }
00053
00054 void set_size(std::size_t size)
00055 {
00056 # ifndef MTL_IGNORE_STATIC_SIZE_VIOLATION
00057 MTL_THROW_IF(Size != size, change_static_size());
00058 # endif
00059 }
00060
00061 std::size_t used_memory() const
00062 {
00063 return Size;
00064 }
00065
00066 friend void swap(self& x, self& y) {}
00067 };
00068
00069 template <>
00070 struct size_helper<0>
00071 {
00072 typedef size_helper self;
00073
00074 size_helper(std::size_t size= 0) : my_used_memory(size) {}
00075
00076 void set_size(std::size_t size)
00077 {
00078 my_used_memory= size;
00079 }
00080
00081 std::size_t used_memory() const
00082 {
00083 return my_used_memory;
00084 }
00085
00086 friend void swap(self& x, self& y)
00087 {
00088 std::swap(x.my_used_memory, y.my_used_memory);
00089 }
00090
00091 protected:
00092 std::size_t my_used_memory;
00093 };
00094
00095
00096
00097
00098 # ifdef MTL_ENABLE_ALIGNMENT
00099
00100 template <typename Value>
00101 struct alignment_helper
00102 {
00103 typedef alignment_helper self;
00104
00105 alignment_helper() : malloc_address(0) {}
00106
00107 Value* alligned_alloc(std::size_t size)
00108 {
00109 bool align= size * sizeof(value_type) >= MTL_ALIGNMENT_LIMIT;
00110 std::size_t bytes= size * sizeof(value_type);
00111
00112 if (align)
00113 bytes+= MTL_ALIGNMENT - 1;
00114
00115 char* p= malloc_address= new char[bytes];
00116 if (align)
00117 while ((long int)(p) % MTL_ALIGNMENT) p++;
00118
00119
00120 return reinterpret_cast<value_type*>(p);
00121 }
00122
00123 void aligned_delete(bool is_own, Value*& data)
00124 {
00125 if (is_own && malloc_address) delete[] malloc_address;
00126 data= 0;
00127 }
00128
00129 friend void swap(self& x, self& y)
00130 {
00131 using std::swap
00132 swap(x.malloc_address, y.malloc_address);
00133 }
00134
00135 private:
00136 char* malloc_address;
00137 };
00138
00139 # else
00140
00141 template <typename Value>
00142 struct alignment_helper
00143 {
00144 typedef alignment_helper self;
00145
00146 Value* alligned_alloc(std::size_t size)
00147 {
00148 Value* tmp= new Value[size];
00149
00150 return tmp;
00151
00152 }
00153
00154 void aligned_delete(bool is_own, Value*& data)
00155 {
00156 if (is_own && data)
00157 delete[] data;
00158 }
00159
00160 friend void swap(self& x, self& y) {}
00161 };
00162
00163 # endif
00164
00165
00166 template <typename Value, bool OnStack, unsigned Size>
00167 struct memory_crtp
00168
00169 {
00170 typedef contiguous_memory_block<Value, OnStack, Size> base;
00171
00172 static bool const on_stack= OnStack;
00173
00174 typedef Value value_type;
00175 typedef value_type* pointer_type;
00176 typedef const value_type* const_pointer_type;
00177
00178
00179
00180 size_t offset(const Value* p) const
00181 {
00182 return p - static_cast<const base&>(*this).data;
00183 }
00184
00185
00186 pointer_type elements()
00187 {
00188 return static_cast<base&>(*this).data;
00189 }
00190
00191
00192 const_pointer_type elements() const
00193 {
00194 return static_cast<const base&>(*this).data;
00195 }
00196
00197
00198
00199 value_type& value_n(size_t offset)
00200 {
00201 return static_cast<base&>(*this).data[offset];
00202 }
00203
00204
00205
00206 const value_type& value_n(size_t offset) const
00207 {
00208 return static_cast<const base&>(*this).data[offset];
00209 }
00210
00211 };
00212
00213
00214 template <typename Value, bool OnStack, unsigned Size>
00215 struct contiguous_memory_block
00216 : public size_helper<Size>,
00217 public alignment_helper<Value>,
00218 public memory_crtp<Value, OnStack, Size>
00219 {
00220 typedef Value value_type;
00221 typedef contiguous_memory_block self;
00222 typedef size_helper<Size> size_base;
00223 typedef alignment_helper<Value> alignment_base;
00224
00226 enum c_t {own,
00227 external,
00228 view
00229 };
00230
00231 private:
00232
00233 void alloc(std::size_t size)
00234 {
00235 category= own;
00236 this->set_size(size);
00237 data= this->alligned_alloc(this->used_memory());
00238 }
00239
00240 void delete_it()
00241 {
00242 this->aligned_delete(category == own, data);
00243 }
00244
00245 template <typename Other>
00246 void copy_construction(const Other& other)
00247 {
00248 using std::copy;
00249
00250 alloc(other.used_memory());
00251
00252 copy(other.data, other.data + other.used_memory(), data);
00253 }
00254
00255 void move_construction(self& other)
00256 {
00257
00258 category= own; data= 0;
00259 swap(*this, other);
00260 }
00261
00262
00263 void copy_view(const self& other)
00264 {
00265
00266 assert(other.category == view);
00267 category= view;
00268 this->set_size(other.used_memory());
00269 data= other.data;
00270 }
00271
00272 template <typename Other>
00273 void copy_assignment(const Other& other)
00274 {
00275
00276 MTL_DEBUG_THROW_IF(this->used_memory() != other.used_memory(), incompatible_size());
00277 std::copy(other.data, other.data + other.used_memory(), data);
00278 }
00279
00280 public:
00281 contiguous_memory_block() : category(own), data(0) {}
00282
00283 explicit contiguous_memory_block(Value *data, std::size_t size, bool is_view= false)
00284 : size_base(size), category(is_view ? view : external), data(data)
00285 {}
00286
00287 explicit contiguous_memory_block(std::size_t size) : category(own)
00288 {
00289
00290 alloc(size);
00291
00292 }
00293
00294
00295 contiguous_memory_block(const self& other)
00296 {
00297
00298 if (other.category == view)
00299 copy_view(other);
00300 else
00301 copy_construction(other);
00302 }
00303
00304
00305 contiguous_memory_block(const self& other, clone_ctor)
00306 {
00307
00308 copy_construction(other);
00309 }
00310
00311
00312 template<typename Value2, bool OnStack2, unsigned Size2>
00313 explicit contiguous_memory_block(const contiguous_memory_block<Value2, OnStack2, Size2>& other)
00314 {
00315 std::cout << "Copy constructor (different type).\n";
00316 copy_construction(other);
00317 }
00318
00319
00320
00321 self& operator=(self other)
00322 {
00323 move_assignment(other);
00324 return *this;
00325 }
00326
00327
00328 protected:
00329 void move_assignment(self& other)
00330 {
00331
00332 if (category == own && other.category == own)
00333 swap(*this, other);
00334 else
00335 copy_assignment(other);
00336 }
00337
00338 public:
00339 template<typename Value2, bool OnStack2, unsigned Size2>
00340 self& operator=(const contiguous_memory_block<Value2, OnStack2, Size2>& other)
00341 {
00342
00343 copy_assignment(other);
00344 return *this;
00345 }
00346
00347
00348 void set_view() { category= view; }
00349
00350 void realloc(std::size_t size)
00351 {
00352
00353 if (size == this->used_memory())
00354 return;
00355 MTL_THROW_IF(category != own,
00356 logic_error("Can't change the size of collections with external memory"));
00357 delete_it();
00358 alloc(size);
00359 }
00360
00361 ~contiguous_memory_block()
00362 {
00363
00364 delete_it();
00365 }
00366
00367 friend void swap(self& x, self& y)
00368 {
00369 using std::swap;
00370 swap(x.category, y.category);
00371 swap(x.data, y.data);
00372 swap(static_cast<size_base&>(x), static_cast<size_base&>(y));
00373 swap(static_cast<alignment_base&>(x), static_cast<alignment_base&>(y));
00374 }
00375
00376 protected:
00377 enum c_t category;
00378 public:
00379 Value *data;
00380 };
00381
00382 template <typename Value, unsigned Size>
00383 struct contiguous_memory_block<Value, true, Size>
00384 : public alignment_helper<Value>,
00385 public memory_crtp<Value, true, Size>
00386 {
00387 typedef Value value_type;
00388 typedef contiguous_memory_block self;
00389
00390
00391 Value data[Size];
00392 explicit contiguous_memory_block(std::size_t size= Size)
00393 {
00394 MTL_DEBUG_THROW_IF(Size != size, incompatible_size());
00395 }
00396
00397
00398 contiguous_memory_block(const self& other)
00399 {
00400
00401 std::copy(other.data, other.data+Size, data);
00402 }
00403
00404
00405 template<typename Value2, bool OnStack2, unsigned Size2>
00406 explicit contiguous_memory_block(const contiguous_memory_block<Value2, OnStack2, Size2>& other)
00407 {
00408
00409 MTL_DEBUG_THROW_IF(Size != other.used_memory(), incompatible_size());
00410 std::copy(other.data, other.data + other.used_memory(), data);
00411 }
00412
00413 self& operator=(const self& other)
00414 {
00415
00416 std::copy(other.data, other.data+Size, data);
00417 return *this;
00418 }
00419
00420
00421 protected:
00422 void move_assignment(self& other)
00423 {
00424 std::copy(other.data, other.data+Size, data);
00425 }
00426
00427 public:
00428 template<typename Value2, bool OnStack2, unsigned Size2>
00429 self& operator=(const contiguous_memory_block<Value2, OnStack2, Size2>& other)
00430 {
00431
00432 MTL_DEBUG_THROW_IF(Size != other.used_memory(), incompatible_size());
00433 std::copy(other.data, other.data + other.used_memory(), data);
00434 return *this;
00435 }
00436
00437
00438 void realloc(std::size_t s)
00439 {
00440
00441 assert(s == Size);
00442 }
00443
00444 std::size_t used_memory() const
00445 {
00446 return Size;
00447 }
00448 };
00449
00450
00451 }}
00452
00453 namespace mtl {
00454 template <typename Value, bool OnStack, unsigned Size>
00455 struct is_clonable< detail::contiguous_memory_block<Value, OnStack, Size> > : boost::mpl::bool_<!OnStack> {};
00456 }
00457
00458 #endif // MTL_CONTIGUOUS_MEMORY_BLOCK_INCLUDE