diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/basic_math.h | 4 | ||||
-rw-r--r-- | zen/crc.h | 13 | ||||
-rw-r--r-- | zen/dir_watcher.cpp | 6 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 10 | ||||
-rw-r--r-- | zen/fixed_list.h | 30 | ||||
-rw-r--r-- | zen/format_unit.cpp | 55 | ||||
-rw-r--r-- | zen/i18n.h | 6 | ||||
-rw-r--r-- | zen/perf.h | 63 | ||||
-rw-r--r-- | zen/serialize.h | 27 | ||||
-rw-r--r-- | zen/shell_execute.h | 4 | ||||
-rw-r--r-- | zen/stl_tools.h | 2 | ||||
-rw-r--r-- | zen/string_tools.h | 52 | ||||
-rw-r--r-- | zen/thread.h | 6 | ||||
-rw-r--r-- | zen/tick_count.h | 141 |
14 files changed, 166 insertions, 253 deletions
diff --git a/zen/basic_math.h b/zen/basic_math.h index e9e17466..eed23477 100644 --- a/zen/basic_math.h +++ b/zen/basic_math.h @@ -18,7 +18,7 @@ namespace numeric { template <class T> T abs(T value); -template <class T> T dist(T a, T b); +template <class T> auto dist(T a, T b); template <class T> int sign(T value); //returns one of {-1, 0, 1} template <class T> T min(T a, T b, T c); template <class T> T max(T a, T b, T c); @@ -90,7 +90,7 @@ T abs(T value) } template <class T> inline -T dist(T a, T b) +auto dist(T a, T b) //return type might be different than T, e.g. std::chrono::duration instead of std::chrono::time_point { return a > b ? a - b : b - a; } @@ -19,6 +19,19 @@ namespace zen { +uint16_t getCrc16(const std::string& str); +uint32_t getCrc32(const std::string& str); +template <class ByteIterator> uint16_t getCrc16(ByteIterator first, ByteIterator last); +template <class ByteIterator> uint32_t getCrc32(ByteIterator first, ByteIterator last); + + + + +//------------------------- implementation ------------------------------- +inline uint16_t getCrc16(const std::string& str) { return getCrc16(str.begin(), str.end()); } +inline uint32_t getCrc32(const std::string& str) { return getCrc32(str.begin(), str.end()); } + + template <class ByteIterator> inline uint16_t getCrc16(ByteIterator first, ByteIterator last) { diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp index 12a6a9f4..98190bba 100644 --- a/zen/dir_watcher.cpp +++ b/zen/dir_watcher.cpp @@ -9,6 +9,7 @@ #include <set> #include "thread.h" #include "scope_guard.h" +#include "basic_math.h" #ifdef ZEN_WIN #include "device_notify.h" @@ -358,10 +359,11 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void() //wait until device removal is confirmed, to prevent locking hDir again by some new watch! if (pimpl_->volRemoval->requestReceived()) { - const std::chrono::steady_clock::time_point stopTime = std::chrono::steady_clock::now() + std::chrono::seconds(15); + const auto startTime = std::chrono::steady_clock::now(); //HandleVolumeRemoval::finished() not guaranteed! note: Windows gives unresponsive applications ca. 10 seconds until unmounting the usb stick in worst case - while (!pimpl_->volRemoval->finished() && std::chrono::steady_clock::now() < stopTime) + while (!pimpl_->volRemoval->finished() && + numeric::dist(std::chrono::steady_clock::now(), startTime) < std::chrono::seconds(15)) //handle potential chrono wrap-around! { processGuiMessages(); //DBT_DEVICEREMOVECOMPLETE message is sent here! std::this_thread::sleep_for(std::chrono::milliseconds(50)); diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index b4599d03..3eb284e1 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -62,7 +62,7 @@ void zen::traverseFolder(const Zstring& dirPath, if (ec == ERROR_NO_MORE_FILES) //not an error situation return; //else we have a problem... report it: - throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(L"FindNextFile", ec)); + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(L"FindNextFile", ec)); } //skip "." and ".." @@ -73,7 +73,7 @@ void zen::traverseFolder(const Zstring& dirPath, continue; if (itemNameRaw[0] == 0) - throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item with empty name."); + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item with empty name."); const Zstring& itemPath = appendSeparator(dirPath) + itemNameRaw; @@ -112,7 +112,7 @@ void zen::traverseFolder(const Zstring& dirPath, { struct ::dirent* dirEntry = nullptr; if (::readdir_r(folder, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0) - THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r"); + THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r"); //don't retry but restart dir traversal on error! https://blogs.msdn.microsoft.com/oldnewthing/20140612-00/?p=753/ if (!dirEntry) //no more items @@ -133,14 +133,14 @@ void zen::traverseFolder(const Zstring& dirPath, } catch (const SysError& e) //failure is not an item-level error since we don't know the normalized name yet!!! { - throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"Failed to generate normalized file name: " + fmtPath(itemNameRaw) + L"\n" + e.toString()); //too obscure to warrant translation } #else const Zstring& itemName = itemNameRaw; #endif if (itemName.empty()) //checks result of osx::normalizeUtfForPosix, too! - throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name."); + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name."); const Zstring& itemPath = appendSeparator(dirPath) + itemName; diff --git a/zen/fixed_list.h b/zen/fixed_list.h index 4376c13f..81197eb4 100644 --- a/zen/fixed_list.h +++ b/zen/fixed_list.h @@ -15,7 +15,7 @@ namespace zen { //std::list(C++11)-like class for inplace element construction supporting non-copyable/non-movable types //-> no iterator invalidation after emplace_back() - + template <class T> class FixedList { @@ -69,7 +69,7 @@ public: const_reference& back() const { return lastInsert_->val; } template <class... Args> - void emplace_back(Args&&... args) + void emplace_back(Args&& ... args) { Node* newNode = new Node(std::forward<Args>(args)...); @@ -160,10 +160,10 @@ class FixedVector public: FixedVector() {} - /* - class EndIterator {}; //just like FixedList: no iterator invalidation after emplace_back() + /* + class EndIterator {}; //just like FixedList: no iterator invalidation after emplace_back() - template <class V> + template <class V> class FixedIterator : public std::iterator<std::forward_iterator_tag, V> //could make this random-access if needed { public: @@ -174,10 +174,10 @@ public: V& operator* () const { return *cont_[pos_]; } V* operator->() const { return &*cont_[pos_]; } private: - std::vector<std::unique_ptr<T>>& cont_; - size_t pos_ = 0; + std::vector<std::unique_ptr<T>>& cont_; + size_t pos_ = 0; }; - */ + */ template <class IterImpl, class V> class FixedIterator : public std::iterator<std::forward_iterator_tag, V> //could make this bidirectional if needed @@ -188,7 +188,7 @@ public: inline friend bool operator==(const FixedIterator& lhs, const FixedIterator& rhs) { return lhs.it_ == rhs.it_; } inline friend bool operator!=(const FixedIterator& lhs, const FixedIterator& rhs) { return !(lhs == rhs); } V& operator* () const { return **it_; } - V* operator->() const { return &**it_; } + V* operator->() const { return &** it_; } private: IterImpl it_; //TODO: avoid iterator invalidation after emplace_back(); caveat: end() must not store old length! }; @@ -199,10 +199,10 @@ public: using reference = T&; using const_reference = const T&; - iterator begin() { return items_.begin(); } + iterator begin() { return items_.begin(); } iterator end () { return items_.end (); } - const_iterator begin() const { return items_.begin(); } + const_iterator begin() const { return items_.begin(); } const_iterator end () const { return items_.end (); } reference front() { return *items_.front(); } @@ -212,15 +212,15 @@ public: const_reference& back() const { return *items_.back(); } template <class... Args> - void emplace_back(Args&&... args) + void emplace_back(Args&& ... args) { - items_.push_back(std::make_unique<T>(std::forward<Args>(args)...)); + items_.push_back(std::make_unique<T>(std::forward<Args>(args)...)); } template <class Predicate> void remove_if(Predicate pred) { - erase_if(items_, [&](const std::unique_ptr<T>& p){ return pred(*p); }); + erase_if(items_, [&](const std::unique_ptr<T>& p) { return pred(*p); }); } void clear() { items_.clear(); } @@ -232,7 +232,7 @@ private: FixedVector (const FixedVector&) = delete; FixedVector& operator=(const FixedVector&) = delete; - std::vector<std::unique_ptr<T>> items_; + std::vector<std::unique_ptr<T>> items_; }; } diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp index d87a1643..08463778 100644 --- a/zen/format_unit.cpp +++ b/zen/format_unit.cpp @@ -16,7 +16,7 @@ #ifdef ZEN_WIN #include "int64.h" #include "win.h" //includes "windows.h" - #include "win_ver.h" + // #include "win_ver.h" #elif defined ZEN_LINUX || defined ZEN_MAC #include <clocale> //thousands separator @@ -155,6 +155,12 @@ std::wstring zen::remainingTimeToString(double timeInSec) } +//std::wstring zen::fractionToString1Dec(double fraction) +//{ +// return printNumber<std::wstring>(L"%.1f", fraction * 100.0) + L'%'; //no need to internationalize fraction!? +//} + + std::wstring zen::fractionToString(double fraction) { return printNumber<std::wstring>(L"%.2f", fraction * 100.0) + L'%'; //no need to internationalize fraction!? @@ -299,32 +305,29 @@ std::wstring zen::utcToLocalTimeString(std::int64_t utcTime) SYSTEMTIME systemTimeLocal = {}; - static const bool useNewLocalTimeCalculation = zen::vistaOrLater(); - //https://msdn.microsoft.com/en-us/library/ms724277 - if (useNewLocalTimeCalculation) //DST conversion like in Windows 7: NTFS stays fixed, but FAT jumps by one hour - { - SYSTEMTIME systemTimeUtc = {}; - if (!::FileTimeToSystemTime(&lastWriteTimeUtc, //__in const FILETIME *lpFileTime, - &systemTimeUtc)) //__out LPSYSTEMTIME lpSystemTime - return errorMsg(); - - if (!::SystemTimeToTzSpecificLocalTime(nullptr, //__in_opt LPTIME_ZONE_INFORMATION lpTimeZone, - &systemTimeUtc, //__in LPSYSTEMTIME lpUniversalTime, - &systemTimeLocal)) //__out LPSYSTEMTIME lpLocalTime - return errorMsg(); - } - else //DST conversion like in Windows 2000 and XP: FAT times stay fixed, while NTFS jumps - { - FILETIME fileTimeLocal = {}; - if (!::FileTimeToLocalFileTime(&lastWriteTimeUtc, //_In_ const FILETIME *lpFileTime, - &fileTimeLocal)) //_Out_ LPFILETIME lpLocalFileTime - return errorMsg(); - - if (!::FileTimeToSystemTime(&fileTimeLocal, //__in const FILETIME *lpFileTime, - &systemTimeLocal)) //__out LPSYSTEMTIME lpSystemTime - return errorMsg(); - } +#ifdef ZEN_WIN_VISTA_AND_LATER + //DST conversion like in Vista and later: NTFS stays fixed, but FAT jumps by one hour + SYSTEMTIME systemTimeUtc = {}; + if (!::FileTimeToSystemTime(&lastWriteTimeUtc, //__in const FILETIME *lpFileTime, + &systemTimeUtc)) //__out LPSYSTEMTIME lpSystemTime + return errorMsg(); + + if (!::SystemTimeToTzSpecificLocalTime(nullptr, //__in_opt LPTIME_ZONE_INFORMATION lpTimeZone, + &systemTimeUtc, //__in LPSYSTEMTIME lpUniversalTime, + &systemTimeLocal)) //__out LPSYSTEMTIME lpLocalTime + return errorMsg(); +#else + //DST conversion like in Windows 2000 and XP: FAT times stay fixed, while NTFS jumps + FILETIME fileTimeLocal = {}; + if (!::FileTimeToLocalFileTime(&lastWriteTimeUtc, //_In_ const FILETIME *lpFileTime, + &fileTimeLocal)) //_Out_ LPFILETIME lpLocalFileTime + return errorMsg(); + + if (!::FileTimeToSystemTime(&fileTimeLocal, //__in const FILETIME *lpFileTime, + &systemTimeLocal)) //__out LPSYSTEMTIME lpSystemTime + return errorMsg(); +#endif zen::TimeComp loc; loc.year = systemTimeLocal.wYear; @@ -98,7 +98,7 @@ std::wstring translate(const std::wstring& singular, const std::wstring& plural, inline -Global<const TranslationHandler>& getGlobalTranslationHandler() +Global<const TranslationHandler>& refGlobalTranslationHandler() { //getTranslator() may be called even after static objects of this translation unit are destroyed! static Global<const TranslationHandler> inst; //external linkage even in header! @@ -110,14 +110,14 @@ Global<const TranslationHandler>& getGlobalTranslationHandler() inline void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler) { - implementation::getGlobalTranslationHandler().set(std::move(newHandler)); + implementation::refGlobalTranslationHandler().set(std::move(newHandler)); } inline std::shared_ptr<const TranslationHandler> getTranslator() { - return implementation::getGlobalTranslationHandler().get(); + return implementation::refGlobalTranslationHandler().get(); } } @@ -7,12 +7,13 @@ #ifndef PERF_H_83947184145342652456 #define PERF_H_83947184145342652456 +#include <chrono> #include "deprecate.h" -#include "tick_count.h" #include "scope_guard.h" #ifdef ZEN_WIN #include <sstream> + #include "win.h" #else #include <iostream> #endif @@ -28,54 +29,47 @@ namespace zen class PerfTimer { public: - class TimerError {}; + ZEN_DEPRECATE PerfTimer() {} - ZEN_DEPRECATE - PerfTimer() : startTime(getTicksNow()) //throw TimerError - { - //std::clock() - "counts CPU time in Linux GCC and wall time in VC++" - WTF!??? - if (ticksPerSec_ == 0) - throw TimerError(); - } - - ~PerfTimer() { if (!resultShown) try { showResult(); } catch (TimerError&) { assert(false); } } + ~PerfTimer() { if (!resultShown_) showResult(); } void pause() { - if (!paused) + if (!paused_) { - paused = true; - elapsedUntilPause += dist(startTime, getTicksNow()); + paused_ = true; + elapsedUntilPause_ += std::chrono::steady_clock::now() - startTime_; //ignore potential ::QueryPerformanceCounter() wrap-around! } } void resume() { - if (paused) + if (paused_) { - paused = false; - startTime = getTicksNow(); + paused_ = false; + startTime_ = std::chrono::steady_clock::now(); } } void restart() { - startTime = getTicksNow(); - paused = false; - elapsedUntilPause = 0; + paused_ = false; + startTime_ = std::chrono::steady_clock::now(); + elapsedUntilPause_ = std::chrono::nanoseconds::zero(); } int64_t timeMs() const { - int64_t ticksTotal = elapsedUntilPause; - if (!paused) - ticksTotal += dist(startTime, getTicksNow()); - return 1000 * ticksTotal / ticksPerSec_; + auto elapsedTotal = elapsedUntilPause_; + if (!paused_) + elapsedTotal += std::chrono::steady_clock::now() - startTime_; + + return std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTotal).count(); } void showResult() { - const bool wasRunning = !paused; + const bool wasRunning = !paused_; if (wasRunning) pause(); //don't include call to MessageBox()! ZEN_ON_SCOPE_EXIT(if (wasRunning) resume()); @@ -86,23 +80,14 @@ public: #else std::clog << "Perf: duration: " << timeMs() << " ms\n"; #endif - resultShown = true; + resultShown_ = true; } private: - TickVal getTicksNow() const - { - const TickVal now = getTicks(); - if (!now.isValid()) - throw TimerError(); - return now; - } - - const std::int64_t ticksPerSec_ = ticksPerSec(); //return 0 on error - bool resultShown = false; - TickVal startTime; - bool paused = false; - int64_t elapsedUntilPause = 0; + bool resultShown_ = false; + bool paused_ = false; + std::chrono::steady_clock::time_point startTime_ = std::chrono::steady_clock::now(); //uses ::QueryPerformanceCounter() + std::chrono::nanoseconds elapsedUntilPause_{}; //std::chrono::duration is uninitialized by default! WTF! When will this stupidity end??? }; } diff --git a/zen/serialize.h b/zen/serialize.h index bc047fee..7322cb07 100644 --- a/zen/serialize.h +++ b/zen/serialize.h @@ -72,8 +72,8 @@ struct UnbufferedOutputStream size_t tryWrite(const void* buffer, size_t bytesToWrite); //may return short! CONTRACT: bytesToWrite > 0 }; */ -//functions based on unbuffered stream abstraction +//functions based on unbuffered stream abstraction template <class UnbufferedInputStream, class UnbufferedOutputStream> void unbufferedStreamCopy(UnbufferedInputStream& streamIn, UnbufferedOutputStream& streamOut, const std::function<void(std::int64_t bytesDelta)>& notifyProgress); //throw X @@ -104,7 +104,6 @@ struct BufferedOutputStream template <class N, class BufferedOutputStream> void writeNumber (BufferedOutputStream& stream, const N& num); // template <class C, class BufferedOutputStream> void writeContainer(BufferedOutputStream& stream, const C& str); //throw () template < class BufferedOutputStream> void writeArray (BufferedOutputStream& stream, const void* data, size_t len); // - //---------------------------------------------------------------------- class UnexpectedEndOfStreamError {}; template <class N, class BufferedInputStream> N readNumber (BufferedInputStream& stream); //throw UnexpectedEndOfStreamError (corrupted data) @@ -115,21 +114,23 @@ template < class BufferedInputStream> void readArray (BufferedInputSt template <class BinContainer> struct MemoryStreamIn { - MemoryStreamIn(const BinContainer& cont) : buffer(cont) {} //this better be cheap! + MemoryStreamIn(const BinContainer& cont) : buffer_(cont) {} //this better be cheap! size_t read(void* data, size_t len) //return "len" bytes unless end of stream! { static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes - const size_t bytesRead = std::min(len, buffer.size() - pos); - auto itFirst = buffer.begin() + pos; + const size_t bytesRead = std::min(len, buffer_.size() - pos_); + auto itFirst = buffer_.begin() + pos_; std::copy(itFirst, itFirst + bytesRead, static_cast<char*>(data)); - pos += bytesRead; + pos_ += bytesRead; return bytesRead; } + size_t pos() const { return pos_; } + private: - const BinContainer buffer; - size_t pos = 0; + const BinContainer buffer_; + size_t pos_ = 0; }; template <class BinContainer> @@ -138,15 +139,15 @@ struct MemoryStreamOut void write(const void* data, size_t len) { static_assert(sizeof(typename BinContainer::value_type) == 1, ""); //expect: bytes - const size_t oldSize = buffer.size(); - buffer.resize(oldSize + len); - std::copy(static_cast<const char*>(data), static_cast<const char*>(data) + len, buffer.begin() + oldSize); + const size_t oldSize = buffer_.size(); + buffer_.resize(oldSize + len); + std::copy(static_cast<const char*>(data), static_cast<const char*>(data) + len, buffer_.begin() + oldSize); } - const BinContainer& ref() const { return buffer; } + const BinContainer& ref() const { return buffer_; } private: - BinContainer buffer; + BinContainer buffer_; }; diff --git a/zen/shell_execute.h b/zen/shell_execute.h index ee8203c3..2f73fc38 100644 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -38,7 +38,7 @@ bool shellExecuteImpl(Function fillExecInfo, ExecutionType type) SHELLEXECUTEINFO execInfo = {}; execInfo.cbSize = sizeof(execInfo); execInfo.lpVerb = nullptr; - execInfo.nShow = SW_SHOWNORMAL; + execInfo.nShow = SW_SHOW; execInfo.fMask = type == EXEC_TYPE_SYNC ? (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC) : 0; //don't use SEE_MASK_ASYNCOK -> different async mode than the default which returns successful despite errors! execInfo.fMask |= SEE_MASK_FLAG_NO_UI; //::ShellExecuteEx() shows a non-blocking pop-up dialog on errors -> we want a blocking one @@ -98,7 +98,7 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError { filePath = argv[0]; for (auto it = argv.begin() + 1; it != argv.end(); ++it) - arguments += (it != argv.begin() ? L" " : L"") + + arguments += (it == argv.begin() + 1 ? L"" : L" ") + (it->empty() || std::any_of(it->begin(), it->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *it + L"\"" : *it); } diff --git a/zen/stl_tools.h b/zen/stl_tools.h index 064d5b51..48f475f3 100644 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -235,7 +235,7 @@ size_t hashBytesAppend(size_t hashVal, ByteIterator first, ByteIterator last) #endif static_assert(sizeof(typename std::iterator_traits<ByteIterator>::value_type) == 1, ""); - for (; first != last; ++first) + for (; first != last; ++first) { hashVal ^= static_cast<size_t>(*first); hashVal *= prime; diff --git a/zen/string_tools.h b/zen/string_tools.h index 9b8e7328..5292dfc6 100644 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -24,6 +24,7 @@ namespace zen { template <class Char> bool isWhiteSpace(Char ch); template <class Char> bool isDigit (Char ch); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only! +template <class Char> bool isHexDigit (Char ch); template <class Char> bool isAlpha (Char ch); template <class S, class T> bool startsWith(const S& str, const T& prefix); // @@ -51,6 +52,9 @@ template <class S, class T, class U> S replaceCpy(const S& str, const T& oldT template <class S, class Num> S numberTo(const Num& number); template <class Num, class S > Num stringTo(const S& str); +std::pair<char, char> hexify (unsigned char c, bool upperCase = true); +char unhexify(char high, char low); + template <class S, class T, class Num> S printNumber(const T& format, const Num& number); //format a single number using std::snprintf() //string to string conversion: converts string-like type into char-compatible target string class @@ -101,6 +105,16 @@ bool isDigit(Char ch) //similar to implmenetation of std::::isdigit()! } +template <class Char> inline +bool isHexDigit(Char c) +{ + static_assert(IsSameType<Char, char>::value || IsSameType<Char, wchar_t>::value, ""); + return (static_cast<Char>('0') <= c && c <= static_cast<Char>('9')) || + (static_cast<Char>('A') <= c && c <= static_cast<Char>('F')) || + (static_cast<Char>('a') <= c && c <= static_cast<Char>('f')); +} + + template <> bool isAlpha(char ch) = delete; //probably not a good idea with UTF-8 anyway... template <> inline bool isAlpha(wchar_t ch) { return std::iswalpha(ch) != 0; } @@ -297,7 +311,7 @@ S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll) return str; const auto* const newBegin = strBegin(newTerm); - const auto* const newEnd = newBegin + strLength(newTerm); + const auto* const newEnd = newBegin + strLength(newTerm); S output; for (;;) @@ -658,6 +672,42 @@ Num stringTo(const S& str) return impl::stringTo<Num>(str, TypeTag()); } + + +inline //hexify beats "printNumber<std::string>("%02X", c)" by a nice factor of 3! +std::pair<char, char> hexify(unsigned char c, bool upperCase) +{ + auto hexifyDigit = [upperCase](int num) -> char //input [0, 15], output 0-9, A-F + { + assert(0 <= num&& num <= 15); //guaranteed by design below! + if (num <= 9) + return static_cast<char>('0' + num); //no signed/unsigned char problem here! + + if (upperCase) + return static_cast<char>('A' + (num - 10)); + else + return static_cast<char>('a' + (num - 10)); + }; + return std::make_pair(hexifyDigit(c / 16), hexifyDigit(c % 16)); +} + + +inline //unhexify beats "::sscanf(&it[3], "%02X", &tmp)" by a factor of 3000 for ~250000 calls!!! +char unhexify(char high, char low) +{ + auto unhexifyDigit = [](char hex) -> int //input 0-9, a-f, A-F; output range: [0, 15] + { + if ('0' <= hex && hex <= '9') //no signed/unsigned char problem here! + return hex - '0'; + else if ('A' <= hex && hex <= 'F') + return (hex - 'A') + 10; + else if ('a' <= hex && hex <= 'f') + return (hex - 'a') + 10; + assert(false); + return 0; + }; + return static_cast<unsigned char>(16 * unhexifyDigit(high) + unhexifyDigit(low)); //[!] convert to unsigned char first, then to char (which may be signed) +} } #endif //STRING_TOOLS_H_213458973046 diff --git a/zen/thread.h b/zen/thread.h index ac94da6a..5bb02a0e 100644 --- a/zen/thread.h +++ b/zen/thread.h @@ -460,9 +460,9 @@ std::uint64_t getThreadId() return ::GetCurrentThreadId(); //no-fail #elif defined ZEN_LINUX - //obviously "gettid()" is not available on Ubuntu/Debian/Suse => use the OpenSSL approach: - static_assert(sizeof(std::uint64_t) >= sizeof(void*), ""); - return reinterpret_cast<std::uint64_t>(static_cast<void*>(&errno)); + //obviously "gettid()" is not available on Ubuntu/Debian/Suse => use the OpenSSL approach: + static_assert(sizeof(std::uint64_t) >= sizeof(void*), ""); + return reinterpret_cast<std::uint64_t>(static_cast<void*>(&errno)); #elif defined ZEN_MAC uint64_t tid = 0; diff --git a/zen/tick_count.h b/zen/tick_count.h deleted file mode 100644 index 5ba4fd1b..00000000 --- a/zen/tick_count.h +++ /dev/null @@ -1,141 +0,0 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef TICK_COUNT_H_3807326223463457 -#define TICK_COUNT_H_3807326223463457 - -#include <cstdint> -#include "type_traits.h" -#include "basic_math.h" - -#ifdef ZEN_WIN - #include "win.h" //includes "windows.h" -#elif defined ZEN_LINUX - #include <time.h> //Posix ::clock_gettime() -#elif defined ZEN_MAC - #include <mach/mach_time.h> -#endif - - -namespace zen -{ -//a portable "GetTickCount()" using "wall time equivalent" - e.g. no jumps due to ntp time corrections -class TickVal; -int64_t dist(const TickVal& lhs, const TickVal& rhs); //use absolute difference for paranoid security: even QueryPerformanceCounter "wraps-around" at *some* time - -int64_t ticksPerSec(); //return 0 on error -TickVal getTicks(); //return invalid value on error: !TickVal::isValid() - - - - - - - - - -//############################ implementation ############################## -class TickVal -{ -public: -#ifdef ZEN_WIN - using NativeVal = LARGE_INTEGER; -#elif defined ZEN_LINUX - using NativeVal = timespec; -#elif defined ZEN_MAC - using NativeVal = uint64_t; -#endif - - TickVal() {} - explicit TickVal(const NativeVal& val) : val_(val) {} - - inline friend - int64_t dist(const TickVal& lhs, const TickVal& rhs) - { -#ifdef ZEN_WIN - return numeric::dist(lhs.val_.QuadPart, rhs.val_.QuadPart); //std::abs(a - b) can lead to overflow! -#elif defined ZEN_LINUX - //structure timespec documented with members: - // time_t tv_sec seconds - // long tv_nsec nanoseconds - const int64_t deltaSec = lhs.val_.tv_sec - rhs.val_.tv_sec; - const int64_t deltaNsec = lhs.val_.tv_nsec - rhs.val_.tv_nsec; - return numeric::abs(deltaSec * 1000000000 + deltaNsec); -#elif defined ZEN_MAC - return numeric::dist(lhs.val_, rhs.val_); -#endif - } - - inline friend - bool operator<(const TickVal& lhs, const TickVal& rhs) - { -#ifdef ZEN_WIN - return lhs.val_.QuadPart < rhs.val_.QuadPart; -#elif defined ZEN_LINUX - if (lhs.val_.tv_sec != rhs.val_.tv_sec) - return lhs.val_.tv_sec < rhs.val_.tv_sec; - return lhs.val_.tv_nsec < rhs.val_.tv_nsec; -#elif defined ZEN_MAC - return lhs.val_ < rhs.val_; -#endif - } - - bool isValid() const { return dist(*this, TickVal()) != 0; } - -private: - NativeVal val_ {}; -}; - - -inline -int64_t ticksPerSec() //return 0 on error -{ -#ifdef ZEN_WIN - LARGE_INTEGER frequency = {}; - if (!::QueryPerformanceFrequency(&frequency)) //MSDN promises: "The frequency cannot change while the system is running." - return 0; //MSDN: "This won't occur on any system that runs Windows XP or later." - static_assert(sizeof(int64_t) >= sizeof(frequency.QuadPart), ""); - return frequency.QuadPart; - -#elif defined ZEN_LINUX - return 1000000000; //precision: nanoseconds - -#elif defined ZEN_MAC - mach_timebase_info_data_t tbi = {}; - if (::mach_timebase_info(&tbi) != KERN_SUCCESS) - return 0; - //structure mach_timebase_info_data_t documented with members: - // uint32_t numer; - // uint32_t denom; - return static_cast<int64_t>(1000000000) * tbi.denom / tbi.numer; -#endif -} - - -inline -TickVal getTicks() //return !isValid() on error -{ -#ifdef ZEN_WIN - LARGE_INTEGER now = {}; - if (!::QueryPerformanceCounter(&now)) - return TickVal(); - //detailed info about QPC: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408 - //- MSDN: "No need to set the thread affinity" - -#elif defined ZEN_LINUX - //gettimeofday() seems fine but is deprecated - timespec now = {}; - if (::clock_gettime(CLOCK_MONOTONIC_RAW, &now) != 0) //CLOCK_MONOTONIC measures time reliably across processors! - return TickVal(); - -#elif defined ZEN_MAC - uint64_t now = ::mach_absolute_time(); //can this call fail??? -#endif - return TickVal(now); -} -} - -#endif //TICK_COUNT_H_3807326223463457 |