#include <cstdint>
#include <cassert>
#include <tuple>
+#include <algorithm>
#include "../util/soft_float.h"
namespace vulkan_cpu
{
namespace json
{
+void write_state::write_indent(std::ostream &os) const
+{
+ for(std::size_t i = indent_level; i > 0; i--)
+ os << options.indent_text;
+}
+
namespace ast
{
namespace soft_float = util::soft_float;
-void null_value::write(std::ostream &os) const
+void null_value::write(std::ostream &os, write_state &state) const
{
os << "null";
}
-void boolean_value::write(std::ostream &os) const
+void boolean_value::write(std::ostream &os, write_state &state) const
{
os << (value ? "true" : "false");
}
}
}
-void string_value::write(std::ostream &os, const std::string &value)
+void string_value::write(std::ostream &os, const std::string &value, write_state &state)
{
os << '\"';
for(unsigned char ch : value)
return used_buffer_size; // report used buffer excluding the null terminator
}
-void number_value::write(std::ostream &os, unsigned base) const
+void number_value::write(std::ostream &os, write_state &state, unsigned base) const
{
write_number(
[&](char ch)
base);
}
-void object::write(std::ostream &os) const
+void object::write(std::ostream &os, write_state &state) const
{
os << '{';
- auto seperator = "";
- for(auto &entry : values)
+ if(!values.empty())
{
- const std::string &key = std::get<0>(entry);
- const value &value = std::get<1>(entry);
- os << seperator;
- seperator = ",";
- string_value::write(os, key);
- os << ':';
- ast::write(os, value);
+ write_state::push_indent push_indent(state);
+ auto seperator = "";
+ auto write_entry = [&](const std::pair<std::string, value> &entry)
+ {
+ const std::string &key = std::get<0>(entry);
+ const value &value = std::get<1>(entry);
+ os << seperator;
+ seperator = ",";
+ if(state.options.composite_value_elements_on_seperate_lines)
+ {
+ os << '\n';
+ state.write_indent(os);
+ }
+ string_value::write(os, key, state);
+ os << ':';
+ json::write(os, value, state);
+ };
+ if(state.options.sort_object_values)
+ {
+ auto compare_fn = [](decltype(values)::const_iterator a,
+ decltype(values)::const_iterator b) -> bool
+ {
+ return std::get<0>(*a) < std::get<0>(*b);
+ };
+ std::vector<decltype(values)::const_iterator> entry_iterators;
+ entry_iterators.reserve(values.size());
+ for(auto i = values.begin(); i != values.end(); ++i)
+ entry_iterators.push_back(i);
+ std::sort(entry_iterators.begin(), entry_iterators.end(), compare_fn);
+ for(auto &i : entry_iterators)
+ write_entry(*i);
+ }
+ else
+ {
+ for(auto &entry : values)
+ write_entry(entry);
+ }
+ push_indent.finish();
+ if(state.options.composite_value_elements_on_seperate_lines)
+ {
+ os << '\n';
+ state.write_indent(os);
+ }
}
os << '}';
}
-void array::write(std::ostream &os) const
+void array::write(std::ostream &os, write_state &state) const
{
os << '[';
- auto seperator = "";
- for(const value &v : values)
+ if(!values.empty())
{
- os << seperator;
- seperator = ",";
- ast::write(os, v);
+ write_state::push_indent push_indent(state);
+ auto seperator = "";
+ for(const value &v : values)
+ {
+ os << seperator;
+ seperator = ",";
+ if(state.options.composite_value_elements_on_seperate_lines)
+ {
+ os << '\n';
+ state.write_indent(os);
+ }
+ json::write(os, v, state);
+ }
+ push_indent.finish();
+ if(state.options.composite_value_elements_on_seperate_lines)
+ {
+ os << '\n';
+ state.write_indent(os);
+ }
}
os << ']';
}
#include <utility>
#include <limits>
#include <type_traits>
+#include <cassert>
#include "../util/variant.h"
namespace vulkan_cpu
{
namespace json
{
+struct write_options
+{
+ bool composite_value_elements_on_seperate_lines = false;
+ bool sort_object_values = false;
+ std::string indent_text = "";
+ write_options()
+ {
+ }
+ write_options(bool composite_value_elements_on_seperate_lines,
+ bool sort_object_values,
+ std::string indent_text) noexcept
+ : composite_value_elements_on_seperate_lines(composite_value_elements_on_seperate_lines),
+ sort_object_values(sort_object_values),
+ indent_text(std::move(indent_text))
+ {
+ }
+ static write_options defaults()
+ {
+ return {};
+ }
+ static write_options pretty(std::string indent_text = " ")
+ {
+ return write_options(true, true, std::move(indent_text));
+ }
+};
+
+struct write_state
+{
+ write_options options;
+ std::size_t indent_level = 0;
+ class push_indent final
+ {
+ push_indent(const push_indent &) = delete;
+ push_indent &operator=(const push_indent &) = delete;
+
+ private:
+ write_state &state;
+ bool finished = false;
+
+ public:
+ push_indent(write_state &state) : state(state)
+ {
+ state.indent_level++;
+ }
+ void finish()
+ {
+ assert(!finished);
+ state.indent_level--;
+ finished = true;
+ }
+ ~push_indent()
+ {
+ if(!finished)
+ state.indent_level--;
+ }
+ };
+ write_state(write_options options) : options(std::move(options))
+ {
+ }
+ void write_indent(std::ostream &os) const;
+};
+
namespace ast
{
struct null_value final
constexpr null_value(std::nullptr_t) noexcept
{
}
- void write(std::ostream &os) const;
+ void write(std::ostream &os, write_state &state) const;
null_value duplicate() const noexcept
{
return {};
constexpr boolean_value(T value) noexcept : value(value)
{
}
- void write(std::ostream &os) const;
+ void write(std::ostream &os, write_state &state) const;
boolean_value duplicate() const noexcept
{
return *this;
string_value(T value) noexcept : value(std::move(value))
{
}
- static void write(std::ostream &os, const std::string &value);
- void write(std::ostream &os) const
+ static void write(std::ostream &os, const std::string &value, write_state &state);
+ void write(std::ostream &os, write_state &state) const
{
- write(os, value);
+ write(os, value, state);
}
string_value duplicate() const noexcept
{
std::size_t output_buffer_size,
bool require_null_terminator = true,
unsigned base = default_base) noexcept;
- void write(std::ostream &os, unsigned base = default_base) const;
+ void write(std::ostream &os, write_state &state, unsigned base = default_base) const;
number_value duplicate() const noexcept
{
return *this;
{
composite_value() = default;
virtual ~composite_value() = default;
- virtual void write(std::ostream &os) const = 0;
+ virtual void write(std::ostream &os, write_state &state) const = 0;
virtual composite_value_pointer duplicate() const = 0;
operator value() const
{
v);
}
-inline void write(std::ostream &os, const value &v)
-{
- util::visit(
- [&](const auto &v) -> void
- {
- return v->write(os);
- },
- v);
-}
-
struct object final : public composite_value
{
std::unordered_map<std::string, value> values;
object(std::unordered_map<std::string, value> values) noexcept : values(std::move(values))
{
}
- virtual void write(std::ostream &os) const override;
+ virtual void write(std::ostream &os, write_state &state) const override;
virtual composite_value_pointer duplicate() const override
{
std::unordered_map<std::string, value> new_values;
array(std::vector<value> values) noexcept : values(std::move(values))
{
}
- virtual void write(std::ostream &os) const override;
+ virtual void write(std::ostream &os, write_state &state) const override;
virtual composite_value_pointer duplicate() const override
{
std::vector<value> new_values;
}
};
}
+
+inline void write(std::ostream &os, const ast::value &v, write_state &state)
+{
+ util::visit(
+ [&](const auto &v) -> void
+ {
+ return v->write(os, state);
+ },
+ v);
+}
+
+inline void write(std::ostream &os, const ast::value &v, write_options options = {})
+{
+ write_state state(std::move(options));
+ write(os, v, state);
+}
}
}