/*
Texel - A UCI chess engine.
Copyright (C) 2012-2014 Peter Ă–sterlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* util.hpp
*
* Created on: Feb 26, 2012
* Author: petero
*/
#ifndef UTIL_HPP_
#define UTIL_HPP_
#include <cstddef>
#include <cstdint>
#include <string>
#include <cstdlib>
#include <sstream>
#include <vector>
#include <array>
#include <algorithm>
#include <atomic>
#include <cctype>
#include <iomanip>
using U64 = uint64_t;
using S64 = int64_t;
using U32 = uint32_t;
using S32 = int32_t;
using U16 = uint16_t;
using S16 = int16_t;
using S8 = int8_t;
using U8 = uint8_t;
template <typename T, size_t N> char (&ArraySizeHelper(T(&array)[N]))[N];
#define COUNT_OF(array) (sizeof(ArraySizeHelper(array)))
template <typename T> class AlignedAllocator;
/** std::vector with cache line aware allocator. */
template <typename T>
class vector_aligned : public std::vector<T, AlignedAllocator<T>> { };
/** Helper class to perform static initialization of a class T. */
template <typename T>
class StaticInitializer {
public:
StaticInitializer() {
T::staticInitialize();
}
};
template <typename T>
T clamp(T val, T min, T max) {
if (val < min)
return min;
else if (val > max)
return max;
else
return val;
}
/** Return integer 2-logarithm of a positive number. */
int floorLog2(U32 x);
// ----------------------------------------------------------------------------
/** Split a string using " " as delimiter. Append words to out. */
inline void
splitString(const std::string& str, std::vector<std::string>& out)
{
std::string word;
std::istringstream iss(str, std::istringstream::in);
while (iss >> word)
out.push_back(word);
}
/** Convert a string to a number. */
template <typename T>
bool
str2Num(const std::string& str, T& result) {
std::stringstream ss(str);
ss >> result;
return !!ss;
}
#if defined(__linux__) && !defined(__arm__) && !defined(__ANDROID__)
inline bool
str2Num(const std::string& str, int& result) {
try {
result = std::stoi(str);
return true;
} catch (...) {
result = 0;
return false;
}
}
inline bool
str2Num(const std::string& str, double& result) {
try {
result = std::stod(str);
return true;
} catch (...) {
result = 0.0;
return false;
}
}
#endif
template <typename T>
bool
hexStr2Num(const std::string& str, T& result) {
std::stringstream ss;
ss << std::hex << str;
ss >> result;
return !!ss;
}
template <typename T>
inline std::string
num2Str(const T& num) {
std::stringstream ss;
ss << num;
return ss.str();
}
inline std::string
num2Hex(U64 num) {
std::stringstream ss;
ss << std::hex << std::setw(16) << std::setfill('0') << num;
return ss.str();
}
/** Convert string to lower case. */
inline std::string
toLowerCase(std::string str) {
for (size_t i = 0; i < str.length(); i++)
str[i] = std::tolower(str[i]);
return str;
}
inline bool
startsWith(const std::string& str, const std::string& startsWith) {
size_t N = startsWith.length();
if (str.length() < N)
return false;
for (size_t i = 0; i < N; i++)
if (str[i] != startsWith[i])
return false;
return true;
}
inline bool
endsWith(const std::string& str, const std::string& endsWith) {
size_t N = endsWith.length();
size_t sN = str.length();
if (sN < N)
return false;
for (size_t i = 0; i < N; i++)
if (str[sN - N + i] != endsWith[i])
return false;
return true;
}
/** Return true if vector v contains element e. */
template <typename T>
inline bool
contains(const std::vector<T>& v, const T& e) {
return std::find(v.begin(), v.end(), e) != v.end();
}
/** Return true if vector v contains element e converted to a string. */
inline bool
contains(const std::vector<std::string> v, const char* e) {
return contains(v, std::string(e));
}
inline std::string
trim(const std::string& s) {
for (int i = 0; i < (int)s.length(); i++) {
if (!isspace(s[i])) {
for (int j = (int)s.length()-1; j >= i; j--)
if (!isspace(s[j]))
return s.substr(i, j-i+1);
return "";
}
}
return "";
}
// ----------------------------------------------------------------------------
// A fixed size array that can compute the sum of a range of values in time O(log N)
template <int N>
class RangeSumArray {
public:
/** Get value at index i. */
int get(size_t i) const {
return arr[i];
}
/** Add delta to value at index i. */
void add(size_t i, int delta) {
arr[i] += delta;
pairs.add(i/2, delta);
}
/** Compute sum of all elements in [b,e). */
int sum(size_t b, size_t e) const {
int result = 0;
sumHelper(b, e, result);
return result;
}
private:
template <int N2> friend class RangeSumArray;
void sumHelper(size_t b, size_t e, int& result) const {
if (b >= e)
return;
if (b & 1) {
result += arr[b];
b++;
}
if (e & 1) {
if (e != N)
result -= arr[e];
e++;
}
pairs.sumHelper(b/2, e/2, result);
}
std::array<std::atomic<int>, N> arr {};
RangeSumArray<(N+1)/2> pairs;
};
template<>
class RangeSumArray<1> {
public:
int get(size_t i) const {
return value;
}
void add(size_t i, int delta) {
value += delta;
}
int sum(size_t b, size_t e) const {
int result = 0;
sumHelper(b, e, result);
return result;
}
private:
template <int N2> friend class RangeSumArray;
void sumHelper(size_t b, size_t e, int& result) const {
if (b < e)
result += value;
}
std::atomic<int> value { 0 };
};
// ----------------------------------------------------------------------------
/** Helper class for shared data where read/write accesses do not have to be sequentially ordered.
* This typically generates code as efficient as using a plain T. However using a plain T in this
* context would invoke undefined behavior, see section 1.10.21 in the C++11 standard. */
template <typename T>
class RelaxedShared {
public:
RelaxedShared<T>() { }
RelaxedShared<T>(T value) { set(value); }
RelaxedShared<T>(const RelaxedShared<T>& r) { set(r.get()); }
RelaxedShared<T>& operator=(const RelaxedShared<T>& r) { set(r.get()); return *this; }
RelaxedShared<T>& operator=(const T& t) { set(t); return *this; }
operator T() const { return get(); }
T get() const { return data.load(std::memory_order_relaxed); }
void set(T value) { data.store(value, std::memory_order_relaxed); }
private:
std::atomic<T> data;
};
#endif /* UTIL_HPP_ */