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.

515 lines
18 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: rangelib/iterator_range.hpp
  3. *
  4. * Purpose: Iterator range adaptor.
  5. *
  6. * Created: 4th November 2003
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2003-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 rangelib/iterator_range.hpp Iterator range adaptor */
  40. #ifndef RANGELIB_INCL_RANGELIB_HPP_ITERATOR_RANGE
  41. #define RANGELIB_INCL_RANGELIB_HPP_ITERATOR_RANGE
  42. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  43. # define RANGELIB_VER_RANGELIB_HPP_ITERATOR_RANGE_MAJOR 2
  44. # define RANGELIB_VER_RANGELIB_HPP_ITERATOR_RANGE_MINOR 6
  45. # define RANGELIB_VER_RANGELIB_HPP_ITERATOR_RANGE_REVISION 4
  46. # define RANGELIB_VER_RANGELIB_HPP_ITERATOR_RANGE_EDIT 43
  47. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  48. /* /////////////////////////////////////////////////////////////////////////
  49. * Auto-generation and compatibility
  50. */
  51. /*
  52. [<[STLSOFT-AUTO:NO-UNITTEST]>]
  53. [Incompatibilies-start]
  54. STLSOFT_COMPILER_IS_BORLAND:
  55. STLSOFT_COMPILER_IS_GCC: __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
  56. STLSOFT_COMPILER_IS_MSVC: _MSC_VER < 1200
  57. STLSOFT_COMPILER_IS_MWERKS: (__MWERKS__ & 0xFF00) < 0x3000
  58. [Incompatibilies-end]
  59. */
  60. /* /////////////////////////////////////////////////////////////////////////
  61. * Includes
  62. */
  63. #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGELIB
  64. # include <rangelib/rangelib.hpp>
  65. #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGELIB */
  66. #ifndef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
  67. # error rangelib/iterator_range.hpp is not compatible with compilers that do not support partial template specialisation
  68. #endif /* !STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  69. #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES
  70. # include <rangelib/range_categories.hpp>
  71. #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES */
  72. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL
  73. # include <stlsoft/util/operator_bool.hpp>
  74. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL */
  75. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES
  76. # include <stlsoft/meta/capabilities.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES */
  78. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS
  79. # include <stlsoft/meta/base_type_traits.hpp>
  80. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS */
  81. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  82. # include <stlsoft/util/std/iterator_helper.hpp>
  83. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  84. #ifdef STLSOFT_UNITTEST
  85. # include <algorithm>
  86. # include <deque>
  87. # include <list>
  88. # include <numeric>
  89. # include <vector>
  90. #endif /* STLSOFT_UNITTEST */
  91. /* /////////////////////////////////////////////////////////////////////////
  92. * Namespace
  93. */
  94. #ifndef RANGELIB_NO_NAMESPACE
  95. # if defined(_STLSOFT_NO_NAMESPACE) || \
  96. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  97. /* There is no stlsoft namespace, so must define ::rangelib */
  98. namespace rangelib
  99. {
  100. # else
  101. /* Define stlsoft::rangelib_project */
  102. namespace stlsoft
  103. {
  104. namespace rangelib_project
  105. {
  106. # endif /* _STLSOFT_NO_NAMESPACE */
  107. #endif /* !RANGELIB_NO_NAMESPACE */
  108. /* /////////////////////////////////////////////////////////////////////////
  109. * Classes
  110. */
  111. #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
  112. /** \brief Traits class for determining the attributes of range-adapted iterator types
  113. *
  114. * \ingroup group__library__rangelib
  115. */
  116. template< ss_typename_param_k I
  117. , bool B_CONST
  118. >
  119. struct iterator_range_traits
  120. {
  121. public:
  122. /// The iterator type
  123. typedef I iterator_type;
  124. /// The value type
  125. typedef ss_typename_type_k I::value_type value_type;
  126. private:
  127. #ifdef STLSOFT_ITERATOR_ITERATOR_FORM2_SUPPORT
  128. // Use the iterator itself to determine whether the iterator is const
  129. enum { is_const = base_type_traits<value_type>::is_const };
  130. #else /* ? STLSOFT_ITERATOR_ITERATOR_FORM2_SUPPORT */
  131. // 1. Use iterator_traits ...
  132. typedef std::iterator_traits<I> traits_type_;
  133. // ... to get the pointer type ...
  134. typedef ss_typename_type_k traits_type_::pointer pointer_type_;
  135. // ... to determine whether the iterator is const
  136. enum { is_const = base_type_traits<pointer_type_>::is_const };
  137. #endif /* !STLSOFT_ITERATOR_ITERATOR_FORM2_SUPPORT */
  138. // 2. Use Determine the base type of the value_type, which may then be used to create a reference of the appropriate type
  139. typedef ss_typename_type_k base_type_traits<value_type>::base_type base_value_type;
  140. // enum { is_const = is_const<pointer>::value };
  141. public:
  142. /// The mutating (non-const) iterator type
  143. typedef I iterator;
  144. /// The non-mutating (const) iterator type
  145. typedef ss_typename_type_k base_type_traits<iterator>::base_type const& const_iterator;
  146. /// The mutating (non-const) refernce type
  147. typedef ss_typename_type_k select_first_type_if<base_value_type const&
  148. , base_value_type &, is_const>::type reference;
  149. /// The non-mutating (const) reference type
  150. typedef base_value_type const& const_reference;
  151. // TODO: Stick in the member-finder stuff here, so can assume ptrdiff_t if none found
  152. /// The difference type
  153. typedef ss_typename_type_k iterator_type::difference_type difference_type;
  154. /// The size type
  155. typedef ss_typename_type_k iterator_type::size_type size_type;
  156. };
  157. # ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  158. template< ss_typename_param_k T
  159. , bool B_CONST
  160. >
  161. struct iterator_range_traits<T*, B_CONST>
  162. {
  163. typedef T value_type;
  164. typedef value_type* iterator;
  165. typedef value_type const* const_iterator;
  166. typedef value_type& reference;
  167. typedef value_type const& const_reference;
  168. };
  169. template< ss_typename_param_k T
  170. , bool B_CONST
  171. >
  172. struct iterator_range_traits<T const*, B_CONST>
  173. {
  174. typedef T value_type;
  175. typedef value_type const* iterator;
  176. typedef value_type const* const_iterator;
  177. typedef value_type const& reference;
  178. typedef value_type const& const_reference;
  179. };
  180. # endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  181. #else /* ? STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  182. template< ss_typename_param_k I
  183. >
  184. struct iterator_range_traits
  185. {
  186. public:
  187. typedef I iterator_type;
  188. typedef ss_typename_type_k iterator_type::value_type value_type;
  189. typedef ss_typename_type_k iterator_type::iterator iterator;
  190. typedef ss_typename_type_k iterator_type::const_iterator const_iterator;
  191. typedef ss_typename_type_k iterator_type::reference reference;
  192. typedef ss_typename_type_k iterator_type::const_reference const_reference;
  193. // TODO: Stick in the member-finder stuff here, so can assume ptrdiff_t if none found
  194. typedef ss_typename_type_k iterator_type::difference_type difference_type;
  195. typedef ss_typename_type_k iterator_type::size_type size_type;
  196. };
  197. template< ss_typename_param_k I
  198. >
  199. struct const_iterator_range_traits
  200. {
  201. public:
  202. typedef I iterator_type;
  203. typedef ss_typename_type_k iterator_type::value_type value_type;
  204. typedef ss_typename_type_k iterator_type::const_iterator iterator;
  205. typedef ss_typename_type_k iterator_type::const_iterator const_iterator;
  206. typedef ss_typename_type_k iterator_type::const_reference reference;
  207. typedef ss_typename_type_k iterator_type::const_reference const_reference;
  208. typedef ss_typename_type_k iterator_type::difference_type difference_type;
  209. typedef ss_typename_type_k iterator_type::size_type size_type;
  210. };
  211. template< ss_typename_param_k T
  212. >
  213. struct pointer_iterator_range_traits
  214. {
  215. typedef T value_type;
  216. typedef T* iterator;
  217. typedef T const* const_iterator;
  218. typedef T& reference;
  219. typedef T const& const_reference;
  220. typedef ptrdiff_t difference_type;
  221. typedef size_t size_type;
  222. };
  223. template< ss_typename_param_k T
  224. >
  225. struct const_pointer_iterator_range_traits
  226. {
  227. typedef T value_type;
  228. typedef T const* iterator;
  229. typedef T const* const_iterator;
  230. typedef T const& reference;
  231. typedef T const& const_reference;
  232. typedef ptrdiff_t difference_type;
  233. typedef size_t size_type;
  234. };
  235. #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  236. /** \brief This class adapts an iterator pair into a Range
  237. *
  238. * \ingroup group__library__rangelib
  239. *
  240. * \param I The iterator type
  241. * \param T The iterator range traits, used to deduce the Range's iterator, const_iterator, reference, const_reference and value_type
  242. *
  243. * It is categoried as an Iterable Range
  244. *
  245. * It could be used as follows
  246. \code
  247. template<typename I>
  248. void dump_elements(I from, I to)
  249. {
  250. for(iterator_range<I> r(from, to); r; ++r)
  251. {
  252. std::cout << &r; // Dump the current value to stdout
  253. }
  254. }
  255. \endcode
  256. */
  257. template< ss_typename_param_k I
  258. #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
  259. , ss_typename_param_k T = iterator_range_traits<I, is_const_type<I>::value> // Determines whether the iterator is const
  260. #else /* ? STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  261. , ss_typename_param_k T
  262. #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  263. >
  264. class iterator_range
  265. : public iterable_range_tag
  266. {
  267. /// \name Member Types
  268. /// @{
  269. public:
  270. /// The iterator type
  271. typedef I iterator_type;
  272. /// The traits type
  273. typedef T traits_type;
  274. /// The range tag type
  275. typedef iterable_range_tag range_tag_type;
  276. /// The current instantiation of this type
  277. typedef iterator_range<I, T> class_type;
  278. /// The value type
  279. typedef ss_typename_type_k traits_type::value_type value_type;
  280. /// The mutating (non-const) iterator type
  281. typedef ss_typename_type_k traits_type::iterator iterator;
  282. /// The non-mutating (const) iterator type
  283. typedef ss_typename_type_k traits_type::const_iterator const_iterator;
  284. /// The mutating (non-const) refernce type
  285. typedef ss_typename_type_k traits_type::reference reference;
  286. /// The non-mutating (const) reference type
  287. typedef ss_typename_type_k traits_type::const_reference const_reference;
  288. /// @}
  289. /// \name Construction
  290. /// @{
  291. public:
  292. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  293. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED) || \
  294. ( defined(STLSOFT_COMPILER_IS_MSVC) && \
  295. _MSC_VER == 1200)
  296. /// Constructs from an iterator pair
  297. iterator_range(iterator first, iterator last)
  298. : m_position(first)
  299. , m_last(last)
  300. {}
  301. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  302. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) && \
  303. ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
  304. _MSC_VER != 1200)
  305. /// Constructs from an iterator pair
  306. template <ss_typename_param_k I2>
  307. iterator_range(I2 first, I2 last)
  308. : m_position(first)
  309. , m_last(last)
  310. {}
  311. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  312. #ifdef STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT
  313. /// Constructs from an array
  314. template <ss_typename_param_k T2, ss_size_t N>
  315. iterator_range(T2 (&ar)[N])
  316. : m_position(&ar[0])
  317. , m_last(&ar[N])
  318. {}
  319. #endif /* STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT */
  320. /// @}
  321. /// \name Notional Range methods
  322. /// @{
  323. private:
  324. STLSOFT_DEFINE_OPERATOR_BOOL_TYPES_T(class_type, boolean_generator_type, boolean_type);
  325. public:
  326. /// Indicates whether the range is open
  327. ss_bool_t is_open() const
  328. {
  329. return m_position != m_last;
  330. }
  331. /// Returns the current value in the range
  332. reference current()
  333. {
  334. STLSOFT_ASSERT(is_open());
  335. return *m_position;
  336. }
  337. /// Returns the current value in the range
  338. const_reference current() const
  339. {
  340. STLSOFT_ASSERT(is_open());
  341. return *m_position;
  342. }
  343. /// Indicates whether the range is open
  344. operator boolean_type() const
  345. {
  346. return boolean_generator_type::translate(is_open());
  347. }
  348. /// Returns the current value in the range
  349. reference operator *()
  350. {
  351. return current();
  352. }
  353. /// Returns the current value in the range
  354. const_reference operator *() const
  355. {
  356. return current();
  357. }
  358. /// Advances the current position in the range
  359. class_type& advance()
  360. {
  361. STLSOFT_MESSAGE_ASSERT("Attempting to increment the range past its end point", is_open());
  362. ++m_position;
  363. return *this;
  364. }
  365. /// Advances the current position in the range
  366. class_type& operator ++()
  367. {
  368. return advance();
  369. }
  370. /// Advances the current position in the range, returning a copy of the
  371. /// range prior to its being advanced
  372. class_type operator ++(int)
  373. {
  374. class_type ret(*this);
  375. operator ++();
  376. return ret;
  377. }
  378. /// @}
  379. /// \name Iterable Range methods
  380. /// @{
  381. public:
  382. /// Returns an iterator to the current position of the range
  383. iterator begin()
  384. {
  385. return m_position;
  386. }
  387. /// Returns an iterator to the end of the range
  388. iterator end()
  389. {
  390. return m_last;
  391. }
  392. /// Returns an iterator to the current position of the range
  393. const_iterator begin() const
  394. {
  395. return m_position;
  396. }
  397. /// Returns an iterator to the end of the range
  398. const_iterator end() const
  399. {
  400. return m_last;
  401. }
  402. /// @}
  403. /// \name Members
  404. /// @{
  405. private:
  406. iterator m_position;
  407. iterator m_last;
  408. /// @}
  409. };
  410. ////////////////////////////////////////////////////////////////////////////
  411. // Functions
  412. #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
  413. template<ss_typename_param_k I>
  414. inline iterator_range<I> make_iterator_range(I &first, I &last)
  415. {
  416. return iterator_range<I>(first, last);
  417. }
  418. #else /* ? STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  419. template<ss_typename_param_k I>
  420. inline iterator_range<I, iterator_range_traits<I> > make_iterator_range(I &first, I &last)
  421. {
  422. return iterator_range<I, iterator_range_traits<I> >(first, last);
  423. }
  424. #if 0
  425. template<ss_typename_param_k T>
  426. inline iterator_range<T*, iterator_range_traits<T> > make_iterator_range(T *first, T* last)
  427. {
  428. return iterator_range<T*, iterator_range_traits<T> >(first, last);
  429. }
  430. #endif /* 0 */
  431. template<ss_typename_param_k T>
  432. inline iterator_range<T const*, const_pointer_iterator_range_traits<const T> > make_iterator_range(T const* first, T const* last)
  433. {
  434. return iterator_range<T const*, const_pointer_iterator_range_traits<const T> >(first, last);
  435. }
  436. #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
  437. ////////////////////////////////////////////////////////////////////////////
  438. // Unit-testing
  439. #ifdef STLSOFT_UNITTEST
  440. # include "./unittest/iterator_range_unittest_.h"
  441. #endif /* STLSOFT_UNITTEST */
  442. /* ////////////////////////////////////////////////////////////////////// */
  443. #ifndef RANGELIB_NO_NAMESPACE
  444. # if defined(_STLSOFT_NO_NAMESPACE) || \
  445. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  446. } // namespace rangelib
  447. # else
  448. } // namespace rangelib_project
  449. } // namespace stlsoft
  450. # endif /* _STLSOFT_NO_NAMESPACE */
  451. #endif /* !RANGELIB_NO_NAMESPACE */
  452. /* ////////////////////////////////////////////////////////////////////// */
  453. #endif /* !RANGELIB_INCL_RANGELIB_HPP_ITERATOR_RANGE */
  454. /* ///////////////////////////// end of file //////////////////////////// */