Newer
Older
WickedDocs / Serializing / test.cpp
#include <type_traits>
#include <cstdint>
#include <cctype>
#include <vector>
#include <string>
#include <cstring>
#include <cstdlib>


template<typename T>
using Array     = std::vector<T>;
using String    = std::string;
using Integer32 = int32_t;


template <class V>
void Visit(V& v, Integer32& i)
{
  v.Visit(i);
}

template <class V>
void Visit(V& v, String& str)
{
  v.Visit(str);
}

template <class V, class T>
void Visit(V& v, Array<T>& arr)
{
  v.Visit(arr);
}

template <class V, class T>
void Visit(V& v, const char* name, T& var)
{
  v.Enter(name);
  var.Visit(v);
  v.Exit(name);
}


class XMLSerializerVisitor
{
public:
  void Enter(const char* name)
  {
    indent(depth);
    output += "<";
    output += name;
    output += ">\n";
    depth++;
  }

  void Exit(const char* name)
  {
    depth--;
    indent(depth);
    output += "</";
    output += name;
    output += ">\n";
  }

  template <class T>
  void Visit(Array<T>& arr)
  {
    Integer32 siz = arr.size();
    Visit("length", siz);
    for (int i = 0; i < arr.size(); i++)
    {
      char buf[1024];
      snprintf(buf, 1024, "element[%i]", i);
      Visit(buf, arr.at(i));
    }
  }

  void Visit(Integer32& var)
  {
    indent(depth);
    output += std::to_string(var);
    output += "\n";
  }

  void Visit(String& var)
  {
    // TODO: limitiation is that the string can not have a new line
    indent(depth);
    output += var;
    output += "\n";
  }

  template <class T>
  void Visit(const char* name, T& var)
  {
    Enter(name);
    ::Visit(*this, var);
    Exit(name);
  }

  std::string& Output()
  {
    return output;
  }
  void reset()
  {
    output = "";
    depth = 0;
  }
private:
  int depth = 0;
  std::string output;
  
  void indent(int spaces)
  {
    for(int i = 0; i < spaces; i++)
    {
      output += "  ";
    }
  }
};



class XMLDeserializerVisitor
{
public:
  XMLDeserializerVisitor(std::string data) : input(data) {}

  void Enter(const char* name)
  {
    String str;
    Visit(str);
    //printf("enter deserializing for -%s-, got -%s-\n", name, str.c_str());
  }
  void Exit(const char* name)
  {
    String str;
    Visit(str);
    //printf("exit deserializing for -%s-, got -%s-\n", name, str.c_str());
  }

  template <class T>
  void Visit(Array<T>& arr)
  {
    Integer32 siz = 0;
    Visit("length", siz);
    arr.resize(siz);
    //printf("deserializing array of len: %i\n", siz);
    for (int i = 0; i < arr.size(); i++)
    {
      char buf[1024];
      snprintf(buf, 1024, "element[%i]", i);
      Visit(buf, arr.at(i));
    }
  }

  void Visit(Integer32& var)
  {
    const char* ptr = input.c_str();
    char* endPtr;
    var = strtol(ptr + offset, &endPtr, 10);
    offset = endPtr - ptr;
  }

  void Visit(String& var)
  {
    stripWhiteSpace();
    int newLineOff = input.find("\n", offset);
    var = input.substr(offset, newLineOff-offset);
    offset = newLineOff;
  }

  template <class T>
  void Visit(const char* name, T& var)
  {
    Enter(name);
    ::Visit(*this, var);
    Exit(name);
  }

private:
  std::string input;
  int offset = 0;
  void stripWhiteSpace()
  {
    while (isspace(input.c_str()[offset]))
    {
        offset++;
    }
  }
};




struct Person
{
  Integer32      id;
  String         name;
  Array<String>  email;
  Array<String>  phoneNumbers;

  // This can do both the serializing and de-serializing
  // This might be good to have generated, but possibly being more explicit could be better too
  // Also note the members could be private and this will still work
  template <class V>
  void Visit(V& v)
  {
    v.Visit("id",id);
    v.Visit("name",name);
    v.Visit("email",email);
    v.Visit("numbers",phoneNumbers);
  }
};





int main(int argc, char* argv[])
{
  std::string input;

  {  
    Person a;
    a.id = 10;
    a.name = "blah";
    a.email.push_back("em@ail.com");
    a.email.push_back("other@add.com");
    a.phoneNumbers.push_back("123555");

    XMLSerializerVisitor serializer;
    Visit(serializer, "personA", a);
    printf("%s", serializer.Output().c_str());
    input = serializer.Output();
  }

  {
    Person b;

    XMLDeserializerVisitor deserializer(input);
    Visit(deserializer, "personB", b);

    {
      XMLSerializerVisitor serializer;
      Visit(serializer, "personB", b);
      printf("%s", serializer.Output().c_str());
    }
  }
}