Port to macOS

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2023-09-12 16:55:16 +02:00
parent 1e993c8c65
commit 83d7fd844d
41 changed files with 1568 additions and 1324 deletions

View File

@ -7,8 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
F48105AD2AAF5FD4004DE682 /* math.hpp in Sources */ = {isa = PBXBuildFile; fileRef = F48105AC2AAF5FD4004DE682 /* math.hpp */; }; F4C07F522AB059580044EDC0 /* pch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C07F512AB059580044EDC0 /* pch.cpp */; };
F4B7FBE02AAF49BC00C6BE9F /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4B7FBDF2AAF49BC00C6BE9F /* main.cpp */; }; F4C07F552AB05B5B0044EDC0 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4C07F542AB05B5B0044EDC0 /* main.cpp */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -24,10 +24,17 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
F48105AC2AAF5FD4004DE682 /* math.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = math.hpp; sourceTree = "<group>"; };
F48105AE2AAF64C7004DE682 /* common.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = common.hpp; sourceTree = "<group>"; };
F4B7FBDC2AAF49BC00C6BE9F /* UnitTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = UnitTests; sourceTree = BUILT_PRODUCTS_DIR; }; F4B7FBDC2AAF49BC00C6BE9F /* UnitTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = UnitTests; sourceTree = BUILT_PRODUCTS_DIR; };
F4B7FBDF2AAF49BC00C6BE9F /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; }; F4C07F4E2AB059300044EDC0 /* math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = math.cpp; sourceTree = "<group>"; };
F4C07F502AB059580044EDC0 /* pch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch.h; sourceTree = "<group>"; };
F4C07F512AB059580044EDC0 /* pch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch.cpp; sourceTree = "<group>"; };
F4C07F532AB05A240044EDC0 /* compat.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = compat.hpp; sourceTree = "<group>"; };
F4C07F542AB05B5B0044EDC0 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
F4C07F562AB08E690044EDC0 /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parser.cpp; sourceTree = "<group>"; };
F4C07F572AB08E690044EDC0 /* unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cpp; sourceTree = "<group>"; };
F4C07F582AB08E690044EDC0 /* sgml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sgml.cpp; sourceTree = "<group>"; };
F4C07F592AB08E690044EDC0 /* ring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ring.cpp; sourceTree = "<group>"; };
F4C07F5A2AB08E690044EDC0 /* stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stream.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -44,7 +51,16 @@
F4B7FBD32AAF49BC00C6BE9F = { F4B7FBD32AAF49BC00C6BE9F = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
F4B7FBDE2AAF49BC00C6BE9F /* UnitTests */, F4C07F542AB05B5B0044EDC0 /* main.cpp */,
F4C07F4E2AB059300044EDC0 /* math.cpp */,
F4C07F562AB08E690044EDC0 /* parser.cpp */,
F4C07F512AB059580044EDC0 /* pch.cpp */,
F4C07F592AB08E690044EDC0 /* ring.cpp */,
F4C07F582AB08E690044EDC0 /* sgml.cpp */,
F4C07F5A2AB08E690044EDC0 /* stream.cpp */,
F4C07F572AB08E690044EDC0 /* unicode.cpp */,
F4C07F502AB059580044EDC0 /* pch.h */,
F4C07F532AB05A240044EDC0 /* compat.hpp */,
F4B7FBDD2AAF49BC00C6BE9F /* Products */, F4B7FBDD2AAF49BC00C6BE9F /* Products */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
@ -58,16 +74,6 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
F4B7FBDE2AAF49BC00C6BE9F /* UnitTests */ = {
isa = PBXGroup;
children = (
F48105AE2AAF64C7004DE682 /* common.hpp */,
F48105AC2AAF5FD4004DE682 /* math.hpp */,
F4B7FBDF2AAF49BC00C6BE9F /* main.cpp */,
);
path = UnitTests;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -125,8 +131,8 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F4B7FBE02AAF49BC00C6BE9F /* main.cpp in Sources */, F4C07F552AB05B5B0044EDC0 /* main.cpp in Sources */,
F48105AD2AAF5FD4004DE682 /* math.hpp in Sources */, F4C07F522AB059580044EDC0 /* pch.cpp in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -184,10 +190,11 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = ../include; HEADER_SEARCH_PATHS = ../include;
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-liconv";
SDKROOT = macosx; SDKROOT = macosx;
}; };
name = Debug; name = Debug;
@ -237,9 +244,10 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = ../include; HEADER_SEARCH_PATHS = ../include;
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
OTHER_LDFLAGS = "-liconv";
SDKROOT = macosx; SDKROOT = macosx;
}; };
name = Release; name = Release;

77
UnitTests/compat.hpp Normal file
View File

@ -0,0 +1,77 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#pragma once
#if defined(_WIN32)
#include <CppUnitTest.h>
#elif defined(__APPLE__)
#include <stdexcept>
#define TEST_CLASS(name) class name
#define TEST_METHOD(name) static void name()
namespace Assert
{
inline void IsTrue(bool c)
{
if (!c)
throw std::runtime_error("not true");
}
inline void IsFalse(bool c)
{
if (c)
throw std::runtime_error("not false");
}
template <class T>
inline void AreEqual(const T& a, const T& b)
{
if (!(a == b))
throw std::runtime_error("not equal");
}
inline void AreEqual(const char* a, const char* b)
{
if (strcmp(a, b) != 0)
throw std::runtime_error("not equal");
}
inline void AreEqual(const wchar_t* a, const wchar_t* b)
{
if (wcscmp(a, b) != 0)
throw std::runtime_error("not equal");
}
template <class T>
inline void AreNotEqual(const T& a, const T& b)
{
if (a == b)
throw std::runtime_error("equal");
}
inline void AreNotEqual(const char* a, const char* b)
{
if (strcmp(a, b) == 0)
throw std::runtime_error("equal");
}
inline void AreNotEqual(const wchar_t* a, const wchar_t* b)
{
if (wcscmp(a, b) == 0)
throw std::runtime_error("equal");
}
template <class E, typename F>
inline void ExpectException(F functor)
{
try { functor(); }
catch (const E&) { return; }
catch (...) { throw std::runtime_error("unexpected exception"); }
throw std::runtime_error("exception not thrown");
}
}
#endif

38
UnitTests/main.cpp Normal file
View File

@ -0,0 +1,38 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#include "pch.h"
#include "math.cpp"
#include "parser.cpp"
#include "ring.cpp"
#include "sgml.cpp"
#include "stream.cpp"
#include "unicode.cpp"
#include <iostream>
int main(int argc, const char * argv[])
{
try {
UnitTests::math::mul();
UnitTests::math::add();
UnitTests::parser::wtest();
UnitTests::parser::sgml_test();
UnitTests::parser::http_test();
UnitTests::ring::test();
UnitTests::sgml::sgml2wstr();
UnitTests::sgml::wstr2sgml();
UnitTests::stream::async();
UnitTests::stream::replicator();
UnitTests::stream::open_close();
UnitTests::unicode::str2wstr();
UnitTests::unicode::wstr2str();
std::cout << "PASS\n";
return 0;
}
catch (const std::exception& ex) {
std::cerr << ex.what() << " FAIL\n";
return 1;
}
}

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -6,7 +6,9 @@
#include "pch.h" #include "pch.h"
using namespace std; using namespace std;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -8,7 +8,9 @@
using namespace std; using namespace std;
using namespace stdex; using namespace stdex;
using namespace stdex::parser; using namespace stdex::parser;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {
@ -176,6 +178,7 @@ namespace UnitTests
TEST_METHOD(sgml_test) TEST_METHOD(sgml_test)
{ {
std::locale locale_slSI("sl_SI");
static const char text[] = "V ko&zcaron;u&scaron;&ccaron;ku zlobnega mizarja stopiclja fant\nin kli&ccaron;e&nbsp;1234567890."; static const char text[] = "V ko&zcaron;u&scaron;&ccaron;ku zlobnega mizarja stopiclja fant\nin kli&ccaron;e&nbsp;1234567890.";
{ {
@ -194,7 +197,7 @@ namespace UnitTests
} }
{ {
sgml_cp p("&Zcaron;"); sgml_cp p("&Zcaron;", SIZE_MAX, false, locale_slSI);
Assert::IsFalse(p.match(text, 4)); Assert::IsFalse(p.match(text, 4));
Assert::IsTrue(p.match(text, 4, _countof(text), match_case_insensitive)); Assert::IsTrue(p.match(text, 4, _countof(text), match_case_insensitive));
Assert::AreEqual((size_t)4, p.interval.start); Assert::AreEqual((size_t)4, p.interval.start);
@ -202,7 +205,7 @@ namespace UnitTests
} }
{ {
sgml_space_cp p; sgml_space_cp p(false, locale_slSI);
Assert::IsFalse(p.match(text)); Assert::IsFalse(p.match(text));
Assert::IsTrue(p.match(text, 1)); Assert::IsTrue(p.match(text, 1));
Assert::AreEqual((size_t)1, p.interval.start); Assert::AreEqual((size_t)1, p.interval.start);
@ -213,7 +216,7 @@ namespace UnitTests
} }
{ {
sgml_string_branch p("apple", "orange", "Ko&Zcaron;u&Scaron;&ccaron;Ku", nullptr); sgml_string_branch p(locale_slSI, "apple", "orange", "Ko&Zcaron;u&Scaron;&ccaron;Ku", nullptr);
Assert::IsFalse(p.match(text, 2)); Assert::IsFalse(p.match(text, 2));
Assert::IsTrue(p.match(text, 2, _countof(text), match_case_insensitive)); Assert::IsTrue(p.match(text, 2, _countof(text), match_case_insensitive));
Assert::AreEqual((size_t)2, p.hit_offset); Assert::AreEqual((size_t)2, p.hit_offset);

View File

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <stdex/base64.hpp> #include <stdex/base64.hpp>
#include <stdex/compat.hpp>
#include <stdex/errno.hpp> #include <stdex/errno.hpp>
#include <stdex/exception.hpp> #include <stdex/exception.hpp>
#include <stdex/hex.hpp> #include <stdex/hex.hpp>
@ -16,7 +17,6 @@
#include <stdex/parser.hpp> #include <stdex/parser.hpp>
#include <stdex/progress.hpp> #include <stdex/progress.hpp>
#include <stdex/ring.hpp> #include <stdex/ring.hpp>
#include <stdex/sal.hpp>
#include <stdex/sgml.hpp> #include <stdex/sgml.hpp>
#include <stdex/stream.hpp> #include <stdex/stream.hpp>
#include <stdex/string.hpp> #include <stdex/string.hpp>
@ -24,7 +24,7 @@
#include <stdex/unicode.hpp> #include <stdex/unicode.hpp>
#include <stdex/vector_queue.hpp> #include <stdex/vector_queue.hpp>
#include <CppUnitTest.h> #include "compat.hpp"
#include <cstdlib> #include <cstdlib>
#include <filesystem> #include <filesystem>

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -6,7 +6,9 @@
#include "pch.h" #include "pch.h"
using namespace std; using namespace std;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -6,7 +6,9 @@
#include "pch.h" #include "pch.h"
using namespace std; using namespace std;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {
@ -38,9 +40,15 @@ namespace UnitTests
{ i + 35, j + 12 }, { i + 35, j + 12 },
{ i + 42, j + 14 }, { i + 42, j + 14 },
{ i + 53, j + 25 }, { i + 53, j + 25 },
#ifdef _WIN32 // wchar_t* is UTF-16
{ i + 62, j + 27 }, { i + 62, j + 27 },
{ i + 62, j + 27 }, { i + 62, j + 27 },
{ i + 71, j + 29 }, { i + 71, j + 29 },
#else // wchar_t* is UTF-32
{ i + 62, j + 26 },
{ i + 62, j + 26 },
{ i + 71, j + 27 },
#endif
} == map); } == map);
} }

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -8,7 +8,9 @@
using namespace std; using namespace std;
using namespace stdex; using namespace stdex;
using namespace stdex::stream; using namespace stdex::stream;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {
@ -17,11 +19,11 @@ namespace UnitTests
public: public:
TEST_METHOD(async) TEST_METHOD(async)
{ {
constexpr size_t total = 1000; constexpr uint32_t total = 1000;
memory_file source(mul(total, sizeof(size_t))); memory_file source(mul(total, sizeof(uint32_t)));
{ {
async_writer<70> writer(source); async_writer<70> writer(source);
for (size_t i = 0; i < total; ++i) { for (uint32_t i = 0; i < total; ++i) {
Assert::IsTrue(writer.ok()); Assert::IsTrue(writer.ok());
writer << i; writer << i;
} }
@ -29,8 +31,8 @@ namespace UnitTests
Assert::AreEqual<stdex::stream::fpos_t>(0, source.seekbeg(0)); Assert::AreEqual<stdex::stream::fpos_t>(0, source.seekbeg(0));
{ {
async_reader<50> reader(source); async_reader<50> reader(source);
size_t x; uint32_t x;
for (size_t i = 0; i < total; ++i) { for (uint32_t i = 0; i < total; ++i) {
reader >> x; reader >> x;
Assert::IsTrue(reader.ok()); Assert::IsTrue(reader.ok());
Assert::AreEqual(i, x); Assert::AreEqual(i, x);
@ -42,9 +44,9 @@ namespace UnitTests
TEST_METHOD(replicator) TEST_METHOD(replicator)
{ {
constexpr size_t total = 1000; constexpr uint32_t total = 1000;
memory_file f1(mul(total, sizeof(size_t))); memory_file f1(mul(total, sizeof(uint32_t)));
sstring filename2, filename3; sstring filename2, filename3;
filename2 = filename3 = temp_path(); filename2 = filename3 = temp_path();
@ -65,7 +67,7 @@ namespace UnitTests
writer.push_back(&f1); writer.push_back(&f1);
writer.push_back(&f2_buf); writer.push_back(&f2_buf);
writer.push_back(&f3); writer.push_back(&f3);
for (size_t i = 0; i < total; ++i) { for (uint32_t i = 0; i < total; ++i) {
Assert::IsTrue(writer.ok()); Assert::IsTrue(writer.ok());
writer << i; writer << i;
} }
@ -76,8 +78,8 @@ namespace UnitTests
f3.seekbeg(0); f3.seekbeg(0);
{ {
buffer f2_buf(f2, 64, 0); buffer f2_buf(f2, 64, 0);
size_t x; uint32_t x;
for (size_t i = 0; i < total; ++i) { for (uint32_t i = 0; i < total; ++i) {
f1 >> x; f1 >> x;
Assert::IsTrue(f1.ok()); Assert::IsTrue(f1.ok());
Assert::AreEqual(i, x); Assert::AreEqual(i, x);
@ -106,26 +108,26 @@ namespace UnitTests
{ {
cached_file dat(invalid_handle, state_t::fail, 4096); cached_file dat(invalid_handle, state_t::fail, 4096);
const sstring filepath = temp_path(); const sstring filepath = temp_path();
constexpr size_t count = 3; constexpr uint32_t count = 3;
sstring filename[count]; sstring filename[count];
stdex::stream::fpos_t start[count]; stdex::stream::fpos_t start[count];
for (size_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
filename[i] = filepath + sprintf(_T("stdex-stream-open_close%zu.tmp"), NULL, i); filename[i] = filepath + sprintf(_T("stdex-stream-open_close%zu.tmp"), NULL, i);
dat.open(filename[i].c_str(), mode_for_reading | mode_for_writing | share_none | mode_preserve_existing | mode_binary); dat.open(filename[i].c_str(), mode_for_reading | mode_for_writing | share_none | mode_preserve_existing | mode_binary);
Assert::IsTrue(dat.ok()); Assert::IsTrue(dat.ok());
start[i] = dat.tell(); start[i] = dat.tell();
Assert::AreNotEqual(fpos_max, start[i]); Assert::AreNotEqual(fpos_max, start[i]);
for (size_t j = 0; j < 31 + 11 * i; ++j) { for (uint32_t j = 0; j < 31 + 11 * i; ++j) {
dat << j * count + i; dat << j * count + i;
Assert::IsTrue(dat.ok()); Assert::IsTrue(dat.ok());
} }
dat.close(); dat.close();
} }
for (size_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
dat.open(filename[i].c_str(), mode_for_reading | share_none | mode_binary); dat.open(filename[i].c_str(), mode_for_reading | share_none | mode_binary);
Assert::IsTrue(dat.ok()); Assert::IsTrue(dat.ok());
for (;;) { for (;;) {
size_t x; uint32_t x;
dat >> x; dat >> x;
if (!dat.ok()) if (!dat.ok())
break; break;
@ -133,7 +135,7 @@ namespace UnitTests
} }
} }
dat.close(); dat.close();
for (size_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
std::filesystem::remove(filename[i]); std::filesystem::remove(filename[i]);
} }

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -6,7 +6,9 @@
#include "pch.h" #include "pch.h"
using namespace std; using namespace std;
#ifdef _WIN32
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#endif
namespace UnitTests namespace UnitTests
{ {

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <assert.h> #include <assert.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -14,6 +14,35 @@
namespace stdex namespace stdex
{ {
/// \cond internal
static const char base64_enc_lookup[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
static const uint8_t base64_dec_lookup[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 1 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 2 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
/* 3 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255,
/* 4 */ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 5 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
/* 6 */ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
/* 7 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
/* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 9 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* A */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* B */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* C */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* D */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* E */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* F */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};
/// \endcond
/// ///
/// Base64 encoding session /// Base64 encoding session
/// ///
@ -140,17 +169,6 @@ namespace stdex
size_t num; ///< Number of bytes used in `buf` size_t num; ///< Number of bytes used in `buf`
}; };
/// \cond internal
static const char base64_enc_lookup[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
/// \endcond
/// ///
/// Base64 decoding session /// Base64 decoding session
/// ///
@ -256,27 +274,4 @@ namespace stdex
uint8_t buf[4]; ///< Internal buffer uint8_t buf[4]; ///< Internal buffer
size_t num; ///< Number of bytes used in `buf` size_t num; ///< Number of bytes used in `buf`
}; };
/// \cond internal
static const uint8_t base64_dec_lookup[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 1 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 2 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
/* 3 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 64, 255, 255,
/* 4 */ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 5 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
/* 6 */ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
/* 7 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
/* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 9 */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* A */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* B */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* C */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* D */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* E */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* F */ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};
/// \endcond
} }

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "system.hpp" #include "system.hpp"
#include "string.hpp" #include "string.hpp"
#include <stdint.h> #include <stdint.h>

View File

@ -1,13 +1,15 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2022-2023 Amebis Copyright © 2022-2023 Amebis
*/ */
#pragma once #pragma once
#include <stddef.h>
#ifdef _WIN32 #ifdef _WIN32
#include <sal.h> #include <sal.h>
#endif #endif
#include <type_traits>
#ifndef _In_ #ifndef _In_
#define _In_ #define _In_
@ -30,15 +32,24 @@
#ifndef _In_z_ #ifndef _In_z_
#define _In_z_ #define _In_z_
#endif #endif
#ifndef _In_opt_z_
#define _In_opt_z_
#endif
#ifndef _In_z_count_ #ifndef _In_z_count_
#define _In_z_count_(p) #define _In_z_count_(p)
#endif #endif
#ifndef _In_reads_
#define _In_reads_(p)
#endif
#ifndef _In_reads_or_z_ #ifndef _In_reads_or_z_
#define _In_reads_or_z_(p) #define _In_reads_or_z_(p)
#endif #endif
#ifndef _In_reads_or_z_opt_ #ifndef _In_reads_or_z_opt_
#define _In_reads_or_z_opt_(p) #define _In_reads_or_z_opt_(p)
#endif #endif
#ifndef _In_reads_bytes_opt_
#define _In_reads_bytes_opt_(p)
#endif
#ifndef _Printf_format_string_params_ #ifndef _Printf_format_string_params_
#define _Printf_format_string_params_(n) #define _Printf_format_string_params_(n)
#endif #endif
@ -46,6 +57,12 @@
#ifndef _Inout_ #ifndef _Inout_
#define _Inout_ #define _Inout_
#endif #endif
#ifndef _Inout_opt_
#define _Inout_opt_
#endif
#ifndef _Inout_cap_
#define _Inout_cap_(p)
#endif
#ifndef _Use_decl_annotations_ #ifndef _Use_decl_annotations_
#define _Use_decl_annotations_ #define _Use_decl_annotations_
@ -57,19 +74,47 @@
#ifndef _Out_opt_ #ifndef _Out_opt_
#define _Out_opt_ #define _Out_opt_
#endif #endif
#ifndef _Out_z_cap_
#define _Out_z_cap_(p)
#endif
#ifndef _Out_writes_
#define _Out_writes_(p)
#endif
#ifndef _Out_writes_bytes_
#define _Out_writes_bytes_(p)
#endif
#ifndef _Out_writes_z_ #ifndef _Out_writes_z_
#define _Out_writes_z_(p) #define _Out_writes_z_(p)
#endif #endif
#ifndef _Out_writes_bytes_to_opt_
#define _Out_writes_bytes_to_opt_(p, q)
#endif
#ifndef _Success_ #ifndef _Success_
#define _Success_(p) #define _Success_(p)
#endif #endif
#ifndef _Ret_maybenull_z_
#define _Ret_maybenull_z_
#endif
#ifndef _Ret_notnull_ #ifndef _Ret_notnull_
#define _Ret_notnull_ #define _Ret_notnull_
#endif #endif
#ifndef _Ret_z_
#define _Ret_z_
#endif
#ifndef _Must_inspect_result_ #ifndef _Must_inspect_result_
#define _Must_inspect_result_ #define _Must_inspect_result_
#endif #endif
#ifndef _Check_return_
#define _Check_return_
#endif
#ifndef _Post_maybez_
#define _Post_maybez_
#endif
#ifndef _Analysis_assume_
#define _Analysis_assume_(p)
#endif
#ifndef _Likely_ #ifndef _Likely_
#if _HAS_CXX20 #if _HAS_CXX20
@ -98,3 +143,19 @@
#else #else
#define _Unreferenced_(x) #define _Unreferenced_(x)
#endif #endif
#ifndef _WIN32
template <typename T, size_t N>
size_t _countof(T (&arr)[N])
{
return std::extent<T[N]>::value;
}
#endif
#ifdef __APPLE__
#define off64_t off_t
#define lseek64 lseek
#define lockf64 lockf
#define ftruncate64 ftruncate
#endif

