Skip to content

Commit

Permalink
ADDED: load method and added print_diff
Browse files Browse the repository at this point in the history
  • Loading branch information
KonanM committed Feb 4, 2021
1 parent 34a577a commit 9a2e5ca
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 12 deletions.
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,15 @@ Feel free to grab the [base64_encoding.hpp](https://github.com/KonanM/tser/blob/
```cpp
void test()
{
tser::BinaryArchive ba2("BggBUg");
auto loadedRobot = ba2.load<Robot>();
//if we construct BinaryArchive with a string it will decode it and initialized it's internal buffer with it
//alternatively you can use tser::load to directly load an object
auto loadedRobot = tser::load<Robot>("BggBUg");
auto robot = Robot{ Point{3,4}, Item::RADAR };
//all the comparision operators are implemented, so I could directly use std::set<Robot>
bool areEqual = (robot == loadedRobot) && !(robot != loadedRobot) && !(robot < loadedRobot);
(void)areEqual;
std::cout << loadedRobot; //prints{ "Robot": {"point" : { "Point": {"x" : 3, "y" : 4}}, "item" : R} }
std::cout << loadedRobot; //prints { "Robot": {"point" : { "Point": {"x" : 3, "y" : 4}}, "item" : "R"} }
}
```

Expand Down Expand Up @@ -272,6 +273,12 @@ int main()
}
```
## Can I print differences between classes of the same type?
For now it is a feature that I'm not sure if I should make it part of the main library. You can find it here [print_diff.hpp](https://github.com/KonanM/tser/tree/master/test/print_diff.hpp).
It ```tser::print_diff(o1,o2);``` only prints the differing parts of the objects, it would be good if I could get some feedback if this should be improved.
## How does it work?
Internally the macro exposes a tuple of the members and the name of the members. It would also be possible to implement this manually for every type.
Expand Down Expand Up @@ -300,7 +307,7 @@ If you are using CMake >= 3.11 you can also use FetchContent to download and use
FetchContent_Declare(
tser
GIT_REPOSITORY https://github.com/KonanM/tser.git
GIT_TAG v1.1
GIT_TAG v1.2
)
FetchContent_MakeAvailable(tser)
target_link_libraries(mylib PRIVATE KonanM::tser)
Expand Down
5 changes: 2 additions & 3 deletions example/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ void test()
{
//if we construct BinaryArchive with a string it will decode it and initialized it's internal buffer with it
//so it's basically one or two lines of code to load a complex object into a test and start using it
tser::BinaryArchive ba2("BggBUg");
auto loadedRobot = ba2.load<Robot>();
auto loadedRobot = tser::load<Robot>("BggBUg");

auto robot = Robot{ x::Point{3,4}, Item::RADAR };
//all the comparision operators are implemented, so I could directly use std::set<Robot>
bool areEqual = (robot == loadedRobot) && !(robot != loadedRobot) && !(robot < loadedRobot);
(void)areEqual;
std::cout << loadedRobot; //prints{ "Robot": {"point" : { "Point": {"x" : 3, "y" : 4}}, "item" : R} }
std::cout << loadedRobot; //prints { "Robot": {"point" : { "Point": {"x" : 3, "y" : 4}}, "item" : "R"} }
}
6 changes: 4 additions & 2 deletions include/tser/tser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ namespace tser{
public:
explicit BinaryArchive(const size_t initialSize = 1024) : m_bytes(initialSize, '\0') {}
explicit BinaryArchive(std::string encodedStr) : m_bytes(decode_base64(encodedStr)), m_bufferSize(m_bytes.size()){}
template<typename T>
template<typename T, std::enable_if_t<!std::is_integral_v<T>, int> = 0>
explicit BinaryArchive(const T& t) { save(t); }
template<typename T>
void save(const T& t){
Expand Down Expand Up @@ -231,7 +231,9 @@ namespace tser{
}
};
template<class Base, typename Derived>
std::conditional_t<std::is_const_v<Derived>, const Base, Base>& to_base(Derived* thisPtr) { return *thisPtr; }
std::conditional_t<std::is_const_v<Derived>, const Base, Base>& base(Derived* thisPtr) { return *thisPtr; }
template<typename T>
auto load(std::string_view encoded) { BinaryArchive ba(encoded); return ba.load<T>(); }
}
//this macro defines printing, serialisation and comparision operators (==,!=,<) for custom types
#define DEFINE_SERIALIZABLE(Type, ...) \
Expand Down
6 changes: 4 additions & 2 deletions single_header/tser/tser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ namespace tser{
public:
explicit BinaryArchive(const size_t initialSize = 1024) : m_bytes(initialSize, '\0') {}
explicit BinaryArchive(std::string encodedStr) : m_bytes(decode_base64(encodedStr)), m_bufferSize(m_bytes.size()){}
template<typename T>
template<typename T, std::enable_if_t<!std::is_integral_v<T>, int> = 0>
explicit BinaryArchive(const T& t) { save(t); }
template<typename T>
void save(const T& t){
Expand Down Expand Up @@ -296,7 +296,9 @@ namespace tser{
}
};
template<class Base, typename Derived>
std::conditional_t<std::is_const_v<Derived>, const Base, Base>& to_base(Derived* thisPtr) { return *thisPtr; }
std::conditional_t<std::is_const_v<Derived>, const Base, Base>& base(Derived* thisPtr) { return *thisPtr; }
template<typename T>
auto load(std::string_view encoded) { BinaryArchive ba(encoded); return ba.load<T>(); }
}
//this macro defines printing, serialisation and comparision operators (==,!=,<) for custom types
#define DEFINE_SERIALIZABLE(Type, ...) \
Expand Down
20 changes: 19 additions & 1 deletion test/SerializeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: BSL-1.0
#include "gtest/gtest.h"
#include "tser/tser.hpp"
#include "print_diff.hpp"

#include <numeric>
#include <optional>
Expand Down Expand Up @@ -228,7 +229,7 @@ TEST(binaryArchive, readPoints)
struct Object : public Point
{
int idx = 0;
DEFINE_SERIALIZABLE(Object, tser::to_base<Point>(this), idx)
DEFINE_SERIALIZABLE(Object, tser::base<Point>(this), idx)
};

TEST(binaryArchive, deriveFromPointTest)
Expand Down Expand Up @@ -403,3 +404,20 @@ TEST(macroSpaces, crazySpace)
{
TestMacroSpaces<MacroCrazySpace>("MacroCrazySpace");
}


struct CompareThem
{
DEFINE_SERIALIZABLE(CompareThem, ints, x, y)
std::array<int, 5> ints{ -1,0,1,2,3 };
int x = 0, y = 0;
};

TEST(print_diff, basic_test)
{
CompareThem a, b;
a.ints[3] = 7;
b.y = 3;
tser::print_diff(a,b, std::cout);

}
68 changes: 68 additions & 0 deletions test/print_diff.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Licensed under the Boost License <https://opensource.org/licenses/BSL-1.0>.
// SPDX-License-Identifier: BSL-1.0
#include "tser/tser.hpp"

#include <string>
#include <ostream>
#include <algorithm>


//if you need deep pointer comparisions you could grab this macro
namespace tser {
template <class T>
void print_diff(const T& lhs, const T& rhs, std::ostream& cerr, const char* typeName = T::_typeName);

template <class T, class Tuple, std::size_t... I>
void print_diffTuple(const Tuple& lhs, const Tuple& rhs, std::ostream& os, std::index_sequence<I...>){
(print_diff(std::get<I>(lhs), std::get<I>(rhs), os, T::_memberNames[I]), ...);
}
template<typename T>
void print_diff(const T& lhs, const T& rhs, std::ostream& os, const char* typeName){
if constexpr (tser::is_container_v<T>){
const bool isEq = std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
if (!isEq){
const size_t lastElem = std::min(lhs.size(), rhs.size());

os << "\n\"" << typeName << "\": \n{";
for (size_t i = 0; i < lastElem; ++i) {
if (lhs[i] != rhs[i]) {
std::string idx = "[" + std::to_string(i) + "]:";
print_diff(lhs[i], rhs[i], os, idx.c_str());
os << '\n';
}
}
if (lhs.size() > rhs.size()) {
os << " Additional element(s) in first type detected! \n";
for (size_t i = lastElem; i < lhs.size(); ++i) {
os << lhs[i] << '\n';
}
}
else if (rhs.size() > lhs.size()) {
os << " Additional element(s) in second type detected! \n";
for (size_t i = lastElem; i < rhs.size(); ++i) {
os << rhs[i] << '\n';
}
}
os << "}\n";
}
}
else if constexpr (tser::is_tser_t_v<T>) {
if (lhs != rhs)
{
os << '\"' << typeName << "\": {";
print_diffTuple<T>(lhs.members(), rhs.members(), os, std::make_index_sequence<std::tuple_size_v<std::decay_t<decltype(lhs.members())>>>());
os << "}";
}
}
else if constexpr (tser::is_pointer_like_v<T>) {
if (lhs && rhs)
print_diff(*lhs, *rhs, os, typeName);
else if (lhs && !rhs)
os << "\"" << typeName << "\": (" << lhs << "/ null )";
else if (rhs && !lhs)
os << "\"" << typeName << "\": ( null /" << rhs << ")";
}
else if (lhs != rhs)
os << '\"' << typeName << "\": (" << lhs << "/" << rhs << ")";
}
}

0 comments on commit 9a2e5ca

Please sign in to comment.