Developer Documentation
SmartRange.hh
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2019, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 
43 #pragma once
44 
45 #include <utility>
46 #include <array>
47 #include <vector>
48 #include <set>
49 
50 //== NAMESPACES ===============================================================
51 
52 namespace OpenMesh {
53 
54 //== FORWARD DECLARATION ======================================================
55 
56 //== CLASS DEFINITION =========================================================
57 
58 namespace {
59 
60 struct Identity
61 {
62  template <typename T>
63  T operator()(const T& _t) const { return _t; }
64 };
65 
66 }
67 
68 template <typename RangeT, typename HandleT, typename Functor>
70 
72 template <typename RangeT, typename HandleT>
74 {
75  using Handle = HandleT;
77  using Range = RangeT;
78 
79  // TODO: Someone with better c++ knowledge may improve the code below.
80 
87  template <typename Functor>
88  auto sum(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
89  {
90  auto range = static_cast<const RangeT*>(this);
91  auto begin = range->begin();
92  auto end = range->end();
93  assert(begin != end);
94  typename std::decay<decltype (f(*begin))>::type result = f(*begin);
95  auto it = begin;
96  ++it;
97  for (; it != end; ++it)
98  result += f(*it);
99  return result;
100  }
101 
108  template <typename Functor>
109  auto avg(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
110  {
111  auto range = static_cast<const RangeT*>(this);
112  auto begin = range->begin();
113  auto end = range->end();
114  assert(begin != end);
115  typename std::decay<decltype (f(*begin))>::type result = f(*begin);
116  auto it = begin;
117  ++it;
118  int n_elements = 1;
119  for (; it != end; ++it)
120  {
121  result += f(*it);
122  ++n_elements;
123  }
124  return (1.0 / n_elements) * result;
125  }
126 
134  template <typename Functor, typename WeightFunctor>
135  auto avg(Functor&& f, WeightFunctor&& w) -> typename std::decay<decltype ((1.0/(w(std::declval<HandleT>())+w(std::declval<HandleT>())))*f(std::declval<HandleT>()))>::type
136  {
137  auto range = static_cast<const RangeT*>(this);
138  auto begin = range->begin();
139  auto end = range->end();
140  assert(begin != end);
141  typename std::decay<decltype (w(*begin))>::type weight = w(*begin);
142  typename std::decay<decltype (w(*begin)*f(*begin))>::type result = weight * f(*begin);
143  typename std::decay<decltype (w(*begin)+w(*begin))>::type weight_sum = weight;
144  auto it = begin;
145  ++it;
146  for (; it != end; ++it)
147  {
148  weight = w(*it);
149  result += weight*f(*it);
150  weight_sum += weight;
151  }
152  return (1.0 / weight_sum) * result;
153  }
154 
162  template <typename Functor>
163  auto any_of(Functor&& f) -> bool
164  {
165  auto range = static_cast<const RangeT*>(this);
166  for (auto e : *range)
167  if (f(e))
168  return true;
169  return false;
170  }
171 
179  template <typename Functor>
180  auto all_of(Functor&& f) -> bool
181  {
182  auto range = static_cast<const RangeT*>(this);
183  for (auto e : *range)
184  if (!f(e))
185  return false;
186  return true;
187  }
188 
198  template <int n, typename Functor = Identity>
199  auto to_array(Functor&& f = {}) -> std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n>
200  {
201  auto range = static_cast<const RangeT*>(this);
202  std::array<typename std::decay<decltype (f(std::declval<HandleT>()))>::type, n> res;
203  auto it = range->begin();
204  auto end = range->end();
205  int i = 0;
206  while (i < n && it != end)
207  res[i++] = f(*(it++));
208  return res;
209  }
210 
218  template <typename Functor = Identity>
219  auto to_vector(Functor&& f = {}) -> std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
220  {
221  auto range = static_cast<const RangeT*>(this);
222  std::vector<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
223  for (const auto& e : *range)
224  res.push_back(f(e));
225  return res;
226  }
227 
235  template <typename Functor = Identity>
236  auto to_set(Functor&& f = {}) -> std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
237  {
238  auto range = static_cast<const RangeT*>(this);
239  std::set<typename std::decay<decltype (f(std::declval<HandleT>()))>::type> res;
240  for (const auto& e : *range)
241  res.insert(f(e));
242  return res;
243  }
244 
253  template <typename Functor>
254  auto first(Functor&& f = {}) -> HandleT
255  {
256  auto range = static_cast<const RangeT*>(this);
257  for (const auto& e : *range)
258  if (f(e))
259  return e;
260  return HandleT();
261  }
262 
269  template <typename Functor>
270  auto min(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
271  {
272  using std::min;
273 
274  auto range = static_cast<const RangeT*>(this);
275  auto it = range->begin();
276  auto end = range->end();
277  assert(it != end);
278 
279  typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
280  ++it;
281 
282  for (; it != end; ++it)
283  res = min(res, f(*it));
284 
285  return res;
286  }
287 
294  template <typename Functor>
295  auto argmin(Functor&& f) -> HandleT
296  {
297  auto range = static_cast<const RangeT*>(this);
298  auto it = range->begin();
299  auto min_it = it;
300  auto end = range->end();
301  assert(it != end);
302 
303  typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_min = f(*it);
304  ++it;
305 
306  for (; it != end; ++it)
307  {
308  auto val = f(*it);
309  if (val < curr_min)
310  {
311  curr_min = val;
312  min_it = it;
313  }
314  }
315 
316  return *min_it;
317  }
318 
325  template <typename Functor>
326  auto max(Functor&& f) -> typename std::decay<decltype (f(std::declval<HandleT>()))>::type
327  {
328  using std::max;
329 
330  auto range = static_cast<const RangeT*>(this);
331  auto it = range->begin();
332  auto end = range->end();
333  assert(it != end);
334 
335  typename std::decay<decltype (f(std::declval<HandleT>()))>::type res = f(*it);
336  ++it;
337 
338  for (; it != end; ++it)
339  res = max(res, f(*it));
340 
341  return res;
342  }
343 
344 
351  template <typename Functor>
352  auto argmax(Functor&& f) -> HandleT
353  {
354  auto range = static_cast<const RangeT*>(this);
355  auto it = range->begin();
356  auto max_it = it;
357  auto end = range->end();
358  assert(it != end);
359 
360  typename std::decay<decltype (f(std::declval<HandleT>()))>::type curr_max = f(*it);
361  ++it;
362 
363  for (; it != end; ++it)
364  {
365  auto val = f(*it);
366  if (val > curr_max)
367  {
368  curr_max = val;
369  max_it = it;
370  }
371  }
372 
373  return *max_it;
374  }
375 
383  template <typename Functor>
384  auto minmax(Functor&& f) -> std::pair<typename std::decay<decltype (f(std::declval<HandleT>()))>::type,
385  typename std::decay<decltype (f(std::declval<HandleT>()))>::type>
386  {
387  return std::make_pair(this->min(f), this->max(f));
388  }
389 
390 
397  template <typename Functor>
398  auto count_if(Functor&& f) -> int
399  {
400  int count = 0;
401  auto range = static_cast<const RangeT*>(this);
402  for (const auto& e : *range)
403  if (f(e))
404  ++count;
405  return count;
406  }
407 
408 
415  template <typename Functor>
416  auto for_each(Functor&& f) -> void
417  {
418  auto range = static_cast<const RangeT*>(this);
419  for (const auto& e : *range)
420  f(e);
421  }
422 
423 
430  template <typename Functor>
432  {
433  auto range = static_cast<const RangeT*>(this);
434  return FilteredSmartRangeT<SmartRange, Handle, Functor>(std::forward<Functor>(f), (*range).begin(), (*range).end());
435  }
436 };
437 
438 
440 template <typename RangeT, typename HandleT, typename Functor>
441 struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, HandleT, Functor>, HandleT>
442 {
444  using BaseIterator = decltype((std::declval<typename RangeT::Range>().begin()));
445 
446  struct FilteredIterator : public BaseIterator
447  {
448 
449  FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end)
450  {
451  if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one
452  operator++();
453  }
454 
455  FilteredIterator& operator=(const FilteredIterator& other)
456  {
457  BaseIterator::operator=(other);
458  end_ = other.end_;
459  return *this;
460  }
461 
462  FilteredIterator& operator++()
463  {
464  if (BaseIterator::operator==(end_)) // don't go past end
465  return *this;
466 
467  // go to next valid one
468  do
469  BaseIterator::operator++();
470  while (BaseIterator::operator!=(end_) && !f_(*(*this)));
471  return *this;
472  }
473 
474  Functor f_; // Should iterators always get a reference to filter stored in range?
475  // Should iterators stay valid after range goes out of scope?
476  BaseIterator end_;
477  };
478 
479  FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward<Functor>(f)), begin_(std::move(begin)), end_(std::move(end)){}
480  FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); }
481  FilteredIterator end() const { return FilteredIterator(f_, end_, end_); }
482 
483  Functor f_;
484  BaseIterator begin_;
485  BaseIterator end_;
486 };
487 
488 
489 
490 //=============================================================================
491 } // namespace OpenMesh
492 //=============================================================================
493 
494 //=============================================================================
auto avg(Functor &&f, WeightFunctor &&w) -> typename std::decay< decltype((1.0/(w(std::declval< HandleT >())+w(std::declval< HandleT >()))) *f(std::declval< HandleT >()))>::type
Computes the weighted average of elements.
Definition: SmartRange.hh:135
auto to_vector(Functor &&f={}) -> std::vector< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to vector.
Definition: SmartRange.hh:219
auto any_of(Functor &&f) -> bool
Check if any element fulfils condition.
Definition: SmartRange.hh:163
Base class for all smart range types.
Definition: SmartRange.hh:73
auto count_if(Functor &&f) -> int
Compute number of elements that satisfy a given predicate.
Definition: SmartRange.hh:398
auto argmin(Functor &&f) -> HandleT
Compute minimal element.
Definition: SmartRange.hh:295
auto min(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute minimum.
Definition: SmartRange.hh:270
auto first(Functor &&f={}) -> HandleT
Get the first element that fulfills a condition.
Definition: SmartRange.hh:254
auto max(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Compute maximum.
Definition: SmartRange.hh:326
auto argmax(Functor &&f) -> HandleT
Compute maximal element.
Definition: SmartRange.hh:352
auto minmax(Functor &&f) -> std::pair< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Computes minimum and maximum.
Definition: SmartRange.hh:384
auto sum(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the sum of elements.
Definition: SmartRange.hh:88
auto to_array(Functor &&f={}) -> std::array< typename std::decay< decltype(f(std::declval< HandleT >()))>::type, n >
Convert range to array.
Definition: SmartRange.hh:199
auto for_each(Functor &&f) -> void
Apply a functor to each element.
Definition: SmartRange.hh:416
auto to_set(Functor &&f={}) -> std::set< typename std::decay< decltype(f(std::declval< HandleT >()))>::type >
Convert range to set.
Definition: SmartRange.hh:236
auto all_of(Functor &&f) -> bool
Check if all elements fulfil condition.
Definition: SmartRange.hh:180
auto filtered(Functor &&f) -> FilteredSmartRangeT< SmartRange, Handle, Functor >
Only iterate over a subset of elements.
Definition: SmartRange.hh:431
auto avg(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the average of elements.
Definition: SmartRange.hh:109
Class which applies a filter when iterating over elements.
Definition: SmartRange.hh:69