base: move Xml_generator::Node::Node behind ABI

Fixes #4063
This commit is contained in:
Norman Feske 2021-03-11 21:32:11 +01:00
parent 9ac23a18d4
commit dc8dd3396d
4 changed files with 97 additions and 53 deletions

View File

@ -223,6 +223,23 @@ class Genode::Xml_generator
_out_buffer.advance(content_buffer.used());
}
/*
* Helper used to pass the 'fn' argument of the public 'Node'
* constructor through an ABI to the implementation of the
* private 'Node' constructor.
*/
struct _Fn : Interface { virtual void call() const = 0; };
template <typename T>
struct _Typed_fn : _Fn
{
T const &_fn;
_Typed_fn(T const &fn) : _fn(fn) { }
void call() const override { _fn(); }
};
Node(Xml_generator &, char const *, _Fn const &);
public:
void insert_attribute(char const *name, char const *value)
@ -264,60 +281,11 @@ class Genode::Xml_generator
_commit_content(content_buffer);
}
template <typename FUNC>
Node(Xml_generator &xml, char const *name, FUNC const &func)
template <typename FN>
Node(Xml_generator &xml, char const *name, FN const &fn)
:
_indent_level(xml._curr_indent),
_parent_node(xml._curr_node),
_parent_was_indented(_parent_node ? _parent_node->is_indented() : false),
_parent_had_content (_parent_node ? _parent_node->has_content() : false),
_out_buffer(_parent_node ? _parent_node->_content_buffer(true)
: xml._out_buffer)
{
_out_buffer.append('\t', _indent_level);
_out_buffer.append("<");
_out_buffer.append(name);
_attr_offset = _out_buffer.used();
xml._curr_node = this;
xml._curr_indent++;
try {
/*
* Process attributes and sub nodes
*/
func();
} catch (...) {
/* reset and drop changes by not committing it */
xml._curr_node = _parent_node;
xml._curr_indent--;
if (_parent_node) {
_parent_node->_undo_content_buffer(true, _parent_was_indented, _parent_had_content); }
throw;
}
xml._curr_node = _parent_node;
xml._curr_indent--;
if (_is_indented) {
_out_buffer.append("\n");
_out_buffer.append('\t', _indent_level);
}
if (_has_content) {
_out_buffer.append("</");
_out_buffer.append(name);
_out_buffer.append(">");
} else
_out_buffer.append("/>");
if (_parent_node)
_parent_node->_commit_content(_out_buffer);
else
xml._out_buffer = _out_buffer;
_out_buffer.append('\0');
}
Node(xml, name, static_cast<_Fn const &>(_Typed_fn<FN>(fn)))
{ }
bool has_content() { return _has_content; }
bool is_indented() { return _is_indented; }

View File

@ -32,6 +32,7 @@ SRC_CC += trace.cc
SRC_CC += root_proxy.cc
SRC_CC += env_session_id_space.cc
SRC_CC += stack_protector.cc
SRC_CC += xml_generator.cc
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include

View File

@ -101,6 +101,8 @@ _ZN6Genode13Vm_connection4Vcpu5pauseEv T
_ZN6Genode13Vm_connection4Vcpu5stateEv T
_ZN6Genode13Vm_connection4VcpuC1ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T
_ZN6Genode13Vm_connection4VcpuC2ERS0_RNS_9AllocatorERNS_17Vcpu_handler_baseERKNS0_11Exit_configE T
_ZN6Genode13Xml_generator4NodeC1ERS0_PKcRKNS1_3_FnE T
_ZN6Genode13Xml_generator4NodeC2ERS0_PKcRKNS1_3_FnE T
_ZN6Genode13sleep_foreverEv T
_ZN6Genode14Capability_map6insertEmm T
_ZN6Genode14Dynamic_linker23_for_each_loaded_objectERNS_3EnvERKNS0_11For_each_fnE T
@ -424,6 +426,7 @@ memset W
stdout_reconnect T
wait_for_continue T
#
# C++ runtime
#

View File

@ -0,0 +1,72 @@
/*
* \brief XML generator
* \author Norman Feske
* \date 2021-03-11
*/
/*
* Copyright (C) 2021 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <util/xml_generator.h>
using namespace Genode;
Xml_generator::Node::Node(Xml_generator &xml, char const *name, _Fn const &func)
:
_indent_level(xml._curr_indent),
_parent_node(xml._curr_node),
_parent_was_indented(_parent_node ? _parent_node->is_indented() : false),
_parent_had_content (_parent_node ? _parent_node->has_content() : false),
_out_buffer(_parent_node ? _parent_node->_content_buffer(true)
: xml._out_buffer)
{
_out_buffer.append('\t', _indent_level);
_out_buffer.append("<");
_out_buffer.append(name);
_attr_offset = _out_buffer.used();
xml._curr_node = this;
xml._curr_indent++;
try {
/*
* Process attributes and sub nodes
*/
func.call();
} catch (...) {
/* reset and drop changes by not committing it */
xml._curr_node = _parent_node;
xml._curr_indent--;
if (_parent_node) {
_parent_node->_undo_content_buffer(true, _parent_was_indented, _parent_had_content); }
throw;
}
xml._curr_node = _parent_node;
xml._curr_indent--;
if (_is_indented) {
_out_buffer.append("\n");
_out_buffer.append('\t', _indent_level);
}
if (_has_content) {
_out_buffer.append("</");
_out_buffer.append(name);
_out_buffer.append(">");
} else
_out_buffer.append("/>");
if (_parent_node)
_parent_node->_commit_content(_out_buffer);
else
xml._out_buffer = _out_buffer;
_out_buffer.append('\0');
}