Molassembler  1.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 
18 namespace Scine {
19 namespace Molassembler {
20 namespace Temple {
21 namespace Traits {
22 
24 template<class Function, typename ...Args>
25 using functionReturnType = std::result_of_t<Function(Args...)>;
26 
27 } // namespace Traits
28 
29 namespace Detail {
30 
32 template<
33  template<typename, size_t> class ArrayType,
34  typename T,
35  size_t size,
36  class UnaryFunction,
37  size_t ... Inds
38 > constexpr auto mapImpl(
39  const ArrayType<T, size>& array,
40  UnaryFunction&& function,
41  std::index_sequence<Inds...> /* inds */
42 ) {
43  return ArrayType<
45  size
46  > {
47  function(array.at(Inds))...
48  };
49 }
50 
51 } // namespace Detail
52 
57 template<
58  template<typename, size_t> class ArrayType,
59  typename T,
60  size_t size,
61  class UnaryFunction
62 > constexpr auto map(
63  const ArrayType<T, size>& array,
64  UnaryFunction&& function
65 ) {
66  return Detail::mapImpl(
67  array,
68  std::forward<UnaryFunction>(function),
69  std::make_index_sequence<size>{}
70  );
71 }
72 
83 template<
84  template<typename, size_t> class ArrayType,
85  typename T,
86  size_t size,
87  class BinaryFunction
88 > constexpr T reduce(
89  const ArrayType<T, size>& array,
90  T init,
91  BinaryFunction&& reduction
92 ) {
93  for(const auto& element : array) {
94  init = reduction(init, element);
95  }
96 
97  return init;
98 }
99 
107 template<
108  template<typename, size_t> class ArrayType,
109  typename T,
110  size_t size
111 > constexpr T sum(const ArrayType<T, size>& array) {
112  T sum {0};
113 
114  for(unsigned i = 0; i < size; ++i) {
115  sum += array.at(i);
116  }
117 
118  return sum;
119 }
120 
121 namespace Detail {
122 
123 
124 template<
125  template<typename, size_t> class ArrayType,
126  typename T,
127  size_t size,
128  size_t ... Inds
129 > constexpr ArrayType<T, size> iotaHelper(
130  std::index_sequence<Inds...> /* inds */
131 ) {
132  return ArrayType<T, size> { static_cast<T>(Inds)... };
133 }
134 
135 } // namespace Detail
136 
138 template<
139  template<typename, size_t> class ArrayType,
140  typename T,
141  size_t size
142 > PURITY_STRONG constexpr std::enable_if_t<
143  std::is_arithmetic<T>::value,
144  ArrayType<T, size>
145 > iota() {
146  return Detail::iotaHelper<ArrayType, T, size>(
147  std::make_index_sequence<size>()
148  );
149 }
150 
151 namespace Detail {
152 
153 template<
154  template<typename, size_t> class ArrayType,
155  typename T,
156  size_t begin,
157  size_t end,
158  size_t ... Inds
159 > constexpr ArrayType<T, (end - begin)> rangeHelper(
160  std::index_sequence<Inds...> /* inds */
161 ) {
162  return ArrayType<T, (end - begin)> {
163  (begin + Inds)...
164  };
165 }
166 
167 } // namespace Detail
168 
170 template<
171  template<typename, size_t> class ArrayType,
172  typename T,
173  size_t begin, // inclusive
174  size_t end // exclusive
175 > constexpr ArrayType<T, (end - begin)> range() {
176  return Detail::rangeHelper<ArrayType, T, begin, end>(
177  std::make_index_sequence<(end - begin)>()
178  );
179 }
180 
181 namespace Detail {
182 
184 template<
185  template<typename, size_t> class ArrayType,
186  typename T,
187  size_t N1,
188  size_t... AIndices,
189  size_t N2,
190  size_t... BIndices
191 >
192 constexpr ArrayType<T, N1+N2> arrayConcatenateImpl(
193  const ArrayType<T, N1>& a,
194  const ArrayType<T, N2>& b,
195  std::index_sequence<AIndices...> /* aInds */,
196  std::index_sequence<BIndices...> /* bInds */
197 ) {
198  return {
199  a.at(AIndices)...,
200  b.at(BIndices)...
201  };
202 }
203 
204 } // namespace Detail
205 
207 template<
208  template<typename, size_t> class ArrayType,
209  typename T,
210  size_t N1,
211  size_t N2
212 >
213 constexpr ArrayType<T, N1+N2> arrayConcatenate(
214  const ArrayType<T, N1>& a,
215  const ArrayType<T, N2>& b
216 ) {
217  return Detail::arrayConcatenateImpl(
218  a,
219  b,
220  std::make_index_sequence<N1>{},
221  std::make_index_sequence<N2>{}
222  );
223 }
224 
225 namespace Detail {
226 
227 template<
228  template<typename, size_t> class ArrayType,
229  typename T,
230  size_t concatenatedSize
231 > constexpr ArrayType<T, concatenatedSize> concatenateHelper(
232  const ArrayType<T, concatenatedSize>& concatenated
233 ) {
234  return concatenated;
235 }
236 
237 template<
238  template<typename, size_t> class ArrayType,
239  typename T,
240  size_t concatenatedSize,
241  size_t curSize,
242  size_t ... Ns
243 > constexpr auto concatenateHelper(
244  const ArrayType<T, concatenatedSize>& concatenated,
245  const ArrayType<T, curSize>& array,
246  const ArrayType<T, Ns>& ... arrays
247 ) {
248  return concatenateHelper(
250  concatenated,
251  array
252  ),
253  arrays...
254  );
255 }
256 
257 } // namespace Detail
258 
260 template<
261  template<typename, size_t> class ArrayType,
262  typename T,
263  size_t N,
264  size_t ... Ns
265 > constexpr auto arrayConcatenate(
266  const ArrayType<T, N>& startingArray,
267  const ArrayType<T, Ns>& ... remainingArrays
268 ) {
269  return Detail::concatenateHelper(startingArray, remainingArrays...);
270 }
271 
276 template<
277  template<typename, size_t> class ArrayType,
278  typename T,
279  size_t size
280 > constexpr bool arraysEqual(
281  const ArrayType<T, size>& a,
282  const ArrayType<T, size>& b
283 ) {
284  for(unsigned i = 0; i < size; ++i) {
285  if(a.at(i) != b.at(i)) {
286  return false;
287  }
288  }
289 
290  return true;
291 }
292 
300 template<
301  template<typename, size_t> class ArrayType,
302  typename T,
303  size_t sizeA,
304  size_t sizeB
305 > constexpr std::enable_if_t<
306  sizeA == sizeB,
307  bool
309  const ArrayType<T, sizeA>& a,
310  const ArrayType<T, sizeB>& b
311 ) {
312  for(unsigned i = 0; i < sizeA; ++i) {
313  if(!(a.at(i) < b.at(i))) {
314  return false;
315  }
316  }
317 
318  return true;
319 }
320 
326 template<
327  template<typename, size_t> class ArrayType,
328  typename T,
329  size_t sizeA,
330  size_t sizeB
331 > constexpr std::enable_if_t<
332  sizeA < sizeB,
333  bool
334 > arraysLess(
335  const ArrayType<T, sizeA>& /* a */,
336  const ArrayType<T, sizeB>& /* b */
337 ) {
338  return true;
339 }
340 
346 template<
347  template<typename, size_t> class ArrayType,
348  typename T,
349  size_t sizeA,
350  size_t sizeB
351 > constexpr std::enable_if_t<
352  (sizeA > sizeB),
353  bool
354 > arraysLess(
355  const ArrayType<T, sizeA>& /* a */,
356  const ArrayType<T, sizeB>& /* b */
357 ) {
358  return false;
359 }
360 
361 // C++17: Replace all arraysLess functions with this single function below:
362 /*template<
363  template<typename, size_t> class ArrayType,
364  typename T,
365  size_t sizeA,
366  size_t sizeB
367 > constexpr std::enable_if_t<
368  (sizeA > sizeB),
369  bool
370 > arraysLess(
371  const ArrayType<T, sizeA>& a,
372  const ArrayType<T, sizeB>& b
373 ) {
374  if constexpr(sizeA < sizeB) {
375  return true;
376  } else if constexpr(sizeA > sizeB) {
377  return false;
378  } else { // sizes equal
379  for(unsigned i = 0; i < sizeA; ++i) {
380  if(!(a.at(i) < b.at(i))) {
381  return false;
382  }
383  }
384 
385  return true;
386  }
387 }*/
388 
397 template<
398  typename T,
399  class LessThanPredicate,
400  class Iter
401 > constexpr Iter lowerBound(
402  Iter bound,
403  Iter last,
404  const T& item,
405  LessThanPredicate predicate
406 ) {
407  using DiffType = decltype(last - bound);
408  static_assert(
409  std::is_signed<DiffType>::value,
410  "Difference between iterators must be a signed type!"
411  );
412 
413  Iter it = bound;
414  DiffType count = last - bound, step = 0;
415 
416  while(count > 0) {
417  it = bound;
418  step = count / 2;
419  it += step; // C++17 std::advance (differentiates between RandomAccess / linear)
420 
421  if(predicate(*it, item)) {
422  ++it;
423  bound = it;
424  count -= step + 1;
425  } else {
426  count = step;
427  }
428  }
429 
430  return bound;
431 }
432 
440 template<
441  class Container,
442  typename T,
443  class LessThanPredicate = std::less<>
444 > constexpr typename Container::const_iterator binarySearch(
445  const Container& container,
446  const T& item,
447  LessThanPredicate predicate = LessThanPredicate()
448 ) {
449  auto bound = lowerBound<T, LessThanPredicate>(
450  container.begin(),
451  container.end(),
452  item,
453  predicate
454  );
455 
456  /* Lower bound merely finds the first item not smaller than the sought one,
457  * this does NOT mean that they're equal.
458  *
459  * a == b <--> !(a < b) && !(b < a)
460  *
461  * Lower bound guarantees the first condition of the right side, but we need
462  * to check the second one to ensure that we have found what we seek, not just
463  * merely something bigger than a.
464  */
465  if(predicate(item, *bound)) {
466  return container.end();
467  }
468 
469  return bound;
470 }
471 
476 template<
477  template<typename, size_t> class ArrayType,
478  typename T,
479  size_t size
480 > constexpr void inPlaceSwap(
481  ArrayType<T, size>& data,
482  const size_t& a,
483  const size_t& b
484 ) {
485  T intermediate = std::move(data.at(b));
486  data.at(b) = std::move(data.at(a));
487  data.at(a) = std::move(intermediate);
488 }
489 
494 template<
495  template<typename, size_t> class ArrayType,
496  typename T,
497  size_t size
498 > constexpr void inPlaceReverse(
499  ArrayType<T, size>& data,
500  const unsigned indexFrom,
501  const unsigned indexTo
502 ) {
503  size_t a = indexFrom, b = indexTo;
504  while(a != b && a != --b) {
505  inPlaceSwap(data, a++, b);
506  }
507 }
508 
517 template<
518  template<typename, size_t> class ArrayType,
519  typename T,
520  size_t size
521 > constexpr std::enable_if_t<
522  (size > 1),
523  bool
524 > inPlaceNextPermutation(
525  ArrayType<T, size>& data,
526  const size_t& first,
527  const size_t& last
528 ) {
529  if(!(
530  first < last
531  && first < size
532  && last <= size
533  )) {
534  throw "Call parameters to inPlaceNextPermutation make no sense!";
535  }
536 
537  size_t i = last - 1, j = 0, k = 0;
538 
539  while(true) {
540  j = i;
541 
542  if(
543  i != 0
544  && data.at(--i) < data.at(j)
545  ) {
546  k = last;
547 
548  while(
549  k != 0
550  && !(
551  data.at(i) < data.at(--k)
552  )
553  ) {
554  // continue;
555  }
556 
557  inPlaceSwap(data, i, k);
558  inPlaceReverse(data, j, last);
559  return true;
560  }
561 
562  if(i == first) {
563  inPlaceReverse(data, first, last);
564  return false;
565  }
566  }
567 }
568 
570 template<
571  template<typename, size_t> class ArrayType,
572  typename T,
573  size_t size
574 > constexpr std::enable_if_t<
575  (size > 1),
576  bool
577 > inPlaceNextPermutation(ArrayType<T, size>& data) {
578  return inPlaceNextPermutation(data, 0, size);
579 }
580 
589 template<
590  template<typename, size_t> class ArrayType,
591  typename T,
592  size_t size
593 > constexpr std::enable_if_t<
594  (size > 1),
595  bool
596 > inPlacePreviousPermutation(
597  ArrayType<T, size>& data,
598  const size_t& first,
599  const size_t& last
600 ) {
601  if(!(
602  first < last
603  && first < size
604  && last <= size
605  )) {
606  throw "Call parameters to inPlaceNextPermutation make no sense!";
607  }
608 
609  size_t i = last - 1, j = 0, k = 0;
610 
611  while(true) {
612  j = i;
613 
614  if(
615  i != 0
616  && data.at(j) < data.at(--i)
617  ) {
618  k = last;
619 
620  while(
621  k != 0
622  && !(
623  data.at(--k) < data.at(i)
624  )
625  ) {
626  // continue;
627  }
628 
629  inPlaceSwap(data, i, k);
630  inPlaceReverse(data, j, last);
631  return true;
632  }
633 
634  if(i == first) {
635  inPlaceReverse(data, first, last);
636  return false;
637  }
638  }
639 }
640 
642 template<
643  template<typename, size_t> class ArrayType,
644  typename T,
645  size_t size
646 > constexpr std::enable_if_t<
647  (size > 1),
648  bool
649 > inPlacePreviousPermutation(ArrayType<T, size>& data) {
650  return inPlacePreviousPermutation(data, 0, size);
651 }
652 
657 template<
658  template<typename, size_t> class ArrayType,
659  typename T,
660  size_t size
661 > constexpr size_t permutationIndex(const ArrayType<T, size>& container) {
662  size_t index = 0;
663  size_t position = 2;// position 1 is paired with factor 0 and so is skipped
664  size_t factor = 1;
665 
666  for(size_t p = size - 2; p != std::numeric_limits<size_t>::max(); --p) {
667  size_t largerSuccessors = 0;
668 
669  for(size_t q = p + 1; q < size; ++q) {
670  if(container.at(p) > container.at(q)) {
671  ++largerSuccessors;
672  }
673  }
674 
675  index += (largerSuccessors * factor);
676  factor *= position;
677  ++position;
678  }
679 
680  return index;
681 }
682 
683 namespace Detail {
684  template<class ContainerType>
685  struct getValueTypeImpl {
686  using type = typename std::remove_const<
687  typename std::remove_reference<
688  decltype(
689  *(
690  std::declval<ContainerType>()
691  ).begin()
692  )
693  >::type
694  >::type;
695  };
696 } // namespace Detail
697 
699 template<class ContainerType>
700 using getValueType = typename Detail::getValueTypeImpl<ContainerType>::type;
701 
713 template<
714  class ContainerType,
715  class LessThanComparator = std::less<
716  getValueType<ContainerType>
717  >
718 > constexpr bool isPartiallyOrdered(
719  const ContainerType& container,
720  LessThanComparator comparator = LessThanComparator {}
721 ) {
722  auto leftIter = container.begin();
723  if(leftIter == container.end()) {
724  return true;
725  }
726 
727  auto rightIter = leftIter + 1;
728 
729  while(rightIter != container.end()) {
730  // equivalent to *rightIter < *leftIter
731  if(comparator(*rightIter, *leftIter)) {
732  return false;
733  }
734 
735  ++leftIter;
736  ++rightIter;
737  }
738 
739  return true;
740 }
741 
753 template<
754  class ContainerType,
755  class LessThanComparator = std::less<
756  getValueType<ContainerType>
757  >
758 > constexpr bool isTotallyOrdered(
759  const ContainerType& container,
760  LessThanComparator comparator = LessThanComparator {}
761 ) {
762  auto leftIter = container.begin();
763  if(leftIter == container.end()) {
764  return true;
765  }
766 
767  auto rightIter = leftIter + 1;
768 
769 
770  while(rightIter != container.end()) {
771  // Equivalent to !(*leftIter < *rightIter
772  if(!comparator(*leftIter, *rightIter)) {
773  return false;
774  }
775 
776  ++leftIter;
777  ++rightIter;
778  }
779 
780  return true;
781 }
782 
783 } // namespace Temple
784 } // namespace Molassembler
785 } // namespace Scine
786 
787 #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:145
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...
Temple::Array< T, size > ArrayType
Definition: Properties.h:143
Defines a set of useful preprocessor macros.
constexpr Get< 0 > first
Calls std::get&lt;0&gt; on any argument it is invoked with.
Definition: Functor.h:123
constexpr T reduce(const ArrayType< T, size > &array, T init, BinaryFunction &&reduction)
Reduce an array-like container with a binary function.
Definition: Containers.h:88
unsigned size(const Shape shape)
Fetch the number of vertices of a shape.
std::result_of_t< Function(Args...)> functionReturnType
Figure out the return type of calling a function.
Definition: Containers.h:25
constexpr bool arraysEqual(const ArrayType< T, size > &a, const ArrayType< T, size > &b)
Array-like container lexicographic equality comparaotr.
Definition: Containers.h:280
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:62
constexpr T sum(const ArrayType< T, size > &array)
Sum up all elements of an array-like class.
Definition: Containers.h:111
constexpr ArrayType< T,(end-begin)> range()
Range for any array type.
Definition: Containers.h:175
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:213
std::size_t permutationIndex(const Container &container)
Calculate the index of permutation of elements in a container.
Definition: Permutations.h:25
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:308
#define PURITY_STRONG
Definition: Preprocessor.h:65