summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/basic_math.h15
-rw-r--r--zen/build_info.h6
-rw-r--r--zen/deprecate.h6
-rw-r--r--zen/dir_watcher.cpp56
-rw-r--r--zen/error_log.h8
-rw-r--r--zen/file_access.cpp170
-rw-r--r--zen/file_access.h4
-rw-r--r--zen/file_error.h8
-rw-r--r--zen/file_id_def.h6
-rw-r--r--zen/file_io.cpp11
-rw-r--r--zen/file_io.h6
-rw-r--r--zen/file_traverser.cpp16
-rw-r--r--zen/file_traverser.h6
-rw-r--r--zen/fixed_list.h23
-rw-r--r--zen/format_unit.cpp19
-rw-r--r--zen/format_unit.h3
-rw-r--r--zen/guid.h9
-rw-r--r--zen/i18n.h39
-rw-r--r--zen/int64.h71
-rw-r--r--zen/long_path_prefix.h8
-rw-r--r--zen/optional.h53
-rw-r--r--zen/perf.h24
-rw-r--r--zen/process_priority.cpp5
-rw-r--r--zen/process_priority.h6
-rw-r--r--zen/recycler.cpp18
-rw-r--r--zen/recycler.h6
-rw-r--r--zen/scope_guard.h115
-rw-r--r--zen/serialize.h6
-rw-r--r--zen/shell_execute.h12
-rw-r--r--zen/stl_tools.h37
-rw-r--r--zen/string_base.h10
-rw-r--r--zen/string_tools.h95
-rw-r--r--zen/string_traits.h55
-rw-r--r--zen/symlink_target.h6
-rw-r--r--zen/thread.h90
-rw-r--r--zen/tick_count.h18
-rw-r--r--zen/time.h91
-rw-r--r--zen/type_tools.h6
-rw-r--r--zen/type_traits.h29
-rw-r--r--zen/utf.h6
-rw-r--r--zen/warn_static.h6
-rw-r--r--zen/win.h6
-rw-r--r--zen/xml_io.h6
-rw-r--r--zen/zstring.cpp59
-rw-r--r--zen/zstring.h118
45 files changed, 716 insertions, 657 deletions
diff --git a/zen/basic_math.h b/zen/basic_math.h
index 14fcae9c..8b745caf 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef BASIC_MATH_HEADER_34726398432
-#define BASIC_MATH_HEADER_34726398432
+#ifndef BASIC_MATH_H_3472639843265675
+#define BASIC_MATH_H_3472639843265675
#include <algorithm>
#include <iterator>
@@ -14,6 +14,7 @@
#include <functional>
#include <cassert>
+
namespace numeric
{
template <class T>
@@ -26,10 +27,10 @@ template <class T>
int sign(T value); //returns -1/0/1
template <class T>
-const T& min(const T& a, const T& b, const T& c);
+T min(T a, T b, T c);
template <class T>
-const T& max(const T& a, const T& b, const T& c);
+T max(T a, T b, T c);
template <class T>
void clamp(T& val, const T& minVal, const T& maxVal); //make sure minVal <= val && val <= maxVal
@@ -114,14 +115,14 @@ int sign(T value) //returns -1/0/1
template <class T> inline
-const T& min(const T& a, const T& b, const T& c)
+T min(T a, T b, T c) //don't follow std::min's "const T&(const T&, const T&)" API
{
return std::min(std::min(a, b), c);
}
template <class T> inline
-const T& max(const T& a, const T& b, const T& c)
+T max(T a, T b, T c)
{
return std::max(std::max(a, b), c);
}
@@ -396,4 +397,4 @@ double norm2(InputIterator first, InputIterator last)
}
}
-#endif //BASIC_MATH_HEADER_34726398432
+#endif //BASIC_MATH_H_3472639843265675
diff --git a/zen/build_info.h b/zen/build_info.h
index 7c738847..09e1c5a7 100644
--- a/zen/build_info.h
+++ b/zen/build_info.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef BUILDINFO_H_5928539285603428657
-#define BUILDINFO_H_5928539285603428657
+#ifndef BUILD_INFO_H_5928539285603428657
+#define BUILD_INFO_H_5928539285603428657
namespace zen
{
@@ -35,4 +35,4 @@ namespace zen
#endif
}
-#endif //BUILDINFO_H_5928539285603428657
+#endif //BUILD_INFO_H_5928539285603428657
diff --git a/zen/deprecate.h b/zen/deprecate.h
index 49d8386b..5cac14c3 100644
--- a/zen/deprecate.h
+++ b/zen/deprecate.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef DEPRECATE_HEADER_2348970348
-#define DEPRECATE_HEADER_2348970348
+#ifndef DEPRECATE_H_234897087787348
+#define DEPRECATE_H_234897087787348
//compiler macros: http://predef.sourceforge.net/precomp.html
#ifdef __GNUC__
@@ -18,4 +18,4 @@
#error add your platform here!
#endif
-#endif //DEPRECATE_HEADER_2348970348
+#endif //DEPRECATE_H_234897087787348
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 3bab8d34..97ecafe5 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -14,6 +14,7 @@
#include "device_notify.h"
#include "win.h" //includes "windows.h"
#include "long_path_prefix.h"
+ #include "optional.h"
#elif defined ZEN_LINUX
#include <map>
@@ -119,9 +120,7 @@ public:
void reportError(const std::wstring& msg, const std::wstring& description, DWORD errorCode) //throw()
{
std::lock_guard<std::mutex> dummy(lockAccess);
-
- ErrorInfo newInfo = { copyStringTo<BasicWString>(msg), copyStringTo<BasicWString>(description), errorCode };
- errorInfo = std::make_unique<ErrorInfo>(newInfo);
+ errorInfo = ErrorInfo({ copyStringTo<BasicWString>(msg), copyStringTo<BasicWString>(description), errorCode });
}
private:
@@ -136,7 +135,7 @@ private:
BasicWString descr;
DWORD errorCode;
};
- std::unique_ptr<ErrorInfo> errorInfo; //non-empty if errors occurred in thread
+ Opt<ErrorInfo> errorInfo; //non-empty if errors occurred in thread
};
@@ -147,8 +146,7 @@ public:
ReadChangesAsync(const Zstring& directory, //make sure to not leak-in thread-unsafe types!
const std::shared_ptr<SharedData>& shared) :
shared_(shared),
- dirpathPf(appendSeparator(directory)),
- hDir(INVALID_HANDLE_VALUE)
+ dirpathPf(appendSeparator(directory))
{
hDir = ::CreateFile(applyLongPathPrefix(dirpathPf).c_str(), //_In_ LPCTSTR lpFileName,
FILE_LIST_DIRECTORY, //_In_ DWORD dwDesiredAccess,
@@ -218,7 +216,7 @@ public:
}
//async I/O is a resource that needs to be guarded since it will write to local variable "buffer"!
- zen::ScopeGuard guardAio = zen::makeGuard([&]
+ auto guardAio = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&]
{
//Canceling Pending I/O Operations: http://msdn.microsoft.com/en-us/library/aa363789(v=vs.85).aspx
#ifdef ZEN_WIN_VISTA_AND_LATER
@@ -265,7 +263,7 @@ private:
std::shared_ptr<SharedData> shared_;
//worker thread only:
Zstring dirpathPf; //thread safe!
- HANDLE hDir;
+ HANDLE hDir = INVALID_HANDLE_VALUE;
};
@@ -277,11 +275,9 @@ public:
InterruptibleThread& worker) :
notificationHandle(registerFolderRemovalNotification(hDir, //throw FileError
displayPath,
- [this] { this->onRequestRemoval (); }, //noexcept!
+ [this]{ this->onRequestRemoval (); }, //noexcept!
[this](bool successful) { this->onRemovalFinished(); })), //
- worker_(worker),
- removalRequested(false),
- operationComplete(false) {}
+ worker_(worker) {}
~HandleVolumeRemoval()
{
@@ -311,8 +307,8 @@ private:
DeviceNotificationHandle* notificationHandle;
InterruptibleThread& worker_;
- bool removalRequested;
- bool operationComplete;
+ bool removalRequested = false;
+ bool operationComplete = false;
};
}
@@ -375,9 +371,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
#elif defined ZEN_LINUX
struct DirWatcher::Pimpl
{
- Pimpl() : notifDescr() {}
-
- int notifDescr;
+ int notifDescr = 0;
std::map<int, Zstring> watchDescrs; //watch descriptor and (sub-)directory name (postfixed with separator) -> owned by "notifDescr"
};
@@ -387,14 +381,14 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
pimpl_(std::make_unique<Pimpl>())
{
//get all subdirectories
- std::vector<Zstring> fullDirList { baseDirPath };
+ std::vector<Zstring> fullFolderList { baseDirPath };
{
std::function<void (const Zstring& path)> traverse;
- traverse = [&traverse, &fullDirList](const Zstring& path)
+ traverse = [&traverse, &fullFolderList](const Zstring& path)
{
traverseFolder(path, nullptr,
- [&](const DirInfo& di ) { fullDirList.push_back(di.fullPath); traverse(di.fullPath); },
+ [&](const DirInfo& di ) { fullFolderList.push_back(di.fullPath); traverse(di.fullPath); },
nullptr, //don't traverse into symlinks (analog to windows build)
[&](const std::wstring& errorMsg) { throw FileError(errorMsg); });
};
@@ -407,7 +401,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
if (pimpl_->notifDescr == -1)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"inotify_init");
- zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->notifDescr); });
+ ZEN_ON_SCOPE_FAIL( ::close(pimpl_->notifDescr); );
//set non-blocking mode
bool initSuccess = false;
@@ -420,7 +414,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"fcntl");
//add watches
- for (const Zstring& subDirPath : fullDirList)
+ for (const Zstring& subDirPath : fullFolderList)
{
int wd = ::inotify_add_watch(pimpl_->notifDescr, subDirPath.c_str(),
IN_ONLYDIR | //"Only watch pathname if it is a directory."
@@ -445,8 +439,6 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
pimpl_->watchDescrs.emplace(wd, appendSeparator(subDirPath));
}
-
- guardDescr.dismiss();
}
@@ -557,8 +549,7 @@ void eventCallback(ConstFSEventStreamRef streamRef,
struct DirWatcher::Pimpl
{
- Pimpl() : eventStream() {}
- FSEventStreamRef eventStream;
+ FSEventStreamRef eventStream = nullptr;
std::vector<DirWatcher::Entry> changedFiles;
};
@@ -583,6 +574,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) :
FSEventStreamContext context = {};
context.info = &pimpl_->changedFiles;
+ //can this fail?? not documented!
pimpl_->eventStream = ::FSEventStreamCreate(nullptr, //CFAllocatorRef allocator,
&eventCallback, //FSEventStreamCallback callback,
&context, //FSEventStreamContext* context,
@@ -591,22 +583,16 @@ DirWatcher::DirWatcher(const Zstring& dirPath) :
0, //CFTimeInterval latency, in seconds
kFSEventStreamCreateFlagWatchRoot |
kFSEventStreamCreateFlagFileEvents); //FSEventStreamCreateFlags flags
- //can this fail?? not documented!
-
- zen::ScopeGuard guardCreate = zen::makeGuard([&] { ::FSEventStreamRelease(pimpl_->eventStream); });
+ ZEN_ON_SCOPE_FAIL( ::FSEventStreamRelease(pimpl_->eventStream); );
+ //no-fail:
::FSEventStreamScheduleWithRunLoop(pimpl_->eventStream, //FSEventStreamRef streamRef,
::CFRunLoopGetCurrent(), //CFRunLoopRef runLoop; CFRunLoopGetCurrent(): failure not documented!
kCFRunLoopDefaultMode); //CFStringRef runLoopMode
- //no-fail
-
- zen::ScopeGuard guardRunloop = zen::makeGuard([&] { ::FSEventStreamInvalidate(pimpl_->eventStream); });
+ ZEN_ON_SCOPE_FAIL( ::FSEventStreamInvalidate(pimpl_->eventStream); );
if (!::FSEventStreamStart(pimpl_->eventStream))
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"Function call failed: FSEventStreamStart"); //no error code documented!
-
- guardCreate .dismiss();
- guardRunloop.dismiss();
}
diff --git a/zen/error_log.h b/zen/error_log.h
index 81892a25..d282ea4b 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef ERRORLOGGING_H_INCLUDED
-#define ERRORLOGGING_H_INCLUDED
+#ifndef ERROR_LOG_H_8917590832147915
+#define ERROR_LOG_H_8917590832147915
#include <cassert>
#include <algorithm>
@@ -86,7 +86,7 @@ namespace
template <class String>
String formatMessageImpl(const LogEntry& entry) //internal linkage
{
- auto getTypeName = [&]() -> std::wstring
+ auto getTypeName = [&]
{
switch (entry.type)
{
@@ -132,4 +132,4 @@ template <class String> inline
String formatMessage(const LogEntry& entry) { return formatMessageImpl<String>(entry); }
}
-#endif //ERRORLOGGING_H_INCLUDED
+#endif //ERROR_LOG_H_8917590832147915
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index e04673d3..2ca373aa 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -8,7 +8,6 @@
#include <map>
#include <algorithm>
#include <stdexcept>
-#include "int64.h"
#include "file_traverser.h"
#include "scope_guard.h"
#include "symlink_target.h"
@@ -17,6 +16,7 @@
#ifdef ZEN_WIN
#include <Aclapi.h>
+ #include "int64.h"
#include "privilege.h"
#include "long_path_prefix.h"
#include "win_ver.h"
@@ -24,7 +24,6 @@
#include <zen/vista_file_op.h> //requires COM initialization!
#endif
-
#elif defined ZEN_LINUX
#include <sys/vfs.h> //statfs
#include <sys/time.h> //lutimes
@@ -135,7 +134,7 @@ bool zen::somethingExists(const Zstring& itemPath)
namespace
{
#ifdef ZEN_WIN
-bool isFatDrive(const Zstring& filePath) //throw()
+bool isFatDrive(const Zstring& filePath) //noexcept
{
const DWORD bufferSize = MAX_PATH + 1;
std::vector<wchar_t> buffer(bufferSize);
@@ -202,12 +201,17 @@ std::uint64_t zen::getFilesize(const Zstring& filePath) //throw FileError
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"CreateFile");
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
- //why not use ::GetFileSizeEx() instead???
- BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
- if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileInformationByHandle");
+ LARGE_INTEGER fileSize = {};
+ if (!::GetFileSizeEx(hFile, //_In_ HANDLE hFile,
+ &fileSize)) //_Out_ PLARGE_INTEGER lpFileSize
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileSizeEx");
+ return fileSize.QuadPart;
- return get64BitUInt(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh);
+ //alternative:
+ //BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
+ //if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
+ // THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileInformationByHandle");
+ //return get64BitUInt(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh);
#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::stat fileInfo = {};
@@ -312,53 +316,56 @@ void zen::removeDirectorySimple(const Zstring& dirPath) //throw FileError
return;
}
#endif
-
throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(functionName, ec));
}
- //may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
- //successfully been *marked* for deletion, but some application still has a handle open!
- //e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
- //Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
+ /*
+ Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
+ successfully been *marked* for deletion, but some application still has a handle open!
+ e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
+ Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
+ Alternatives: 1. move file/empty folder to some other location, then DeleteFile()/RemoveDirectory()
+ 2. use CreateFile/FILE_FLAG_DELETE_ON_CLOSE *without* FILE_SHARE_DELETE instead of DeleteFile() => early failure
+ */
}
namespace
{
-void removeDirectoryImpl(const Zstring& dirPath) //throw FileError
+void removeDirectoryImpl(const Zstring& folderPath) //throw FileError
{
- assert(dirExists(dirPath)); //[!] no symlinks in this context!!!
- //attention: check if dirPath is a symlink! Do NOT traverse into it deleting contained files!!!
+ assert(dirExists(folderPath)); //[!] no symlinks in this context!!!
+ //attention: check if folderPath is a symlink! Do NOT traverse into it deleting contained files!!!
- std::vector<Zstring> fileList;
- std::vector<Zstring> dirLinkList;
- std::vector<Zstring> dirList;
+ std::vector<Zstring> filePaths;
+ std::vector<Zstring> folderSymlinkPaths;
+ std::vector<Zstring> folderPaths;
//get all files and directories from current directory (WITHOUT subdirectories!)
- traverseFolder(dirPath,
- [&](const FileInfo& fi) { fileList.push_back(fi.fullPath); },
- [&](const DirInfo& di) { dirList .push_back(di.fullPath); }, //defer recursion => save stack space and allow deletion of extremely deep hierarchies!
+ traverseFolder(folderPath,
+ [&](const FileInfo& fi) { filePaths.push_back(fi.fullPath); },
+ [&](const DirInfo& di) { folderPaths .push_back(di.fullPath); }, //defer recursion => save stack space and allow deletion of extremely deep hierarchies!
[&](const SymlinkInfo& si)
{
#ifdef ZEN_WIN
if (dirExists(si.fullPath)) //dir symlink
- dirLinkList.push_back(si.fullPath);
+ folderSymlinkPaths.push_back(si.fullPath);
else //file symlink, broken symlink
#endif
- fileList.push_back(si.fullPath);
+ filePaths.push_back(si.fullPath);
},
[](const std::wstring& errorMsg) { throw FileError(errorMsg); });
- for (const Zstring& filePath : fileList)
+ for (const Zstring& filePath : filePaths)
removeFile(filePath); //throw FileError
- for (const Zstring& dirLinkPath : dirLinkList)
- removeDirectorySimple(dirLinkPath); //throw FileError
+ for (const Zstring& symlinkPath : folderSymlinkPaths)
+ removeDirectorySimple(symlinkPath); //throw FileError
//delete directories recursively
- for (const Zstring& subDirPath : dirList)
- removeDirectoryImpl(subDirPath); //throw FileError; call recursively to correctly handle symbolic links
+ for (const Zstring& subFolderPath : folderPaths)
+ removeDirectoryImpl(subFolderPath); //throw FileError; call recursively to correctly handle symbolic links
- removeDirectorySimple(dirPath); //throw FileError
+ removeDirectorySimple(folderPath); //throw FileError
}
}
@@ -442,7 +449,7 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
}
#elif defined ZEN_LINUX || defined ZEN_MAC
- //rename() will never fail with EEXIST, but always overwrite!
+ //rename() will never fail with EEXIST, but always (atomically) overwrite! => equivalent to SetFileInformationByHandle() + FILE_RENAME_INFO::ReplaceIfExists
//=> Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy
//=> OS X: no solution
@@ -458,7 +465,7 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
throw FileError(errorMsg, errorDescr);
};
- if (!EqualFilePath()(pathSource, pathTarget)) //OS X: changing file name case is not an "already exists" error!
+ if (!equalFilePath(pathSource, pathTarget)) //OS X: changing file name case is not an "already exists" error!
if (somethingExists(pathTarget))
throwException(EEXIST);
@@ -511,7 +518,7 @@ Zstring findUnused8Dot3Name(const Zstring& filePath) //find a unique 8.3 short n
if (!somethingExists(output)) //ensure uniqueness
return output;
}
- throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...") + utfCvrtTo<std::string>(pathPrefix) +
+ throw std::runtime_error(std::string("100,000,000 files, one for each number, exist in this directory? You're kidding...") + utfCvrtTo<std::string>(pathPrefix) +
"\n" + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
}
@@ -529,8 +536,8 @@ bool have8dot3NameClash(const Zstring& filePath)
if (!shortName.empty() &&
!longName .empty() &&
- EqualFilePath()(origName, shortName) &&
- !EqualFilePath()(shortName, longName))
+ equalFilePath(origName, shortName) &&
+ !equalFilePath(shortName, longName))
{
//for filePath short and long file name are equal and another unrelated file happens to have the same short name
//e.g. filePath == "TESTWE~1", but another file is existing named "TestWeb" with short name ""TESTWE~1"
@@ -896,9 +903,9 @@ void setFileTimeRaw(const Zstring& filePath, const struct ::timespec& modTime, P
#elif defined ZEN_MAC
struct AttrBufFileTimes
{
- std::uint32_t length;
- struct ::timespec createTime; //keep order; see docs!
- struct ::timespec writeTime; //
+ std::uint32_t length = 0;
+ struct ::timespec createTime = {}; //keep order; see docs!
+ struct ::timespec writeTime = {}; //
} __attribute__((aligned(4), packed));
@@ -915,7 +922,7 @@ void setFileTimeRaw(const Zstring& filePath,
attribs.bitmapcount = ATTR_BIT_MAP_COUNT;
attribs.commonattr = (createTime ? ATTR_CMN_CRTIME : 0) | ATTR_CMN_MODTIME;
- AttrBufFileTimes newTimes = {};
+ AttrBufFileTimes newTimes;
if (createTime)
{
newTimes.createTime.tv_sec = createTime->tv_sec;
@@ -944,7 +951,7 @@ void getFileTimeRaw(int fd, //throw FileError
attribs.bitmapcount = ATTR_BIT_MAP_COUNT;
attribs.commonattr = ATTR_CMN_CRTIME | ATTR_CMN_MODTIME;
- AttrBufFileTimes fileTimes = {};
+ AttrBufFileTimes fileTimes;
const int rv = ::fgetattrlist(fd, //int fd,
&attribs, //struct ::attrlist* attrList,
@@ -1080,7 +1087,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
if (rv3 < 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtPath(target)), L"setfilecon");
}
-#endif //HAVE_SELINUX
+#endif
//copy permissions for files, directories or symbolic links: requires admin rights
@@ -1340,7 +1347,9 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
bool copyFilePermissions)
{
#ifdef ZEN_WIN
- //special handling for volume root: trying to create existing root directory results in ERROR_ACCESS_DENIED rather than ERROR_ALREADY_EXISTS!
+auto getErrorMsg = [](const Zstring& path){ return replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(path)); };
+
+//special handling for volume root: trying to create existing root directory results in ERROR_ACCESS_DENIED rather than ERROR_ALREADY_EXISTS!
Zstring dirTmp = removeLongPathPrefix(endsWith(targetPath, FILE_NAME_SEPARATOR) ?
beforeLast(targetPath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE) :
targetPath);
@@ -1349,16 +1358,19 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
{
dirTmp += FILE_NAME_SEPARATOR; //we do not support "C:" to represent a relative path!
- const ErrorCode lastError = somethingExists(dirTmp) ? ERROR_ALREADY_EXISTS : ERROR_PATH_NOT_FOUND; //don't use dirExists() => harmonize with ErrorTargetExisting!
-
- const std::wstring errorMsg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(dirTmp));
- const std::wstring errorDescr = formatSystemError(L"CreateDirectory", lastError);
+ const DWORD ec = somethingExists(dirTmp) ? ERROR_ALREADY_EXISTS : ERROR_PATH_NOT_FOUND; //don't use dirExists() => harmonize with ErrorTargetExisting!
+ const std::wstring errorDescr = formatSystemError(L"CreateDirectory", ec);
- if (lastError == ERROR_ALREADY_EXISTS)
- throw ErrorTargetExisting(errorMsg, errorDescr);
- throw FileError(errorMsg, errorDescr); //[!] this is NOT a ErrorTargetPathMissing case!
+ if (ec == ERROR_ALREADY_EXISTS)
+ throw ErrorTargetExisting(getErrorMsg(dirTmp), errorDescr);
+ throw FileError(getErrorMsg(dirTmp), errorDescr); //[!] this is NOT a ErrorTargetPathMissing case!
}
+ //deliberately don't support creating irregular folders like "...." https://social.technet.microsoft.com/Forums/windows/en-US/ffee2322-bb6b-4fdf-86f9-8f93cf1fa6cb/
+ if (endsWith(targetPath, L' ') ||
+ endsWith(targetPath, L'.'))
+ throw FileError(getErrorMsg(targetPath), replaceCpy(_("%x is not a regular directory name."), L"%x", fmtPath(afterLast(targetPath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL))));
+
//don't use ::CreateDirectoryEx:
//- it may fail with "wrong parameter (error code 87)" when source is on mapped online storage
//- automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)!
@@ -1383,14 +1395,13 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
if (ec != ERROR_SUCCESS)
{
- const std::wstring errorMsg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(targetPath));
const std::wstring errorDescr = formatSystemError(L"CreateDirectory", ec);
if (ec == ERROR_ALREADY_EXISTS)
- throw ErrorTargetExisting(errorMsg, errorDescr);
+ throw ErrorTargetExisting(getErrorMsg(targetPath), errorDescr);
else if (ec == ERROR_PATH_NOT_FOUND)
- throw ErrorTargetPathMissing(errorMsg, errorDescr);
- throw FileError(errorMsg, errorDescr);
+ throw ErrorTargetPathMissing(getErrorMsg(targetPath), errorDescr);
+ throw FileError(getErrorMsg(targetPath), errorDescr);
}
}
@@ -1489,13 +1500,12 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
/*int rv =*/ ::copyfile(sourcePath.c_str(), targetPath.c_str(), 0, COPYFILE_XATTR);
#endif
- zen::ScopeGuard guardNewDir = zen::makeGuard([&] { try { removeDirectorySimple(targetPath); } catch (FileError&) {} }); //ensure cleanup:
+ ZEN_ON_SCOPE_FAIL(try { removeDirectorySimple(targetPath); }
+ catch (FileError&) {}); //ensure cleanup:
//enforce copying file permissions: it's advertized on GUI...
if (copyFilePermissions)
copyItemPermissions(sourcePath, targetPath, ProcSymlink::FOLLOW); //throw FileError
-
- guardNewDir.dismiss(); //target has been created successfully!
}
}
@@ -1529,7 +1539,8 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourceLink)), L"%y", L"\n" + fmtPath(targetLink)), functionName);
//allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist!
- zen::ScopeGuard guardNewLink = zen::makeGuard([&]
+
+ auto cleanUp = [&]
{
try
{
@@ -1541,7 +1552,8 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
removeFile(targetLink); //throw FileError
}
catch (FileError&) {}
- });
+ };
+ ZEN_ON_SCOPE_FAIL(cleanUp());
//file times: essential for sync'ing a symlink: enforce this! (don't just try!)
#ifdef ZEN_WIN
@@ -1573,8 +1585,6 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
if (copyFilePermissions)
copyItemPermissions(sourceLink, targetLink, ProcSymlink::DIRECT); //throw FileError
-
- guardNewLink.dismiss(); //target has been created successfully!
}
@@ -1798,7 +1808,8 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
throw FileError(errorMsg, errorDescr);
}
- ScopeGuard guardTarget = makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {} }); //transactional behavior: guard just after opening target and before managing hFileTarget
+ ZEN_ON_SCOPE_FAIL(try { removeFile(targetFile); }
+ catch (FileError&) {} ); //transactional behavior: guard just after opening target and before managing hFileTarget
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFileTarget));
//----------------------------------------------------------------------
@@ -1807,7 +1818,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"GetFileInformationByHandle");
//return up-to-date file attributes
- InSyncAttributes newAttrib = {};
+ InSyncAttributes newAttrib;
newAttrib.fileSize = get64BitUInt(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh);
newAttrib.modificationTime = filetimeToTimeT(fileInfoSource.ftLastWriteTime); //no DST hack (yet)
newAttrib.sourceFileId = extractFileId(fileInfoSource);
@@ -1923,7 +1934,6 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
&fileInfoSource.ftLastWriteTime))
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(targetFile)), L"SetFileTime");
- guardTarget.dismiss();
return newAttrib;
}
@@ -1938,20 +1948,17 @@ struct CallbackData
const Zstring& targetFile) :
sourceFile_(sourceFile),
targetFile_(targetFile),
- onUpdateCopyStatus_(onUpdateCopyStatus),
- fileInfoSrc(),
- fileInfoTrg(),
- bytesReported() {}
+ onUpdateCopyStatus_(onUpdateCopyStatus) {}
const Zstring& sourceFile_;
const Zstring& targetFile_;
const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus_; //optional
std::exception_ptr exception; //out
- BY_HANDLE_FILE_INFORMATION fileInfoSrc; //out: modified by CopyFileEx() at beginning
- BY_HANDLE_FILE_INFORMATION fileInfoTrg; //
+ BY_HANDLE_FILE_INFORMATION fileInfoSrc{}; //out: modified by CopyFileEx() at beginning
+ BY_HANDLE_FILE_INFORMATION fileInfoTrg{}; //
- std::int64_t bytesReported; //used internally to calculate bytes transferred delta
+ std::int64_t bytesReported = 0; //used internally to calculate bytes transferred delta
};
@@ -2060,7 +2067,7 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
try { activatePrivilege(SE_RESTORE_NAME); }
catch (const FileError&) { backupPrivilegesActive = false; }
- zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {} });
+ auto guardTarget = zen::makeGuard<ScopeGuardRunMode::ON_FAIL>([&] { try { removeFile(targetFile); } catch (FileError&) {} });
//transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we? ;)
DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS;
@@ -2152,9 +2159,7 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
// - perf: recent measurements show no slow down at all for buffered USB sticks!
setFileTimeRaw(targetFile, &cbd.fileInfoSrc.ftCreationTime, cbd.fileInfoSrc.ftLastWriteTime, ProcSymlink::FOLLOW); //throw FileError
- guardTarget.dismiss(); //target has been created successfully!
-
- InSyncAttributes newAttrib = {};
+ InSyncAttributes newAttrib;
newAttrib.fileSize = get64BitUInt(cbd.fileInfoSrc.nFileSizeLow, cbd.fileInfoSrc.nFileSizeHigh);
newAttrib.modificationTime = filetimeToTimeT(cbd.fileInfoSrc.ftLastWriteTime);
newAttrib.sourceFileId = extractFileId(cbd.fileInfoSrc);
@@ -2228,8 +2233,9 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
}
if (onUpdateCopyStatus) onUpdateCopyStatus(0); //throw X!
- InSyncAttributes newAttrib = {};
- zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {} });
+ InSyncAttributes newAttrib;
+ ZEN_ON_SCOPE_FAIL( try { removeFile(targetFile); }
+ catch (FileError&) {} );
//transactional behavior: place guard after ::open() and before lifetime of FileOutput:
//=> don't delete file that existed previously!!!
{
@@ -2278,7 +2284,6 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
setFileTime(targetFile, sourceInfo.st_mtime, ProcSymlink::FOLLOW); //throw FileError
#endif
- guardTarget.dismiss(); //target has been created successfully!
return newAttrib;
}
#endif
@@ -2303,15 +2308,12 @@ InSyncAttributes zen::copyNewFile(const Zstring& sourceFile, const Zstring& targ
{
const InSyncAttributes attr = copyFileOsSpecific(sourceFile, targetFile, onUpdateCopyStatus); //throw FileError, ErrorTargetExisting, ErrorFileLocked
- if (copyFilePermissions)
- {
- //at this point we know we created a new file, so it's fine to delete it for cleanup!
- zen::ScopeGuard guardTargetFile = zen::makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {}});
+ //at this point we know we created a new file, so it's fine to delete it for cleanup!
+ ZEN_ON_SCOPE_FAIL(try { removeFile(targetFile); }
+ catch (FileError&) {});
+ if (copyFilePermissions)
copyItemPermissions(sourceFile, targetFile, ProcSymlink::FOLLOW); //throw FileError
- guardTargetFile.dismiss(); //target has been created successfully!
- }
-
return attr;
}
diff --git a/zen/file_access.h b/zen/file_access.h
index 3588f79b..ec5bda66 100644
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -55,8 +55,8 @@ void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copy
struct InSyncAttributes
{
- std::uint64_t fileSize;
- std::int64_t modificationTime; //time_t UTC compatible
+ std::uint64_t fileSize = 0;
+ std::int64_t modificationTime = 0; //time_t UTC compatible
FileId sourceFileId;
FileId targetFileId;
};
diff --git a/zen/file_error.h b/zen/file_error.h
index 7be52282..f41a878a 100644
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FILEERROR_H_INCLUDED_839567308565656789
-#define FILEERROR_H_INCLUDED_839567308565656789
+#ifndef FILE_ERROR_H_839567308565656789
+#define FILE_ERROR_H_839567308565656789
#include <string>
#include "zstring.h"
@@ -49,7 +49,7 @@ DEFINE_NEW_FILE_ERROR(ErrorDifferentVolume);
__pragma(warning(suppress: 4127)) /*"conditional expression is constant"*/ \
} while (false)
-#else //variant witout "__pragma":
+#else //same thing witout "__pragma":
#define THROW_LAST_FILE_ERROR(msg, functionName) \
do { const ErrorCode ecInternal = getLastError(); throw FileError(msg, formatSystemError(functionName, ecInternal)); } while (false)
#endif
@@ -66,4 +66,4 @@ inline std::wstring fmtPath(const Zstring& displayPath) { return fmtPath(utfCvrt
inline std::wstring fmtPath(const wchar_t* displayPath) { return fmtPath(std::wstring(displayPath)); }
}
-#endif //FILEERROR_H_INCLUDED_839567308565656789
+#endif //FILE_ERROR_H_839567308565656789
diff --git a/zen/file_id_def.h b/zen/file_id_def.h
index c33edf81..24e45795 100644
--- a/zen/file_id_def.h
+++ b/zen/file_id_def.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FILE_ID_INTERNAL_HEADER_013287632486321493
-#define FILE_ID_INTERNAL_HEADER_013287632486321493
+#ifndef FILE_ID_DEF_H_013287632486321493
+#define FILE_ID_DEF_H_013287632486321493
#include <utility>
@@ -66,4 +66,4 @@ FileId extractFileId(const struct ::stat& fileInfo)
#endif
}
-#endif //FILE_ID_INTERNAL_HEADER_013287632486321493
+#endif //FILE_ID_DEF_H_013287632486321493
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 68e852da..5e8b7a1d 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -150,14 +150,11 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
//------------------------------------------------------------------------------------------------------
- ScopeGuard constructorGuard = zen::makeGuard([&] //destructor call would lead to member double clean-up!!!
- {
-#ifdef ZEN_WIN
- ::CloseHandle(fileHandle);
+#ifdef ZEN_WIN //destructor call would lead to member double clean-up!!!
+ ZEN_ON_SCOPE_FAIL(::CloseHandle(fileHandle));
#elif defined ZEN_LINUX || defined ZEN_MAC
- ::close(fileHandle);
+ ZEN_ON_SCOPE_FAIL(::close(fileHandle));
#endif
- });
#ifdef ZEN_LINUX //handle still un-owned => need constructor guard
//optimize read-ahead on input file:
@@ -167,8 +164,6 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
#elif defined ZEN_MAC
//"dtruss" doesn't show use of "fcntl() F_RDAHEAD/F_RDADVISE" for "cp")
#endif
-
- constructorGuard.dismiss();
}
diff --git a/zen/file_io.h b/zen/file_io.h
index 52be7f95..5bcf4189 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FILEIO_89578342758342572345
-#define FILEIO_89578342758342572345
+#ifndef FILE_IO_H_89578342758342572345
+#define FILE_IO_H_89578342758342572345
#include "file_error.h"
@@ -88,4 +88,4 @@ private:
};
}
-#endif //FILEIO_89578342758342572345
+#endif //FILE_IO_H_89578342758342572345
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index facce75c..7fd6c596 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -6,9 +6,9 @@
#include "file_traverser.h"
#include "file_error.h"
-#include "int64.h"
#ifdef ZEN_WIN
+ #include "int64.h"
#include "long_path_prefix.h"
#include "file_access.h"
#include "symlink_target.h"
@@ -68,8 +68,8 @@ void zen::traverseFolder(const Zstring& dirPath,
//skip "." and ".."
const wchar_t* const itemNameRaw = findData.cFileName;
- if (itemNameRaw[0] == 0)
- throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item with empty name.");
+ if (itemNameRaw[0] == 0)
+ throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item with empty name.");
if (itemNameRaw[0] == L'.' &&
(itemNameRaw[1] == 0 || (itemNameRaw[1] == L'.' && itemNameRaw[2] == 0)))
@@ -106,15 +106,15 @@ void zen::traverseFolder(const Zstring& dirPath,
std::vector<char> bufferUtfDecomposed;
#endif
- DIR* dirObj = ::opendir(dirPath.c_str()); //directory must NOT end with path separator, except "/"
- if (!dirObj)
+ DIR* folder = ::opendir(dirPath.c_str()); //directory must NOT end with path separator, except "/"
+ if (!folder)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"opendir");
- ZEN_ON_SCOPE_EXIT(::closedir(dirObj)); //never close nullptr handles! -> crash
+ ZEN_ON_SCOPE_EXIT(::closedir(folder)); //never close nullptr handles! -> crash
for (;;)
{
struct ::dirent* dirEntry = nullptr;
- if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0)
+ 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");
//don't retry but restart dir traversal on error! http://blogs.msdn.com/b/oldnewthing/archive/2014/06/12/10533529.aspx
@@ -125,7 +125,7 @@ void zen::traverseFolder(const Zstring& dirPath,
const char* itemNameRaw = dirEntry->d_name;
if (itemNameRaw[0] == 0)
- throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
+ throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
if (itemNameRaw[0] == '.' &&
(itemNameRaw[1] == 0 || (itemNameRaw[1] == '.' && itemNameRaw[2] == 0)))
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index 75c7660c..9f850e01 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FOLDER_TRAVERSER_H_INCLUDED_3127463214871234
-#define FOLDER_TRAVERSER_H_INCLUDED_3127463214871234
+#ifndef FILER_TRAVERSER_H_127463214871234
+#define FILER_TRAVERSER_H_127463214871234
#include <cstdint>
#include <functional>
@@ -41,4 +41,4 @@ void traverseFolder(const Zstring& dirPath, //noexcept
const std::function<void (const std::wstring& errorMsg)>& onError); //
}
-#endif //FOLDER_TRAVERSER_H_INCLUDED_3127463214871234
+#endif //FILER_TRAVERSER_H_127463214871234
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index 61ce3f16..362577d5 100644
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -4,12 +4,13 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef FIXED_LIST_01238467085684139453534
-#define FIXED_LIST_01238467085684139453534
+#ifndef FIXED_LIST_H_01238467085684139453534
+#define FIXED_LIST_H_01238467085684139453534
#include <cassert>
#include <iterator>
+
namespace zen
{
//std::list(C++11)-like class for inplace element construction supporting non-copyable/movable types
@@ -20,9 +21,9 @@ class FixedList
struct Node
{
template <class... Args>
- Node(Args&& ... args) : next(nullptr), val(std::forward<Args>(args)...) {}
+ Node(Args&& ... args) : val(std::forward<Args>(args)...) {}
- Node* next; //singly linked list is sufficient
+ Node* next = nullptr; //singly linked list is sufficient
T val;
};
@@ -35,14 +36,14 @@ public:
class ListIterator : public std::iterator<std::forward_iterator_tag, U>
{
public:
- ListIterator(NodeT* it = nullptr) : iter(it) {}
- ListIterator& operator++() { iter = iter->next; return *this; }
- inline friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) { return lhs.iter == rhs.iter; }
+ ListIterator(NodeT* it = nullptr) : it_(it) {}
+ ListIterator& operator++() { it_ = it_->next; return *this; }
+ inline friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) { return lhs.it_ == rhs.it_; }
inline friend bool operator!=(const ListIterator& lhs, const ListIterator& rhs) { return !(lhs == rhs); }
- U& operator* () const { return iter->val; }
- U* operator->() const { return &iter->val; }
+ U& operator* () const { return it_->val; }
+ U* operator->() const { return &it_->val; }
private:
- NodeT* iter;
+ NodeT* it_;
};
typedef T value_type;
@@ -154,4 +155,4 @@ private:
};
}
-#endif //FIXED_LIST_01238467085684139453534
+#endif //FIXED_LIST_H_01238467085684139453534
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 9624458c..e9c686aa 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -8,12 +8,12 @@
#include "basic_math.h"
#include "i18n.h"
#include "time.h"
-#include "int64.h"
#include <cwchar> //swprintf
#include <ctime>
#include <cstdio>
#ifdef ZEN_WIN
+ #include "int64.h"
#include "win.h" //includes "windows.h"
#include "win_ver.h"
@@ -25,9 +25,18 @@
using namespace zen;
+std::wstring zen::formatTwoDigitPrecision(double value)
+{
+ //print two digits: 0,1 | 1,1 | 11
+ if (numeric::abs(value) < 9.95) //9.99 must not be formatted as "10.0"
+ return printNumber<std::wstring>(L"%.1f", value);
+ return numberTo<std::wstring>(numeric::round(value));
+}
+
+
std::wstring zen::formatThreeDigitPrecision(double value)
{
- //print at least three digits: 0,01 | 0,11 | 1,11 | 11,1 | 111
+ //print three digits: 0,01 | 0,11 | 1,11 | 11,1 | 111
if (numeric::abs(value) < 9.995) //9.999 must not be formatted as "10.00"
return printNumber<std::wstring>(L"%.2f", value);
if (numeric::abs(value) < 99.95) //99.99 must not be formatted as "100.0"
@@ -197,7 +206,7 @@ private:
return inst;
}
- IntegerFormat() : fmt(), valid_(false)
+ IntegerFormat()
{
//all we want is default NUMBERFMT, but set NumDigits to 0
fmt.NumDigits = 0;
@@ -224,10 +233,10 @@ private:
}
}
- NUMBERFMT fmt;
+ NUMBERFMT fmt = {};
std::wstring thousandSep;
std::wstring decimalSep;
- bool valid_;
+ bool valid_ = false;
};
}
#endif
diff --git a/zen/format_unit.h b/zen/format_unit.h
index d50baa32..eacb8d46 100644
--- a/zen/format_unit.h
+++ b/zen/format_unit.h
@@ -19,7 +19,8 @@ std::wstring remainingTimeToString(double timeInSec);
std::wstring fractionToString(double fraction); //within [0, 1]
std::wstring utcToLocalTimeString(std::int64_t utcTime); //like Windows Explorer would...
-std::wstring formatThreeDigitPrecision(double value); //= *at least* three digits
+std::wstring formatTwoDigitPrecision (double value); //format with fixed number of digits
+std::wstring formatThreeDigitPrecision(double value); //(unless value is too large)
template <class NumberType>
std::wstring toGuiString(NumberType number); //format integer number including thousands separator
diff --git a/zen/guid.h b/zen/guid.h
index d4b59eb4..7f247508 100644
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -4,16 +4,15 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef GUID_H_INCLUDED_80425780237502345
-#define GUID_H_INCLUDED_80425780237502345
+#ifndef GUID_H_80425780237502345
+#define GUID_H_80425780237502345
#include <string>
#include <boost/uuid/uuid.hpp>
#ifdef __GNUC__ //boost should clean this mess up
#pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wshadow"
- #pragma GCC diagnostic ignored "-Wuninitialized"
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <boost/uuid/uuid_generators.hpp>
@@ -35,4 +34,4 @@ std::string generateGUID() //creates a 16 byte GUID
}
}
-#endif //GUID_H_INCLUDED_80425780237502345
+#endif //GUID_H_80425780237502345
diff --git a/zen/i18n.h b/zen/i18n.h
index 1a075413..3ab5748a 100644
--- a/zen/i18n.h
+++ b/zen/i18n.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef I18_N_HEADER_3843489325045
-#define I18_N_HEADER_3843489325045
+#ifndef I18_N_H_3843489325044253425456
+#define I18_N_H_3843489325044253425456
#include <string>
#include <memory>
@@ -28,18 +28,24 @@
namespace zen
{
-//implement handler to enable program wide localizations: implement THREAD-SAFE ACCESS!
+//implement handler to enable program wide localizations:
struct TranslationHandler
{
+ //THREAD-SAFETY: "const" member must model thread-safe access!
+ TranslationHandler() {}
virtual ~TranslationHandler() {}
//C++11: std::wstring should be thread-safe like an int
- virtual std::wstring translate(const std::wstring& text) = 0; //simple translation
- virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n) = 0;
+ virtual std::wstring translate(const std::wstring& text) const = 0; //simple translation
+ virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n) const = 0;
+
+private:
+ TranslationHandler (const TranslationHandler&) = delete;
+ TranslationHandler& operator=(const TranslationHandler&) = delete;
};
-void setTranslator(std::unique_ptr<TranslationHandler>&& newHandler = nullptr); //take ownership
-TranslationHandler* getTranslator();
+void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler = nullptr); //take ownership
+const TranslationHandler* getTranslator();
@@ -59,12 +65,13 @@ namespace implementation
inline
std::wstring translate(const std::wstring& text)
{
- if (TranslationHandler* t = getTranslator())
+ if (const TranslationHandler* t = getTranslator())
return t->translate(text);
return text;
}
+
//translate plural forms: "%x day" "%x days"
//returns "1 day" if n == 1; "123 days" if n == 123 for english language
inline
@@ -72,7 +79,7 @@ std::wstring translate(const std::wstring& singular, const std::wstring& plural,
{
assert(contains(plural, L"%x"));
- if (TranslationHandler* t = getTranslator())
+ if (const TranslationHandler* t = getTranslator())
{
std::wstring translation = t->translate(singular, plural, n);
assert(!contains(translation, L"%x"));
@@ -82,6 +89,7 @@ std::wstring translate(const std::wstring& singular, const std::wstring& plural,
return replaceCpy(std::abs(n) == 1 ? singular : plural, L"%x", toGuiString(n));
}
+
template <class T> inline
std::wstring translate(const std::wstring& singular, const std::wstring& plural, T n)
{
@@ -89,19 +97,22 @@ std::wstring translate(const std::wstring& singular, const std::wstring& plural,
return translate(singular, plural, static_cast<std::int64_t>(n));
}
+
inline
-std::unique_ptr<TranslationHandler>& globalHandler()
+std::unique_ptr<const TranslationHandler>& globalHandler()
{
- static std::unique_ptr<TranslationHandler> inst; //external linkage even in header!
+ static std::unique_ptr<const TranslationHandler> inst; //external linkage even in header!
return inst;
}
}
+
inline
-void setTranslator(std::unique_ptr<TranslationHandler>&& newHandler) { implementation::globalHandler() = std::move(newHandler); }
+void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler) { implementation::globalHandler() = std::move(newHandler); }
+
inline
-TranslationHandler* getTranslator() { return implementation::globalHandler().get(); }
+const TranslationHandler* getTranslator() { return implementation::globalHandler().get(); }
}
-#endif //I18_N_HEADER_3843489325045
+#endif //I18_N_H_3843489325044253425456
diff --git a/zen/int64.h b/zen/int64.h
deleted file mode 100644
index bc01a4c2..00000000
--- a/zen/int64.h
+++ /dev/null
@@ -1,71 +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 gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef FFS_LARGE_64_BIT_INTEGER_H_INCLUDED
-#define FFS_LARGE_64_BIT_INTEGER_H_INCLUDED
-
-#include <cstdint>
-
-#ifdef ZEN_WIN
- #include "win.h"
-#endif
-
-
-namespace zen
-{
-#ifdef ZEN_WIN
-inline
-std::int64_t get64BitInt(DWORD low, LONG high)
-{
- static_assert(sizeof(low) + sizeof(high) == sizeof(std::int64_t), "");
-
- LARGE_INTEGER cvt = {};
- cvt.LowPart = low;
- cvt.HighPart = high;
- return cvt.QuadPart;
-}
-
-std::int64_t get64BitInt(std::uint64_t low, std::int64_t high) = delete;
-
-
-inline
-std::uint64_t get64BitUInt(DWORD low, DWORD high)
-{
- static_assert(sizeof(low) + sizeof(high) == sizeof(std::uint64_t), "");
-
- ULARGE_INTEGER cvt = {};
- cvt.LowPart = low;
- cvt.HighPart = high;
- return cvt.QuadPart;
-}
-
-std::int64_t get64BitUInt(std::uint64_t low, std::uint64_t high) = delete;
-
-
-//convert FILETIME (number of 100-nanosecond intervals since January 1, 1601 UTC)
-// to time_t (number of seconds since Jan. 1st 1970 UTC)
-//
-//FAT32 time is preserved exactly: FAT32 -> toTimeT -> tofiletime -> FAT32
-inline
-std::int64_t filetimeToTimeT(const FILETIME& ft)
-{
- return static_cast<std::int64_t>(get64BitUInt(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - get64BitInt(3054539008UL, 2); //caveat: signed/unsigned arithmetics!
- //timeshift between ansi C time and FILETIME in seconds == 11644473600s
-}
-
-inline
-FILETIME timetToFileTime(std::int64_t utcTime)
-{
- ULARGE_INTEGER cvt = {};
- cvt.QuadPart = (utcTime + get64BitInt(3054539008UL, 2)) * 10000000U; //caveat: signed/unsigned arithmetics!
-
- const FILETIME output = { cvt.LowPart, cvt.HighPart };
- return output;
-}
-#endif
-}
-
-#endif //FFS_LARGE_64_BIT_INTEGER_H_INCLUDED
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index 6f6ebfdc..ef8e5dc8 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef LONGPATHPREFIX_H_INCLUDED
-#define LONGPATHPREFIX_H_INCLUDED
+#ifndef LONG_PATH_PREFIX_H_3984678473567247567
+#define LONG_PATH_PREFIX_H_3984678473567247567
#include "win.h"
#include "zstring.h"
@@ -60,7 +60,7 @@ Zstring applyLongPathPrefixImpl(const Zstring& path)
assert(!path.empty()); //nicely check almost all WinAPI accesses!
assert(!zen::isWhiteSpace(path[0]));
- //http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#naming_conventions))
+ //http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#naming_conventions
/*
- special names like ".NUL" create all kinds of trouble (e.g. CreateDirectory() reports success, but does nothing)
unless prefix is supplied => accept as limitation
@@ -131,4 +131,4 @@ Zstring zen::ntPathToWin32Path(const Zstring& path) //noexcept
return path;
}
-#endif //LONGPATHPREFIX_H_INCLUDED
+#endif //LONG_PATH_PREFIX_H_3984678473567247567
diff --git a/zen/optional.h b/zen/optional.h
index d65820c2..c01d95ff 100644
--- a/zen/optional.h
+++ b/zen/optional.h
@@ -8,6 +8,7 @@
#define OPTIONAL_H_2857428578342203589
#include <cassert>
+#include <type_traits>
namespace zen
{
@@ -36,36 +37,52 @@ template <class T>
class Opt
{
public:
- Opt() : value() , valid(false) {}
- Opt(NoValue) : value() , valid(false) {}
- Opt(const T& val) : value(val), valid(true ) {}
+ Opt() {}
+ Opt(NoValue) {}
+ Opt(const T& val) : valid(true) { new (&rawMem) T(val); } //throw X
- Opt(const Opt& tmp) : value(tmp.valid ? tmp.value : T()), valid(tmp.valid) {}
+ Opt(const Opt& other) : valid(other.valid)
+ {
+ if (const T* val = other.get())
+ new (&rawMem) T(*val); //throw X
+ }
- Opt& operator=(const Opt& tmp)
+ ~Opt() { if (T* val = get()) val->~T(); }
+
+ Opt& operator=(const Opt& other) //strong exception-safety iff T::operator=() is strongly exception-safe
{
- if (tmp.valid)
- value = tmp.value;
- valid = tmp.valid;
+ if (T* val = get())
+ {
+ if (const T* valOther = other.get())
+ *val = *valOther; //throw X
+ else
+ {
+ valid = false;
+ val->~T();
+ }
+ }
+ else if (const T* valOther = other.get())
+ {
+ new (&rawMem) T(*valOther); //throw X
+ valid = true;
+ }
return *this;
}
- ////rvalue optimization: only basic exception safety:
- // Opt(Opt&& tmp) : value(std::move(tmp.value)), valid(tmp.valid) {}
-
explicit operator bool() const { return valid; } //thank you C++11!!!
- const T& operator*() const { assert(valid); return value; }
- /**/ T& operator*() { assert(valid); return value; }
+ const T* get() const { return valid ? reinterpret_cast<const T*>(&rawMem) : nullptr; }
+ T* get() { return valid ? reinterpret_cast< T*>(&rawMem) : nullptr; }
- const T* operator->() const { assert(valid); return &value; }
- /**/ T* operator->() { assert(valid); return &value; }
+ const T& operator*() const { return *get(); }
+ /**/ T& operator*() { return *get(); }
- void reset() { valid = false; }
+ const T* operator->() const { return get(); }
+ /**/ T* operator->() { return get(); }
private:
- T value;
- bool valid;
+ std::aligned_storage_t<sizeof(T), alignof(T)> rawMem; //don't require T to be default-constructible!
+ bool valid = false;
};
}
diff --git a/zen/perf.h b/zen/perf.h
index 6015d97b..3762617f 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef DEBUG_PERF_HEADER_83947184145342652456
-#define DEBUG_PERF_HEADER_83947184145342652456
+#ifndef PERF_H_83947184145342652456
+#define PERF_H_83947184145342652456
#include "deprecate.h"
#include "tick_count.h"
@@ -17,6 +17,7 @@
#include <iostream>
#endif
+
//############# two macros for quick performance measurements ###############
#define PERF_START zen::PerfTimer perfTest;
#define PERF_STOP perfTest.showResult();
@@ -30,19 +31,14 @@ public:
class TimerError {};
ZEN_DEPRECATE
- PerfTimer() : //throw TimerError
- ticksPerSec_(ticksPerSec()),
- resultShown(false),
- startTime(getTicksNow()),
- paused(false),
- elapsedUntilPause(0)
+ 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&) {} }
+ ~PerfTimer() { if (!resultShown) try { showResult(); } catch (TimerError&) { assert(false); } }
void pause()
{
@@ -102,12 +98,12 @@ private:
return now;
}
- const std::int64_t ticksPerSec_;
- bool resultShown;
+ const std::int64_t ticksPerSec_ = ticksPerSec(); //return 0 on error
+ bool resultShown = false;
TickVal startTime;
- bool paused;
- int64_t elapsedUntilPause;
+ bool paused = false;
+ int64_t elapsedUntilPause = 0;
};
}
-#endif //DEBUG_PERF_HEADER_83947184145342652456
+#endif //PERF_H_83947184145342652456
diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp
index 017eaa8b..2d1abafa 100644
--- a/zen/process_priority.cpp
+++ b/zen/process_priority.cpp
@@ -30,11 +30,6 @@ PreventStandby::~PreventStandby()
}
-#ifndef PROCESS_MODE_BACKGROUND_BEGIN
- #define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000 // Windows Server 2003 and Windows XP/2000: This value is not supported!
- #define PROCESS_MODE_BACKGROUND_END 0x00200000 //
-#endif
-
struct ScheduleForBackgroundProcessing::Pimpl {};
diff --git a/zen/process_priority.h b/zen/process_priority.h
index 72ce972c..48b95c9e 100644
--- a/zen/process_priority.h
+++ b/zen/process_priority.h
@@ -3,8 +3,8 @@
// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef PREVENTSTANDBY_H_83421759082143245
-#define PREVENTSTANDBY_H_83421759082143245
+#ifndef PROCESS_PRIORITY_H_83421759082143245
+#define PROCESS_PRIORITY_H_83421759082143245
#include <memory>
#include "file_error.h"
@@ -35,4 +35,4 @@ private:
};
}
-#endif //PREVENTSTANDBY_H_83421759082143245
+#endif //PROCESS_PRIORITY_H_83421759082143245
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index d49e686c..59d2729a 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -12,6 +12,8 @@
#ifdef ZEN_WIN_VISTA_AND_LATER
#include "vista_file_op.h"
+ #else
+ #include "com_tools.h"
#endif
#elif defined ZEN_LINUX
@@ -179,12 +181,18 @@ bool zen::recycleBinExists(const Zstring& dirPath, const std::function<void ()>&
#else
//excessive runtime if recycle bin exists, is full and drive is slow:
- auto ft = runAsync([dirPath]()
+ auto ft = runAsync([dirPath]() -> HRESULT
{
- SHQUERYRBINFO recInfo = {};
- recInfo.cbSize = sizeof(recInfo);
- return ::SHQueryRecycleBin(dirPath.c_str(), //__in_opt LPCTSTR pszRootPath,
- &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
+ try
+ {
+ ComInitializer ci; //throw SysError
+
+ SHQUERYRBINFO recInfo = {};
+ recInfo.cbSize = sizeof(recInfo);
+ return ::SHQueryRecycleBin(dirPath.c_str(), //__in_opt LPCTSTR pszRootPath,
+ &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
+ }
+ catch (SysError&) { assert(false); return ERROR_GEN_FAILURE; }
});
while (ft.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
diff --git a/zen/recycler.h b/zen/recycler.h
index 3df7fda2..4b5658cb 100644
--- a/zen/recycler.h
+++ b/zen/recycler.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef RECYCLER_H_INCLUDED_18345067341545
-#define RECYCLER_H_INCLUDED_18345067341545
+#ifndef RECYCLER_H_18345067341545
+#define RECYCLER_H_18345067341545
#include <vector>
#include <functional>
@@ -48,4 +48,4 @@ void recycleOrDelete(const std::vector<Zstring>& filePaths, //throw FileError, r
#endif
}
-#endif //RECYCLER_H_INCLUDED_18345067341545
+#endif //RECYCLER_H_18345067341545
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index b5564c9b..791764de 100644
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -4,79 +4,116 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef ZEN_SCOPEGUARD_8971632487321434
-#define ZEN_SCOPEGUARD_8971632487321434
+#ifndef SCOPE_GUARD_H_8971632487321434
+#define SCOPE_GUARD_H_8971632487321434
#include <cassert>
+#include <exception>
#include <type_traits> //std::decay
-//best of Zen, Loki and C++11
+//best of Zen, Loki and C++17
+
+
+#ifdef ZEN_WIN
+inline int getUncaughtExceptionCount() { return std::uncaught_exceptions(); }
+
+#elif defined ZEN_LINUX || defined ZEN_MAC
+//std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP
+#ifdef ZEN_LINUX
+ static_assert(__GNUC__ < 5 || (__GNUC__ == 5 && (__GNUC_MINOR__ < 2 || (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support");
+#else
+ static_assert(__clang_major__ < 7 || (__clang_major__ == 7 && __clang_minor__ <= 0), "check std::uncaught_exceptions support");
+#endif
+
+namespace __cxxabiv1
+{
+struct __cxa_eh_globals;
+extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept;
+}
+
+inline int getUncaughtExceptionCount()
+{
+ return *(reinterpret_cast<unsigned int*>(static_cast<char*>(static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + sizeof(void*)));
+}
+#endif
+
namespace zen
{
//Scope Guard
/*
- zen::ScopeGuard lockAio = zen::makeGuard([&] { ::CloseHandle(hDir); });
+ auto guardAio = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { ::CloseHandle(hDir); });
...
- lockAio.dismiss();
-*/
+ guardAio.dismiss();
-//Scope Exit
-/*
+Scope Exit:
ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_FAIL(UndoPreviousWork());
+ ZEN_ON_SCOPE_SUCCESS(NotifySuccess());
*/
-class ScopeGuardBase
+enum class ScopeGuardRunMode
{
-public:
- void dismiss() { dismissed_ = true; }
-
-protected:
- ScopeGuardBase() {}
- ScopeGuardBase(ScopeGuardBase&& other) : dismissed_(other.dismissed_) { other.dismiss(); } //take over responsibility
- ~ScopeGuardBase() {} //[!] protected non-virtual base class destructor
-
- bool isDismissed() const { return dismissed_; }
-
-private:
- ScopeGuardBase (const ScopeGuardBase&) = delete;
- ScopeGuardBase& operator=(const ScopeGuardBase&) = delete;
-
- bool dismissed_ = false;
+ ON_EXIT,
+ ON_SUCCESS,
+ ON_FAIL
};
-template <typename F>
-class ScopeGuardImpl : public ScopeGuardBase
+template <ScopeGuardRunMode runMode, typename F>
+class ScopeGuard
{
public:
- explicit ScopeGuardImpl(const F& fun) : fun_(fun) {}
- explicit ScopeGuardImpl( F&& fun) : fun_(std::move(fun)) {}
- ScopeGuardImpl(ScopeGuardImpl&& other) : ScopeGuardBase(std::move(other)), fun_(std::move(other.fun_)) {}
+ explicit ScopeGuard(const F& fun) : fun_(fun) {}
+ explicit ScopeGuard( F&& fun) : fun_(std::move(fun)) {}
+
+ ScopeGuard(ScopeGuard&& other) : fun_(std::move(other.fun_)),
+ exeptionCount(other.exeptionCount),
+ dismissed(other.dismissed) { other.dismissed = true; }
- ~ScopeGuardImpl()
+ ~ScopeGuard() noexcept(runMode != ScopeGuardRunMode::ON_SUCCESS)
{
- if (!this->isDismissed())
- try
+#ifdef _MSC_VER
+ #pragma warning(suppress: 4127) //"conditional expression is constant"
+#endif
+ if (!dismissed)
+ {
+ if (runMode != ScopeGuardRunMode::ON_EXIT)
{
- fun_();
+ const bool failed = getUncaughtExceptionCount() > exeptionCount;
+ if ((runMode == ScopeGuardRunMode::ON_FAIL) != failed)
+ return;
}
- catch (...) { assert(false); }
+
+ if (runMode == ScopeGuardRunMode::ON_SUCCESS)
+ fun_(); //throw X
+ else
+ try { fun_(); }
+ catch (...) { assert(false); } //consistency: don't expect exceptions for ON_EXIT even if "!failed"!
+ }
}
+ void dismiss() { dismissed = true; }
+
private:
+ ScopeGuard (const ScopeGuard&) = delete;
+ ScopeGuard& operator=(const ScopeGuard&) = delete;
+
F fun_;
+ const int exeptionCount = getUncaughtExceptionCount();
+ bool dismissed = false;
};
-typedef ScopeGuardBase&& ScopeGuard;
-template <class F> inline
-ScopeGuardImpl<typename std::decay<F>::type> makeGuard(F&& fun) { return ScopeGuardImpl<typename std::decay<F>::type>(std::forward<F>(fun)); }
+template <ScopeGuardRunMode runMode, class F> inline
+auto makeGuard(F&& fun) { return ScopeGuard<runMode, std::decay_t<F>>(std::forward<F>(fun)); }
}
#define ZEN_CONCAT_SUB(X, Y) X ## Y
#define ZEN_CONCAT(X, Y) ZEN_CONCAT_SUB(X, Y)
-#define ZEN_ON_SCOPE_EXIT(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__);
+#define ZEN_ON_SCOPE_EXIT(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_EXIT >([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__);
+#define ZEN_ON_SCOPE_FAIL(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_FAIL >([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__);
+#define ZEN_ON_SCOPE_SUCCESS(X) auto ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard<zen::ScopeGuardRunMode::ON_SUCCESS>([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__);
-#endif //ZEN_SCOPEGUARD_8971632487321434
+#endif //SCOPE_GUARD_H_8971632487321434
diff --git a/zen/serialize.h b/zen/serialize.h
index ff2871b1..77cf657e 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef SERIALIZE_H_INCLUDED_83940578357
-#define SERIALIZE_H_INCLUDED_83940578357
+#ifndef SERIALIZE_H_839405783574356
+#define SERIALIZE_H_839405783574356
#include <functional>
#include <cstdint>
@@ -250,4 +250,4 @@ C readContainer(BinInputStream& stream) //throw UnexpectedEndOfStreamError
}
}
-#endif //SERIALIZE_H_INCLUDED_83940578357
+#endif //SERIALIZE_H_839405783574356
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index 2adce179..9b8e00f9 100644
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef EXECUTE_HEADER_23482134578134134
-#define EXECUTE_HEADER_23482134578134134
+#ifndef SHELL_EXECUTE_H_23482134578134134
+#define SHELL_EXECUTE_H_23482134578134134
#include "file_error.h"
@@ -94,9 +94,9 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError
if (!argv.empty())
{
filepath = argv[0];
- for (auto iter = argv.begin() + 1; iter != argv.end(); ++iter)
- arguments += (iter != argv.begin() ? L" " : L"") +
- (iter->empty() || std::any_of(iter->begin(), iter->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *iter + L"\"" : *iter);
+ for (auto it = argv.begin() + 1; it != argv.end(); ++it)
+ arguments += (it != argv.begin() ? L" " : L"") +
+ (it->empty() || std::any_of(it->begin(), it->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *it + L"\"" : *it);
}
auto fillExecInfo = [&](SHELLEXECUTEINFO& execInfo)
@@ -130,4 +130,4 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError
}
}
-#endif //EXECUTE_HEADER_23482134578134134
+#endif //SHELL_EXECUTE_H_23482134578134134
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 1e38f1b0..b78dd5dd 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STL_TOOLS_HEADER_84567184321434
-#define STL_TOOLS_HEADER_84567184321434
+#ifndef STL_TOOLS_H_84567184321434
+#define STL_TOOLS_H_84567184321434
#include <set>
#include <map>
@@ -15,6 +15,7 @@
#include "type_tools.h"
#include "build_info.h"
+
//enhancements for <algorithm>
namespace zen
{
@@ -93,11 +94,11 @@ namespace impl
template <class S, class Predicate> inline
void set_or_map_erase_if(S& s, Predicate p)
{
- for (auto iter = s.begin(); iter != s.end();)
- if (p(*iter))
- s.erase(iter++);
+ for (auto it = s.begin(); it != s.end();)
+ if (p(*it))
+ s.erase(it++);
else
- ++iter;
+ ++it;
}
}
@@ -125,14 +126,14 @@ void append(std::map<KeyType, ValueType, LessType, Alloc>& m, const C& c) { m.in
template <class M, class K, class V> inline
V& map_add_or_update(M& map, const K& key, const V& value) //efficient add or update without "default-constructible" requirement (Effective STL, item 24)
{
- auto iter = map.lower_bound(key);
- if (iter != map.end() && !(map.key_comp()(key, iter->first)))
+ auto it = map.lower_bound(key);
+ if (it != map.end() && !(map.key_comp()(key, it->first)))
{
- iter->second = value;
- return iter->second;
+ it->second = value;
+ return it->second;
}
else
- return map.insert(iter, typename M::value_type(key, value))->second;
+ return map.insert(it, typename M::value_type(key, value))->second;
}
@@ -158,12 +159,12 @@ ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const
template <class BidirectionalIterator, class T> inline
BidirectionalIterator find_last(const BidirectionalIterator first, const BidirectionalIterator last, const T& value)
{
- for (BidirectionalIterator iter = last; iter != first;) //reverse iteration: 1. check 2. decrement 3. evaluate
+ for (BidirectionalIterator it = last; it != first;) //reverse iteration: 1. check 2. decrement 3. evaluate
{
- --iter; //
+ --it; //
- if (*iter == value)
- return iter;
+ if (*it == value)
+ return it;
}
return last;
}
@@ -173,7 +174,7 @@ template <class BidirectionalIterator1, class BidirectionalIterator2> inline
BidirectionalIterator1 search_last(const BidirectionalIterator1 first1, BidirectionalIterator1 last1,
const BidirectionalIterator2 first2, const BidirectionalIterator2 last2)
{
- const BidirectionalIterator1 iterNotFound = last1;
+ const BidirectionalIterator1 itNotFound = last1;
//reverse iteration: 1. check 2. decrement 3. evaluate
for (;;)
@@ -184,7 +185,7 @@ BidirectionalIterator1 search_last(const BidirectionalIterator1 first1, Bi
for (;;)
{
if (it2 == first2) return it1;
- if (it1 == first1) return iterNotFound;
+ if (it1 == first1) return itNotFound;
--it1;
--it2;
@@ -231,4 +232,4 @@ size_t hashBytes(const unsigned char* ptr, size_t len)
}
}
-#endif //STL_TOOLS_HEADER_84567184321434
+#endif //STL_TOOLS_H_84567184321434
diff --git a/zen/string_base.h b/zen/string_base.h
index 224797e8..96d46fc4 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef Z_BASE_H_INCLUDED_08321745456
-#define Z_BASE_H_INCLUDED_08321745456
+#ifndef STRING_BASE_H_083217454562342526
+#define STRING_BASE_H_083217454562342526
#include <algorithm>
#include <cassert>
@@ -249,8 +249,8 @@ public:
//std::string functions
size_t length() const;
size_t size () const { return length(); }
- const Char* c_str() const { return rawStr; }; //C-string format with 0-termination
- const Char* data() const { return rawStr; }; //internal representation, 0-termination not guaranteed
+ const Char* c_str() const { return rawStr; } //C-string format with 0-termination
+ const Char* data() const { return rawStr; } //internal representation, 0-termination not guaranteed
const Char operator[](size_t pos) const;
bool empty() const { return length() == 0; }
void clear();
@@ -686,4 +686,4 @@ Zbase<Char, SP, AP>& Zbase<Char, SP, AP>::operator+=(Char ch)
}
}
-#endif //Z_BASE_H_INCLUDED_08321745456
+#endif //STRING_BASE_H_083217454562342526
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 8f83b9cd..fc9fe806 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STRING_TOOLS_HEADER_213458973046
-#define STRING_TOOLS_HEADER_213458973046
+#ifndef STRING_TOOLS_H_213458973046
+#define STRING_TOOLS_H_213458973046
#include <cctype> //isspace
#include <cwctype> //iswspace
@@ -42,8 +42,8 @@ template <class S, class T> S afterFirst (const S& str, const T& term, FailureRe
template <class S, class T> S beforeFirst(const S& str, const T& term, FailureReturnVal rv);
template <class S, class T> std::vector<S> split(const S& str, const T& delimiter);
-template <class S> void trim ( S& str, bool fromLeft = true, bool fromRight = true);
-template <class S> S trimCpy(const S& str, bool fromLeft = true, bool fromRight = true);
+template <class S> void trim (S& str, bool fromLeft = true, bool fromRight = true);
+template <class S> S trimCpy(S str, bool fromLeft = true, bool fromRight = true);
template <class S, class T, class U> void replace ( S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
template <class S, class T, class U> S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
@@ -54,7 +54,7 @@ template <class Num, class S > Num stringTo(const S& str);
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
-template <class T, class S> T copyStringTo(const S& str);
+template <class T, class S> T copyStringTo(S&& str);
@@ -94,6 +94,7 @@ bool isDigit(Char ch) //similar to implmenetation of std::::isdigit()!
return static_cast<Char>('0') <= ch && ch <= static_cast<Char>('9');
}
+
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; }
@@ -252,7 +253,7 @@ std::vector<S> split(const S& str, const T& delimiter)
}
-namespace implementation
+namespace impl
{
ZEN_INIT_DETECT_MEMBER(append);
@@ -295,8 +296,8 @@ S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
for (;;)
{
- implementation::stringAppend(output, strPos, strMatch - strPos);
- implementation::stringAppend(output, newBegin, newLen);
+ impl::stringAppend(output, strPos, strMatch - strPos);
+ impl::stringAppend(output, newBegin, newLen);
strPos = strMatch + oldLen;
@@ -308,7 +309,7 @@ S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
if (strMatch == strEnd)
break;
}
- implementation::stringAppend(output, strPos, strEnd - strPos);
+ impl::stringAppend(output, strPos, strEnd - strPos);
return output;
}
@@ -346,16 +347,15 @@ void trim(S& str, bool fromLeft, bool fromRight)
template <class S> inline
-S trimCpy(const S& str, bool fromLeft, bool fromRight)
+S trimCpy(S str, bool fromLeft, bool fromRight)
{
//implementing trimCpy() in terms of trim(), instead of the other way round, avoids memory allocations when trimming from right!
- S tmp = str;
- trim(tmp, fromLeft, fromRight);
- return tmp;
+ trim(str, fromLeft, fromRight);
+ return std::move(str); //"str" is an l-value parameter => no copy elision!
}
-namespace implementation
+namespace impl
{
template <class S, class T>
struct CopyStringToString
@@ -363,18 +363,19 @@ struct CopyStringToString
T copy(const S& src) const { return T(strBegin(src), strLength(src)); }
};
-template <class S>
-struct CopyStringToString<S, S> //perf: we don't need a deep copy if string types match
+template <class T>
+struct CopyStringToString<T, T> //perf: we don't need a deep copy if string types match
{
- const S& copy(const S& src) const { return src; }
+ template <class S>
+ T copy(S&& str) const { return std::forward<S>(str); }
};
}
template <class T, class S> inline
-T copyStringTo(const S& str) { return implementation::CopyStringToString<S, T>().copy(str); }
+T copyStringTo(S&& str) { return impl::CopyStringToString<std::decay_t<S>, T>().copy(std::forward<S>(str)); }
-namespace implementation
+namespace impl
{
template <class Num> inline
int saferPrintf(char* buffer, size_t bufferSize, const char* format, const Num& number) //there is no such thing as a "safe" printf ;)
@@ -400,17 +401,18 @@ int saferPrintf(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const
template <class S, class T, class Num> inline
S printNumber(const T& format, const Num& number) //format a single number using ::sprintf
{
- typedef typename GetCharType<S>::Type CharType;
+ static_assert(IsSameType<typename GetCharType<S>::Type, typename GetCharType<T>::Type>::value, "");
+ using CharType = typename GetCharType<S>::Type;
const int BUFFER_SIZE = 128;
- CharType buffer[BUFFER_SIZE];
- const int charsWritten = implementation::saferPrintf(buffer, BUFFER_SIZE, strBegin(format), number);
+ CharType buffer[BUFFER_SIZE]; //zero-initialize?
+ const int charsWritten = impl::saferPrintf(buffer, BUFFER_SIZE, strBegin(format), number);
return charsWritten > 0 ? S(buffer, charsWritten) : S();
}
-namespace implementation
+namespace impl
{
enum NumberType
{
@@ -424,7 +426,7 @@ enum NumberType
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_OTHER>) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
{
- typedef typename GetCharType<S>::Type CharType;
+ using CharType = typename GetCharType<S>::Type;
std::basic_ostringstream<CharType> ss;
ss << number;
@@ -453,7 +455,7 @@ template <class OutputIterator, class Num> inline
void formatNegativeInteger(Num n, OutputIterator& it)
{
assert(n < 0);
- typedef typename std::iterator_traits<OutputIterator>::value_type CharType;
+ using CharType = typename std::iterator_traits<OutputIterator>::value_type;
do
{
const Num tmp = n / 10;
@@ -469,7 +471,7 @@ template <class OutputIterator, class Num> inline
void formatPositiveInteger(Num n, OutputIterator& it)
{
assert(n >= 0);
- typedef typename std::iterator_traits<OutputIterator>::value_type CharType;
+ using CharType = typename std::iterator_traits<OutputIterator>::value_type;
do
{
const Num tmp = n / 10;
@@ -483,8 +485,9 @@ void formatPositiveInteger(Num n, OutputIterator& it)
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
{
- typedef typename GetCharType<S>::Type CharType;
- CharType buffer[2 + sizeof(Num) * 241 / 100]; //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
+ using CharType = typename GetCharType<S>::Type;
+ CharType buffer[2 + sizeof(Num) * 241 / 100]; //zero-initialize?
+ //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
//required chars (+ sign char): 1 + ceil(ln_10(256^sizeof(n) / 2 + 1)) -> divide by 2 for signed half-range; second +1 since one half starts with 1!
// <= 1 + ceil(ln_10(256^sizeof(n))) =~ 1 + ceil(sizeof(n) * 2.4082) <= 2 + floor(sizeof(n) * 2.41)
@@ -503,8 +506,8 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
{
- typedef typename GetCharType<S>::Type CharType;
- CharType buffer[1 + sizeof(Num) * 241 / 100];
+ using CharType = typename GetCharType<S>::Type;
+ CharType buffer[1 + sizeof(Num) * 241 / 100]; //zero-initialize?
//required chars: ceil(ln_10(256^sizeof(n))) =~ ceil(sizeof(n) * 2.4082) <= 1 + floor(sizeof(n) * 2.41)
auto it = std::end(buffer);
@@ -519,7 +522,7 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
template <class Num, class S> inline
Num stringTo(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number conversion using streams: convenient, but SLOW
{
- typedef typename GetCharType<S>::Type CharType;
+ using CharType = typename GetCharType<S>::Type;
Num number = 0;
std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType>>(str)) >> number;
return number;
@@ -538,8 +541,8 @@ Num stringTo(const S& str, Int2Type<NUM_TYPE_FLOATING_POINT>)
template <class Num, class S>
Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to integers: slightly faster than std::atoi, but more importantly: generic
{
- typedef typename GetCharType<S>::Type CharType;
-
+ using CharType = typename GetCharType<S>::Type;
+
const CharType* first = strBegin(str);
const CharType* last = first + strLength(str);
@@ -606,28 +609,28 @@ Num stringTo(const S& str, Int2Type<NUM_TYPE_UNSIGNED_INT>) //very fast conversi
template <class S, class Num> inline
S numberTo(const Num& number)
{
- typedef Int2Type<
- IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
- implementation::NUM_TYPE_OTHER> TypeTag;
+ using TypeTag = Int2Type<
+ IsSignedInt <Num>::value ? impl::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? impl::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? impl::NUM_TYPE_FLOATING_POINT :
+ impl::NUM_TYPE_OTHER>;
- return implementation::numberTo<S>(number, TypeTag());
+ return impl::numberTo<S>(number, TypeTag());
}
template <class Num, class S> inline
Num stringTo(const S& str)
{
- typedef Int2Type<
- IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
- implementation::NUM_TYPE_OTHER> TypeTag;
+ using TypeTag = Int2Type<
+ IsSignedInt <Num>::value ? impl::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? impl::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? impl::NUM_TYPE_FLOATING_POINT :
+ impl::NUM_TYPE_OTHER>;
- return implementation::stringTo<Num>(str, TypeTag());
+ return impl::stringTo<Num>(str, TypeTag());
}
}
-#endif //STRING_TOOLS_HEADER_213458973046
+#endif //STRING_TOOLS_H_213458973046
diff --git a/zen/string_traits.h b/zen/string_traits.h
index 61fa2625..12701dc3 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -4,12 +4,13 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STRING_TRAITS_HEADER_813274321443234
-#define STRING_TRAITS_HEADER_813274321443234
+#ifndef STRING_TRAITS_H_813274321443234
+#define STRING_TRAITS_H_813274321443234
#include <cstring> //strlen
#include "type_tools.h"
+
//uniform access to string-like types, both classes and character arrays
namespace zen
{
@@ -42,12 +43,12 @@ public:
StringRef(Iterator first, Iterator last) : len_(last - first), str_(first != last ? &*first : nullptr) {}
//StringRef(const Char* str, size_t len) : str_(str), len_(len) {} -> needless constraint! Char* not available for empty range!
- const Char* data() const { return str_; } //1. no null-termination! 2. may be nullptr!
+ Char* data () const { return str_; } //1. no null-termination! 2. may be nullptr!
size_t length() const { return len_; }
private:
- size_t len_;
- const Char* str_;
+ const size_t len_;
+ Char* str_;
};
@@ -67,16 +68,14 @@ namespace implementation
template<class S, class Char> //test if result of S::c_str() can convert to const Char*
class HasConversion
{
- typedef char Yes[1];
- typedef char No [2];
+ using Yes = char[1];
+ using No = char[2];
static Yes& hasConversion(const Char*);
static No& hasConversion(...);
- static S& createInstance();
-
public:
- enum { value = sizeof(hasConversion(createInstance().c_str())) == sizeof(Yes) };
+ enum { value = sizeof(hasConversion(std::declval<S>().c_str())) == sizeof(Yes) };
};
@@ -89,7 +88,7 @@ struct GetCharTypeImpl<S, true> :
typename SelectIf<HasConversion<S, char >::value, char, NullType>::Type
>::Type>
{
- //typedef typename S::value_type Type;
+ //using Type = typename S::value_type;
/*DON'T use S::value_type:
1. support Glib::ustring: value_type is "unsigned int" but c_str() returns "const char*"
2. wxString, wxWidgets v2.9, has some questionable string design: wxString::c_str() returns a proxy (wxCStrData) which
@@ -100,8 +99,10 @@ struct GetCharTypeImpl<S, true> :
template <> struct GetCharTypeImpl<char, false> : ResultType<char > {};
template <> struct GetCharTypeImpl<wchar_t, false> : ResultType<wchar_t> {};
-template <> struct GetCharTypeImpl<StringRef<char >, false> : ResultType<char > {};
-template <> struct GetCharTypeImpl<StringRef<wchar_t>, false> : ResultType<wchar_t> {};
+template <> struct GetCharTypeImpl<StringRef<char >, false> : ResultType<char > {};
+template <> struct GetCharTypeImpl<StringRef<wchar_t >, false> : ResultType<wchar_t> {};
+template <> struct GetCharTypeImpl<StringRef<const char >, false> : ResultType<char > {};
+template <> struct GetCharTypeImpl<StringRef<const wchar_t>, false> : ResultType<wchar_t> {};
ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
@@ -111,11 +112,11 @@ ZEN_INIT_DETECT_MEMBER(length); //
template <class S>
class StringTraits
{
- typedef typename RemoveRef <S >::Type NonRefType;
- typedef typename RemoveConst <NonRefType >::Type NonConstType;
- typedef typename RemoveArray <NonConstType>::Type NonArrayType;
- typedef typename RemovePointer<NonArrayType>::Type NonPtrType;
- typedef typename RemoveConst <NonPtrType >::Type UndecoratedType; //handle "const char* const"
+ using NonRefType = typename RemoveRef <S >::Type;
+ using NonConstType = typename RemoveConst <NonRefType >::Type;
+ using NonArrayType = typename RemoveArray <NonConstType>::Type;
+ using NonPtrType = typename RemovePointer<NonArrayType>::Type;
+ using UndecoratedType = typename RemoveConst <NonPtrType >::Type ; //handle "const char* const"
public:
enum
@@ -125,7 +126,7 @@ public:
HasMember_length <NonConstType>::value
};
- typedef typename GetCharTypeImpl<UndecoratedType, isStringClass>::Type CharType;
+ using CharType = typename GetCharTypeImpl<UndecoratedType, isStringClass>::Type;
enum
{
@@ -171,8 +172,11 @@ inline const char* strBegin(const char* str) { return str; }
inline const wchar_t* strBegin(const wchar_t* str) { return str; }
inline const char* strBegin(const char& ch) { return &ch; }
inline const wchar_t* strBegin(const wchar_t& ch) { return &ch; }
-inline const char* strBegin(const StringRef<char >& ref) { return ref.data(); }
-inline const wchar_t* strBegin(const StringRef<wchar_t>& ref) { return ref.data(); }
+
+inline const char* strBegin(const StringRef<char >& ref) { return ref.data(); }
+inline const wchar_t* strBegin(const StringRef<wchar_t >& ref) { return ref.data(); }
+inline const char* strBegin(const StringRef<const char >& ref) { return ref.data(); }
+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
@@ -185,8 +189,11 @@ inline size_t strLength(const char* str) { return cStringLength(str); }
inline size_t strLength(const wchar_t* str) { return cStringLength(str); }
inline size_t strLength(char) { return 1; }
inline size_t strLength(wchar_t) { return 1; }
-inline size_t strLength(const StringRef<char >& ref) { return ref.length(); }
-inline size_t strLength(const StringRef<wchar_t>& ref) { return ref.length(); }
+
+inline size_t strLength(const StringRef<char >& ref) { return ref.length(); }
+inline size_t strLength(const StringRef<wchar_t >& ref) { return ref.length(); }
+inline size_t strLength(const StringRef<const char >& ref) { return ref.length(); }
+inline size_t strLength(const StringRef<const wchar_t>& ref) { return ref.length(); }
}
@@ -206,4 +213,4 @@ size_t strLength(S&& str)
}
}
-#endif //STRING_TRAITS_HEADER_813274321443234
+#endif //STRING_TRAITS_H_813274321443234
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index b5ca8191..f50d1806 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef SYMLINK_80178347019835748321473214
-#define SYMLINK_80178347019835748321473214
+#ifndef SYMLINK_TARGET_H_801783470198357483
+#define SYMLINK_TARGET_H_801783470198357483
#include "scope_guard.h"
#include "file_error.h"
@@ -240,4 +240,4 @@ bool isSymlink(const WIN32_FIND_DATA& data)
#endif
}
-#endif //SYMLINK_80178347019835748321473214
+#endif //SYMLINK_TARGET_H_801783470198357483
diff --git a/zen/thread.h b/zen/thread.h
index b10dd342..bb6e7901 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -4,19 +4,23 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STD_THREAD_WRAP_H_7896323423432
-#define STD_THREAD_WRAP_H_7896323423432
+#ifndef THREAD_H_7896323423432235246427
+#define THREAD_H_7896323423432235246427
#include <thread>
#include <future>
-#include <zen/scope_guard.h>
-#include <zen/type_traits.h>
+#include "scope_guard.h"
+#include "type_traits.h"
+#include "optional.h"
+#ifdef ZEN_WIN
+#include "win.h"
+#endif
+
namespace zen
{
class InterruptionStatus;
-
class InterruptibleThread
{
public:
@@ -58,6 +62,9 @@ void interruptibleWait(std::condition_variable& cv, std::unique_lock<std::mutex>
template <class Rep, class Period>
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime); //throw ThreadInterruption
+#ifdef ZEN_WIN
+void setCurrentThreadName(const char* threadName);
+#endif
//------------------------------------------------------------------------------------------
/*
@@ -72,7 +79,7 @@ Example:
//dir exising
*/
template <class Function>
-auto runAsync(Function&& fun) -> std::future<decltype(fun())>;
+auto runAsync(Function&& fun);
//wait for all with a time limit: return true if *all* results are available!
template<class InputIterator, class Duration>
@@ -90,18 +97,18 @@ public:
GetFirstResult();
template <class Fun>
- void addJob(Fun&& f); //f must return a std::unique_ptr<T> containing a value if successful
+ void addJob(Fun&& f); //f must return a zen::Opt<T> containing a value if successful
template <class Duration>
bool timedWait(const Duration& duration) const; //true: "get()" is ready, false: time elapsed
//return first value or none if all jobs failed; blocks until result is ready!
- std::unique_ptr<T> get() const; //may be called only once!
+ Opt<T> get() const; //may be called only once!
private:
class AsyncResult;
std::shared_ptr<AsyncResult> asyncResult_;
- size_t jobsTotal_;
+ size_t jobsTotal_ = 0;
};
//------------------------------------------------------------------------------------------
@@ -111,7 +118,7 @@ template <class T>
class Protected
{
public:
- Protected() : value_() {}
+ Protected() {}
Protected(const T& value) : value_(value) {}
template <class Function>
@@ -126,7 +133,7 @@ private:
Protected& operator=(const Protected&) = delete;
std::mutex lockValue;
- T value_;
+ T value_{};
};
@@ -142,7 +149,7 @@ private:
namespace impl
{
template <class Function> inline
-auto runAsync(Function&& fun, TrueType /*copy-constructible*/) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun, TrueType /*copy-constructible*/)
{
typedef decltype(fun()) ResultType;
@@ -155,17 +162,17 @@ auto runAsync(Function&& fun, TrueType /*copy-constructible*/) -> std::future<de
template <class Function> inline
-auto runAsync(Function&& fun, FalseType /*copy-constructible*/) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun, FalseType /*copy-constructible*/)
{
//support move-only function objects!
auto sharedFun = std::make_shared<Function>(std::forward<Function>(fun));
- return runAsync([sharedFun]() { return (*sharedFun)(); }, TrueType());
+ return runAsync([sharedFun] { return (*sharedFun)(); }, TrueType());
}
}
template <class Function> inline
-auto runAsync(Function&& fun) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun)
{
return impl::runAsync(std::forward<Function>(fun), StaticBool<std::is_copy_constructible<Function>::value>());
}
@@ -187,7 +194,7 @@ class GetFirstResult<T>::AsyncResult
{
public:
//context: worker threads
- void reportFinished(std::unique_ptr<T>&& result)
+ void reportFinished(Opt<T>&& result)
{
{
std::lock_guard<std::mutex> dummy(lockResult);
@@ -206,7 +213,7 @@ public:
return conditionJobDone.wait_for(dummy, duration, [&] { return this->jobDone(jobsTotal); });
}
- std::unique_ptr<T> getResult(size_t jobsTotal)
+ Opt<T> getResult(size_t jobsTotal)
{
std::unique_lock<std::mutex> dummy(lockResult);
conditionJobDone.wait(dummy, [&] { return this->jobDone(jobsTotal); });
@@ -226,20 +233,20 @@ private:
#endif
std::mutex lockResult;
- size_t jobsFinished = 0; //
- std::unique_ptr<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
+ size_t jobsFinished = 0; //
+ Opt<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
std::condition_variable conditionJobDone;
};
template <class T> inline
-GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>()), jobsTotal_(0) {}
+GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>()) {}
template <class T>
template <class Fun> inline
-void GetFirstResult<T>::addJob(Fun&& f) //f must return a std::unique_ptr<T> containing a value on success
+void GetFirstResult<T>::addJob(Fun&& f) //f must return a zen::Opt<T> containing a value on success
{
std::thread t([asyncResult = this->asyncResult_, f = std::forward<Fun>(f)] { asyncResult->reportFinished(f()); });
++jobsTotal_;
@@ -253,7 +260,7 @@ bool GetFirstResult<T>::timedWait(const Duration& duration) const { return async
template <class T> inline
-std::unique_ptr<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
+Opt<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
//------------------------------------------------------------------------------------------
@@ -263,7 +270,7 @@ std::unique_ptr<T> GetFirstResult<T>::get() const { return asyncResult_->getResu
#elif defined __GNUC__ || defined __clang__
#define ZEN_THREAD_LOCAL_SPECIFIER __thread
#else
- #error "game over"
+ #error "Game over!"
#endif
@@ -316,7 +323,7 @@ public:
void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //throw ThreadInterruption
{
std::unique_lock<std::mutex> lock(lockSleep);
- if (conditionSleepInterruption.wait_for(lock, relTime, [&] { return static_cast<bool>(this->interrupted); }))
+ if (conditionSleepInterruption.wait_for(lock, relTime, [this] { return static_cast<bool>(this->interrupted); }))
throw ThreadInterruption();
}
@@ -406,6 +413,39 @@ InterruptibleThread::InterruptibleThread(Function&& f) : intStatus_(std::make_sh
inline
void InterruptibleThread::interrupt() { intStatus_->interrupt(); }
+
+
+#ifdef ZEN_WIN
+//https://randomascii.wordpress.com/2015/10/26/thread-naming-in-windows-time-for-something-better/
+
+#pragma pack(push,8)
+struct THREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+};
+#pragma pack(pop)
+
+
+inline
+void setCurrentThreadName(const char* threadName)
+{
+const DWORD MS_VC_EXCEPTION = 0x406D1388;
+
+THREADNAME_INFO info = {};
+ info.dwType = 0x1000;
+ info.szName = threadName;
+ info.dwThreadID = GetCurrentThreadId();
+
+ __try
+ {
+ ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER){}
+}
+#endif
}
-#endif //STD_THREAD_WRAP_H_7896323423432
+#endif //THREAD_H_7896323423432235246427
diff --git a/zen/tick_count.h b/zen/tick_count.h
index b5667c6c..647876fb 100644
--- a/zen/tick_count.h
+++ b/zen/tick_count.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef ZEN_TICK_COUNT_HEADER_3807326
-#define ZEN_TICK_COUNT_HEADER_3807326
+#ifndef TICK_COUNT_H_3807326223463457
+#define TICK_COUNT_H_3807326223463457
#include <cstdint>
#include "type_traits.h"
@@ -13,18 +13,12 @@
#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
-//template <class T> inline
-//T dist(T a, T b)
-//{
-// return a > b ? a - b : b - a;
-//}
+
namespace zen
{
@@ -55,7 +49,7 @@ public:
typedef uint64_t NativeVal;
#endif
- TickVal() : val_() {}
+ TickVal() {}
explicit TickVal(const NativeVal& val) : val_(val) {}
inline friend
@@ -92,7 +86,7 @@ public:
bool isValid() const { return dist(*this, TickVal()) != 0; }
private:
- NativeVal val_;
+ NativeVal val_ {};
};
@@ -144,4 +138,4 @@ TickVal getTicks() //return !isValid() on error
}
}
-#endif //ZEN_TICK_COUNT_HEADER_3807326
+#endif //TICK_COUNT_H_3807326223463457
diff --git a/zen/time.h b/zen/time.h
index 516fc511..4f546e4e 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef ZEN_TIME_HEADER_845709281432434
-#define ZEN_TIME_HEADER_845709281432434
+#ifndef TIME_H_8457092814324342453627
+#define TIME_H_8457092814324342453627
#include <ctime>
#include "string_tools.h"
@@ -13,16 +13,14 @@
namespace zen
{
-struct TimeComp //replaces "struct std::tm" and SYSTEMTIME
+struct TimeComp //replaces std::tm and SYSTEMTIME
{
- TimeComp() : year(0), month(0), day(0), hour(0), minute(0), second(0) {}
-
- int year; // -
- int month; //1-12
- int day; //1-31
- int hour; //0-23
- int minute; //0-59
- int second; //0-61
+ int year = 0; // -
+ int month = 0; //1-12
+ int day = 0; //1-31
+ int hour = 0; //0-23
+ int minute = 0; //0-59
+ int second = 0; //0-60 (including leap second)
};
TimeComp localTime (time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components
@@ -32,9 +30,9 @@ time_t localToTimeT(const TimeComp& comp); //convert local time com
/*
format (current) date and time; example:
- formatTime<std::wstring>(L"%Y*%m*%d"); -> "2011*10*29"
- formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
- formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
+ formatTime<std::wstring>(L"%Y|%m|%d"); -> "2011|10|29"
+ formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
+ formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
*/
template <class String, class String2>
String formatTime(const String2& format, const TimeComp& comp = localTime()); //format as specified by "std::strftime", returns empty string on failure
@@ -74,7 +72,7 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp); //simi
namespace implementation
{
inline
-struct std::tm toClibTimeComponents(const TimeComp& comp)
+std::tm toClibTimeComponents(const TimeComp& comp)
{
assert(1 <= comp.month && comp.month <= 12 &&
1 <= comp.day && comp.day <= 31 &&
@@ -82,19 +80,21 @@ struct std::tm toClibTimeComponents(const TimeComp& comp)
0 <= comp.minute && comp.minute <= 59 &&
0 <= comp.second && comp.second <= 61);
- struct std::tm ctc = {};
+ 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-61
+ 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_wday
+ //ctc.tm_yday
return ctc;
}
inline
-TimeComp toZenTimeComponents(const struct ::tm& ctc)
+TimeComp toZenTimeComponents(const std::tm& ctc)
{
TimeComp comp;
comp.year = ctc.tm_year + 1900;
@@ -157,21 +157,21 @@ struct GetFormat<FormatIsoDateTimeTag> //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:
// VS 2010: CRASH unless "_invalid_parameter_handler" is set: http://msdn.microsoft.com/en-us/library/ksazx244.aspx
// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
inline
-size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const struct std::tm* timeptr)
+size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const std::tm* timeptr)
{
return std::strftime(buffer, bufferSize, format, timeptr);
}
inline
-size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const struct std::tm* timeptr)
+size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const std::tm* timeptr)
{
return std::wcsftime(buffer, bufferSize, format, timeptr);
}
/*
inline
-bool isValid(const struct std::tm& t)
+bool isValid(const std::tm& t)
{
-> not enough! MSCRT has different limits than the C standard which even seem to change with different versions:
_VALIDATE_RETURN((( timeptr->tm_sec >=0 ) && ( timeptr->tm_sec <= 59 ) ), EINVAL, FALSE)
@@ -194,7 +194,7 @@ bool isValid(const struct std::tm& t)
*/
template <class CharType> inline
-size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const struct std::tm* timeptr)
+size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr)
{
#if defined _MSC_VER && !defined NDEBUG
//there's no way around: application init must register an invalid parameter handler that does nothing !!!
@@ -215,7 +215,7 @@ 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
{
typedef typename GetCharType<String>::Type CharType;
- struct std::tm ctc = toClibTimeComponents(comp);
+ std::tm ctc = toClibTimeComponents(comp);
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
@@ -236,10 +236,9 @@ String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
inline
TimeComp localTime(time_t utc)
{
- struct ::tm lt = {};
+ std::tm lt = {};
- //use thread-safe variants of localtime()!
-#ifdef ZEN_WIN
+#ifdef ZEN_WIN //use thread-safe variants of std::localtime()!
if (::localtime_s(&lt, &utc) != 0)
#else
if (::localtime_r(&utc, &lt) == nullptr)
@@ -253,7 +252,7 @@ TimeComp localTime(time_t utc)
inline
time_t localToTimeT(const TimeComp& comp) //returns -1 on error
{
- struct std::tm ctc = implementation::toClibTimeComponents(comp);
+ std::tm ctc = implementation::toClibTimeComponents(comp);
return std::mktime(&ctc);
}
@@ -279,36 +278,36 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
typedef typename GetCharType<String>::Type CharType;
static_assert(IsSameType<CharType, typename GetCharType<String2>::Type>::value, "");
- const CharType* iterFmt = strBegin(format);
- const CharType* const fmtLast = iterFmt + strLength(format);
+ const CharType* itFmt = strBegin(format);
+ const CharType* const fmtLast = itFmt + strLength(format);
- const CharType* iterStr = strBegin(str);
- const CharType* const strLast = iterStr + strLength(str);
+ const CharType* itStr = strBegin(str);
+ const CharType* const strLast = itStr + strLength(str);
auto extractNumber = [&](int& result, size_t digitCount) -> bool
{
- if (strLast - iterStr < makeSigned(digitCount))
+ if (strLast - itStr < makeSigned(digitCount))
return false;
- if (std::any_of(iterStr, iterStr + digitCount, [](CharType c) { return !isDigit(c); }))
+ if (std::any_of(itStr, itStr + digitCount, [](CharType c) { return !isDigit(c); }))
return false;
- result = zen::stringTo<int>(StringRef<CharType>(iterStr, iterStr + digitCount));
- iterStr += digitCount;
+ result = zen::stringTo<int>(StringRef<const CharType>(itStr, itStr + digitCount));
+ itStr += digitCount;
return true;
};
- for (; iterFmt != fmtLast; ++iterFmt)
+ for (; itFmt != fmtLast; ++itFmt)
{
- const CharType fmt = *iterFmt;
+ const CharType fmt = *itFmt;
if (fmt == '%')
{
- ++iterFmt;
- if (iterFmt == fmtLast)
+ ++itFmt;
+ if (itFmt == fmtLast)
return false;
- switch (*iterFmt)
+ switch (*itFmt)
{
case 'Y':
if (!extractNumber(comp.year, 4))
@@ -340,19 +339,19 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
}
else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars
{
- while (iterStr != strLast && isWhiteSpace(*iterStr))
- ++iterStr;
+ while (itStr != strLast && isWhiteSpace(*itStr))
+ ++itStr;
}
else
{
- if (iterStr == strLast || *iterStr != fmt)
+ if (itStr == strLast || *itStr != fmt)
return false;
- ++iterStr;
+ ++itStr;
}
}
- return iterStr == strLast;
+ return itStr == strLast;
}
}
-#endif //ZEN_TIME_HEADER_845709281432434
+#endif //TIME_H_8457092814324342453627
diff --git a/zen/type_tools.h b/zen/type_tools.h
index 31384d4c..a1e628a1 100644
--- a/zen/type_tools.h
+++ b/zen/type_tools.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef TYPE_TOOLS_HEADER_45237590734254545
-#define TYPE_TOOLS_HEADER_45237590734254545
+#ifndef TYPE_TOOLS_H_45237590734254545
+#define TYPE_TOOLS_H_45237590734254545
#include "type_traits.h"
@@ -100,4 +100,4 @@ template <class Predicate> inline
LessDescending<Predicate> makeDescending(Predicate pred) { return pred; }
}
-#endif //TYPE_TOOLS_HEADER_45237590734254545
+#endif //TYPE_TOOLS_H_45237590734254545
diff --git a/zen/type_traits.h b/zen/type_traits.h
index 3ec90f49..ac7f1a42 100644
--- a/zen/type_traits.h
+++ b/zen/type_traits.h
@@ -4,11 +4,12 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef TYPE_TRAITS_HEADER_3425628658765467
-#define TYPE_TRAITS_HEADER_3425628658765467
+#ifndef TYPE_TRAITS_H_3425628658765467
+#define TYPE_TRAITS_H_3425628658765467
#include <type_traits> //all we need is std::is_class!!
+
namespace zen
{
//################# TMP compile time return values: "inherit to return compile-time result" ##############
@@ -21,8 +22,8 @@ struct StaticInt
template <bool b>
struct StaticBool : StaticInt<b> {};
-typedef StaticBool<true> TrueType;
-typedef StaticBool<false> FalseType;
+using TrueType = StaticBool<true>;
+using FalseType = StaticBool<false>;
template <class EnumType, EnumType val>
struct StaticEnum
@@ -33,15 +34,15 @@ struct StaticEnum
template <class T>
struct ResultType
{
- typedef T Type;
+ using Type = T;
};
//Herb Sutter's signedness conversion helpers: http://herbsutter.com/2013/06/13/gotw-93-solution-auto-variables-part-2/
template<class T> inline
-typename std::make_signed<T>::type makeSigned(T t) { return static_cast<typename std::make_signed<T>::type>(t); }
+typename std::make_signed<T>::type makeSigned(T t) { return static_cast<std::make_signed_t<T>>(t); }
template<class T> inline
-typename std::make_unsigned<T>::type makeUnsigned(T t) { return static_cast<typename std::make_unsigned<T>::type>(t); }
+typename std::make_unsigned<T>::type makeUnsigned(T t) { return static_cast<std::make_unsigned_t<T>>(t); }
//################# Built-in Types ########################
//Example: "IsSignedInt<int>::value" evaluates to "true"
@@ -136,8 +137,8 @@ struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
struct HasMemberImpl_##NAME \
{ \
private: \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ using Yes = char[1]; \
+ using No = char[2]; \
\
template <typename U, U t> \
class Helper {}; \
@@ -165,8 +166,8 @@ struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
template<typename U> \
class HasMember_##NAME \
{ \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ using Yes = char[1]; \
+ using No = char[2]; \
\
template <typename T, T t> class Helper {}; \
\
@@ -182,8 +183,8 @@ struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
template<typename T> \
class HasMemberType_##TYPENAME \
{ \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ using Yes = char[1]; \
+ using No = char[2]; \
\
template <typename U> class Helper {}; \
\
@@ -194,4 +195,4 @@ struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
};
}
-#endif //TYPE_TRAITS_HEADER_3425628658765467
+#endif //TYPE_TRAITS_H_3425628658765467
diff --git a/zen/utf.h b/zen/utf.h
index 42758c35..117b13bc 100644
--- a/zen/utf.h
+++ b/zen/utf.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STRING_UTF8_HEADER_01832479146991573473545
-#define STRING_UTF8_HEADER_01832479146991573473545
+#ifndef UTF_H_01832479146991573473545
+#define UTF_H_01832479146991573473545
#include <cstdint>
#include <iterator>
@@ -455,4 +455,4 @@ TargetString utfCvrtTo(const SourceString& str)
}
}
-#endif //STRING_UTF8_HEADER_01832479146991573473545
+#endif //UTF_H_01832479146991573473545
diff --git a/zen/warn_static.h b/zen/warn_static.h
index 3f268ec3..bba17cb7 100644
--- a/zen/warn_static.h
+++ b/zen/warn_static.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef WARN_STATIC_HEADER_08724567834560832745
-#define WARN_STATIC_HEADER_08724567834560832745
+#ifndef WARN_STATIC_H_08724567834560832745
+#define WARN_STATIC_H_08724567834560832745
/*
Portable Compile-Time Warning
@@ -30,4 +30,4 @@ Usage:
enum { STATIC_WARNING_CONCAT(warn_static_dummy_value, __LINE__) = sizeof(STATIC_WARNING_87903124) };
#endif
-#endif //WARN_STATIC_HEADER_08724567834560832745
+#endif //WARN_STATIC_H_08724567834560832745
diff --git a/zen/win.h b/zen/win.h
index 13ecf4e4..8c1a1c7b 100644
--- a/zen/win.h
+++ b/zen/win.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef YAWFWH_YET_ANOTHER_WRAPPER_FOR_WINDOWS_H
-#define YAWFWH_YET_ANOTHER_WRAPPER_FOR_WINDOWS_H
+#ifndef WIN_H_8701570183560183247891346363457
+#define WIN_H_8701570183560183247891346363457
#ifndef _WINSOCKAPI_ //prevent inclusion of winsock.h in windows.h: obsoleted by and conflicting with winsock2.h
#define _WINSOCKAPI_
@@ -30,4 +30,4 @@
#endif
//------------------------------------------------------
-#endif //YAWFWH_YET_ANOTHER_WRAPPER_FOR_WINDOWS_H
+#endif //WIN_H_8701570183560183247891346363457
diff --git a/zen/xml_io.h b/zen/xml_io.h
index 16e01aff..4876ac55 100644
--- a/zen/xml_io.h
+++ b/zen/xml_io.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef XMLBASE_H_INCLUDED
-#define XMLBASE_H_INCLUDED
+#ifndef XML_IO_H_8914759321263879
+#define XML_IO_H_8914759321263879
#include <zenxml/xml.h>
#include "file_error.h"
@@ -23,4 +23,4 @@ void checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filepath); //th
void saveXmlDocument(const XmlDoc& doc, const Zstring& filepath); //throw FileError
}
-#endif // XMLBASE_H_INCLUDED
+#endif //XML_IO_H_8914759321263879
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 3b29e664..59f15f19 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -6,14 +6,10 @@
#include "zstring.h"
#include <stdexcept>
-#include <unordered_map>
#ifdef ZEN_WIN
#include "dll.h"
- #include "win_ver.h"
-
-#elif defined ZEN_MAC
- #include <ctype.h> //toupper()
+ //#include "win_ver.h"
#endif
using namespace zen;
@@ -52,7 +48,7 @@ const SysDllFun<CompareStringOrdinalFunc> compareStringOrdinal = SysDllFun<Compa
}
-int cmpFilePath(const Zchar* lhs, size_t lhsLen, const Zchar* rhs, size_t rhsLen)
+int cmpStringNoCase(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen)
{
assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls!
assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); //
@@ -79,7 +75,7 @@ int cmpFilePath(const Zchar* lhs, size_t lhsLen, const Zchar* rhs, size_t rhsLen
if (minSize == 0) //LCMapString does not allow input sizes of 0!
return static_cast<int>(lhsLen) - static_cast<int>(rhsLen);
- auto copyToUpperCase = [&](const wchar_t* strIn, wchar_t* strOut)
+ auto copyToUpperCase = [minSize](const wchar_t* strIn, wchar_t* strOut)
{
//faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString()
if (::LCMapString(LOCALE_INVARIANT, //__in LCID Locale,
@@ -118,43 +114,18 @@ int cmpFilePath(const Zchar* lhs, size_t lhsLen, const Zchar* rhs, size_t rhsLen
}
-Zstring makeUpperCopy(const Zstring& str)
-{
- const int len = static_cast<int>(str.size());
-
- if (len == 0) //LCMapString does not allow input sizes of 0!
- return str;
-
- Zstring output = str;
-
- //LOCALE_INVARIANT is NOT available with Windows 2000 -> ok
-
- //use Windows' upper case conversion: faster than ::CharUpper()
- if (::LCMapString(LOCALE_INVARIANT, //__in LCID Locale,
- LCMAP_UPPERCASE, //__in DWORD dwMapFlags,
- str.c_str(), //__in LPCTSTR lpSrcStr,
- len, //__in int cchSrc,
- &*output.begin(), //__out LPTSTR lpDestStr,
- len) == 0) //__in int cchDest
- throw std::runtime_error("Error comparing strings (LCMapString). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
-
- return output;
-}
-
-
-#elif defined ZEN_MAC
-Zstring makeUpperCopy(const Zstring& str)
+void makeUpperInPlace(wchar_t* str, size_t strLen)
{
- const size_t len = str.size();
-
- Zstring output;
- output.resize(len);
-
- std::transform(str.begin(), str.end(), output.begin(), [](char c) { return static_cast<char>(::toupper(static_cast<unsigned char>(c))); }); //locale-dependent!
-
- //result of toupper() is an unsigned char mapped to int range, so the char representation is in the last 8 bits and we need not care about signedness!
- //this should work for UTF-8, too: all chars >= 128 are mapped upon themselves!
-
- return output;
+ //- use Windows' upper case conversion: faster than ::CharUpper()
+ //- LOCALE_INVARIANT is NOT available with Windows 2000 -> ok
+ //- MSDN: "The destination string can be the same as the source string only if LCMAP_UPPERCASE or LCMAP_LOWERCASE is set"
+ if (strLen != 0) //LCMapString does not allow input sizes of 0!
+ if (::LCMapString(LOCALE_INVARIANT, //__in LCID Locale,
+ LCMAP_UPPERCASE, //__in DWORD dwMapFlags,
+ str, //__in LPCTSTR lpSrcStr,
+ static_cast<int>(strLen), //__in int cchSrc,
+ str, //__out LPTSTR lpDestStr,
+ static_cast<int>(strLen)) == 0) //__in int cchDest
+ throw std::runtime_error("Error comparing strings (LCMapString). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
}
#endif
diff --git a/zen/zstring.h b/zen/zstring.h
index 462ea39c..3a431ea7 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -4,15 +4,11 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef ZSTRING_H_INCLUDED_73425873425789
-#define ZSTRING_H_INCLUDED_73425873425789
+#ifndef ZSTRING_H_73425873425789
+#define ZSTRING_H_73425873425789
#include "string_base.h"
-#ifdef ZEN_LINUX
- #include <cstring> //strncmp
-#endif
-
#ifdef ZEN_WIN //Windows encodes Unicode as UTF-16 wchar_t
typedef wchar_t Zchar;
@@ -30,33 +26,33 @@
typedef zen::Zbase<Zchar, zen::StorageRefCountThreadSafe, zen::AllocatorOptimalSpeed> Zstring;
+int cmpStringNoCase(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen);
+#if defined ZEN_LINUX || defined ZEN_MAC
+ int cmpStringNoCase(const char* lhs, size_t lhsLen, const char* rhs, size_t rhsLen);
+#endif
+
+template <class S, class T> inline
+bool equalNoCase(const S& lhs, const T& rhs) { using namespace zen; return cmpStringNoCase(strBegin(lhs), strLength(lhs), strBegin(rhs), strLength(rhs)) == 0; }
+
+template <class S>
+S makeUpperCopy(S str);
-//Compare filepaths: Windows does NOT distinguish between upper/lower-case, while Linux DOES
-int cmpFilePath(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen);
+//Compare filepaths: Windows/OS X does NOT distinguish between upper/lower-case, while Linux DOES
+int cmpFilePath(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen);
#if defined ZEN_LINUX || defined ZEN_MAC
int cmpFilePath(const char* lhs, size_t lhsLen, const char* rhs, size_t rhsLen);
#endif
+template <class S, class T> inline
+bool equalFilePath(const S& lhs, const T& rhs) { using namespace zen; return cmpFilePath(strBegin(lhs), strLength(lhs), strBegin(rhs), strLength(rhs)) == 0; }
-
-
-struct LessFilePath //case-insensitive on Windows, case-sensitive on Linux
+struct LessFilePath
{
template <class S, class T>
bool operator()(const S& lhs, const T& rhs) const { using namespace zen; return cmpFilePath(strBegin(lhs), strLength(lhs), strBegin(rhs), strLength(rhs)) < 0; }
};
-struct EqualFilePath //case-insensitive on Windows, case-sensitive on Linux
-{
- template <class S, class T>
- bool operator()(const S& lhs, const T& rhs) const { using namespace zen; return cmpFilePath(strBegin(lhs), strLength(lhs), strBegin(rhs), strLength(rhs)) == 0; }
-};
-
-
-#if defined ZEN_WIN || defined ZEN_MAC
- Zstring makeUpperCopy(const Zstring& str);
-#endif
inline
@@ -103,38 +99,98 @@ bool pathEndsWith(const S& str, const T& postfix)
//################################# inline implementation ########################################
+#ifdef ZEN_WIN
+void makeUpperInPlace(wchar_t* str, size_t strLen);
-#if defined ZEN_LINUX || defined ZEN_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
inline
-int cmpFilePath(const char* lhs, size_t lhsLen, const char* rhs, size_t rhsLen)
+void makeUpperInPlace(wchar_t* str, size_t strLen)
+{
+ std::for_each(str, str + strLen, [](wchar_t& c) { c = std::towupper(c); }); //locale-dependent!
+}
+
+
+inline
+void makeUpperInPlace(char* str, size_t strLen)
+{
+ std::for_each(str, str + strLen, [](char& c) { c = std::toupper(static_cast<unsigned char>(c)); }); //locale-dependent!
+ //result of toupper() is an unsigned char mapped to int range, so the char representation is in the last 8 bits and we need not care about signedness!
+ //this should work for UTF-8, too: all chars >= 128 are mapped upon themselves!
+}
+
+
+inline
+int cmpStringNoCase(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen)
+{
+ assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls!
+ assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); //
+
+ const int rv = ::wcsncasecmp(lhs, rhs, std::min(lhsLen, rhsLen)); //locale-dependent!
+ if (rv != 0)
+ return rv;
+ return static_cast<int>(lhsLen) - static_cast<int>(rhsLen);
+}
+
+
+inline
+int cmpStringNoCase(const char* lhs, size_t lhsLen, const char* rhs, size_t rhsLen)
{
assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls!
assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); //
-#if defined ZEN_LINUX
- const int rv = std::strncmp(lhs, rhs, std::min(lhsLen, rhsLen));
-#elif defined ZEN_MAC
const int rv = ::strncasecmp(lhs, rhs, std::min(lhsLen, rhsLen)); //locale-dependent!
-#endif
if (rv != 0)
return rv;
return static_cast<int>(lhsLen) - static_cast<int>(rhsLen);
}
+#endif
+
+
+template <class S> inline
+S makeUpperCopy(S str)
+{
+ const size_t len = str.length(); //we assert S is a string type!
+ if (len > 0)
+ makeUpperInPlace(&*str.begin(), len);
+
+ return std::move(str); //"str" is an l-value parameter => no copy elision!
+}
+
inline
int cmpFilePath(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen)
{
+#if defined ZEN_WIN || defined ZEN_MAC
+ return cmpStringNoCase(lhs, lhsLen, rhs, rhsLen);
+
+#elif defined ZEN_LINUX
assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls!
assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); //
-#if defined ZEN_LINUX
const int rv = std::wcsncmp(lhs, rhs, std::min(lhsLen, rhsLen));
-#elif defined ZEN_MAC
- const int rv = ::wcsncasecmp(lhs, rhs, std::min(lhsLen, rhsLen)); //locale-dependent!
+ if (rv != 0)
+ return rv;
+ return static_cast<int>(lhsLen) - static_cast<int>(rhsLen);
#endif
+}
+
+
+#if defined ZEN_LINUX || defined ZEN_MAC
+inline
+int cmpFilePath(const char* lhs, size_t lhsLen, const char* rhs, size_t rhsLen)
+{
+#if defined ZEN_MAC
+ return cmpStringNoCase(lhs, lhsLen, rhs, rhsLen);
+
+#elif defined ZEN_LINUX
+ assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls!
+ assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); //
+
+ const int rv = std::strncmp(lhs, rhs, std::min(lhsLen, rhsLen));
if (rv != 0)
return rv;
return static_cast<int>(lhsLen) - static_cast<int>(rhsLen);
+#endif
}
#endif
@@ -172,4 +228,4 @@ int cmpFilePath(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rh
#error no target platform defined
#endif
-#endif //ZSTRING_H_INCLUDED_73425873425789
+#endif //ZSTRING_H_73425873425789
bgstack15