Molassembler  3.0.0
Molecule graph and conformer library
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
AllPairs.h
Go to the documentation of this file.
1 
8 #ifndef INCLUDE_MOLASSEMBLER_TEMPLE_ALL_PAIRS_ADAPTOR_H
9 #define INCLUDE_MOLASSEMBLER_TEMPLE_ALL_PAIRS_ADAPTOR_H
10 
13 
14 #include <tuple>
15 
16 namespace Scine {
17 namespace Molassembler {
18 namespace Temple {
19 namespace Adaptors {
20 namespace Detail {
21 
22 template<class Base>
23 struct EmptySizeSupplier {};
24 
25 template<class Base>
26 struct SingleContainerPairsSizeSupplier {
27  std::size_t size() const {
28  const std::size_t N = static_cast<const Base&>(*this).container.size();
29  return N * (N - 1) / 2;
30  }
31 };
32 
33 template<class Base>
34 struct TwoContainersPairsSizeSupplier {
35  std::size_t size() const {
36  const auto& base = static_cast<const Base&>(*this);
37  return base.containerT.size() * base.containerU.size();
38  }
39 };
40 
41 template<class Container>
42 struct SingleContainerPairsGenerator
43  : public std::conditional_t<
44  Traits::hasSize<Container>::value,
45  SingleContainerPairsSizeSupplier<SingleContainerPairsGenerator<Container>>,
46  EmptySizeSupplier<SingleContainerPairsGenerator<Container>>
47  >
48 {
51  // See tricks documentation
52  using BoundContainer = typename Binding<Container>::type;
53 
54  using ContainerValueType = decltype(
55  *std::begin(
56  std::declval<const Container>()
57  )
58  );
59 
60  using PairType = std::pair<ContainerValueType, ContainerValueType>;
61 
62  using ContainerIteratorType = decltype(
63  std::begin(std::declval<const Container>())
64  );
66 
69  BoundContainer container;
71 
74  explicit SingleContainerPairsGenerator(Container&& passContainer)
75  : container(std::forward<Container>(passContainer)) {}
77 
80  template<class ContainerIterator>
81  class iterator {
82  public:
83  using iterator_category = std::forward_iterator_tag;
84  using value_type = PairType;
85  using difference_type = int;
86  using pointer = const PairType*;
87  using reference = const PairType&;
88 
89  iterator() = default;
90  iterator(ContainerIterator left, ContainerIterator right, ContainerIterator end)
91  : left_(std::move(left)),
92  right_(std::move(right)),
93  end_(std::move(end))
94  {}
95 
96  // Prefix increment
97  iterator& operator ++ () {
98  ++right_;
99  if(right_ == end_) {
100  ++left_;
101  right_ = left_;
102  ++right_;
103  }
104 
105  return *this;
106  }
107 
108  // Postfix increment
109  iterator operator ++ (int) {
110  iterator prior = *this;
111  ++(*this);
112  return prior;
113  }
114 
115  bool operator == (const iterator& other) const {
116  return left_ == other.left_ && right_ == other.right_;
117  }
118 
119  bool operator != (const iterator& other) const {
120  return !(*this == other);
121  }
122 
123  PairType operator * () const {
124  return {*left_, *right_};
125  }
126 
127  private:
128  ContainerIterator left_, right_, end_;
129  };
130 
131  iterator<ContainerIteratorType> begin() const {
132  auto maybeNextToBegin = std::begin(container);
133  if(maybeNextToBegin != std::end(container)) {
134  ++maybeNextToBegin;
135  }
136 
137  return {
138  std::begin(container),
139  std::move(maybeNextToBegin),
140  std::end(container)
141  };
142  }
143 
144  iterator<ContainerIteratorType> end() const {
145  auto maybePriorToEnd = std::end(container);
146  if(maybePriorToEnd != std::begin(container)) {
147  --maybePriorToEnd;
148  }
149 
150  return {
151  std::move(maybePriorToEnd),
152  std::end(container),
153  std::end(container)
154  };
155  }
157 };
158 
159 template<class ContainerT, class ContainerU>
160 struct TwoContainersAllPairsGenerator
161  : public std::conditional_t<
162  Traits::hasSize<ContainerT>::value && Traits::hasSize<ContainerU>::value,
163  TwoContainersPairsSizeSupplier<TwoContainersAllPairsGenerator<ContainerT, ContainerU>>,
164  SingleContainerPairsSizeSupplier<TwoContainersAllPairsGenerator<ContainerT, ContainerU>>
165  >
166 {
169  using BoundContainerT = typename Binding<ContainerT>::type;
170  using BoundContainerU = typename Binding<ContainerU>::type;
171 
172  using T = decltype(
173  *std::begin(
174  std::declval<ContainerT>()
175  )
176  );
177 
178  using U = decltype(
179  *std::begin(
180  std::declval<ContainerU>()
181  )
182  );
183 
184  using PairType = std::pair<T, U>;
185 
186  using ContainerTIterator = decltype(
187  std::begin(std::declval<const ContainerT>())
188  );
189  using ContainerUIterator = decltype(
190  std::begin(std::declval<const ContainerU>())
191  );
193 
196  BoundContainerT containerT;
197  BoundContainerU containerU;
199 
202  TwoContainersAllPairsGenerator(
203  ContainerT&& t,
204  ContainerU&& u
205  ) : containerT(std::forward<ContainerT>(t)),
206  containerU(std::forward<ContainerU>(u))
207  {}
209 
212  template<class TIterator, class UIterator>
213  class iterator {
214  public:
215  using iterator_category = std::forward_iterator_tag;
216  using value_type = PairType;
217  using difference_type = int;
218  using pointer = const PairType*;
219  using reference = const PairType&;
220 
221  iterator() = default;
222  iterator(
223  TIterator tBegin,
224  TIterator tEnd,
225  UIterator uBegin,
226  UIterator uEnd
227  ) : tIter_(std::move(tBegin)),
228  tEnd_(std::move(tEnd)),
229  uBegin_(std::move(uBegin)),
230  uIter_(uBegin_),
231  uEnd_(std::move(uEnd))
232  {}
233 
234  iterator& operator ++ () {
235  ++uIter_;
236  if(uIter_ == uEnd_) {
237  ++tIter_;
238  uIter_ = uBegin_;
239  }
240 
241  return *this;
242  }
243 
244  iterator operator ++ (int) {
245  iterator prior = *this;
246  ++(*this);
247  return prior;
248  }
249 
250  bool operator == (const iterator& other) const {
251  return (
252  std::tie(tIter_, tEnd_, uIter_, uEnd_)
253  == std::tie(other.tIter_, other.tEnd_, other.uIter_, other.uEnd_)
254  );
255  }
256 
257  bool operator != (const iterator& other) const {
258  return !(*this == other);
259  }
260 
261  PairType operator * () const {
262  return {*tIter_, *uIter_};
263  }
264 
265  private:
266  TIterator tIter_, tEnd_;
267  UIterator uBegin_, uIter_, uEnd_;
268  };
269 
270  iterator<ContainerTIterator, ContainerUIterator> begin() const {
271  return {
272  std::begin(containerT),
273  std::end(containerT),
274  std::begin(containerU),
275  std::end(containerU)
276  };
277  }
278 
279  iterator<ContainerTIterator, ContainerUIterator> end() const {
280  return {
281  std::end(containerT),
282  std::end(containerT),
283  std::begin(containerU),
284  std::end(containerU)
285  };
286  }
288 };
289 
290 } // namespace Detail
291 
292 template<class Container>
293 auto allPairs(Container&& container) {
294  return Detail::SingleContainerPairsGenerator<Container>(
295  std::forward<Container>(container)
296  );
297 }
298 
299 template<class ContainerT, class ContainerU>
300 auto allPairs(ContainerT&& t, ContainerU&& u) {
301  return Detail::TwoContainersAllPairsGenerator<ContainerT, ContainerU>(
302  std::forward<ContainerT>(t),
303  std::forward<ContainerU>(u)
304  );
305 }
306 
307 } // namespace Adaptors
308 } // namespace Temple
309 } // namespace Molassembler
310 } // namespace Scine
311 
312 #endif
Provides an identity functor.
Type that will own rvalues, reference lvalues.
Definition: Binding.h:37
Compile-time container type traits.