filter_iterator.hpp

Go to the documentation of this file.
00001 /* /////////////////////////////////////////////////////////////////////////
00002  * File:        stlsoft/iterators/filter_iterator.hpp
00003  *
00004  * Purpose:     An iterator adaptor that uses a predicate to filter desired
00005  *              values from the iterator's underlying sequence.
00006  *
00007  * Created:     9th July 2004
00008  * Updated:     10th January 2007
00009  *
00010  * Home:        http://stlsoft.org/
00011  *
00012  * Copyright (c) 2004-2007, Matthew Wilson and Synesis Software
00013  * All rights reserved.
00014  *
00015  * Redistribution and use in source and binary forms, with or without
00016  * modification, are permitted provided that the following conditions are met:
00017  *
00018  * - Redistributions of source code must retain the above copyright notice, this
00019  *   list of conditions and the following disclaimer.
00020  * - Redistributions in binary form must reproduce the above copyright notice,
00021  *   this list of conditions and the following disclaimer in the documentation
00022  *   and/or other materials provided with the distribution.
00023  * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
00024  *   any contributors may be used to endorse or promote products derived from
00025  *   this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037  * POSSIBILITY OF SUCH DAMAGE.
00038  *
00039  * ////////////////////////////////////////////////////////////////////// */
00040 
00041 
00049 #ifndef STLSOFT_INCL_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR
00050 #define STLSOFT_INCL_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR
00051 
00052 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00053 # define STLSOFT_VER_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR_MAJOR    4
00054 # define STLSOFT_VER_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR_MINOR    2
00055 # define STLSOFT_VER_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR_REVISION 3
00056 # define STLSOFT_VER_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR_EDIT     33
00057 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
00058 
00059 /* /////////////////////////////////////////////////////////////////////////
00060  * Compatibility
00061  */
00062 
00063 /*
00064 [Incompatibilies-start]
00065 STLSOFT_COMPILER_IS_BORLAND:
00066 STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1310
00067 STLSOFT_COMPILER_IS_WATCOM:
00068 [Incompatibilies-end]
00069  */
00070 
00071 /* /////////////////////////////////////////////////////////////////////////
00072  * Includes
00073  */
00074 
00075 #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
00076 # include <stlsoft/stlsoft.h>
00077 #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
00078 
00079 #if !defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT)
00080 # error filter_iterator cannot be used with compilers that do not support partial template specialisation
00081 #else /* ? STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
00082 # ifndef STLSOFT_INCL_STLSOFT_ITERATOR_HPP_ADAPTED_ITERATOR_TRAITS
00083 #  include <stlsoft/iterators/adapted_iterator_traits.hpp>
00084 # endif /* !STLSOFT_INCL_STLSOFT_ITERATOR_HPP_ADAPTED_ITERATOR_TRAITS */
00085 #endif /* !STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
00086 #ifndef STLSOFT_INCL_STLSOFT_HPP_META_YESNO
00087 # include <stlsoft/meta/yesno.hpp>
00088 #endif /* !STLSOFT_INCL_STLSOFT_HPP_META_YESNO */
00089 #ifndef STLSOFT_INCL_STLSOFT_HPP_META_IS_POINTER_TYPE
00090 # include <stlsoft/meta/is_pointer_type.hpp>
00091 #endif /* !STLSOFT_INCL_STLSOFT_HPP_META_IS_POINTER_TYPE */
00092 #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_CATEGORY_LIMITERS
00093 #include <stlsoft/util/std/iterator_category_limiters.hpp>
00094 #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_CATEGORY_LIMITERS */
00095 
00096 /* /////////////////////////////////////////////////////////////////////////
00097  * Feature discrimination
00098  */
00099 
00100 #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
00101 # define STLSOFT_FILTER_ITERATOR_MUTABLE_OP_SUPPORT
00102 #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
00103 
00104 #if defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT)
00105 # if !defined(STLSOFT_COMPILER_IS_GCC) || \
00106      __GNUC__ > 4 || \
00107      (   __GNUC__ == 3 && \
00108          __GNUC_MINOR__ >= 4)
00109 #   define STLSOFT_FILTER_ITERATOR_MEM_SEL_OP_SUPPORT
00110 # endif /* compiler */
00111 #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT */
00112 
00113 /* /////////////////////////////////////////////////////////////////////////
00114  * Namespace
00115  */
00116 
00117 #ifndef _STLSOFT_NO_NAMESPACE
00118 namespace stlsoft
00119 {
00120 #endif /* _STLSOFT_NO_NAMESPACE */
00121 
00122 /* /////////////////////////////////////////////////////////////////////////
00123  * Classes
00124  */
00125 
00131 template<   ss_typename_param_k I
00132         ,   ss_typename_param_k P
00133         ,   ss_typename_param_k T = adapted_iterator_traits<I>
00134         >
00135 // [[synesis:class:iterator: filter_iterator<T<I>, T<P>, T<T>>]]
00136 class filter_iterator
00137 {
00140 public:
00141     typedef I                                                               base_iterator_type;
00142     typedef P                                                               filter_predicate_type;
00143     typedef T                                                               traits_type;
00144     typedef filter_iterator<I, P, T>                                        class_type;
00145 #if 0
00146     typedef ss_typename_type_k traits_type::iterator_category               iterator_category;
00147 #else /* ? 0 */
00148     typedef ss_typename_type_k min_iterator_category<   ss_typename_type_k traits_type::iterator_category
00149                                                     ,   std::bidirectional_iterator_tag
00150                                                     >::iterator_category    iterator_category;
00151 #endif /* 0 */
00152     typedef ss_typename_type_k traits_type::value_type                      value_type;
00153     typedef ss_typename_type_k traits_type::difference_type                 difference_type;
00154     typedef ss_typename_type_k traits_type::pointer                         pointer;
00155     typedef ss_typename_type_k traits_type::const_pointer                   const_pointer;
00156     typedef ss_typename_type_k traits_type::reference                       reference;
00157     typedef ss_typename_type_k traits_type::const_reference                 const_reference;
00158     typedef ss_typename_type_k traits_type::effective_reference             effective_reference;
00159     typedef ss_typename_type_k traits_type::effective_const_reference       effective_const_reference;
00160     typedef ss_typename_type_k traits_type::effective_pointer               effective_pointer;
00161     typedef ss_typename_type_k traits_type::effective_const_pointer         effective_const_pointer;
00163 
00166 public:
00167     filter_iterator(base_iterator_type begin, base_iterator_type end, filter_predicate_type pr)
00168         : m_it(begin)
00169         , m_begin(begin)
00170         , m_end(end)
00171         , m_predicate(pr)
00172     {
00173         for(; m_it != m_end; ++m_it)
00174         {
00175             if(m_predicate(*m_it))
00176             {
00177                 break;
00178             }
00179         }
00180     }
00181 
00183     base_iterator_type  base() const
00184     {
00185         return m_it;
00186     }
00188 
00191 public:
00192     class_type &operator ++()
00193     {
00194         STLSOFT_MESSAGE_ASSERT("Attempting to increment an end-point iterator", m_it != m_end);
00195 
00196         for(++m_it; m_it != m_end; ++m_it)
00197         {
00198             if(m_predicate(*m_it))
00199             {
00200                 break;
00201             }
00202         }
00203 
00204         return *this;
00205     }
00206     class_type operator ++(int)
00207     {
00208         class_type  ret(*this);
00209 
00210         operator ++();
00211 
00212         return ret;
00213     }
00214 
00215     effective_reference operator *()
00216     {
00217         return *m_it;
00218     }
00219     effective_const_reference operator *() const
00220     {
00221         return *m_it;
00222     }
00223 
00224 #ifdef STLSOFT_FILTER_ITERATOR_MEM_SEL_OP_SUPPORT
00225 # ifdef STLSOFT_FILTER_ITERATOR_MUTABLE_OP_SUPPORT
00226     effective_pointer operator ->()
00227     {
00228         enum { is_iterator_pointer_type = is_pointer_type<base_iterator_type>::value };
00229 
00230         // This has to be a separate typedef, otherwise DMC++ has a fit
00231         typedef ss_typename_type_k value_to_yesno_type<is_iterator_pointer_type>::type  yesno_t;
00232 
00233         return invoke_member_selection_operator_(yesno_t());
00234     }
00235 # endif /* STLSOFT_FILTER_ITERATOR_MUTABLE_OP_SUPPORT */
00236 
00237     effective_const_pointer operator ->() const
00238     {
00239         enum { is_iterator_pointer_type = is_pointer_type<base_iterator_type>::value };
00240 
00241         // This has to be a separate typedef, otherwise DMC++ has a fit
00242         typedef ss_typename_type_k value_to_yesno_type<is_iterator_pointer_type>::type  yesno_t;
00243 
00244         return invoke_member_selection_operator_(yesno_t());
00245     }
00246 #endif /* STLSOFT_FILTER_ITERATOR_MUTABLE_OP_SUPPORT */
00248 
00251 public:
00252     class_type &operator --()
00253     {
00254         STLSOFT_MESSAGE_ASSERT("Attempting to increment a start-of-range iterator", m_it != m_begin);
00255 
00256         for(--m_it; m_it != m_begin; --m_it)
00257         {
00258             if(m_predicate(*m_it))
00259             {
00260                 break;
00261             }
00262         }
00263 
00264         return *this;
00265     }
00266     class_type operator --(int)
00267     {
00268         class_type  ret(*this);
00269 
00270         operator --();
00271 
00272         return ret;
00273     }
00275 
00278 public:
00279     ss_bool_t equal(class_type const &rhs) const
00280     {
00281         STLSOFT_MESSAGE_ASSERT("Comparing iterators from different sequences", m_end == rhs.m_end);
00282 
00283         return m_it == rhs.m_it;
00284     }
00286     ss_bool_t equals(class_type const &rhs) const
00287     {
00288         return equal(rhs);
00289     }
00291 
00294 public:
00295     difference_type distance() const
00296     {
00297         return m_end - m_it;
00298     }
00300 
00303 private:
00304 #ifdef STLSOFT_FILTER_ITERATOR_MEM_SEL_OP_SUPPORT
00305     effective_pointer invoke_member_selection_operator_(yes_type)
00306     {
00307         return m_it;
00308     }
00309     effective_pointer invoke_member_selection_operator_(no_type)
00310     {
00311         return m_it.operator ->();
00312     }
00313 
00314     effective_const_pointer invoke_member_selection_operator_(yes_type) const
00315     {
00316         return m_it;
00317     }
00318     effective_const_pointer invoke_member_selection_operator_(no_type) const
00319     {
00320         return m_it.operator ->();
00321     }
00322 #endif /* STLSOFT_FILTER_ITERATOR_MEM_SEL_OP_SUPPORT */
00324 
00327 private:
00328     base_iterator_type      m_it;
00329     base_iterator_type      m_begin;
00330     base_iterator_type      m_end;
00331     filter_predicate_type   m_predicate;
00333 };
00334 
00335 /* /////////////////////////////////////////////////////////////////////////
00336  * Creator function
00337  */
00338 
00349 template<   ss_typename_param_k I
00350         ,   ss_typename_param_k P
00351         >
00352 inline filter_iterator<I, P> make_filter_iterator(I from, I to, P pr)
00353 {
00354     return filter_iterator<I, P>(from, to, pr);
00355 }
00356 
00369 template<   ss_typename_param_k I
00370         ,   ss_typename_param_k P
00371         >
00372 inline filter_iterator<I, P> filter(I from, I to, P pr)
00373 {
00374     return make_filter_iterator(from, to, pr);
00375 }
00376 
00377 /* /////////////////////////////////////////////////////////////////////////
00378  * Operators
00379  */
00380 
00381 // operator ==
00382 
00383 template<   ss_typename_param_k I
00384         ,   ss_typename_param_k P
00385         ,   ss_typename_param_k T
00386         >
00387 inline ss_bool_t operator ==(filter_iterator<I, P, T> const &lhs, filter_iterator<I, P, T> const &rhs)
00388 {
00389     return lhs.equal(rhs);
00390 }
00391 
00392 // operator !=
00393 
00394 template<   ss_typename_param_k I
00395         ,   ss_typename_param_k P
00396         ,   ss_typename_param_k T
00397         >
00398 inline ss_bool_t operator !=(filter_iterator<I, P, T> const &lhs, filter_iterator<I, P, T> const &rhs)
00399 {
00400     return !lhs.equal(rhs);
00401 }
00402 
00404 // Unit-testing
00405 
00406 #ifdef STLSOFT_UNITTEST
00407 # include "./unittest/filter_iterator_unittest_.h"
00408 #endif /* STLSOFT_UNITTEST */
00409 
00410 /* ////////////////////////////////////////////////////////////////////// */
00411 
00412 #ifndef _STLSOFT_NO_NAMESPACE
00413 } // namespace stlsoft
00414 #endif /* _STLSOFT_NO_NAMESPACE */
00415 
00416 /* ////////////////////////////////////////////////////////////////////// */
00417 
00418 #endif /* !STLSOFT_INCL_STLSOFT_ITERATORS_HPP_FILTER_ITERATOR */
00419 
00420 /* ////////////////////////////////////////////////////////////////////// */

STLSoft Libraries documentation © Synesis Software Pty Ltd, 2001-2007