View File

@ -1,67 +1,87 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "system.hpp" #include "system.hpp"
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#ifdef _WIN32 #ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
#ifndef BYTE_ORDER
#if defined(_WIN32)
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN #if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
#define BYTE_ORDER LITTLE_ENDIAN
#elif REG_DWORD == REG_DWORD_BIG_ENDIAN #elif REG_DWORD == REG_DWORD_BIG_ENDIAN
#define BIG_ENDIAN #define BYTE_ORDER BIG_ENDIAN
#else #endif
#error Unknown endian #elif defined(__APPLE__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define BYTE_ORDER LITTLE_ENDIAN
#elif __BYTE_ORDER == __ORDER_BIG_ENDIAN__
#define BYTE_ORDER BIG_ENDIAN
#endif #endif
#else #else
#include <endian.h> #include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define BYTE_ORDER LITTLE_ENDIAN
#elif __BYTE_ORDER == __BIG_ENDIAN #elif __BYTE_ORDER == __BIG_ENDIAN
#define BIG_ENDIAN #define BYTE_ORDER BIG_ENDIAN
#else #endif
#endif
#ifndef BYTE_ORDER
#error Unknown endian #error Unknown endian
#endif #endif
#endif #endif
namespace stdex namespace stdex
{ {
inline uint8_t byteswap(_In_ const uint8_t value)
{
return value;
}
inline uint16_t byteswap(_In_ const uint16_t value) inline uint16_t byteswap(_In_ const uint16_t value)
{ {
#if _MSC_VER >= 1300 #if _MSC_VER >= 1300
return _byteswap_ushort(value); return _byteswap_ushort(value);
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
uint16_t t = (value & 0x00ff) << 8; uint16_t t = (value & 0x00ff) << 8;
t |= (value) >> 8; t |= (value) >> 8;
return t; return t;
#else #else
return __builtin_bswap16(value); return __builtin_bswap16(value);
#endif #endif
} }
inline uint32_t byteswap(_In_ const uint32_t value) inline uint32_t byteswap(_In_ const uint32_t value)
{ {
#if _MSC_VER >= 1300 #if _MSC_VER >= 1300
return _byteswap_ulong(value); return _byteswap_ulong(value);
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
uint32_t t = (value & 0x000000ff) << 24; uint32_t t = (value & 0x000000ff) << 24;
t |= (value & 0x0000ff00) << 8; t |= (value & 0x0000ff00) << 8;
t |= (value & 0x00ff0000) >> 8; t |= (value & 0x00ff0000) >> 8;
t |= (value) >> 24; t |= (value) >> 24;
return t; return t;
#else #else
return __builtin_bswap32(value); return __builtin_bswap32(value);
#endif #endif
} }
inline uint64_t byteswap(_In_ const uint64_t value) inline uint64_t byteswap(_In_ const uint64_t value)
{ {
#if _MSC_VER >= 1300 #if _MSC_VER >= 1300
return _byteswap_uint64(value); return _byteswap_uint64(value);
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
uint64_t t = (value & 0x00000000000000ff) << 56; uint64_t t = (value & 0x00000000000000ff) << 56;
t |= (value & 0x000000000000ff00) << 40; t |= (value & 0x000000000000ff00) << 40;
t |= (value & 0x0000000000ff0000) << 24; t |= (value & 0x0000000000ff0000) << 24;
@ -71,25 +91,34 @@ namespace stdex
t |= (value & 0x00ff000000000000) >> 40; t |= (value & 0x00ff000000000000) >> 40;
t |= (value) >> 56; t |= (value) >> 56;
return t; return t;
#else #else
return __builtin_bswap64(value); return __builtin_bswap64(value);
#endif #endif
} }
inline int16_t byteswap(_In_ const int16_t value) { return byteswap((uint16_t)value); } inline int8_t byteswap(_In_ const char value) { return byteswap(static_cast<uint8_t>(value)); }
inline int32_t byteswap(_In_ const int32_t value) { return byteswap((uint32_t)value); } inline int8_t byteswap(_In_ const int8_t value) { return byteswap(static_cast<uint8_t>(value)); }
inline int64_t byteswap(_In_ const int64_t value) { return byteswap((uint64_t)value); } inline int16_t byteswap(_In_ const int16_t value) { return byteswap(static_cast<uint16_t>(value)); }
inline int32_t byteswap(_In_ const int32_t value) { return byteswap(static_cast<uint32_t>(value)); }
inline int64_t byteswap(_In_ const int64_t value) { return byteswap(static_cast<uint64_t>(value)); }
inline float byteswap(_In_ const float value) { return byteswap(*reinterpret_cast<const uint32_t*>(&value)); }
inline double byteswap(_In_ const double value) { return byteswap(*reinterpret_cast<const uint64_t*>(&value)); }
inline void byteswap(_Inout_ uint8_t* value) { assert(value); *value = byteswap(*value); }
inline void byteswap(_Inout_ uint16_t* value) { assert(value); *value = byteswap(*value); } inline void byteswap(_Inout_ uint16_t* value) { assert(value); *value = byteswap(*value); }
inline void byteswap(_Inout_ uint32_t* value) { assert(value); *value = byteswap(*value); } inline void byteswap(_Inout_ uint32_t* value) { assert(value); *value = byteswap(*value); }
inline void byteswap(_Inout_ uint64_t* value) { assert(value); *value = byteswap(*value); } inline void byteswap(_Inout_ uint64_t* value) { assert(value); *value = byteswap(*value); }
inline void byteswap(_Inout_ int16_t* value) { byteswap((uint16_t*)value); } inline void byteswap(_Inout_ char* value) { byteswap(reinterpret_cast<uint8_t*>(value)); }
inline void byteswap(_Inout_ int32_t* value) { byteswap((uint32_t*)value); } inline void byteswap(_Inout_ int8_t* value) { byteswap(reinterpret_cast<uint8_t*>(value)); }
inline void byteswap(_Inout_ int64_t* value) { byteswap((uint64_t*)value); } inline void byteswap(_Inout_ int16_t* value) { byteswap(reinterpret_cast<uint16_t*>(value)); }
inline void byteswap(_Inout_ int32_t* value) { byteswap(reinterpret_cast<uint32_t*>(value)); }
inline void byteswap(_Inout_ int64_t* value) { byteswap(reinterpret_cast<uint64_t*>(value)); }
inline void byteswap(_Inout_ float* value) { byteswap(reinterpret_cast<uint32_t*>(value)); }
inline void byteswap(_Inout_ double* value) { byteswap(reinterpret_cast<uint64_t*>(value)); }
} }
#ifdef BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
#define LE2HE(x) stdex::byteswap(x) #define LE2HE(x) stdex::byteswap(x)
#define BE2HE(x) (x) #define BE2HE(x) (x)
#define HE2LE(x) stdex::byteswap(x) #define HE2LE(x) stdex::byteswap(x)

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>

