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();
 | |
| }
 |