288 lines
6.7 KiB
C++
288 lines
6.7 KiB
C++
|
#include "archiver.h"
|
||
|
#include <iostream>
|
||
|
#include <vector>
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Test1: simple object
|
||
|
|
||
|
struct Student {
|
||
|
Student() : name(), age(), height(), canSwim() {}
|
||
|
Student(const std::string name, unsigned age, double height, bool canSwim) :
|
||
|
name(name), age(age), height(height), canSwim(canSwim)
|
||
|
{}
|
||
|
|
||
|
std::string name;
|
||
|
unsigned age;
|
||
|
double height;
|
||
|
bool canSwim;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Student& s) {
|
||
|
ar.StartObject();
|
||
|
ar.Member("name") & s.name;
|
||
|
ar.Member("age") & s.age;
|
||
|
ar.Member("height") & s.height;
|
||
|
ar.Member("canSwim") & s.canSwim;
|
||
|
return ar.EndObject();
|
||
|
}
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& os, const Student& s) {
|
||
|
return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim;
|
||
|
}
|
||
|
|
||
|
void test1() {
|
||
|
std::string json;
|
||
|
|
||
|
// Serialize
|
||
|
{
|
||
|
Student s("Lua", 9, 150.5, true);
|
||
|
|
||
|
JsonWriter writer;
|
||
|
writer & s;
|
||
|
json = writer.GetString();
|
||
|
std::cout << json << std::endl;
|
||
|
}
|
||
|
|
||
|
// Deserialize
|
||
|
{
|
||
|
Student s;
|
||
|
JsonReader reader(json.c_str());
|
||
|
reader & s;
|
||
|
std::cout << s << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Test2: std::vector <=> JSON array
|
||
|
//
|
||
|
// You can map a JSON array to other data structures as well
|
||
|
|
||
|
struct Group {
|
||
|
Group() : groupName(), students() {}
|
||
|
std::string groupName;
|
||
|
std::vector<Student> students;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Group& g) {
|
||
|
ar.StartObject();
|
||
|
|
||
|
ar.Member("groupName");
|
||
|
ar & g.groupName;
|
||
|
|
||
|
ar.Member("students");
|
||
|
size_t studentCount = g.students.size();
|
||
|
ar.StartArray(&studentCount);
|
||
|
if (ar.IsReader)
|
||
|
g.students.resize(studentCount);
|
||
|
for (size_t i = 0; i < studentCount; i++)
|
||
|
ar & g.students[i];
|
||
|
ar.EndArray();
|
||
|
|
||
|
return ar.EndObject();
|
||
|
}
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& os, const Group& g) {
|
||
|
os << g.groupName << std::endl;
|
||
|
for (std::vector<Student>::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr)
|
||
|
os << *itr << std::endl;
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
void test2() {
|
||
|
std::string json;
|
||
|
|
||
|
// Serialize
|
||
|
{
|
||
|
Group g;
|
||
|
g.groupName = "Rainbow";
|
||
|
|
||
|
Student s1("Lua", 9, 150.5, true);
|
||
|
Student s2("Mio", 7, 120.0, false);
|
||
|
g.students.push_back(s1);
|
||
|
g.students.push_back(s2);
|
||
|
|
||
|
JsonWriter writer;
|
||
|
writer & g;
|
||
|
json = writer.GetString();
|
||
|
std::cout << json << std::endl;
|
||
|
}
|
||
|
|
||
|
// Deserialize
|
||
|
{
|
||
|
Group g;
|
||
|
JsonReader reader(json.c_str());
|
||
|
reader & g;
|
||
|
std::cout << g << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// Test3: polymorphism & friend
|
||
|
//
|
||
|
// Note that friendship is not necessary but make things simpler.
|
||
|
|
||
|
class Shape {
|
||
|
public:
|
||
|
virtual ~Shape() {}
|
||
|
virtual const char* GetType() const = 0;
|
||
|
virtual void Print(std::ostream& os) const = 0;
|
||
|
|
||
|
protected:
|
||
|
Shape() : x_(), y_() {}
|
||
|
Shape(double x, double y) : x_(x), y_(y) {}
|
||
|
|
||
|
template <typename Archiver>
|
||
|
friend Archiver& operator&(Archiver& ar, Shape& s);
|
||
|
|
||
|
double x_, y_;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Shape& s) {
|
||
|
ar.Member("x") & s.x_;
|
||
|
ar.Member("y") & s.y_;
|
||
|
return ar;
|
||
|
}
|
||
|
|
||
|
class Circle : public Shape {
|
||
|
public:
|
||
|
Circle() : radius_() {}
|
||
|
Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {}
|
||
|
~Circle() {}
|
||
|
|
||
|
const char* GetType() const { return "Circle"; }
|
||
|
|
||
|
void Print(std::ostream& os) const {
|
||
|
os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
template <typename Archiver>
|
||
|
friend Archiver& operator&(Archiver& ar, Circle& c);
|
||
|
|
||
|
double radius_;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Circle& c) {
|
||
|
ar & static_cast<Shape&>(c);
|
||
|
ar.Member("radius") & c.radius_;
|
||
|
return ar;
|
||
|
}
|
||
|
|
||
|
class Box : public Shape {
|
||
|
public:
|
||
|
Box() : width_(), height_() {}
|
||
|
Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {}
|
||
|
~Box() {}
|
||
|
|
||
|
const char* GetType() const { return "Box"; }
|
||
|
|
||
|
void Print(std::ostream& os) const {
|
||
|
os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
template <typename Archiver>
|
||
|
friend Archiver& operator&(Archiver& ar, Box& b);
|
||
|
|
||
|
double width_, height_;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Box& b) {
|
||
|
ar & static_cast<Shape&>(b);
|
||
|
ar.Member("width") & b.width_;
|
||
|
ar.Member("height") & b.height_;
|
||
|
return ar;
|
||
|
}
|
||
|
|
||
|
class Canvas {
|
||
|
public:
|
||
|
Canvas() : shapes_() {}
|
||
|
~Canvas() { Clear(); }
|
||
|
|
||
|
void Clear() {
|
||
|
for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr)
|
||
|
delete *itr;
|
||
|
}
|
||
|
|
||
|
void AddShape(Shape* shape) { shapes_.push_back(shape); }
|
||
|
|
||
|
void Print(std::ostream& os) {
|
||
|
for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) {
|
||
|
(*itr)->Print(os);
|
||
|
std::cout << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
template <typename Archiver>
|
||
|
friend Archiver& operator&(Archiver& ar, Canvas& c);
|
||
|
|
||
|
std::vector<Shape*> shapes_;
|
||
|
};
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Shape*& shape) {
|
||
|
std::string type = ar.IsReader ? "" : shape->GetType();
|
||
|
ar.StartObject();
|
||
|
ar.Member("type") & type;
|
||
|
if (type == "Circle") {
|
||
|
if (ar.IsReader) shape = new Circle;
|
||
|
ar & static_cast<Circle&>(*shape);
|
||
|
}
|
||
|
else if (type == "Box") {
|
||
|
if (ar.IsReader) shape = new Box;
|
||
|
ar & static_cast<Box&>(*shape);
|
||
|
}
|
||
|
return ar.EndObject();
|
||
|
}
|
||
|
|
||
|
template <typename Archiver>
|
||
|
Archiver& operator&(Archiver& ar, Canvas& c) {
|
||
|
size_t shapeCount = c.shapes_.size();
|
||
|
ar.StartArray(&shapeCount);
|
||
|
if (ar.IsReader) {
|
||
|
c.Clear();
|
||
|
c.shapes_.resize(shapeCount);
|
||
|
}
|
||
|
for (size_t i = 0; i < shapeCount; i++)
|
||
|
ar & c.shapes_[i];
|
||
|
return ar.EndArray();
|
||
|
}
|
||
|
|
||
|
void test3() {
|
||
|
std::string json;
|
||
|
|
||
|
// Serialize
|
||
|
{
|
||
|
Canvas c;
|
||
|
c.AddShape(new Circle(1.0, 2.0, 3.0));
|
||
|
c.AddShape(new Box(4.0, 5.0, 6.0, 7.0));
|
||
|
|
||
|
JsonWriter writer;
|
||
|
writer & c;
|
||
|
json = writer.GetString();
|
||
|
std::cout << json << std::endl;
|
||
|
}
|
||
|
|
||
|
// Deserialize
|
||
|
{
|
||
|
Canvas c;
|
||
|
JsonReader reader(json.c_str());
|
||
|
reader & c;
|
||
|
c.Print(std::cout);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int main() {
|
||
|
test1();
|
||
|
test2();
|
||
|
test3();
|
||
|
}
|