View File

@ -1,11 +1,11 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <exception> #include <exception>
namespace stdex namespace stdex
@ -13,7 +13,7 @@ namespace stdex
/// ///
/// User cancelled exception /// User cancelled exception
/// ///
class user_cancelled : public std::exception class user_cancelled : public std::runtime_error
{ {
public: public:
/// ///
@ -21,7 +21,7 @@ namespace stdex
/// ///
/// \param[in] msg Error message /// \param[in] msg Error message
/// ///
user_cancelled(_In_opt_z_ const char *msg = nullptr) : exception(msg) user_cancelled(_In_opt_z_ const char *msg = nullptr) : runtime_error(msg)
{ {
} }
}; };

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <assert.h> #include <assert.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "stream.hpp" #include "stream.hpp"
#include <ios> #include <ios>
#include <istream> #include <istream>

View File

@ -1,11 +1,11 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <vector> #include <vector>
namespace stdex namespace stdex
@ -78,7 +78,7 @@ namespace stdex
/// Adds two intervals by components /// Adds two intervals by components
/// ///
/// \param[in] a First interval /// \param[in] a First interval
/// \param[in] a Second interval /// \param[in] b Second interval
/// ///
/// \returns Resulting interval /// \returns Resulting interval
/// ///
@ -137,7 +137,7 @@ inline stdex::interval<T> operator++(_Inout_ stdex::interval<T>& i, int) // Post
/// Subtracts two intervals by components /// Subtracts two intervals by components
/// ///
/// \param[in] a First interval /// \param[in] a First interval
/// \param[in] a Second interval /// \param[in] b Second interval
/// ///
/// \returns Resulting interval /// \returns Resulting interval
/// ///

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <vector> #include <vector>
namespace stdex namespace stdex

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "system.hpp" #include "system.hpp"
#include <stdexcept> #include <stdexcept>

View File

@ -1,4 +1,4 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
@ -19,7 +19,7 @@ namespace stdex
template <class T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> template <class T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0>
inline no_delete(const no_delete<T2>&) noexcept {} inline no_delete(const no_delete<T2>&) noexcept {}
inline void operator()(T* p) const noexcept { p; } inline void operator()(T* p) const noexcept { _Unreferenced_(p); }
}; };
/// ///

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "interval.hpp" #include "interval.hpp"
#include <chrono> #include <chrono>
@ -25,7 +25,7 @@ namespace stdex
/// ///
virtual void set_text(_In_z_ const char* msg) virtual void set_text(_In_z_ const char* msg)
{ {
msg; _Unreferenced_(msg);
} }
/// ///
@ -56,7 +56,7 @@ namespace stdex
/// ///
virtual void show(_In_ bool show = true) virtual void show(_In_ bool show = true)
{ {
show; _Unreferenced_(show);
} }
/// ///
@ -168,7 +168,7 @@ namespace stdex
/// ///
inline progress<T>* detach() inline progress<T>* detach()
{ {
progress* k = m_host; progress<T>* k = m_host;
m_host = NULL; m_host = NULL;
return k; return k;
} }
@ -258,7 +258,7 @@ namespace stdex
} }
protected: protected:
progress* m_host; progress<T>* m_host;
interval<T> m_local, m_global, m_section; interval<T> m_local, m_global, m_section;
}; };
@ -281,7 +281,7 @@ namespace stdex
~progress_switcher() ~progress_switcher()
{ {
m_host_ref = detach(); m_host_ref = this->detach();
} }
protected: protected:

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <assert.h> #include <assert.h>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>

View File

@ -1,12 +1,12 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "compat.hpp"
#include "mapping.hpp" #include "mapping.hpp"
#include "sal.hpp"
#include "sgml_unicode.hpp" #include "sgml_unicode.hpp"
#include "string.hpp" #include "string.hpp"
#include <assert.h> #include <assert.h>
@ -173,7 +173,8 @@ namespace stdex
} }
template <class T> template <class T>
inline _Deprecated_("Use stdex::sgml2wstrcat") void sgml2wstr( _Deprecated_("Use stdex::sgml2wstrcat")
inline void sgml2wstr(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_reads_or_z_opt_(count_src) const T* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const T* src, _In_ size_t count_src,
_In_ int skip = 0, _In_ int skip = 0,
@ -192,8 +193,6 @@ namespace stdex
/// \param[in] offset Logical starting offset of source and destination strings. Unused when map parameter is nullptr. /// \param[in] offset Logical starting offset of source and destination strings. Unused when map parameter is nullptr.
/// \param[in,out] map The vector to append index mapping between source and destination string to. /// \param[in,out] map The vector to append index mapping between source and destination string to.
/// ///
/// \return Unicode string
///
template <class T> template <class T>
inline void sgml2wstrcat( inline void sgml2wstrcat(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
@ -206,7 +205,8 @@ namespace stdex
} }
template <class T> template <class T>
inline _Deprecated_("Use stdex::sgml2wstrcat") void sgml2wstr( _Deprecated_("Use stdex::sgml2wstrcat")
inline void sgml2wstr(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_ const std::basic_string<T>& src, _In_ const std::basic_string<T>& src,
_In_ int skip = 0, _In_ int skip = 0,
@ -324,7 +324,8 @@ namespace stdex
} }
template <class T> template <class T>
inline _Deprecated_("Use stdex::sgml2wstrcat") size_t sgml2wstr( _Deprecated_("Use stdex::sgml2wstrcat")
inline size_t sgml2wstr(
_Inout_cap_(count_dst) wchar_t* dst, _In_ size_t count_dst, _Inout_cap_(count_dst) wchar_t* dst, _In_ size_t count_dst,
_In_reads_or_z_opt_(count_src) const T* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const T* src, _In_ size_t count_src,
_In_ int skip = 0, _In_ int skip = 0,
@ -582,7 +583,8 @@ namespace stdex
} }
} }
inline _Deprecated_("Use stdex::wstr2sgmlcat") void wstr2sgml( _Deprecated_("Use stdex::wstr2sgmlcat")
inline void wstr2sgml(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ size_t what = 0) _In_ size_t what = 0)
@ -605,7 +607,8 @@ namespace stdex
wstr2sgmlcat(dst, src.c_str(), src.size(), what); wstr2sgmlcat(dst, src.c_str(), src.size(), what);
} }
inline _Deprecated_("Use stdex::wstr2sgmlcat") void wstr2sgml( _Deprecated_("Use stdex::wstr2sgmlcat")
inline void wstr2sgml(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_ const std::wstring& src, _In_ const std::wstring& src,
_In_ size_t what = 0) _In_ size_t what = 0)
@ -745,7 +748,8 @@ namespace stdex
return j; return j;
} }
inline _Deprecated_("Use stdex::wstr2sgmlcat") size_t wstr2sgml( _Deprecated_("Use stdex::wstr2sgmlcat")
inline size_t wstr2sgml(
_Inout_cap_(count_dst) char* dst, _In_ size_t count_dst, _Inout_cap_(count_dst) char* dst, _In_ size_t count_dst,
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ size_t what = 0) _In_ size_t what = 0)

