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.

517 lines
21 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: rangelib/associative_range.hpp
  3. *
  4. * Purpose: Associative container range adaptor.
  5. *
  6. * Created: 1st October 2004
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2004-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/associative_range.hpp Sequence container range adaptor */
  40. #ifndef RANGELIB_INCL_RANGELIB_HPP_ASSOCIATIVE_RANGE
  41. #define RANGELIB_INCL_RANGELIB_HPP_ASSOCIATIVE_RANGE
  42. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  43. # define RANGELIB_VER_RANGELIB_HPP_ASSOCIATIVE_RANGE_MAJOR 1
  44. # define RANGELIB_VER_RANGELIB_HPP_ASSOCIATIVE_RANGE_MINOR 4
  45. # define RANGELIB_VER_RANGELIB_HPP_ASSOCIATIVE_RANGE_REVISION 6
  46. # define RANGELIB_VER_RANGELIB_HPP_ASSOCIATIVE_RANGE_EDIT 33
  47. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  48. /* /////////////////////////////////////////////////////////////////////////
  49. * Auto-generation and compatibility
  50. */
  51. /*
  52. [Incompatibilies-start]
  53. STLSOFT_COMPILER_IS_MSVC: _MSC_VER < 1200
  54. STLSOFT_COMPILER_IS_MWERKS: (__MWERKS__ & 0xFF00) < 0x3000
  55. [Incompatibilies-end]
  56. */
  57. /* /////////////////////////////////////////////////////////////////////////
  58. * Includes
  59. */
  60. #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGELIB
  61. # include <rangelib/rangelib.hpp>
  62. #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGELIB */
  63. #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES
  64. # include <rangelib/range_categories.hpp>
  65. #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGE_CATEGORIES */
  66. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL
  67. # include <stlsoft/util/operator_bool.hpp>
  68. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL */
  69. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_CONST_TYPE
  70. # include <stlsoft/meta/is_const_type.hpp>
  71. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_CONST_TYPE */
  72. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  73. # include <stlsoft/util/std/iterator_helper.hpp>
  74. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  75. #if defined(STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED)
  76. // This stuff's needed for type fixing 'referent_type' => 'mapped_type'
  77. # ifndef STLSOFT_INCL_STLSOFT_META_HPP_MEMBER_TRAITS
  78. # include <stlsoft/meta/member_traits.hpp>
  79. # endif /* !STLSOFT_INCL_STLSOFT_META_HPP_MEMBER_TRAITS */
  80. # ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_ASSOCIATIVE_MAPPED_TYPE_DETECTOR
  81. # include <stlsoft/collections/util/associative_mapped_type_detector.hpp>
  82. # endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_ASSOCIATIVE_MAPPED_TYPE_DETECTOR */
  83. #else /* ? STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  84. # if defined(STLSOFT_CF_STD_LIBRARY_IS_DINKUMWARE_VC)
  85. # if STLSOFT_CF_STD_LIBRARY_DINKUMWARE_VC_VERSION <= STLSOFT_CF_DINKUMWARE_VC_VERSION_6_0
  86. # pragma message("associative_range<> assumes that the adapted type has a 'mapped_type' member type. std::map in the Dinkumware library that ships with Visual C++ 5 & 6 uses the non-standard 'referent_type', so adapting a parameterisation of it will not compile")
  87. # endif /* STLSOFT_CF_STD_LIBRARY_DINKUMWARE_VC_VERSION <= STLSOFT_CF_DINKUMWARE_VC_VERSION_6_0 */
  88. # endif /* STLSOFT_CF_STD_LIBRARY_IS_DINKUMWARE_VC */
  89. #endif /* STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  90. #ifdef STLSOFT_UNITTEST
  91. # include <algorithm>
  92. # include <map>
  93. # include <numeric>
  94. #endif /* STLSOFT_UNITTEST */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Namespace
  97. */
  98. #ifndef RANGELIB_NO_NAMESPACE
  99. # if defined(_STLSOFT_NO_NAMESPACE) || \
  100. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  101. /* There is no stlsoft namespace, so must define ::rangelib */
  102. namespace rangelib
  103. {
  104. # else
  105. /* Define stlsoft::rangelib_project */
  106. namespace stlsoft
  107. {
  108. namespace rangelib_project
  109. {
  110. # endif /* _STLSOFT_NO_NAMESPACE */
  111. #endif /* !RANGELIB_NO_NAMESPACE */
  112. /* /////////////////////////////////////////////////////////////////////////
  113. * Classes
  114. */
  115. #if defined(STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED)
  116. /** \brief Traits class for determining the attributes of range-adapted associative container types
  117. *
  118. * \ingroup group__library__rangelib
  119. */
  120. template< ss_typename_param_k S
  121. , bool B_CONST
  122. >
  123. struct associative_range_traits
  124. {
  125. public:
  126. /// The associative type
  127. typedef S associative_type;
  128. /// The associative reference type
  129. typedef S& associative_reference_type;
  130. /// The key type
  131. typedef ss_typename_type_k associative_type::key_type key_type;
  132. /// The mapped type
  133. typedef ss_typename_type_k associative_mapped_type_detector<S>::mapped_type mapped_type;
  134. /// The value type
  135. typedef ss_typename_type_k associative_type::value_type value_type;
  136. /// The mutating (non-const) iterator type
  137. typedef ss_typename_type_k select_first_type_if< ss_typename_type_k associative_type::const_iterator
  138. , ss_typename_type_k associative_type::iterator
  139. , B_CONST
  140. >::type iterator;
  141. /// The non-mutating (const) iterator type
  142. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  143. /// The mutating (non-const) reference type
  144. typedef ss_typename_type_k select_first_type_if< ss_typename_type_k associative_type::const_reference
  145. , ss_typename_type_k associative_type::reference
  146. , B_CONST
  147. >::type reference;
  148. /// The non-mutating (const) reference type
  149. typedef ss_typename_type_k associative_type::const_reference const_reference;
  150. // TODO: Stick in the member-finder stuff here, so can assume ptrdiff_t if none found
  151. /// The difference type
  152. typedef ss_typename_type_k associative_type::difference_type difference_type;
  153. /// The size type
  154. typedef ss_typename_type_k associative_type::size_type size_type;
  155. };
  156. template< ss_typename_param_k S
  157. >
  158. struct associative_range_traits<S, true>
  159. {
  160. public:
  161. typedef S associative_type;
  162. typedef S& associative_reference_type;
  163. typedef ss_typename_type_k associative_type::key_type key_type;
  164. typedef ss_typename_type_k associative_mapped_type_detector<S>::mapped_type mapped_type;
  165. // typedef ss_typename_type_k associative_type::referent_type mapped_type;
  166. typedef ss_typename_type_k associative_type::value_type value_type;
  167. typedef ss_typename_type_k associative_type::const_iterator iterator;
  168. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  169. typedef ss_typename_type_k associative_type::const_reference reference;
  170. typedef ss_typename_type_k associative_type::const_reference const_reference;
  171. // TODO: Stick in the member-finder stuff here, so can assume ptrdiff_t if none found
  172. typedef ss_typename_type_k associative_type::difference_type difference_type;
  173. typedef ss_typename_type_k associative_type::size_type size_type;
  174. };
  175. #else /* ? STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  176. template< ss_typename_param_k S
  177. >
  178. struct associative_range_traits
  179. {
  180. public:
  181. typedef S associative_type;
  182. typedef S& associative_reference_type;
  183. typedef ss_typename_type_k associative_type::key_type key_type;
  184. typedef ss_typename_type_k associative_type::mapped_type mapped_type;
  185. typedef ss_typename_type_k associative_type::value_type value_type;
  186. typedef ss_typename_type_k associative_type::iterator iterator;
  187. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  188. typedef ss_typename_type_k associative_type::reference reference;
  189. typedef ss_typename_type_k associative_type::const_reference const_reference;
  190. typedef ss_typename_type_k associative_type::difference_type difference_type;
  191. typedef ss_typename_type_k associative_type::size_type size_type;
  192. };
  193. template< ss_typename_param_k S
  194. >
  195. struct associative_range_traits_dinkumware_early
  196. {
  197. public:
  198. typedef S associative_type;
  199. typedef S& associative_reference_type;
  200. typedef ss_typename_type_k associative_type::key_type key_type;
  201. typedef ss_typename_type_k associative_type::referent_type mapped_type;
  202. typedef ss_typename_type_k associative_type::value_type value_type;
  203. typedef ss_typename_type_k associative_type::iterator iterator;
  204. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  205. typedef ss_typename_type_k associative_type::reference reference;
  206. typedef ss_typename_type_k associative_type::const_reference const_reference;
  207. typedef ss_typename_type_k associative_type::difference_type difference_type;
  208. typedef ss_typename_type_k associative_type::size_type size_type;
  209. };
  210. template< ss_typename_param_k S
  211. >
  212. struct const_associative_range_traits
  213. {
  214. public:
  215. typedef S associative_type;
  216. typedef S const& associative_reference_type;
  217. typedef ss_typename_type_k associative_type::key_type key_type;
  218. typedef ss_typename_type_k associative_type::mapped_type mapped_type;
  219. typedef ss_typename_type_k associative_type::value_type value_type;
  220. typedef ss_typename_type_k associative_type::const_iterator iterator;
  221. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  222. typedef ss_typename_type_k associative_type::const_reference reference;
  223. typedef ss_typename_type_k associative_type::const_reference const_reference;
  224. typedef ss_typename_type_k associative_type::difference_type difference_type;
  225. typedef ss_typename_type_k associative_type::size_type size_type;
  226. };
  227. template< ss_typename_param_k S
  228. >
  229. struct const_associative_range_traits_dinkumware_early
  230. {
  231. public:
  232. typedef S associative_type;
  233. typedef S const& associative_reference_type;
  234. typedef ss_typename_type_k associative_type::key_type key_type;
  235. typedef ss_typename_type_k associative_type::referent_type mapped_type;
  236. typedef ss_typename_type_k associative_type::value_type value_type;
  237. typedef ss_typename_type_k associative_type::const_iterator iterator;
  238. typedef ss_typename_type_k associative_type::const_iterator const_iterator;
  239. typedef ss_typename_type_k associative_type::const_reference reference;
  240. typedef ss_typename_type_k associative_type::const_reference const_reference;
  241. typedef ss_typename_type_k associative_type::difference_type difference_type;
  242. typedef ss_typename_type_k associative_type::size_type size_type;
  243. };
  244. #endif /* STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  245. /** \brief This class adapts an STL associative instance into a Range
  246. *
  247. * \ingroup group__library__rangelib
  248. *
  249. * \param S The associative class
  250. * \param T The associative range traits, used to deduce the Range's iterator, const_iterator, reference, const_reference and value_type
  251. *
  252. * It is categoried as an Iterable Range
  253. *
  254. * It could be used as follows:
  255. \code
  256. void dump_elements(std::vector<int> const& numbers)
  257. {
  258. for(associative_range<std::vector<int> > r(numbers); r; ++r)
  259. {
  260. std::cout << &r; // Dump the current value to stdout
  261. }
  262. }
  263. \endcode
  264. */
  265. template< ss_typename_param_k S
  266. #if defined(STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED)
  267. , ss_typename_param_k T = associative_range_traits<S, is_const_type<S>::value> // Determines whether the associative is const
  268. #else /* ? STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  269. , ss_typename_param_k T = const_associative_range_traits<S> // Determines whether the associative is const
  270. #endif /* STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  271. >
  272. class associative_range
  273. : public iterable_range_tag
  274. {
  275. public:
  276. /// The associative type
  277. typedef S associative_type;
  278. /// The traits type
  279. typedef T traits_type;
  280. /// The range category tag type
  281. typedef iterable_range_tag range_tag_type;
  282. /// The current instantiation of the type
  283. typedef associative_range<S, T> class_type;
  284. /// The associative reference type
  285. typedef ss_typename_type_k traits_type::associative_reference_type associative_reference_type;
  286. /// The key type
  287. typedef ss_typename_type_k traits_type::key_type key_type;
  288. /// The referent type
  289. typedef ss_typename_type_k traits_type::mapped_type mapped_type;
  290. /// The value type
  291. typedef ss_typename_type_k traits_type::value_type value_type;
  292. /// The mutating (non-const) iterator type
  293. typedef ss_typename_type_k traits_type::iterator iterator;
  294. /// The non-mutating (const) iterator type
  295. typedef ss_typename_type_k traits_type::const_iterator const_iterator;
  296. /// The mutating (non-const) reference type
  297. typedef ss_typename_type_k traits_type::reference reference;
  298. /// The non-mutating (const) reference type
  299. typedef ss_typename_type_k traits_type::const_reference const_reference;
  300. /// The difference type
  301. typedef ss_typename_type_k traits_type::difference_type difference_type;
  302. /// The size type
  303. typedef ss_typename_type_k traits_type::size_type size_type;
  304. public:
  305. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
  306. defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED) || \
  307. ( defined(STLSOFT_COMPILER_IS_MSVC) && \
  308. _MSC_VER == 1200)
  309. /// Constructor
  310. ///
  311. /// \param seq The associative which will be adapted to a range
  312. associative_range(associative_reference_type seq) // The constness of this will require some thinking about. Maybe need associative_range and const_associative_range??
  313. : m_position(seq.begin())
  314. , m_last(seq.end())
  315. {}
  316. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */
  317. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) && \
  318. ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
  319. _MSC_VER != 1200)
  320. /// Constructor
  321. ///
  322. /// \param seq The associative which will be adapted to a range
  323. template <ss_typename_param_k S2>
  324. associative_range(S2 &seq)
  325. : m_position(seq.begin())
  326. , m_last(seq.end())
  327. {}
  328. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  329. /// Copy constructor
  330. ///
  331. /// \note This has to be provided, to avoid precipitating C4217 with Visual C++
  332. associative_range(class_type const& rhs)
  333. : m_position(rhs.m_position)
  334. , m_last(rhs.m_last)
  335. {}
  336. /// Copy assignment operator
  337. ///
  338. /// \note This has to be provided, to avoid precipitating C4217 with Visual C++
  339. class_type& operator =(class_type const& rhs)
  340. {
  341. m_position = rhs.m_position;
  342. m_last = rhs.m_last;
  343. return *this;
  344. }
  345. /// \name Notional Range methods
  346. /// @{
  347. private:
  348. STLSOFT_DEFINE_OPERATOR_BOOL_TYPES_T(class_type, boolean_generator_type, boolean_type);
  349. public:
  350. /// Indicates whether the range is open
  351. ss_bool_t is_open() const
  352. {
  353. return m_position != m_last;
  354. }
  355. /// Returns the current key+value pair in the range
  356. reference current()
  357. {
  358. STLSOFT_ASSERT(is_open());
  359. return *m_position;
  360. }
  361. /// Returns the current key+value pair in the range
  362. const_reference current() const
  363. {
  364. STLSOFT_ASSERT(is_open());
  365. return *m_position;
  366. }
  367. /// Returns the key of the current item in the range
  368. key_type current_key()
  369. {
  370. return current().first;
  371. }
  372. /// Returns the value of the current item in the range
  373. key_type current_key() const
  374. {
  375. return current().first;
  376. }
  377. /// Returns the value of the current item in the range
  378. mapped_type current_value()
  379. {
  380. return current().second;
  381. }
  382. /// Returns the value of the current item in the range
  383. mapped_type current_value() const
  384. {
  385. return current().second;
  386. }
  387. /// Advances the current position in the range
  388. class_type& advance()
  389. {
  390. STLSOFT_MESSAGE_ASSERT("Attempting to increment the range past its end point", is_open());
  391. ++m_position;
  392. return *this;
  393. }
  394. /// Indicates whether the range is open
  395. operator boolean_type() const
  396. {
  397. return boolean_generator_type::translate(is_open());
  398. }
  399. /// Returns the current key+value pair in the range
  400. reference operator *()
  401. {
  402. return current();
  403. }
  404. /// Returns the current key+value pair in the range
  405. const_reference operator *() const
  406. {
  407. return current();
  408. }
  409. /// Advances the current position in the range
  410. class_type& operator ++()
  411. {
  412. return advance();
  413. }
  414. /// Advances the current position in the range, returning a copy of the
  415. /// range prior to its being advanced
  416. class_type operator ++(int)
  417. {
  418. class_type ret(*this);
  419. operator ++();
  420. return ret;
  421. }
  422. /// @}
  423. /// \name Iterable Range methods
  424. /// @{
  425. public:
  426. /// Returns an iterator to the current position of the range
  427. iterator begin()
  428. {
  429. return m_position;
  430. }
  431. /// Returns an iterator to the end of the range
  432. iterator end()
  433. {
  434. return m_last;
  435. }
  436. /// Returns an iterator to the current position of the range
  437. const_iterator begin() const
  438. {
  439. return m_position;
  440. }
  441. /// Returns an iterator to the end of the range
  442. const_iterator end() const
  443. {
  444. return m_last;
  445. }
  446. /// @}
  447. // Members
  448. private:
  449. iterator m_position;
  450. iterator m_last;
  451. };
  452. ////////////////////////////////////////////////////////////////////////////
  453. // Unit-testing
  454. #ifdef STLSOFT_UNITTEST
  455. # include "./unittest/associative_range_unittest_.h"
  456. #endif /* STLSOFT_UNITTEST */
  457. /* ////////////////////////////////////////////////////////////////////// */
  458. #ifndef RANGELIB_NO_NAMESPACE
  459. # if defined(_STLSOFT_NO_NAMESPACE) || \
  460. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  461. } // namespace rangelib
  462. # else
  463. } // namespace rangelib_project
  464. } // namespace stlsoft
  465. # endif /* _STLSOFT_NO_NAMESPACE */
  466. #endif /* !RANGELIB_NO_NAMESPACE */
  467. /* ////////////////////////////////////////////////////////////////////// */
  468. #endif /* !RANGELIB_INCL_RANGELIB_HPP_ASSOCIATIVE_RANGE */
  469. /* ///////////////////////////// end of file //////////////////////////// */