You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
16 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/algorithms/pod.hpp
  3. *
  4. * Purpose: Algorithms for Plain-Old Data types.
  5. *
  6. * Created: 17th January 2002
  7. * Updated: 11th August 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2002-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file stlsoft/algorithms/pod.hpp
  40. *
  41. * \brief [C++ only] Algorithms for use with POD types
  42. * (\ref group__library__algorithms "Algorithms" Library).
  43. */
  44. #ifndef STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD
  45. #define STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_POD_MAJOR 3
  48. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_POD_MINOR 5
  49. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_POD_REVISION 3
  50. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_POD_EDIT 90
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  56. # include <stlsoft/stlsoft.h>
  57. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  58. #ifndef STLSOFT_INCL_STLSOFT_ALGORITHM_STD_HPP_ALT
  59. # include <stlsoft/algorithms/std/alt.hpp>
  60. #endif /* !STLSOFT_INCL_STLSOFT_ALGORITHM_STD_HPP_ALT */
  61. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS
  62. # include <stlsoft/util/constraints.hpp>
  63. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS */
  64. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_INTEGRAL_TYPE
  65. # include <stlsoft/meta/is_integral_type.hpp>
  66. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_INTEGRAL_TYPE */
  67. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_POINTER_TYPE
  68. # include <stlsoft/meta/is_pointer_type.hpp>
  69. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_POINTER_TYPE */
  70. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE
  71. # include <stlsoft/meta/is_same_type.hpp>
  72. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE */
  73. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_YESNO
  74. # include <stlsoft/meta/yesno.hpp>
  75. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_YESNO */
  76. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  77. defined(STLSOFT_COMPILER_IS_INTEL) || \
  78. defined(STLSOFT_COMPILER_IS_MSVC)
  79. # include <memory.h> // for memcpy
  80. #else /* ? compiler */
  81. # include <string.h> // for memcpy
  82. #endif /* compiler */
  83. #ifdef STLSOFT_UNITTEST
  84. # ifndef STLSOFT_INCL_STLSOFT_ERROR_HPP_EXCEPTIONS
  85. # include <stlsoft/error/exceptions.hpp> // for null_exception_policy
  86. # endif /* !STLSOFT_INCL_STLSOFT_ERROR_HPP_EXCEPTIONS */
  87. #endif /* STLSOFT_UNITTEST */
  88. /* /////////////////////////////////////////////////////////////////////////
  89. * Namespace
  90. */
  91. #ifndef _STLSOFT_NO_NAMESPACE
  92. namespace stlsoft
  93. {
  94. #endif /* _STLSOFT_NO_NAMESPACE */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Helper functions
  97. */
  98. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  99. struct ximpl_stlsoft_algorithm_pod_helper_
  100. {
  101. // Same-type operations
  102. template<
  103. ss_typename_param_k T
  104. >
  105. static void pod_copy_n_(
  106. T* dest
  107. , T const* src
  108. , ss_size_t n
  109. , yes_type
  110. )
  111. {
  112. ::memcpy(dest, src, n * sizeof(*dest));
  113. }
  114. template<
  115. ss_typename_param_k T
  116. >
  117. static void pod_move_n_(
  118. T* dest
  119. , T const* src
  120. , ss_size_t n
  121. , yes_type
  122. )
  123. {
  124. ::memmove(dest, src, n * sizeof(*dest));
  125. }
  126. // Different-type operations
  127. //
  128. // - ptr-to-ptr is fine
  129. // - int-to-int is fine
  130. template<
  131. ss_typename_param_k O
  132. , ss_typename_param_k I
  133. >
  134. static void pod_copy_n_(
  135. O* dest
  136. , I const* src
  137. , ss_size_t n
  138. , no_type
  139. )
  140. {
  141. enum { O_IS_INTEGRAL_TYPE = (0 != is_integral_type<O>::value) };
  142. enum { I_IS_INTEGRAL_TYPE = (0 != is_integral_type<I>::value) };
  143. enum { O_IS_POINTER_TYPE = (0 != is_pointer_type<O>::value) };
  144. enum { I_IS_POINTER_TYPE = (0 != is_pointer_type<I>::value) };
  145. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*src));
  146. STLSOFT_STATIC_ASSERT(int(O_IS_INTEGRAL_TYPE) == int(I_IS_INTEGRAL_TYPE));
  147. STLSOFT_STATIC_ASSERT(int(O_IS_POINTER_TYPE) == int(I_IS_POINTER_TYPE));
  148. ::memcpy(dest, src, n * sizeof(*dest));
  149. }
  150. template<
  151. ss_typename_param_k O
  152. , ss_typename_param_k I
  153. >
  154. static void pod_move_n_(
  155. O* dest
  156. , I const* src
  157. , ss_size_t n
  158. , no_type
  159. )
  160. {
  161. enum { O_IS_INTEGRAL_TYPE = (0 != is_integral_type<O>::value) };
  162. enum { I_IS_INTEGRAL_TYPE = (0 != is_integral_type<I>::value) };
  163. enum { O_IS_POINTER_TYPE = (0 != is_pointer_type<O>::value) };
  164. enum { I_IS_POINTER_TYPE = (0 != is_pointer_type<I>::value) };
  165. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*src));
  166. STLSOFT_STATIC_ASSERT(int(O_IS_INTEGRAL_TYPE) == int(I_IS_INTEGRAL_TYPE));
  167. STLSOFT_STATIC_ASSERT(int(O_IS_POINTER_TYPE) == int(I_IS_POINTER_TYPE));
  168. ::memmove(dest, src, n * sizeof(*dest));
  169. }
  170. };
  171. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  172. /* /////////////////////////////////////////////////////////////////////////
  173. * Algorithms
  174. */
  175. /** \brief Copies one range of POD (Plain Old Data) entities to another
  176. *
  177. * \ingroup group__library__algorithms
  178. *
  179. * This algorithm has the same semantics as std::copy(), but it uses
  180. * ::memcpy() to copy elements en bloc, rather than copy assignment of one element
  181. * at a time.
  182. *
  183. \code
  184. const int8_t src_bytes[3] = { -1, 0, +1 };
  185. int8_t dest_bytes[3];
  186. pod_copy(&src_bytes[0], &src_bytes[0] + STLSOFT_NUM_ELEMENTS(src_bytes), &dest_bytes[0]);
  187. assert(0 == memcmp(&src_bytes[0], &dest_bytes[0], sizeof(src_bytes)));
  188. \endcode
  189. *
  190. * \note The implementation uses static assertions to ensure that the source and
  191. * destination element types are the same size.
  192. *
  193. * \note The implementation uses constraints ensure sure that the source and
  194. * destination element types are POD
  195. *
  196. * \param first Contiguous Iterator marking the start of the source range
  197. * \param last Contiguous Iterator marking the one-past-the-end of the source range
  198. * \param dest Contiguous Iterator marking the start of the source range
  199. */
  200. template< ss_typename_param_k I
  201. , ss_typename_param_k O
  202. >
  203. // [[synesis:function:algorithm: pod_copy(T<I> *first, T<I>* last, T<O>* dest)]]
  204. inline void pod_copy(I* first, I* last, O* dest)
  205. {
  206. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  207. defined(STLSOFT_COMPILER_IS_DMC)
  208. std_copy(&first[0], &last[0], &dest[0]);
  209. #else /* ? compiler */
  210. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*first));
  211. stlsoft_constraint_must_be_pod(O);
  212. stlsoft_constraint_must_be_pod(I);
  213. enum { TYPES_ARE_SAME = is_same_type<I, O>::value };
  214. typedef ss_typename_type_k value_to_yesno_type<TYPES_ARE_SAME>::type yesno_t;
  215. ss_size_t n = static_cast<ss_size_t>(last - first);
  216. ximpl_stlsoft_algorithm_pod_helper_::pod_copy_n_(dest, first, n, yesno_t());
  217. #endif /* compiler */
  218. }
  219. /** \brief Copies one range of POD (Plain Old Data) entities to another
  220. *
  221. * \ingroup group__library__algorithms
  222. *
  223. * This algorithm uses ::memcpy() to copy elements en bloc, rather than
  224. * copy assignment of one element at a time.
  225. *
  226. \code
  227. const int8_t src_bytes[3] = { -1, 0, +1 };
  228. int8_t dest_bytes[3];
  229. pod_copy_n(&dest_bytes[0], &src_bytes[0], STLSOFT_NUM_ELEMENTS(src_bytes));
  230. assert(0 == memcmp(&src_bytes[0], &dest_bytes[0], sizeof(src_bytes)));
  231. \endcode
  232. *
  233. * \note The implementation uses static assertions to ensure that the source and
  234. * destination element types are the same size.
  235. *
  236. * \note The implementation uses constraints ensure sure that the source and
  237. * destination element types are POD
  238. *
  239. * \param dest Contiguous Iterator marking the start of the source range
  240. * \param src Contiguous Iterator marking the start of the source range
  241. * \param n Number of elements in the range
  242. */
  243. template< ss_typename_param_k I
  244. , ss_typename_param_k O
  245. >
  246. // [[synesis:function:algorithm: pod_copy_n(T<O>* dest, T<I> *src, size_t n)]]
  247. inline void pod_copy_n(O *dest, I *src, ss_size_t n)
  248. {
  249. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  250. defined(STLSOFT_COMPILER_IS_DMC)
  251. std_copy(&src[0], &src[n], &dest[0]);
  252. #else /* ? compiler */
  253. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*src));
  254. stlsoft_constraint_must_be_pod(O);
  255. stlsoft_constraint_must_be_pod(I);
  256. enum { TYPES_ARE_SAME = is_same_type<I, O>::value };
  257. typedef ss_typename_type_k value_to_yesno_type<TYPES_ARE_SAME>::type yesno_t;
  258. ximpl_stlsoft_algorithm_pod_helper_::pod_copy_n_(dest, src, n, yesno_t());
  259. #endif /* compiler */
  260. }
  261. /** \brief Copies one range of POD (Plain Old Data) entities to another, where the two
  262. * may potentially overlap
  263. *
  264. * \ingroup group__library__algorithms
  265. *
  266. * This algorithm has the same semantics as std::copy(), but it uses
  267. * ::memmove() to copy elements en bloc, rather than copy assignment of one element
  268. * at a time.
  269. *
  270. * \note The implementation uses static assertions to ensure that the source and
  271. * destination element types are the same size.
  272. *
  273. * \note The implementation uses constraints ensure sure that the source and
  274. * destination element types are POD
  275. *
  276. * \param first Contiguous Iterator marking the start of the source range
  277. * \param last Contiguous Iterator marking the one-past-the-end of the source range
  278. * \param dest Contiguous Iterator marking the start of the source range
  279. */
  280. template< ss_typename_param_k I
  281. , ss_typename_param_k O
  282. >
  283. // [[synesis:function:algorithm: pod_move(T<I>* first, T<I>* last, T<O>* dest)]]
  284. inline void pod_move(I* first, I* last, O* dest)
  285. {
  286. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  287. defined(STLSOFT_COMPILER_IS_DMC)
  288. std_copy(&first[0], &last[0], &dest[0]);
  289. #else /* ? compiler */
  290. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*first));
  291. stlsoft_constraint_must_be_pod(O);
  292. stlsoft_constraint_must_be_pod(I);
  293. enum { TYPES_ARE_SAME = is_same_type<I, O>::value };
  294. typedef ss_typename_type_k value_to_yesno_type<TYPES_ARE_SAME>::type yesno_t;
  295. ss_size_t n = static_cast<ss_size_t>(last - first);
  296. ximpl_stlsoft_algorithm_pod_helper_::pod_move_n_(dest, first, n, yesno_t());
  297. #endif /* compiler */
  298. }
  299. /** \brief Copies one range of POD (Plain Old Data) entities to another, where the two
  300. * may potentially overlap
  301. *
  302. * \ingroup group__library__algorithms
  303. *
  304. * \note This algorithm uses ::memmove() to copy elements en bloc, rather than
  305. * copy assignment of one element at a time.
  306. *
  307. * \note The implementation uses static assertions to ensure that the source and
  308. * destination element types are the same size.
  309. *
  310. * \note The implementation uses constraints ensure sure that the source and
  311. * destination element types are POD
  312. *
  313. * \param dest Contiguous Iterator marking the start of the source range
  314. * \param src Contiguous Iterator marking the start of the source range
  315. * \param n Number of elements in the range
  316. */
  317. template< ss_typename_param_k I
  318. , ss_typename_param_k O
  319. >
  320. // [[synesis:function:algorithm: pod_move_n(T<O> *dest, T<I> *src, size_t n)]]
  321. inline void pod_move_n(O *dest, I *src, ss_size_t n)
  322. {
  323. #if defined(STLSOFT_COMPILER_IS_BORLAND) || \
  324. defined(STLSOFT_COMPILER_IS_DMC)
  325. std_copy(&src[0], &src[n], &dest[0]);
  326. #else /* ? compiler */
  327. STLSOFT_STATIC_ASSERT(sizeof(*dest) == sizeof(*src));
  328. stlsoft_constraint_must_be_pod(O);
  329. stlsoft_constraint_must_be_pod(I);
  330. enum { TYPES_ARE_SAME = is_same_type<I, O>::value };
  331. typedef ss_typename_type_k value_to_yesno_type<TYPES_ARE_SAME>::type yesno_t;
  332. ximpl_stlsoft_algorithm_pod_helper_::pod_move_n_(dest, src, n, yesno_t());
  333. #endif /* compiler */
  334. }
  335. /** \brief Sets all the elements in a range of POD (Plain Old Data) to a given value
  336. *
  337. * \ingroup group__library__algorithms
  338. *
  339. * This algorithm has the same semantics as std::fill_n(), but it uses
  340. * ::memset() for some types to set the range of elements, rather than copy
  341. * assignment of one element at a time.
  342. *
  343. \code
  344. const int8_t src_bytes[3] = { 3, 3, 3 };
  345. int8_t dest_bytes[3];
  346. pod_fill_n(&dest_bytes[0], STLSOFT_NUM_ELEMENTS(src_bytes), 3);
  347. assert(0 == memcmp(&src_bytes[0], &dest_bytes[0], sizeof(src_bytes)));
  348. \endcode
  349. *
  350. * The generic overload uses std::fill_n(), so performance is likely to be
  351. * identical to std::fill_n() in the general case. However, it is overloaded
  352. * to use ::memset() on \c char, \c signed \c char and \c unsigned \c char
  353. * types, for which performance gains are likely.
  354. *
  355. * \param dest Contiguous Iterator marking the start of the source range
  356. * \param n Number of elements in the range
  357. * \param value Value to which each element in dest[0, n) will be set
  358. */
  359. template< ss_typename_param_k T
  360. , ss_typename_param_k V
  361. >
  362. // [[synesis:function:algorithm: pod_fill_n(T<T> *dest, T<V> const& value)]]
  363. inline void pod_fill_n(T *dest, ss_size_t n, V const& value)
  364. {
  365. // Constrain to POD type:
  366. stlsoft_constraint_must_be_pod(T);
  367. std_fill_n(dest, n, value);
  368. }
  369. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  370. // [[synesis:function:algorithm: pod_fill_n(char *dest, int value)]]
  371. inline void pod_fill_n(char *dest, ss_size_t n, int value)
  372. {
  373. ::memset(dest, value, n);
  374. }
  375. // [[synesis:function:algorithm: pod_fill_n(signed char *dest, int value)]]
  376. inline void pod_fill_n(signed char *dest, ss_size_t n, int value)
  377. {
  378. ::memset(dest, value, n);
  379. }
  380. // [[synesis:function:algorithm: pod_fill_n(unsigned char *dest, int value)]]
  381. inline void pod_fill_n(unsigned char *dest, ss_size_t n, int value)
  382. {
  383. ::memset(dest, value, n);
  384. }
  385. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  386. ////////////////////////////////////////////////////////////////////////////
  387. // Unit-testing
  388. #ifdef STLSOFT_UNITTEST
  389. # include "./unittest/pod_unittest_.h"
  390. #endif /* STLSOFT_UNITTEST */
  391. /* ////////////////////////////////////////////////////////////////////// */
  392. #ifndef _STLSOFT_NO_NAMESPACE
  393. } // namespace stlsoft
  394. #endif /* _STLSOFT_NO_NAMESPACE */
  395. /* ////////////////////////////////////////////////////////////////////// */
  396. #endif /* !STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD */
  397. /* ///////////////////////////// end of file //////////////////////////// */