Line data Source code
1 : /* 2 : * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved. 3 : * 4 : * This file is part of the pairinteraction library. 5 : * 6 : * The pairinteraction library is free software: you can redistribute it and/or modify 7 : * it under the terms of the GNU Lesser General Public License as published by 8 : * the Free Software Foundation, either version 3 of the License, or 9 : * (at your option) any later version. 10 : * 11 : * The pairinteraction library is distributed in the hope that it will be useful, 12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : * GNU Lesser General Public License for more details. 15 : * 16 : * You should have received a copy of the GNU Lesser General Public License 17 : * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>. 18 : */ 19 : 20 : #ifndef UTILS_H 21 : #define UTILS_H 22 : 23 : #include <algorithm> 24 : #include <array> 25 : #include <complex> 26 : #include <functional> 27 : #include <random> 28 : #include <type_traits> 29 : 30 : #ifdef _WIN32 31 : #include <Windows.h> 32 : #else 33 : #include <unistd.h> 34 : #endif 35 : 36 : namespace utils { 37 : 38 : template <typename T> 39 : struct is_complex : std::false_type {}; 40 : template <typename S> 41 : struct is_complex<std::complex<S>> : std::true_type {}; 42 : 43 : template <typename T> 44 0 : inline T conjugate(const T &val) { 45 0 : return val; 46 : } 47 : template <typename S> 48 0 : inline std::complex<S> conjugate(const std::complex<S> &val) { 49 0 : return std::conj(val); 50 : } 51 : 52 : template <typename T> 53 169 : inline bool is_true(const T &val) { 54 338 : return std::all_of(val.begin(), val.end(), [](bool i) { return i; }); 55 : } 56 125 : inline bool is_true(bool val) { return val; } 57 : 58 : template <typename T> 59 0 : inline typename std::enable_if<!is_complex<T>::value, T>::type imaginary_unit() { 60 0 : throw std::runtime_error( 61 : "For operations that invoke the imaginary number, a complex data type is needed."); 62 : } 63 : template <typename T> 64 28 : inline typename std::enable_if<is_complex<T>::value, T>::type imaginary_unit() { 65 28 : return {0, 1}; 66 : } 67 : 68 : template <typename T, typename U> 69 4380 : inline T convert(const U &val) { 70 4380 : return val; 71 : } 72 : template <typename S> 73 152 : inline S convert(const std::complex<S> &val) { 74 152 : return std::real(val); 75 : } 76 : 77 : /** \brief Thread-local static random engine 78 : * 79 : * To save some effort this function initializes a static thread-local 80 : * random engine to avoid race conditions and broken random sampling. 81 : * It is seeded once using `std::random_device` for good entropy. 82 : * 83 : * \returns Reference to static thread-local random engine 84 : */ 85 1 : inline std::default_random_engine &randint_engine() { 86 1 : static thread_local std::default_random_engine eng{std::random_device{}()}; 87 1 : return eng; 88 : } 89 : 90 : /** \brief Generate a random integer 91 : * 92 : * This is very similar to the implementation of randint in the GCC 93 : * standard library Fundamentals TS v2. It is specified by the 94 : * standard per clause 13.2.2.1, Function template randint. 95 : * 96 : * The function generates a random integer in the closed interval 97 : * [\p a,\p b]. 98 : * 99 : * \param a lower bound 100 : * \param b upper bound 101 : * \returns random integer between \p a and \p b. 102 : */ 103 : template <typename T> 104 1 : inline T randint(T a, T b) { 105 : static_assert(std::is_integral<T>::value && sizeof(T) > 1, "The type must be an integer!"); 106 1 : return std::uniform_int_distribution<T>(a, b)(randint_engine()); 107 : } 108 : 109 : // https://de.wikipedia.org/wiki/FNV_(Informatik) 110 0 : inline uint64_t FNV64(const uint8_t *s, size_t sz) { 111 0 : const uint64_t magicPrime = 0x00000100000001b3; 112 0 : uint64_t hash = 0xcbf29ce484222325; 113 : 114 0 : for (size_t i = 0; i < sz; ++i) { 115 0 : hash = (hash ^ s[i]) * magicPrime; 116 : } 117 0 : return hash; 118 : } 119 : 120 308 : inline long get_pid() { 121 : #ifdef _WIN32 122 : return GetCurrentProcessId(); 123 : #else 124 308 : return ::getpid(); 125 : #endif 126 : } 127 : 128 : /// \brief Hash function 129 : /// 130 : /// The `std::hash` template allows specialization but only for types that are 131 : /// not in the standard library. This means that we cannot specialize 132 : /// `std::hash` for, e.g. `std::array`. To this end we define a struct `hash` 133 : /// which just inherits from `std::hash` by default. 134 : /// 135 : /// \tparam Key type to be hashed 136 : template <typename Key> 137 : struct hash; 138 : 139 : /// \brief Combine hashes 140 : /// 141 : /// The implementation of `hash_combine` is copied from Boost but simplified. 142 : /// It uses the custom `hash`. 143 : /// 144 : /// \param seed start hash 145 : /// \param v value whose hash is to be added to \p seed 146 : template <typename T> 147 26104435 : inline void hash_combine(std::size_t &seed, T const &v) { 148 : hash<T> hasher; 149 26104435 : seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 150 26104435 : } 151 : 152 : /// \brief Combine hashes of values in a range 153 : /// 154 : /// \param first forward iterator 155 : /// \param last forward iterator 156 : /// \returns combined hash of all values in the range 157 : template <typename It> 158 5106180 : inline std::size_t hash_range(It first, It last) { 159 5106180 : std::size_t seed = 0; 160 15318584 : for (; first != last; ++first) { 161 10212404 : hash_combine(seed, *first); 162 : } 163 5106180 : return seed; 164 : } 165 : 166 : // By default use std::hash 167 : template <typename T> 168 : struct hash : std::hash<T> {}; 169 : 170 : // Specializations for other types 171 : template <typename T, std::size_t N> 172 : struct hash<std::array<T, N>> { 173 : using argument_type = std::array<T, N>; 174 : using result_type = std::size_t; 175 5106178 : std::size_t operator()(std::array<T, N> const &a) const { 176 5106178 : return hash_range(a.begin(), a.end()); 177 : } 178 : }; 179 : 180 : template <typename T> 181 : struct hash<std::complex<T>> { 182 : using argument_type = std::complex<T>; 183 : using result_type = std::size_t; 184 0 : std::size_t operator()(std::complex<T> const &c) const { 185 0 : std::size_t seed = 0; 186 0 : hash_combine(seed, c.real()); 187 0 : hash_combine(seed, c.imag()); 188 0 : return seed; 189 : } 190 : }; 191 : 192 : } // namespace utils 193 : 194 : #endif // UTILS_H