Refactor json renderer to share implementation for vector and string

This commit is contained in:
Siarhei Fedartsou 2022-09-30 14:57:57 +02:00
parent 463663b05e
commit a9c72e393a
2 changed files with 62 additions and 104 deletions

View File

@ -27,18 +27,18 @@ namespace
constexpr int MAX_FLOAT_STRING_LENGTH = 256; constexpr int MAX_FLOAT_STRING_LENGTH = 256;
} }
struct Renderer template <typename Out> struct Renderer
{ {
explicit Renderer(std::ostream &_out) : out(_out) {} explicit Renderer(Out &_out) : out(_out) {}
void operator()(const String &string) const void operator()(const String &string)
{ {
out << "\""; write('"');
out << escape_JSON(string.value); write(escape_JSON(string.value));
out << "\""; write('"');
} }
void operator()(const Number &number) const void operator()(const Number &number)
{ {
char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'}; char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'};
ieee754::dtoa_milo(number.value, buffer); ieee754::dtoa_milo(number.value, buffer);
@ -64,120 +64,72 @@ struct Renderer
} }
++pos; ++pos;
} }
out << buffer; write(buffer);
} }
void operator()(const Object &object) const void operator()(const Object &object)
{ {
out << "{"; write('{');
for (auto it = object.values.begin(), end = object.values.end(); it != end;) for (auto it = object.values.begin(), end = object.values.end(); it != end;)
{ {
out << "\"" << it->first << "\":"; write('\"');
write(it->first);
write("\"");
mapbox::util::apply_visitor(Renderer(out), it->second); mapbox::util::apply_visitor(Renderer(out), it->second);
if (++it != end) if (++it != end)
{ {
out << ","; write(',');
} }
} }
out << "}"; write('}');
} }
void operator()(const Array &array) const void operator()(const Array &array)
{ {
out << "["; write('[');
for (auto it = array.values.cbegin(), end = array.values.cend(); it != end;) for (auto it = array.values.cbegin(), end = array.values.cend(); it != end;)
{ {
mapbox::util::apply_visitor(Renderer(out), *it); mapbox::util::apply_visitor(Renderer(out), *it);
if (++it != end) if (++it != end)
{ {
out << ","; write(',');
} }
} }
out << "]"; write(']');
} }
void operator()(const True &) const { out << "true"; } void operator()(const True &) { write("true"); }
void operator()(const False &) const { out << "false"; } void operator()(const False &) { write("false"); }
void operator()(const Null &) const { out << "null"; } void operator()(const Null &) { write("null"); }
private: private:
std::ostream &out; void write(const std::string &str);
void write(const char *str);
void write(char ch);
private:
Out &out;
}; };
struct ArrayRenderer template <> void Renderer<std::vector<char>>::write(const std::string &str)
{ {
explicit ArrayRenderer(std::vector<char> &_out) : out(_out) {} out.insert(out.end(), str.begin(), str.end());
}
void operator()(const String &string) const template <> void Renderer<std::vector<char>>::write(const char *str)
{ {
out.push_back('\"'); out.insert(out.end(), str, str + strlen(str));
const auto string_to_insert = escape_JSON(string.value); }
out.insert(std::end(out), std::begin(string_to_insert), std::end(string_to_insert));
out.push_back('\"');
}
void operator()(const Number &number) const template <> void Renderer<std::ostream>::write(const std::string &str) { out << str; }
{
const std::string number_string = cast::to_string_with_precision(number.value);
out.insert(out.end(), number_string.begin(), number_string.end());
}
void operator()(const Object &object) const template <> void Renderer<std::ostream>::write(const char *str) { out << str; }
{
out.push_back('{');
for (auto it = object.values.begin(), end = object.values.end(); it != end;)
{
out.push_back('\"');
out.insert(out.end(), it->first.begin(), it->first.end());
out.push_back('\"');
out.push_back(':');
mapbox::util::apply_visitor(ArrayRenderer(out), it->second); template <> void Renderer<std::vector<char>>::write(char ch) { out.push_back(ch); }
if (++it != end)
{
out.push_back(',');
}
}
out.push_back('}');
}
void operator()(const Array &array) const template <> void Renderer<std::ostream>::write(char ch) { out << ch; }
{
out.push_back('[');
for (auto it = array.values.cbegin(), end = array.values.cend(); it != end;)
{
mapbox::util::apply_visitor(ArrayRenderer(out), *it);
if (++it != end)
{
out.push_back(',');
}
}
out.push_back(']');
}
void operator()(const True &) const
{
const std::string temp("true");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const False &) const
{
const std::string temp("false");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const Null &) const
{
const std::string temp("null");
out.insert(out.end(), temp.begin(), temp.end());
}
private:
std::vector<char> &out;
};
inline void render(std::ostream &out, const Object &object) inline void render(std::ostream &out, const Object &object)
{ {
@ -188,7 +140,7 @@ inline void render(std::ostream &out, const Object &object)
inline void render(std::vector<char> &out, const Object &object) inline void render(std::vector<char> &out, const Object &object)
{ {
Value value = object; Value value = object;
mapbox::util::apply_visitor(ArrayRenderer(out), value); mapbox::util::apply_visitor(Renderer(out), value);
} }
} // namespace json } // namespace json

View File

@ -1,8 +1,8 @@
#include "osrm/json_container.hpp"
#include "util/json_container.hpp" #include "util/json_container.hpp"
#include "util/json_renderer.hpp" #include "util/json_renderer.hpp"
#include "util/timing_util.hpp" #include "util/timing_util.hpp"
#include "osrm/json_container.hpp"
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -55,9 +55,9 @@ int main(int, char **)
{ {
using namespace osrm; using namespace osrm;
const auto location = json::Array{{{7.437070}, {43.749248}}}; const auto location = json::Array{{{7.437070}, {43.749248}}};
json::Object reference{ json::Object reference{
{{"code", "Ok"}, {{"code", "Ok"},
{"waypoints", {"waypoints",
json::Array{{json::Object{{{"name", "Boulevard du Larvotto"}, json::Array{{json::Object{{{"name", "Boulevard du Larvotto"},
@ -123,19 +123,25 @@ int main(int, char **)
{"in", 0}}}}}} {"in", 0}}}}}}
}}}}}}}}}}}}}}}}}; }}}}}}}}}}}}}}}}};
json::Array arr; json::Array arr;
for (size_t index = 0; index < 256; ++index) { for (size_t index = 0; index < 4096; ++index)
arr.values.push_back(reference); {
} arr.values.push_back(reference);
json::Object obj{{{"arr", arr}}}; }
std::string ss; json::Object obj{{{"arr", arr}}};
TIMER_START(create_object);
TIMER_START(stringstream);
std::stringstream ss;
json::render(ss, obj); json::render(ss, obj);
//std::string s{ss.begin(), ss.end()}; std::string s{ss.str()};
TIMER_STOP(create_object); TIMER_STOP(stringstream);
std::cout << TIMER_MSEC(create_object) << "ms" std::cout << "String: " << TIMER_MSEC(stringstream) << "ms" << std::endl;
<< std::endl; TIMER_START(vector);
// (void)s; std::vector<char> vec;
// std::cerr << ss << "\n"; json::render(vec, obj);
TIMER_STOP(vector);
std::cout << "Vector: " << TIMER_MSEC(vector) << "ms" << std::endl;
// (void)s;
// std::cerr << ss << "\n";
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }