Molassembler  3.0.0
Molecule graph and conformer library
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Containers.h
Go to the documentation of this file.
1 
10 #ifndef INCLUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_CONTAINERS_H
11 #define INCLUDE_MOLASSEMBLER_TEMPLE_CONSTEXPR_CONTAINERS_H
12 
14 
15 #include <array>
16 #include <limits>
17 #include <functional>
18 
19 namespace Scine {
20 namespace Molassembler {
21 namespace Temple {
22 namespace Traits {
23 
25 template<class Function, typename ...Args>
26 using functionReturnType = std::result_of_t<Function(Args...)>;
27 
28 } // namespace Traits
29 
30 namespace Detail {
31 
33 template<
34  template<typename, std::size_t> class ArrayType,
35  typename T,
36  std::size_t size,
37  class UnaryFunction,
38  std::size_t ... Inds
39 > constexpr auto mapImpl(
40  const ArrayType<T, size>& array,
41  UnaryFunction&& function,
42  std::index_sequence<Inds...> /* inds */
43 ) {
44  return ArrayType<
46  size
47  > {
48  function(array.at(Inds))...
49  };
50 }
51 
52 } // namespace Detail
53 
58 template<
59  template<typename, std::size_t> class ArrayType,
60  typename T,
61  std::size_t size,
62  class UnaryFunction
63 > constexpr auto map(
64  const ArrayType<T, size>& array,
65  UnaryFunction&& function
66 ) {
67  return Detail::mapImpl(
68  array,
69  std::forward<UnaryFunction>(function),
70  std::make_index_sequence<size>{}
71  );
72 }
73 
84 template<
85  template<typename, std::size_t> class ArrayType,
86  typename T,
87  std::size_t size,
88  class BinaryFunction
89 > constexpr T reduce(
90  const ArrayType<T, size>& array,
91  T init,
92  BinaryFunction&& reduction
93 ) {
94  for(const auto& element : array) {
95  init = reduction(init, element);
96  }
97 
98  return init;
99 }
100 
108 template<
109  template<typename, std::size_t> class ArrayType,
110  typename T,
111  std::size_t size
112 > constexpr T sum(const ArrayType<T, size>& array) {
113  T sum {0};
114 
115  for(unsigned i = 0; i < size; ++i) {
116  sum += array.at(i);
117  }
118 
119  return sum;
120 }
121 
122 namespace Detail {
123 
124 
125 template<
126  template<typename, std::size_t> class ArrayType,
127  typename T,
128  std::size_t size,
129  std::size_t ... Inds
130 > constexpr ArrayType<T, size> iotaHelper(
131  std::index_sequence<Inds...> /* inds */
132 ) {
133  return ArrayType<T, size> { static_cast<T>(Inds)... };
134 }
135 
136 } // namespace Detail
137 
139 template<
140  template<typename, std::size_t> class ArrayType,
141  typename T,
142  std::size_t size
143 > PURITY_STRONG constexpr std::enable_if_t<
144  std::is_arithmetic<T>::value,
145  ArrayType<T, size>
146 > iota() {
147  return Detail::iotaHelper<ArrayType, T, size>(
148  std::make_index_sequence<size>()
149  );
150 }
151 
152 namespace Detail {
153 
154 template<
155  template<typename, std::size_t> class ArrayType,
156  typename T,
157  std::size_t begin,
158  std::size_t end,
159  std::size_t ... Inds
160 > constexpr ArrayType<T, (end - begin)> rangeHelper(
161  std::index_sequence<Inds...> /* inds */
162 ) {
163  return ArrayType<T, (end - begin)> {
164  (begin + Inds)...
165  };
166 }
167 
168 } // namespace Detail
169 
171 template<
172  template<typename, std::size_t> class ArrayType,
173  typename T,
174  std::size_t begin, // inclusive
175  std::size_t end // exclusive
176 > constexpr ArrayType<T, (end - begin)> range() {
177  return Detail::rangeHelper<ArrayType, T, begin, end>(
178  std::make_index_sequence<(end - begin)>()
179  );
180 }
181 
182 namespace Detail {
183 
185 template<
186  template<typename, std::size_t> class ArrayType,
187  typename T,
188  std::size_t N1,
189  std::size_t... AIndices,
190  std::size_t N2,
191  std::size_t... BIndices
192 >
193 constexpr ArrayType<T, N1+N2> arrayConcatenateImpl(
194  const ArrayType<T, N1>& a,
195  const ArrayType<T, N2>& b,
196  std::index_sequence<AIndices...> /* aInds */,
197  std::index_sequence<BIndices...> /* bInds */
198 ) {
199  return {
200  a.at(AIndices)...,
201  b.at(BIndices)...
202  };
203 }
204 
205 } // namespace Detail
206 
208 template<
209  template<typename, std::size_t> class ArrayType,
210  typename T,
211  std::size_t N1,
212  std::size_t N2
213 >
214 constexpr ArrayType<T, N1+N2> arrayConcatenate(
215  const ArrayType<T, N1>& a,
216  const ArrayType<T, N2>& b
217 ) {
218  return Detail::arrayConcatenateImpl(
219  a,
220  b,
221  std::make_index_sequence<N1>{},
222  std::make_index_sequence<N2>{}
223  );
224 }
225 
226 namespace Detail {
227 
228 template<
229  template<typename, std::size_t> class ArrayType,
230  typename T,
231  std::size_t concatenatedSize
232 > constexpr ArrayType<T, concatenatedSize> concatenateHelper(
233  const ArrayType<T, concatenatedSize>& concatenated
234 ) {
235  return concatenated;
236 }
237 
238 template<
239  template<typename, std::size_t> class ArrayType,
240  typename T,
241  std::size_t concatenatedSize,
242  std::size_t curSize,
243  std::size_t ... Ns
244 > constexpr auto concatenateHelper(
245  const ArrayType<T, concatenatedSize>& concatenated,
246  const ArrayType<T, curSize>& array,
247  const ArrayType<T, Ns>& ... arrays
248 ) {
249  return concatenateHelper(
251  concatenated,
252  array
253  ),
254  arrays...
255  );
256 }
257 
258 } // namespace Detail
259 
261 template<
262  template<typename, std::size_t> class ArrayType,
263  typename T,
264  std::size_t N,
265  std::size_t ... Ns
266 > constexpr auto arrayConcatenate(
267  const ArrayType<T, N>& startingArray,
268  const ArrayType<T, Ns>& ... remainingArrays
269 ) {
270  return Detail::concatenateHelper(startingArray, remainingArrays...);
271 }
272 
277 template<
278  template<typename, std::size_t> class ArrayType,
279  typename T,
280  std::size_t size
281 > constexpr bool arraysEqual(
282  const ArrayType<T, size>& a,
283  const ArrayType<T, size>& b
284 ) {
285  for(unsigned i = 0; i < size; ++i) {
286  if(a.at(i) != b.at(i)) {
287  return false;
288  }
289  }
290 
291  return true;
292 }
293 
298 template<
299  template<typename, std::size_t> class ArrayType,
300  typename T,
301  std::size_t sizeA,
302  std::size_t sizeB
303 > constexpr std::enable_if_t<
304  (sizeA > sizeB),
305  bool
307  const ArrayType<T, sizeA>& a,
308  const ArrayType<T, sizeB>& b
309 ) {
310  if constexpr(sizeA < sizeB) {
311  return true;
312  } else if constexpr(sizeA > sizeB) {
313  return false;
314  } else { // sizes equal
315  for(unsigned i = 0; i < sizeA; ++i) {
316  if(!(a.at(i) < b.at(i))) {
317  return false;
318  }
319  }
320 
321  return true;
322  }
323 }
324 
333 template<
334  typename T,
335  class LessThanPredicate,
336  class Iter
337 > constexpr Iter lowerBound(
338  Iter bound,
339  Iter last,
340  const T& item,
341  LessThanPredicate predicate
342 ) {
343  using DiffType = decltype(last - bound);
344  static_assert(
345  std::is_signed<DiffType>::value,
346  "Difference between iterators must be a signed type!"
347  );
348 
349  Iter it = bound;
350  DiffType count = last - bound;
351  DiffType step = 0;
352 
353  while(count > 0) {
354  it = bound;
355  step = count / 2;
356  std::advance(it, step);
357 
358  if(predicate(*it, item)) {
359  ++it;
360  bound = it;
361  count -= step + 1;
362  } else {
363  count = step;
364  }
365  }
366 
367  return bound;
368 }
369 
377 template<
378  class Container,
379  typename T,
380  class LessThanPredicate = std::less<>
381 > constexpr typename Container::const_iterator binarySearch(
382  const Container& container,
383  const T& item,
384  LessThanPredicate predicate = LessThanPredicate()
385 ) {
386  auto bound = lowerBound<T, LessThanPredicate>(
387  container.begin(),
388  container.end(),
389  item,
390  predicate
391  );
392 
393  /* Lower bound merely finds the first item not smaller than the sought one,
394  * this does NOT mean that they're equal.
395  *
396  * a == b <--> !(a < b) && !(b < a)
397  *
398  * Lower bound guarantees the first condition of the right side, but we need
399  * to check the second one to ensure that we have found what we seek, not just
400  * merely something bigger than a.
401  */
402  if(predicate(item, *bound)) {
403  return container.end();
404  }
405 
406  return bound;
407 }
408 
409 namespace Detail {
410  template<class ContainerType>
411  struct getValueTypeImpl {
412  using type = typename std::remove_const<
413  typename std::remove_reference<
414  decltype(
415  *(std::declval<ContainerType>()).begin()
416  )
417  >::type
418  >::type;
419  };
420 } // namespace Detail
421 
423 template<class ContainerType>
424 using getValueType = typename Detail::getValueTypeImpl<ContainerType>::type;
425 
437 template<
438  class ContainerType,
439  class LessThanComparator = std::less<
441  >
442 > constexpr bool isPartiallyOrdered(
443  const ContainerType& container,
444  LessThanComparator comparator = LessThanComparator {}
445 ) {
446  auto leftIter = container.begin();
447  if(leftIter == container.end()) {
448  return true;
449  }
450 
451  auto rightIter = leftIter + 1;
452 
453  while(rightIter != container.end()) {
454  // equivalent to *rightIter < *leftIter
455  if(comparator(*rightIter, *leftIter)) {
456  return false;
457  }
458 
459  ++leftIter;
460  ++rightIter;
461  }
462 
463  return true;
464 }
465 
477 template<
478  class ContainerType,
479  class LessThanComparator = std::less<
480  getValueType<ContainerType>
481  >
482 > constexpr bool isTotallyOrdered(
483  const ContainerType& container,
484  LessThanComparator comparator = LessThanComparator {}
485 ) {
486  auto leftIter = container.begin();
487  if(leftIter == container.end()) {
488  return true;
489  }
490 
491  auto rightIter = leftIter + 1;
492 
493 
494  while(rightIter != container.end()) {
495  // Equivalent to !(*leftIter < *rightIter
496  if(!comparator(*leftIter, *rightIter)) {
497  return false;
498  }
499 
500  ++leftIter;
501  ++rightIter;
502  }
503 
504  return true;
505 }
506 
507 } // namespace Temple
508 } // namespace Molassembler
509 } // namespace Scine
510 
511 #endif
PURITY_STRONG constexpr std::enable_if_t< std::is_arithmetic< T >::value, ArrayType< T, size >> iota()
Iota for any array type.
Definition: Containers.h:146
double element(const PositionCollection &normalizedPositions, const Elements::Rotation &rotation)
Returns the CSM for a Rotation symmetry element along the rotation axis without optimizing the coordi...
constexpr Container::const_iterator binarySearch(const Container &container, const T &item, LessThanPredicate predicate=LessThanPredicate())
Binary search an order container.
Definition: Containers.h:381
constexpr std::enable_if_t< (sizeA > sizeB), bool > arraysLess(const ArrayType< T, sizeA > &a, const ArrayType< T, sizeB > &b)
Lexicographical comparison for two instances of an array-like class.
Definition: Containers.h:306
constexpr bool isTotallyOrdered(const ContainerType &container, LessThanComparator comparator=LessThanComparator{})
Checks if the container hold strictly increasing values.
Definition: Containers.h:482
constexpr Iter lowerBound(Iter bound, Iter last, const T &item, LessThanPredicate predicate)
Constexpr lower bound algorithm from STL.
Definition: Containers.h:337
Defines a set of useful preprocessor macros.
constexpr T reduce(const ArrayType< T, size > &array, T init, BinaryFunction &&reduction)
Reduce an array-like container with a binary function.
Definition: Containers.h:89
constexpr bool isPartiallyOrdered(const ContainerType &container, LessThanComparator comparator=LessThanComparator{})
Checks if a container is partially ordered.
Definition: Containers.h:442
std::result_of_t< Function(Args...)> functionReturnType
Figure out the return type of calling a function.
Definition: Containers.h:26
constexpr bool arraysEqual(const ArrayType< T, size > &a, const ArrayType< T, size > &b)
Array-like container lexicographic equality comparaotr.
Definition: Containers.h:281
constexpr auto map(const ArrayType< T, size > &array, UnaryFunction &&function)
Maps all elements of any array-like container with a unary function.
Definition: Containers.h:63
constexpr T sum(const ArrayType< T, size > &array)
Sum up all elements of an array-like class.
Definition: Containers.h:112
constexpr ArrayType< T,(end-begin)> range()
Range for any array type.
Definition: Containers.h:176
typename Detail::getValueTypeImpl< ContainerType >::type getValueType
Figures out the value type of a container via its iterators.
Definition: Containers.h:424
constexpr ArrayType< T, N1+N2 > arrayConcatenate(const ArrayType< T, N1 > &a, const ArrayType< T, N2 > &b)
Concatenation of two instances of an array-like class.
Definition: Containers.h:214
#define PURITY_STRONG
Definition: Preprocessor.h:65