ios, stream: replace <iostream> with leaner and faster own streaming

Our test program runs 15 minutes using our streams vs. 25 minutes using
std::iostream derived streams.

Streams were ported from Amebis AOsn project.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
2023-08-17 13:00:57 +02:00
parent 4965d1eac5
commit 8457226168
10 changed files with 3810 additions and 823 deletions

View File

@@ -23,7 +23,7 @@ Global
{9AFC377D-C32D-4D42-82C2-09FC818020A2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
HideSolutionNode = false
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BBDB843D-98C3-46EF-BDE8-0E80FD851852}

View File

@@ -111,11 +111,14 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<ItemGroup>
<ClCompile Include="ios.cpp" />
<ClCompile Include="math.cpp" />
<ClCompile Include="parser.cpp" />
<ClCompile Include="pch.cpp">
@@ -123,6 +126,7 @@
</ClCompile>
<ClCompile Include="ring.cpp" />
<ClCompile Include="sgml.cpp" />
<ClCompile Include="stream.cpp" />
<ClCompile Include="unicode.cpp" />
</ItemGroup>
<ItemGroup>

View File

@@ -24,15 +24,15 @@
<ClCompile Include="parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ios.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="math.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ring.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="unicode.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@@ -1,103 +0,0 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#include "pch.h"
using namespace std;
using namespace stdex;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTests
{
TEST_CLASS(ios)
{
public:
TEST_METHOD(fstream)
{
WCHAR path[MAX_PATH];
ExpandEnvironmentStringsW(L"%windir%\\notepad.exe", path, _countof(path));
stdex::fstream f(path, ios_base::in | ios_base::binary);
Assert::IsTrue(f.good());
Assert::IsTrue(f.mtime() < chrono::system_clock::now());
}
TEST_METHOD(isharedstrstream)
{
static const char data[] = "\xde\xad\xca\xfe";
stdex::isharedstrstream f(data, _countof(data));
Assert::IsTrue(f.good());
char val;
f.read(&val, 1);
Assert::IsTrue(f.gcount() == 1);
Assert::IsTrue(f.good());
Assert::IsTrue(val == data[0]);
f.read(&val, 1);
Assert::IsTrue(f.gcount() == 1);
Assert::IsTrue(f.good());
Assert::IsTrue(val == data[1]);
f.seekg(_countof(data) - 1);
f.read(&val, 1);
Assert::IsTrue(f.gcount() == 1);
Assert::IsTrue(f.good());
Assert::IsTrue(val == data[_countof(data) - 1]);
f.read(&val, 1);
Assert::IsTrue(f.eof());
f.clear();
f.seekg(-2, ios_base::end);
f.read(&val, 1);
Assert::IsTrue(f.gcount() == 1);
Assert::IsTrue(f.good());
Assert::IsTrue(val == data[_countof(data) - 2]);
}
TEST_METHOD(diagstream)
{
constexpr size_t n = 3;
unique_ptr<std::fstream> f[n];
vector<std::fstream*> fv(n);
{
for (size_t i = 0; i < n; ++i) {
WCHAR path[MAX_PATH];
ExpandEnvironmentStringsW(stdex::sprintf(L"%%temp%%\\file%zu.dat", NULL, i).c_str(), path, _countof(path));
f[i].reset(new std::fstream(path, ios_base::out | ios_base::binary));
fv[i] = f[i].get();
}
stdex::diagstream d(fv.begin(), fv.end());
srand(0);
auto write_some_random = [](_Inout_ ostream& f, _In_ size_t amount)
{
for (size_t i = 0; i < amount; ++i) {
auto r = static_cast<uint32_t>(rand());
f.write(reinterpret_cast<const char*>(&r), sizeof(r) / sizeof(char));
}
};
write_some_random(d, 15);
d.seekp(3);
write_some_random(d, 2);
d.seekp(28);
write_some_random(d, 7);
}
{
for (size_t i = 0; i < n; ++i) {
WCHAR path[MAX_PATH];
ExpandEnvironmentStringsW(stdex::sprintf(L"%%temp%%\\file%zu.dat", NULL, i).c_str(), path, _countof(path));
f[i].reset(new std::fstream(path, ios_base::in | ios_base::binary));
fv[i] = f[i].get();
}
stdex::diagstream d(fv.begin(), fv.end());
do {
uint32_t r;
d.read(reinterpret_cast<char*>(&r), sizeof(r) / sizeof(char));
} while (!d.eof());
}
}
};
}

View File

@@ -14,7 +14,6 @@
#include <stdex/hex.hpp>
#include <stdex/idrec.hpp>
#include <stdex/interval.hpp>
#include <stdex/ios.hpp>
#include <stdex/mapping.hpp>
#include <stdex/math.hpp>
#include <stdex/parser.hpp>
@@ -22,11 +21,14 @@
#include <stdex/ring.hpp>
#include <stdex/sal.hpp>
#include <stdex/sgml.hpp>
#include <stdex/stream.hpp>
#include <stdex/string.hpp>
#include <stdex/system.hpp>
#include <stdex/unicode.hpp>
#include <stdex/vector_queue.hpp>
#include <CppUnitTest.h>
#include <cstdlib>
#include <filesystem>
#include <thread>

111
UnitTests/stream.cpp Normal file
View File

@@ -0,0 +1,111 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2023 Amebis
*/
#include "pch.h"
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTests
{
TEST_CLASS(stream)
{
public:
TEST_METHOD(async)
{
constexpr size_t total = 1000;
stdex::stream::memory_file source(stdex::mul(total, sizeof(size_t)));
{
stdex::stream::async_writer<70> writer(source);
for (size_t i = 0; i < total; ++i) {
Assert::IsTrue(writer.ok());
writer << i;
}
}
Assert::AreEqual<fpos_t>(0, source.seekbeg(0));
{
stdex::stream::async_reader<50> reader(source);
size_t x;
for (size_t i = 0; i < total; ++i) {
reader >> x;
Assert::IsTrue(reader.ok());
Assert::AreEqual(i, x);
}
reader >> x;
Assert::IsFalse(reader.ok());
}
}
TEST_METHOD(replicator)
{
constexpr size_t total = 1000;
stdex::stream::memory_file f1(stdex::mul(total, sizeof(size_t)));
std::basic_string<stdex::sys_char> filename2, filename3;
#ifdef _WIN32
{
TCHAR temp_path[MAX_PATH];
Assert::IsTrue(ExpandEnvironmentStrings(_T("%TEMP%\\"), temp_path, _countof(temp_path)) < MAX_PATH);
filename2 = filename3 = temp_path;
}
#else
filename2 = filename3 = "/tmp/";
#endif
filename2 += _T("stdex-stream-replicator-2.tmp");
stdex::stream::file f2(
filename2.c_str(),
stdex::stream::mode_for_reading | stdex::stream::mode_for_writing | stdex::stream::mode_create | stdex::stream::mode_binary);
filename3 += _T("stdex-stream-replicator-3.tmp");
stdex::stream::cached_file f3(
filename3.c_str(),
stdex::stream::mode_for_reading | stdex::stream::mode_for_writing | stdex::stream::mode_create | stdex::stream::mode_binary,
128);
{
stdex::stream::replicator writer;
stdex::stream::buffer f2_buf(f2, 0, 32);
writer.push_back(&f1);
writer.push_back(&f2_buf);
writer.push_back(&f3);
for (size_t i = 0; i < total; ++i) {
Assert::IsTrue(writer.ok());
writer << i;
}
}
f1.seekbeg(0);
f2.seekbeg(0);
f3.seekbeg(0);
{
stdex::stream::buffer f2_buf(f2, 64, 0);
size_t x;
for (size_t i = 0; i < total; ++i) {
f1 >> x;
Assert::IsTrue(f1.ok());
Assert::AreEqual(i, x);
f2_buf >> x;
Assert::IsTrue(f2_buf.ok());
Assert::AreEqual(i, x);
f3 >> x;
Assert::IsTrue(f3.ok());
Assert::AreEqual(i, x);
}
f1 >> x;
Assert::IsFalse(f1.ok());
f2_buf >> x;
Assert::IsFalse(f2_buf.ok());
f3 >> x;
Assert::IsFalse(f3.ok());
}
f2.close();
std::filesystem::remove(filename2);
f3.close();
std::filesystem::remove(filename3);
}
};
}