1
0
mirror of https://github.com/paboyle/Grid.git synced 2025-06-10 19:36:56 +01:00

XMLReader implementation and a virtual Reader/Writer template framework.

Test_serialisation has an example of *code* *free* object serialisation
to both ostream and to XML using macro magic.

Implementing TextReader/TextWriter, YAML, JSON etc.. should be trivial
and we can use configure time options to select the default "Reader" typedef.

Present done with

"using XMLPolicy::Reader"

to pick up the default serialisation strategy.
This commit is contained in:
Peter Boyle
2015-08-20 16:21:26 +01:00
parent fdfe194c41
commit ab81a25073
10 changed files with 348 additions and 7 deletions

View File

@ -0,0 +1,100 @@
#ifndef GRID_MACRO_MAGIC_H
#define GRID_MACRO_MAGIC_H
#define strong_inline __attribute__((always_inline)) inline
#ifndef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)>(y)?(y):(x))
#endif
#define GRID_MACRO_FIRST(a, ...) a
#define GRID_MACRO_SECOND(a, b, ...) b
#define GRID_MACRO_EMPTY()
#define GRID_MACRO_EVAL(...) GRID_MACRO_EVAL1024(__VA_ARGS__)
#define GRID_MACRO_EVAL1024(...) GRID_MACRO_EVAL512(GRID_MACRO_EVAL512(__VA_ARGS__))
#define GRID_MACRO_EVAL512(...) GRID_MACRO_EVAL256(GRID_MACRO_EVAL256(__VA_ARGS__))
#define GRID_MACRO_EVAL256(...) GRID_MACRO_EVAL128(GRID_MACRO_EVAL128(__VA_ARGS__))
#define GRID_MACRO_EVAL128(...) GRID_MACRO_EVAL64(GRID_MACRO_EVAL64(__VA_ARGS__))
#define GRID_MACRO_EVAL64(...) GRID_MACRO_EVAL32(GRID_MACRO_EVAL32(__VA_ARGS__))
#define GRID_MACRO_EVAL32(...) GRID_MACRO_EVAL16(GRID_MACRO_EVAL16(__VA_ARGS__))
#define GRID_MACRO_EVAL16(...) GRID_MACRO_EVAL8(GRID_MACRO_EVAL8(__VA_ARGS__))
#define GRID_MACRO_EVAL8(...) GRID_MACRO_EVAL4(GRID_MACRO_EVAL4(__VA_ARGS__))
#define GRID_MACRO_EVAL4(...) GRID_MACRO_EVAL2(GRID_MACRO_EVAL2(__VA_ARGS__))
#define GRID_MACRO_EVAL2(...) GRID_MACRO_EVAL1(GRID_MACRO_EVAL1(__VA_ARGS__))
#define GRID_MACRO_EVAL1(...) __VA_ARGS__
#define GRID_MACRO_DEFER1(m) m GRID_MACRO_EMPTY()
#define GRID_MACRO_DEFER2(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()
#define GRID_MACRO_DEFER3(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()()
#define GRID_MACRO_DEFER4(m) m GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY GRID_MACRO_EMPTY()()()()
#define GRID_MACRO_IS_PROBE(...) GRID_MACRO_SECOND(__VA_ARGS__, 0)
#define GRID_MACRO_PROBE() ~, 1
#define GRID_MACRO_CAT(a,b) a ## b
#define GRID_MACRO_NOT(x) GRID_MACRO_IS_PROBE(GRID_MACRO_CAT(_GRID_MACRO_NOT_, x))
#define _GRID_MACRO_NOT_0 GRID_MACRO_PROBE()
#define GRID_MACRO_BOOL(x) GRID_MACRO_NOT(GRID_MACRO_NOT(x))
#define GRID_MACRO_IF_ELSE(condition) _GRID_MACRO_IF_ELSE(GRID_MACRO_BOOL(condition))
#define _GRID_MACRO_IF_ELSE(condition) GRID_MACRO_CAT(_GRID_MACRO_IF_, condition)
#define _GRID_MACRO_IF_1(...) __VA_ARGS__ _GRID_MACRO_IF_1_ELSE
#define _GRID_MACRO_IF_0(...) _GRID_MACRO_IF_0_ELSE
#define _GRID_MACRO_IF_1_ELSE(...)
#define _GRID_MACRO_IF_0_ELSE(...) __VA_ARGS__
#define GRID_MACRO_HAS_ARGS(...) GRID_MACRO_BOOL(GRID_MACRO_FIRST(_GRID_MACRO_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _GRID_MACRO_END_OF_ARGUMENTS_() 0
#define GRID_MACRO_MAP(m, first, second, ...) \
m(first,second) \
GRID_MACRO_IF_ELSE(GRID_MACRO_HAS_ARGS(__VA_ARGS__))( \
GRID_MACRO_DEFER4(_GRID_MACRO_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _GRID_MACRO_MAP() GRID_MACRO_MAP
#define GRID_MACRO_MEMBER(A,B) A B;
#define GRID_MACRO_OS_WRITE_MEMBER(A,B) os<< #A <<" "#B <<" = "<< obj. B <<" ; " <<std::endl;
#define GRID_MACRO_READ_MEMBER(A,B) read(RD,#B,obj. B);
#define GRID_MACRO_WRITE_MEMBER(A,B) write(WR,#B,obj. B);
#define GRID_DECL_CLASS_MEMBERS(cname,...) \
\
\
GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_MEMBER,__VA_ARGS__)) \
\
\
template<class Writer> friend void write(Writer &WR,const std::string &s, const cname &obj){ \
push(WR,s);\
GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_WRITE_MEMBER,__VA_ARGS__)) \
pop(WR);\
} \
\
\
template<class Reader> friend void read(Reader &RD,const std::string &s, cname &obj){ \
push(RD,s);\
GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_READ_MEMBER,__VA_ARGS__)) \
pop(RD);\
} \
\
\
friend std::ostream & operator << (std::ostream &os, const cname &obj ) { \
os<<"class "<<#cname<<" {"<<std::endl;\
GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_OS_WRITE_MEMBER,__VA_ARGS__)) \
os<<"}"; \
return os;\
};
#endif

