Molassembler  1.2.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 
301 template<
302  template<typename, std::size_t> class ArrayType,
303  typename T,
304  std::size_t sizeA,
305  std::size_t sizeB
306 > constexpr std::enable_if_t<
307  sizeA == sizeB,
308  bool
310  const ArrayType<T, sizeA>& a,
311  const ArrayType<T, sizeB>& b
312 ) {
313  for(unsigned i = 0; i < sizeA; ++i) {
314  if(!(a.at(i) < b.at(i))) {
315  return false;
316  }
317  }
318 
319  return true;
320 }
321 
327 template<
328  template<typename, std::size_t> class ArrayType,
329  typename T,
330  std::size_t sizeA,
331  std::size_t sizeB
332 > constexpr std::enable_if_t<
333  sizeA < sizeB,
334  bool
335 > arraysLess(
336  const ArrayType<T, sizeA>& /* a */,
337  const ArrayType<T, sizeB>& /* b */
338 ) {
339  return true;
340 }
341 
347 template<
348  template<typename, std::size_t> class ArrayType,
349  typename T,
350  std::size_t sizeA,
351  std::size_t sizeB
352 > constexpr std::enable_if_t<
353  (sizeA > sizeB),
354  bool
355 > arraysLess(
356  const ArrayType<T, sizeA>& /* a */,
357  const ArrayType<T, sizeB>& /* b */
358 ) {
359  return false;
360 }
361 
362 // C++17: Replace all arraysLess functions with this single function below:
363 /*template<
364  template<typename, std::size_t> class ArrayType,
365  typename T,
366  std::size_t sizeA,
367  std::size_t sizeB
368 > constexpr std::enable_if_t<
369  (sizeA > sizeB),
370  bool
371 > arraysLess(
372  const ArrayType<T, sizeA>& a,
373  const ArrayType<T, sizeB>& b
374 ) {
375  if constexpr(sizeA < sizeB) {
376  return true;
377  } else if constexpr(sizeA > sizeB) {
378  return false;
379  } else { // sizes equal
380  for(unsigned i = 0; i < sizeA; ++i) {
381  if(!(a.at(i) < b.at(i))) {
382  return false;
383  }
384  }
385 
386  return true;
387  }
388 }*/
389 
398 template<
399  typename T,
400  class LessThanPredicate,
401  class Iter
402 > constexpr Iter lowerBound(
403  Iter bound,
404  Iter last,
405  const T& item,
406  LessThanPredicate predicate
407 ) {
408  using DiffType = decltype(last - bound);
409  static_assert(
410  std::is_signed<DiffType>::value,
411  "Difference between iterators must be a signed type!"
412  );
413 
414  Iter it = bound;
415  DiffType count = last - bound;
416  DiffType step = 0;
417 
418  while(count > 0) {
419  it = bound;
420  step = count / 2;
421  it += step; // C++17 std::advance (differentiates between RandomAccess / linear)
422 
423  if(predicate(*it, item)) {
424  ++it;
425  bound = it;
426  count -= step + 1;
427  } else {
428  count = step;
429  }
430  }
431 
432  return bound;
433 }
434 
442 template<
443  class Container,
444  typename T,
445  class LessThanPredicate = std::less<>
446 > constexpr typename Container::const_iterator binarySearch(
447  const Container& container,
448  const T& item,
449  LessThanPredicate predicate = LessThanPredicate()
450 ) {
451  auto bound = lowerBound<T, LessThanPredicate>(
452  container.begin(),
453  container.end(),
454  item,
455  predicate
456  );
457 
458  /* Lower bound merely finds the first item not smaller than the sought one,
459  * this does NOT mean that they're equal.
460  *
461  * a == b <--> !(a < b) && !(b < a)
462  *
463  * Lower bound guarantees the first condition of the right side, but we need
464  * to check the second one to ensure that we have found what we seek, not just
465  * merely something bigger than a.
466  */
467  if(predicate(item, *bound)) {
468  return container.end();
469  }
470 
471  return bound;
472 }
473 
474 namespace Detail {
475  template<class ContainerType>
476  struct getValueTypeImpl {
477  using type = typename std::remove_const<
478  typename std::remove_reference<
479  decltype(
480  *(std::declval<ContainerType>()).begin()
481  )
482  >::type
483  >::type;
484  };
485 } // namespace Detail
486 
488 template<class ContainerType>
489 using getValueType = typename Detail::getValueTypeImpl<ContainerType>::type;
490 
502 template<
503  class ContainerType,
504  class LessThanComparator = std::less<
505  getValueType<ContainerType>
506  >
507 > constexpr bool isPartiallyOrdered(
508  const ContainerType& container,
509  LessThanComparator comparator = LessThanComparator {}
510 ) {
511  auto leftIter = container.begin();
512  if(leftIter == container.end()) {
513  return true;
514  }
515 
516  auto rightIter = leftIter + 1;
517 
518  while(rightIter != container.end()) {
519  // equivalent to *rightIter < *leftIter
520  if(comparator(*rightIter, *leftIter)) {
521  return false;
522  }
523 
524  ++leftIter;
525  ++rightIter;
526  }
527 
528  return true;
529 }
530 
542 template<
543  class ContainerType,
544  class LessThanComparator = std::less<
545  getValueType<ContainerType>
546  >
547 > constexpr bool isTotallyOrdered(
548  const ContainerType& container,
549  LessThanComparator comparator = LessThanComparator {}
550 ) {
551  auto leftIter = container.begin();
552  if(leftIter == container.end()) {
553  return true;
554  }
555 
556  auto rightIter = leftIter + 1;
557 
558 
559  while(rightIter != container.end()) {
560  // Equivalent to !(*leftIter < *rightIter
561  if(!comparator(*leftIter, *rightIter)) {
562  return false;
563  }
564 
565  ++leftIter;
566  ++rightIter;
567  }
568 
569  return true;
570 }
571 
572 } // namespace Temple
573 } // namespace Molassembler
574 } // namespace Scine
575 
576 #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...
Temple::Array< T, size > ArrayType
Definition: Properties.h:144
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
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
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
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:309
#define PURITY_STRONG
Definition: Preprocessor.h:65