From 18c00718f6d1e4c04914219d9568ce6130bc8fe8 Mon Sep 17 00:00:00 2001 From: Patrick Brosi Date: Thu, 9 Aug 2018 19:33:20 +0200 Subject: [PATCH] add util/json to repo --- src/util/json/Writer.cpp | 173 +++++++++++++++++++++++++++++++++++++++ src/util/json/Writer.h | 108 ++++++++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 src/util/json/Writer.cpp create mode 100644 src/util/json/Writer.h diff --git a/src/util/json/Writer.cpp b/src/util/json/Writer.cpp new file mode 100644 index 0000000..ee65753 --- /dev/null +++ b/src/util/json/Writer.cpp @@ -0,0 +1,173 @@ +// Copyright 2018, University of Freiburg, +// Chair of Algorithms and Data Structures. +// Authors: Patrick Brosi + +#include +#include "Writer.h" +#include "util/String.h" +using namespace util; +using namespace json; + +using std::ostream; +using std::string; +using std::map; + +// _____________________________________________________________________________ +Writer::Writer(std::ostream* out) + : _out(out), _pretty(false), _indent(2), _floatPrec(10) {} + +// _____________________________________________________________________________ +Writer::Writer(std::ostream* out, size_t prec) + : _out(out), _pretty(false), _indent(2), _floatPrec(prec) {} + +// _____________________________________________________________________________ +Writer::Writer(std::ostream* out, size_t prec, bool pret) + : _out(out), _pretty(pret), _indent(2), _floatPrec(prec) {} + +// _____________________________________________________________________________ +Writer::Writer(std::ostream* out, size_t prec, bool pret, size_t indent) + : _out(out), _pretty(pret), _indent(indent), _floatPrec(prec) {} + +// _____________________________________________________________________________ +void Writer::obj() { + if (!_stack.empty() && _stack.top().type == OBJ) + throw WriterException("Object not allowed as key"); + if (!_stack.empty() && _stack.top().type == KEY) _stack.pop(); + if (!_stack.empty() && _stack.top().type == ARR) valCheck(); + if (_stack.size() && _stack.top().type == ARR) prettor(); + *_out << "{"; + _stack.push({OBJ, 1}); +} + +// _____________________________________________________________________________ +void Writer::key(const std::string& k) { + if (_stack.empty() || _stack.top().type != OBJ) + throw WriterException("Keys only allowed in objects."); + if (!_stack.top().empty) (*_out) << "," << (_pretty ? " " : ""); + _stack.top().empty = 0; + prettor(); + *_out << "\"" << k << "\"" + << ":" << (_pretty ? " " : ""); + _stack.push({KEY, 1}); +} + +// _____________________________________________________________________________ +void Writer::valCheck() { + if (_stack.empty() || (_stack.top().type != KEY && _stack.top().type != ARR)) + throw WriterException("Value not allowed here."); + if (!_stack.empty() && _stack.top().type == KEY) _stack.pop(); + if (!_stack.empty() && _stack.top().type == ARR) { + if (!_stack.top().empty) (*_out) << "," << (_pretty ? " " : ""); + _stack.top().empty = 0; + } +} + +// _____________________________________________________________________________ +void Writer::val(const std::string& v) { + valCheck(); + *_out << "\"" << util::jsonStringEscape(v) << "\""; +} + +// _____________________________________________________________________________ +void Writer::val(const char* v) { + valCheck(); + *_out << "\"" << util::jsonStringEscape(v) << "\""; +} + +// _____________________________________________________________________________ +void Writer::val(bool v) { + valCheck(); + *_out << (v ? "true" : "false"); +} + +// _____________________________________________________________________________ +void Writer::val(int v) { + valCheck(); + *_out << v; +} + +// _____________________________________________________________________________ +void Writer::val(double v) { + valCheck(); + *_out << std::fixed << std::setprecision(_floatPrec) << v; +} + +// _____________________________________________________________________________ +void Writer::val(Null) { + valCheck(); + *_out << "null"; +} + +// _____________________________________________________________________________ +void Writer::val(const Val& v) { + switch (v.type) { + case Val::JSNULL: + val(Null()); + return; + case Val::INT: + val(v.i); + return; + case Val::FLOAT: + val(v.f); + return; + case Val::BOOL: + val((bool)v.i); + return; + case Val::STRING: + val(v.str); + return; + case Val::ARRAY: + arr(); + for (const Val& varr : v.arr) val(varr); + close(); + return; + case Val::DICT: + obj(); + for (const auto& vdic : v.dict) { + keyVal(vdic.first, vdic.second); + }; + close(); + return; + } +} + +// _____________________________________________________________________________ +void Writer::arr() { + if (!_stack.empty() && _stack.top().type == OBJ) + throw WriterException("Array not allowed as key"); + if (!_stack.empty() && _stack.top().type == KEY) _stack.pop(); + if (!_stack.empty() && _stack.top().type == ARR) valCheck(); + *_out << "["; + _stack.push({ARR, 1}); +} + +// _____________________________________________________________________________ +void Writer::prettor() { + if (_pretty) { + *_out << "\n"; + for (size_t i = 0; i < _indent * _stack.size(); i++) (*_out) << " "; + } +} + +// _____________________________________________________________________________ +void Writer::closeAll() { + while (!_stack.empty()) close(); +} + +// _____________________________________________________________________________ +void Writer::close() { + if (_stack.empty()) return; + switch (_stack.top().type) { + case OBJ: + _stack.pop(); + prettor(); + (*_out) << "}"; + break; + case ARR: + _stack.pop(); + (*_out) << "]"; + break; + case KEY: + throw WriterException("Missing value."); + } +} diff --git a/src/util/json/Writer.h b/src/util/json/Writer.h new file mode 100644 index 0000000..0a9948d --- /dev/null +++ b/src/util/json/Writer.h @@ -0,0 +1,108 @@ +// Copyright 2018, University of Freiburg, +// Chair of Algorithms and Data Structures. +// Authors: Patrick Brosi + +#ifndef UTIL_JSON_WRITER_H_ +#define UTIL_JSON_WRITER_H_ + +#include +#include +#include +#include +#include + +namespace util { +namespace json { + +class WriterException : public std::exception { + public: + WriterException(std::string msg) : _msg(msg) {} + ~WriterException() throw() {} + + virtual const char* what() const throw() { return _msg.c_str(); }; + + private: + std::string _msg; +}; + +struct Null {}; + +struct Val { + enum VAL_T { INT, FLOAT, STRING, ARRAY, DICT, BOOL, JSNULL }; + VAL_T type; + int i; + double f; + std::string str; + std::vector arr; + std::map dict; + + Val() { type = DICT; } + Val(Null) { type = JSNULL; } + Val(const std::vector& arrC) { arr = arrC, type = ARRAY; } + Val(const std::map& dC) { dict = dC, type = DICT; } + Val(const std::string& strC) { str = strC, type = STRING; } + Val(const char* strC) { str = strC, type = STRING; } + Val(double fC) { f = fC, type = FLOAT; } + Val(int iC) { i = iC, type = INT; } + Val(bool fC) { i = fC, type = BOOL; } +}; + +typedef int Int; +typedef double Float; +typedef bool Bool; +typedef std::string String; +typedef std::vector Array; +typedef std::map Dict; + +// simple JSON writer class without much overhead +class Writer { + public: + explicit Writer(std::ostream* out); + Writer(std::ostream* out, size_t prec); + Writer(std::ostream* out, size_t prec, bool pretty); + Writer(std::ostream* out, size_t prec, bool pretty, size_t indent); + ~Writer(){}; + + void obj(); + void arr(); + void key(const std::string& k); + void val(const std::string& v); + void val(const char* v); + void val(double v); + void val(int v); + void val(bool v); + void val(Null); + void val(const Val& v); + template + void keyVal(const std::string& k, const V& v) { + key(k); + val(v); + } + + void close(); + void closeAll(); + + private: + std::ostream* _out; + + enum NODE_T { OBJ, ARR, KEY }; + + struct Node { + NODE_T type; + bool empty; + }; + + std::stack _stack; + + bool _pretty; + size_t _indent; + size_t _floatPrec; + + void valCheck(); + void prettor(); +}; + +} // namespace json +} // namespace util + +#endif // UTIL_JSON_WRITER_H_