インデント対応

諏訪子 <suwako@076.moe>、2026-06-30 02:01
コミット 87be4c0e1a4f35cd36d43878637a11e2c26ef19a ・親 0f739e4 ・ファイルを見る

4個のファイル、+126 -50

@@ -41,6 +41,11 @@
4141 UnterminatedString,
4242 }; // enum class Error
4343
44+ struct SerializeOptions {
45+ bool pretty = false;
46+ size_t indent = 2;
47+ };
48+
4449 struct ParseResult;
4550 struct StringHash;
4651 class Object;
@@ -142,14 +147,15 @@
142147 static ParseResult parse(std::string_view jsonText);
143148
144149 public:
145- string serialize() const;
146- bool serialize_to_file(const string &path);
150+ string serialize(const SerializeOptions &opts = {}) const;
151+ bool serialize_to_file(const string &path, const SerializeOptions &opts = {}) const;
147152
148153 private:
149- static string serialize_number(f64 n);
154+ static string make_indent(size_t depth, size_t width);
155+
156+ private:
157+ string serialize_impl(const SerializeOptions &opts, size_t depth) const;
150158 static string serialize_string(const string &s);
151- static string serialize_array(const Array &arr);
152- static string serialize_object(const Object &obj);
153159
154160 private:
155161 Variant m_Value;
変更 src/file.cc
@@ -28,7 +28,8 @@
2828
2929 vector<u8> read_file(const string &filename, bool binary) {
3030 std::ios::openmode flags = std::ios::in | std::ios::ate;
31- if (binary) flags |= std::ios::binary;
31+ //if (binary) flags |= std::ios::binary;
32+ flags |= std::ios::binary;
3233
3334 std::ifstream file(filename, flags);
3435 if (!file) {
@@ -36,7 +37,9 @@
3637 }
3738
3839 auto size = file.tellg();
40+ file.clear();
3941 file.seekg(0, std::ios::beg);
42+
4043 vector<u8> data(static_cast<size_t>(size));
4144 if (!file.read(reinterpret_cast<char *>(data.data()), size)) {
4245 throw std::runtime_error("ファイルの読み込みに失敗。");
変更 src/json.cc
@@ -224,25 +224,88 @@
224224 return Parser(content).parse();
225225 }
226226
227- string Value::serialize() const {
228- if (is_null()) return "null";
229- if (is_bool()) return as_bool() ? "true" : "false";
230- if (is_number()) return serialize_number(as_number());
231- if (is_string()) return serialize_string(as_string());
232- if (is_array()) return serialize_array(as_array());
233- if (is_object()) return serialize_object(as_object());
227+ string Value::serialize(const SerializeOptions &opts) const {
228+ return serialize_impl(opts, 0);
229+ }
230+
231+ string Value::serialize_impl(const SerializeOptions &opts, size_t depth) const {
232+ if (is_null()) return "null";
233+ if (is_bool()) return as_bool() ? "true" : "false";
234+ if (is_number()) {
235+ std::ostringstream oss;
236+ oss << as_number();
237+ return oss.str();
238+ }
239+ if (is_string())
240+ return serialize_string(as_string());
234241
242+ if (is_array()) {
243+ const auto &arr = as_array();
244+
245+ string out = "[";
246+ if (opts.pretty && !arr.empty())
247+ out += "\n";
248+
249+ for (size_t i = 0; i < arr.size(); ++i) {
250+ if (opts.pretty)
251+ out += make_indent(depth + 1, opts.indent);
252+
253+ out += arr[i].serialize_impl(opts, depth + 1);
254+
255+ if (i + 1 < arr.size())
256+ out += ",";
257+
258+ if (opts.pretty)
259+ out += "\n";
260+ }
261+
262+ if (opts.pretty && !arr.empty())
263+ out += make_indent(depth, opts.indent);
264+
265+ out += "]";
266+ return out;
267+ }
268+
269+ if (is_object()) {
270+ const auto &obj = as_object();
271+
272+ string out = "{";
273+
274+ if (opts.pretty && !obj.empty())
275+ out += "\n";
276+
277+ size_t i = 0;
278+ for (const auto &[key, val] : obj) {
279+ if (opts.pretty)
280+ out += make_indent(depth + 1, opts.indent);
281+
282+ out += serialize_string(key);
283+ out += opts.pretty ? ": " : ":";
284+ out += val.serialize_impl(opts, depth + 1);
285+
286+ if (++i < obj.size())
287+ out += ",";
288+
289+ if (opts.pretty)
290+ out += "\n";
291+ }
292+
293+ if (opts.pretty && !obj.empty())
294+ out += make_indent(depth, opts.indent);
295+
296+ out += "}";
297+ return out;
298+ }
299+
235300 return "null";
236301 }
237302
238- bool Value::serialize_to_file(const string &path) {
239- return write_file(path, { serialize() }, false);
303+ bool Value::serialize_to_file(const string &path, const SerializeOptions &opts) const {
304+ return write_file(path, { serialize(opts) }, false);
240305 }
241306
242- string Value::serialize_number(f64 n) {
243- std::ostringstream oss;
244- oss << n;
245- return oss.str();
307+ string Value::make_indent(size_t depth, size_t width) {
308+ return string(depth * width, ' ');
246309 }
247310
248311 string Value::serialize_string(const string &s) {
@@ -260,34 +323,6 @@
260323 }
261324
262325 out += "\"";
263- return out;
264- }
265-
266- string Value::serialize_array(const Array &arr) {
267- string out = "[";
268-
269- for (size_t i = 0; i < arr.size(); ++i) {
270- if (i > 0) out += ",";
271- out += arr[i].serialize();
272- }
273-
274- out += "]";
275- return out;
276- }
277-
278- string Value::serialize_object(const Object &obj) {
279- string out = "{";
280- bool first = true;
281-
282- for (const auto &[key, val] : obj) {
283- if (!first) out += ",";
284- first = false;
285- out += serialize_string(key);
286- out += ":";
287- out += val.serialize();
288- }
289-
290- out += "}";
291326 return out;
292327 }
293328
変更 tests/main.cc
@@ -40,10 +40,20 @@
4040
4141 auto out = res.value->serialize();
4242 std::cout << out << std::endl;
43+ auto out2 = res.value->serialize({ .pretty = true, .indent = 2 });
44+ std::cout << out2 << std::endl;
45+ auto out3 = res.value->serialize({ .pretty = true, .indent = 8 });
46+ std::cout << out3 << std::endl;
4347
4448 auto res2 = json::Parser(out).parse();
4549 assert(res2.error == json::Error::None);
4650
51+ auto res3 = json::Parser(out2).parse();
52+ assert(res3.error == json::Error::None);
53+
54+ auto res4 = json::Parser(out3).parse();
55+ assert(res4.error == json::Error::None);
56+
4757 std::cout << "Memory OK" << std::endl;
4858 }
4959
@@ -76,10 +86,14 @@
7686 assert(subject->as_string() == "acct:suwako@sns.076.moe");
7787
7888 auto out = res.value->serialize_to_file("webfinger2.json");
89+ auto out2 = res.value->serialize_to_file("webfinger3.json", { .pretty = true, .indent = 2 });
7990
8091 auto res2 = json::Parser::parse_from_file("webfinger2.json");
8192 assert(res2.error == json::Error::None);
8293
94+ auto res3 = json::Parser::parse_from_file("webfinger3.json");
95+ assert(res3.error == json::Error::None);
96+
8397 std::cout << "WebFinger OK" << std::endl;
8498 }
8599
@@ -105,7 +119,7 @@
105119 assert(scene.get("nodes")->is_array());
106120 auto &sceneNodes = scene.get("nodes")->as_array();
107121 assert(sceneNodes.size() == 1);
108- assert(sceneNodes[0].is_number() == 0);
122+ assert(sceneNodes[0].as_number() == 0);
109123 }
110124
111125 {
@@ -115,7 +129,7 @@
115129 assert(arr[0].is_object());
116130 auto &node = arr[0].as_object();
117131
118- assert(node.get("mesh")->is_number() == 0);
132+ assert(node.get("mesh")->as_number() == 0);
119133 }
120134
121135 {
@@ -123,7 +137,7 @@
123137 auto &arr = buffers->as_array();
124138 assert(arr.size() == 1);
125139 assert(arr[0].is_object());
126- assert(arr[0].as_object().get("uri")->as_string() == "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA");
140+ assert(arr[0].as_object().get("uri")->as_string() == "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=");
127141 assert(arr[0].as_object().get("byteLength")->as_number() == 44);
128142 }
129143
@@ -185,10 +199,14 @@
185199 }
186200
187201 auto out = res.value->serialize_to_file("gltf2.json");
202+ auto out2 = res.value->serialize_to_file("gltf3.json", {.pretty = true, .indent = 2});
188203
189204 auto res2 = json::Parser::parse_from_file("gltf2.json");
190205 assert(res2.error == json::Error::None);
191206
207+ auto res3 = json::Parser::parse_from_file("gltf3.json");
208+ assert(res3.error == json::Error::None);
209+
192210 std::cout << "glTF OK" << std::endl;
193211 }
194212
@@ -236,12 +254,26 @@
236254 assert(pubkey.get("publicKeyPem")->as_string() == "-----BEGIN PUBLIC KEY-----\n...\n----END PUBLIC KEY----");
237255
238256 auto out = res.value->serialize_to_file("activitypub2.json");
257+ auto out2 = res.value->serialize_to_file("activitypub3.json", { .pretty = true, .indent = 2 });
239258
240259 auto res2 = json::Parser::parse_from_file("activitypub2.json");
241260 assert(res2.error == json::Error::None);
242261
262+ auto res3 = json::Parser::parse_from_file("activitypub3.json");
263+ assert(res3.error == json::Error::None);
264+
243265 std::cout << "ActivityPub OK" << std::endl;
244266 }
267+
268+ //{
269+ // const string src = R"({
270+ // "a": [,,,])";
271+
272+ // auto res = json::Parser(src).parse();
273+ // assert(res.error == json::Error::SyntaxError);
274+
275+ // std::cout << "Bad OK" << std::endl;
276+ //}
245277
246278 return 0;
247279 }