-
Notifications
You must be signed in to change notification settings - Fork 128
feat(dom): add pretty serialization API #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -227,5 +227,102 @@ sonic_force_inline SonicError SerializeImpl(const NodeType* node, | |
| return kSerErrorInvalidObjKey; | ||
| } | ||
|
|
||
| inline void PushPrettyLine(WriteBuffer& wb, size_t depth, size_t indent_size) { | ||
| wb.Push('\n'); | ||
| for (size_t i = 0; i < depth; ++i) { | ||
| for (size_t j = 0; j < indent_size; ++j) { | ||
| wb.Push(' '); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| template <SerializeFlags serializeFlags, typename NodeType> | ||
| SonicError PrettySerializeImpl(const NodeType* node, WriteBuffer& wb, | ||
| size_t indent_size) { | ||
| struct ParentCtx { | ||
| const NodeType* node; | ||
| size_t index; | ||
| }; | ||
|
|
||
| constexpr SerializeFlags append_flags = | ||
| serializeFlags | SerializeFlags::kSerializeAppendBuffer; | ||
| internal::Stack parents; | ||
| size_t depth = 0; | ||
| SonicError error = kErrorNone; | ||
|
|
||
| if constexpr ((serializeFlags & SerializeFlags::kSerializeAppendBuffer) == | ||
| 0) { | ||
| wb.Clear(); | ||
| } | ||
| wb.Reserve(wb.Size() + 64); | ||
|
|
||
| value_begin: | ||
| if (!node->IsContainer() || node->Empty()) { | ||
| error = SerializeImpl<append_flags>(node, wb); | ||
| if (sonic_unlikely(error != kErrorNone)) { | ||
| return error; | ||
| } | ||
| goto value_end; | ||
| } | ||
|
|
||
| wb.Push(node->IsObject() ? '{' : '['); | ||
| parents.Push(ParentCtx{node, 0}); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a nonempty document is deeply nested enough that AGENTS.md reference: AGENTS.md:L137-L146 Useful? React with 👍 / 👎. |
||
| ++depth; | ||
| PushPrettyLine(wb, depth, indent_size); | ||
|
|
||
| if (node->IsObject()) { | ||
| auto member = node->MemberBegin(); | ||
| if (sonic_unlikely(!member->name.IsString())) { | ||
| return kSerErrorInvalidObjKey; | ||
| } | ||
| error = SerializeImpl<append_flags>(&(member->name), wb); | ||
| if (sonic_unlikely(error != kErrorNone)) { | ||
| return error; | ||
| } | ||
| wb.Push(':'); | ||
| wb.Push(' '); | ||
| node = &(member->value); | ||
| } else { | ||
| node = &(*(node->Begin())); | ||
| } | ||
| goto value_begin; | ||
|
|
||
| value_end: | ||
| if (parents.Empty()) { | ||
| return kErrorNone; | ||
| } | ||
|
|
||
| { | ||
| ParentCtx* parent = parents.Top<ParentCtx>(); | ||
| ++parent->index; | ||
| if (parent->index < parent->node->Size()) { | ||
| wb.Push(','); | ||
| PushPrettyLine(wb, depth, indent_size); | ||
| if (parent->node->IsObject()) { | ||
| auto member = parent->node->MemberBegin() + parent->index; | ||
| if (sonic_unlikely(!member->name.IsString())) { | ||
| return kSerErrorInvalidObjKey; | ||
| } | ||
| error = SerializeImpl<append_flags>(&(member->name), wb); | ||
| if (sonic_unlikely(error != kErrorNone)) { | ||
| return error; | ||
| } | ||
| wb.Push(':'); | ||
| wb.Push(' '); | ||
| node = &(member->value); | ||
| } else { | ||
| node = &(*(parent->node->Begin() + parent->index)); | ||
| } | ||
| goto value_begin; | ||
| } | ||
|
|
||
| --depth; | ||
| PushPrettyLine(wb, depth, indent_size); | ||
| wb.Push(parent->node->IsObject() ? '}' : ']'); | ||
| parents.Pop<ParentCtx>(1); | ||
| } | ||
| goto value_end; | ||
| } | ||
|
|
||
| } // namespace internal | ||
| } // namespace sonic_json | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For every scalar or empty-container value, this invokes
SerializeImpl, which unconditionally constructs and destroys its own heap-backedinternal::Stackeven though leaf serialization never needs that stack; object keys incur the same cost through the other calls below. Consequently, pretty-printing an N-element primitive array performs O(N) avoidable heap allocation/free pairs, which makes this serialization path scale poorly; emit leaves through a reusable scalar helper or shared traversal state instead.AGENTS.md reference: AGENTS.md:L569-L577
Useful? React with 👍 / 👎.