Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2014
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.07 KB | None | 0 0
  1. #ifndef __ND_ARRAY__
  2. #define __ND_ARRAY__
  3.  
  4. //================================================
  5. // @file ndArray.h
  6. // @author Jonathan Hadida
  7. // @contact cf https://github.com/Sheljohn/MexArray
  8. //================================================
  9.  
  10. #include <iostream>
  11. #include <cstdlib>
  12. #include <cstdarg>
  13. #include <cstdio>
  14.  
  15. #include <exception>
  16. #include <stdexcept>
  17.  
  18. #include <memory>
  19. #include <algorithm>
  20. #include <type_traits>
  21. #include <initializer_list>
  22.  
  23. // Protect 1D access (comment for faster access)
  24. #define ND_ARRAY_SAFE_ACCESS
  25. #ifdef ND_ARRAY_SAFE_ACCESS
  26. #define ND_ARRAY_PROTECT(k,n) (k % n)
  27. #else
  28. #define ND_ARRAY_PROTECT(k,n) k
  29. #endif
  30.  
  31.  
  32.  
  33. /******************** ********** ********************/
  34. /******************** ********** ********************/
  35.  
  36.  
  37.  
  38. /**
  39. * Convert nd coordinates to 1d index.
  40. * Two main variants are provided:
  41. * - Taking an ARRAY as coordinates (size input by template)
  42. * - Taking a VA_LIST as a list of coordinate inputs (cf operator() below).
  43. */
  44. template <unsigned N>
  45. unsigned sub2ind( const unsigned *subs, const unsigned *size, const unsigned *strides )
  46. {
  47. register unsigned ind = 0;
  48.  
  49. for (unsigned i = 0; i < N; ++i)
  50. ind += ND_ARRAY_PROTECT(subs[i],size[i]) * strides[i];
  51.  
  52. return ind;
  53. }
  54.  
  55. template <unsigned N>
  56. unsigned sub2ind( va_list& vl, const unsigned *size, const unsigned *strides )
  57. {
  58. register unsigned ind = 0;
  59.  
  60. for (unsigned i = 1; i < N; ++i)
  61. ind += ND_ARRAY_PROTECT(va_arg(vl,unsigned),size[i]) * strides[i];
  62.  
  63. va_end(vl); return ind;
  64. }
  65.  
  66. template <> inline unsigned
  67. sub2ind<0>( const unsigned*, const unsigned*, const unsigned* )
  68. { return 0; }
  69. template <> inline unsigned
  70. sub2ind<1>( const unsigned *subs, const unsigned*, const unsigned* )
  71. { return *subs; }
  72. template <> inline unsigned
  73. sub2ind<2>( const unsigned *subs, const unsigned *size, const unsigned* )
  74. { return (subs[0] + subs[1]*size[0]); }
  75.  
  76. // ------------------------------------------------------------------------
  77.  
  78. /**
  79. * Simple singleton.
  80. */
  81. template <typename T> struct singleton { static T instance; };
  82. template <typename T> T singleton<T>::instance = T();
  83.  
  84. // ------------------------------------------------------------------------
  85.  
  86. /**
  87. * Dummy deleter functor.
  88. * This litterally does nothing to the input pointer; it can be used
  89. * safely with shared pointers for either statically allocated memory
  90. * (eg fixed-size arrays) or externally managed memory (eg Matlab in/out).
  91. */
  92. template <typename T>
  93. struct no_delete
  94. { inline void operator() ( T* ptr ) const {} };
  95.  
  96.  
  97.  
  98. /******************** ********** ********************/
  99. /******************** ********** ********************/
  100.  
  101.  
  102.  
  103. /**
  104. * n-dimensional array.
  105. * NOTE: T can be CONST (underlying elements non-assignable),
  106. * or NON-CONST (underlying elements assignable, suitable for
  107. * owned memory allocation for instance).
  108. */
  109. template <typename T, unsigned N>
  110. class ndArray
  111. {
  112. public:
  113.  
  114. typedef T value_type;
  115. typedef T* pointer;
  116. typedef T& reference;
  117.  
  118. typedef typename std::add_const<T>::type const_value;
  119. typedef const_value* const_pointer;
  120. typedef const_value& const_reference;
  121.  
  122. typedef std::shared_ptr<value_type> shared;
  123. typedef ndArray<T,N> self;
  124.  
  125.  
  126.  
  127. // Constructors
  128. ndArray() { reset(); }
  129. ndArray( pointer ptr, const unsigned *size, bool manage ) { assign(ptr,size,manage); }
  130.  
  131.  
  132. // Copy constructor
  133. ndArray( const self& other ) { operator=(other); }
  134. self& operator= ( const self& other );
  135.  
  136. // Check pointer validity
  137. inline bool empty() const { return !((bool) m_data); }
  138. inline operator bool() const { return m_data; }
  139.  
  140. // Print array dimensions
  141. void info() const;
  142.  
  143.  
  144.  
  145. // ------------------------------------------------------------------------
  146.  
  147.  
  148.  
  149. // Clear contents
  150. void clear();
  151. void reset();
  152.  
  153.  
  154. // Assign a pointer or another instance
  155. void assign( pointer ptr, const unsigned *size, bool manage );
  156. void assign( const self& other ) { operator=(other); }
  157.  
  158.  
  159. // Swap contents with another array
  160. void swap( self& other );
  161.  
  162.  
  163. // Copy from another array
  164. template <typename U>
  165. void copy( const ndArray<U,N>& other );
  166.  
  167.  
  168.  
  169. // ------------------------------------------------------------------------
  170.  
  171.  
  172.  
  173. // 1D access
  174. inline reference operator[] ( unsigned n ) const
  175. { return data()[ ND_ARRAY_PROTECT(n,m_numel) ]; }
  176.  
  177. // ND access
  178. reference operator() ( const unsigned *subs ) const
  179. { return data()[ sub2ind<N>(subs, m_size, m_strides) ]; }
  180.  
  181. reference operator() ( std::initializer_list<unsigned> subs ) const
  182. {
  183. #ifdef ND_ARRAY_SAFE_ACCESS
  184. if ( subs.size() != N )
  185. throw std::length_error("Invalid coordinates length.");
  186. #endif
  187. return data()[ sub2ind<N>(subs.begin(), m_size, m_strides) ];
  188. }
  189.  
  190. // Coordinates access
  191. reference operator() ( unsigned i, ... ) const
  192. {
  193. va_list vl; va_start(vl,i);
  194. return data()[ i+sub2ind<N>(vl, m_size, m_strides) ];
  195. }
  196.  
  197.  
  198. // Access data directly
  199. inline const_pointer cdata() const { return m_data.get(); }
  200. inline pointer data() const { return m_data.get(); }
  201.  
  202. // Iterators
  203. inline const_pointer cbegin() const { return data(); }
  204. inline const_pointer cend() const { return data() + m_numel; }
  205.  
  206. inline pointer begin() const { return data(); }
  207. inline pointer end() const { return data() + m_numel; }
  208.  
  209.  
  210.  
  211. // ------------------------------------------------------------------------
  212.  
  213.  
  214.  
  215. // Dimensions
  216. inline const unsigned* size() const { return m_size; }
  217. inline unsigned size( unsigned n ) const { return m_size[ n % N ]; }
  218. inline const unsigned* strides() const { return m_strides; }
  219. inline unsigned stride( unsigned n ) const { return m_strides[ n % N ]; }
  220. inline unsigned numel() const { return m_numel; }
  221. inline unsigned ndims() const { return N; }
  222.  
  223.  
  224.  
  225. protected:
  226.  
  227. void assign_shared( pointer ptr, bool manage );
  228.  
  229. unsigned m_numel;
  230. unsigned m_size[N];
  231. unsigned m_strides[N];
  232.  
  233. shared m_data;
  234. };
  235.  
  236.  
  237.  
  238. /******************** ********** ********************/
  239. /******************** ********** ********************/
  240.  
  241.  
  242.  
  243. // Include implementation
  244. #include "ndArray.hpp"
  245.  
  246. #endif
  247.  
  248. /**
  249. * Assignment operator.
  250. * Performs a shallow copy of the other instance.
  251. * For deep-copies, see copy() below.
  252. */
  253. template <typename T, unsigned N>
  254. ndArray<T,N>& ndArray<T,N>::operator=( const self& other )
  255. {
  256. if ( other.m_data != m_data )
  257. {
  258. // Clear current instance first
  259. clear();
  260.  
  261. // Copy data from other
  262. m_data = other.m_data;
  263. m_numel = other.m_numel;
  264. std::copy_n( other.m_size, N, m_size );
  265. std::copy_n( other.m_strides, N, m_strides );
  266. }
  267.  
  268. return *this;
  269. }
  270.  
  271. // ------------------------------------------------------------------------
  272.  
  273. /**
  274. * Performs a deep-copy of another instance with possibly
  275. * different value-type. Deep copies are allowed only if
  276. * the pointer type is non-const (otherwise no assignment
  277. * is possible).
  278. *
  279. * To perform the copy, a new memory allocation is requested
  280. * to store as many values as other.m_numel; the current
  281. * instance takes ownership of this new memory.
  282. *
  283. * Note that subsequent shallow copies (see assignment operator)
  284. * will simply share this ownership (reference counting).
  285. * Note also that this code might generate warnings because of
  286. * the value-cast performed on the values of other.
  287. */
  288. template <typename T, unsigned N>
  289. template <typename U>
  290. void ndArray<T,N>::copy( const ndArray<U,N>& other )
  291. {
  292. if ( !std::is_const<T>::value )
  293. {
  294. // Create new allocation only if necessary
  295. if ( other.numel() == m_numel )
  296. {
  297. // Otherwise simply copy dimensions
  298. std::copy_n( other.size(), N, m_size );
  299. std::copy_n( other.strides(), N, m_strides );
  300. }
  301. else
  302. assign( new T[ other.numel() ], other.size(), true );
  303.  
  304. // Copy data
  305. auto dst = begin(); auto src = other.cbegin();
  306. for ( ;src != other.cend(); ++src, ++dst ) *dst = (T) *src;
  307. }
  308. else
  309. throw std::logic_error("Const values cannot be assigned!");
  310. }
  311.  
  312. // ------------------------------------------------------------------------
  313.  
  314. /**
  315. * Reset shared pointer.
  316. * This will trigger the deletion of the underlying memory if
  317. * m_data is unique (m_data.use_count() == 1). Note that if the
  318. * data was assigned with 'manage' set to false (see below),
  319. * the deleter(no_delete functor) will NOT release the memory.
  320. */
  321. template <typename T, unsigned N>
  322. void ndArray<T,N>::clear()
  323. {
  324. m_data.reset();
  325. }
  326.  
  327. // ------------------------------------------------------------------------
  328.  
  329. /**
  330. * More thorough cleanup. Calls clear() (see above), and sets
  331. * all the rest to 0.
  332. */
  333. template <typename T, unsigned N>
  334. void ndArray<T,N>::reset()
  335. {
  336. clear();
  337. m_numel = 0;
  338. std::fill_n( m_size, N, 0 );
  339. std::fill_n( m_strides, N, 0 );
  340. }
  341.  
  342. // ------------------------------------------------------------------------
  343.  
  344. /**
  345. * Swap contents with another ndArray.
  346. */
  347. template <typename T, unsigned N>
  348. void ndArray<T,N>::swap( self& other )
  349. {
  350. std::swap( m_numel, other.m_numel );
  351. for ( unsigned i = 0; i < N; ++i )
  352. {
  353. std::swap( m_size[i], other.m_size[i] );
  354. std::swap( m_strides[i], other.m_strides[i] );
  355. }
  356. m_data.swap( other.m_data );
  357. }
  358.  
  359. // ------------------------------------------------------------------------
  360.  
  361. /**
  362. * Internal method (protected) to assign the shared pointer.
  363. * Dimensions are assumed to be taken care of by the public
  364. * assign variants (see below); only the pointer, it's length
  365. * and the flag 'manage' are required here.
  366. *
  367. * 'manage' allows to specify whether or not the shared pointer
  368. * should release the memory when the last refering instance is
  369. * destroyed.
  370. *
  371. * If true, the default deleter std::default_delete will be
  372. * assigned to the shared pointer. Note that this deleter releases
  373. * memory allocated USING NEW ONLY;
  374. * DO NOT use malloc/calloc or other C allocation variants.
  375. *
  376. * If false, the deleter no_delete is given instead; this will NOT
  377. * release the memory when the last refering instance is destroyed.
  378. * Use only with either externally managed (eg Matlab) or static
  379. * allocations.
  380. */
  381. template <typename T, unsigned N>
  382. void ndArray<T,N>::assign_shared( pointer ptr, bool manage )
  383. {
  384. if (manage)
  385. m_data.reset( ptr );
  386. else
  387. m_data.reset( ptr, no_delete<T>() );
  388. }
  389.  
  390. // ------------------------------------------------------------------------
  391.  
  392. /**
  393. * Assign from pointer and size.
  394. *
  395. * If manage == true, the internal shared pointer m_data
  396. * will assume ownership of the memory pointed by ptr, and
  397. * try to release it using delete[] when the last refering
  398. * instance gets destroyed.
  399. * If ptr is dynamically allocated, make sure that the
  400. * allocation is performed with NEW, and NOT C variants
  401. * like malloc/calloc/etc.
  402. *
  403. * If manage == false, a dummy deleter (no_delete functor) is
  404. * passed to the shared pointer; nothing happens to the memory
  405. * pointed by ptr when the last refering instance gets destroyed.
  406. */
  407. template <typename T, unsigned N>
  408. void ndArray<T,N>::assign( pointer ptr, const unsigned *size, bool manage )
  409. {
  410. if ( ptr != data() )
  411. {
  412. // Compute internal dimensions
  413. m_numel = 1;
  414. for ( unsigned i = 0; i < N; ++i )
  415. {
  416. m_size[i] = size[i];
  417. m_numel *= size[i];
  418. m_strides[ (i+1) % N ] = m_numel;
  419. } m_strides[0] = 1;
  420.  
  421. // Set data
  422. assign_shared( ptr, manage );
  423. }
  424. }
  425.  
  426. // ------------------------------------------------------------------------
  427.  
  428. /**
  429. * Simply prints information about the dimensions of the
  430. * n-dimensional array (size & number of elements).
  431. */
  432. template <typename T, unsigned N>
  433. void ndArray<T,N>::info() const
  434. {
  435. if ( m_data )
  436. {
  437. printf("%u-dimensional array of size (%u", N, m_size[0]);
  438. for ( unsigned d = 1; d < N; ++d )
  439. printf(", %u", m_size[d]);
  440. printf(") = %u elements.n", m_numel);
  441. }
  442. else
  443. printf("Empty %u-dimensional array.n", N);
  444. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement