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_ */ |