You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
840 lines
20 KiB
C
840 lines
20 KiB
C
|
4 years ago
|
/*! \file StdUtils.h
|
||
|
|
\brief useful functions working with std functions.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
Created: 2015/06/22, author: Jin Bingwen.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef __StdUtils_h_
|
||
|
|
#define __StdUtils_h_
|
||
|
|
|
||
|
|
#if (defined(_MSC_VER) && _MSC_VER <= 1600)
|
||
|
|
#define LITTLE_CPP11 1
|
||
|
|
#else
|
||
|
|
#include <thread>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if (defined _WINDOWS) || (defined WIN32)
|
||
|
|
#define USE_WIN_API 1
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if defined(__GNUC__) || defined(__clang__)
|
||
|
|
#define DEPRECATED __attribute__((deprecated))
|
||
|
|
#elif defined(_MSC_VER)
|
||
|
|
#define DEPRECATED __declspec(deprecated)
|
||
|
|
#else
|
||
|
|
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
|
||
|
|
#define DEPRECATED
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if _WIN64 || __x86_64__ || __ppc64__
|
||
|
|
#define CYCLOPS_64 1
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include "CyclopsVersion.h"
|
||
|
|
#include "CyclopsLock.h"
|
||
|
|
|
||
|
|
#include <vector>
|
||
|
|
#include <string>
|
||
|
|
#include <sstream>
|
||
|
|
#include <memory>
|
||
|
|
#include <map>
|
||
|
|
#include <fstream>
|
||
|
|
#include <algorithm>
|
||
|
|
#include <ctime>
|
||
|
|
#include <cctype>
|
||
|
|
|
||
|
|
#include "Asserte.h"
|
||
|
|
|
||
|
|
using std::string;
|
||
|
|
using std::vector;
|
||
|
|
using std::stringstream;
|
||
|
|
|
||
|
|
#if defined(LITTLE_CPP11)
|
||
|
|
#define GET_SIGN(x) (x < 0 ? true : false)
|
||
|
|
#else
|
||
|
|
#define GET_SIGN(x) std::signbit(x)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
inline unsigned int bitCount(unsigned int u)
|
||
|
|
{
|
||
|
|
unsigned int uCount;
|
||
|
|
|
||
|
|
uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
|
||
|
|
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T, typename _Iter>
|
||
|
|
T sum(_Iter s, _Iter e)
|
||
|
|
{
|
||
|
|
if (s == e)
|
||
|
|
{
|
||
|
|
return T();
|
||
|
|
}
|
||
|
|
T ret = *s;
|
||
|
|
s++;
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
ret += *s;
|
||
|
|
s++;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T, typename _Iter>
|
||
|
|
_Iter findTopNPercentEle(_Iter s, _Iter e, float nPersent)
|
||
|
|
{
|
||
|
|
auto maxVal = std::max_element(s, e);
|
||
|
|
T threVal = (*maxVal)*(1.0f - nPersent);
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
if (*s < threVal)
|
||
|
|
{
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
++s;
|
||
|
|
}
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T, typename _Iter>
|
||
|
|
_Iter findSumTopNPercentEle(_Iter s, _Iter e, float nPersent)
|
||
|
|
{
|
||
|
|
T sumVal = sum<T, _Iter>(s, e);
|
||
|
|
T threVal = sumVal*nPersent;
|
||
|
|
sumVal = 0;
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
sumVal += *s;
|
||
|
|
if (sumVal > threVal)
|
||
|
|
{
|
||
|
|
s++;
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
s++;
|
||
|
|
}
|
||
|
|
return e;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
void clearAndResetVec(vector<T>* vec, int n)
|
||
|
|
{
|
||
|
|
if (vec) {
|
||
|
|
vec->clear();
|
||
|
|
vec->reserve(n);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
void genIncVec(vector<T>& vec, T start, int count, T step)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < count; ++i)
|
||
|
|
{
|
||
|
|
vec.push_back(start);
|
||
|
|
start += step;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class SortEle
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
SortEle() : mSortVal(0), pEle(NULL) {}
|
||
|
|
SortEle(double val, const void* pData) : mSortVal(val), pEle(pData) {}
|
||
|
|
double mSortVal;
|
||
|
|
const void* pEle;
|
||
|
|
bool operator< (const SortEle& i)
|
||
|
|
{
|
||
|
|
return mSortVal < i.mSortVal;
|
||
|
|
}
|
||
|
|
bool operator>(const SortEle& i)
|
||
|
|
{
|
||
|
|
return mSortVal > i.mSortVal;
|
||
|
|
}
|
||
|
|
SortEle operator+ (const SortEle& i)
|
||
|
|
{
|
||
|
|
return SortEle(mSortVal + i.mSortVal, pEle);
|
||
|
|
}
|
||
|
|
void operator+= (const SortEle& i)
|
||
|
|
{
|
||
|
|
mSortVal += i.mSortVal;
|
||
|
|
}
|
||
|
|
SortEle operator- (const SortEle& i)
|
||
|
|
{
|
||
|
|
return SortEle(mSortVal - i.mSortVal, pEle);
|
||
|
|
}
|
||
|
|
operator float()
|
||
|
|
{
|
||
|
|
return (float)mSortVal;
|
||
|
|
}
|
||
|
|
operator double()
|
||
|
|
{
|
||
|
|
return mSortVal;
|
||
|
|
}
|
||
|
|
SortEle operator* (float f)
|
||
|
|
{
|
||
|
|
return SortEle(mSortVal*f, pEle);
|
||
|
|
}
|
||
|
|
void operator= (float f)
|
||
|
|
{
|
||
|
|
mSortVal = f;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
template<typename _It, typename _Ty>
|
||
|
|
_It findRange(_It s, _It e, const _Ty& val)
|
||
|
|
{
|
||
|
|
if (s == e)
|
||
|
|
{
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
_It mi = (e - s) / 2 + s;
|
||
|
|
if (val < *mi)
|
||
|
|
{
|
||
|
|
return findRange(s, mi, val);
|
||
|
|
}
|
||
|
|
else if (val > *mi)
|
||
|
|
{
|
||
|
|
return findRange(mi + 1, e, val);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return mi;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _Ty, typename _It>
|
||
|
|
void add(_It s, _It e, const _Ty& val)
|
||
|
|
{
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
*s += val;
|
||
|
|
s++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _Ty, typename _It>
|
||
|
|
bool allInRange(_It s, _It e, _Ty minVal, _Ty maxVal)
|
||
|
|
{
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
if (*s < minVal || *s > maxVal)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
++s;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _Ty, typename _It>
|
||
|
|
bool anyInRange(_It s, _It e, _Ty minVal, _Ty maxVal)
|
||
|
|
{
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
if (*s >= minVal && *s <= maxVal)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
++s;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _Ty, typename _It>
|
||
|
|
bool anyIn(_It s, _It e, _Ty v)
|
||
|
|
{
|
||
|
|
while (s != e)
|
||
|
|
{
|
||
|
|
if (*s == v)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
++s;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _T>
|
||
|
|
bool loadAValueFromFile(string filePath, _T& ret)
|
||
|
|
{
|
||
|
|
std::fstream fs;
|
||
|
|
fs.open(filePath, std::fstream::in);
|
||
|
|
if (!fs.is_open())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
fs >> ret;
|
||
|
|
fs.close();
|
||
|
|
}
|
||
|
|
|
||
|
|
// search range is [si, ei), not include ei
|
||
|
|
template<typename _PairIter>
|
||
|
|
_PairIter max_first_element(_PairIter si, _PairIter ei)
|
||
|
|
{
|
||
|
|
if (si == ei)
|
||
|
|
{
|
||
|
|
return ei;
|
||
|
|
}
|
||
|
|
|
||
|
|
// exclude ei
|
||
|
|
_PairIter ret = --ei;
|
||
|
|
ei++;
|
||
|
|
|
||
|
|
auto maxVal = si->first;
|
||
|
|
si++;
|
||
|
|
|
||
|
|
while (si != ei)
|
||
|
|
{
|
||
|
|
if (maxVal < si->first)
|
||
|
|
{
|
||
|
|
maxVal = si->first;
|
||
|
|
ret = si;
|
||
|
|
}
|
||
|
|
++si;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename _Ty0, typename _Ty1>
|
||
|
|
string joinStr(_Ty0 s0, _Ty1 s1)
|
||
|
|
{
|
||
|
|
stringstream ss;
|
||
|
|
ss << s0 << s1;
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
template<typename _Ty0, typename _Ty1, typename _Ty2>
|
||
|
|
string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2)
|
||
|
|
{
|
||
|
|
stringstream ss;
|
||
|
|
ss << s0 << s1 << s2;
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
template<typename _Ty0, typename _Ty1, typename _Ty2, typename _Ty3>
|
||
|
|
string joinStr(_Ty0 s0, _Ty1 s1, _Ty2 s2, _Ty3 s3)
|
||
|
|
{
|
||
|
|
stringstream ss;
|
||
|
|
ss << s0 << s1 << s2 << s3;
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
string toLower(const string& str);
|
||
|
|
string toUpper(const string& str);
|
||
|
|
|
||
|
|
vector<string> splitString(const string& str, const string& sep);
|
||
|
|
string mergeString(const vector<string>& strVec, const string& sep);
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
protected:\
|
||
|
|
type m##name;
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_GETFUN(type, name)\
|
||
|
|
public:\
|
||
|
|
type get##name() const { return m##name; }
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETFUN(type, name)\
|
||
|
|
public:\
|
||
|
|
void set##name(type val) { m##name = val; }
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETFUN2(type, name, val1, val2)\
|
||
|
|
public:\
|
||
|
|
void set##name(type val) {\
|
||
|
|
_ASSERTE(val >= val1 && val <= val2);\
|
||
|
|
if (val >= val1 && val <= val2) m##name = val; }
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETENUM(type, name)\
|
||
|
|
public:\
|
||
|
|
void set##name(type val) { m##name = val; }\
|
||
|
|
void set##name(int val) {\
|
||
|
|
set##name(static_cast<type>(val)); }
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETENUM2(type, name, val1, val2)\
|
||
|
|
public:\
|
||
|
|
void set##name(type val) {\
|
||
|
|
_ASSERTE(val >= val1 && val <= val2);\
|
||
|
|
if (val >= val1 && val <= val2) m##name = val; }\
|
||
|
|
void set##name(int val) {\
|
||
|
|
set##name(static_cast<type>(val)); }
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETPAIR(type, name)\
|
||
|
|
public:\
|
||
|
|
void set##name(type val1, type val2) {\
|
||
|
|
if (val1 > val2) { m##name##Start = val2; m##name##End = val1; }\
|
||
|
|
else { m##name##Start = val1; m##name##End = val2; }\
|
||
|
|
}
|
||
|
|
|
||
|
|
#define _DECLARE_PARAMETER_SETPAIR2(type, name, val1, val2)\
|
||
|
|
public:\
|
||
|
|
void set##name(type value1, type value2) {\
|
||
|
|
_ASSERTE(value1 >= val1 && value1 <= val2 && value2 >= val1 && value2 <= val2);\
|
||
|
|
if (value1 >= val1 && value1 <= val2 && value2 >= val1 && value2 <= val2) {\
|
||
|
|
if (value1 > value2) { m##name##Start = value2; m##name##End = value1; }\
|
||
|
|
else { m##name##Start = value1; m##name##End = value2; }\
|
||
|
|
}\
|
||
|
|
}
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER(type, name)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETFUN(type, name)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER2(type, name, val1, val2)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETFUN2(type, name, val1 , val2)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_SET(type, name)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETFUN(type, name)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_SET2(type, name, val1, val2)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETFUN2(type, name, val1, val2)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_GET(type, name)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_ENUM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETENUM(type, name)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_ENUM2(type, name, val1, val2)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name)\
|
||
|
|
_DECLARE_PARAMETER_SETENUM2(type, name, val1, val2)
|
||
|
|
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_PAIR(type, name)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name##Start)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name##End)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name##Start)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name##End)\
|
||
|
|
_DECLARE_PARAMETER_SETPAIR(type, name)
|
||
|
|
|
||
|
|
#define DECLARE_PARAMETER_PAIR2(type, name, val1, val2)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name##Start)\
|
||
|
|
_DECLARE_PARAMETER_MEM(type, name##End)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name##Start)\
|
||
|
|
_DECLARE_PARAMETER_GETFUN(type, name##End)\
|
||
|
|
_DECLARE_PARAMETER_SETPAIR2(type, name, val1, val2)
|
||
|
|
|
||
|
|
|
||
|
|
// Declare the provide class as a singleton.
|
||
|
|
// Get instance via Class::getInstance().
|
||
|
|
//
|
||
|
|
// Note: according to C++11 standard, static object initialization will
|
||
|
|
// be made only by one thread, other threads will wait till it complete.
|
||
|
|
// start from VS2014, this macro is thread-safe.
|
||
|
|
#define DECLARE_SINGLETON(type, ...)\
|
||
|
|
public:\
|
||
|
|
static type& getInstance() {\
|
||
|
|
static type inst(__VA_ARGS__);\
|
||
|
|
return inst;\
|
||
|
|
}
|
||
|
|
|
||
|
|
// Declare the provide class as a singleton.
|
||
|
|
// Get instance via Class::getInstance().
|
||
|
|
//
|
||
|
|
// Note: according to C++11 standard, static object initialization will
|
||
|
|
// be made only by one thread, other threads will wait till it complete.
|
||
|
|
// start from VS2014, this macro is thread-safe.
|
||
|
|
#define DECLARE_SINGLETON_NOPARA(type)\
|
||
|
|
public:\
|
||
|
|
static type& getInstance() {\
|
||
|
|
static type inst;\
|
||
|
|
return inst;\
|
||
|
|
}
|
||
|
|
|
||
|
|
// A simple version of object factory that use object name as key and hold object instances.
|
||
|
|
// It's thread-safe.
|
||
|
|
// Note: factory own the object instance, aka. own the object instance's memory, which means it will
|
||
|
|
// deallocate the memory when it self is destroyed (when the who application is shutdown).
|
||
|
|
// You don't need to delete the object instance yourself, and even worse, it will cause the double-delete crash.
|
||
|
|
// Use DECL_GET_INSTANCE to define getInstance() functions inside your class, and also IMPL_GET_INSTANCE in cpp.
|
||
|
|
template<typename T, typename TPtr,
|
||
|
|
typename std::enable_if<std::is_base_of<std::shared_ptr<T>, TPtr>::value>::type* = nullptr>
|
||
|
|
class ObjectFactory
|
||
|
|
{
|
||
|
|
DECLARE_SINGLETON_NOPARA(ObjectFactory)
|
||
|
|
|
||
|
|
public:
|
||
|
|
TPtr getObject(const char* name)
|
||
|
|
{
|
||
|
|
CyclopsLockGuard guard(&mLock);
|
||
|
|
auto it = mLookupTable.find(name);
|
||
|
|
if (it == mLookupTable.end()) {
|
||
|
|
// create new
|
||
|
|
TPtr ptr = std::make_shared<T>();
|
||
|
|
it = mLookupTable.insert(std::make_pair(name, ptr)).first;
|
||
|
|
}
|
||
|
|
return it->second;
|
||
|
|
}
|
||
|
|
TPtr getObject(const std::string& name) {
|
||
|
|
return getObject(name.c_str());
|
||
|
|
}
|
||
|
|
bool deleteObject(const char* name) {
|
||
|
|
CyclopsLockGuard guard(&mLock);
|
||
|
|
auto it = mLookupTable.find(name);
|
||
|
|
if (it == mLookupTable.end()) return false;
|
||
|
|
mLookupTable.erase(it);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
bool deleteObject(const std::string& name) {
|
||
|
|
return deleteObject(name.c_str());
|
||
|
|
}
|
||
|
|
bool updateObject(const char* name, TPtr obj) {
|
||
|
|
CyclopsLockGuard guard(&mLock);
|
||
|
|
mLookupTable[name] = obj;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
bool updateObject(const std::string& name, TPtr obj) {
|
||
|
|
return updateObject(name.c_str(), obj);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool isEmpty() {
|
||
|
|
CyclopsSharedLockGuard guard(&mLock);
|
||
|
|
return mLookupTable.empty();
|
||
|
|
}
|
||
|
|
vector<string> getAllEntries() {
|
||
|
|
CyclopsSharedLockGuard guard(&mLock);
|
||
|
|
vector<string> ret;
|
||
|
|
for (auto it = mLookupTable.begin(); it != mLookupTable.end(); ++it) {
|
||
|
|
ret.push_back(it->first);
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
ObjectFactory() {}
|
||
|
|
virtual ~ObjectFactory() {}
|
||
|
|
std::map<string, TPtr> mLookupTable;
|
||
|
|
CyclopsLock mLock;
|
||
|
|
};
|
||
|
|
|
||
|
|
#define DECL_GET_INSTANCE(TPtr)\
|
||
|
|
public:\
|
||
|
|
static TPtr getInstance(const char* name);\
|
||
|
|
static TPtr getInstance(const std::string& name);\
|
||
|
|
static bool deleteInstance(const char* name);\
|
||
|
|
static bool deleteInstance(const std::string& name);\
|
||
|
|
static bool updateInstance(const char* name, TPtr nobj);\
|
||
|
|
static bool updateInstance(const std::string& name, TPtr nobj);
|
||
|
|
|
||
|
|
#define IMPL_GET_INSTANCE(T, TPtr)\
|
||
|
|
TPtr T::getInstance(const char* name) { return ObjectFactory<T, TPtr>::getInstance().getObject(name);}\
|
||
|
|
TPtr T::getInstance(const std::string& name) { return getInstance(name.c_str());}\
|
||
|
|
bool T::deleteInstance(const char* name) { return ObjectFactory<T, TPtr>::getInstance().deleteObject(name); }\
|
||
|
|
bool T::deleteInstance(const std::string& name) { return deleteInstance(name.c_str()); }\
|
||
|
|
bool T::updateInstance(const char* name, TPtr obj) { return ObjectFactory<T, TPtr>::getInstance().updateObject(name, obj); }\
|
||
|
|
bool T::updateInstance(const std::string& name, TPtr obj) { return updateInstance(name.c_str(), obj); }
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
inline T ensureRng(T val, T minVal, T maxVal) {
|
||
|
|
return std::min<T>(maxVal, std::max<T>(minVal, val));
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
inline bool inRng(T val, T minVal, T maxVal) {
|
||
|
|
return val >= minVal && val <= maxVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
inline void rangeVector(std::vector<T>& vec, size_t n, size_t startIdx = 0) {
|
||
|
|
vec.reserve(n);
|
||
|
|
size_t endIdx = startIdx + n;
|
||
|
|
for (size_t i = startIdx; i < endIdx; ++i) vec.push_back((T)i);
|
||
|
|
}
|
||
|
|
|
||
|
|
#if !defined(LITTLE_CPP11)
|
||
|
|
#include <functional>
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
vector<size_t> sort_permutation(const vector<T>& vec, std::function<bool(const T&, const T&)> comparefunc, size_t n = 0, size_t startIdx = 0)
|
||
|
|
{
|
||
|
|
size_t vecSize = n > 0 ? n : vec.size();
|
||
|
|
vector<size_t> p;
|
||
|
|
if (vecSize == 0) return p;
|
||
|
|
rangeVector(p, vecSize, startIdx);
|
||
|
|
std::sort(p.begin(), p.end(), [&](size_t i, size_t j) {
|
||
|
|
return comparefunc(vec[i], vec[j]);
|
||
|
|
});
|
||
|
|
|
||
|
|
return p;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
vector<size_t> sort_permutation(vector<T>& vec, std::function<bool(T&, T&)> comparefunc, size_t n = 0, size_t startIdx = 0)
|
||
|
|
{
|
||
|
|
size_t vecSize = n > 0 ? n : vec.size();
|
||
|
|
vector<size_t> p;
|
||
|
|
if (vecSize == 0) return p;
|
||
|
|
rangeVector(p, vecSize, startIdx);
|
||
|
|
std::sort(p.begin(), p.end(), [&](size_t i, size_t j) {
|
||
|
|
return comparefunc(vec[i], vec[j]);
|
||
|
|
});
|
||
|
|
|
||
|
|
return p;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
vector<T> apply_permutation(const vector<T>& vec, const vector<size_t>& p)
|
||
|
|
{
|
||
|
|
vector<T> sorted_vec(vec.size());
|
||
|
|
std::transform(p.begin(), p.end(), sorted_vec.begin(),
|
||
|
|
[&](size_t i) { return vec[i]; });
|
||
|
|
return sorted_vec;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
vector<size_t> sort_permutation_partial(const vector<T>& vec,
|
||
|
|
std::function<bool(const T&, const T&)> comparefunc, size_t n)
|
||
|
|
{
|
||
|
|
size_t vecSize = vec.size();
|
||
|
|
vector<size_t> p(vecSize);
|
||
|
|
|
||
|
|
for (int i = 0; i < vecSize; ++i) p[i] = i;
|
||
|
|
std::partial_sort(p.begin(), p.begin() + n, p.end(), [&](size_t i, size_t j) {
|
||
|
|
return comparefunc(vec[i], vec[j]);
|
||
|
|
});
|
||
|
|
|
||
|
|
return p;
|
||
|
|
}
|
||
|
|
|
||
|
|
template <typename T>
|
||
|
|
vector<T> apply_permutation_partial(const vector<T>& vec, const vector<size_t>& p, size_t n)
|
||
|
|
{
|
||
|
|
vector<T> sorted_vec(n);
|
||
|
|
std::transform(p.begin(), p.begin() + n, sorted_vec.begin(),
|
||
|
|
[&](size_t i) { return vec[i]; });
|
||
|
|
return sorted_vec;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
T binarySearch(const T& startVal, const T& endVal, std::function<bool(const T& val)> searchFunc,
|
||
|
|
std::function<bool(const T& rng, const T& val)> stopFunc)
|
||
|
|
{
|
||
|
|
// startVal -> i -> endVal
|
||
|
|
T i = startVal, _startVal = startVal, _endVal = endVal;
|
||
|
|
do
|
||
|
|
{
|
||
|
|
bool ret = searchFunc(i);
|
||
|
|
T rng;
|
||
|
|
if (_startVal == i || ret) {
|
||
|
|
// converge towards endVal
|
||
|
|
_startVal = i;
|
||
|
|
i = (i + _endVal) / 2.;
|
||
|
|
rng = _startVal - i;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// converge towards startVal
|
||
|
|
_endVal = i;
|
||
|
|
i = (i + _startVal) / 2.;
|
||
|
|
rng = i - _endVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (stopFunc(rng, i)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
} while (true);
|
||
|
|
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if !defined(LITTLE_CPP11)
|
||
|
|
|
||
|
|
CYCLOPS_UTILS_SPEC std::string getCurTimeAsFileName();
|
||
|
|
|
||
|
|
std::vector<std::string> getAllFilesInFolder(const std::string& folderPath,
|
||
|
|
const std::vector<std::string>& validExtension);
|
||
|
|
|
||
|
|
inline std::vector<std::string> getAllImagesInFolder(const std::string& folderPath) {
|
||
|
|
return getAllFilesInFolder(folderPath, { ".png", ".bmp", ".jpg", ".jpeg" });
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string getFolderName(const std::string& folderPath);
|
||
|
|
|
||
|
|
std::string getFileName(const std::string& filePath, bool withExtension = true);
|
||
|
|
|
||
|
|
std::string getFileExtension(const std::string& filePath);
|
||
|
|
|
||
|
|
inline bool isImagePath(const std::string& filePath) {
|
||
|
|
string ext = getFileExtension(filePath);
|
||
|
|
return ext == ".png" || ext == ".bmp" || ext == ".jpg" || ext == ".jpeg";
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string makePathPreferred(const std::string& p);
|
||
|
|
|
||
|
|
bool isSamePath(const std::string& p1, const std::string& p2);
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
template<typename T>
|
||
|
|
class ObjectVectorIterator
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
// Construct the iterator, to make things easier, the iterator will take owner ship of the provide vector.
|
||
|
|
ObjectVectorIterator(std::vector<T>& takeVec) {
|
||
|
|
mVec = std::move(takeVec);
|
||
|
|
toFront();
|
||
|
|
}
|
||
|
|
ObjectVectorIterator(const ObjectVectorIterator& other) {
|
||
|
|
mVec = std::move(other.mVec);
|
||
|
|
mCurIndex = other.mCurIndex;
|
||
|
|
}
|
||
|
|
// Returns true if there is at least one item ahead of the iterator
|
||
|
|
inline bool hasNext() const {
|
||
|
|
return (!mVec.empty()) && ((mCurIndex == -1) || (mCurIndex < (mVec.size() - 1)));
|
||
|
|
}
|
||
|
|
inline bool hasPrevious() const {
|
||
|
|
return (mCurIndex >= 1) && (mCurIndex <= mVec.size());
|
||
|
|
}
|
||
|
|
inline T& next() {
|
||
|
|
return mVec.at(++mCurIndex);
|
||
|
|
}
|
||
|
|
inline T& previous() {
|
||
|
|
return mVec.at(--mCurIndex);
|
||
|
|
}
|
||
|
|
// Moves the iterator to the front of the container (before the first item).
|
||
|
|
inline void toFront() {
|
||
|
|
mCurIndex = -1;
|
||
|
|
}
|
||
|
|
// Moves the iterator to the back of the container (after the last item).
|
||
|
|
inline void toBack() {
|
||
|
|
mCurIndex = mVec.size();
|
||
|
|
}
|
||
|
|
// Moves the iterator to the middle of the container
|
||
|
|
inline void jumpTo(int idx) {
|
||
|
|
mCurIndex = ensureRng(idx - 1, -1, mVec.size());
|
||
|
|
}
|
||
|
|
// Return total size
|
||
|
|
inline size_t size() const {
|
||
|
|
return mVec.size();
|
||
|
|
}
|
||
|
|
// Get current index
|
||
|
|
inline int currentIndex() const {
|
||
|
|
return mCurIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::vector<T> mVec;
|
||
|
|
size_t mCurIndex;
|
||
|
|
};
|
||
|
|
|
||
|
|
#if !defined(LITTLE_CPP11)
|
||
|
|
|
||
|
|
#include <atomic>
|
||
|
|
class AsyncResult
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
typedef std::shared_ptr<AsyncResult> Ptr;
|
||
|
|
typedef std::function<void(AsyncResult*)> AsyncFunc;
|
||
|
|
|
||
|
|
enum {
|
||
|
|
AsyncNotStart = 9999,
|
||
|
|
AsyncRunning = 8888,
|
||
|
|
};
|
||
|
|
|
||
|
|
AsyncResult(AsyncFunc func, int total = 0)
|
||
|
|
: mFunc(func), mLock(), mSucceed(AsyncNotStart), mStopEarly(false), mTotal(0), mProgress(0)
|
||
|
|
{}
|
||
|
|
~AsyncResult() {
|
||
|
|
if (mThread.joinable())
|
||
|
|
mThread.detach();
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual void start() {
|
||
|
|
if (!mThread.joinable() && mSucceed == AsyncNotStart && mTotal == 0) {
|
||
|
|
CyclopsLockGuard write_gaurd(&mLock);
|
||
|
|
mSucceed = AsyncRunning;
|
||
|
|
mThread = std::thread(mFunc, this); // start if not start yet
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual float getStatus() {
|
||
|
|
if (!mThread.joinable() || (mSucceed != AsyncNotStart && mSucceed != AsyncRunning))
|
||
|
|
return 1; // thread is finished or not started
|
||
|
|
if (mSucceed == AsyncNotStart) {
|
||
|
|
return 0; // not started, or not running
|
||
|
|
}
|
||
|
|
else if (mSucceed == AsyncRunning) {
|
||
|
|
// running, calculate process percentage
|
||
|
|
if (mTotal <= 0) return 0;
|
||
|
|
int c = count();
|
||
|
|
return c == mTotal ? 0.99 // waiting for the succeed flag
|
||
|
|
: (float)(c) / mTotal;
|
||
|
|
}
|
||
|
|
// either succeed or fail
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual int count() { return mProgress; }
|
||
|
|
|
||
|
|
void waitForDone() {
|
||
|
|
if (mThread.joinable() && mSucceed == AsyncRunning) {
|
||
|
|
mThread.join();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void stop() { mStopEarly = true; }
|
||
|
|
bool isStopped() const { return mStopEarly; }
|
||
|
|
|
||
|
|
bool succeeded() const { return mSucceed > 0; }
|
||
|
|
|
||
|
|
int errorCode() const { return mSucceed; }
|
||
|
|
|
||
|
|
void setProgress(int val) { mProgress = val; }
|
||
|
|
|
||
|
|
std::string getNameById(int id) {
|
||
|
|
CyclopsSharedLockGuard gaurd(&mLock);
|
||
|
|
auto it = mIdNames.find(id);
|
||
|
|
if (it != mIdNames.end()) {
|
||
|
|
return it->second;
|
||
|
|
}
|
||
|
|
return std::string();
|
||
|
|
}
|
||
|
|
|
||
|
|
int getIdByName(const std::string& name) {
|
||
|
|
CyclopsSharedLockGuard gaurd(&mLock);
|
||
|
|
for (auto it = mIdNames.begin(); it != mIdNames.end(); ++it) {
|
||
|
|
if (it->second == name) {
|
||
|
|
return it->first;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
|
||
|
|
// for AsyncFunc to set succeed code when finished
|
||
|
|
// AsyncNotStart and AsyncRunning is reserved for status control
|
||
|
|
// > 0 for succeed, -1 for failure and error code
|
||
|
|
virtual void setSucceed(int val) {
|
||
|
|
mSucceed = val;
|
||
|
|
_ASSERTE(count() <= mTotal);
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual void registerTargetName(int id, const std::string& name) {
|
||
|
|
CyclopsLockGuard write_gaurd(&mLock);
|
||
|
|
mIdNames[id] = name;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
std::thread mThread;
|
||
|
|
std::atomic_int mSucceed;
|
||
|
|
std::atomic_bool mStopEarly;
|
||
|
|
CyclopsLock mLock;
|
||
|
|
std::atomic_int mTotal; // total number of tests
|
||
|
|
std::atomic_int mProgress; // simple implementation of async result
|
||
|
|
AsyncFunc mFunc;
|
||
|
|
std::map<int, std::string> mIdNames;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#endif // __StdUtils_h_
|