Skip to content

Commit 540d925

Browse files
committed
implemented serializer
1 parent 185853a commit 540d925

File tree

13 files changed

+318
-37
lines changed

13 files changed

+318
-37
lines changed

CMakeLists.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.16)
22

3-
project("project_name" C CXX)
3+
project("dubu_serialize" C CXX)
44

55
include("cmake/prevent_in_source_builds.cmake")
66
include("cmake/standard_project_setup.cmake")
@@ -16,11 +16,11 @@ option(${PROJECT_NAME}_BUILD_TESTS
1616
"If the ${PROJECT_NAME} tests are built in addition to the ${PROJECT_NAME} library."
1717
ON)
1818

19-
add_subdirectory("app")
19+
add_subdirectory("dubu_serialize")
2020

2121
if(${${PROJECT_NAME}_BUILD_TESTS})
2222
enable_testing()
2323
include(GoogleTest)
2424
include("thirdparty/googletest.cmake")
25-
add_subdirectory("test")
25+
add_subdirectory("dubu_serialize_test")
2626
endif()

README.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
# cmake-project-template
1+
![Windows](https://github.com/Husenap/cmake-project-template/workflows/Windows/badge.svg)
2+
![Ubuntu](https://github.com/Husenap/cmake-project-template/workflows/Ubuntu/badge.svg)
23

3-
Uses CMake for generating.
4+
```
5+
_ _ _ _ _
6+
_| |_ _| |_ _ _ ___ ___ ___ ___|_|___| |_|___ ___
7+
| . | | | . | | |___|_ -| -_| _| | .'| | |- _| -_|
8+
|___|___|___|___| |___|___|_| |_|__,|_|_|___|___|
9+
```
410

5-
![Windows](https://github.com/Husenap/cmake-project-template/workflows/Windows/badge.svg)
6-
![Ubuntu](https://github.com/Husenap/cmake-project-template/workflows/Ubuntu/badge.svg)
11+
C++ Serialization Library

app/CMakeLists.txt

-15
This file was deleted.

app/src/main.cpp

-7
This file was deleted.

dubu_serialize/CMakeLists.txt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
set(target_name "dubu_serialize")
2+
3+
set(src_serialize
4+
"src/dubu_serialize/Endian.h"
5+
"src/dubu_serialize/Buffer.h"
6+
"src/dubu_serialize/Serializer.h")
7+
8+
set(src_files
9+
${src_serialize}
10+
"src/dummy.cpp")
11+
12+
# Project
13+
add_library(${target_name} STATIC ${src_files})
14+
15+
target_link_libraries(${target_name}
16+
compiler_features
17+
compiler_warnings)
18+
19+
source_group("src" FILES "src/main.cpp")
20+
21+
target_include_directories(${target_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
22+
23+
set_target_properties(${target_name} PROPERTIES FOLDER ${${PROJECT_NAME}_FOLDER})
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#pragma once
2+
3+
#include <filesystem>
4+
#include <fstream>
5+
6+
namespace dubu::serialize {
7+
8+
class WriteBuffer {
9+
public:
10+
virtual ~WriteBuffer() = default;
11+
virtual void Write(const char* buffer, std::size_t size) = 0;
12+
};
13+
14+
class ReadBuffer {
15+
public:
16+
virtual ~ReadBuffer() = default;
17+
virtual void Read(char* buffer, std::size_t size) = 0;
18+
};
19+
20+
class FileBuffer : public WriteBuffer, public ReadBuffer {
21+
public:
22+
enum class Mode { Read, Write };
23+
24+
public:
25+
FileBuffer(std::filesystem::path filePath, Mode mode)
26+
: mMode(mode) {
27+
if (mMode == Mode::Read) {
28+
mStream.open(filePath, std::ios::in | std::ios::binary);
29+
} else {
30+
mStream.open(filePath, std::ios::out | std::ios::binary);
31+
}
32+
}
33+
~FileBuffer() { mStream.close(); }
34+
35+
template <typename T>
36+
T Tell() {
37+
if (mMode == Mode::Read) {
38+
return static_cast<T>(mStream.tellg());
39+
} else {
40+
return static_cast<T>(mStream.tellp());
41+
}
42+
}
43+
44+
template <typename T>
45+
void Seek(T position) {
46+
if (mMode == Mode::Read) {
47+
mStream.seekg(static_cast<std::streampos>(position));
48+
} else {
49+
mStream.seekp(static_cast<std::streampos>(position));
50+
}
51+
}
52+
53+
void Write(const char* buffer, std::size_t size) override { mStream.write(buffer, size); }
54+
void Read(char* buffer, std::size_t size) override { mStream.read(buffer, size); }
55+
56+
private:
57+
std::fstream mStream;
58+
Mode mMode = Mode::Read;
59+
};
60+
61+
} // namespace dubu::serialize
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
namespace dubu::serialize::internal {
4+
5+
class Endian {
6+
private:
7+
Endian() = delete;
8+
static constexpr uint32_t data = 0x01020304;
9+
static constexpr uint8_t magic = static_cast<uint8_t>(data);
10+
11+
public:
12+
static constexpr bool little = magic == 0x04;
13+
static constexpr bool big = magic == 0x01;
14+
};
15+
16+
template <typename T>
17+
inline void FlipEndian(T& u) {
18+
union {
19+
T u;
20+
unsigned char u8[sizeof(T)];
21+
} source, dest;
22+
23+
source.u = u;
24+
25+
for (std::size_t k = 0; k < sizeof(T); ++k) {
26+
dest.u8[k] = source.u8[sizeof(T) - k - 1];
27+
}
28+
29+
u = dest.u;
30+
}
31+
32+
} // namespace dubu::serialize::internal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
6+
#include "Buffer.h"
7+
#include "Endian.h"
8+
9+
namespace dubu::serialize::internal {
10+
11+
template <typename T, bool IsArithmetic>
12+
struct Serializer {
13+
void Read(ReadBuffer& buffer, T& object) { object.Serialize(buffer); }
14+
void Write(WriteBuffer& buffer, const T& object) { object.Serialize(buffer); }
15+
};
16+
17+
} // namespace dubu::serialize::internal
18+
19+
namespace dubu::serialize {
20+
21+
template <typename T>
22+
ReadBuffer& operator>>(ReadBuffer& buffer, T& object) {
23+
internal::Serializer<T, std::is_arithmetic_v<std::decay_t<T>>>().Read(buffer, object);
24+
return buffer;
25+
}
26+
27+
template <typename T>
28+
WriteBuffer& operator<<(WriteBuffer& buffer, const T& object) {
29+
internal::Serializer<T, std::is_arithmetic_v<std::decay_t<T>>>().Write(buffer, object);
30+
return buffer;
31+
}
32+
33+
} // namespace dubu::serialize
34+
35+
namespace dubu::serialize::internal {
36+
37+
template <typename T>
38+
struct Serializer<T, true> {
39+
void Read(ReadBuffer& buffer, T& object) {
40+
buffer.Read(reinterpret_cast<char*>(&object), sizeof(T));
41+
if (Endian::big) {
42+
FlipEndian(object);
43+
}
44+
}
45+
void Write(WriteBuffer& buffer, const T& object) {
46+
if (Endian::big) {
47+
T objectCopy(object);
48+
FlipEndian(objectCopy);
49+
buffer.Write(reinterpret_cast<const char*>(&objectCopy), sizeof(T));
50+
} else {
51+
buffer.Write(reinterpret_cast<const char*>(&object), sizeof(T));
52+
}
53+
}
54+
};
55+
56+
template <>
57+
struct Serializer<std::string, false> {
58+
void Read(ReadBuffer& buffer, std::string& object) {
59+
uint32_t size;
60+
buffer >> size;
61+
object.resize(static_cast<std::size_t>(size));
62+
buffer.Read(&object[0], static_cast<std::size_t>(size));
63+
}
64+
void Write(WriteBuffer& buffer, const std::string& object) {
65+
uint32_t size = static_cast<uint32_t>(object.size());
66+
buffer << size;
67+
buffer.Write(&object[0], object.size());
68+
}
69+
};
70+
71+
template <typename T>
72+
struct Serializer<std::vector<T>, false> {
73+
void Read(ReadBuffer& buffer, std::vector<T>& object) {
74+
uint32_t size;
75+
buffer >> size;
76+
object.resize(static_cast<std::size_t>(size));
77+
for (std::size_t i = 0; i < object.size(); ++i) {
78+
buffer >> object[i];
79+
}
80+
}
81+
void Write(WriteBuffer& buffer, const std::vector<T>& object) {
82+
buffer << static_cast<uint32_t>(object.size());
83+
for (std::size_t i = 0; i < object.size(); ++i) {
84+
buffer << object[i];
85+
}
86+
}
87+
};
88+
89+
} // namespace dubu::serialize::internal

dubu_serialize/src/dummy.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+


dubu_serialize/src/precompiled.h

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
#include <fstream>

test/CMakeLists.txt dubu_serialize_test/CMakeLists.txt

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
set(target_name "app_test")
1+
set(target_name "dubu_serialize_test")
22

33
set(src_files
4-
"src/unit.cpp")
4+
"unit/SerializerTests.cpp")
55

66
add_executable(${target_name} ${src_files})
77

88
target_link_libraries(${target_name}
99
gtest
1010
gmock
11-
gmock_main)
11+
gmock_main
12+
dubu_serialize)
1213

1314
set_target_properties(${target_name} PROPERTIES FOLDER ${${PROJECT_NAME}_FOLDER}/test)
1415

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include <string>
2+
3+
#include <dubu_serialize/Serializer.h>
4+
#include <gmock/gmock.h>
5+
6+
TEST(dubu_serialize, single_int) {
7+
const char* fileName = "single_int.bin";
8+
uint32_t expectedValue = 0xC0FFEE;
9+
10+
{
11+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Write);
12+
13+
fileBuffer << expectedValue;
14+
15+
EXPECT_EQ(fileBuffer.Tell<int>(), 4);
16+
}
17+
18+
{
19+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Read);
20+
21+
uint32_t value;
22+
fileBuffer >> value;
23+
24+
EXPECT_EQ(fileBuffer.Tell<int>(), 4);
25+
EXPECT_EQ(value, expectedValue);
26+
}
27+
}
28+
29+
TEST(dubu_serialize, single_string) {
30+
const char* fileName = "single_string.bin";
31+
std::string expectedValue = "Hello World!";
32+
33+
{
34+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Write);
35+
36+
fileBuffer << expectedValue;
37+
38+
EXPECT_EQ(fileBuffer.Tell<int>(), 16);
39+
}
40+
41+
{
42+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Read);
43+
44+
std::string value;
45+
fileBuffer >> value;
46+
47+
EXPECT_EQ(value, expectedValue);
48+
EXPECT_EQ(fileBuffer.Tell<int>(), 16);
49+
}
50+
}
51+
52+
TEST(dubu_serialize, single_vector_int) {
53+
const char* fileName = "single_vector_int.bin";
54+
std::vector<int> expectedValue{9, 12, 35, 23, 58, 93, 12};
55+
56+
{
57+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Write);
58+
59+
fileBuffer << expectedValue;
60+
61+
EXPECT_EQ(fileBuffer.Tell<int>(), 32);
62+
}
63+
64+
{
65+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Read);
66+
67+
std::vector<int> value;
68+
fileBuffer >> value;
69+
70+
EXPECT_THAT(value, testing::ElementsAreArray(expectedValue));
71+
EXPECT_EQ(fileBuffer.Tell<int>(), 32);
72+
}
73+
}
74+
75+
TEST(dubu_serialize, nested_vector_string) {
76+
const char* fileName = "nested_vector_string.bin";
77+
std::vector<std::vector<std::string>> expectedValue{{"hello", "world"}, {"bye", "world"}};
78+
79+
{
80+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Write);
81+
82+
fileBuffer << expectedValue;
83+
}
84+
85+
{
86+
auto fileBuffer = dubu::serialize::FileBuffer(fileName, dubu::serialize::FileBuffer::Mode::Read);
87+
88+
std::vector<std::vector<std::string>> value;
89+
fileBuffer >> value;
90+
91+
EXPECT_THAT(value, testing::ElementsAreArray(expectedValue));
92+
}
93+
}

0 commit comments

Comments
 (0)