diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2018-05-09 00:09:55 +0200 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2018-05-09 00:09:55 +0200 |
commit | 9b623ea3943165fe7efb5e47a0b5b9452c1599e6 (patch) | |
tree | dde40e07e907ac6e0ca9ea32524f2cd4810d4be6 /zen | |
parent | 9.7 (diff) | |
download | FreeFileSync-9b623ea3943165fe7efb5e47a0b5b9452c1599e6.tar.gz FreeFileSync-9b623ea3943165fe7efb5e47a0b5b9452c1599e6.tar.bz2 FreeFileSync-9b623ea3943165fe7efb5e47a0b5b9452c1599e6.zip |
9.8
Diffstat (limited to 'zen')
-rwxr-xr-x | zen/basic_math.h | 18 | ||||
-rwxr-xr-x | zen/build_info.h | 3 | ||||
-rwxr-xr-x | zen/dir_watcher.cpp | 22 | ||||
-rwxr-xr-x | zen/dir_watcher.h | 13 | ||||
-rwxr-xr-x | zen/error_log.h | 29 | ||||
-rwxr-xr-x | zen/file_access.h | 1 | ||||
-rwxr-xr-x | zen/file_error.h | 1 | ||||
-rwxr-xr-x | zen/file_id_def.h | 2 | ||||
-rwxr-xr-x | zen/file_io.h | 2 | ||||
-rwxr-xr-x | zen/file_traverser.cpp | 2 | ||||
-rwxr-xr-x | zen/file_traverser.h | 6 | ||||
-rwxr-xr-x | zen/fixed_list.h | 1 | ||||
-rwxr-xr-x | zen/format_unit.cpp | 7 | ||||
-rwxr-xr-x | zen/format_unit.h | 4 | ||||
-rwxr-xr-x | zen/globals.h | 1 | ||||
-rwxr-xr-x | zen/i18n.h | 7 | ||||
-rwxr-xr-x | zen/optional.h | 1 | ||||
-rwxr-xr-x | zen/process_priority.h | 1 | ||||
-rwxr-xr-x | zen/scope_guard.h | 2 | ||||
-rwxr-xr-x | zen/shell_execute.h | 8 | ||||
-rwxr-xr-x | zen/shutdown.cpp | 4 | ||||
-rwxr-xr-x | zen/shutdown.h | 1 | ||||
-rwxr-xr-x | zen/string_base.h | 2 | ||||
-rwxr-xr-x | zen/string_tools.h | 12 | ||||
-rwxr-xr-x | zen/string_traits.h | 16 | ||||
-rwxr-xr-x | zen/thread.h | 2 | ||||
-rwxr-xr-x | zen/time.h | 199 | ||||
-rwxr-xr-x | zen/utf.h | 13 | ||||
-rwxr-xr-x | zen/xml_io.h | 2 | ||||
-rwxr-xr-x | zen/zstring.cpp | 11 |
30 files changed, 220 insertions, 173 deletions
diff --git a/zen/basic_math.h b/zen/basic_math.h index 1b6b7e97..16f69bde 100755 --- a/zen/basic_math.h +++ b/zen/basic_math.h @@ -31,7 +31,7 @@ template <class T> T clampCpy(T val, T minVal, T maxVal); template <class T, class InputIterator> //precondition: range must be sorted! auto nearMatch(const T& val, InputIterator first, InputIterator last); -int round(double d); //"little rounding function" +int64_t round(double d); //"little rounding function" template <class N, class D> auto integerDivideRoundUp(N numerator, D denominator); @@ -182,7 +182,7 @@ std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, Input } } } - return std::make_pair(lowest, largest); + return { lowest, largest }; } @@ -220,20 +220,20 @@ bool isNull(T value) inline -int round(double d) +int64_t round(double d) { - assert(d - 0.5 >= std::numeric_limits<int>::min() && //if double is larger than what int can represent: - d + 0.5 <= std::numeric_limits<int>::max()); //=> undefined behavior! - return static_cast<int>(d < 0 ? d - 0.5 : d + 0.5); + assert(d - 0.5 >= std::numeric_limits<int64_t>::min() && //if double is larger than what int can represent: + d + 0.5 <= std::numeric_limits<int64_t>::max()); //=> undefined behavior! + return static_cast<int64_t>(d < 0 ? d - 0.5 : d + 0.5); } template <class N, class D> inline auto integerDivideRoundUp(N numerator, D denominator) { - static_assert(std::is_integral<N>::value && std::is_unsigned<N>::value, ""); - static_assert(std::is_integral<D>::value && std::is_unsigned<D>::value, ""); - assert(denominator > 0); + static_assert(std::is_integral<N>::value, ""); + static_assert(std::is_integral<D>::value, ""); + assert(numerator > 0 && denominator > 0); return (numerator + denominator - 1) / denominator; } diff --git a/zen/build_info.h b/zen/build_info.h index 7b0aa9cf..9b8b7fc0 100755 --- a/zen/build_info.h +++ b/zen/build_info.h @@ -7,8 +7,6 @@ #ifndef BUILD_INFO_H_5928539285603428657 #define BUILD_INFO_H_5928539285603428657 -namespace zen -{ //determine build info: defines ZEN_BUILD_32BIT or ZEN_BUILD_64BIT #ifdef __LP64__ @@ -24,6 +22,5 @@ namespace zen #ifdef ZEN_BUILD_64BIT static_assert(sizeof(void*) == 8, ""); #endif -} #endif //BUILD_INFO_H_5928539285603428657 diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp index 17f2244d..0cbde150 100755 --- a/zen/dir_watcher.cpp +++ b/zen/dir_watcher.cpp @@ -30,11 +30,11 @@ struct DirWatcher::Impl DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError - baseDirPath(dirPath), + baseDirPath_(dirPath), pimpl_(std::make_unique<Impl>()) { //get all subdirectories - std::vector<Zstring> fullFolderList { baseDirPath }; + std::vector<Zstring> fullFolderList { baseDirPath_ }; { std::function<void (const Zstring& path)> traverse; @@ -46,13 +46,13 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError [&](const std::wstring& errorMsg) { throw FileError(errorMsg); }); }; - traverse(baseDirPath); + traverse(baseDirPath_); } //init pimpl_->notifDescr = ::inotify_init(); if (pimpl_->notifDescr == -1) - THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"inotify_init"); + THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"inotify_init"); ZEN_ON_SCOPE_FAIL( ::close(pimpl_->notifDescr); ); @@ -64,7 +64,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1; } if (!initSuccess) - THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"fcntl"); + THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"fcntl"); //add watches for (const Zstring& subDirPath : fullFolderList) @@ -101,7 +101,7 @@ DirWatcher::~DirWatcher() } -std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) //throw FileError +std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>& requestUiRefresh, std::chrono::milliseconds cbInterval) //throw FileError { std::vector<char> buffer(512 * (sizeof(struct ::inotify_event) + NAME_MAX + 1)); @@ -118,7 +118,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void() if (errno == EAGAIN) //this error is ignored in all inotify wrappers I found return std::vector<Entry>(); - THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"read"); + THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"read"); } std::vector<Entry> output; @@ -135,19 +135,19 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void() { //Note: evt.len is NOT the size of the evt.name c-string, but the array size including all padding 0 characters! //It may be even 0 in which case evt.name must not be used! - const Zstring fullname = it->second + evt.name; + const Zstring itemPath = it->second + evt.name; if ((evt.mask & IN_CREATE) || (evt.mask & IN_MOVED_TO)) - output.emplace_back(ACTION_CREATE, fullname); + output.push_back({ ACTION_CREATE, itemPath }); else if ((evt.mask & IN_MODIFY) || (evt.mask & IN_CLOSE_WRITE)) - output.emplace_back(ACTION_UPDATE, fullname); + output.push_back({ ACTION_UPDATE, itemPath }); else if ((evt.mask & IN_DELETE ) || (evt.mask & IN_DELETE_SELF) || (evt.mask & IN_MOVE_SELF ) || (evt.mask & IN_MOVED_FROM)) - output.emplace_back(ACTION_DELETE, fullname); + output.push_back({ ACTION_DELETE, itemPath }); } } bytePos += sizeof(struct ::inotify_event) + evt.len; diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h index 8045d184..b4796618 100755 --- a/zen/dir_watcher.h +++ b/zen/dir_watcher.h @@ -9,6 +9,7 @@ #include <vector> #include <memory> +#include <chrono> #include <functional> #include "file_error.h" @@ -50,26 +51,22 @@ public: struct Entry { - Entry() {} - Entry(ActionType action, const Zstring& filepath) : action_(action), filepath_(filepath) {} - - ActionType action_ = ACTION_CREATE; - Zstring filepath_; + ActionType action = ACTION_CREATE; + Zstring filePath; }; //extract accumulated changes since last call - std::vector<Entry> getChanges(const std::function<void()>& processGuiMessages); //throw FileError + std::vector<Entry> getChanges(const std::function<void()>& requestUiRefresh, std::chrono::milliseconds cbInterval); //throw FileError private: DirWatcher (const DirWatcher&) = delete; DirWatcher& operator=(const DirWatcher&) = delete; - const Zstring baseDirPath; + const Zstring baseDirPath_; struct Impl; const std::unique_ptr<Impl> pimpl_; }; - } #endif diff --git a/zen/error_log.h b/zen/error_log.h index 1fcbdefb..b6660850 100755 --- a/zen/error_log.h +++ b/zen/error_log.h @@ -20,18 +20,18 @@ namespace zen { enum MessageType { - TYPE_INFO = 0x1, - TYPE_WARNING = 0x2, - TYPE_ERROR = 0x4, - TYPE_FATAL_ERROR = 0x8, + MSG_TYPE_INFO = 0x1, + MSG_TYPE_WARNING = 0x2, + MSG_TYPE_ERROR = 0x4, + MSG_TYPE_FATAL_ERROR = 0x8, }; using MsgString = Zbase<wchar_t>; //std::wstring may employ small string optimization: we cannot accept bloating the "ErrorLog::entries" memory block below (think 1 million items) struct LogEntry { - time_t time; - MessageType type; + time_t time = 0; + MessageType type = MSG_TYPE_FATAL_ERROR; MsgString message; }; @@ -45,7 +45,7 @@ public: template <class String> //a wchar_t-based string! void logMsg(const String& text, MessageType type); - int getItemCount(int typeFilter = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const; + int getItemCount(int typeFilter = MSG_TYPE_INFO | MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) const; //subset of std::vector<> interface: using const_iterator = std::vector<LogEntry>::const_iterator; @@ -67,10 +67,9 @@ private: //######################## implementation ########################## template <class String> inline -void ErrorLog::logMsg(const String& text, zen::MessageType type) +void ErrorLog::logMsg(const String& text, MessageType type) { - const LogEntry newEntry = { std::time(nullptr), type, copyStringTo<MsgString>(text) }; - entries_.push_back(newEntry); + entries_.push_back({ std::time(nullptr), type, copyStringTo<MsgString>(text) }); } @@ -90,13 +89,13 @@ String formatMessageImpl(const LogEntry& entry) //internal linkage { switch (entry.type) { - case TYPE_INFO: + case MSG_TYPE_INFO: return _("Info"); - case TYPE_WARNING: + case MSG_TYPE_WARNING: return _("Warning"); - case TYPE_ERROR: + case MSG_TYPE_ERROR: return _("Error"); - case TYPE_FATAL_ERROR: + case MSG_TYPE_FATAL_ERROR: return _("Serious Error"); } assert(false); @@ -104,7 +103,7 @@ String formatMessageImpl(const LogEntry& entry) //internal linkage }; String formattedText = L"[" + formatTime<String>(FORMAT_TIME, getLocalTime(entry.time)) + L"] " + copyStringTo<String>(getTypeName()) + L": "; - const size_t prefixLen = formattedText.size(); + const size_t prefixLen = formattedText.size(); //considers UTF-16 only! for (auto it = entry.message.begin(); it != entry.message.end(); ) if (*it == L'\n') diff --git a/zen/file_access.h b/zen/file_access.h index 743ad15d..c62ddc98 100755 --- a/zen/file_access.h +++ b/zen/file_access.h @@ -13,6 +13,7 @@ #include "file_id_def.h" #include "serialize.h" + namespace zen { //note: certain functions require COM initialization! (vista_file_op.h) diff --git a/zen/file_error.h b/zen/file_error.h index decc0f7e..086d0998 100755 --- a/zen/file_error.h +++ b/zen/file_error.h @@ -12,6 +12,7 @@ #include "utf.h" #include "sys_error.h" //we'll need this later anyway! + namespace zen { class FileError //A high-level exception class giving detailed context information for end users diff --git a/zen/file_id_def.h b/zen/file_id_def.h index 7772e3e3..f58cb479 100755 --- a/zen/file_id_def.h +++ b/zen/file_id_def.h @@ -7,8 +7,6 @@ #ifndef FILE_ID_DEF_H_013287632486321493 #define FILE_ID_DEF_H_013287632486321493 -#include <utility> - #include <sys/stat.h> diff --git a/zen/file_io.h b/zen/file_io.h index 369cdc01..5b0b8cb0 100755 --- a/zen/file_io.h +++ b/zen/file_io.h @@ -13,7 +13,7 @@ namespace zen { - const char LINE_BREAK[] = "\n"; //since OS X apple uses newline, too + const char LINE_BREAK[] = "\n"; //since OS X Apple uses newline, too /* OS-buffered file IO optimized for diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index aa4c439e..bc53f206 100755 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -55,7 +55,7 @@ void zen::traverseFolder(const Zstring& dirPath, continue; const Zstring& itemName = itemNameRaw; - if (itemName.empty()) //checks result of osx::normalizeUtfForPosix, too! + if (itemName.empty()) //checks result of normalizeUtfForPosix, too! 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/file_traverser.h b/zen/file_traverser.h index 19359148..5c1683f8 100755 --- a/zen/file_traverser.h +++ b/zen/file_traverser.h @@ -18,8 +18,8 @@ struct FileInfo { Zstring itemName; Zstring fullPath; - uint64_t fileSize; //[bytes] - time_t modTime; //number of seconds since Jan. 1st 1970 UTC + uint64_t fileSize; //[bytes] + time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC }; struct FolderInfo @@ -32,7 +32,7 @@ struct SymlinkInfo { Zstring itemName; Zstring fullPath; - time_t modTime; //number of seconds since Jan. 1st 1970 UTC + time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC }; //- non-recursive diff --git a/zen/fixed_list.h b/zen/fixed_list.h index 535ffa31..10b66233 100755 --- a/zen/fixed_list.h +++ b/zen/fixed_list.h @@ -11,6 +11,7 @@ #include <iterator> #include "stl_tools.h" + namespace zen { //std::list(C++11)-like class for inplace element construction supporting non-copyable/non-movable types diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp index 0f54a34b..09134c07 100755 --- a/zen/format_unit.cpp +++ b/zen/format_unit.cpp @@ -5,7 +5,6 @@ // ***************************************************************************** #include "format_unit.h" -//#include <cwchar> //swprintf #include <ctime> #include <cstdio> #include "basic_math.h" @@ -112,7 +111,7 @@ std::wstring roundToBlock(double timeInHigh, const int blockSizeLow = granularity * timeInHigh < 1 ? numeric::nearMatch(granularity * timeInLow, std::begin(stepsLow), std::end(stepsLow)): numeric::nearMatch(granularity * timeInHigh, std::begin(stepsHigh), std::end(stepsHigh)) * unitLowPerHigh; - const int roundedtimeInLow = numeric::round(timeInLow / blockSizeLow) * blockSizeLow; + const int roundedtimeInLow = static_cast<int>(numeric::round(timeInLow / blockSizeLow) * blockSizeLow); std::wstring output = formatUnitTime(roundedtimeInLow / unitLowPerHigh, unitHigh); if (unitLowPerHigh > blockSizeLow) @@ -162,13 +161,13 @@ std::wstring zen::formatFraction(double fraction) -std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number) +std::wstring zen::impl::includeNumberSeparator(const std::wstring& number) { //we have to include thousands separator ourselves; this doesn't work for all countries (e.g india), but is better than nothing //::setlocale (LC_ALL, ""); -> implicitly called by wxLocale const lconv* localInfo = ::localeconv(); //always bound according to doc - const std::wstring& thousandSep = utfTo<std::wstring>(localInfo->thousands_sep); + const std::wstring& thousandSep = zen::utfTo<std::wstring>(localInfo->thousands_sep); // THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).thousands_sep(); - why not working? // DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).decimal_point(); diff --git a/zen/format_unit.h b/zen/format_unit.h index 154ec542..9c6a4690 100755 --- a/zen/format_unit.h +++ b/zen/format_unit.h @@ -37,7 +37,7 @@ std::wstring formatNumber(NumberType number); //format integer number including //--------------- inline impelementation ------------------------------------------- -namespace ffs_Impl +namespace impl { std::wstring includeNumberSeparator(const std::wstring& number); } @@ -46,7 +46,7 @@ template <class NumberType> inline std::wstring formatNumber(NumberType number) { static_assert(IsInteger<NumberType>::value, ""); - return ffs_Impl::includeNumberSeparator(zen::numberTo<std::wstring>(number)); + return impl::includeNumberSeparator(zen::numberTo<std::wstring>(number)); } } diff --git a/zen/globals.h b/zen/globals.h index 32781f2a..c57d97ff 100755 --- a/zen/globals.h +++ b/zen/globals.h @@ -11,6 +11,7 @@ #include <memory> #include "scope_guard.h" + namespace zen { //solve static destruction order fiasco by providing shared ownership and serialized access to global variables @@ -13,6 +13,7 @@ #include "string_tools.h" #include "format_unit.h" + //minimal layer enabling text translation - without platform/library dependencies! #define ZEN_TRANS_CONCAT_SUB(X, Y) X ## Y @@ -55,7 +56,7 @@ std::shared_ptr<const TranslationHandler> getTranslator(); //######################## implementation ############################## -namespace implementation +namespace impl { inline Global<const TranslationHandler>& refGlobalTranslationHandler() @@ -69,14 +70,14 @@ Global<const TranslationHandler>& refGlobalTranslationHandler() inline std::shared_ptr<const TranslationHandler> getTranslator() { - return implementation::refGlobalTranslationHandler().get(); + return impl::refGlobalTranslationHandler().get(); } inline void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler) { - implementation::refGlobalTranslationHandler().set(std::move(newHandler)); + impl::refGlobalTranslationHandler().set(std::move(newHandler)); } diff --git a/zen/optional.h b/zen/optional.h index a2a1a169..0ef5f1db 100755 --- a/zen/optional.h +++ b/zen/optional.h @@ -10,6 +10,7 @@ #include <cassert> #include <type_traits> + namespace zen { /* diff --git a/zen/process_priority.h b/zen/process_priority.h index bec8f9b5..cfadfff1 100755 --- a/zen/process_priority.h +++ b/zen/process_priority.h @@ -10,6 +10,7 @@ #include <memory> #include "file_error.h" + namespace zen { //signal a "busy" state to the operating system diff --git a/zen/scope_guard.h b/zen/scope_guard.h index 2048af9b..6945b011 100755 --- a/zen/scope_guard.h +++ b/zen/scope_guard.h @@ -13,7 +13,7 @@ //std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP - static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 2 || (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support"); + static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || (__GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ <= 0))), "check std::uncaught_exceptions support"); namespace __cxxabiv1 { diff --git a/zen/shell_execute.h b/zen/shell_execute.h index 18e4854b..43bede61 100755 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -17,10 +17,10 @@ namespace zen { //launch commandline and report errors via popup dialog //Windows: COM needs to be initialized before calling this function! -enum ExecutionType +enum class ExecutionType { - EXEC_TYPE_SYNC, - EXEC_TYPE_ASYNC + SYNC, + ASYNC }; namespace @@ -36,7 +36,7 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError - uses a zero-sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list in Windows */ - if (type == EXEC_TYPE_SYNC) + if (type == ExecutionType::SYNC) { //Posix ::system() - execute a shell command const int rv = ::system(command.c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect... diff --git a/zen/shutdown.cpp b/zen/shutdown.cpp index dd02814f..1794e4a8 100755 --- a/zen/shutdown.cpp +++ b/zen/shutdown.cpp @@ -18,7 +18,7 @@ void zen::shutdownSystem() //throw FileError //https://linux.die.net/man/2/reboot => needs admin rights! //"systemctl" should work without admin rights: - shellExecute("sleep 1; systemctl poweroff", EXEC_TYPE_ASYNC); //throw FileError + shellExecute("sleep 1; systemctl poweroff", ExecutionType::ASYNC); //throw FileError //sleep 1: give FFS some time to properly shut down! } @@ -27,7 +27,7 @@ void zen::shutdownSystem() //throw FileError void zen::suspendSystem() //throw FileError { //"systemctl" should work without admin rights: - shellExecute("systemctl suspend", EXEC_TYPE_ASYNC); //throw FileError + shellExecute("systemctl suspend", ExecutionType::ASYNC); //throw FileError } diff --git a/zen/shutdown.h b/zen/shutdown.h index b9d47df6..df2314f8 100755 --- a/zen/shutdown.h +++ b/zen/shutdown.h @@ -9,6 +9,7 @@ #include "file_error.h" + namespace zen { void shutdownSystem(); //throw FileError diff --git a/zen/string_base.h b/zen/string_base.h index 30699c38..2d043d4f 100755 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -13,8 +13,8 @@ #include <atomic> #include "string_tools.h" -//Zbase - a policy based string class optimizing performance and flexibility +//Zbase - a policy based string class optimizing performance and flexibility namespace zen { /* diff --git a/zen/string_tools.h b/zen/string_tools.h index 5058f78d..7734b6f0 100755 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -27,6 +27,7 @@ template <class Char> bool isDigit (Char c); //not exactly the same as "std: template <class Char> bool isHexDigit (Char c); template <class Char> bool isAsciiAlpha(Char c); template <class Char> Char asciiToLower(Char c); +template <class Char> Char asciiToUpper(Char c); //case-sensitive comparison (compile-time correctness: use different number of arguments as STL comparison predicates!) struct CmpBinary { template <class Char> int operator()(const Char* lhs, size_t lhsLen, const Char* rhs, size_t rhsLen) const; }; @@ -159,6 +160,15 @@ Char asciiToLower(Char c) } +template <class Char> inline +Char asciiToUpper(Char c) +{ + if (static_cast<Char>('a') <= c && c <= static_cast<Char>('z')) + return static_cast<Char>(c - static_cast<Char>('a') + static_cast<Char>('A')); + return c; +} + + template <class S, class T, class Function> inline bool startsWith(const S& str, const T& prefix, Function cmpStringFun) { @@ -740,7 +750,7 @@ std::pair<char, char> hexify(unsigned char c, bool upperCase) else return static_cast<char>('a' + (num - 10)); }; - return std::make_pair(hexifyDigit(c / 16), hexifyDigit(c % 16)); + return { hexifyDigit(c / 16), hexifyDigit(c % 16) }; } diff --git a/zen/string_traits.h b/zen/string_traits.h index 502250c2..805db46d 100755 --- a/zen/string_traits.h +++ b/zen/string_traits.h @@ -63,7 +63,7 @@ private: //---------------------- implementation ---------------------- -namespace implementation +namespace impl { template<class S, class Char> //test if result of S::c_str() can convert to const Char* class HasConversion @@ -137,13 +137,13 @@ public: } template <class T> -struct IsStringLike : StaticBool<implementation::StringTraits<T>::isStringLike> {}; +struct IsStringLike : StaticBool<impl::StringTraits<T>::isStringLike> {}; template <class T> -struct GetCharType : ResultType<typename implementation::StringTraits<T>::CharType> {}; +struct GetCharType : ResultType<typename impl::StringTraits<T>::CharType> {}; -namespace implementation +namespace impl { //strlen/wcslen are vectorized since VS14 CTP3 inline size_t cStringLength(const char* str) { return std::strlen(str); } @@ -162,7 +162,7 @@ size_t cStringLength(const C* str) } #endif -template <class S, typename = typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type> inline +template <class S, typename = typename EnableIf<StringTraits<S>::isStringClass>::Type> inline const typename GetCharType<S>::Type* strBegin(const S& str) //SFINAE: T must be a "string" { return str.c_str(); @@ -179,7 +179,7 @@ inline const char* strBegin(const StringRef<const char >& ref) { return ref inline const wchar_t* strBegin(const StringRef<const wchar_t>& ref) { return ref.data(); } -template <class S, typename = typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type> inline +template <class S, typename = typename EnableIf<StringTraits<S>::isStringClass>::Type> inline size_t strLength(const S& str) //SFINAE: T must be a "string" { return str.length(); @@ -201,7 +201,7 @@ template <class S> inline auto strBegin(S&& str) -> const typename GetCharType<S>::Type* { static_assert(IsStringLike<S>::value, ""); - return implementation::strBegin(std::forward<S>(str)); + return impl::strBegin(std::forward<S>(str)); } @@ -209,7 +209,7 @@ template <class S> inline size_t strLength(S&& str) { static_assert(IsStringLike<S>::value, ""); - return implementation::strLength(std::forward<S>(str)); + return impl::strLength(std::forward<S>(str)); } } diff --git a/zen/thread.h b/zen/thread.h index 0bff5adc..bfb66c31 100755 --- a/zen/thread.h +++ b/zen/thread.h @@ -73,7 +73,7 @@ std::async replacement without crappy semantics: Example: Zstring dirpath = ... - auto ft = zen::runAsync([=](){ return zen::dirExists(dirpath); }); + auto ft = zen::runAsync([=]{ return zen::dirExists(dirpath); }); if (ft.wait_for(std::chrono::milliseconds(200)) == std::future_status::ready && ft.get()) //dir exising */ @@ -22,19 +22,19 @@ struct TimeComp //replaces std::tm and SYSTEMTIME int minute = 0; //0-59 int second = 0; //0-60 (including leap second) }; - inline bool operator==(const TimeComp& lhs, const TimeComp& rhs) { return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second; } +inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); } -TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components -time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error +TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components, returns TimeComp() on error +time_t localToTimeT(const TimeComp& tc); //convert local time components to time_t (UTC), returns -1 on error -TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components -time_t utcToTimeT(const TimeComp& comp); //convert UTC time components to time_t (UTC), returns -1 on error +TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components, returns TimeComp() on error +time_t utcToTimeT(const TimeComp& tc); //convert UTC time components to time_t (UTC), returns -1 on error -TimeComp getCompileTime(); +TimeComp getCompileTime(); //returns TimeComp() on error //---------------------------------------------------------------------------------------------------------------------------------- @@ -45,7 +45,7 @@ format (current) date and time; example: formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34" */ template <class String, class String2> -String formatTime(const String2& format, const TimeComp& comp = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure +String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure //the "format" parameter of formatTime() is partially specialized with the following type tags: const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 08/23/01 @@ -58,8 +58,12 @@ const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M //---------------------------------------------------------------------------------------------------------------------------------- +/* +example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02"); + parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02"); +*/ template <class String, class String2> -bool parseTime(const String& format, const String2& str, TimeComp& comp); //similar to ::strptime(), return true on success +TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime() //---------------------------------------------------------------------------------------------------------------------------------- @@ -75,29 +79,26 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp); //simi - - - //############################ implementation ############################## -namespace implementation +namespace impl { inline -std::tm toClibTimeComponents(const TimeComp& comp) +std::tm toClibTimeComponents(const TimeComp& tc) { - assert(1 <= comp.month && comp.month <= 12 && - 1 <= comp.day && comp.day <= 31 && - 0 <= comp.hour && comp.hour <= 23 && - 0 <= comp.minute && comp.minute <= 59 && - 0 <= comp.second && comp.second <= 61); + assert(1 <= tc.month && tc.month <= 12 && + 1 <= tc.day && tc.day <= 31 && + 0 <= tc.hour && tc.hour <= 23 && + 0 <= tc.minute && tc.minute <= 59 && + 0 <= tc.second && tc.second <= 61); std::tm ctc = {}; - ctc.tm_year = comp.year - 1900; //years since 1900 - ctc.tm_mon = comp.month - 1; //0-11 - ctc.tm_mday = comp.day; //1-31 - ctc.tm_hour = comp.hour; //0-23 - ctc.tm_min = comp.minute; //0-59 - ctc.tm_sec = comp.second; //0-60 (including leap second) - ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available + ctc.tm_year = tc.year - 1900; //years since 1900 + ctc.tm_mon = tc.month - 1; //0-11 + ctc.tm_mday = tc.day; //1-31 + ctc.tm_hour = tc.hour; //0-23 + ctc.tm_min = tc.minute; //0-59 + ctc.tm_sec = tc.second; //0-60 (including leap second) + ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available //ctc.tm_wday //ctc.tm_yday return ctc; @@ -106,14 +107,14 @@ std::tm toClibTimeComponents(const TimeComp& comp) inline TimeComp toZenTimeComponents(const std::tm& ctc) { - TimeComp comp; - comp.year = ctc.tm_year + 1900; - comp.month = ctc.tm_mon + 1; - comp.day = ctc.tm_mday; - comp.hour = ctc.tm_hour; - comp.minute = ctc.tm_min; - comp.second = ctc.tm_sec; - return comp; + TimeComp tc; + tc.year = ctc.tm_year + 1900; + tc.month = ctc.tm_mon + 1; + tc.day = ctc.tm_mday; + tc.hour = ctc.tm_hour; + tc.minute = ctc.tm_min; + tc.second = ctc.tm_sec; + return tc; } @@ -206,7 +207,6 @@ bool isValid(const std::tm& t) template <class CharType> inline size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr) { - return strftimeWrap_impl(buffer, bufferSize, format, timeptr); } @@ -215,10 +215,10 @@ struct UserDefinedFormatTag {}; struct PredefinedFormatTag {}; template <class String, class String2> inline -String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure +String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure { using CharType = typename GetCharType<String>::Type; - std::tm ctc = toClibTimeComponents(comp); + std::tm ctc = toClibTimeComponents(tc); std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent @@ -227,11 +227,12 @@ String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormat return String(buffer, charsWritten); } + template <class String, class FormatType> inline -String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag) +String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag) { using CharType = typename GetCharType<String>::Type; - return formatTime<String>(GetFormat<FormatType>().format(CharType()), comp, UserDefinedFormatTag()); + return formatTime<String>(GetFormat<FormatType>().format(CharType()), tc, UserDefinedFormatTag()); } } @@ -239,37 +240,49 @@ String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag) inline TimeComp getLocalTime(time_t utc) { - std::tm comp = {}; - if (::localtime_r(&utc, &comp) == nullptr) + if (utc == -1) //failure code from std::time(nullptr) + return TimeComp(); + + std::tm ctc = {}; + if (::localtime_r(&utc, &ctc) == nullptr) return TimeComp(); - return implementation::toZenTimeComponents(comp); + return impl::toZenTimeComponents(ctc); } inline TimeComp getUtcTime(time_t utc) { - std::tm comp = {}; - if (::gmtime_r(&utc, &comp) == nullptr) + if (utc == -1) //failure code from std::time(nullptr) return TimeComp(); - return implementation::toZenTimeComponents(comp); + std::tm ctc = {}; + if (::gmtime_r(&utc, &ctc) == nullptr) + return TimeComp(); + + return impl::toZenTimeComponents(ctc); } inline -time_t localToTimeT(const TimeComp& comp) //returns -1 on error +time_t localToTimeT(const TimeComp& tc) //returns -1 on error { - std::tm ctc = implementation::toClibTimeComponents(comp); + if (tc == TimeComp()) + return -1; + + std::tm ctc = impl::toClibTimeComponents(tc); return std::mktime(&ctc); } inline -time_t utcToTimeT(const TimeComp& comp) //returns -1 on error +time_t utcToTimeT(const TimeComp& tc) //returns -1 on error { - std::tm ctc = implementation::toClibTimeComponents(comp); + if (tc == TimeComp()) + return -1; + + std::tm ctc = impl::toClibTimeComponents(tc); ctc.tm_isdst = 0; //"Zero (0) to indicate that standard time is in effect" => unused by _mkgmtime, but take no chances return ::timegm(&ctc); } @@ -283,39 +296,36 @@ TimeComp getCompileTime() if (compileTime[4] == ' ') //day is space-padded, but %d expects zero-padding compileTime[4] = '0'; - TimeComp tc = {}; - if (parseTime("%b %d %Y %H:%M:%S", compileTime, tc)) - return tc; - - assert(false); - return TimeComp(); + return parseTime("%b %d %Y %H:%M:%S", compileTime); } template <class String, class String2> inline -String formatTime(const String2& format, const TimeComp& comp) +String formatTime(const String2& format, const TimeComp& tc) { + if (tc == TimeComp()) //failure code from getLocalTime() + return String(); + using FormatTag = typename SelectIf< IsSameType<String2, FormatDateTag >::value || IsSameType<String2, FormatTimeTag >::value || IsSameType<String2, FormatDateTimeTag >::value || IsSameType<String2, FormatIsoDateTag >::value || IsSameType<String2, FormatIsoTimeTag >::value || - IsSameType<String2, FormatIsoDateTimeTag>::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type; + IsSameType<String2, FormatIsoDateTimeTag>::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type; - return implementation::formatTime<String>(format, comp, FormatTag()); + return impl::formatTime<String>(format, tc, FormatTag()); } +namespace impl +{ template <class String, class String2> -bool parseTime(const String& format, const String2& str, TimeComp& comp) //return true on success +TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag) { using CharType = typename GetCharType<String>::Type; static_assert(IsSameType<CharType, typename GetCharType<String2>::Type>::value, ""); - const CharType* itFmt = strBegin(format); - const CharType* const fmtLast = itFmt + strLength(format); - const CharType* itStr = strBegin(str); const CharType* const strLast = itStr + strLength(str); @@ -332,6 +342,11 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur return true; }; + TimeComp output; + + const CharType* itFmt = strBegin(format); + const CharType* const fmtLast = itFmt + strLength(format); + for (; itFmt != fmtLast; ++itFmt) { const CharType fmt = *itFmt; @@ -340,22 +355,22 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur { ++itFmt; if (itFmt == fmtLast) - return false; + return TimeComp(); switch (*itFmt) { case 'Y': - if (!extractNumber(comp.year, 4)) - return false; + if (!extractNumber(output.year, 4)) + return TimeComp(); break; case 'm': - if (!extractNumber(comp.month, 2)) - return false; + if (!extractNumber(output.month, 2)) + return TimeComp(); break; case 'b': //abbreviated month name: Jan-Dec { if (strLast - itStr < 3) - return false; + return TimeComp(); const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name) @@ -365,30 +380,30 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur asciiToLower(itStr[2]) == name[2]; }); if (itMonth == std::end(months)) - return false; + return TimeComp(); - comp.month = 1 + static_cast<int>(itMonth - std::begin(months)); + output.month = 1 + static_cast<int>(itMonth - std::begin(months)); itStr += 3; } break; case 'd': - if (!extractNumber(comp.day, 2)) - return false; + if (!extractNumber(output.day, 2)) + return TimeComp(); break; case 'H': - if (!extractNumber(comp.hour, 2)) - return false; + if (!extractNumber(output.hour, 2)) + return TimeComp(); break; case 'M': - if (!extractNumber(comp.minute, 2)) - return false; + if (!extractNumber(output.minute, 2)) + return TimeComp(); break; case 'S': - if (!extractNumber(comp.second, 2)) - return false; + if (!extractNumber(output.second, 2)) + return TimeComp(); break; default: - return false; + return TimeComp(); } } else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars @@ -399,12 +414,36 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur else { if (itStr == strLast || *itStr != fmt) - return false; + return TimeComp(); ++itStr; } } - return itStr == strLast; + if (itStr != strLast) + return TimeComp(); + + return output; +} + + +template <class FormatType, class String> inline +TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag) +{ + using CharType = typename GetCharType<String>::Type; + return parseTime(GetFormat<FormatType>().format(CharType()), str, UserDefinedFormatTag()); +} +} + + +template <class String, class String2> inline +TimeComp parseTime(const String& format, const String2& str) +{ + using FormatTag = typename SelectIf< + IsSameType<String, FormatIsoDateTag >::value || + IsSameType<String, FormatIsoTimeTag >::value || + IsSameType<String, FormatIsoDateTimeTag>::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type; + + return impl::parseTime(format, str, FormatTag()); } } @@ -12,6 +12,7 @@ #include "string_tools.h" //copyStringTo #include "optional.h" + namespace zen { //convert all(!) char- and wchar_t-based "string-like" objects applying a UTF8 conversions (but only if necessary!) @@ -39,7 +40,7 @@ UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t u //----------------------- implementation ---------------------------------- -namespace implementation +namespace impl { using CodePoint = uint32_t; using Char16 = uint16_t; @@ -308,7 +309,7 @@ using UtfDecoder = UtfDecoderImpl<CharType, sizeof(CharType)>; template <class UtfString> inline bool isValidUtf(const UtfString& str) { - using namespace implementation; + using namespace impl; UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str)); while (Opt<CodePoint> cp = decoder.getNext()) @@ -323,7 +324,7 @@ template <class UtfString> inline size_t unicodeLength(const UtfString& str) //return number of code points (+ correctly handle broken UTF encoding) { size_t uniLen = 0; - implementation::UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str)); + impl::UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str)); while (decoder.getNext()) ++uniLen; return uniLen; @@ -334,7 +335,7 @@ template <class UtfString> inline UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t uniPosLast) //return position of unicode char in UTF-encoded string { assert(uniPosFirst <= uniPosLast && uniPosLast <= unicodeLength(str)); - using namespace implementation; + using namespace impl; using CharType = typename GetCharType<UtfString>::Type; UtfString output; if (uniPosFirst >= uniPosLast) //optimize for empty range @@ -353,7 +354,7 @@ UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t u //------------------------------------------------------------------------------------------- -namespace implementation +namespace impl { template <class TargetString, class SourceString> inline TargetString utfTo(const SourceString& str, FalseType) @@ -380,7 +381,7 @@ TargetString utfTo(const SourceString& str, TrueType) { return copyStringTo<Targ template <class TargetString, class SourceString> inline TargetString utfTo(const SourceString& str) { - return implementation::utfTo<TargetString>(str, StaticBool<sizeof(typename GetCharType<SourceString>::Type) == sizeof(typename GetCharType<TargetString>::Type)>()); + return impl::utfTo<TargetString>(str, StaticBool<sizeof(typename GetCharType<SourceString>::Type) == sizeof(typename GetCharType<TargetString>::Type)>()); } } diff --git a/zen/xml_io.h b/zen/xml_io.h index 8d3346c6..a53a7edb 100755 --- a/zen/xml_io.h +++ b/zen/xml_io.h @@ -10,11 +10,11 @@ #include <zenxml/xml.h> #include "file_error.h" + //combine zen::Xml and zen file i/o //-> loadXmlDocument vs loadStream: //1. better error reporting //2. quick exit if (potentially large) input file is not an XML - namespace zen { XmlDoc loadXmlDocument(const Zstring& filePath); //throw FileError diff --git a/zen/zstring.cpp b/zen/zstring.cpp index 2aa3b3f2..ce94fe56 100755 --- a/zen/zstring.cpp +++ b/zen/zstring.cpp @@ -44,18 +44,17 @@ int compareNoCaseUtf8(const char* lhs, size_t lhsLen, const char* rhs, size_t rh //- strncasecmp implements ASCII CI-comparsion only! => signature is broken for UTF8-input; toupper() similarly doesn't support Unicode //- wcsncasecmp: https://opensource.apple.com/source/Libc/Libc-763.12/string/wcsncasecmp-fbsd.c // => re-implement comparison based on towlower() to avoid memory allocations - using namespace zen::implementation; - UtfDecoder<char> decL(lhs, lhsLen); - UtfDecoder<char> decR(rhs, rhsLen); + impl::UtfDecoder<char> decL(lhs, lhsLen); + impl::UtfDecoder<char> decR(rhs, rhsLen); for (;;) { - const Opt<CodePoint> cpL = decL.getNext(); - const Opt<CodePoint> cpR = decR.getNext(); + const Opt<impl::CodePoint> cpL = decL.getNext(); + const Opt<impl::CodePoint> cpR = decR.getNext(); if (!cpL || !cpR) return static_cast<int>(!cpR) - static_cast<int>(!cpL); - static_assert(sizeof(wchar_t) == sizeof(CodePoint), ""); + static_assert(sizeof(wchar_t) == sizeof(impl::CodePoint), ""); const wchar_t charL = ::towlower(static_cast<wchar_t>(*cpL)); //ordering: towlower() converts to higher code points than towupper() const wchar_t charR = ::towlower(static_cast<wchar_t>(*cpR)); //uses LC_CTYPE category of current locale if (charL != charR) |