summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2020-03-18 08:59:09 -0400
committerB Stack <bgstack15@gmail.com>2020-03-18 08:59:09 -0400
commit2c4db439d235b68478d90c450289d2d0ba418547 (patch)
tree5c378aa54f4bb65c081cf9a92530d8af1f1f53dd /zen
parentMerge branch '10.20' into 'master' (diff)
downloadFreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.tar.gz
FreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.tar.bz2
FreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.zip
add upstream 10.21
Diffstat (limited to 'zen')
-rw-r--r--zen/basic_math.h16
-rw-r--r--zen/crc.h58
-rw-r--r--zen/dir_watcher.cpp3
-rw-r--r--zen/error_log.h85
-rw-r--r--zen/file_access.cpp4
-rw-r--r--zen/file_io.cpp6
-rw-r--r--zen/file_io.h2
-rw-r--r--zen/format_unit.cpp5
-rw-r--r--zen/guid.h12
-rw-r--r--zen/http.cpp42
-rw-r--r--zen/http.h8
-rw-r--r--zen/legacy_compiler.h17
-rw-r--r--zen/open_ssl.cpp31
-rw-r--r--zen/perf.h2
-rw-r--r--zen/recycler.cpp4
-rw-r--r--zen/serialize.h38
-rw-r--r--zen/shell_execute.h4
-rw-r--r--zen/socket.h4
-rw-r--r--zen/string_base.h32
-rw-r--r--zen/string_tools.h12
-rw-r--r--zen/string_traits.h3
-rw-r--r--zen/sys_error.cpp184
-rw-r--r--zen/sys_error.h62
-rw-r--r--zen/system.cpp31
-rw-r--r--zen/thread.cpp2
-rw-r--r--zen/thread.h2
-rw-r--r--zen/time.h184
-rw-r--r--zen/zlib_wrap.cpp14
-rw-r--r--zen/zlib_wrap.h6
-rw-r--r--zen/zstring.cpp3
-rw-r--r--zen/zstring.h7
31 files changed, 472 insertions, 411 deletions
diff --git a/zen/basic_math.h b/zen/basic_math.h
index 8a32ee69..26dda9a6 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -14,6 +14,7 @@
#include <functional>
#include <cassert>
#include "type_traits.h"
+#include "legacy_compiler.h"
namespace numeric
@@ -53,17 +54,6 @@ double mad(RandomAccessIterator first, RandomAccessIterator last); //note: inval
template <class InputIterator>
double norm2(InputIterator first, InputIterator last);
-//constants
-const double pi = 3.14159265358979323846;
-const double e = 2.71828182845904523536;
-const double sqrt2 = 1.41421356237309504880;
-const double ln2 = 0.693147180559945309417;
-
-#if __cpp_lib_math_constants //C++20
- #error implement math constants from <numbers> header
-#endif
-//static_assert(pi + e + sqrt2 + ln2 == 7.9672352249818781, "whoopsie");
-
//----------------------------------------------------------------------------------
@@ -213,14 +203,14 @@ T power(T value)
inline
double radToDeg(double rad)
{
- return rad * 180.0 / numeric::pi;
+ return rad * (180.0 / std::numbers::pi);
}
inline
double degToRad(double degree)
{
- return degree * numeric::pi / 180.0;
+ return degree / (180.0 / std::numbers::pi);
}
diff --git a/zen/crc.h b/zen/crc.h
index df460a03..0570cced 100644
--- a/zen/crc.h
+++ b/zen/crc.h
@@ -64,38 +64,32 @@ uint32_t getCrc32(ByteIterator first, ByteIterator last) //https://en.wikipedia.
{
constexpr uint32_t crcTable[] =
{
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static_assert(arraySize(crcTable) == 256 && arrayAccumulate<uint64_t>(crcTable) == 549755813760);
static_assert(sizeof(typename std::iterator_traits<ByteIterator>::value_type) == 1);
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 94632ea4..307b48e5 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -85,7 +85,8 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
const ErrorCode ec = getLastError(); //copy before directly/indirectly making other system calls!
if (ec == ENOSPC) //fix misleading system message "No space left on device"
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)),
- formatSystemError(L"inotify_add_watch", numberTo<std::wstring>(ec), L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."));
+ formatSystemError(L"inotify_add_watch", L"ENOSPC",
+ L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."));
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)), formatSystemError(L"inotify_add_watch", ec));
}
diff --git a/zen/error_log.h b/zen/error_log.h
index cc52fc6e..ab23e33a 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -8,9 +8,7 @@
#define ERROR_LOG_H_8917590832147915
#include <cassert>
-#include <algorithm>
#include <vector>
-//#include <string>
#include "time.h"
#include "i18n.h"
#include "utf.h"
@@ -31,10 +29,10 @@ struct LogEntry
{
time_t time = 0;
MessageType type = MSG_TYPE_FATAL_ERROR;
- Zstringw message; //std::wstring may employ small string optimization: we cannot accept bloating the "ErrorLog::entries_" memory block below (think 1 million items)
+ Zstringc message; //conserve memory (=> avoid std::string SSO overhead!)
};
-std::wstring formatMessage(const LogEntry& entry);
+std::string formatMessage(const LogEntry& entry);
class ErrorLog
@@ -42,7 +40,14 @@ class ErrorLog
public:
void logMsg(const std::wstring& msg, MessageType type);
- int getItemCount(int typeFilter = MSG_TYPE_INFO | MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) const;
+ struct Stats
+ {
+ int info = 0;
+ int warning = 0;
+ int error = 0;
+ int fatal = 0;
+ };
+ Stats getStats() const;
//subset of std::vector<> interface:
using const_iterator = std::vector<LogEntry>::const_iterator;
@@ -65,59 +70,79 @@ private:
inline
void ErrorLog::logMsg(const std::wstring& msg, MessageType type)
{
- entries_.push_back({ std::time(nullptr), type, copyStringTo<Zstringw>(msg) });
+ entries_.push_back({ std::time(nullptr), type, utfTo<Zstringc>(msg) });
}
-inline
-int ErrorLog::getItemCount(int typeFilter) const
-{
- return static_cast<int>(std::count_if(entries_.begin(), entries_.end(), [typeFilter](const LogEntry& e) { return e.type & typeFilter; }));
-}
-
-inline
-std::wstring getMessageTypeLabel(MessageType type)
+inline
+ErrorLog::Stats ErrorLog::getStats() const
{
- switch (type)
+ Stats count;
+ for (const LogEntry& entry : entries_)
+ switch (entry.type)
{
case MSG_TYPE_INFO:
- return _("Info");
+ ++count.info;
+ break;
case MSG_TYPE_WARNING:
- return _("Warning");
+ ++count.warning;
+ break;
case MSG_TYPE_ERROR:
- return _("Error");
+ ++count.error;
+ break;
case MSG_TYPE_FATAL_ERROR:
- return _("Serious Error");
+ ++count.fatal;
+ break;
}
- assert(false);
- return std::wstring();
+ assert(static_cast<int>(entries_.size()) == count.info + count.warning + count.error + count.fatal);
+ return count;
+}
+
+
+inline
+std::wstring getMessageTypeLabel(MessageType type)
+{
+ switch (type)
+ {
+ case MSG_TYPE_INFO:
+ return _("Info");
+ case MSG_TYPE_WARNING:
+ return _("Warning");
+ case MSG_TYPE_ERROR:
+ return _("Error");
+ case MSG_TYPE_FATAL_ERROR:
+ return _("Serious Error");
+ }
+ assert(false);
+ return std::wstring();
}
inline
-std::wstring formatMessage(const LogEntry& entry)
+std::string formatMessage(const LogEntry& entry)
{
- std::wstring msgFmt = L"[" + formatTime<std::wstring>(FORMAT_TIME, getLocalTime(entry.time)) + L"] " + getMessageTypeLabel(entry.type) + L": ";
+ std::string msgFmt = '[' + utfTo<std::string>(formatTime(formatTimeTag, getLocalTime(entry.time))) + "] " + utfTo<std::string>(getMessageTypeLabel(entry.type)) + ": ";
const size_t prefixLen = unicodeLength(msgFmt); //consider Unicode!
- const Zstringw msg = trimCpy(entry.message);
- static_assert(std::is_same_v<decltype(msg), const Zstringw>, "don't worry about copying as long as we're using a ref-counted string!");
+ const Zstringc msg = trimCpy(entry.message);
+ static_assert(std::is_same_v<decltype(msg), const Zstringc>, "don't worry about copying as long as we're using a ref-counted string!");
for (auto it = msg.begin(); it != msg.end(); )
- if (*it == L'\n')
+ if (*it == '\n')
{
- msgFmt += L'\n';
- msgFmt.append(prefixLen, L' ');
+ msgFmt += '\n';
+ msgFmt.append(prefixLen, ' ');
++it;
//skip duplicate newlines
- for (;it != msg.end() && *it == L'\n'; ++it)
+ for (; it != msg.end() && *it == '\n'; ++it)
;
}
else
msgFmt += *it++;
- return msgFmt += L'\n';
+ msgFmt += '\n';
+ return msgFmt;
}
}
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index e23d48be..4f6704d2 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -311,7 +311,7 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r
{
auto throwException = [&](int ec)
{
- const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathFrom)), L"%y", L"\n" + fmtPath(pathTo));
+ const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L'\n' + fmtPath(pathFrom)), L"%y", L'\n' + fmtPath(pathTo));
const std::wstring errorDescr = formatSystemError(L"rename", ec);
if (ec == EXDEV)
@@ -575,7 +575,7 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath, bool
const Zstring linkPath = getSymlinkTargetRaw(sourcePath); //throw FileError; accept broken symlinks
if (::symlink(linkPath.c_str(), targetPath.c_str()) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourcePath)), L"%y", L"\n" + fmtPath(targetPath)), L"symlink");
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L'\n' + fmtPath(sourcePath)), L"%y", L'\n' + fmtPath(targetPath)), L"symlink");
//allow only consistent objects to be created -> don't place before ::symlink(); targetPath may already exist!
ZEN_ON_SCOPE_FAIL(try { removeSymlinkPlain(targetPath); /*throw FileError*/ }
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index e788bcfe..b78259e0 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -68,7 +68,7 @@ FileBase::FileHandle openHandleForRead(const Zstring& filePath) //throw FileErro
return name + printNumber<std::wstring>(L"0%06o", m & S_IFMT);
}();
throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filePath)),
- _("Unsupported item type.") + L" [" + typeName + L"]");
+ _("Unsupported item type.") + L" [" + typeName + L']');
}
}
//else: let ::open() fail for errors like "not existing"
@@ -100,7 +100,7 @@ FileInput::FileInput(const Zstring& filePath, const IOCallback& notifyUnbuffered
size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError, ErrorFileLocked; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToRead == getBlockSize());
ssize_t bytesRead = 0;
@@ -215,7 +215,7 @@ FileOutput::~FileOutput()
size_t FileOutput::tryWrite(const void* buffer, size_t bytesToWrite) //throw FileError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToWrite <= getBlockSize());
ssize_t bytesWritten = 0;
diff --git a/zen/file_io.h b/zen/file_io.h
index 54bde5aa..b47c6077 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -119,7 +119,7 @@ void saveBinContainer(const Zstring& filePath, const BinContainer& buffer, const
if (!buffer.empty())
{
/*snake oil?*/ fileOut.preAllocateSpaceBestEffort(buffer.size()); //throw FileError
- fileOut.write(&*buffer.begin(), buffer.size()); //throw FileError, X
+ fileOut.write(&buffer[0], buffer.size()); //throw FileError, X
}
fileOut.finalize(); //throw FileError, X
}
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index f2df4153..91a881dc 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -11,6 +11,7 @@
#include "i18n.h"
#include "time.h"
#include "globals.h"
+#include "utf.h"
#include <clocale> //thousands separator
#include "utf.h" //
@@ -115,7 +116,7 @@ std::wstring roundToBlock(double timeInHigh,
std::wstring output = formatUnitTime(roundedtimeInLow / unitLowPerHigh, unitHigh);
if (unitLowPerHigh > blockSizeLow)
- output += L" " + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow);
+ output += L' ' + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow);
return output;
}
}
@@ -194,7 +195,7 @@ std::wstring zen::formatUtcToLocalTime(time_t utcTime)
TimeComp loc = getLocalTime(utcTime);
- std::wstring dateString = formatTime<std::wstring>(L"%x %X", loc);
+ std::wstring dateString = utfTo<std::wstring>(formatTime(Zstr("%x %X"), loc));
return !dateString.empty() ? dateString : errorMsg();
}
diff --git a/zen/guid.h b/zen/guid.h
index 657ed07a..88059be8 100644
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -26,8 +26,8 @@ std::string generateGUID() //creates a 16-byte GUID
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25) //getentropy() requires glibc 2.25 (ldd --version) PS: CentOS 7 is on 2.17
if (::getentropy(&guid[0], guid.size()) != 0) //"The maximum permitted value for the length argument is 256"
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"getentropy", errno)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"getentropy", errno)));
#else
class RandomGeneratorPosix
{
@@ -35,8 +35,8 @@ std::string generateGUID() //creates a 16-byte GUID
RandomGeneratorPosix()
{
if (fd_ == -1)
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"open", errno)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"open", errno)));
}
~RandomGeneratorPosix() { ::close(fd_); }
@@ -47,8 +47,8 @@ std::string generateGUID() //creates a 16-byte GUID
{
const ssize_t bytesRead = ::read(fd_, static_cast<char*>(buf) + offset, size - offset);
if (bytesRead < 1) //0 means EOF => error in this context (should check for buffer overflow, too?)
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"read", bytesRead < 0 ? errno : EIO)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"read", bytesRead < 0 ? errno : EIO)));
offset += bytesRead;
assert(offset <= size);
}
diff --git a/zen/http.cpp b/zen/http.cpp
index 8cd99d7a..c6a390de 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -19,7 +19,7 @@ class HttpInputStream::Impl
public:
Impl(const Zstring& url,
const std::string* postBuf /*issue POST if bound, GET otherwise*/,
- const Zstring& contentType, //required for POST
+ const std::string& contentType, //required for POST
bool disableGetCache /*not relevant for POST (= never cached)*/,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
@@ -37,9 +37,9 @@ public:
const bool useTls = [&]
{
- if (startsWithAsciiNoCase(url, Zstr("http://")))
+ if (startsWithAsciiNoCase(url, "http://"))
return false;
- if (startsWithAsciiNoCase(url, Zstr("https://")))
+ if (startsWithAsciiNoCase(url, "https://"))
return true;
throw SysError(L"URL uses unexpected protocol.");
}();
@@ -49,7 +49,7 @@ public:
std::map<std::string, std::string, LessAsciiNoCase> headers;
if (postBuf && !contentType.empty())
- headers["Content-Type"] = utfTo<std::string>(contentType);
+ headers["Content-Type"] = contentType;
if (useTls) //HTTP default port: 443, see %WINDIR%\system32\drivers\etc\services
{
@@ -96,7 +96,7 @@ public:
const size_t blockSize = std::min(static_cast<size_t>(1024), memBuf_.size()); //smaller block size: try to only read header part
buf.resize(buf.size() + blockSize);
const size_t bytesReceived = tryRead(&*(buf.end() - blockSize), blockSize); //throw SysError
- buf.resize(buf.size() - blockSize + bytesReceived); //caveat: unsigned arithmetics
+ buf.resize(buf.size() - (blockSize - bytesReceived)); //caveat: unsigned arithmetics
if (contains(buf, headerDelim))
{
@@ -122,8 +122,8 @@ public:
statusCode_ = stringTo<int>(statusItems[1]);
for (const std::string& line : split(headersBuf, "\r\n", SplitType::SKIP_EMPTY))
- responseHeaders_[trimCpy(beforeFirst(line, ":", IF_MISSING_RETURN_ALL))] =
- /**/ trimCpy(afterFirst (line, ":", IF_MISSING_RETURN_NONE));
+ responseHeaders_[trimCpy(beforeFirst(line, ':', IF_MISSING_RETURN_ALL))] =
+ /**/ trimCpy(afterFirst (line, ':', IF_MISSING_RETURN_NONE));
//try to get "Content-Length" header if available
if (const std::string* value = getHeader("Content-Length"))
@@ -236,7 +236,7 @@ namespace
{
std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
const std::string* postBuf /*issue POST if bound, GET otherwise*/,
- const Zstring& contentType, //required for POST
+ const std::string& contentType, //required for POST
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
const IOCallback& notifyUnbufferedIO) //throw SysError, X
@@ -248,8 +248,8 @@ std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
auto response = std::make_unique<HttpInputStream::Impl>(urlRed, postBuf, contentType, false /*disableGetCache*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
//https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection
- const int httpStatusCode = response->getStatusCode();
- if (httpStatusCode / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too!
+ const int httpStatus = response->getStatusCode();
+ if (httpStatus / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too!
{
const std::string* value = response->getHeader("Location");
if (!value || value->empty())
@@ -259,8 +259,8 @@ std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
}
else
{
- if (httpStatusCode != 200) //HTTP_STATUS_OK(200)
- throw SysError(formatHttpStatusCode(httpStatusCode)); //e.g. HTTP_STATUS_NOT_FOUND(404)
+ if (httpStatus != 200) //HTTP_STATUS_OK(200)
+ throw SysError(formatHttpStatus(httpStatus)); //e.g. HTTP_STATUS_NOT_FOUND(404)
return response;
}
@@ -340,19 +340,19 @@ std::vector<std::pair<std::string, std::string>> zen::xWwwFormUrlDecode(const st
HttpInputStream zen::sendHttpGet(const Zstring& url, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
- return sendHttpRequestImpl(url, nullptr /*postBuf*/, Zstr("") /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X
+ return sendHttpRequestImpl(url, nullptr /*postBuf*/, "" /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X
}
HttpInputStream zen::sendHttpPost(const Zstring& url, const std::vector<std::pair<std::string, std::string>>& postParams,
const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
- return sendHttpPost(url, xWwwFormUrlEncode(postParams), Zstr("application/x-www-form-urlencoded"), userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
+ return sendHttpPost(url, xWwwFormUrlEncode(postParams), "application/x-www-form-urlencoded", userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
}
-HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const Zstring& contentType,
+HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const std::string& contentType,
const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
return sendHttpRequestImpl(url, &postBuf, contentType, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
@@ -365,7 +365,7 @@ bool zen::internetIsAlive() //noexcept
{
auto response = std::make_unique<HttpInputStream::Impl>(Zstr("http://www.google.com/"),
nullptr /*postParams*/,
- Zstr("") /*contentType*/,
+ "" /*contentType*/,
true /*disableGetCache*/,
Zstr("FreeFileSync"),
nullptr /*caCertFilePath*/,
@@ -380,7 +380,7 @@ bool zen::internetIsAlive() //noexcept
}
-std::wstring zen::formatHttpStatusCode(int sc)
+std::wstring zen::formatHttpStatus(int sc)
{
const wchar_t* statusText = [&] //https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
{
@@ -462,13 +462,13 @@ std::wstring zen::formatHttpStatusCode(int sc)
}
-bool zen::isValidEmail(const Zstring& email)
+bool zen::isValidEmail(const std::string& email)
{
//https://en.wikipedia.org/wiki/Email_address#Syntax
//https://tools.ietf.org/html/rfc3696 => note errata! https://www.rfc-editor.org/errata_search.php?rfc=3696
//https://tools.ietf.org/html/rfc5321
- std::string local = utfTo<std::string>(beforeLast(email, Zstr('@'), IF_MISSING_RETURN_NONE));
- std::string domain = utfTo<std::string>( afterLast(email, Zstr('@'), IF_MISSING_RETURN_NONE));
+ std::string local = beforeLast(email, '@', IF_MISSING_RETURN_NONE);
+ std::string domain = afterLast(email, '@', IF_MISSING_RETURN_NONE);
//consider: "t@st"@email.com t\@st@email.com"
auto stripComments = [](std::string& part)
@@ -517,7 +517,7 @@ bool zen::isValidEmail(const Zstring& email)
}
-std::string zen::htmlSpecialChars(const std::string& str)
+std::string zen::htmlSpecialChars(const std::string_view& str)
{
//mirror PHP: https://github.com/php/php-src/blob/e99d5d39239c611e1e7304e79e88545c4e71a073/ext/standard/html_tables.h#L6189
std::string output;
diff --git a/zen/http.h b/zen/http.h
index fbaa09de..09395f8f 100644
--- a/zen/http.h
+++ b/zen/http.h
@@ -48,15 +48,15 @@ HttpInputStream sendHttpPost(const Zstring& url,
const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
HttpInputStream sendHttpPost(const Zstring& url,
- const std::string& postBuf, const Zstring& contentType,
+ const std::string& postBuf, const std::string& contentType,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
bool internetIsAlive(); //noexcept
-std::wstring formatHttpStatusCode(int httpStatusCode);
-bool isValidEmail(const Zstring& email);
-std::string htmlSpecialChars(const std::string& str);
+std::wstring formatHttpStatus(int httpStatus);
+bool isValidEmail(const std::string& email);
+std::string htmlSpecialChars(const std::string_view& str);
std::string xWwwFormUrlEncode(const std::vector<std::pair<std::string, std::string>>& paramPairs);
std::vector<std::pair<std::string, std::string>> xWwwFormUrlDecode(const std::string& str);
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 54dd7f59..8d44f3f7 100644
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -8,11 +8,6 @@
#define LEGACY_COMPILER_H_839567308565656789
-#if !__cpp_lib_erase_if
- #include <vector>
- #include <set>
- #include <map>
-#endif
//https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
@@ -58,8 +53,18 @@ private:
T* const data_;
};
-//---------------------------------------------------------------------------------
+#if __cpp_lib_math_constants
+ #error get rid of workaround:
+#endif
+
+namespace numbers
+{
+const double pi = 3.14159265358979323846;
+const double e = 2.71828182845904523536;
+const double sqrt2 = 1.41421356237309504880;
+const double ln2 = 0.693147180559945309417;
+}
}
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index dc9c8a19..b823f8ca 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -322,8 +322,8 @@ std::string createSignature(const std::string& message, EVP_PKEY* privateKey) //
reinterpret_cast<unsigned char*>(&signature[0]), //unsigned char* sigret,
&sigLen) != 1) //size_t* siglen
throw SysError(formatLastOpenSSLError(L"EVP_DigestSignFinal"));
- signature.resize(sigLen);
+ signature.resize(sigLen);
return signature;
}
@@ -373,7 +373,7 @@ void zen::verifySignature(const std::string& message, const std::string& signatu
namespace
{
-std::wstring formatSslErrorRaw(int ec)
+std::wstring formatSslErrorCode(int ec)
{
switch (ec)
{
@@ -388,12 +388,15 @@ std::wstring formatSslErrorRaw(int ec)
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ACCEPT);
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC);
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC_JOB);
+ ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_CLIENT_HELLO_CB);
+
+ default:
+ return replaceCpy<std::wstring>(L"SSL error %x", L"%x", numberTo<std::wstring>(ec));
}
- return L"Unknown SSL error: " + numberTo<std::wstring>(ec);
}
-std::wstring formatX509ErrorRaw(long ec)
+std::wstring formatX509ErrorCode(long ec)
{
switch (ec)
{
@@ -473,8 +476,10 @@ std::wstring formatX509ErrorRaw(long ec)
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_NEEDED);
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_FAILED);
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_CERT_UNKNOWN);
+
+ default:
+ return replaceCpy<std::wstring>(L"X509 error %x", L"%x", numberTo<std::wstring>(ec));
}
- return L"Unknown X509 error: " + numberTo<std::wstring>(ec);
}
}
@@ -487,7 +492,7 @@ public:
{
ZEN_ON_SCOPE_FAIL(cleanup(); /*destructor call would lead to member double clean-up!!!*/);
- ctx_ = ::SSL_CTX_new(TLS_client_method());
+ ctx_ = ::SSL_CTX_new(::TLS_client_method());
if (!ctx_)
throw SysError(formatLastOpenSSLError(L"SSL_CTX_new"));
@@ -526,13 +531,13 @@ public:
const int rv = ::SSL_connect(ssl_); //implicitly calls SSL_set_connect_state()
if (rv != 1)
- throw SysError(formatLastOpenSSLError(L"SSL_connect") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv)));
+ throw SysError(formatLastOpenSSLError(L"SSL_connect") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv)));
if (caCertFilePath)
{
const long verifyResult = ::SSL_get_verify_result(ssl_);
if (verifyResult != X509_V_OK)
- throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorRaw(verifyResult), L""));
+ throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorCode(verifyResult), L""));
}
}
@@ -554,7 +559,7 @@ public:
size_t tryRead(void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
size_t bytesReceived = 0;
const int rv = ::SSL_read_ex(ssl_, buffer, bytesToRead, &bytesReceived);
@@ -564,7 +569,7 @@ public:
if (sslError == SSL_ERROR_ZERO_RETURN || //EOF + close_notify alert
(sslError == SSL_ERROR_SYSCALL && ::ERR_peek_last_error() == 0)) //EOF: only expected for HTTP/1.0
return 0;
- throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L" " + formatSslErrorRaw(sslError));
+ throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L' ' + formatSslErrorCode(sslError));
}
assert(bytesReceived > 0); //SSL_read_ex() considers EOF an error!
if (bytesReceived > bytesToRead) //better safe than sorry
@@ -576,12 +581,12 @@ public:
size_t tryWrite(const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
size_t bytesWritten = 0;
const int rv = ::SSL_write_ex(ssl_, buffer, bytesToWrite, &bytesWritten);
if (rv != 1)
- throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv)));
+ throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv)));
if (bytesWritten > bytesToWrite)
throw SysError(L"SSL_write_ex: buffer overflow.");
@@ -759,7 +764,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
auto numToBeString = [](size_t n) -> std::string
{
- static_assert(usingLittleEndian()&& sizeof(n) >= 4);
+ static_assert(usingLittleEndian() && sizeof(n) >= 4);
const char* numStr = reinterpret_cast<const char*>(&n);
return { numStr[3], numStr[2], numStr[1], numStr[0] }; //big endian!
};
diff --git a/zen/perf.h b/zen/perf.h
index b6cb5bb0..9f368016 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -98,7 +98,7 @@ public:
const int64_t timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(watch_.elapsed()).count();
const std::string msg = numberTo<std::string>(timeMs) + " ms";
- std::clog << "Perf: duration: " << msg << "\n";
+ std::clog << "Perf: duration: " << msg << '\n';
resultShown_ = true;
}
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index dc156a6f..f4fd870b 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -45,7 +45,9 @@ bool zen::recycleOrDeleteIfExists(const Zstring& itemPath) //throw FileError
return true;
}
- throw FileError(errorMsg, formatSystemError(L"g_file_trash", replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)));
+ throw FileError(errorMsg, formatSystemError(L"g_file_trash",
+ replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)),
+ utfTo<std::wstring>(error->message)));
//g_quark_to_string(error->domain)
}
return true;
diff --git a/zen/serialize.h b/zen/serialize.h
index dd884e3b..1eabcdec 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -25,35 +25,6 @@ namespace zen
binary container for data storage: must support "basic" std::vector interface (e.g. std::vector<std::byte>, std::string, Zbase<char>)
*/
-//binary container reference implementations
-using Utf8String = Zbase<char>; //ref-counted + COW text stream + guaranteed performance: exponential growth
-class ByteArray; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?)
-
-
-class ByteArray //essentially a std::vector<std::byte> with ref-counted semantics, but no COW! => *almost* value type semantics, but not quite
-{
-public:
- using value_type = std::vector<std::byte>::value_type;
- using iterator = std::vector<std::byte>::iterator;
- using const_iterator = std::vector<std::byte>::const_iterator;
-
- iterator begin() { return buffer_.ref().begin(); }
- iterator end () { return buffer_.ref().end (); }
-
- const_iterator begin() const { return buffer_.ref().begin(); }
- const_iterator end () const { return buffer_.ref().end (); }
-
- void resize(size_t len) { buffer_.ref().resize(len); }
- size_t size() const { return buffer_.ref().size(); }
- bool empty() const { return buffer_.ref().empty(); }
-
- inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return lhs.buffer_.ref() == rhs.buffer_.ref(); }
-
-private:
- SharedRef<std::vector<std::byte>> buffer_ = makeSharedRef<std::vector<std::byte>>();
- //perf: shared_ptr indirection irrelevant: less than 1% slower!
-};
-
/*
-------------------------------
|Buffered Input Stream Concept|
@@ -158,6 +129,7 @@ struct MemoryStreamOut
}
const BinContainer& ref() const { return buffer_; }
+ /**/ BinContainer& ref() { return buffer_; }
private:
MemoryStreamOut (const MemoryStreamOut&) = delete;
@@ -180,7 +152,7 @@ void bufferedStreamCopy(BufferedInputStream& streamIn, //throw X
{
const size_t blockSize = streamIn.getBlockSize();
if (blockSize == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
std::vector<std::byte> buffer(blockSize);
for (;;)
@@ -201,7 +173,7 @@ BinContainer bufferedLoad(BufferedInputStream& streamIn) //throw X
const size_t blockSize = streamIn.getBlockSize();
if (blockSize == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
BinContainer buffer;
for (;;)
@@ -238,7 +210,7 @@ void writeContainer(BufferedOutputStream& stream, const C& cont) //don't even co
const auto len = cont.size();
writeNumber(stream, static_cast<uint32_t>(len));
if (len > 0)
- writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
+ writeArray(stream, &cont[0], sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
}
@@ -276,7 +248,7 @@ C readContainer(BufferedInputStream& stream) //throw UnexpectedEndOfStreamError
catch (std::length_error&) { throw UnexpectedEndOfStreamError(); } //most likely this is due to data corruption!
catch ( std::bad_alloc&) { throw UnexpectedEndOfStreamError(); } //
- readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError
+ readArray(stream, &cont[0], sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError
}
return cont;
}
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index 580c4558..faea4bd9 100644
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -74,7 +74,7 @@ int shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) /
std::string getCommandOutput(const Zstring& command) //throw SysError
{
//https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/popen.3.html
- FILE* pipe = ::popen(command.c_str(), "r");
+ FILE* pipe = ::popen(command.c_str(), "r");
if (!pipe)
THROW_LAST_SYS_ERROR(L"popen");
ZEN_ON_SCOPE_EXIT(::pclose(pipe));
@@ -97,7 +97,7 @@ std::string getCommandOutput(const Zstring& command) //throw SysError
output.resize(output.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics
}
while (!::feof(pipe));
-
+
return output;
}
}
diff --git a/zen/socket.h b/zen/socket.h
index 827d446b..3bd0a2a0 100644
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -89,7 +89,7 @@ namespace
size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
int bytesReceived = 0;
for (;;)
@@ -114,7 +114,7 @@ size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //thro
size_t tryWriteSocket(SocketType socket, const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
int bytesWritten = 0;
for (;;)
diff --git a/zen/string_base.h b/zen/string_base.h
index 6c835c72..d2e00baf 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -221,6 +221,7 @@ public:
Zbase();
Zbase(const Char* str) : Zbase(str, str + strLength(str)) {} //implicit conversion from a C-string!
Zbase(const Char* str, size_t len) : Zbase(str, str + len) {}
+ Zbase(size_t count, Char fillChar);
Zbase(const Zbase& str);
Zbase(Zbase&& tmp) noexcept;
template <class InputIterator>
@@ -251,7 +252,8 @@ public:
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 operator[](size_t pos) const;
+ const Char& operator[](size_t pos) const;
+ /**/ Char& operator[](size_t pos);
bool empty() const { return length() == 0; }
void clear();
size_t find (const Zbase& str, size_t pos = 0) const; //
@@ -283,10 +285,11 @@ public:
static const size_t npos = static_cast<size_t>(-1);
private:
- Zbase (int) = delete; //
- Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char"
- Zbase& operator+=(int) = delete; //
- void push_back (int) = delete; //
+ Zbase (int) = delete; //
+ Zbase(size_t count, int) = delete; //
+ Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char"
+ Zbase& operator+= (int) = delete; //
+ void push_back (int) = delete; //
Char* rawStr_;
};
@@ -360,6 +363,15 @@ Zbase<Char, SP>::Zbase(InputIterator first, InputIterator last)
template <class Char, template <class> class SP> inline
+Zbase<Char, SP>::Zbase(size_t count, Char fillChar)
+{
+ rawStr_ = this->create(count);
+ std::fill(rawStr_, rawStr_ + count, fillChar);
+ rawStr_[count] = 0;
+}
+
+
+template <class Char, template <class> class SP> inline
Zbase<Char, SP>::Zbase(const Zbase<Char, SP>& str)
{
rawStr_ = this->clone(str.rawStr_);
@@ -544,7 +556,15 @@ size_t Zbase<Char, SP>::length() const
template <class Char, template <class> class SP> inline
-const Char Zbase<Char, SP>::operator[](size_t pos) const
+const Char& Zbase<Char, SP>::operator[](size_t pos) const
+{
+ assert(pos < length()); //design by contract! no runtime check!
+ return rawStr_[pos];
+}
+
+
+template <class Char, template <class> class SP> inline
+Char& Zbase<Char, SP>::operator[](size_t pos)
{
assert(pos < length()); //design by contract! no runtime check!
return rawStr_[pos];
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 5c444830..40a4ea52 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -167,8 +167,8 @@ Char asciiToLower(Char c)
}
-template <class Char> inline
-Char asciiToUpper(Char c)
+ template <class Char> inline
+ Char asciiToUpper(Char c)
{
if (static_cast<Char>('a') <= c && c <= static_cast<Char>('z'))
return static_cast<Char>(c - static_cast<Char>('a') + static_cast<Char>('A'));
@@ -182,13 +182,13 @@ inline int strcmpWithNulls(const char* ptr1, const char* ptr2, size_t num)
inline int strcmpWithNulls(const wchar_t* ptr1, const wchar_t* ptr2, size_t num) { return std::wmemcmp(ptr1, ptr2, num); } //
-template <class Char> inline
-int strcmpAsciiNoCase(const Char* lhs, const Char* rhs, size_t len)
+template <class Char1, class Char2> inline
+int strcmpAsciiNoCase(const Char1* lhs, const Char2* rhs, size_t len)
{
while (len-- > 0)
{
- const Char charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case
- const Char charR = asciiToLower(*rhs++); //
+ const Char1 charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case
+ const Char2 charR = asciiToLower(*rhs++); //
if (charL != charR)
return static_cast<unsigned int>(charL) - static_cast<unsigned int>(charR); //unsigned char-comparison is the convention!
//unsigned underflow is well-defined!
diff --git a/zen/string_traits.h b/zen/string_traits.h
index f1269130..69d76b44 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -220,7 +220,8 @@ auto makeStringView(Iterator first, Iterator last)
last - first);
}
-template <class Iterator> inline auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); }
+template <class Iterator> inline
+auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); }
}
#endif //STRING_TRAITS_H_813274321443234
diff --git a/zen/sys_error.cpp b/zen/sys_error.cpp
index 2acaca1d..b802780b 100644
--- a/zen/sys_error.cpp
+++ b/zen/sys_error.cpp
@@ -4,3 +4,187 @@
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
+#include "sys_error.h"
+ #include <cstring>
+
+using namespace zen;
+
+
+
+
+std::wstring zen::getSystemErrorDescription(ErrorCode ec) //return empty string on error
+{
+ const ErrorCode currentError = getLastError(); //not necessarily == ec
+ ZEN_ON_SCOPE_EXIT(errno = currentError);
+
+ std::wstring errorMsg;
+ errorMsg = utfTo<std::wstring>(::strerror(ec));
+ return trimCpy(errorMsg); //Windows messages seem to end with a space...
+}
+
+
+namespace
+{
+std::wstring formatSystemErrorCode(ErrorCode ec)
+{
+ switch (ec) //pretty much all codes currently used on CentOS 7 and macOS 10.15
+ {
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPERM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOENT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESRCH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINTR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENXIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(E2BIG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOEXEC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADF);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECHILD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EAGAIN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EACCES);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EFAULT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTBLK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBUSY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EEXIST);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EXDEV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENODEV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTDIR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISDIR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINVAL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENFILE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMFILE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTTY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETXTBSY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EFBIG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSPC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EROFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMLINK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDOM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERANGE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDEADLK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENAMETOOLONG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOLCK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSYS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTEMPTY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELOOP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMSG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EIDRM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSTR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENODATA);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETIME);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOLINK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMULTIHOP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADMSG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EOVERFLOW);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EILSEQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUSERS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSOCK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDESTADDRREQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMSGSIZE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTOTYPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOPROTOOPT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTONOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESOCKTNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSUP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPFNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EAFNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADDRINUSE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADDRNOTAVAIL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETUNREACH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETRESET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNABORTED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNRESET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOBUFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISCONN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTCONN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESHUTDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETOOMANYREFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETIMEDOUT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNREFUSED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTUNREACH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EALREADY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINPROGRESS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESTALE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDQUOT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECANCELED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EOWNERDEAD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTRECOVERABLE);
+
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECHRNG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL2NSYNC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL3HLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL3RST);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELNRNG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUNATCH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOCSI);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL2HLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EXFULL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOANO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADRQC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADSLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBFONT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENONET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOPKG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESRMNT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECOMM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDOTDOT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTUNIQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADFD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMCHG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBACC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBBAD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBSCN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBMAX);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBEXEC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERESTART);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESTRPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUCLEAN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTNAM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENAVAIL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISNAM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTEIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEDIUM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMEDIUMTYPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOKEY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYEXPIRED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREVOKED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREJECTED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERFKILL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHWPOISON);
+ default:
+ return replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(ec));
+ }
+}
+}
+
+
+std::wstring zen::formatSystemError(const std::wstring& functionName, ErrorCode ec)
+{
+ return formatSystemError(functionName, formatSystemErrorCode(ec), getSystemErrorDescription(ec));
+}
+
+
+std::wstring zen::formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg)
+{
+ std::wstring output = errorCode + L':';
+
+ const std::wstring errorMsgFmt = trimCpy(errorMsg);
+ if (!errorMsgFmt.empty())
+ {
+ output += L' ';
+ output += errorMsgFmt;
+ }
+
+ output += L" [" + functionName + L']';
+ return output;
+}
diff --git a/zen/sys_error.h b/zen/sys_error.h
index a9347bdd..6bef45ea 100644
--- a/zen/sys_error.h
+++ b/zen/sys_error.h
@@ -8,11 +8,10 @@
#define SYS_ERROR_H_3284791347018951324534
#include <string>
-#include "utf.h"
-#include "i18n.h"
#include "scope_guard.h"
+#include "i18n.h"
+#include "utf.h"
- #include <cstring>
#include <cerrno>
@@ -23,9 +22,8 @@ namespace zen
ErrorCode getLastError();
-std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec);
std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg);
-
+std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec);
//A low-level exception class giving (non-translated) detail information only - same conceptional level like "GetLastError()"!
@@ -47,11 +45,6 @@ private:
do { const ErrorCode ecInternal = getLastError(); throw SysError(formatSystemError(functionName, ecInternal)); } while (false)
-//helper for error checking macros:
-inline bool validatBool(bool b) { return b; }
-inline bool validatBool(void* b) { return b != nullptr; }
-bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESULT
-
@@ -59,56 +52,15 @@ bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESUL
inline
ErrorCode getLastError()
{
- return errno; //don't use "::", errno is a macro!
+ return errno; //don't use "::" prefix, errno is a macro!
}
-std::wstring formatSystemErrorRaw(long long) = delete; //intentional overload ambiguity to catch usage errors
-
-inline
-std::wstring formatSystemErrorRaw(ErrorCode ec) //return empty string on error
-{
- const ErrorCode currentError = getLastError(); //not necessarily == lastError
-
- std::wstring errorMsg;
- ZEN_ON_SCOPE_EXIT(errno = currentError);
-
- errorMsg = utfTo<std::wstring>(::strerror(ec));
- trim(errorMsg); //Windows messages seem to end with a blank...
-
- return errorMsg;
-}
+std::wstring getSystemErrorDescription(ErrorCode ec); //return empty string on error
+//intentional overload ambiguity to catch usage errors with HRESULT:
+std::wstring getSystemErrorDescription(long long) = delete;
-std::wstring formatSystemError(const std::wstring& functionName, long long lastError) = delete; //intentional overload ambiguity to catch usage errors with HRESULT!
-
-inline
-std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec)
-{
- const std::wstring errorCode = numberTo<std::wstring>(ec);
- const std::wstring errorDescr = formatSystemErrorRaw(ec);
-
- return formatSystemError(functionName, replaceCpy(_("Error Code %x"), L"%x", errorCode), errorDescr);
-}
-
-
-inline
-std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg)
-{
- std::wstring output = errorCode + L":";
-
- const std::wstring errorMsgFmt = trimCpy(errorMsg);
- if (!errorMsgFmt.empty())
- {
- output += L" ";
- output += errorMsgFmt;
- }
-
- output += L" [" + functionName + L"]";
-
- return output;
-}
-
}
#endif //SYS_ERROR_H_3284791347018951324534
diff --git a/zen/system.cpp b/zen/system.cpp
index 5945484f..9401b94f 100644
--- a/zen/system.cpp
+++ b/zen/system.cpp
@@ -44,6 +44,7 @@ namespace
ComputerModel zen::getComputerModel() //throw FileError
{
+ ComputerModel cm;
try
{
auto tryGetInfo = [](const Zstring& filePath)
@@ -57,9 +58,33 @@ ComputerModel zen::getComputerModel() //throw FileError
}
catch (const FileError& e) { throw SysError(e.toString()); } //errors should be further enriched by context info => SysError
};
- return { tryGetInfo("/sys/devices/virtual/dmi/id/product_name"), //throw SysError
- tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor") }; //
+ cm.model = tryGetInfo("/sys/devices/virtual/dmi/id/product_name"); //throw SysError
+ cm.vendor = tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor"); //
+
+ //clean up:
+ for (const char* dummyModel :
+ {
+ "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA",
+ "System Product Name", "Please change product name", "INVALID",
+ })
+ if (equalAsciiNoCase(cm.model, dummyModel))
+ {
+ cm.model.clear();
+ break;
+ }
+
+ for (const char* dummyVendor :
+ {
+ "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA",
+ "System manufacturer", "OEM Manufacturer",
+ })
+ if (equalAsciiNoCase(cm.vendor, dummyVendor))
+ {
+ cm.vendor.clear();
+ break;
+ }
+ return cm;
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
}
@@ -73,7 +98,7 @@ std::wstring zen::getOsDescription() //throw FileError
{
const std::string osName = trimCpy(getCommandOutput("lsb_release --id -s" )); //throw SysError
const std::string osVersion = trimCpy(getCommandOutput("lsb_release --release -s")); //
- return utfTo<std::wstring>(osName + " " + osVersion); //e.g. "CentOS 7.7.1908"
+ return utfTo<std::wstring>(osName + ' ' + osVersion); //e.g. "CentOS 7.7.1908"
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
diff --git a/zen/thread.cpp b/zen/thread.cpp
index 49c6d9b3..6e8b8219 100644
--- a/zen/thread.cpp
+++ b/zen/thread.cpp
@@ -28,7 +28,7 @@ uint64_t getThreadIdNative()
const pid_t tid = ::syscall(SYS_gettid); //no-fail
//"Invalid thread and process IDs": https://devblogs.microsoft.com/oldnewthing/20040223-00/?p=40503
//if (tid == 0) -> not sure this holds on Linux, too!
- // throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to get thread ID.");
+ // throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to get thread ID.");
static_assert(sizeof(uint64_t) >= sizeof(tid));
return tid;
}
diff --git a/zen/thread.h b/zen/thread.h
index d6cafab7..a1d5197c 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -149,7 +149,7 @@ class ThreadGroup
{
public:
ThreadGroup(size_t threadCountMax, const std::string& groupName) : threadCountMax_(threadCountMax), groupName_(groupName)
- { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); }
+ { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); }
~ThreadGroup()
{
diff --git a/zen/time.h b/zen/time.h
index 27ce518f..9718e5f6 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -8,7 +8,7 @@
#define TIME_H_8457092814324342453627
#include <ctime>
-#include "string_tools.h"
+#include "zstring.h"
namespace zen
@@ -24,7 +24,7 @@ struct TimeComp //replaces std::tm and SYSTEMTIME
};
inline bool operator==(const TimeComp& lhs, const TimeComp& rhs)
{
- return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second;
+ return lhs.second == rhs.second && lhs.minute == rhs.minute && lhs.hour == rhs.hour && lhs.day == rhs.day && lhs.month == rhs.month && lhs.year == rhs.year;
}
inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); }
@@ -37,34 +37,26 @@ time_t utcToTimeT(const TimeComp& tc); //convert UTC time compone
TimeComp getCompileTime(); //returns TimeComp() on error
//----------------------------------------------------------------------------------------------------------------------------------
-
-/*
-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"
-*/
-template <class String, class String2>
-String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
+/* format (current) date and time; example:
+ formatTime(Zstr("%Y|%m|%d")); -> "2011|10|29"
+ formatTime(formatDateTag); -> "2011-10-29"
+ formatTime(formatTimeTag); -> "17:55:34" */
+Zstring formatTime(const Zchar* format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
//the "format" parameter of formatTime() is partially specialized with the following type tags:
-const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 8/23/2001
-const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 2:55:02 PM
-const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. 8/23/2001 2:55:02 PM
+const Zchar* const formatDateTag = Zstr("%x"); //locale-dependent date representation: e.g. 8/23/2001
+const Zchar* const formatTimeTag = Zstr("%X"); //locale-dependent time representation: e.g. 2:55:02 PM
+const Zchar* const formatDateTimeTag = Zstr("%c"); //locale-dependent date and time: e.g. 8/23/2001 2:55:02 PM
-const struct FormatIsoDateTag {} FORMAT_ISO_DATE = {}; //%Y-%m-%d - e.g. 2001-08-23
-const struct FormatIsoTimeTag {} FORMAT_ISO_TIME = {}; //%H:%M:%S - e.g. 14:55:02
-const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02
+const Zchar* const formatIsoDateTag = Zstr("%Y-%m-%d"); //e.g. 2001-08-23
+const Zchar* const formatIsoTimeTag = Zstr("%H:%M:%S"); //e.g. 14:55:02
+const Zchar* const formatIsoDateTimeTag = Zstr("%Y-%m-%d %H:%M:%S"); //e.g. 2001-08-23 14:55:02
//----------------------------------------------------------------------------------------------------------------------------------
-
-/*
-example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02");
- parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02");
-*/
+//example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02");
+// parseTime(formatIsoDateTimeTag, "2001-08-23 14:55:02");
template <class String, class String2>
TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime()
-
//----------------------------------------------------------------------------------------------------------------------------------
@@ -118,68 +110,6 @@ TimeComp toZenTimeComponents(const std::tm& ctc)
}
-template <class T>
-struct GetFormat; //get default time formats as char* or wchar_t*
-
-template <>
-struct GetFormat<FormatDateTag> //%x - locale dependent date representation: e.g. 08/23/01
-{
- const char* format(char) const { return "%x"; }
- const wchar_t* format(wchar_t) const { return L"%x"; }
-};
-
-template <>
-struct GetFormat<FormatTimeTag> //%X - locale dependent time representation: e.g. 14:55:02
-{
- const char* format(char) const { return "%X"; }
- const wchar_t* format(wchar_t) const { return L"%X"; }
-};
-
-template <>
-struct GetFormat<FormatDateTimeTag> //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001
-{
- const char* format(char) const { return "%c"; }
- const wchar_t* format(wchar_t) const { return L"%c"; }
-};
-
-template <>
-struct GetFormat<FormatIsoDateTag> //%Y-%m-%d - e.g. 2001-08-23
-{
- const char* format(char) const { return "%Y-%m-%d"; }
- const wchar_t* format(wchar_t) const { return L"%Y-%m-%d"; }
-};
-
-template <>
-struct GetFormat<FormatIsoTimeTag> //%H:%M:%S - e.g. 14:55:02
-{
- const char* format(char) const { return "%H:%M:%S"; }
- const wchar_t* format(wchar_t) const { return L"%H:%M:%S"; }
-};
-
-template <>
-struct GetFormat<FormatIsoDateTimeTag> //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02
-{
- const char* format(char) const { return "%Y-%m-%d %H:%M:%S"; }
- const wchar_t* format(wchar_t) const { return L"%Y-%m-%d %H:%M:%S"; }
-};
-
-
-//strftime() craziness on invalid input:
-// VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://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 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 std::tm* timeptr)
-{
- return std::wcsftime(buffer, bufferSize, format, timeptr);
-}
-
/*
inline
bool isValid(const std::tm& t)
@@ -203,35 +133,6 @@ bool isValid(const std::tm& t)
//tm_isdst
};
*/
-
-template <class CharType> inline
-size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr)
-{
- return strftimeWrap_impl(buffer, bufferSize, format, timeptr);
-}
-
-
-struct UserDefinedFormatTag {};
-struct PredefinedFormatTag {};
-
-template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
-{
- std::tm ctc = toClibTimeComponents(tc);
- std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
- //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
-
- GetCharTypeT<String> buffer[256] = {};
- const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc);
- return String(buffer, charsWritten);
-}
-
-
-template <class String, class FormatType> inline
-String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag)
-{
- return formatTime<String>(GetFormat<FormatType>().format(GetCharTypeT<String>()), tc, UserDefinedFormatTag());
-}
}
@@ -298,28 +199,29 @@ TimeComp getCompileTime()
}
-template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& tc)
+inline
+Zstring formatTime(const Zchar* format, const TimeComp& tc)
{
if (tc == TimeComp()) //failure code from getLocalTime()
- return String();
+ return Zstring();
- using FormatTag = std::conditional_t<
- std::is_same_v<String2, FormatDateTag > ||
- std::is_same_v<String2, FormatTimeTag > ||
- std::is_same_v<String2, FormatDateTimeTag > ||
- std::is_same_v<String2, FormatIsoDateTag > ||
- std::is_same_v<String2, FormatIsoTimeTag > ||
- std::is_same_v<String2, FormatIsoDateTimeTag>, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>;
+ std::tm ctc = impl::toClibTimeComponents(tc);
+ std::mktime(&ctc); //unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
+ //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
- return impl::formatTime<String>(format, tc, FormatTag());
+ Zstring buffer(256, Zstr('\0'));
+ //strftime() craziness on invalid input:
+ // VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation
+ // GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
+ // Windows: avoid char-based strftime() which uses ANSI encoding! (e.g. Greek letters for AM/PM)
+ const size_t charsWritten = std::strftime(&buffer[0], buffer.size(), format, &ctc);
+ buffer.resize(charsWritten);
+ return buffer;
}
-namespace impl
-{
template <class String, class String2>
-TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag)
+TimeComp parseTime(const String& format, const String2& str)
{
using CharType = GetCharTypeT<String>;
static_assert(std::is_same_v<CharType, GetCharTypeT<String2>>);
@@ -371,11 +273,9 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa
return TimeComp();
const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
- auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name)
+ auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* month)
{
- return asciiToLower(itStr[0]) == name[0] &&
- asciiToLower(itStr[1]) == name[1] &&
- asciiToLower(itStr[2]) == name[2];
+ return equalAsciiNoCase(makeStringView(itStr, 3), month);
});
if (itMonth == std::end(months))
return TimeComp();
@@ -422,26 +322,6 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa
return output;
}
-
-
-template <class FormatType, class String> inline
-TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag)
-{
- return parseTime(GetFormat<FormatType>().format(GetCharTypeT<String>()), str, UserDefinedFormatTag());
-}
-}
-
-
-template <class String, class String2> inline
-TimeComp parseTime(const String& format, const String2& str)
-{
- using FormatTag = std::conditional_t<
- std::is_same_v<String, FormatIsoDateTag > ||
- std::is_same_v<String, FormatIsoTimeTag > ||
- std::is_same_v<String, FormatIsoDateTimeTag>, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>;
-
- return impl::parseTime(format, str, FormatTag());
-}
}
#endif //TIME_H_8457092814324342453627
diff --git a/zen/zlib_wrap.cpp b/zen/zlib_wrap.cpp
index 57a0f33c..685843c3 100644
--- a/zen/zlib_wrap.cpp
+++ b/zen/zlib_wrap.cpp
@@ -29,8 +29,10 @@ std::wstring formatZlibStatusCode(int sc)
ZEN_CHECK_CASE_FOR_CONSTANT(Z_MEM_ERROR);
ZEN_CHECK_CASE_FOR_CONSTANT(Z_BUF_ERROR);
ZEN_CHECK_CASE_FOR_CONSTANT(Z_VERSION_ERROR);
+
+ default:
+ return replaceCpy<std::wstring>(L"zlib status %x", L"%x", numberTo<std::wstring>(sc));
}
- return replaceCpy<std::wstring>(L"zlib status %x.", L"%x", numberTo<std::wstring>(sc));
}
}
@@ -53,7 +55,7 @@ size_t zen::impl::zlib_compress(const void* src, size_t srcLen, void* trg, size_
// Z_MEM_ERROR: not enough memory
// Z_BUF_ERROR: not enough room in the output buffer
if (rv != Z_OK || bufferSize > trgLen)
- throw SysError(formatSystemError(L"compress2", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib compress2", formatZlibStatusCode(rv), L""));
return bufferSize;
}
@@ -71,7 +73,7 @@ size_t zen::impl::zlib_decompress(const void* src, size_t srcLen, void* trg, siz
// Z_BUF_ERROR: not enough room in the output buffer
// Z_DATA_ERROR: input data was corrupted or incomplete
if (rv != Z_OK || bufferSize > trgLen)
- throw SysError(formatSystemError(L"uncompress", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib uncompress", formatZlibStatusCode(rv), L""));
return bufferSize;
}
@@ -96,7 +98,7 @@ public:
memLevel, //int memLevel
Z_DEFAULT_STRATEGY); //int strategy
if (rv != Z_OK)
- throw SysError(formatSystemError(L"deflateInit2", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib deflateInit2", formatZlibStatusCode(rv), L""));
}
~Impl()
@@ -108,7 +110,7 @@ public:
size_t read(void* buffer, size_t bytesToRead) //throw SysError, X; return "bytesToRead" bytes unless end of stream!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
gzipStream_.next_out = static_cast<Bytef*>(buffer);
gzipStream_.avail_out = static_cast<uInt>(bytesToRead);
@@ -131,7 +133,7 @@ public:
if (rv == Z_STREAM_END)
return bytesToRead - gzipStream_.avail_out;
if (rv != Z_OK)
- throw SysError(formatSystemError(L"deflate", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib deflate", formatZlibStatusCode(rv), L""));
if (gzipStream_.avail_out == 0)
return bytesToRead;
diff --git a/zen/zlib_wrap.h b/zen/zlib_wrap.h
index b820a4f8..3db609da 100644
--- a/zen/zlib_wrap.h
+++ b/zen/zlib_wrap.h
@@ -63,7 +63,7 @@ BinContainer compress(const BinContainer& stream, int level) //throw SysError
//save uncompressed stream size for decompression
const uint64_t uncompressedSize = stream.size(); //use portable number type!
contOut.resize(sizeof(uncompressedSize));
- std::memcpy(&*contOut.begin(), &uncompressedSize, sizeof(uncompressedSize));
+ std::memcpy(&contOut[0], &uncompressedSize, sizeof(uncompressedSize));
const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!!
@@ -105,8 +105,8 @@ BinContainer decompress(const BinContainer& stream) //throw SysError
contOut.resize(static_cast<size_t>(uncompressedSize)); //throw std::bad_alloc
}
//most likely this is due to data corruption:
- catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo<std::wstring>(e.what())); }
- catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo<std::wstring>(e.what())); }
+ catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())); }
+ catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())); }
const size_t bytesWritten = impl::zlib_decompress(&*stream.begin() + sizeof(uncompressedSize),
stream.size() - sizeof(uncompressedSize),
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index ff20b8cf..046a3bd4 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -50,7 +50,8 @@ Zstring getUnicodeNormalForm(const Zstring& str)
{
//fast pre-check:
if (isAsciiString(str)) //perf: in the range of 3.5ns
- return str; //god bless our ref-counting! => save output string memory consumption!
+ return str;
+ static_assert(std::is_same_v<decltype(str), const Zbase<Zchar>&>, "god bless our ref-counting! => save output string memory consumption!");
//Example: const char* decomposed = "\x6f\xcc\x81";
// const char* precomposed = "\xc3\xb3";
diff --git a/zen/zstring.h b/zen/zstring.h
index f24e4299..d5d8c588 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -19,8 +19,9 @@
//a high-performance string for interfacing with native OS APIs in multithreaded contexts
using Zstring = zen::Zbase<Zchar>;
-//for special UI-contexts: guaranteed exponential growth + ref-counting
-using Zstringw = zen::Zbase<wchar_t>;
+//for special UI-contexts: guaranteed exponential growth + ref-counting + COW + no SSO overhead
+using Zstringc = zen::Zbase<char>;
+//using Zstringw = zen::Zbase<wchar_t>;
//Caveat: don't expect input/output string sizes to match:
@@ -34,7 +35,7 @@ Zstring makeUpperCopy(const Zstring& str);
Zstring getUnicodeNormalForm(const Zstring& str);
// "In fact, Unicode declares that there is an equivalence relationship between decomposed and composed sequences,
// and conformant software should not treat canonically equivalent sequences, whether composed or decomposed or something in between, as different."
-// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html
+// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html
struct LessUnicodeNormal { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return getUnicodeNormalForm(lhs) < getUnicodeNormalForm(rhs);} };
bgstack15