initial implementation
This commit is contained in:
commit
effbbf22d9
9 changed files with 798 additions and 0 deletions
99
include/xo/printjson/JsonPrinter.hpp
Normal file
99
include/xo/printjson/JsonPrinter.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* @file JsonPrinter.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
#include "xo/reflect/TypeDrivenMap.hpp"
|
||||
#include "xo/reflect/TaggedPtr.hpp"
|
||||
//#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace json {
|
||||
class PrintJson;
|
||||
|
||||
class JsonPrinter {
|
||||
public:
|
||||
using Reflect = xo::reflect::Reflect;
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
|
||||
public:
|
||||
JsonPrinter(PrintJson const * pjson) : pjson_{pjson} {}
|
||||
virtual ~JsonPrinter() = default;
|
||||
|
||||
PrintJson const * pjson() const { return pjson_; }
|
||||
|
||||
/* print tagged pointer in json format */
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const = 0;
|
||||
|
||||
void report_internal_type_consistency_error(TypeDescr td1,
|
||||
TypeDescr td2,
|
||||
std::ostream * p_os) const;
|
||||
|
||||
/* convenience method for derived printers.
|
||||
* retrieves contents of tp as a T*, complains to *p_os if that fails.
|
||||
*
|
||||
* (Failure would occur if printer for type T was instead installed
|
||||
* for some unrelated type U)
|
||||
*/
|
||||
template<typename T>
|
||||
T * check_recover_native(TaggedPtr tp, std::ostream * p_os) const {
|
||||
T * x = tp.recover_native<T>();
|
||||
|
||||
if (!x) {
|
||||
this->report_internal_type_consistency_error(Reflect::require<T>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
|
||||
return x;
|
||||
} /*check_recover_native*/
|
||||
|
||||
void assign_pjson(PrintJson const * pjson) {
|
||||
assert(this->pjson_ == nullptr || this->pjson_ == pjson);
|
||||
this->pjson_ = pjson;
|
||||
} /*assign_pjson*/
|
||||
|
||||
private:
|
||||
/* a json printers is installed into one PrintJson instance;
|
||||
* capture address of that instance at install time
|
||||
*/
|
||||
PrintJson const * pjson_ = nullptr;
|
||||
}; /*JsonPrinter*/
|
||||
|
||||
/* AsStringJsonPrinter<T>
|
||||
* prints a T-instance by using operator<< and surrounding in quotes.
|
||||
*
|
||||
* e.g:
|
||||
* T & x = ..;
|
||||
* std::ostream * p_os = ..;
|
||||
*
|
||||
* *p_os << "\"" << x << "\""
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
class AsStringJsonPrinter : public JsonPrinter {
|
||||
public:
|
||||
AsStringJsonPrinter(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override
|
||||
{
|
||||
T * x = this->check_recover_native<T>(tp, p_os);
|
||||
|
||||
if(x) {
|
||||
*p_os << "\"" << *x << "\"";
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*AsStringJsonPrinter*/
|
||||
} /*namespace json*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end JsonPrinter.hpp */
|
||||
143
include/xo/printjson/PrintJson.hpp
Normal file
143
include/xo/printjson/PrintJson.hpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* @file JsonPrinter.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonPrinter.hpp"
|
||||
#include "xo/reflect/TypeDrivenMap.hpp"
|
||||
#include "xo/reflect/SelfTagging.hpp"
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace json {
|
||||
class PrintJson : public reflect::SelfTagging {
|
||||
public:
|
||||
using Reflect = xo::reflect::Reflect;
|
||||
using TypeDrivenMap = xo::reflect::TypeDrivenMap<std::unique_ptr<JsonPrinter>>;
|
||||
using SelfTagging = xo::reflect::SelfTagging;
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using TaggedRcptr = xo::reflect::TaggedRcptr;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
|
||||
public:
|
||||
PrintJson();
|
||||
~PrintJson() = default;
|
||||
|
||||
template<typename T>
|
||||
void print(T const & x_arg, std::ostream * p_os) const {
|
||||
T * x = const_cast<T *>(&x_arg);
|
||||
|
||||
this->print_tp(Reflect::make_tp(x), p_os);
|
||||
} /*print*/
|
||||
|
||||
/* print object tp on stream *p_os, in JSON format;
|
||||
*/
|
||||
void print_tp(TaggedPtr tp, std::ostream * p_os) const;
|
||||
|
||||
/* convenience -- shorthand for
|
||||
* .print(obj->self_tp(), p_os)
|
||||
*/
|
||||
void print_obj(ref::rp<SelfTagging> const & obj, std::ostream * p_os) const;
|
||||
|
||||
void provide_printer(TypeId id, std::unique_ptr<JsonPrinter> p) {
|
||||
*(printer_map_.require(id)) = std::move(p);
|
||||
}
|
||||
|
||||
void provide_printer(TypeDescr td, std::unique_ptr<JsonPrinter> p) {
|
||||
this->provide_printer(td->id(), std::move(p));
|
||||
}
|
||||
|
||||
/* write json representation for tp on *p_os */
|
||||
void print_aux(TaggedPtr tp, std::ostream * p_os) const;
|
||||
|
||||
// ----- inherited from SelfTagging -----
|
||||
|
||||
virtual TaggedRcptr self_tp();
|
||||
|
||||
private:
|
||||
/* provide printers for common basic types */
|
||||
void provide_std_printers();
|
||||
|
||||
private:
|
||||
/* map contains specialized printers for specific c++ types */
|
||||
TypeDrivenMap printer_map_;
|
||||
}; /*PrintJson*/
|
||||
|
||||
/* Using singleton here to collect type-specific json printers,
|
||||
* collected during program initialization.
|
||||
*
|
||||
* Could relabel as PrintJsonInitContext if desired
|
||||
*/
|
||||
class PrintJsonSingleton {
|
||||
public:
|
||||
static ref::rp<PrintJson> instance();
|
||||
|
||||
private:
|
||||
/* we don't need this to be stored as pointer.
|
||||
* memory burned if unused will be one empty std::vector<>
|
||||
*/
|
||||
static ref::rp<PrintJson> s_instance;
|
||||
}; /*PrintJsonSingleton*/
|
||||
|
||||
} /*namespace json*/
|
||||
|
||||
#ifdef NOT_USING
|
||||
namespace print {
|
||||
using PrintJson = xo::json::PrintJson;
|
||||
|
||||
/* stream inserter for printing a T-instance in json format */
|
||||
template<typename T>
|
||||
class jsonp_impl {
|
||||
public:
|
||||
jsonp_impl(T const & x, PrintJson const * pjson) : value_(x), pjson_{pjson} {}
|
||||
//jsonp_impl(T const & x, PrintJson const * pjson) : value_{x}, pjson_{pjson} {}
|
||||
//jsonp_impl(T && x, PrintJson const * pjson) : value_(std::move(x)), pjson_{pjson} {}
|
||||
|
||||
void print(std::ostream & os) const {
|
||||
using xo::reflect::Reflect;
|
||||
|
||||
this->pjson_->print_tp(Reflect::make_tp(&value_), &os);
|
||||
} /*print*/
|
||||
|
||||
private:
|
||||
/* value, to be printed, in json format */
|
||||
T value_;
|
||||
/* json printer (bc we don't care for singletons) */
|
||||
PrintJson const * pjson_ = nullptr;
|
||||
}; /*jsonp_impl*/
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
std::ostream & operator<<(std::ostream & os, jsonp_impl<T> const & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
} /*operator<<*/
|
||||
|
||||
/* writing out std::forward<T> behavior for completeness' sake:
|
||||
*
|
||||
* 1. call jsonp(x) with rvalue std::string x, then:
|
||||
* - T will be deduced to [std::string]
|
||||
* (in particular: _not_ std::string &, std::string const &, std::string &&)
|
||||
* - rvalue std::string passed to jsonp_impl ctor
|
||||
*
|
||||
* 2a. call jsonp(x) with std::string & x, then:
|
||||
* - T deduced to [std::string &]
|
||||
* - std::string & passed to jsonp_impl ctor
|
||||
*
|
||||
* 2b. call jsonp(x) with std::string const & x, then:
|
||||
* - T deduced to [std::string const &]
|
||||
* - std::string const & passed to jsonp_impl ctor
|
||||
*/
|
||||
template<typename T>
|
||||
auto jsonp(T && x, PrintJson const * pjson) {
|
||||
return jsonp_impl<T>(std::forward<T>(x), pjson);
|
||||
} /*jsonp*/
|
||||
} /*namespace print*/
|
||||
#endif
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end JsonPrinter.hpp */
|
||||
29
include/xo/printjson/init_printjson.hpp
Normal file
29
include/xo/printjson/init_printjson.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* file init_printjson.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Sep 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/subsys/Subsystem.hpp"
|
||||
|
||||
namespace xo {
|
||||
/* tag to represent the printjson/ subsystem within ordered initialization */
|
||||
enum S_printjson_tag {};
|
||||
|
||||
/* Use:
|
||||
* // anywhere, to declare printjson dependency e.g. at file scope
|
||||
* InitEvidence s_evidence = InitSubsys<S_printjson_tag>::require();
|
||||
*
|
||||
* // from main(), though can resort to module initialization in a pybind11 library
|
||||
* Subsystem::initialize_all();
|
||||
*/
|
||||
template<>
|
||||
struct InitSubsys<S_printjson_tag> {
|
||||
static void init();
|
||||
static InitEvidence require();
|
||||
};
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end init_printjson.hpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue