Archiver Initial
This commit is contained in:
parent
01ba8160ef
commit
3575cbc543
25 changed files with 652 additions and 124 deletions
BIN
Modules/.vs/slnx.sqlite
Normal file
BIN
Modules/.vs/slnx.sqlite
Normal file
Binary file not shown.
|
|
@ -12,7 +12,8 @@ target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
|
|||
|
||||
### -------------------------- Tests -------------------------- ###
|
||||
enable_testing()
|
||||
add_executable(${PROJECT_NAME}Tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/Tests.cpp)
|
||||
file(GLOB SOURCES_TEST "./tests/*.cpp")
|
||||
add_executable(${PROJECT_NAME}Tests ${SOURCES_TEST})
|
||||
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME})
|
||||
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
|
||||
|
||||
|
|
|
|||
146
Modules/public/Archiver.hpp
Normal file
146
Modules/public/Archiver.hpp
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
// Used to transfer data to or from some sort of archive
|
||||
// Abstracts interface so that actual archive must only overload readBytes and writeBytes
|
||||
// The main idea is that it transfers data as bytes only if this type of data does not have special API functions
|
||||
template <bool tRead>
|
||||
class ArchiverTemplate {
|
||||
public:
|
||||
struct HasFunc {
|
||||
typedef ArchiverTemplate& ArchRef;
|
||||
template <typename T, typename = void> struct Write : FalseType {};
|
||||
template <typename T> struct Write<T, VoidType<decltype(DeclareValue<T>()().archiveWrite(DeclareValue<ArchRef>()()))>> : TrueType {};
|
||||
|
||||
template <typename T, typename = void> struct Read : FalseType {};
|
||||
template <typename T> struct Read<T, VoidType<decltype(DeclareValue<T>()().archiveRead(DeclareValue<ArchRef>()()))>> : TrueType {};
|
||||
|
||||
template <typename T, typename = void> struct Archive : FalseType {};
|
||||
template <typename T> struct Archive<T, VoidType<decltype(DeclareValue<T>()().archive(DeclareValue<ArchRef>()()))>> : TrueType {};
|
||||
|
||||
template <typename T>
|
||||
struct AssertCombinations {
|
||||
static constexpr auto assert() {
|
||||
if (HasFunc::template Read<T>::value != HasFunc::template Write<T>::value) return false;
|
||||
if (HasFunc::template Read<T>::value) {
|
||||
if (HasFunc::template Read<T>::value == HasFunc::template Archive<T>::value) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
virtual void writeBytes(const int1* val, ualni size) = 0;
|
||||
virtual void readBytes(int1* val, ualni size) = 0;
|
||||
|
||||
public:
|
||||
ArchiverTemplate() = default;
|
||||
|
||||
// check if type has explicit write method. if not write as bytes
|
||||
template<typename Type>
|
||||
void operator <<(const Type& val) {
|
||||
static_assert(!tRead);
|
||||
static_assert(HasFunc::template AssertCombinations<Type>::assert());
|
||||
if constexpr (HasFunc::template Write<Type>::value) {
|
||||
val.archiveWrite(*this);
|
||||
} else {
|
||||
writeBytes((const int1*) &val, sizeof(val));
|
||||
}
|
||||
}
|
||||
|
||||
// check if type has explicit read method. if not read as bytes
|
||||
template<typename Type>
|
||||
void operator >>(Type& val) {
|
||||
static_assert(tRead);
|
||||
static_assert(HasFunc::template AssertCombinations<Type>::assert());
|
||||
if constexpr (HasFunc::template Read<Type>::value) {
|
||||
val.archiveRead(*this);
|
||||
} else {
|
||||
readBytes((int1*) &val, sizeof(val));
|
||||
}
|
||||
}
|
||||
|
||||
// check if type has explicit archive method. if not read/write as bytes
|
||||
template<typename Type>
|
||||
void operator %(Type& val) {
|
||||
static_assert(HasFunc::template AssertCombinations<Type>::assert());
|
||||
if constexpr (HasFunc::template Archive<Type>::value) {
|
||||
val.archive(*this);
|
||||
} else {
|
||||
if constexpr (tRead) {
|
||||
operator>>(val);
|
||||
} else {
|
||||
operator<<(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void operator %(const Type& val) {
|
||||
static_assert(HasFunc::template AssertCombinations<Type>::assert());
|
||||
if constexpr (HasFunc::template Archive<Type>::value) {
|
||||
((Type&)val).archive(*this);
|
||||
} else {
|
||||
if constexpr (tRead) {
|
||||
operator>>(val);
|
||||
} else {
|
||||
operator<<(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<ualni tMaxMemory, bool tRead>
|
||||
class ArchiverExample : public ArchiverTemplate<tRead> {
|
||||
public:
|
||||
ArchiverExample() = default;
|
||||
|
||||
protected:
|
||||
void incrementAddresses(ualni size) {
|
||||
if (mFirstNotWritten == mAddress) mFirstNotWritten += size;
|
||||
mAddress += size;
|
||||
}
|
||||
|
||||
void writeBytes(const int1* val, ualni size) override {
|
||||
for (auto i = 0; i < size; i++) mBuff[mAddress + i] = val[i];
|
||||
incrementAddresses(size);
|
||||
}
|
||||
|
||||
void readBytes(int1* val, ualni size) override {
|
||||
for (auto i = 0; i < size; i++) val[i] = mBuff[mAddress + i];
|
||||
incrementAddresses(size);
|
||||
}
|
||||
|
||||
template<typename tType>
|
||||
static void test() {
|
||||
const tType val;
|
||||
tType res;
|
||||
|
||||
res.change();
|
||||
|
||||
ArchiverExample<tMaxMemory, false> write;
|
||||
ArchiverExample<tMaxMemory, true> read;
|
||||
|
||||
write % val;
|
||||
|
||||
for (auto i = 0; i < tMaxMemory; i++) read.mBuff[i] = write.mBuff[i];
|
||||
|
||||
read % res;
|
||||
|
||||
if (val != res) {
|
||||
throw "test failed";
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
int1 mBuff[tMaxMemory]{};
|
||||
|
||||
private:
|
||||
ualni mAddress = 0;
|
||||
ualni mFirstNotWritten = 0;
|
||||
};
|
||||
}
|
||||
|
|
@ -4,15 +4,40 @@
|
|||
#include "Environment.hpp"
|
||||
#include "TypeInfo.hpp"
|
||||
#include <initializer_list>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace tp {
|
||||
template<typename Type>
|
||||
using init_list = std::initializer_list<Type>;
|
||||
using InitialierList = std::initializer_list<Type>;
|
||||
|
||||
// Selects whether to pass by constant reference or by value
|
||||
template <typename tType>
|
||||
using SelCopyArg = typename TypeSelect<(sizeof(tType) > sizeof(tp::alni)), const tType&, tType>::Result;
|
||||
using SelectValueOrReference = typename TypeSelect<(sizeof(tType) > sizeof(tp::alni)), const tType&, tType>::Result;
|
||||
|
||||
template <typename tType>
|
||||
using VoidType = void;
|
||||
|
||||
template <typename tType>
|
||||
struct Reference {
|
||||
tType& operator()() {}
|
||||
};
|
||||
|
||||
template <typename tType>
|
||||
struct DeclareValue {
|
||||
tType operator()() {}
|
||||
};
|
||||
|
||||
struct TrueType {
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
struct FalseType {
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
}
|
||||
|
||||
namespace tp {
|
||||
ualni next2pow(ualni v);
|
||||
uhalni next2pow(uhalni v);
|
||||
ufalni next2pow(ufalni v);
|
||||
|
|
|
|||
50
Modules/public/SizeCounter.hpp
Normal file
50
Modules/public/SizeCounter.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
// TODO
|
||||
template <bool tRecursive>
|
||||
class SizeCounter {
|
||||
typedef SizeCounter& ArchRef;
|
||||
template <typename T, typename = void> struct HasSizeCounter : FalseType {};
|
||||
template <typename T> struct HasSizeCounter<T, VoidType<decltype(DeclareValue<T>()().count(DeclareValue<ArchRef>()()))>> : TrueType {};
|
||||
|
||||
public:
|
||||
SizeCounter() = default;
|
||||
|
||||
template<typename Type>
|
||||
void count(const Type& val) {
|
||||
if constexpr (HasSizeCounter<Type>::value) {
|
||||
val.count(*this);
|
||||
} else {
|
||||
if constexpr (tRecursive) {
|
||||
count(sizeof(val));
|
||||
} else {
|
||||
mSize += sizeof(Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void countSizeUnused(ualni size) {
|
||||
mSizeUnused += size;
|
||||
}
|
||||
|
||||
void countSize(ualni size) {
|
||||
mSize += size;
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni getSizeUnused() const {
|
||||
return mSizeUnused;
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni getSize() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
private:
|
||||
ualni mSize = 0;
|
||||
ualni mSizeUnused = 0;
|
||||
};
|
||||
}
|
||||
202
Modules/tests/TestArchiver.cpp
Normal file
202
Modules/tests/TestArchiver.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
#include "Archiver.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace tp;
|
||||
|
||||
bool sFailed = false;
|
||||
|
||||
struct Undef {
|
||||
char character1 = 'a';
|
||||
bool boolean = true;
|
||||
ualni integer = 321;
|
||||
char character2 = 'a';
|
||||
|
||||
void change() {
|
||||
character1++;
|
||||
character2--;
|
||||
integer++;
|
||||
boolean = !boolean;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const Undef& in) const {
|
||||
if (character1 != in.character1) return true;
|
||||
if (character2 != in.character2) return true;
|
||||
if (integer != in.integer) return true;
|
||||
if (boolean != in.boolean) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct SimpleArchive {
|
||||
char character = 'a';
|
||||
ualni integer = 123;
|
||||
bool boolean = true;
|
||||
Undef undef;
|
||||
|
||||
template<typename tArchiver>
|
||||
void archive(tArchiver& ar) {
|
||||
ar % character;
|
||||
ar % integer;
|
||||
ar % boolean;
|
||||
ar % undef;
|
||||
}
|
||||
|
||||
void change() {
|
||||
character++;
|
||||
integer++;
|
||||
boolean = !boolean;
|
||||
undef.change();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const SimpleArchive& in) const {
|
||||
if (character != in.character) return true;
|
||||
if (integer != in.integer) return true;
|
||||
if (boolean != in.boolean) return true;
|
||||
if (undef != in.undef) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Simple {
|
||||
char character = 'a';
|
||||
ualni integer = 123;
|
||||
bool boolean = true;
|
||||
Undef undef;
|
||||
|
||||
template<typename tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
ar >> character;
|
||||
ar >> integer;
|
||||
ar >> boolean;
|
||||
ar >> undef;
|
||||
}
|
||||
|
||||
template<typename tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << character;
|
||||
ar << integer;
|
||||
ar << boolean;
|
||||
ar << undef;
|
||||
}
|
||||
|
||||
void change() {
|
||||
character++;
|
||||
integer++;
|
||||
boolean = !boolean;
|
||||
undef.change();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const Simple& in) const {
|
||||
if (character != in.character) return true;
|
||||
if (integer != in.integer) return true;
|
||||
if (boolean != in.boolean) return true;
|
||||
if (undef != in.undef) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename tType>
|
||||
struct Set {
|
||||
tType buff[10];
|
||||
ualni len = 5;
|
||||
|
||||
template<typename tArchiver>
|
||||
void archiveRead(tArchiver& ar) {
|
||||
ar >> len;
|
||||
for (auto i = 0; i < len; i++) {
|
||||
ar >> buff[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename tArchiver>
|
||||
void archiveWrite(tArchiver& ar) const {
|
||||
ar << len;
|
||||
for (auto i = 0; i < len; i++) {
|
||||
ar << buff[i];
|
||||
}
|
||||
}
|
||||
|
||||
void change() {
|
||||
len = 2;
|
||||
for (auto i = 0; i < len; i++) {
|
||||
buff[i].change();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const Set& in) const {
|
||||
for (auto i = 0; i < len; i++) {
|
||||
if (buff[i] != in.buff[i]) return true;
|
||||
}
|
||||
|
||||
if (len != in.len) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename tType>
|
||||
struct Complex {
|
||||
Undef undef;
|
||||
Set<tType> set;
|
||||
|
||||
template<typename tArchiver>
|
||||
void archive(tArchiver& ar) {
|
||||
ar % set;
|
||||
ar % undef;
|
||||
}
|
||||
|
||||
void change() {
|
||||
undef.change();
|
||||
set.change();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const Complex& in) const {
|
||||
return undef != in.undef || set != in.set;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename tType>
|
||||
void test() {
|
||||
constexpr auto size = 1024;
|
||||
|
||||
const tType val;
|
||||
tType res;
|
||||
|
||||
res.change();
|
||||
|
||||
ArchiverExample<size, false> write;
|
||||
ArchiverExample<size, true> read;
|
||||
|
||||
write % val;
|
||||
|
||||
for (auto i = 0; i < size; i++) read.mBuff[i] = write.mBuff[i];
|
||||
|
||||
read % res;
|
||||
|
||||
if (val != res) {
|
||||
printf("Test %s Failed\n", typeid(tType).name());
|
||||
sFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename A, typename = void> struct HasArchive : FalseType {};
|
||||
template <typename T, typename A> struct HasArchive<T, A, VoidType<decltype(DeclareValue<T>()().archive(DeclareValue<A&>()()))>> : TrueType {};
|
||||
|
||||
void testArchiver() {
|
||||
|
||||
printf("has archive method - %i\n", HasArchive<SimpleArchive, ArchiverExample<10, false>>::value);
|
||||
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<SimpleArchive>::value);
|
||||
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<Simple>::value);
|
||||
|
||||
test<SimpleArchive>();
|
||||
test<Simple>();
|
||||
test<Set<Simple>>();
|
||||
test<Complex<Simple>>();
|
||||
|
||||
if (sFailed) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include "Module.hpp"
|
||||
|
||||
#include "Common.hpp"
|
||||
void testArchiver();
|
||||
|
||||
int main() {
|
||||
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleBase, nullptr };
|
||||
|
|
@ -13,10 +13,12 @@ int main() {
|
|||
|
||||
ASSERT(tp::gEnvironment.mWidth == tp::Environment::ArchWidth::X64);
|
||||
|
||||
ASSERT(tp::max(2, 1) == 2);
|
||||
ASSERT(tp::max(-1, 0) == 0);
|
||||
ASSERT(tp::max(0, -1) == 0);
|
||||
ASSERT(tp::min(0, -1) == -1);
|
||||
ASSERT(tp::max(2, 1) == 2)
|
||||
ASSERT(tp::max(-1, 0) == 0)
|
||||
ASSERT(tp::max(0, -1) == 0)
|
||||
ASSERT(tp::min(0, -1) == -1)
|
||||
|
||||
testArchiver();
|
||||
|
||||
TestModule.deinitialize();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue