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