Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
data_table_json.hpp
Go to the documentation of this file.
1
5#pragma once
6#include "data_table.hpp"
7
9{
12{
13 std::vector<std::string> columns = {};
14};
15
16namespace data_table_detail
17{
18// JSON writes must ignore the caller's locale, field width and numeric stream flags.
20{
21 std::ostream& stream;
22 void put(char c) { stream.put(c); }
23 json_output& operator<<(std::string_view text)
24 {
25 stream.write(text.data(), static_cast<std::streamsize>(text.size()));
26 return *this;
27 }
29 {
30 this->put(c);
31 return *this;
32 }
33};
34
35// Validates UTF-8 and escapes JSON syntax/control bytes without changing numerical text.
36void write_json_string(std::ostream& out, std::string_view value);
37
38template <typename T> void write_json_value(json_output& out, T const& value)
39{
40 if constexpr (optional_traits<T>::optional)
41 {
42 if (value)
44 else
45 out << "null";
46 }
47 else if constexpr (std::same_as<T, std::string>)
48 write_json_string(out.stream, value);
49 else if constexpr (runtime_real<T>)
50 {
51 out << "{\"value\":";
52 write_json_string(out.stream, value.is_exact() ? value.to_string() : cell_text(value, {}, true));
53 out << ",\"precision\":";
54 if (value.is_exact())
55 out << "\"exact\"";
56 else
57 out << fmt::format("{}", value.precision().bit_count());
58 out << '}';
59 }
60 else if constexpr (Real<T>)
61 write_json_string(out.stream, cell_text(value, {}, true));
62 else if constexpr (integer<T>)
63 {
64 if constexpr (uni20::numeric_limits<T>::digits() > 53)
65 write_json_string(out.stream, cell_text(value, {}, true));
66 else
67 out << cell_text(value, {}, true);
68 }
69 else
70 out << cell_text(value, {}, true);
71}
72
73template <DataTableValue T> void write_json_column(json_output& out, data_column<T> const& column)
74{
75 using V = value_type<T>;
76 out << "{\"id\":";
77 write_json_string(out.stream, column.identifier());
78 out << ",\"label\":";
79 write_json_string(out.stream, column.label());
80 out << ",\"unit\":";
81 write_json_string(out.stream, column.unit());
82 out << ",\"description\":";
83 write_json_string(out.stream, column.description());
84 out << ",\"type\":";
85 if constexpr (half_integer<V>)
86 {
87 out << "\"half_int\",\"storage_bits\":"
88 << fmt::format("{}", uni20::numeric_limits<typename V::value_type>::digits() + 1) << ",\"encoding\":\"number\"";
89 }
90 else if constexpr (runtime_real<V>)
91 out << "\"real\",\"radix\":2,\"precision\":\"per_value\",\"encoding\":\"value_precision\"";
92 else if constexpr (Real<V>)
93 {
94 out << "\"real\",\"radix\":" << fmt::format("{}", uni20::numeric_limits<V>::radix)
95 << ",\"precision_bits\":" << fmt::format("{}", uni20::numeric_limits<V>::digits())
96 << ",\"encoding\":\"decimal_string\"";
97 }
98 else if constexpr (integer<V>)
99 {
100 write_json_string(out.stream, fmt::format("{}int{}", std::is_signed_v<V> ? "" : "u",
101 uni20::numeric_limits<V>::digits() + (std::is_signed_v<V> ? 1 : 0)));
102 out << ",\"encoding\":";
103 write_json_string(out.stream, uni20::numeric_limits<V>::digits() > 53 ? "decimal_string" : "number");
104 }
105 else if constexpr (std::same_as<V, bool>)
106 out << "\"bool\"";
107 else
108 out << "\"string\"";
109 out << ",\"nullable\":" << (optional_traits<T>::optional ? "true" : "false") << '}';
110}
111
112template <typename Schema, typename Row>
113void write_json_row(json_output& out, Schema const& schema, Row const& row, resolved_projection const& selection)
114{
115 out.put('[');
116 bool first = true;
117 visit_selected(schema, row, selection, [&](auto const&, auto const& value, auto const&) {
118 if (!std::exchange(first, false)) out.put(',');
120 });
121 out.put(']');
122 check_output(out.stream);
123}
124
125inline void write_json_metadata(json_output& out, table_metadata const& metadata)
126{
127 out.put('{');
128 bool first = true;
129 for (auto const& [key, value] : metadata)
130 {
131 if (!std::exchange(first, false)) out.put(',');
132 write_json_string(out.stream, key);
133 out.put(':');
134 write_json_string(out.stream, value);
135 }
136 out.put('}');
137}
138
139template <typename Schema>
140void write_json_begin(json_output& out, std::string const& title, Schema const& schema, table_metadata const& metadata,
141 resolved_projection const& selection, data_sink_start start)
142{
143 check_output(out.stream);
144 out << "{\"title\":";
145 write_json_string(out.stream, title);
146 out << ",\"metadata\":";
147 write_json_metadata(out, metadata);
148 out << ",\"first_row\":" << fmt::format("{}", start.first_row) << ",\"columns\":[";
149 bool first = true;
150 for (auto index : selection.indices)
151 visit_column(schema, index, [&](auto const& column) {
152 if (!std::exchange(first, false)) out.put(',');
153 write_json_column(out, column);
154 });
155 out << "],\"rows\":[";
156 check_output(out.stream);
157}
158
159inline void write_json_end(json_output& out, table_metadata const* summary)
160{
161 out.put(']');
162 if (summary)
163 {
164 out << ",\"summary\":";
165 write_json_metadata(out, *summary);
166 }
167 out << "}\n";
168 check_output(out.stream);
169}
170} // namespace data_table_detail
171
178template <DataTableValue... Ts>
179void write_json(std::ostream& stream, data_table<Ts...> const& table, data_json_options const& options = {})
180{
181 auto rows = table.rows();
182 auto selection = data_table_detail::resolve_projection(table.columns(), {.columns = options.columns});
183 data_table_detail::json_output out{stream};
184 data_table_detail::write_json_begin(out, table.title(), table.columns(), table.metadata(), selection, {});
185 bool first = true;
186 for (auto const& row : rows)
187 {
188 if (!std::exchange(first, false)) out.put(',');
189 data_table_detail::write_json_row(out, table.columns(), row, selection);
190 }
191 data_table_detail::write_json_end(out, table.summary() ? &*table.summary() : nullptr);
192}
193} // namespace uni20::presentation
Typed column schema with owned metadata and deferred display formatting.
Definition data_table.hpp:206
data_column & label(std::string text)
Definition data_table.hpp:218
data_column & description(std::string text)
Definition data_table.hpp:228
std::string const & identifier() const noexcept
Definition data_table.hpp:283
data_column & unit(std::string text)
Definition data_table.hpp:223
Typed result table with synchronous sinks and optional retained history.
Definition data_table.hpp:404
Concept for real scalar types (float, double, etc.).
Definition scalar_concepts.hpp:69
locale_t value
Definition data_table.cpp:49
Typed result tables with deferred presentation and numerical export.
presentation::styled_text text
Definition display.cpp:141
Definition cli.cpp:6
streaming_table table(std::string title, stream destination)
Create a schema-first streaming display table.
Definition display.cpp:800
void write_json_column(json_output &out, data_column< T > const &column)
Definition data_table_json.hpp:73
void visit_selected(Schema const &schema, Row const &row, resolved_projection const &selection, Function &&function)
Definition data_table.hpp:719
void write_json_value(json_output &out, T const &value)
Definition data_table_json.hpp:38
void write_json_end(json_output &out, table_metadata const *summary)
Definition data_table_json.hpp:159
void check_output(std::ostream &out)
Definition data_table.cpp:40
resolved_projection resolve_projection(Schema const &schema, table_projection const &options)
Definition data_table.hpp:688
void visit_column(Schema const &schema, std::size_t index, Function &&function)
Definition data_table.hpp:681
std::string cell_text(T const &value, data_column_display const &display, bool machine)
Definition data_table.hpp:636
void write_json_begin(json_output &out, std::string const &title, Schema const &schema, table_metadata const &metadata, resolved_projection const &selection, data_sink_start start)
Definition data_table_json.hpp:140
void write_json_string(std::ostream &out, std::string_view value)
Definition data_table.cpp:71
void write_json_row(json_output &out, Schema const &schema, Row const &row, resolved_projection const &selection)
Definition data_table_json.hpp:113
void write_json_metadata(json_output &out, table_metadata const &metadata)
Definition data_table_json.hpp:125
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
Definition data_table.cpp:8
std::map< std::string, std::string > table_metadata
Application metadata is owned text, independent of numerical rows.
Definition data_table.hpp:314
void write_json(std::ostream &stream, data_table< Ts... > const &table, data_json_options const &options={})
Write an ordered schema and typed rows, preserving real and integer precision.
Definition data_table_json.hpp:179
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16
Ordered JSON column selection. Empty selects every column; display precision is never applied.
Definition data_table_json.hpp:12
std::vector< std::string > columns
Definition data_table_json.hpp:13
The index of the first row this attachment can emit (zero for full replay).
Definition data_table.hpp:344
std::size_t first_row
Definition data_table.hpp:345
void put(char c)
Definition data_table_json.hpp:22
json_output & operator<<(char c)
Definition data_table_json.hpp:28
json_output & operator<<(std::string_view text)
Definition data_table_json.hpp:23
std::ostream & stream
Definition data_table_json.hpp:21
std::vector< std::size_t > indices
Definition data_table.hpp:676