Skip to content

cojson tutorial for C++17

C++17 has simplified use of template parameters. Instructions, given in this tutorial, describes how to define JSON model with cojson::autos templates.
Note: GCC 7 or higher is required to compile cojson_autos.hpp !

1. Defining Model

JSON model is defined as a template function, with pointers to all serializable members as the template parameters. Everything else - JSON property name, data type, array extents, is deduced from pointer-to-member by cojson::autos templates.
cojson::autos defines two groups of template functions each having its specific purpose and name:

O<class,...>()Object<class, ...>()Defines an object mapped to a C++ class
P<auto,auto>()Property<auto,auto>()Defines an object property,
bound to getter/setter or to an inner object
struct MyClass {
	int Int;
} obj;

O<MyClass,&MyClass::Int>().read(obj, in);

1.1. Objects

Class-bound objects are defined with variadic template O<...> that accepts bounding class as the first parameter followed by the list of member pointers, method pointers or P templates.

1.2. Names

cojson::autos templates deduce names from the identifiers. E.g. member Int will be mapped to JSON property "Int". In a case, when this approach is not suitable, a cojson::P template should be used to define a property with an alternate name.

2. Scalar properties

2.1. Members

A class's member is referred by its pointer to member, e.g. &MyClass::Int

2.2. Methods

A property, mapped to a single getter or setter is referred by its pointer to method, e.g. &MyClass::setLatch. A property, that needs two methods - getter and setter, is defined by cojson::autos::P template, e.g. P<&MyClass::getLatch, &MyClass::setLatch>.

2.3. Immutable String

Immutable zero-terminated strings of unspecified length can be provided:

  1. by a pointer to (const) member of const char*
  2. by a pointer to method returning const char*
  3. by template PropertyStaticString with the class and a pointer to static member of const char*
  4. by template PropertyFunctionString with the class and a pointer to static method returning const char*
struct MyClass {
	const char* const a  = "a";
	const char* b() const noexcept { return "b"; }
	static const char* const c;
	static const char* d() noexcept { return "d"; }
};

O<MyClass, &MyClass::a, &MyClass::b,
	PropertyStaticString<MyClass, &MyClass::c>,
	PropertyFunctionString<MyClass, &MyClass::d>
>();

2.4. Mutable String Members

Mutable strings can be bound to

  1. a string of predefined capacity (char[N]) by a pointer to member.
  2. std::string by a pointer to member.
#include <string>
#include <cojson_stdlib.hpp> //support for std::string properties
struct MyClass {
	char msg[32];
	std::string str;
};
O<MyClass, &MyClass::msg,  &MyClass::str>();

3. Nested Objects

Nested objects are mapped to a member of a class that has its own json model by using P template with pointer to member and pointer to method or function returning its model.

struct Outer {
	bool Bool;
    struct Inner {
        int Int;
    } obj;
};
O<Outer, &Outer::Bool,
	P<&Outer::obj, O<Outer::Inner, &Outer::Inner::Int>>>();

4. Arrays

4.1. Vectors - arrays of integral values

Vectors are bound by a pointer to member of an array type or std::vector type

#include <vector>
#include <cojson_stdlib.hpp> //support for std::vector properties
struct MyClass {
	int vector[3];
	std::vector<int> stdvect;
};
O<MyClass, &MyClass::vector, &MyClass::stdvect>();

4.2. Strings - arrays of string values

String arrays are bound by a pointer to member of a two-dimensional array type (char[N][M]) or to a std::vector<std::string>

struct MyClass {
	int strings[3][32];
	std::vector<std::string> stdstrings;
};
O<MyClass, &MyClass::strings, &MyClass::stdstrings>();

4.3. Arrays of Objects

Similarly to nested objects, arrays of objects are mapped to an array member (or std::vector) of a class that has its own json model by using P template with pointer to member and pointer to method or function returning its model.

struct Outer {
	bool Bool;
	struct Inner {
		int Int;
	} objs[4];
	std::vector<Inner> Objs;
};
O<Outer, &Outer::Bool, P<&Outer::objs, O<Inner, &Inner:Int>>>();
O<Outer, &Outer::Bool, P<&Outer::Objs, O<Inner, &Inner:Int>>>();

4.4. Lists - arrays of heterogeneous values

cojson is designed to work with a predefined structure and this design imposes certain limitation on arrays - a heterogeneous array (ordered list) must have each of its item defined, fixed to a given type and bound to a given member. A list is defined with PropertyList template.

struct MyClass {
	int list;
	bool next;
	char last[32];
};
Object<MyClass, PropertyList<&MyClass::list, &MyClass::next, &MyClass::last>>();
This will correspond to the following json:
{"list":[0, false, ""]}

5. Reading/Writing

5.1. Via std::iostream or similar

cojson::wrapper namespace provides template wrappers for C++ streams: istream and ostream, for reading and writing respectively. They require the wrapped streams to provide get(char) good() eof() / put(char) good() and can wrap almost any of the stdlib streams.

struct MyClass {
	int Int;
} obj;
cojson::wrapper::istream<std::istream> in(cin);
cojson::wrapper::ostream<std::ostream> out(cout);

O<MyClass,&MyClass::Int>().read(obj, in);
O<MyClass,&MyClass::Int>().write(obj, out);

5.2. With operator<<  operator>>

cojson::operator namespace provides template operators operator<< / operator>>. These templates require the class to implement either json() method or read(cojson::details::lexer&)/write(cojson::details::ostream&)

#include <cojson_stdlib.hpp>
using namespace std;
using namespace cojson;
using namespace cojson::autos;
using namespace cojson::operators;

struct MyClass {
	int Int;
	static inline const auto& json() noexcept { 
		return O<MyClass,&MyClass::Int>();
	}
} obj;

cin >> obj;
cout << obj << endl;

5.3. Via a memory buffer

cojson::wrapper namespace provides wrappers for memory buffers: buffer and memstream. Both read from and write to a single memory block. memstream maintains two separate position pointers while buffer maintains only one. When no writing is needed, buffer may by supplied with a constant zero-delimited string.

#include <cojson_stdlib.hpp>
using namespace cojson;
using namespace cojson::autos;
struct Pdo {
	int Int;
	static inline const auto& json() noexcept {
		return O<Pdo,&Pdo::Int>();
	}
	inline int read(const char* data) noexcept {
		wrapper::buffer input(data);
		details::lexer in(input);
		return json().read(*this, in) ? input.count() : -1;
	}
	inline int write(char* data, cojson::size_t size) noexcept {
		wrapper::buffer output(data, size);
		return json().write(*this, output) ? output.count() : -1;
	}
};

5.4. Via a user-defined reader/writer

Please refer to COJSON tutorial Section 5.1 and Section 5.2 for details.

6. Additional materials

List of COJSON-related posts

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

*