View File

@ -1,15 +1,15 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "compat.hpp"
#include "endian.hpp" #include "endian.hpp"
#include "interval.hpp" #include "interval.hpp"
#include "math.hpp" #include "math.hpp"
#include "ring.hpp" #include "ring.hpp"
#include "sal.hpp"
#include "string.hpp" #include "string.hpp"
#include "system.hpp" #include "system.hpp"
#include "unicode.hpp" #include "unicode.hpp"
@ -19,6 +19,10 @@
#if defined(_WIN32) #if defined(_WIN32)
#include <asptlb.h> #include <asptlb.h>
#include <objidl.h> #include <objidl.h>
#else
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#endif #endif
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
@ -254,7 +258,7 @@ namespace stdex
return *this; return *this;
} }
if (read_array(&data, sizeof(T), 1) == 1) if (read_array(&data, sizeof(T), 1) == 1)
LE2HE(&data); (void)LE2HE(&data);
else { else {
data = 0; data = 0;
if (ok()) if (ok())
@ -279,7 +283,7 @@ namespace stdex
{ {
if (!ok()) _Unlikely_ if (!ok()) _Unlikely_
return *this; return *this;
#ifdef BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
T data_le = HE2LE(data); T data_le = HE2LE(data);
write(&data_le, sizeof(T)); write(&data_le, sizeof(T));
#else #else
@ -630,10 +634,6 @@ namespace stdex
inline basic& operator <<(_In_ const uint32_t data) { return write_data(data); } inline basic& operator <<(_In_ const uint32_t data) { return write_data(data); }
inline basic& operator >>(_Out_ uint64_t& data) { return read_data(data); } inline basic& operator >>(_Out_ uint64_t& data) { return read_data(data); }
inline basic& operator <<(_In_ const uint64_t data) { return write_data(data); } inline basic& operator <<(_In_ const uint64_t data) { return write_data(data); }
#if defined(_WIN64) && defined(_NATIVE_SIZE_T_DEFINED)
inline basic& operator >>(_Out_ size_t& data) { return read_data(data); }
inline basic& operator <<(_In_ const size_t data) { return write_data(data); }
#endif
inline basic& operator >>(_Out_ float& data) { return read_data(data); } inline basic& operator >>(_Out_ float& data) { return read_data(data); }
inline basic& operator <<(_In_ const float data) { return write_data(data); } inline basic& operator <<(_In_ const float data) { return write_data(data); }
inline basic& operator >>(_Out_ double& data) { return read_data(data); } inline basic& operator >>(_Out_ double& data) { return read_data(data); }
@ -683,10 +683,11 @@ namespace stdex
}; };
#if _HAS_CXX20 #if _HAS_CXX20
using time_point = std::chrono::time_point<std::chrono::file_clock>; using clock = std::chrono::file_clock;
#else #else
using time_point = std::chrono::time_point<std::chrono::system_clock>; using clock = std::chrono::system_clock;
#endif #endif
using time_point = std::chrono::time_point<clock>;
/// ///
/// Basic seekable stream operations /// Basic seekable stream operations
@ -755,7 +756,7 @@ namespace stdex
{ {
_Unreferenced_(offset); _Unreferenced_(offset);
_Unreferenced_(length); _Unreferenced_(length);
throw std::exception("not implemented"); throw std::domain_error("not implemented");
} }
/// ///
@ -765,7 +766,7 @@ namespace stdex
{ {
_Unreferenced_(offset); _Unreferenced_(offset);
_Unreferenced_(length); _Unreferenced_(length);
throw std::exception("not implemented"); throw std::domain_error("not implemented");
} }
/// ///
@ -809,7 +810,7 @@ namespace stdex
virtual void set_ctime(time_point date) virtual void set_ctime(time_point date)
{ {
_Unreferenced_(date); _Unreferenced_(date);
throw std::exception("not implemented"); throw std::domain_error("not implemented");
} }
/// ///
@ -818,7 +819,7 @@ namespace stdex
virtual void set_atime(time_point date) virtual void set_atime(time_point date)
{ {
_Unreferenced_(date); _Unreferenced_(date);
throw std::exception("not implemented"); throw std::domain_error("not implemented");
} }
/// ///
@ -827,7 +828,7 @@ namespace stdex
virtual void set_mtime(time_point date) virtual void set_mtime(time_point date)
{ {
_Unreferenced_(date); _Unreferenced_(date);
throw std::exception("not implemented"); throw std::domain_error("not implemented");
} }
#ifdef _WIN32 #ifdef _WIN32
@ -855,7 +856,7 @@ namespace stdex
/// ///
/// \param[in] default_charset Fallback charset to return when no BOM detected. /// \param[in] default_charset Fallback charset to return when no BOM detected.
/// ///
charset_id read_charset(_In_ charset_id default_charset = charset_id::default) charset_id read_charset(_In_ charset_id default_charset = charset_id::system)
{ {
if (seek(0) != 0) if (seek(0) != 0)
throw std::runtime_error("failed to seek"); throw std::runtime_error("failed to seek");
@ -1057,6 +1058,7 @@ namespace stdex
case op_t::flush: case op_t::flush:
w.source->flush(); w.source->flush();
break; break;
case op_t::noop:;
} }
w.op = op_t::noop; w.op = op_t::noop;
lk.unlock(); lk.unlock();
@ -2096,8 +2098,7 @@ namespace stdex
} }
if (!succeeded) _Unlikely_ if (!succeeded) _Unlikely_
#else #else
ssize_t num_read = static_cast<ssize_t>(std::min<size_t>(to_read, block_size)); ssize_t num_read = ::read(m_h, data, static_cast<ssize_t>(std::min<size_t>(to_read, block_size)));
num_read = read(m_h, data, num_read);
if (num_read < 0) _Unlikely_ if (num_read < 0) _Unlikely_
#endif #endif
{ {
@ -2149,7 +2150,7 @@ namespace stdex
return length - to_write; return length - to_write;
} }
#else #else
ssize_t num_written = write(m_h, data, static_cast<ssize_t>(std::min<size_t>(to_write, block_size))); ssize_t num_written = ::write(m_h, data, static_cast<ssize_t>(std::min<size_t>(to_write, block_size)));
if (num_written < 0) _Unlikely_ { if (num_written < 0) _Unlikely_ {
m_state = state_t::fail; m_state = state_t::fail;
return length - to_write; return length - to_write;
@ -2487,13 +2488,18 @@ namespace stdex
m_h = CreateFile(filename, dwDesiredAccess, dwShareMode, &sa, dwCreationDisposition, dwFlagsAndAttributes, nullptr); m_h = CreateFile(filename, dwDesiredAccess, dwShareMode, &sa, dwCreationDisposition, dwFlagsAndAttributes, nullptr);
#else #else
int flags = 0; int flags = 0;
if (mode & mode_for_reading) flags |= O_RDONLY; switch (mode & (mode_for_reading | mode_for_writing)) {
if (mode & mode_for_writing) flags |= O_WRONLY; case mode_for_reading: flags |= O_RDONLY; break;
case mode_for_writing: flags |= O_WRONLY; break;
case mode_for_reading | mode_for_writing: flags |= O_RDWR; break;
}
if (mode & mode_create) flags |= mode & mode_preserve_existing ? O_CREAT : (O_CREAT | O_EXCL); if (mode & mode_create) flags |= mode & mode_preserve_existing ? O_CREAT : (O_CREAT | O_EXCL);
if (mode & hint_write_thru) flags |= O_DSYNC; if (mode & hint_write_thru) flags |= O_DSYNC;
#ifndef __APPLE__
if (mode & hint_no_buffering) flags |= O_RSYNC; if (mode & hint_no_buffering) flags |= O_RSYNC;
#endif
m_h = open(filename, flags, DEFFILEMODE); m_h = ::open(filename, flags, DEFFILEMODE);
#endif #endif
if (m_h != invalid_handle) { if (m_h != invalid_handle) {
m_state = state_t::ok; m_state = state_t::ok;
@ -2515,7 +2521,7 @@ namespace stdex
return li.QuadPart; return li.QuadPart;
} }
#else #else
off64_t result = lseek64(m_h, offset, how); off64_t result = lseek64(m_h, offset, static_cast<int>(how));
if (result >= 0) { if (result >= 0) {
m_state = state_t::ok; m_state = state_t::ok;
return result; return result;
@ -2667,8 +2673,8 @@ namespace stdex
return ft2tp(ft); return ft2tp(ft);
#else #else
struct stat buf; struct stat buf;
if (fstat(m_h, &buf) >= 0); if (fstat(m_h, &buf) >= 0)
return time_point::from_time_t(buf.st_atim); return clock::from_time_t(buf.st_atime);
#endif #endif
return time_point::min(); return time_point::min();
} }
@ -2682,7 +2688,7 @@ namespace stdex
#else #else
struct stat buf; struct stat buf;
if (fstat(m_h, &buf) >= 0) if (fstat(m_h, &buf) >= 0)
return time_point::from_time_t(buf.st_mtim); return clock::from_time_t(buf.st_mtime);
#endif #endif
return time_point::min(); return time_point::min();
} }
@ -2708,9 +2714,10 @@ namespace stdex
if (SetFileTime(m_h, nullptr, &ft, nullptr)) if (SetFileTime(m_h, nullptr, &ft, nullptr))
return; return;
#else #else
struct timespec ts[2]; struct timespec ts[2] = {
ts[0].tv_sec = date; { date.time_since_epoch().count(), 0 },
ts[1].tv_nsec = UTIME_OMIT; { 0, UTIME_OMIT },
};
if (futimens(m_h, ts) >= 0) if (futimens(m_h, ts) >= 0)
return; return;
#endif #endif
@ -2725,9 +2732,10 @@ namespace stdex
if (SetFileTime(m_h, nullptr, nullptr, &ft)) if (SetFileTime(m_h, nullptr, nullptr, &ft))
return; return;
#else #else
struct timespec ts[2]; struct timespec ts[2] = {
ts[0].tv_nsec = UTIME_OMIT; { 0, UTIME_OMIT },
ts[1].tv_sec = date; { date.time_since_epoch().count(), 0 },
};
if (futimens(m_h, ts) >= 0) if (futimens(m_h, ts) >= 0)
return; return;
#endif #endif
@ -2773,7 +2781,6 @@ namespace stdex
/// ///
/// \param[in] filename Filename /// \param[in] filename Filename
/// \param[in] mode Bitwise combination of mode_t flags /// \param[in] mode Bitwise combination of mode_t flags
/// \param[in] cache_size Size of the cache block
/// ///
void open(_In_z_ const schar_t* filename, _In_ int mode) void open(_In_z_ const schar_t* filename, _In_ int mode)
{ {
@ -3077,7 +3084,7 @@ namespace stdex
if (end_offset <= m_size) { if (end_offset <= m_size) {
uint32_t num_chars = LE2HE(*reinterpret_cast<uint32_t*>(m_data + m_offset)); uint32_t num_chars = LE2HE(*reinterpret_cast<uint32_t*>(m_data + m_offset));
m_offset = end_offset; m_offset = end_offset;
end_offset = stdex::add(m_offset + stdex::mul(num_chars, sizeof(_Elem))); end_offset = stdex::add(m_offset, stdex::mul(num_chars, sizeof(_Elem)));
_Elem* start = reinterpret_cast<_Elem*>(m_data + m_offset); _Elem* start = reinterpret_cast<_Elem*>(m_data + m_offset);
if (end_offset <= m_size) { if (end_offset <= m_size) {
data.assign(start, start + num_chars); data.assign(start, start + num_chars);
@ -3208,7 +3215,7 @@ namespace stdex
if (!ok()) _Unlikely_ if (!ok()) _Unlikely_
return *this; return *this;
} }
auto p = tok.m_podatki + m_offset; auto p = m_data + m_offset;
*reinterpret_cast<uint32_t*>(p) = HE2LE((uint32_t)num_chars); *reinterpret_cast<uint32_t*>(p) = HE2LE((uint32_t)num_chars);
memcpy(p + sizeof(uint32_t), data, size_chars); memcpy(p + sizeof(uint32_t), data, size_chars);
m_offset = end_offset; m_offset = end_offset;
@ -3384,9 +3391,6 @@ namespace stdex
inline void set(_In_ fpos_t offset, _In_ const uint16_t data) { set<uint16_t>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const uint16_t data) { set<uint16_t>(offset, data); }
inline void set(_In_ fpos_t offset, _In_ const uint32_t data) { set<uint32_t>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const uint32_t data) { set<uint32_t>(offset, data); }
inline void set(_In_ fpos_t offset, _In_ const uint64_t data) { set<uint64_t>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const uint64_t data) { set<uint64_t>(offset, data); }
#if defined(_WIN64) && defined(_NATIVE_SIZE_T_DEFINED)
inline void set(_In_ fpos_t offset, _In_ const size_t data) { set<size_t>(offset, data); }
#endif
inline void set(_In_ fpos_t offset, _In_ const float data) { set<float>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const float data) { set<float>(offset, data); }
inline void set(_In_ fpos_t offset, _In_ const double data) { set<double>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const double data) { set<double>(offset, data); }
inline void set(_In_ fpos_t offset, _In_ const char data) { set<char>(offset, data); } inline void set(_In_ fpos_t offset, _In_ const char data) { set<char>(offset, data); }
@ -3421,9 +3425,6 @@ namespace stdex
inline void get(_In_ fpos_t offset, _Out_ uint16_t & data) { get<uint16_t>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ uint16_t & data) { get<uint16_t>(offset, data); }
inline void get(_In_ fpos_t offset, _Out_ uint32_t & data) { get<uint32_t>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ uint32_t & data) { get<uint32_t>(offset, data); }
inline void get(_In_ fpos_t offset, _Out_ uint64_t & data) { get<uint64_t>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ uint64_t & data) { get<uint64_t>(offset, data); }
#if defined(_WIN64) && defined(_NATIVE_SIZE_T_DEFINED)
inline void get(_In_ fpos_t offset, _Out_ size_t & data) { get<size_t>(offset, data); }
#endif
inline void get(_In_ fpos_t offset, _Out_ float& data) { get<float>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ float& data) { get<float>(offset, data); }
inline void get(_In_ fpos_t offset, _Out_ double& data) { get<double>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ double& data) { get<double>(offset, data); }
inline void get(_In_ fpos_t offset, _Out_ char& data) { get<char>(offset, data); } inline void get(_In_ fpos_t offset, _Out_ char& data) { get<char>(offset, data); }
@ -3447,10 +3448,6 @@ namespace stdex
inline memory_file& operator >>(_Out_ uint32_t & data) { return read_data(data); } inline memory_file& operator >>(_Out_ uint32_t & data) { return read_data(data); }
inline memory_file& operator <<(_In_ const uint64_t data) { return write_data(data); } inline memory_file& operator <<(_In_ const uint64_t data) { return write_data(data); }
inline memory_file& operator >>(_Out_ uint64_t & data) { return read_data(data); } inline memory_file& operator >>(_Out_ uint64_t & data) { return read_data(data); }
#if defined(_WIN64) && defined(_NATIVE_SIZE_T_DEFINED)
inline memory_file& operator <<(_In_ const size_t data) { return write_data(data); }
inline memory_file& operator >>(_Out_ size_t & data) { return read_data(data); }
#endif
inline memory_file& operator <<(_In_ const float data) { return write_data(data); } inline memory_file& operator <<(_In_ const float data) { return write_data(data); }
inline memory_file& operator >>(_Out_ float& data) { return read_data(data); } inline memory_file& operator >>(_Out_ float& data) { return read_data(data); }
inline memory_file& operator <<(_In_ const double data) { return write_data(data); } inline memory_file& operator <<(_In_ const double data) { return write_data(data); }

View File

@ -1,16 +1,22 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2016-2023 Amebis Copyright © 2016-2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif
#include <locale>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
@ -36,19 +42,35 @@ namespace stdex
/// ///
void operator()(_In_ locale_t locale) const void operator()(_In_ locale_t locale) const
{ {
#ifdef _WIN32
free_locale(locale); free_locale(locale);
#else
freelocale(locale);
#endif
} }
}; };
/// ///
/// locale_t helper class to free_locale when going out of scope /// locale_t helper class to free_locale when going out of scope
/// ///
#if defined(_WIN32)
using locale = std::unique_ptr<__crt_locale_pointers, free_locale_delete>; using locale = std::unique_ptr<__crt_locale_pointers, free_locale_delete>;
#elif defined(__APPLE__)
using locale = std::unique_ptr<struct _xlocale, free_locale_delete>;
#else
using locale = std::unique_ptr<struct __locale_struct, free_locale_delete>;
#endif
/// ///
/// Reusable C locale /// Reusable C locale
/// ///
#if defined(_WIN32)
static locale locale_C(_create_locale(LC_ALL, "C")); static locale locale_C(_create_locale(LC_ALL, "C"));
#elif defined(__APPLE__)
static locale locale_C(newlocale(LC_ALL_MASK, "C", LC_GLOBAL_LOCALE));
#else
#error TODO
#endif
/// ///
/// UTF-16 code unit /// UTF-16 code unit
@ -124,10 +146,10 @@ namespace stdex
inline bool iscombining(_In_ char32_t chr) inline bool iscombining(_In_ char32_t chr)
{ {
return return
0x0300 <= chr && chr < 0x0370 || (0x0300 <= chr && chr < 0x0370) ||
0x1dc0 <= chr && chr < 0x1e00 || (0x1dc0 <= chr && chr < 0x1e00) ||
0x20d0 <= chr && chr < 0x2100 || (0x20d0 <= chr && chr < 0x2100) ||
0xfe20 <= chr && chr < 0xfe30; (0xfe20 <= chr && chr < 0xfe30);
} }
/// ///
@ -151,7 +173,7 @@ namespace stdex
inline size_t islbreak(_In_reads_or_z_opt_(count) const T* chr, _In_ size_t count) inline size_t islbreak(_In_reads_or_z_opt_(count) const T* chr, _In_ size_t count)
{ {
_Analysis_assume_(chr || !count); _Analysis_assume_(chr || !count);
if (count >= 2 && (chr[0] == '\r' && chr[1] == '\n' || chr[0] == '\n' && chr[1] == '\r')) if (count >= 2 && ((chr[0] == '\r' && chr[1] == '\n') || (chr[0] == '\n' && chr[1] == '\r')))
return 2; return 2;
if (count > 1 && (chr[0] == '\n' || chr[0] == '\r')) if (count > 1 && (chr[0] == '\n' || chr[0] == '\r'))
return 1; return 1;
@ -811,7 +833,7 @@ namespace stdex
goto error; goto error;
if (value < max_ui_pre1 || // Multiplication nor addition will not overflow. if (value < max_ui_pre1 || // Multiplication nor addition will not overflow.
value == max_ui_pre1 && digit <= max_ui_pre2) // Small digits will not overflow. (value == max_ui_pre1 && digit <= max_ui_pre2)) // Small digits will not overflow.
value = value * (T_bin)radix + digit; value = value * (T_bin)radix + digit;
else { else {
// Overflow! // Overflow!
@ -1060,7 +1082,7 @@ namespace stdex
#pragma warning(suppress: 4996) #pragma warning(suppress: 4996)
r = _vsnprintf_l(str, capacity, format, locale, arg); r = _vsnprintf_l(str, capacity, format, locale, arg);
#else #else
r = vsnprintf(str, capacity, format, arg); r = ::vsnprintf(str, capacity, format, arg);
#endif #endif
if (r == -1 && strnlen(str, capacity) == capacity) { if (r == -1 && strnlen(str, capacity) == capacity) {
// Buffer overrun. Estimate buffer size for the next iteration. // Buffer overrun. Estimate buffer size for the next iteration.

View File

@ -12,9 +12,11 @@
#include <oaidl.h> #include <oaidl.h>
#include <tchar.h> #include <tchar.h>
#else #else
#define _LARGEFILE64_SOURCE
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "sal.hpp" #include "compat.hpp"
#include <assert.h> #include <assert.h>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>

View File

@ -1,14 +1,19 @@
/* /*
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
Copyright © 2023 Amebis Copyright © 2023 Amebis
*/ */
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
#include "endian.hpp"
#include "math.hpp"
#include "system.hpp" #include "system.hpp"
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#ifndef _WIN32
#include <iconv.h>
#endif
#include <memory> #include <memory>
#include <string> #include <string>
@ -16,28 +21,87 @@ namespace stdex
{ {
enum class charset_id : uint16_t { enum class charset_id : uint16_t {
#ifdef _WIN32 #ifdef _WIN32
default = CP_ACP, system = CP_ACP,
utf8 = CP_UTF8, utf8 = CP_UTF8,
utf16 = 1200 /*CP_WINUNICODE*/, utf16 = 1200 /*CP_WINUNICODE*/,
#else #else
default = 0, system = 0,
utf8,
utf16,
utf32,
#endif #endif
}; };
#ifndef _WIN32
/// ///
/// Convert string to Unicode (UTF-16 on Windows) and append to string /// Unicode converter context
///
template <typename T_from, typename T_to>
class iconverter
{
public:
iconverter(_In_ charset_id from, _In_ charset_id to)
{
m_handle = iconv_open(to_encoding(to), to_encoding(from));
if (m_handle == (iconv_t)-1)
throw std::runtime_error("iconv_open failed");
}
~iconverter()
{
iconv_close(m_handle);
}
void convert(_Inout_ std::basic_string<T_to> &dst, _In_reads_or_z_opt_(count) const T_from* src, _In_ size_t count_src) const
{
T_to buf[0x100];
count_src = stdex::strnlen(src, count_src);
size_t src_size = stdex::mul(sizeof(T_from), count_src);
do {
T_to* output = &buf[0];
size_t output_size = sizeof(buf);
errno = 0;
iconv(m_handle, (char**)&src, &src_size, (char**)&output, &output_size);
if (errno)
throw std::runtime_error("iconv failed");
dst.insert(dst.end(), buf, (T_to*)((char*)buf + sizeof(buf) - output_size));
} while (src_size);
}
protected:
static const char* to_encoding(_In_ charset_id charset)
{
switch (charset) {
case charset_id::system:
case charset_id::utf8: return "UTF-8";
#if BYTE_ORDER == BIG_ENDIAN
case charset_id::utf16: return "UTF-16BE";
case charset_id::utf32: return "UTF-32BE";
#else
case charset_id::utf16: return "UTF-16LE";
case charset_id::utf32: return "UTF-32LE";
#endif
default: throw std::invalid_argument("unsupported charset");
}
}
protected:
iconv_t m_handle;
};
#endif
///
/// Convert string to Unicode (UTF-16 on Windows, UTF-32 elsewhere)) and append to string
/// ///
/// \param[in,out] dst String to append Unicode to /// \param[in,out] dst String to append Unicode to
/// \param[in] src String /// \param[in] src String
/// \param[in] count_src String character count limit /// \param[in] count_src String character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
///
/// \return Unicode string
/// ///
inline void strcat( inline void strcat(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
assert(src || !count_src); assert(src || !count_src);
#ifdef _WIN32 #ifdef _WIN32
@ -59,14 +123,15 @@ namespace stdex
dst.append(szBuffer.get(), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1); dst.append(szBuffer.get(), count_src != SIZE_MAX ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
} }
#else #else
throw std::exception("not implemented"); iconverter<char, wchar_t>(charset, charset_id::utf32).convert(dst, src, count_src);
#endif #endif
} }
inline _Deprecated_("Use stdex::strcat") void str2wstr( _Deprecated_("Use stdex::strcat")
inline void str2wstr(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
} }
@ -76,22 +141,21 @@ namespace stdex
/// ///
/// \param[in,out] dst String to append Unicode to /// \param[in,out] dst String to append Unicode to
/// \param[in] src String /// \param[in] src String
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
///
/// \return Unicode string
/// ///
inline void strcat( inline void strcat(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_ const std::string& src, _In_ const std::string& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src.data(), src.size(), charset); strcat(dst, src.data(), src.size(), charset);
} }
inline _Deprecated_("Use stdex::strcat") void str2wstr( _Deprecated_("Use stdex::strcat")
inline void str2wstr(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_ const std::string& src, _In_ const std::string& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src, charset); strcat(dst, src, charset);
} }
@ -102,14 +166,12 @@ namespace stdex
/// \param[in,out] dst String to write Unicode to /// \param[in,out] dst String to write Unicode to
/// \param[in] src String /// \param[in] src String
/// \param[in] count_src String character count limit /// \param[in] count_src String character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
///
/// \return Unicode string
/// ///
inline void strcpy( inline void strcpy(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
dst.clear(); dst.clear();
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
@ -120,14 +182,12 @@ namespace stdex
/// ///
/// \param[in,out] dst String to write Unicode to /// \param[in,out] dst String to write Unicode to
/// \param[in] src String /// \param[in] src String
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
///
/// \return Unicode string
/// ///
inline void strcpy( inline void strcpy(
_Inout_ std::wstring& dst, _Inout_ std::wstring& dst,
_In_ const std::string& src, _In_ const std::string& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcpy(dst, src.data(), src.size(), charset); strcpy(dst, src.data(), src.size(), charset);
} }
@ -136,13 +196,13 @@ namespace stdex
/// Convert string to Unicode string (UTF-16 on Windows) /// Convert string to Unicode string (UTF-16 on Windows)
/// ///
/// \param[in] src String. Must be zero-terminated. /// \param[in] src String. Must be zero-terminated.
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return Unicode string /// \return Unicode string
/// ///
inline std::wstring str2wstr( inline std::wstring str2wstr(
_In_z_ const char* src, _In_z_ const char* src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
std::wstring dst; std::wstring dst;
strcat(dst, src, SIZE_MAX, charset); strcat(dst, src, SIZE_MAX, charset);
@ -154,13 +214,13 @@ namespace stdex
/// ///
/// \param[in] src String /// \param[in] src String
/// \param[in] count_src String character count limit /// \param[in] count_src String character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return Unicode string /// \return Unicode string
/// ///
inline std::wstring str2wstr( inline std::wstring str2wstr(
_In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const char* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
std::wstring dst; std::wstring dst;
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
@ -171,29 +231,29 @@ namespace stdex
/// Convert string to Unicode string (UTF-16 on Windows) /// Convert string to Unicode string (UTF-16 on Windows)
/// ///
/// \param[in] src String /// \param[in] src String
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return Unicode string /// \return Unicode string
/// ///
inline std::wstring str2wstr( inline std::wstring str2wstr(
_In_ const std::string& src, _In_ const std::string& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
return str2wstr(src.c_str(), src.size(), charset); return str2wstr(src.c_str(), src.size(), charset);
} }
/// ///
/// Convert Unicode string (UTF-16 on Windows) to SGML and append to string /// Convert Unicode string (UTF-16 on Windows, UTF-32 elsewhere) to SGML and append to string
/// ///
/// \param[in,out] dst String to append SGML to /// \param[in,out] dst String to append SGML to
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] count_src Unicode string character count limit /// \param[in] count_src Unicode string character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
inline void strcat( inline void strcat(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
assert(src || !count_src); assert(src || !count_src);
#ifdef _WIN32 #ifdef _WIN32
@ -216,14 +276,15 @@ namespace stdex
dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1); dst.append(szBuffer.get(), count_src != SIZE_MAX ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
} }
#else #else
throw std::exception("not implemented"); iconverter<wchar_t, char>(charset_id::utf32, charset).convert(dst, src, count_src);
#endif #endif
} }
inline _Deprecated_("Use stdex::strcat") void wstr2str( _Deprecated_("Use stdex::strcat")
inline void wstr2str(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
} }
@ -233,20 +294,21 @@ namespace stdex
/// ///
/// \param[in,out] dst String to append SGML to /// \param[in,out] dst String to append SGML to
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
inline void strcat( inline void strcat(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_ const std::wstring& src, _In_ const std::wstring& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src.c_str(), src.size(), charset); strcat(dst, src.c_str(), src.size(), charset);
} }
inline _Deprecated_("Use stdex::strcat") void wstr2str( _Deprecated_("Use stdex::strcat")
inline void wstr2str(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_ const std::wstring& src, _In_ const std::wstring& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcat(dst, src, charset); strcat(dst, src, charset);
} }
@ -257,12 +319,12 @@ namespace stdex
/// \param[in,out] dst String to write SGML to /// \param[in,out] dst String to write SGML to
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] count_src Unicode string character count limit /// \param[in] count_src Unicode string character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
inline void strcpy( inline void strcpy(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
dst.clear(); dst.clear();
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
@ -273,12 +335,12 @@ namespace stdex
/// ///
/// \param[in,out] dst String to write SGML to /// \param[in,out] dst String to write SGML to
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
inline void strcpy( inline void strcpy(
_Inout_ std::string& dst, _Inout_ std::string& dst,
_In_ const std::wstring& src, _In_ const std::wstring& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
strcpy(dst, src.data(), src.size(), charset); strcpy(dst, src.data(), src.size(), charset);
} }
@ -287,13 +349,13 @@ namespace stdex
/// Convert Unicode string (UTF-16 on Windows) to string /// Convert Unicode string (UTF-16 on Windows) to string
/// ///
/// \param[in] src Unicode string. Must be zero-terminated. /// \param[in] src Unicode string. Must be zero-terminated.
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return String /// \return String
/// ///
inline std::string wstr2str( inline std::string wstr2str(
_In_z_ const wchar_t* src, _In_z_ const wchar_t* src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
std::string dst; std::string dst;
strcat(dst, src, SIZE_MAX, charset); strcat(dst, src, SIZE_MAX, charset);
@ -305,13 +367,13 @@ namespace stdex
/// ///
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] count_src Unicode string character count limit /// \param[in] count_src Unicode string character count limit
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return String /// \return String
/// ///
inline std::string wstr2str( inline std::string wstr2str(
_In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src, _In_reads_or_z_opt_(count_src) const wchar_t* src, _In_ size_t count_src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
std::string dst; std::string dst;
strcat(dst, src, count_src, charset); strcat(dst, src, count_src, charset);
@ -322,13 +384,13 @@ namespace stdex
/// Convert Unicode string (UTF-16 on Windows) to string /// Convert Unicode string (UTF-16 on Windows) to string
/// ///
/// \param[in] src Unicode string /// \param[in] src Unicode string
/// \param[in] charset Charset (stdex::charset_id::default - system default) /// \param[in] charset Charset (stdex::charset_id::system - system default)
/// ///
/// \return String /// \return String
/// ///
inline std::string wstr2str( inline std::string wstr2str(
_In_ const std::wstring& src, _In_ const std::wstring& src,
_In_ charset_id charset = charset_id::default) _In_ charset_id charset = charset_id::system)
{ {
return wstr2str(src.c_str(), src.size(), charset); return wstr2str(src.c_str(), src.size(), charset);
} }

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "sal.hpp" #include "compat.hpp"
namespace stdex namespace stdex
{ {

View File

@ -1,18 +0,0 @@
#pragma once
#include <stdexcept>
template <class T>
void are_equal(const T& a, const T& b)
{
if (!(a == b))
throw std::runtime_error("values are not equal");
}
template <class E, typename F>
void expect_exception(F functor)
{
try { functor(); }
catch (const E&) { return; }
throw std::runtime_error("exception expected");
}

View File

@ -1,16 +0,0 @@
#include "math.hpp"
#include <iostream>
int main(int argc, const char * argv[])
{
try {
UnitTests::math::mul();
UnitTests::math::add();
std::cout << "PASS\n";
return 0;
}
catch (const std::exception& ex) {
std::cerr << ex.what() << " FAIL\n";
return 1;
}
}

View File

@ -1,39 +0,0 @@
#pragma once
#include "common.hpp"
#include <stdex/math.hpp>
using namespace std;
namespace UnitTests
{
class math
{
public:
static void mul()
{
are_equal<size_t>(10, stdex::mul(2, 5));
are_equal<size_t>(10, stdex::mul(5, 2));
are_equal<size_t>(0, stdex::mul(0, 10));
are_equal<size_t>(0, stdex::mul(10, 0));
are_equal<size_t>(0, stdex::mul(SIZE_MAX, 0));
are_equal<size_t>(0, stdex::mul(0, SIZE_MAX));
are_equal<size_t>(SIZE_MAX, stdex::mul(SIZE_MAX, 1));
are_equal<size_t>(SIZE_MAX, stdex::mul(1, SIZE_MAX));
expect_exception<std::invalid_argument>([] { stdex::mul(SIZE_MAX, 2); });
expect_exception<std::invalid_argument>([] { stdex::mul(2, SIZE_MAX); });
}
static void add()
{
are_equal<size_t>(7, stdex::add(2, 5));
are_equal<size_t>(7, stdex::add(5, 2));
are_equal<size_t>(10, stdex::add(0, 10));
are_equal<size_t>(10, stdex::add(10, 0));
are_equal<size_t>(SIZE_MAX, stdex::add(SIZE_MAX, 0));
are_equal<size_t>(SIZE_MAX, stdex::add(0, SIZE_MAX));
expect_exception<std::invalid_argument>([] { stdex::add(SIZE_MAX, 1); });
expect_exception<std::invalid_argument>([] { stdex::add(1, SIZE_MAX); });
}
};
}