test_iterators.cxx
Go to the documentation of this file.
1 
4 #include "WireCellUtil/Testing.h"
5 #include <boost/range.hpp>
6 
7 #include <boost/function.hpp>
8 
9 #include <vector>
10 #include <iostream>
11 #include <algorithm> // copy_if
12 #include <iterator> // back_inserter
13 #include <memory> // shared_ptr
14 #include <vector>
15 #include <cmath>
16 
17 using namespace std;
18 using namespace WireCell;
19 
20 // This is the base/interface data type that will be iterated over.
21 struct IMyClass {
22  virtual ~IMyClass() {}
23  virtual int get_i() const = 0;
24  virtual float get_f() const = 0;
25 };
26 
27 // This is a concrete imp of that interface and may reside deep inside
28 // some private scope.
29 struct MyClass : public IMyClass {
30  int m_i;
31  float m_f;
32 
33  MyClass(int i=0, float f=0.0) : m_i(i), m_f(f) {}
34  virtual ~MyClass() {}
35  virtual int get_i() const { return m_i; }
36  virtual float get_f() const { return m_f; }
37 };
38 
39 // What I expose to my clients. Ie, something that looks lika a
40 // std::vector<const IMyClass*>::iterator.
42 
43 // Begin/end pairs passed to and by clients.
44 typedef std::pair<my_iterator, my_iterator> my_range;
45 
46 
47 // What I and all other implementers of my interface use as an
48 // abstract base class for the iterator of the base data type. The
49 // template parameter must match the one used to define my_iterator.
51 
52 // In the end, the concrete imp that exposes iterators to IMyClass
53 // needs to store implementation-specific data types and this store is
54 // here. It need not be exposed to anyone but the concrete-imp. It's
55 // non-const since I own it and control when it's finalized. I may
56 // also delete it one day.
57 typedef vector< MyClass* > MyStoreType;
58 
59 
60 // Since the above store is really just an STL vector the
61 // implementation need not explicitly write matching concrete
62 // iterator, but can use the STL adapter.
64 
65 
66 // Selectors
67 typedef boost::function<bool (const IMyClass*)> my_selector;
68 
69 struct SelectInt {
70  int target;
71  SelectInt(int want) : target(want) {}
72  bool operator()(const IMyClass* obj) {
73  return obj->get_i() == target;
74  }
75 };
76 
77 struct SelectInRange {
78  float minval, maxval;
79  SelectInRange(float min, float max) : minval(min), maxval(max) {}
80  bool operator()(const IMyClass* obj) {
81  return minval <= obj->get_f() && obj->get_f() < maxval;
82  }
83 };
84 
88 
89 
91 {
92  return my_range(my_adapted_iterator(store.begin()),
93  my_adapted_iterator(store.end()));
94 }
95 
96 
97 int main()
98 {
99 
100  // This would be deep in side some custom class.
101  MyStoreType store;
102  store.push_back(new MyClass(0,0.0));
103  store.push_back(new MyClass(1,42.));
104  store.push_back(new MyClass(2,6.9));
105 
106  MyClass* first = *(store.begin());
107  AssertMsg(first, "No first");
108  AssertMsg(first->get_i() == 0 && first->get_f() == 0.0, "first ain't first");
109 
110  // This would be an element of the base class's interface which
111  // the custom class implements. It returns generic iterators on
112  // the base/interface data type. These iterators may be copied
113  // without slicing.
114  my_range r = get_data(store);
115 
116  // Finally, here is some client of the interface using the data
117  // born deep inside the custom class and accessing it only via
118  // interfaces.
119  for (my_iterator it = boost::begin(r); it != boost::end(r); ++it) {
120  // make a temp for syntactic convenience/clarity
121  const IMyClass* myptr = *it;
122  const IMyClass& myobj = *myptr;
123  cout << myobj.get_i() << " "
124  << myobj.get_f() << endl;
125  }
126 
127 
128  vector< const IMyClass* > res(r.first, r.second);
129  AssertMsg(res.size(), "range constructor failed.");
130  res.clear();
131 
132  copy(r.first, r.second, back_inserter(res));
133  AssertMsg(res.size(), "copy failed.");
134  res.clear();
135 
136 
137  copy_if(boost::begin(r), boost::end(r), back_inserter(res), get1);
138  cerr << "Got: " << res.size() << endl;
139  AssertMsg(1 == res.size(), "Failed to get1");
140  AssertMsg(res[0]->get_f() == 42., "Got wrong1");
141  res.clear();
142 
143  copy_if(boost::begin(r), boost::end(r), back_inserter(res), get10);
144  AssertMsg(0 == res.size(), "Got get10 but should not.");
145  res.clear();
146 
147  copy_if(boost::begin(r), boost::end(r), back_inserter(res), just_right);
148  AssertMsg(1 == res.size(), "Failed to get just_right");
149  cerr << "Got: " << res[0]->get_i() << " " << res[0]->get_f() << endl;
150  AssertMsg(res[0]->get_i() == 2 && fabs(res[0]->get_f() - 6.9) < 1e-6, "Got just_wrong value");
151  res.clear();
152 
153  return 0;
154 }
virtual ~MyClass()
my_selector get10
IteratorAdapter< MyStoreType::iterator, my_base_iterator > my_adapted_iterator
boost::function< bool(const IMyClass *)> my_selector
bool operator()(const IMyClass *obj)
IteratorBase< const IMyClass * > my_base_iterator
SelectInRange just_right
SelectInt get1
STL namespace.
virtual float get_f() const
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:72
virtual ~IMyClass()
const double e
virtual int get_i() const
SelectInt(int want)
MyClass(int i=0, float f=0.0)
bool operator()(const IMyClass *obj)
vector< MyClass * > MyStoreType
static int max(int a, int b)
Definition: Main.h:22
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
virtual float get_f() const =0
SelectInRange(float min, float max)
#define AssertMsg
Definition: Testing.h:8
virtual int get_i() const =0
T copy(T const &v)
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:67
int main()
std::pair< my_iterator, my_iterator > my_range
my_range get_data(MyStoreType &store)
Iterator< const IMyClass * > my_iterator
QTextStream & endl(QTextStream &s)