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
14 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/algorithms/unordered.hpp
  3. *
  4. * Purpose: Algorithms for manipulating unordered sequences.
  5. *
  6. * Created: 17th January 2002
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2002-2009, 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/unordered.hpp
  40. *
  41. * \brief [C++ only] Algorithms for manipulating unordered sequences
  42. * (\ref group__library__algorithms "Algorithms" Library).
  43. */
  44. #ifndef STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_UNORDERED
  45. #define STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_UNORDERED
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_UNORDERED_MAJOR 3
  48. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_UNORDERED_MINOR 3
  49. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_UNORDERED_REVISION 2
  50. # define STLSOFT_VER_STLSOFT_ALGORITHMS_HPP_UNORDERED_EDIT 71
  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_ALGORITHMS_STD_HPP_ALT
  59. # include <stlsoft/algorithms/std/alt.hpp>
  60. #endif /* !STLSOFT_INCL_STLSOFT_ALGORITHMS_STD_HPP_ALT */
  61. #ifdef STLSOFT_CF_std_NAMESPACE
  62. # include <functional>
  63. #endif /* STLSOFT_CF_std_NAMESPACE */
  64. /* /////////////////////////////////////////////////////////////////////////
  65. * Namespace
  66. */
  67. #ifndef _STLSOFT_NO_NAMESPACE
  68. namespace stlsoft
  69. {
  70. #endif /* _STLSOFT_NO_NAMESPACE */
  71. /* /////////////////////////////////////////////////////////////////////////
  72. * Algorithms
  73. */
  74. #ifdef STLSOFT_CF_std_NAMESPACE
  75. /** \brief Finds the first duplicate item in the unordered sequence
  76. * <code>[first, last)</code>.
  77. *
  78. * \ingroup group__library__algorithms
  79. *
  80. * If a duplicate is found, the return value is a pair of the iterators
  81. * referring to the first and second elements comprising the duplicate.
  82. * If no duplicate is found, the return value is a pair containing the
  83. * \c last iterator in both its members
  84. *
  85. * \param first The start of the (unordered) sequence
  86. * \param last The (one past the) end point of the sequence
  87. *
  88. * \note This algorithm works for ordered sequences, but \c std::adjacent_find
  89. * is more suitable for such cases
  90. */
  91. template<ss_typename_param_k I>
  92. // [[synesis:function:algorithm: find_first_duplicate(T<I> first, T<I> last)]]
  93. #if defined(STLSOFT_COMPILER_IS_DMC) && \
  94. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  95. inline stlsoft_ns_qual_std_(pair)<I, I> find_first_duplicate(I first, I last)
  96. #else /* ? compiler */
  97. inline stlsoft_ns_qual_std(pair)<I, I> find_first_duplicate(I first, I last)
  98. #endif /* compiler */
  99. {
  100. for(; first != last; ++first)
  101. {
  102. I next = first;
  103. for(++next; next != last; ++next)
  104. {
  105. if(*next == *first)
  106. {
  107. return stlsoft_ns_qual_std(make_pair)(first, next);
  108. }
  109. }
  110. }
  111. return stlsoft_ns_qual_std(make_pair)(last, last);
  112. }
  113. /** \brief
  114. *
  115. * \ingroup group__library__algorithms
  116. *
  117. */
  118. template< ss_typename_param_k I
  119. , ss_typename_param_k BP
  120. >
  121. // [[synesis:function:algorithm: find_first_duplicate(T<I> first, T<I> last, T<BP> pred)]]
  122. #if defined(STLSOFT_COMPILER_IS_DMC) && \
  123. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  124. inline stlsoft_ns_qual_std_(pair)<I, I> find_first_duplicate(I first, I last, BP pred)
  125. #else /* ? compiler */
  126. inline stlsoft_ns_qual_std(pair)<I, I> find_first_duplicate(I first, I last, BP pred)
  127. #endif /* compiler */
  128. {
  129. for(; first != last; ++first)
  130. {
  131. I next = first;
  132. for(++next; next != last; ++next)
  133. {
  134. if(pred(*next, *first))
  135. {
  136. return stlsoft_ns_qual_std(make_pair)(first, next);
  137. }
  138. }
  139. }
  140. return stlsoft_ns_qual_std(make_pair)(last, last);
  141. }
  142. #endif /* STLSOFT_CF_std_NAMESPACE */
  143. /** \brief
  144. *
  145. * \ingroup group__library__algorithms
  146. *
  147. */
  148. template <ss_typename_param_k FI>
  149. // [[synesis:function:algorithm: unordered_unique(T<I> first, T<I> last)]]
  150. inline FI unordered_unique(FI first, FI last)
  151. {
  152. if(first != last)
  153. {
  154. // Because this is unordered, we need to enumerate through the
  155. // elements in the sequence, and ...
  156. const FI start = first;
  157. FI dest = ++first;
  158. for(; first != last; ++first)
  159. {
  160. // ... for each element in the sequence, we see if it has
  161. // already in the 'accepted' sequence, and, if not, ...
  162. if(dest == std_find(start, dest, *first))
  163. {
  164. // ... add it into the accepted sequence at the
  165. // current point.
  166. //
  167. // Effectively, this is to overwrite the element
  168. // if the source and destination points are different,
  169. // or simply moving past it if not.
  170. if(dest != first)
  171. {
  172. *dest = *first;
  173. }
  174. ++dest;
  175. }
  176. }
  177. first = dest;
  178. }
  179. return first;
  180. }
  181. /** \brief
  182. *
  183. * \ingroup group__library__algorithms
  184. *
  185. */
  186. template< ss_typename_param_k FI
  187. , ss_typename_param_k BP
  188. >
  189. // [[synesis:function:algorithm: unordered_unique(T<I> first, T<I> last, T<BP> pred)]]
  190. inline FI unordered_unique(FI first, FI last, BP pred)
  191. {
  192. if(first != last)
  193. {
  194. // Because this is unordered, we need to enumerate through the
  195. // elements in the sequence, and ...
  196. const FI start = first;
  197. FI dest = ++first;
  198. for(; first != last; ++first)
  199. {
  200. // ... for each element in the sequence, we see if it has
  201. // already in the 'accepted' sequence, and, if not, ...
  202. if(dest == std_find_if(start, dest, std::bind2nd(pred, *first)))
  203. {
  204. // ... add it into the accepted sequence at the
  205. // current point.
  206. //
  207. // Effectively, this is to overwrite the element
  208. // if the source and destination points are different,
  209. // or simply moving past it if not.
  210. if(dest != first)
  211. {
  212. *dest = *first;
  213. }
  214. ++dest;
  215. }
  216. }
  217. first = dest;
  218. }
  219. return first;
  220. }
  221. /** \brief
  222. *
  223. * \ingroup group__library__algorithms
  224. *
  225. */
  226. template< ss_typename_param_k FI
  227. , ss_typename_param_k BP
  228. >
  229. // [[synesis:function:algorithm: unordered_unique_if(T<I> first, T<I> last, T<BP> pred)]]
  230. inline FI unordered_unique_if(FI first, FI last, BP pred)
  231. {
  232. return unordered_unique(first, last, pred);
  233. }
  234. /** \brief
  235. *
  236. * \ingroup group__library__algorithms
  237. *
  238. */
  239. template< ss_typename_param_k FI
  240. , ss_typename_param_k OI
  241. >
  242. // [[synesis:function:algorithm: unordered_unique(T<I> first, T<I> last, T<OI> dest)]]
  243. inline OI unordered_unique_copy(FI first, FI last, OI dest)
  244. {
  245. if(first != last)
  246. {
  247. // Because this is unordered, we need to enumerate through the
  248. // elements in the sequence, and ...
  249. const OI start = dest;
  250. FI curr = first; // The first elements is always unique
  251. *dest++ = *first++;
  252. for(; first != last; ++first)
  253. {
  254. // ... for each element in the sequence, we see if it has
  255. // already in the 'accepted' sequence, and, if not, ...
  256. if(dest == std_find(start, dest, *first))
  257. {
  258. // ... add it into the accepted sequence at the
  259. // current point.
  260. *dest = *first;
  261. ++dest;
  262. }
  263. }
  264. }
  265. return dest;
  266. }
  267. /** \brief This algorithm removes duplicate entries from unordered sequences.
  268. *
  269. * \ingroup group__library__algorithms
  270. *
  271. * It necessarily runs in O(n2) time, since it must do a bubble-like double
  272. * pass on the sequence (in order to work with unordered sequences).
  273. *
  274. * \param container The container
  275. * \param pred The predicate used to determine the equivalence of items
  276. */
  277. // [[synesis:function:algorithm: remove_duplicates_from_unordered_sequence(T<C> &container, T<BP> pred)]]
  278. template< ss_typename_param_k C
  279. , ss_typename_param_k BP
  280. >
  281. inline void remove_duplicates_from_unordered_sequence(C &container, BP pred)
  282. {
  283. typedef ss_typename_type_k C::iterator iterator_t;
  284. ss_size_t index;
  285. iterator_t begin;
  286. for(index = 0, begin = container.begin(); begin != container.end(); )
  287. {
  288. iterator_t it = begin;
  289. iterator_t end = container.end();
  290. if(++it == end)
  291. {
  292. ++begin;
  293. }
  294. else
  295. {
  296. for(;;)
  297. {
  298. if(pred(*begin, *it))
  299. {
  300. ss_size_t last;
  301. // Erase the element. We now assume that all iterators
  302. // are invalidated
  303. container.erase(it);
  304. // Remember the last erasure point
  305. last = index;
  306. // Set begin back to the start of the sequence
  307. begin = container.begin();
  308. // Move begin to the point where it was at the last erasure
  309. std_advance(begin, static_cast<ss_ptrdiff_t>(last)); // Need to cast so that RAI impl doesn't incur impl conv from unsigned to signed in i += n;
  310. break;
  311. }
  312. else
  313. {
  314. if(++it == end)
  315. {
  316. ++begin;
  317. ++index;
  318. break;
  319. }
  320. }
  321. }
  322. }
  323. }
  324. }
  325. #ifdef STLSOFT_CF_std_NAMESPACE
  326. /** \brief This algorithm removes duplicate entries from unordered sequences.
  327. *
  328. * \ingroup group__library__algorithms
  329. *
  330. * It necessarily runs in O(n2) time, since it must do a bubble-like double
  331. * pass on the sequence (in order to work with unordered sequences).
  332. *
  333. * \param container The container
  334. */
  335. // [[synesis:function:algorithm: remove_duplicates_from_unordered_sequence(T<C> &container)]]
  336. template<ss_typename_param_k C>
  337. inline void remove_duplicates_from_unordered_sequence(C &container)
  338. {
  339. typedef ss_typename_type_k C::value_type value_t;
  340. remove_duplicates_from_unordered_sequence(container, stlsoft_ns_qual_std(equal_to)<value_t>());
  341. }
  342. #endif /* STLSOFT_CF_std_NAMESPACE */
  343. /** \brief Skips along from a given iteration point to the first subsequent
  344. * iteration point whose value is not equal to that of the starting
  345. * point
  346. *
  347. * \ingroup group__library__algorithms
  348. *
  349. *
  350. * \param first The start of the sequence
  351. * \param last The (one past the) end point of the sequence
  352. */
  353. template<ss_typename_param_k I>
  354. // [[synesis:function:algorithm: fill_all(T<I> first, T<I> last)]]
  355. inline I skip_equal(I first, I last)
  356. {
  357. if(first == last)
  358. {
  359. return last;
  360. }
  361. else
  362. {
  363. for(I next = first; next != last; ++next)
  364. {
  365. if(*next != *first)
  366. {
  367. return next;
  368. }
  369. }
  370. return last;
  371. }
  372. }
  373. /** \brief Determines whether all elements from the range
  374. * <code>[first2, last2)</code> are contained within the range
  375. * <code>[first1, last1)</code>.
  376. *
  377. * \ingroup group__library__algorithms
  378. *
  379. * \note The algorithm does <i>not</i> assume that the ranges are ordered, and
  380. * so does linear searches. If the ranges are ordered, you should use \c std::includes
  381. */
  382. template< ss_typename_param_k I1
  383. , ss_typename_param_k I2
  384. >
  385. inline ss_bool_t unordered_includes(I1 first1, I1 last1, I2 first2, I2 last2)
  386. {
  387. for(; first2 != last2; ++first2)
  388. {
  389. ss_bool_t bFound = false;
  390. for(I1 i1 = first1; i1 != last1; ++i1)
  391. {
  392. if(*first2 == *i1)
  393. {
  394. bFound = true;
  395. break;
  396. }
  397. }
  398. if(!bFound)
  399. {
  400. return false;
  401. }
  402. }
  403. return true;
  404. }
  405. ////////////////////////////////////////////////////////////////////////////
  406. // Unit-testing
  407. #ifdef STLSOFT_UNITTEST
  408. # include "./unittest/unordered_unittest_.h"
  409. #endif /* STLSOFT_UNITTEST */
  410. /* ////////////////////////////////////////////////////////////////////// */
  411. #ifndef _STLSOFT_NO_NAMESPACE
  412. } // namespace stlsoft
  413. #endif /* _STLSOFT_NO_NAMESPACE */
  414. /* ////////////////////////////////////////////////////////////////////// */
  415. #endif /* !STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_UNORDERED */
  416. /* ///////////////////////////// end of file //////////////////////////// */