vbl_batch_compact_multimap.h
Go to the documentation of this file.
1 // This is core/vbl/vbl_batch_compact_multimap.h
2 #ifndef vbl_batch_compact_multimap_h_
3 #define vbl_batch_compact_multimap_h_
4 //:
5 // \file
6 // \brief Like a smaller and slightly faster vcl_batch_multimap but without the pair<key, value> sequence
7 // \author Ian Scott, Imorphics 2011
8 
9 #include <vector>
10 #include <cstddef>
11 #include <functional>
12 #include <utility>
13 #include <algorithm>
14 #include <iterator>
15 #include <cassert>
16 #ifdef _MSC_VER
17 # include <vcl_msvc_warnings.h>
18 #endif
19 
20 
21 //: A fast read and batch-write map-style collection.
22 // This container stores its keys separately from its values, and has fast construction and deletion.
23 // It has all the const-access map fundtions, but its contents can only be modified all-at-once.
24 // You can not get a key,value pair, but you can get access to all the compactly-stored values for
25 // a given key.
26 template <typename K, typename T, typename C=std::less<K> >
28 {
29  public:
30  typedef K key_type;
31  typedef T value_type;
32  //: The type of data in the inputted sequence.
33  typedef typename std::pair<key_type, value_type> input_type;
34  typedef C key_compare;
35  typedef unsigned index_type;
36  typedef typename std::vector<key_type> key_container_type;
37  typedef typename std::vector<index_type> index_container_type;
38  typedef typename std::vector<value_type> value_container_type;
39 
40  typedef typename key_container_type::const_iterator const_key_iterator;
41  typedef typename value_container_type::const_iterator const_value_iterator;
42 
43  protected:
44  //: The type of container used internally to process inputted data.
45  typedef typename std::vector<input_type> input_container_type;
46 
47  public:
48  //: A comparator to sort input data, by ignoring the value in pair<key, value>
50  {
51  public:
53 
55 
57 
58  bool operator()(const input_type& x, const input_type& y) const
59  { return comp(x.first, y.first); }
60  };
61 
62  vbl_batch_compact_multimap() = default;
63 
64  template <typename CI>
65  vbl_batch_compact_multimap(CI start, CI finish)
66  {
67  input_container_type in(start, finish);
68  std::sort(in.begin(), in.end(), input_compare(key_compare()));
69  assign_sorted(in.begin(), in.end());
70  }
71 
72  //: Change all the values in the multimap.
73  template <typename CI>
74  void assign(CI start, CI finish)
75  {
76  input_container_type in(start, finish);
77  std::sort(in.begin(), in.end(), input_compare(key_compare()));
78  assign_sorted(in.begin(), in.end());
79  }
80 
81  //: Change all the values in the multimap, to a ready sorted sequence
82  // The input values must already be sorted on their v.first members.
83  template <typename CI>
84  void assign_sorted(CI start, CI finish)
85  {
86  keys_.clear();
87  indices_.clear();
88  values_.clear();
89  assert(is_sorted(start, finish, input_compare(key_compare())));
90  while (start != finish)
91  {
92  typename std::iterator_traits<CI>::value_type::first_type const & last_start_val = start->first;
93  keys_.push_back(start->first);
94  indices_.push_back(values_.size());
95  values_.push_back(start->second);
96  while(++start != finish && start->first == last_start_val)
97  {
98  values_.push_back(start->second);
99  }
100  }
101  indices_.push_back(values_.size()); // always one more index than key.
102  }
103 
105  {
106  keys_.swap(x.keys_);
107  indices_.swap(x.indices_);
108  values_.swap(x.values_);
109  }
110 
112  {
113  return keys_ == rhs.keys_ &&
114  indices_ == rhs.indices_ &&
115  values_ == rhs.values_;
116  }
117 
118  // const vector API
119 
120  const_key_iterator keys_begin() const { return keys_.begin(); }
121  const_key_iterator keys_end() const { return keys_.end(); }
122  const_value_iterator values_begin() const { return values_.begin(); }
123  const_value_iterator values_end() const { return values_.end(); }
124  bool empty() const { return values_.empty(); }
125  std::size_t size() const { return values_.size(); }
126 
127  // const map API
128 
129  //: Finds the beginning of a subsequence of values whose key matches given \p x.
130  // \return iterator to the first value whose key matches \p x, or the
131  // next greatest element if no match is found.
133  {
134  const_key_iterator k_it = std::lower_bound(keys_.begin(), keys_.end(),
135  x, key_compare() );
136 
137  return values_.begin() + indices_[k_it - keys_.begin()];
138  }
139 
140  //: Finds the one past the end of a subsequence of values whose key matches given \p x.
141  // \return iterator to one past the last value whose key that matches \p key, or to the
142  // next greatest element if no match is found.
144  {
145  const_key_iterator k_it = std::upper_bound(keys_.begin(), keys_.end(),
146  x, key_compare() );
147 
148  return values_.begin() + indices_[k_it - keys_.begin()];
149  }
150 
151  //: A more efficient make_pair(lower_bound(...), upper_bound(...))
152  std::pair<const_value_iterator, const_value_iterator> equal_range(const key_type& x) const
153  {
154  // This appears particularly slow in MSVC10 with no optimisation. In particular it appears slower
155  // than std::map dereference.
156  const_key_iterator k_it = std::lower_bound(keys_.begin(), keys_.end(),
157  x, key_compare() );
158 
159  if (k_it == keys_end() || *k_it != x)
160  {
161  const_value_iterator v_it=values_.begin() + indices_[k_it - keys_.begin()];
162  return std::make_pair(v_it, v_it);
163  }
164  else
165  {
166  return std::make_pair(values_.begin() + indices_[k_it - keys_.begin()],
167  values_.begin() + indices_[k_it - keys_.begin() + 1u] );
168  }
169  }
170 
171  //: Finds the first value with key matching \p x, or returns values_end() if no match,
173  {
174  const_key_iterator k_it = std::lower_bound(keys_.begin(), keys_.end(),
175  x, key_compare() );
176 
177  if (k_it == keys_end() || *k_it != x)
178  return values_end();
179  else
180  return values_.begin() + indices_[k_it - keys_.begin()];
181  }
182 
183  //: Finds the number of values matching key \p x,
184  std::size_t count(const key_type& x) const
185  {
186  const_key_iterator k_it = std::lower_bound(keys_.begin(), keys_.end(),
187  x, key_compare() );
188 
189  if (k_it == keys_end() || *k_it != x)
190  return 0;
191  else
192  return indices_[k_it - keys_.begin() + 1u] - indices_[k_it - keys_.begin()];
193  }
194 
195  private:
199 
200  template <typename CI, typename CMP>
201  bool is_sorted(CI start, CI end, CMP comp)
202  {
203  if (start == end) return true;
204 
205  for (--end; start!=end; ++start)
206  {
207  // if cmp(a,b) is the sorting criteria, then !cmp(b,a) is the testing criteria for is_sorted.
208  if (comp(*(start+1), *start)) return false;
209  }
210  return true;
211  }
212 };
213 
214 template<typename K, typename T, typename C>
216 {
217  x.swap(y);
218 }
219 
220 #endif // vbl_batch_compact_multimap_h_
vbl_batch_compact_multimap()=default
bool is_sorted(CI start, CI end, CMP comp)
void swap(vbl_batch_compact_multimap &x)
std::vector< value_type > value_container_type
bool operator==(const vbl_batch_compact_multimap &rhs)
void assign(CI start, CI finish)
Change all the values in the multimap.
std::vector< key_type > key_container_type
std::pair< key_type, value_type > input_type
The type of data in the inputted sequence.
const_value_iterator lower_bound(const key_type &x) const
Finds the beginning of a subsequence of values whose key matches given x.
vbl_batch_compact_multimap(CI start, CI finish)
std::pair< const_value_iterator, const_value_iterator > equal_range(const key_type &x) const
A more efficient make_pair(lower_bound(...), upper_bound(...)).
const_key_iterator keys_begin() const
const_value_iterator values_begin() const
value_container_type::const_iterator const_value_iterator
std::vector< index_type > index_container_type
bool operator()(const input_type &x, const input_type &y) const
void assign_sorted(CI start, CI finish)
Change all the values in the multimap, to a ready sorted sequence.
A fast read and batch-write map-style collection.
std::size_t count(const key_type &x) const
Finds the number of values matching key x,.
const_value_iterator upper_bound(const key_type &x) const
Finds the one past the end of a subsequence of values whose key matches given x.
const_key_iterator keys_end() const
void swap(vbl_batch_compact_multimap< K, T, C > &x, vbl_batch_compact_multimap< K, T, C > &y)
A comparator to sort input data, by ignoring the value in pair<key, value>.
const_value_iterator find(const key_type &x) const
Finds the first value with key matching x, or returns values_end() if no match,.
key_container_type::const_iterator const_key_iterator
const_value_iterator values_end() const
std::vector< input_type > input_container_type
The type of container used internally to process inputted data.