diff --git a/repos/os/include/os/buffered_xml.h b/repos/os/include/os/buffered_xml.h index 913da6eb1..706e769ae 100644 --- a/repos/os/include/os/buffered_xml.h +++ b/repos/os/include/os/buffered_xml.h @@ -15,7 +15,9 @@ #define _OS__BUFFERED_XML_H_ /* Genode includes */ +#include #include +#include #include namespace Genode { class Buffered_xml; } @@ -25,23 +27,51 @@ class Genode::Buffered_xml { private: - Allocator &_alloc; - char const * const _ptr; /* pointer to dynamically allocated buffer */ - Xml_node const _xml; /* referring to buffer of '_ptr' */ + Allocator &_alloc; + + struct Allocation { char *ptr; size_t size; } const _allocation; + + Xml_node const _xml { _allocation.ptr, _allocation.size }; /** * \throw Allocator::Out_of_memory */ - static char const *_init_ptr(Allocator &alloc, Xml_node node) + Allocation _copy_xml_node(Xml_node node) { - char *ptr = nullptr; + Allocation allocation { }; node.with_raw_node([&] (char const *start, size_t length) { - ptr = (char *)alloc.alloc(length); - Genode::memcpy(ptr, start, length); + allocation = Allocation { (char *)_alloc.alloc(length), length }; + Genode::memcpy(allocation.ptr, start, length); }); - return ptr; + return allocation; + } + + /** + * Generate XML into allocated buffer + * + * \throw Allocation::Out_of_memory + */ + template + Allocation _generate(char const *node_name, FN const &fn, size_t size) + { + Allocation allocation { }; + + retry( + + [&] () { + allocation = Allocation { (char *)_alloc.alloc(size), size }; + Xml_generator xml(allocation.ptr, size, node_name, + [&] () { fn(xml); }); }, + + [&] () { + _alloc.free(allocation.ptr, allocation.size); + allocation = { }; + size = size*2; + } + ); + return allocation; } /* @@ -53,18 +83,50 @@ class Genode::Buffered_xml public: /** - * Constructor + * Constructor for buffering a copy of the specified XML node * * \throw Allocator::Out_of_memory */ Buffered_xml(Allocator &alloc, Xml_node node) : - _alloc(alloc), _ptr(_init_ptr(alloc, node)), _xml(_ptr, node.size()) + _alloc(alloc), _allocation(_copy_xml_node(node)) { } - ~Buffered_xml() { _alloc.free(const_cast(_ptr), _xml.size()); } + struct Min_size { size_t value; }; + /** + * Constructor for buffering generated XML + * + * \param name name of top-level XML node + * \param fn functor that takes an 'Xml_generator &' as argument + * \param size initial allocation size + * + * \throw Allocator::Out_of_memory + */ + template + Buffered_xml(Allocator &alloc, char const *name, FN const &fn, Min_size size) + : + _alloc(alloc), _allocation(_generate(name, fn, size.value)) + { } + + template + Buffered_xml(Allocator &alloc, char const *name, FN const &fn) + : + Buffered_xml(alloc, name, fn, Min_size{4000}) + { } + + ~Buffered_xml() { _alloc.free(_allocation.ptr, _allocation.size); } + + /* + * \deprecated Use 'with_xml_node' instead + */ Xml_node xml() const { return _xml; } + + /** + * Call functor 'fn' with 'Xml_node const &' as argument + */ + template + void with_xml_node(FN const &fn) const { fn(_xml); } }; #endif /* _OS__BUFFERED_XML_H_ */