source: trunk/yat/utility/MergeIterator.h @ 3387

Last change on this file since 3387 was 3387, checked in by Peter, 8 years ago

refs #803. MergeIterator?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.1 KB
Line 
1#ifndef theplu_yat_utility_merge_iterator
2#define theplu_yat_utility_merge_iterator
3
4// $Id: MergeIterator.h 3387 2015-03-16 01:47:55Z peter $
5
6/*
7  Copyright (C) 2013 Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "stl_utility.h"
26#include "yat/utility/yat_assert.h"
27
28#include <boost/iterator/iterator_facade.hpp>
29#include <boost/iterator/iterator_traits.hpp>
30
31#include <iterator>
32#include <set>
33#include <vector>
34
35namespace theplu {
36namespace yat {
37namespace utility {
38
39  /**
40     \brief Iterate over several ranges as if ranges have been merged
41
42     MergeIterator is an \input_iterator that is created from several
43     ranges and will iterate over the elements in the ranges as if
44     ranges have been merged. Input ranges have to be sorted (as defined by
45     the \c Compare object) or behaviour is undefined. When
46     incremented, the iterator looks at next element in each range,
47     identifies the smallest element, and points at that.
48
49     \since New in yat 0.11
50   */
51  template<
52    typename Base,
53    class Compare=std::less<typename std::iterator_traits<Base>::value_type>
54    >
55  class MergeIterator
56    : public boost::iterator_facade<
57    MergeIterator<Base, Compare>,
58    typename boost::iterator_value<Base>::type,
59    boost::single_pass_traversal_tag,
60    typename boost::iterator_reference<Base>::type
61    >
62  {
63  public:
64    /**
65       Creates an end-of-range iterator
66     */
67    MergeIterator(void) {};
68
69    /**
70       \brief Create MergeIterator
71
72       Create a MergeIterator that will iterate over ranges
73       [vec[0].first, vec[0].second), [vec[1].first, vec[1].second), ...
74
75       \see make_merge_iterator(const std::vector<std::pair<Base, Base> >&)
76     */
77    MergeIterator(const std::vector<std::pair<Base, Base> >& vec)
78    { init(vec); };
79
80    /**
81       \brief Creates MergeIterator using \a comp as compare object.
82
83       Same as MergeIterator(2) but using \a comp rather than using a
84       default constructed Compare object.
85
86       \see
87       make_merge_iterator(const std::vector<std::pair<Base, Base> >&, const Compare&)
88     */
89    MergeIterator(const std::vector<std::pair<Base, Base> >& vec,
90                  const Compare& comp)
91    : data_(PairCompare(comp))
92    { init(vec); }
93
94  private:
95    friend class boost::iterator_core_access;
96
97    typename MergeIterator<Base, Compare>::reference dereference(void) const;
98    bool equal(const MergeIterator& other) const;
99    void init(const std::vector<std::pair<Base,Base> >& v);
100    void increment(void);
101
102    class PairCompare
103    {
104    public:
105      PairCompare(void) {}
106      PairCompare(const Compare& c) : comp_(c) {}
107      bool operator()(const std::pair<Base, Base>& x,
108                      const std::pair<Base, Base>& y) const
109      { return comp_(*x.first, *y.first); }
110    private:
111      Compare comp_;
112    };
113
114    std::multiset<std::pair<Base, Base>, PairCompare> data_;
115  };
116
117  /**
118     Creates a MergeIterator that iterates over ranges defined in \a vec.
119
120     \relates MergeIterator
121   */
122  template<typename Base>
123  MergeIterator<Base>
124  make_merge_iterator(const std::vector<std::pair<Base, Base> >& vec)
125  {
126    return MergeIterator<Base>(vec);
127  }
128
129
130  /**
131     Creates a MergeIterator that iterates over ranges defined in \a
132     vec, using \a comp to compare elements.
133
134     \relates MergeIterator
135  */
136  template<typename Base, class Compare>
137  MergeIterator<Base, Compare>
138  make_merge_iterator(const std::vector<std::pair<Base, Base> >& vec,
139                      const Compare& comp)
140  {
141    return MergeIterator<Base, Compare>(vec, comp);
142  }
143
144
145
146  // template implementations
147
148  template<typename Base, class Compare>
149  typename MergeIterator<Base, Compare>::reference
150  MergeIterator<Base, Compare>::dereference(void) const
151  {
152    YAT_ASSERT(data_.size());
153    YAT_ASSERT(data_.begin()->first != data_.begin()->second);
154    return *data_.begin()->first;
155  }
156
157
158  template<typename Base, class Compare>
159  bool MergeIterator<Base, Compare>::equal(const MergeIterator& other) const
160  {
161    if (data_.empty() || other.data_.empty())
162      return data_.empty() == other.data_.empty();
163    return data_.begin()->first == other.data_.begin()->first;
164  }
165
166
167  template<typename Base, class Compare>
168  void
169  MergeIterator<Base,Compare>::init(const std::vector<std::pair<Base,Base> >& v)
170  {
171    for (size_t i=0; i<v.size(); ++i)
172      if (v[i].first != v[i].second)
173        data_.insert(v[i]);
174  }
175
176
177  template<typename Base, class Compare>
178  void MergeIterator<Base, Compare>::increment(void)
179  {
180    if (data_.empty())
181      return;
182    // store first range
183    std::pair<Base, Base> tmp = *data_.begin();
184    // remove first range from set of ranges
185    data_.erase(data_.begin());
186    // iterate the first range and if not end-of-range, insert the
187    // range back into set of ranges
188    if (++(tmp.first) != tmp.second)
189      data_.insert(tmp);
190  }
191
192}}}
193#endif
Note: See TracBrowser for help on using the repository browser.