View File

@ -0,0 +1,81 @@
#ifndef GRID_SERIALISATION_READER_H
#define GRID_SERIALISATION_READER_H
#include <serialisation/MacroMagic.h>
namespace Grid {
// Generic reader writer interface
template< class Writer> void push(Writer & WR,const std::string &s) { WR.push(s);}
template< class Writer> void push(Writer & WR,const char *s) { WR.push(std::string(s));}
template< class Writer> void pop (Writer & WR) { WR.pop();}
template< class Writer> void write(Writer& wr, const std::string& s,const char * output ) { wr.iwrite(s,std::string(output)); };
template< class Writer> void write(Writer& wr, const std::string& s,const std::string &output) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, int16_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, uint16_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, int32_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, uint32_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, int64_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, uint64_t output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, float output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, double output ) { wr.iwrite(s,output); };
template< class Writer> void write(Writer& wr, const std::string& s, bool output ) { wr.iwrite(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s,std::string &output) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, int16_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, uint16_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, int32_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, uint32_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, int64_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, uint64_t &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, float &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, double &output ) { rd.iread(s,output); };
template< class Reader> void read(Reader& rd, const std::string& s, bool &output ) { rd.iread(s,output); };
template<class Writer, class T>
void write(Writer& wr, const std::string& s,const std::vector<T> output ) {
push(wr,s);
for(int i=0;i<output.size();i++){
std::ostringstream oss; oss << "elem" << i;
write(wr,oss.str(),output[i]);
}
pop(wr);
};
template<class Reader, class T>
void read(Reader& rd, const std::string& s,std::vector<T> &output ) {
rd.iread(s,output);
};
template < class T >
inline std::ostream& operator << (std::ostream& os, const std::vector<T>& v)
{
os << "[";
for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
{
os << " " << *ii;
}
os << " ]";
return os;
}
}
// Todo:
//#include <serialisation/CoutReader.h>
//#include <serialisation/TextReader.h>
//#include <serialisation/JSONReader.h>
//#include <serialisation/YAMLReader.h>
#include <serialisation/XMLReader.h>
namespace Grid {
using XMLPolicy::Reader;
using XMLPolicy::Writer;
}
#endif

