//////////////////////////////////////////////////////////////////// // Util.h // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) #ifndef __SEACAVE_UTIL_H__ #define __SEACAVE_UTIL_H__ // I N C L U D E S ///////////////////////////////////////////////// #ifdef _MSC_VER #include #else #include #include #endif // D E F I N E S /////////////////////////////////////////////////// #define PATH_SEPARATOR _T('/') #define PATH_SEPARATOR_STR _T("/") #define REVERSE_PATH_SEPARATOR _T('\\') #ifdef _MSC_VER #define LINE_SEPARATOR_STR _T("\r\n") #define LINE_SEPARATOR_LEN 2 #else #define LINE_SEPARATOR_STR _T("\n") #define LINE_SEPARATOR_LEN 1 #endif #ifdef _MSC_VER #define SETTINGS_PATH _T("%APPDATA%") #else #define SETTINGS_PATH _T("~/.config") #endif #define ensureUnifySlashWin ensureUnifyReverseSlash #define ensureUnifySlashUnix ensureUnifySlash #define GET_TICK() Util::getTick() #define GET_TIME() Util::getTime() #define SIMD_ENABLED Util::ms_CPUFNC namespace SEACAVE { // S T R U C T S /////////////////////////////////////////////////// // Manage setting/removing bit flags template class TFlags { public: typedef TYPE Type; public: inline TFlags() : flags(0) { } inline TFlags(const TFlags& rhs) : flags(rhs.flags) { } inline TFlags(Type f) : flags(f) { } inline bool isSet(Type aFlag) const { return (flags & aFlag) == aFlag; } inline bool isSet(Type aFlag, Type nF) const { return (flags & (aFlag|nF)) == aFlag; } inline bool isSetExclusive(Type aFlag) const { return flags == aFlag; } inline bool isAnySet(Type aFlag) const { return (flags & aFlag) != 0; } inline bool isAnySet(Type aFlag, Type nF) const { const Type m(flags & (aFlag|nF)); return m != 0 && (m & nF) == 0; } inline bool isAnySetExclusive(Type aFlag) const { return (flags & aFlag) != 0 && (flags & ~aFlag) == 0; } inline void set(Type aFlag, bool bSet) { if (bSet) set(aFlag); else unset(aFlag); } inline void set(Type aFlag) { flags |= aFlag; } inline void unset(Type aFlag) { flags &= ~aFlag; } inline void flip(Type aFlag) { flags ^= aFlag; } inline void operator=(TFlags rhs) { flags = rhs.flags; } inline operator Type() const { return flags; } inline operator Type&() { return flags; } protected: Type flags; #ifdef _USE_BOOST // implement BOOST serialization friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int /*version*/) { ar & flags; } #endif }; typedef class GENERAL_API TFlags Flags; /*----------------------------------------------------------------*/ // A histogram class, that computes the distribution function (df) // of unique sended value or iterable data inside the provided range. // The Histogram object can keep a tally of values within a range, // the range is arranged into some number of bins specified during // construction. // Jansson Consulting // 2009-06-30, updated 2011-06-17 and 2011-08-03 // 2011-12-17 Modified by Pierre Moulon // - use vector array to avoid memory management // - add value by sequence with iterator // 2015-04-04 Modified by cDc // - rewrite // - add GetApproximatePermille() // Dedicated to the public domain. template class THistogram { public: typedef TYPE Type; public: // Construct a histogram that can count within a range of values. // All bins of the histogram are set to zero. THistogram(const std::pair& range, size_t bins=10) : Start(range.first), End(range.second), BinInterval(Type(bins)/(End-Start)), Freq(bins, 0), Overflow(0), Underflow(0) {} // Construct a histogram from a sequence of data template void Add(DataInputIterator begin, DataInputIterator end) { for (DataInputIterator iter = begin; iter != end; ++iter) Add(static_cast(*iter)); } // Increase the count for the bin that holds a value that is in range // for this histogram or the under-/overflow count if it is not in range void Add(const Type& x) { if (x < Start) { ++Underflow; } else { const size_t i(static_cast((x-Start)*BinInterval)); if (i < Freq.size()) ++Freq[i]; else ++Overflow; } } // Get the sum of all counts in the histogram inline size_t GetTotalCount() const { return std::accumulate(Freq.begin(), Freq.end(), 0); } // Get the overflow count inline size_t GetOverflow() const { return Overflow; } // Get the underflow count inline size_t GetUnderflow() const { return Underflow; } // Get frequencies inline const std::vector& GetHist() const { return Freq; } // Get XbinsValue std::vector GetXbinsValue() const { const size_t NBins(Freq.size()); std::vector vec_XbinValue(NBins); const Type val((End-Start)/static_cast(NBins-1)); for (size_t i = 0; i < NBins; ++i) vec_XbinValue[i] = (val*static_cast(i) + Start); return vec_XbinValue; } // Get start inline Type GetStart() const { return Start; } // Get End inline Type GetEnd() const { return End; } // Returns the approximate permille Type GetApproximatePermille(float permille) const { ASSERT(permille >= 0.f && permille <= 1.f); size_t NumValues(0); for (size_t n: Freq) NumValues += n; size_t Num(0); Type UpperBound(Start); for (size_t i = 0; i < Freq.size(); ++i) { if (static_cast(Num)/NumValues > permille) return UpperBound; Num += Freq[i]; UpperBound = (static_cast(i)*End)/(Freq.size()-1)+Start; } return End; } // Text display of the histogram std::string ToString(const std::string& sTitle = "") const { std::ostringstream os; os.precision(3); os << sTitle << "\n"; const size_t n(Freq.size()); for (size_t i = 0; i < n; ++i) os << static_cast(End-Start)/n*static_cast(i) << "\t|\t" << Freq[i] << "\n"; os << End << "\n"; return os.str(); } protected: const Type Start, End, BinInterval; // min/max/step of values std::vector Freq; // histogram size_t Overflow, Underflow; // count under/over flow }; typedef class GENERAL_API THistogram Histogram32F; typedef class GENERAL_API THistogram Histogram64F; /*----------------------------------------------------------------*/ class GENERAL_API Util { public: static String getAppName() { #ifdef _MSC_VER TCHAR buf[MAX_PATH+1]; GetModuleFileName(NULL, buf, MAX_PATH); return ensureUnifySlash(String(buf)); #else // _MSC_VER LPTSTR home = getenv("HOME"); if (home == NULL) return String(); String name(String(home) + "/app"); return ensureUnifySlash(name); #endif // _MSC_VER } // generate a unique name based on process ID and time static String getUniqueName(TCHAR dash='-') { TCHAR szDate[256]; #ifdef _MSC_VER SYSTEMTIME st; GetLocalTime(&st); LPTSTR szTime = szDate+ GetDateFormat(LOCALE_USER_DEFAULT,0,&st,_T("yy''MM''dd"),szDate,80); GetTimeFormat(LOCALE_USER_DEFAULT,0,&st,_T("HH''mm''ss"),szTime,80); #else // _MSC_VER const time_t t = time(NULL); const struct tm *tmp = localtime(&t); LPTSTR szTime = szDate+1+ strftime(szDate, 80, "%y%m%d", tmp); strftime(szTime, 80, "%H%M%S", tmp); #endif // _MSC_VER const uint32_t ID((uint32_t(__PROCESS__) + RAND())&0x00FFFFFF); if (dash) return String::FormatString("%s%c%s%c%06X", szDate, dash, szTime, dash, ID); return String::FormatString("%s%s%06X", szDate, szTime, ID); } static String translateError(int aError) { #ifdef _MSC_VER LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, aError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); String tmp((LPCTSTR)lpMsgBuf); // Free the buffer. LocalFree(lpMsgBuf); String::size_type i; while ((i = tmp.find_last_of(LINE_SEPARATOR_STR)) != String::npos) tmp.erase(i, LINE_SEPARATOR_LEN); return tmp; #else // _MSC_VER return strerror(aError); #endif // _MSC_VER } static String& trimUnifySlash(String& path) { String::size_type start = 1; while ((start = path.find(PATH_SEPARATOR, start)) != String::npos) if (path[start-1] == PATH_SEPARATOR) path.erase(start, 1); else ++start; return path; } static String& ensureUnifySlash(String& path) { String::size_type start = 0; while ((start = path.find(REVERSE_PATH_SEPARATOR, start)) != String::npos) path[start] = PATH_SEPARATOR; return trimUnifySlash(path); } static String& ensureUnifyReverseSlash(String& path) { String::size_type start = 0; while ((start = path.find(PATH_SEPARATOR, start)) != String::npos) path[start] = REVERSE_PATH_SEPARATOR; return path; } static String& ensureFolderSlash(String& path) { if (path.empty()) return path; String::size_type nEnd = path.size()-1; if (path[nEnd] != PATH_SEPARATOR) path += PATH_SEPARATOR; return path; } static void ensureFolder(const String& path) { String::size_type start = 0; while ((start = path.find(PATH_SEPARATOR, start)) != String::npos) #ifdef _MSC_VER CreateDirectory(path.substr(0, ++start).c_str(), NULL); #else mkdir(path.substr(0, ++start).c_str(), 0755); #endif } static String& ensureValidPath(String& path) { return simplifyPath(ensureUnifySlash(strTrim(path, _T("\"")))); } static String& ensureValidFolderPath(String& path) { return simplifyPath(ensureFolderSlash(ensureUnifySlash(strTrim(path, _T("\""))))); } static inline bool isFullPath(LPCTSTR path) { // returns true if local drive full path or network path return (path && ( #ifdef _MSC_VER (path[1]==_T(':') && path[0]!=_T('\0')) || #else // _MSC_VER path[0]==_T('/') || #endif // _MSC_VER #ifdef UNICODE *reinterpret_cast(path)==0x5C005C00/*"\\\\"*/)); #else *reinterpret_cast(path)==0x5C5C/*"\\\\"*/)); #endif // UNICODE } static String getFullPath(const String& str) { if (isFullPath(str)) return str; return getCurrentFolder()+str; } static inline bool isParentFolder(LPCTSTR path, int off=0) { // returns true if the folder starting at the given position in path is the parent folder ".." if (off < 0 || path[off] != _T('.')) return false; if (off > 0 && path[off-1] != PATH_SEPARATOR) return false; if (path[off+1] != _T('.')) return false; return path[off+2] == _T('\0') || path[off+2] == PATH_SEPARATOR; } static String getHomeFolder(); static String getApplicationFolder(); static String getCurrentFolder(); static String getProcessFolder() { return getFilePath(getAppName()); } static String ensureUnitPath(const String& path) { if (path.find(_T(" ")) == String::npos) return path; return String(_T("\"")+path+_T("\"")); } static String& simplifyPath(String& path) { // compress path by removing all "./" and "folder/../" occurrences // (if path only, it should end in path-separator) { // removes all "./" occurrences String::size_type i(0); while ((i = path.find(_T(".") PATH_SEPARATOR_STR, i)) != String::npos) { if (i > 0 && path[i-1] != PATH_SEPARATOR) i += 2; else path.erase(i, 2); }} { // removes all "folder/../" occurrences String::size_type i(0); while ((i = path.find(_T("..") PATH_SEPARATOR_STR, i)) != String::npos) { if (i > 1 && path[i-1] == PATH_SEPARATOR) { String::size_type prev = path.rfind(PATH_SEPARATOR, i-2); if (prev == String::npos) prev = 0; else ++prev; if (!isParentFolder(path, (int)prev)) { path.erase(prev, i+3-prev); i = prev; continue; } } i += 3; }} return path; } static String getSimplifiedPath(String path) { return simplifyPath(path); } static String getRelativePath(const String& currentPath, const String& targetPath) { // returns the path to the target relative to the current path; // both current and target paths must be full paths; // current path is assumed to be a folder, while target path can be also a file CLISTDEF2(String) currentPathValues, targetPathValues; Util::strSplit(currentPath, PATH_SEPARATOR, currentPathValues); if (currentPathValues.back().empty()) currentPathValues.pop_back(); Util::strSplit(targetPath, PATH_SEPARATOR, targetPathValues); size_t idxCurrentPath(0), idxTargetPath(0); while ( idxCurrentPath < currentPathValues.size() && idxTargetPath < targetPathValues.size() && #ifdef _MSC_VER _tcsicmp(currentPathValues[idxCurrentPath], targetPathValues[idxTargetPath]) == 0 #else _tcscmp(currentPathValues[idxCurrentPath], targetPathValues[idxTargetPath]) == 0 #endif ) ++idxCurrentPath, ++idxTargetPath; if (idxCurrentPath == 0) return targetPath; String relativePath; relativePath.reserve(targetPath.size()); while (idxCurrentPath < currentPathValues.size()) { relativePath += _T("..") PATH_SEPARATOR_STR; ++idxCurrentPath; } const size_t idxFirstTarget(idxTargetPath); while (idxTargetPath < targetPathValues.size()) { if (idxTargetPath > idxFirstTarget) relativePath += PATH_SEPARATOR; relativePath += targetPathValues[idxTargetPath++]; } return relativePath; } static String& getCommonPath(String& commonPath, const String& path) { // returns the path shared by the given paths #ifdef _MSC_VER while (_tcsnicmp(commonPath, path, commonPath.length()) != 0) { #else while (_tcsncmp(commonPath, path, commonPath.length()) != 0) { #endif commonPath.pop_back(); commonPath = getFilePath(commonPath); } return commonPath; } static String getCommonPath(const String* arrPaths, size_t numPaths) { // returns the path shared by all given paths ASSERT(numPaths > 0); String commonPath(arrPaths[0]); for (size_t i=1; !commonPath.empty() && i 3 && nrNumbers > 0) return buf; rez = (uint32_t)((sTime%((int64_t)24*3600*1000)) / (3600*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%uh", rez); } if (nAproximate > 2 && nrNumbers > 0) return buf; rez = (uint32_t)((sTime%((int64_t)3600*1000)) / (60*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%um", rez); } if (nAproximate > 1 && nrNumbers > 0) return buf; rez = (uint32_t)((sTime%((int64_t)60*1000)) / (1*1000)); if (rez) { ++nrNumbers; len += _stprintf(buf+len, "%us", rez); } if (nAproximate > 0 && nrNumbers > 0) return buf; rez = (uint32_t)(sTime%((int64_t)1*1000)); if (rez || !nrNumbers) len += _stprintf(buf+len, "%ums", rez); return String(buf, len); } static String toString(const wchar_t* wsz) { if (wsz == NULL) return String(); #if 1 return std::wstring_convert, wchar_t>().to_bytes(wsz); #elif 1 std::mbstate_t state = std::mbstate_t(); const size_t len(std::wcsrtombs(NULL, &wsz, 0, &state)); if (len == static_cast(-1)) return String(); std::vector mbstr(len+1); if (std::wcsrtombs(&mbstr[0], &wsz, mbstr.size(), &state) == static_cast(-1)) return String(); return String(&mbstr[0]); #else const std::wstring ws(wsz); const std::locale locale(""); typedef std::codecvt converter_type; const converter_type& converter = std::use_facet(locale); std::vector to(ws.length() * converter.max_length()); std::mbstate_t state; const wchar_t* from_next; char* to_next; if (converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next) != converter_type::ok) return String(); return std::string(&to[0], to_next); #endif } static int64_t toInt64(LPCTSTR aString) { #ifdef _MSC_VER return _atoi64(aString); #else return atoll(aString); #endif } static int toInt(LPCTSTR aString) { return atoi(aString); } static uint32_t toUInt32Hex(LPCTSTR aString) { uint32_t val; sscanf(aString, "%x", &val); return val; } static uint32_t toUInt32(LPCTSTR aString) { return (uint32_t)atoi(aString); } static double toDouble(LPCTSTR aString) { return atof(aString); } static float toFloat(LPCTSTR aString) { return (float)atof(aString); } static time_t getTime() { return (time_t)time(NULL); } static uint32_t getTick() { #ifdef _MSC_VER return GetTickCount(); #else timeval tv; gettimeofday(&tv, NULL); return (uint32_t)(tv.tv_sec * 1000 ) + (tv.tv_usec / 1000); #endif } /** * IPRT - CRC64. * * The method to compute the CRC64 is referred to as CRC-64-ISO: * http://en.wikipedia.org/wiki/Cyclic_redundancy_check * The generator polynomial is x^64 + x^4 + x^3 + x + 1. * Reverse polynom: 0xd800000000000000ULL * * As in: http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Runtime/common/checksum/crc64.cpp */ /** * Calculate CRC64 for a memory block. * * @returns CRC64 for the memory block. * @param pv Pointer to the memory block. * @param cb Size of the memory block in bytes. */ static uint64_t CRC64(const void *pv, size_t cb); /** * Start a multiblock CRC64 calculation. * * @returns Start CRC64. */ static uint64_t CRC64Start() { return 0ULL; } /** * Processes a multiblock of a CRC64 calculation. * * @returns Intermediate CRC64 value. * @param uCRC64 Current CRC64 intermediate value. * @param pv The data block to process. * @param cb The size of the data block in bytes. */ static uint64_t CRC64Process(uint64_t uCRC64, const void *pv, size_t cb); /** * Complete a multiblock CRC64 calculation. * * @returns CRC64 value. * @param uCRC64 Current CRC64 intermediate value. */ static uint64_t CRC64Finish(uint64_t uCRC64) { return uCRC64; } static void Init(); static String GetCPUInfo(); static String GetRAMInfo(); static String GetOSInfo(); static String GetDiskInfo(const String&); enum CPUFNC {NA=0, SSE, AVX}; static const Flags ms_CPUFNC; static void LogBuild(); static void LogMemoryInfo(); static LPSTR* CommandLineToArgvA(LPCSTR CmdLine, size_t& _argc); static String CommandLineToString(size_t argc, LPCTSTR* argv) { String strCmdLine; for (size_t i=1; i msgLen) std::cout << String(lastMsgLen-msgLen, _T(' ')); std::cout << std::flush; lastMsgLen = msgLen; } }; template static std::pair ComputePercentileMinMax(const T *data, size_t size){ if (size == 0) return std::make_pair(0, 0); // Find min/max T aMin = data[0]; T aMax = data[0]; for (size_t i = 1; i < size; i++) { if (data[i] > aMax) aMax = data[i]; if (data[i] < aMin) aMin = data[i]; } const float range = static_cast(aMax - aMin); if (range == 0.0f) return std::make_pair(aMin, aMax); float closestMinP = 9999.0f; float closestMaxP = 9999.0f; T min = 0; T max = 0; // Get min/max values at the 10th and 90th percentile for (size_t i = 0; i < size; i++) { const float percentile = (static_cast(data[i]) - static_cast(aMin)) / range; const float minP = abs(percentile - 0.1f); const float maxP = abs(percentile - 0.9f); if (minP < closestMinP) { min = data[i]; closestMinP = minP; } if (maxP < closestMaxP) { max = data[i]; closestMaxP = maxP; } } return std::make_pair(min, max); } }; /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_UTIL_H__