buffer.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. // Copyright (c) 2006-2018 Maxim Khizhinsky
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef CDSLIB_OPT_BUFFER_H
  6. #define CDSLIB_OPT_BUFFER_H
  7. #include <memory.h>
  8. #include <cds/details/defs.h>
  9. #include <cds/user_setup/allocator.h>
  10. #include <cds/details/allocator.h>
  11. #include <cds/algo/int_algo.h>
  12. #include <memory>
  13. namespace cds { namespace opt {
  14. /// [type-option] Option setter for user-provided plain buffer
  15. /**
  16. This option is used by some container as a random access array for storing
  17. container's item; for example, a bounded queue may use
  18. this option to define underlying buffer implementation.
  19. The template parameter \p Type should be rebindable.
  20. Implementations:
  21. - \p opt::v::initialized_static_buffer
  22. - \p opt::v::uninitialized_static_buffer
  23. - \p opt::v::initialized_dynamic_buffer
  24. - \p opt::v::uninitialized_dynamic_buffer
  25. Uninitialized buffer is just an array of uninitialized elements.
  26. Each element should be manually constructed, for example with a placement new operator.
  27. When the uninitialized buffer is destroyed the destructor of its element is not called.
  28. Initialized buffer contains default-constructed elements. Element destructor is called automatically
  29. when the buffer is destroyed.
  30. @note Usually, initialized and uninitialized buffers are not interchangeable.
  31. */
  32. template <typename Type>
  33. struct buffer {
  34. //@cond
  35. template <typename Base> struct pack: public Base
  36. {
  37. typedef Type buffer;
  38. };
  39. //@endcond
  40. };
  41. namespace v {
  42. /// Static uninitialized buffer
  43. /**
  44. One of available type for \p opt::buffer option.
  45. This buffer maintains static array of uninitialized elements.
  46. You should manually construct each element when needed.
  47. No dynamic memory allocation performed.
  48. \par Template parameters:
  49. - \p T - item type the buffer stores
  50. - \p Capacity - the capacity of buffer. The value must be power of two if \p Exp2 is \p true
  51. - \p Exp2 - a boolean flag. If it is \p true the buffer capacity must be power of two.
  52. Otherwise it can be any positive number. Usually, it is required that the buffer has
  53. size of a power of two.
  54. */
  55. template <typename T, size_t Capacity, bool Exp2 = true>
  56. class uninitialized_static_buffer
  57. {
  58. public:
  59. typedef T value_type; ///< value type
  60. static constexpr const size_t c_nCapacity = Capacity; ///< Capacity
  61. static constexpr const bool c_bExp2 = Exp2; ///< \p Exp2 flag
  62. /// Rebind buffer for other template parameters
  63. template <typename Q, size_t Capacity2 = c_nCapacity, bool Exp22 = c_bExp2>
  64. struct rebind {
  65. typedef uninitialized_static_buffer<Q, Capacity2, Exp22> other; ///< Rebind result type
  66. };
  67. // Capacity must be power of 2
  68. static_assert(!c_bExp2 || (c_nCapacity & (c_nCapacity - 1)) == 0, "Capacity must be power of two");
  69. private:
  70. //@cond
  71. union element {
  72. value_type v;
  73. char c;
  74. element()
  75. {}
  76. };
  77. element m_buffer[c_nCapacity];
  78. //@endcond
  79. public:
  80. /// Construct static buffer
  81. uninitialized_static_buffer() noexcept
  82. {}
  83. /// Construct buffer of given capacity
  84. /**
  85. This ctor ignores \p nCapacity argument. The capacity of static buffer
  86. is defined by template argument \p Capacity
  87. */
  88. uninitialized_static_buffer( size_t nCapacity ) noexcept
  89. {
  90. CDS_UNUSED( nCapacity );
  91. }
  92. uninitialized_static_buffer( const uninitialized_static_buffer& ) = delete;
  93. uninitialized_static_buffer& operator =( const uninitialized_static_buffer& ) = delete;
  94. /// Get item \p i
  95. value_type& operator []( size_t i )
  96. {
  97. assert( i < capacity());
  98. return m_buffer[i].v;
  99. }
  100. /// Get item \p i, const version
  101. const value_type& operator []( size_t i ) const
  102. {
  103. assert( i < capacity());
  104. return m_buffer[i].v;
  105. }
  106. /// Returns buffer capacity
  107. constexpr size_t capacity() const noexcept
  108. {
  109. return c_nCapacity;
  110. }
  111. /// Zeroize the buffer
  112. void zeroize()
  113. {
  114. memset( m_buffer, 0, capacity() * sizeof(m_buffer[0]));
  115. }
  116. /// Returns pointer to buffer array
  117. value_type * buffer() noexcept
  118. {
  119. return &( m_buffer[0].v );
  120. }
  121. /// Returns pointer to buffer array
  122. value_type * buffer() const noexcept
  123. {
  124. return &( m_buffer[0].v );
  125. }
  126. /// Returns <tt> idx % capacity() </tt>
  127. /**
  128. If the buffer size is a power of two, binary arithmethics is used
  129. instead of modulo arithmetics
  130. */
  131. size_t mod( size_t idx )
  132. {
  133. constexpr_if ( c_bExp2 )
  134. return idx & ( capacity() - 1 );
  135. else
  136. return idx % capacity();
  137. }
  138. //@cond
  139. template <typename I>
  140. typename std::enable_if< sizeof(I) != sizeof(size_t), size_t >::type mod( I idx )
  141. {
  142. constexpr_if ( c_bExp2 )
  143. return static_cast<size_t>( idx & static_cast<I>( capacity() - 1 ));
  144. else
  145. return static_cast<size_t>( idx % capacity());
  146. }
  147. //@endcond
  148. };
  149. /// Static initialized buffer
  150. /**
  151. One of available type for \p opt::buffer option.
  152. This buffer maintains static array of default-constructed elements.
  153. No dynamic memory allocation performed.
  154. \par Template parameters:
  155. - \p T - item type the buffer stores
  156. - \p Capacity - the capacity of buffer. The value must be power of two if \p Exp2 is \p true
  157. - \p Exp2 - a boolean flag. If it is \p true the buffer capacity must be power of two.
  158. Otherwise it can be any positive number. Usually, it is required that the buffer has
  159. size of a power of two.
  160. */
  161. template <typename T, size_t Capacity, bool Exp2 = true>
  162. class initialized_static_buffer
  163. {
  164. public:
  165. typedef T value_type; ///< value type
  166. static constexpr const size_t c_nCapacity = Capacity; ///< Capacity
  167. static constexpr const bool c_bExp2 = Exp2; ///< \p Exp2 flag
  168. /// Rebind buffer for other template parameters
  169. template <typename Q, size_t Capacity2 = c_nCapacity, bool Exp22 = c_bExp2>
  170. struct rebind {
  171. typedef initialized_static_buffer<Q, Capacity2, Exp22> other; ///< Rebind result type
  172. };
  173. // Capacity must be power of 2
  174. static_assert(!c_bExp2 || (c_nCapacity & (c_nCapacity - 1)) == 0, "Capacity must be power of two");
  175. private:
  176. //@cond
  177. value_type m_buffer[c_nCapacity];
  178. //@endcond
  179. public:
  180. /// Construct static buffer
  181. initialized_static_buffer() noexcept
  182. {}
  183. /// Construct buffer of given capacity
  184. /**
  185. This ctor ignores \p nCapacity argument. The capacity of static buffer
  186. is defined by template argument \p Capacity
  187. */
  188. initialized_static_buffer( size_t nCapacity ) noexcept
  189. {
  190. CDS_UNUSED( nCapacity );
  191. }
  192. initialized_static_buffer( const initialized_static_buffer& ) = delete;
  193. initialized_static_buffer& operator =( const initialized_static_buffer& ) = delete;
  194. /// Get item \p i
  195. value_type& operator []( size_t i )
  196. {
  197. assert( i < capacity());
  198. return m_buffer[i];
  199. }
  200. /// Get item \p i, const version
  201. const value_type& operator []( size_t i ) const
  202. {
  203. assert( i < capacity());
  204. return m_buffer[i];
  205. }
  206. /// Returns buffer capacity
  207. constexpr size_t capacity() const noexcept
  208. {
  209. return c_nCapacity;
  210. }
  211. /// Zeroize the buffer
  212. void zeroize()
  213. {
  214. memset( m_buffer, 0, capacity() * sizeof(m_buffer[0]));
  215. }
  216. /// Returns pointer to buffer array
  217. value_type * buffer() noexcept
  218. {
  219. return m_buffer;
  220. }
  221. /// Returns pointer to buffer array
  222. value_type * buffer() const noexcept
  223. {
  224. return m_buffer;
  225. }
  226. /// Returns <tt> idx % capacity() </tt>
  227. /**
  228. If the buffer size is a power of two, binary arithmethics is used
  229. instead of modulo arithmetics
  230. */
  231. size_t mod( size_t idx )
  232. {
  233. constexpr_if ( c_bExp2 )
  234. return idx & ( capacity() - 1 );
  235. else
  236. return idx % capacity();
  237. }
  238. //@cond
  239. template <typename I>
  240. typename std::enable_if< sizeof( I ) != sizeof( size_t ), size_t >::type mod( I idx )
  241. {
  242. constexpr_if ( c_bExp2 )
  243. return static_cast<size_t>( idx & static_cast<I>( capacity() - 1 ));
  244. else
  245. return static_cast<size_t>( idx % capacity());
  246. }
  247. //@endcond
  248. };
  249. /// Dynamically allocated uninitialized buffer
  250. /**
  251. One of available type for \p opt::buffer option.
  252. This buffer maintains dynamically allocated array of uninitialized elements.
  253. You should manually construct each element when needed.
  254. Allocation is performed at construction time.
  255. \par Template parameters:
  256. - \p T - item type storing in the buffer
  257. - \p Alloc - an allocator used for allocating internal buffer (\p std::allocator interface)
  258. - \p Exp2 - a boolean flag. If it is \p true the buffer capacity must be power of two.
  259. Otherwise it can be any positive number. Usually, it is required that the buffer has
  260. size of a power of two.
  261. */
  262. template <typename T, class Alloc = CDS_DEFAULT_ALLOCATOR, bool Exp2 = true>
  263. class uninitialized_dynamic_buffer
  264. {
  265. public:
  266. typedef T value_type; ///< Value type
  267. typedef Alloc allocator; ///< Allocator type;
  268. static constexpr const bool c_bExp2 = Exp2; ///< \p Exp2 flag
  269. /// Rebind buffer for other template parameters
  270. template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
  271. struct rebind {
  272. typedef uninitialized_dynamic_buffer<Q, Alloc2, Exp22> other; ///< Rebinding result type
  273. };
  274. //@cond
  275. typedef typename std::allocator_traits<allocator>::template rebind_alloc<value_type> allocator_type;
  276. //@endcond
  277. private:
  278. //@cond
  279. value_type * m_buffer;
  280. size_t const m_nCapacity;
  281. //@endcond
  282. public:
  283. /// Allocates dynamic buffer of given \p nCapacity
  284. /**
  285. If \p Exp2 class template parameter is \p true then actual capacity
  286. of allocating buffer is nearest upper to \p nCapacity power of two.
  287. */
  288. uninitialized_dynamic_buffer( size_t nCapacity )
  289. : m_nCapacity( c_bExp2 ? beans::ceil2(nCapacity) : nCapacity )
  290. {
  291. assert( m_nCapacity >= 2 );
  292. // Capacity must be power of 2
  293. assert( !c_bExp2 || (m_nCapacity & (m_nCapacity - 1)) == 0 );
  294. m_buffer = allocator_type().allocate( m_nCapacity );
  295. }
  296. /// Destroys dynamically allocated buffer
  297. ~uninitialized_dynamic_buffer()
  298. {
  299. allocator_type().deallocate( m_buffer, m_nCapacity );
  300. }
  301. uninitialized_dynamic_buffer( const uninitialized_dynamic_buffer& ) = delete;
  302. uninitialized_dynamic_buffer& operator =( const uninitialized_dynamic_buffer& ) = delete;
  303. /// Get item \p i
  304. value_type& operator []( size_t i )
  305. {
  306. assert( i < capacity());
  307. return m_buffer[i];
  308. }
  309. /// Get item \p i, const version
  310. const value_type& operator []( size_t i ) const
  311. {
  312. assert( i < capacity());
  313. return m_buffer[i];
  314. }
  315. /// Returns buffer capacity
  316. size_t capacity() const noexcept
  317. {
  318. return m_nCapacity;
  319. }
  320. /// Zeroize the buffer
  321. void zeroize()
  322. {
  323. memset( m_buffer, 0, capacity() * sizeof(m_buffer[0]));
  324. }
  325. /// Returns pointer to buffer array
  326. value_type * buffer() noexcept
  327. {
  328. return m_buffer;
  329. }
  330. /// Returns pointer to buffer array
  331. value_type * buffer() const noexcept
  332. {
  333. return m_buffer;
  334. }
  335. /// Returns <tt> idx % capacity() </tt>
  336. /**
  337. If the buffer size is a power of two, binary arithmethics is used
  338. instead of modulo arithmetics
  339. */
  340. size_t mod( size_t idx )
  341. {
  342. constexpr_if ( c_bExp2 )
  343. return idx & ( capacity() - 1 );
  344. else
  345. return idx % capacity();
  346. }
  347. //@cond
  348. template <typename I>
  349. typename std::enable_if< sizeof( I ) != sizeof( size_t ), size_t >::type mod( I idx )
  350. {
  351. constexpr_if ( c_bExp2 )
  352. return static_cast<size_t>( idx & static_cast<I>( capacity() - 1 ));
  353. else
  354. return static_cast<size_t>( idx % capacity());
  355. }
  356. //@endcond
  357. };
  358. /// Dynamically allocated initialized buffer
  359. /**
  360. One of available type for \p opt::buffer option.
  361. This buffer maintains dynamically allocated array of initialized default-constructed elements.
  362. Allocation is performed at construction time.
  363. \par Template parameters:
  364. - \p T - item type storing in the buffer
  365. - \p Alloc - an allocator used for allocating internal buffer (\p std::allocator interface)
  366. - \p Exp2 - a boolean flag. If it is \p true the buffer capacity must be power of two.
  367. Otherwise it can be any positive number. Usually, it is required that the buffer has
  368. size of a power of two.
  369. */
  370. template <typename T, class Alloc = CDS_DEFAULT_ALLOCATOR, bool Exp2 = true>
  371. class initialized_dynamic_buffer
  372. {
  373. public:
  374. typedef T value_type; ///< Value type
  375. typedef Alloc allocator; ///< Allocator type
  376. static constexpr const bool c_bExp2 = Exp2; ///< \p Exp2 flag
  377. /// Rebind buffer for other template parameters
  378. template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
  379. struct rebind {
  380. typedef initialized_dynamic_buffer<Q, Alloc2, Exp22> other; ///< Rebinding result type
  381. };
  382. //@cond
  383. typedef cds::details::Allocator<value_type, allocator> allocator_type;
  384. //@endcond
  385. private:
  386. //@cond
  387. value_type * m_buffer;
  388. size_t const m_nCapacity;
  389. //@endcond
  390. public:
  391. /// Allocates dynamic buffer of given \p nCapacity
  392. /**
  393. If \p Exp2 class template parameter is \p true then actual capacity
  394. of allocating buffer is nearest upper to \p nCapacity power of two.
  395. */
  396. initialized_dynamic_buffer( size_t nCapacity )
  397. : m_nCapacity( c_bExp2 ? beans::ceil2(nCapacity) : nCapacity )
  398. {
  399. assert( m_nCapacity >= 2 );
  400. // Capacity must be power of 2
  401. assert( !c_bExp2 || (m_nCapacity & (m_nCapacity - 1)) == 0 );
  402. allocator_type a;
  403. m_buffer = a.NewArray( m_nCapacity );
  404. }
  405. /// Destroys dynamically allocated buffer
  406. ~initialized_dynamic_buffer()
  407. {
  408. allocator_type a;
  409. a.Delete( m_buffer, m_nCapacity );
  410. }
  411. initialized_dynamic_buffer( const initialized_dynamic_buffer& ) = delete;
  412. initialized_dynamic_buffer& operator =( const initialized_dynamic_buffer& ) = delete;
  413. /// Get item \p i
  414. value_type& operator []( size_t i )
  415. {
  416. assert( i < capacity());
  417. return m_buffer[i];
  418. }
  419. /// Get item \p i, const version
  420. const value_type& operator []( size_t i ) const
  421. {
  422. assert( i < capacity());
  423. return m_buffer[i];
  424. }
  425. /// Returns buffer capacity
  426. size_t capacity() const noexcept
  427. {
  428. return m_nCapacity;
  429. }
  430. /// Zeroize the buffer
  431. void zeroize()
  432. {
  433. memset( m_buffer, 0, capacity() * sizeof(m_buffer[0]));
  434. }
  435. /// Returns pointer to buffer array
  436. value_type * buffer() noexcept
  437. {
  438. return m_buffer;
  439. }
  440. /// Returns pointer to buffer array
  441. value_type * buffer() const noexcept
  442. {
  443. return m_buffer;
  444. }
  445. /// Returns <tt> idx % capacity() </tt>
  446. /**
  447. If the buffer size is a power of two, binary arithmethics is used
  448. instead of modulo arithmetics
  449. */
  450. size_t mod( size_t idx )
  451. {
  452. constexpr_if ( c_bExp2 )
  453. return idx & ( capacity() - 1 );
  454. else
  455. return idx % capacity();
  456. }
  457. //@cond
  458. template <typename I>
  459. typename std::enable_if< sizeof( I ) != sizeof( size_t ), size_t >::type mod( I idx )
  460. {
  461. constexpr_if ( c_bExp2 )
  462. return static_cast<size_t>( idx & static_cast<I>( capacity() - 1 ));
  463. else
  464. return static_cast<size_t>( idx % capacity());
  465. }
  466. //@endcond
  467. };
  468. } // namespace v
  469. }} // namespace cds::opt
  470. #endif // #ifndef CDSLIB_OPT_BUFFER_H