View File

@ -0,0 +1,168 @@
#ifndef GRID_SERIALISATION_XML_READER_H
#define GRID_SERIALISATION_XML_READER_H
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <math.h>
#include <vector>
#include <cassert>
#include "pugixml/pugixml.h"
namespace Grid {
class XMLWriter {
private:
pugi::xml_document doc;
pugi::xml_node node;
std::string file;
public:
XMLWriter(const std::string &_file) : file(_file)
{
node=doc.append_child();
node.set_name("document");
}
~XMLWriter()
{
// simple_walker walker;
// doc.traverse(walker);
doc.save_file(file.c_str()," ");
}
void push(const std::string &s)
{
node = node.append_child(s.c_str());
}
void pop(void) {
node = node.parent();
}
void iwrite( const std::string& s,const std::string &output ) {
pugi::xml_node leaf=node.append_child(s.c_str());
leaf.append_child(pugi::node_pcdata).set_value(output.c_str());
};
void iwrite( const std::string& s, int16_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, uint16_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, int32_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, uint32_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, int64_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, uint64_t output ) { writeInternal(s,output); };
void iwrite( const std::string& s, float output ) { writeInternal(s,output); };
void iwrite( const std::string& s, double output ) { writeInternal(s,output); };
void iwrite( const std::string& s, bool output ) { writeInternal(s,output); };
private:
template<class T> void writeInternal( const std::string& s, T output ){
std::ostringstream os;
os << std::boolalpha << output;
iwrite(s,os.str());
}
};
class XMLReader {
private:
pugi::xml_document doc;
pugi::xml_node node;
public:
XMLReader(const std::string &_file)
{
pugi::xml_parse_result result = doc.load_file(_file.c_str());
if ( !result ) {
std::cout << "XML error description: " << result.description() << "\n";
std::cout << "XML error offset: " << result.offset << "\n";
}
assert(result);
// simple_walker walker;
// doc.traverse(walker);
node= doc.child("document");
}
~XMLReader()
{
}
void iread( const std::string& s,std::string &output ) {
output=node.child(s.c_str()).first_child().value();
};
void push(const std::string &s)
{
node = node.child(s.c_str());
}
void pop(void) {
node = node.parent();
}
template<class T>
void iread( const std::string& s, std::vector<T> &output ) {
output.resize(0);
T tmp;
push(s);
int i=0;
for(pugi::xml_node it=node.first_child(); it; it = it.next_sibling() ){
std::ostringstream oss; oss << "elem" << i;
read(*this,oss.str(),tmp);
output.push_back(tmp);
i++;
}
pop();
};
void iread( const std::string& s, int16_t &output ) { readInternal(s,output); };
void iread( const std::string& s, uint16_t &output ) { readInternal(s,output); };
void iread( const std::string& s, int32_t &output ) { readInternal(s,output); };
void iread( const std::string& s, uint32_t &output ) { readInternal(s,output); };
void iread( const std::string& s, int64_t &output ) { readInternal(s,output); };
void iread( const std::string& s, uint64_t &output ) { readInternal(s,output); };
void iread( const std::string& s, float &output ) { readInternal(s,output); };
void iread( const std::string& s, double &output ) { readInternal(s,output); };
void iread( const std::string& s, bool &output ) { readInternal(s,output); };
private:
template<class T> void readInternal( const std::string& path, T &output ){
std::string asString;
iread(path,asString);
convert(asString,output);
}
template<class T> void convert(const std::string &asString,T &output)
{
std::istringstream is(asString); is.exceptions(std::ios::failbit);
try {
is >> std::boolalpha >> output;
} catch(std::istringstream::failure e) {
std::cerr << "XML read failure on "<<" "<<asString<<" "<<typeid(T).name()<<std::endl;
}
assert( is.tellg()==-1);
}
};
namespace XMLPolicy
{
typedef XMLReader Reader;
typedef XMLWriter Writer;
};
}
#endif