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.

356 lines
12 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: rangelib/operator_adaptors.hpp
  3. *
  4. * Purpose: Definition of the mutating_operator_adaptor and
  5. * non_mutating_operator_adaptor classes.
  6. *
  7. * Created: 4th November 2003
  8. * Updated: 10th August 2009
  9. *
  10. * Home: http://stlsoft.org/
  11. *
  12. * Copyright (c) 2003-2009, Matthew Wilson and Synesis Software
  13. * All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice, this
  19. * list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright notice,
  21. * this list of conditions and the following disclaimer in the documentation
  22. * and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  24. * any contributors may be used to endorse or promote products derived from
  25. * this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. /** \file rangelib/operator_adaptors.hpp
  41. *
  42. * \brief [C++ only] Definition of the rangelib::mutating_operator_adaptor
  43. * and rangelib::non_mutating_operator_adaptor classes, which are used to
  44. * bolt in Range operators to classes that implement the range methods
  45. * (\ref group__library__smart_pointers "Smart Pointers" Library).
  46. */
  47. #ifndef RANGELIB_INCL_RANGELIB_HPP_OPERATOR_ADAPTORS
  48. #define RANGELIB_INCL_RANGELIB_HPP_OPERATOR_ADAPTORS
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define RANGELIB_VER_RANGELIB_HPP_OPERATOR_ADAPTORS_MAJOR 1
  51. # define RANGELIB_VER_RANGELIB_HPP_OPERATOR_ADAPTORS_MINOR 5
  52. # define RANGELIB_VER_RANGELIB_HPP_OPERATOR_ADAPTORS_REVISION 4
  53. # define RANGELIB_VER_RANGELIB_HPP_OPERATOR_ADAPTORS_EDIT 30
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Compatibility
  57. */
  58. /*
  59. [Incompatibilies-start]
  60. STLSOFT_COMPILER_IS_MSVC: _MSC_VER < 1200
  61. STLSOFT_COMPILER_IS_MWERKS: (__MWERKS__ & 0xFF00) < 0x3000
  62. [Incompatibilies-end]
  63. */
  64. /* /////////////////////////////////////////////////////////////////////////
  65. * Includes
  66. */
  67. #ifndef RANGELIB_INCL_RANGELIB_HPP_RANGELIB
  68. # include <rangelib/rangelib.hpp>
  69. #endif /* !RANGELIB_INCL_RANGELIB_HPP_RANGELIB */
  70. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES
  71. # include <stlsoft/meta/capabilities.hpp>
  72. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES */
  73. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_SELECT_FIRST_TYPE_IF
  74. # include <stlsoft/meta/select_first_type_if.hpp>
  75. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_SELECT_FIRST_TYPE_IF */
  76. #if defined(STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED)
  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. #endif /* STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  81. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL
  82. # include <stlsoft/util/operator_bool.hpp>
  83. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_OPERATOR_BOOL */
  84. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_INERT
  85. # include <stlsoft/util/inert.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_INERT */
  87. /* /////////////////////////////////////////////////////////////////////////
  88. * Namespace
  89. */
  90. #ifndef RANGELIB_NO_NAMESPACE
  91. # if defined(_STLSOFT_NO_NAMESPACE) || \
  92. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  93. /* There is no stlsoft namespace, so must define ::rangelib */
  94. namespace rangelib
  95. {
  96. # else
  97. /* Define stlsoft::rangelib_project */
  98. namespace stlsoft
  99. {
  100. namespace rangelib_project
  101. {
  102. # endif /* _STLSOFT_NO_NAMESPACE */
  103. #endif /* !RANGELIB_NO_NAMESPACE */
  104. /* /////////////////////////////////////////////////////////////////////////
  105. * Classes
  106. */
  107. /** \brief This class facilitates specific definition of the \c const_iterator and
  108. * \c iterator member types
  109. *
  110. * \ingroup group__library__rangelib
  111. */
  112. template< ss_typename_param_k CR
  113. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  114. _MSC_VER < 1300
  115. , ss_typename_param_k R = inert
  116. #else /* ? compiler */
  117. , ss_typename_param_k R = void
  118. #endif /* compiler */
  119. >
  120. struct operator_adaptor_specific_traits
  121. {
  122. public:
  123. /// The non-mutating (const) reference type
  124. typedef CR const_reference;
  125. /// The mutating (non-const) reference type
  126. typedef R reference;
  127. };
  128. /** \brief This class is a reverse bolt-in, which provides mutating and
  129. * non-mutating Range operators based on the method forms of its
  130. * parameterising (and deriving) class
  131. *
  132. * \ingroup group__library__rangelib
  133. *
  134. * \note Because this is a reverse bolt-in, \c R is an incomplete type at the
  135. * time of the template parsing. Hence, we cannot deduce \c reference and
  136. * \c const_reference from \c R. This is why the traits type is required in
  137. * the form of the \c T parameter.
  138. */
  139. template< ss_typename_param_k R
  140. , ss_typename_param_k T
  141. >
  142. class mutating_operator_adaptor
  143. {
  144. public:
  145. /// The range type
  146. typedef R adapted_range_type;
  147. /// The traits type
  148. typedef T traits_type;
  149. /// The type of this instantiation
  150. typedef mutating_operator_adaptor<R, T> class_type;
  151. /// The mutating (non-const) reference type
  152. typedef ss_typename_type_k traits_type::reference reference;
  153. /// The non-mutating (const) reference type
  154. typedef ss_typename_type_k traits_type::const_reference const_reference;
  155. protected:
  156. /// \brief Default constructor
  157. ///
  158. /// This is defined protected to ensure that the adaptor may only be used
  159. /// as a base class, and not instantiated directly
  160. mutating_operator_adaptor()
  161. {}
  162. /// \name Range operators
  163. /// @{
  164. private:
  165. STLSOFT_DEFINE_OPERATOR_BOOL_TYPES_T(class_type, boolean_generator_type, boolean_type);
  166. public:
  167. /// Indicates whether the range is open
  168. operator boolean_type() const
  169. {
  170. return boolean_generator_type::translate(static_cast<adapted_range_type const*>(this)->is_open());
  171. }
  172. /// Returns the current value in the range
  173. reference operator *()
  174. {
  175. return static_cast<adapted_range_type*>(this)->current();
  176. }
  177. /// Returns the current value in the range
  178. const_reference operator *() const
  179. {
  180. return static_cast<adapted_range_type const*>(this)->current();
  181. }
  182. /// Advances the current position in the range
  183. adapted_range_type& operator ++()
  184. {
  185. return static_cast<adapted_range_type*>(this)->advance();
  186. }
  187. /// Advances the current position in the range, returning a copy of the
  188. /// range prior to its being advanced
  189. adapted_range_type operator ++(int)
  190. {
  191. adapted_range_type ret(*static_cast<adapted_range_type const*>(this));
  192. operator ++();
  193. return ret;
  194. }
  195. /// @}
  196. };
  197. /** \brief This class is a reverse bolt-in, which provides non-mutating Range
  198. * operators based on the method forms of its parameterising (and deriving)
  199. * class
  200. *
  201. * \ingroup group__library__rangelib
  202. *
  203. * \note Because this is a reverse bolt-in, \c R is an incomplete type at the
  204. * time of the template parsing. Hence, we cannot deduce \c reference and
  205. * \c const_reference from \c R. This is why the traits type is required in
  206. * the form of the \c T parameter.
  207. */
  208. template< ss_typename_param_k R
  209. , ss_typename_param_k T
  210. >
  211. class non_mutating_operator_adaptor
  212. {
  213. public:
  214. /// The range type
  215. typedef R adapted_range_type;
  216. /// The traits type
  217. typedef T traits_type;
  218. /// The type of this instantiation
  219. typedef non_mutating_operator_adaptor<R, T> class_type;
  220. /// The non-mutating (const) reference type
  221. typedef ss_typename_type_k traits_type::const_reference const_reference;
  222. protected:
  223. /// \brief Default constructor
  224. ///
  225. /// This is defined protected to ensure that the adaptor may only be used
  226. /// as a base class, and not instantiated directly
  227. non_mutating_operator_adaptor()
  228. {}
  229. /// \name Range operators
  230. /// @{
  231. private:
  232. STLSOFT_DEFINE_OPERATOR_BOOL_TYPES_T(class_type, boolean_generator_type, boolean_type);
  233. public:
  234. /// Indicates whether the range is open
  235. operator boolean_type() const
  236. {
  237. return boolean_generator_type::translate(static_cast<adapted_range_type const*>(this)->is_open());
  238. }
  239. /// Returns the current value in the range
  240. const_reference operator *() const
  241. {
  242. return static_cast<adapted_range_type const*>(this)->current();
  243. }
  244. /// Advances the current position in the range
  245. adapted_range_type& operator ++()
  246. {
  247. return static_cast<adapted_range_type*>(this)->advance();
  248. }
  249. /// Advances the current position in the range, returning a copy of the
  250. /// range prior to its being advanced
  251. adapted_range_type operator ++(int)
  252. {
  253. adapted_range_type ret(*static_cast<adapted_range_type const*>(this));
  254. operator ++();
  255. return ret;
  256. }
  257. /// @}
  258. };
  259. #if defined(STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED)
  260. template< ss_typename_param_k R
  261. , ss_typename_param_k T
  262. , ss_bool_t
  263. >
  264. struct fixer_mutating_operator_adaptor
  265. {
  266. typedef mutating_operator_adaptor<R, T> type;
  267. };
  268. # ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  269. // When not present it uses void as a placeholder
  270. template< ss_typename_param_k R
  271. , ss_typename_param_k T
  272. >
  273. struct fixer_mutating_operator_adaptor<R, T, false>
  274. {
  275. typedef void type;
  276. };
  277. # endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  278. /** \brief This type is used to select the mutating or non-mutating form of the
  279. * operator adaptor
  280. *
  281. * \ingroup group__library__rangelib
  282. */
  283. template< ss_typename_param_k R
  284. , ss_typename_param_k T
  285. >
  286. struct operator_adaptor_selector
  287. {
  288. private:
  289. enum { HAS_MEMBER_ITERATOR = 0 != member_traits<R>::has_member_iterator };
  290. public:
  291. /// The mutating (non-const) operator adaptor type
  292. typedef ss_typename_type_k select_first_type_if<ss_typename_type_k fixer_mutating_operator_adaptor<R, T, HAS_MEMBER_ITERATOR>::type
  293. , non_mutating_operator_adaptor<R, T>
  294. , HAS_MEMBER_ITERATOR
  295. >::type type;
  296. };
  297. #endif /* STLSOFT_CF_HAS_MEMBER_TYPE_SUPPORTED */
  298. ////////////////////////////////////////////////////////////////////////////
  299. // Unit-testing
  300. #ifdef STLSOFT_UNITTEST
  301. # include "./unittest/operator_adaptors_unittest_.h"
  302. #endif /* STLSOFT_UNITTEST */
  303. /* ////////////////////////////////////////////////////////////////////// */
  304. #ifndef RANGELIB_NO_NAMESPACE
  305. # if defined(_STLSOFT_NO_NAMESPACE) || \
  306. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  307. } // namespace rangelib
  308. # else
  309. } // namespace rangelib_project
  310. } // namespace stlsoft
  311. # endif /* _STLSOFT_NO_NAMESPACE */
  312. #endif /* !RANGELIB_NO_NAMESPACE */
  313. /* ////////////////////////////////////////////////////////////////////// */
  314. #endif /* !RANGELIB_INCL_RANGELIB_HPP_OPERATOR_ADAPTORS */
  315. /* ///////////////////////////// end of file //////////////////////////// */