Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 99 | pmbaty | 1 | /* |
| 2 | Texel - A UCI chess engine. |
||
| 3 | Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.com |
||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify |
||
| 6 | it under the terms of the GNU General Public License as published by |
||
| 7 | the Free Software Foundation, either version 3 of the License, or |
||
| 8 | (at your option) any later version. |
||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, |
||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 13 | GNU General Public License for more details. |
||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License |
||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
| 17 | */ |
||
| 18 | |||
| 19 | /* |
||
| 20 | * util.hpp |
||
| 21 | * |
||
| 22 | * Created on: Feb 26, 2012 |
||
| 23 | * Author: petero |
||
| 24 | */ |
||
| 25 | |||
| 26 | #ifndef UTIL_HPP_ |
||
| 27 | #define UTIL_HPP_ |
||
| 28 | |||
| 29 | #include <cstddef> |
||
| 30 | #include <cstdint> |
||
| 31 | #include <string> |
||
| 32 | #include <cstdlib> |
||
| 33 | #include <sstream> |
||
| 34 | #include <vector> |
||
| 35 | #include <array> |
||
| 36 | #include <algorithm> |
||
| 37 | #include <atomic> |
||
| 38 | #include <cctype> |
||
| 39 | #include <iomanip> |
||
| 40 | |||
| 41 | using U64 = uint64_t; |
||
| 42 | using S64 = int64_t; |
||
| 43 | using U32 = uint32_t; |
||
| 44 | using S32 = int32_t; |
||
| 45 | using U16 = uint16_t; |
||
| 46 | using S16 = int16_t; |
||
| 47 | using S8 = int8_t; |
||
| 48 | using U8 = uint8_t; |
||
| 49 | |||
| 50 | template <typename T, size_t N> char (&ArraySizeHelper(T(&array)[N]))[N]; |
||
| 51 | #define COUNT_OF(array) (sizeof(ArraySizeHelper(array))) |
||
| 52 | |||
| 53 | template <typename T> class AlignedAllocator; |
||
| 54 | /** std::vector with cache line aware allocator. */ |
||
| 55 | template <typename T> |
||
| 56 | class vector_aligned : public std::vector<T, AlignedAllocator<T>> { }; |
||
| 57 | |||
| 58 | |||
| 59 | /** Helper class to perform static initialization of a class T. */ |
||
| 60 | template <typename T> |
||
| 61 | class StaticInitializer { |
||
| 62 | public: |
||
| 63 | StaticInitializer() { |
||
| 64 | T::staticInitialize(); |
||
| 65 | } |
||
| 66 | }; |
||
| 67 | |||
| 68 | template <typename T> |
||
| 69 | T clamp(T val, T min, T max) { |
||
| 70 | if (val < min) |
||
| 71 | return min; |
||
| 72 | else if (val > max) |
||
| 73 | return max; |
||
| 74 | else |
||
| 75 | return val; |
||
| 76 | } |
||
| 77 | |||
| 78 | /** Return integer 2-logarithm of a positive number. */ |
||
| 79 | int floorLog2(U32 x); |
||
| 80 | |||
| 81 | // ---------------------------------------------------------------------------- |
||
| 82 | |||
| 83 | /** Split a string using " " as delimiter. Append words to out. */ |
||
| 84 | inline void |
||
| 85 | splitString(const std::string& str, std::vector<std::string>& out) |
||
| 86 | { |
||
| 87 | std::string word; |
||
| 88 | std::istringstream iss(str, std::istringstream::in); |
||
| 89 | while (iss >> word) |
||
| 90 | out.push_back(word); |
||
| 91 | } |
||
| 92 | |||
| 93 | /** Convert a string to a number. */ |
||
| 94 | template <typename T> |
||
| 95 | bool |
||
| 96 | str2Num(const std::string& str, T& result) { |
||
| 97 | std::stringstream ss(str); |
||
| 98 | ss >> result; |
||
| 99 | return !!ss; |
||
| 100 | } |
||
| 101 | #if defined(__linux__) && !defined(__arm__) && !defined(__ANDROID__) |
||
| 102 | inline bool |
||
| 103 | str2Num(const std::string& str, int& result) { |
||
| 104 | try { |
||
| 105 | result = std::stoi(str); |
||
| 106 | return true; |
||
| 107 | } catch (...) { |
||
| 108 | result = 0; |
||
| 109 | return false; |
||
| 110 | } |
||
| 111 | } |
||
| 112 | inline bool |
||
| 113 | str2Num(const std::string& str, double& result) { |
||
| 114 | try { |
||
| 115 | result = std::stod(str); |
||
| 116 | return true; |
||
| 117 | } catch (...) { |
||
| 118 | result = 0.0; |
||
| 119 | return false; |
||
| 120 | } |
||
| 121 | } |
||
| 122 | #endif |
||
| 123 | |||
| 124 | template <typename T> |
||
| 125 | bool |
||
| 126 | hexStr2Num(const std::string& str, T& result) { |
||
| 127 | std::stringstream ss; |
||
| 128 | ss << std::hex << str; |
||
| 129 | ss >> result; |
||
| 130 | return !!ss; |
||
| 131 | } |
||
| 132 | |||
| 133 | template <typename T> |
||
| 134 | inline std::string |
||
| 135 | num2Str(const T& num) { |
||
| 136 | std::stringstream ss; |
||
| 137 | ss << num; |
||
| 138 | return ss.str(); |
||
| 139 | } |
||
| 140 | |||
| 141 | inline std::string |
||
| 142 | num2Hex(U64 num) { |
||
| 143 | std::stringstream ss; |
||
| 144 | ss << std::hex << std::setw(16) << std::setfill('0') << num; |
||
| 145 | return ss.str(); |
||
| 146 | } |
||
| 147 | |||
| 148 | /** Convert string to lower case. */ |
||
| 149 | inline std::string |
||
| 150 | toLowerCase(std::string str) { |
||
| 151 | for (size_t i = 0; i < str.length(); i++) |
||
| 152 | str[i] = std::tolower(str[i]); |
||
| 153 | return str; |
||
| 154 | } |
||
| 155 | |||
| 156 | inline bool |
||
| 157 | startsWith(const std::string& str, const std::string& startsWith) { |
||
| 158 | size_t N = startsWith.length(); |
||
| 159 | if (str.length() < N) |
||
| 160 | return false; |
||
| 161 | for (size_t i = 0; i < N; i++) |
||
| 162 | if (str[i] != startsWith[i]) |
||
| 163 | return false; |
||
| 164 | return true; |
||
| 165 | } |
||
| 166 | |||
| 167 | inline bool |
||
| 168 | endsWith(const std::string& str, const std::string& endsWith) { |
||
| 169 | size_t N = endsWith.length(); |
||
| 170 | size_t sN = str.length(); |
||
| 171 | if (sN < N) |
||
| 172 | return false; |
||
| 173 | for (size_t i = 0; i < N; i++) |
||
| 174 | if (str[sN - N + i] != endsWith[i]) |
||
| 175 | return false; |
||
| 176 | return true; |
||
| 177 | } |
||
| 178 | |||
| 179 | /** Return true if vector v contains element e. */ |
||
| 180 | template <typename T> |
||
| 181 | inline bool |
||
| 182 | contains(const std::vector<T>& v, const T& e) { |
||
| 183 | return std::find(v.begin(), v.end(), e) != v.end(); |
||
| 184 | } |
||
| 185 | |||
| 186 | /** Return true if vector v contains element e converted to a string. */ |
||
| 187 | inline bool |
||
| 188 | contains(const std::vector<std::string> v, const char* e) { |
||
| 189 | return contains(v, std::string(e)); |
||
| 190 | } |
||
| 191 | |||
| 192 | inline std::string |
||
| 193 | trim(const std::string& s) { |
||
| 194 | for (int i = 0; i < (int)s.length(); i++) { |
||
| 195 | if (!isspace(s[i])) { |
||
| 196 | for (int j = (int)s.length()-1; j >= i; j--) |
||
| 197 | if (!isspace(s[j])) |
||
| 198 | return s.substr(i, j-i+1); |
||
| 199 | return ""; |
||
| 200 | } |
||
| 201 | } |
||
| 202 | return ""; |
||
| 203 | } |
||
| 204 | |||
| 205 | // ---------------------------------------------------------------------------- |
||
| 206 | |||
| 207 | // A fixed size array that can compute the sum of a range of values in time O(log N) |
||
| 208 | template <int N> |
||
| 209 | class RangeSumArray { |
||
| 210 | public: |
||
| 211 | |||
| 212 | /** Get value at index i. */ |
||
| 213 | int get(size_t i) const { |
||
| 214 | return arr[i]; |
||
| 215 | } |
||
| 216 | |||
| 217 | /** Add delta to value at index i. */ |
||
| 218 | void add(size_t i, int delta) { |
||
| 219 | arr[i] += delta; |
||
| 220 | pairs.add(i/2, delta); |
||
| 221 | } |
||
| 222 | |||
| 223 | /** Compute sum of all elements in [b,e). */ |
||
| 224 | int sum(size_t b, size_t e) const { |
||
| 225 | int result = 0; |
||
| 226 | sumHelper(b, e, result); |
||
| 227 | return result; |
||
| 228 | } |
||
| 229 | |||
| 230 | private: |
||
| 231 | template <int N2> friend class RangeSumArray; |
||
| 232 | |||
| 233 | void sumHelper(size_t b, size_t e, int& result) const { |
||
| 234 | if (b >= e) |
||
| 235 | return; |
||
| 236 | if (b & 1) { |
||
| 237 | result += arr[b]; |
||
| 238 | b++; |
||
| 239 | } |
||
| 240 | if (e & 1) { |
||
| 241 | if (e != N) |
||
| 242 | result -= arr[e]; |
||
| 243 | e++; |
||
| 244 | } |
||
| 245 | pairs.sumHelper(b/2, e/2, result); |
||
| 246 | } |
||
| 247 | |||
| 248 | std::array<std::atomic<int>, N> arr {}; |
||
| 249 | RangeSumArray<(N+1)/2> pairs; |
||
| 250 | }; |
||
| 251 | |||
| 252 | template<> |
||
| 253 | class RangeSumArray<1> { |
||
| 254 | public: |
||
| 255 | int get(size_t i) const { |
||
| 256 | return value; |
||
| 257 | } |
||
| 258 | |||
| 259 | void add(size_t i, int delta) { |
||
| 260 | value += delta; |
||
| 261 | } |
||
| 262 | |||
| 263 | int sum(size_t b, size_t e) const { |
||
| 264 | int result = 0; |
||
| 265 | sumHelper(b, e, result); |
||
| 266 | return result; |
||
| 267 | } |
||
| 268 | |||
| 269 | private: |
||
| 270 | template <int N2> friend class RangeSumArray; |
||
| 271 | |||
| 272 | void sumHelper(size_t b, size_t e, int& result) const { |
||
| 273 | if (b < e) |
||
| 274 | result += value; |
||
| 275 | } |
||
| 276 | |||
| 277 | std::atomic<int> value { 0 }; |
||
| 278 | }; |
||
| 279 | |||
| 280 | // ---------------------------------------------------------------------------- |
||
| 281 | |||
| 282 | /** Helper class for shared data where read/write accesses do not have to be sequentially ordered. |
||
| 283 | * This typically generates code as efficient as using a plain T. However using a plain T in this |
||
| 284 | * context would invoke undefined behavior, see section 1.10.21 in the C++11 standard. */ |
||
| 285 | template <typename T> |
||
| 286 | class RelaxedShared { |
||
| 287 | public: |
||
| 288 | RelaxedShared<T>() { } |
||
| 289 | RelaxedShared<T>(T value) { set(value); } |
||
| 290 | RelaxedShared<T>(const RelaxedShared<T>& r) { set(r.get()); } |
||
| 291 | RelaxedShared<T>& operator=(const RelaxedShared<T>& r) { set(r.get()); return *this; } |
||
| 292 | RelaxedShared<T>& operator=(const T& t) { set(t); return *this; } |
||
| 293 | operator T() const { return get(); } |
||
| 294 | T get() const { return data.load(std::memory_order_relaxed); } |
||
| 295 | void set(T value) { data.store(value, std::memory_order_relaxed); } |
||
| 296 | private: |
||
| 297 | std::atomic<T> data; |
||
| 298 | }; |
||
| 299 | |||
| 300 | #endif /* UTIL_HPP_ */ |