23#ifndef _util_misc_xmlwriter_h
24#define _util_misc_xmlwriter_h
26#define BOOST_PARAMETER_MAX_ARITY 15
33#include <boost/archive/iterators/base64_from_binary.hpp>
34#include <boost/archive/iterators/insert_linebreaks.hpp>
35#include <boost/archive/iterators/transform_width.hpp>
36#include <boost/archive/iterators/ostream_iterator.hpp>
39#include <boost/property_tree/ptree.hpp>
40#include <boost/property_tree/xml_parser.hpp>
43#include <boost/type_traits.hpp>
44#include <boost/mpl/not.hpp>
45#include <boost/mpl/or.hpp>
46#include <boost/mpl/and.hpp>
49#include <boost/parameter/name.hpp>
50#include <boost/parameter/preprocessor.hpp>
51#include <boost/version.hpp>
56#include <util/misc/runnable.h>
57#include <util/misc/exenv.h>
58#include <util/misc/consumableresources.h>
59#include <util/keyval/keyval.h>
60#include <util/misc/scexception.h>
61#include <util/misc/xml.h>
63#ifndef NO_USE_BOOST_ENDIAN
65# if __has_include(<boost/detail/endian.hpp>)
66# include <boost/detail/endian.hpp>
68# include <boost/endian.hpp>
71# include <boost/endian.hpp>
73# if defined(BOOST_LITTLE_ENDIAN)
74# define IS_BIG_ENDIAN false
75# elif defined(BOOST_BIG_ENDIAN)
76# define IS_BIG_ENDIAN true
78# include <arpa/inet.h>
79# define IS_BIG_ENDIAN htonl(47) == 47
82# include <arpa/inet.h>
83# define IS_BIG_ENDIAN htonl(47) == 47
89 using boost::property_tree::ptree;
90#if BOOST_VERSION >= 105600
91 typedef boost::property_tree::xml_writer_settings<std::string> xml_writer_settings;
93 typedef boost::property_tree::xml_writer_settings<char> xml_writer_settings;
105 BOOST_PARAMETER_NAME(
object)
106 BOOST_PARAMETER_NAME(outfile)
107 BOOST_PARAMETER_NAME(out)
108 BOOST_PARAMETER_NAME(compress_data)
109 BOOST_PARAMETER_NAME(pretty_print)
110 BOOST_PARAMETER_NAME(indent_spaces)
111 BOOST_PARAMETER_NAME(use_tabs)
112 BOOST_PARAMETER_NAME(human_readable)
113 BOOST_PARAMETER_NAME(fold_in_class_names)
114 BOOST_PARAMETER_NAME(root_name)
115 BOOST_PARAMETER_NAME(name)
116 BOOST_PARAMETER_NAME(attributes)
130 template<
typename T,
bool do_it>
131 struct destroy_data {
132 void operator()(T* data)
const { };
136 struct destroy_data<T, true> {
137 void operator()(T* data)
const {
144 template<typename T, bool deallocate_when_destroyed=not std::is_const<T>::value>
149 bool human_readable_;
156 bool human_readable=
false,
157 bool pretty_print=
false
161 human_readable_(human_readable),
162 pretty_print_(pretty_print)
166 destroy_data<T, deallocate_when_destroyed>()(data_);
169 unsigned long n()
const {
return n_; }
170 T* data()
const {
return data_; }
171 bool human_readable()
const {
return human_readable_; }
172 bool pretty_print()
const {
return pretty_print_; }
183 template <
typename T>
184 typename boost::enable_if<
185 boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
194 template <
typename T>
198 typename boost::disable_if_c<
199 boost::is_base_of<
XMLWritable,
typename boost::decay<T>::type>::value
200 or not boost::is_base_of<
RefCount,
typename boost::decay<T>::type>::value,
202 >::type
const& parent,
211 ptree& write_xml(
const Eigen::MatrixXd&, ptree&,
const XMLWriter&);
212 ptree& write_xml(
const Eigen::VectorXd&, ptree&,
const XMLWriter&);
213 ptree& write_xml(
const std::vector<double>&, ptree&,
const XMLWriter&);
215 template<
typename Derived>
216 ptree& write_xml(
const Eigen::MatrixBase<Derived>&, ptree&,
const XMLWriter&);
229 ptree* current_root_;
230 std::stack<ptree*> pt_stack_;
233 bool delete_pt_ =
false;
236 bool human_readable_;
237 bool fold_in_class_name_;
238 bool writing_done_ =
false;
240 int pretty_print_spaces_;
241 char pretty_print_space_char_;
242 std::vector< Ref<XMLWritable> > data_;
243 xml_writer_settings write_settings_;
247 void init_filename(
const std::string& filename);
249 std::string filename_;
267 bool fold_in_class_name()
const {
return fold_in_class_name_; }
268 const std::string& filename()
const {
return filename_; }
269 bool writing_done()
const {
return writing_done_; }
270 bool has_active_context()
const {
return pt_stack_.size() > 1; }
278 bool preserve_data_pointer =
false
281 assert(!compress_data_);
282 if(!human_readable_){
283 pt.put(
"<xmlattr>.ndata", ndata);
284 pt.put(
"<xmlattr>.datum_size",
sizeof(T));
285 pt.put(
"<xmlattr>.big_endian", IS_BIG_ENDIAN);
288 pt.put(
"<xmlattr>.ndata", ndata);
289 pt.put(
"<xmlattr>.human_readable",
true);
292 if(preserve_data_pointer) {
308 template <
typename T>
314 return this->write_to_xml(obj, parent);
317 template <
typename T>
321 std::string wrapper_name
325 ptree& child_tree = parent.add_child(wrapper_name, ptree());
326 this->write_to_xml(obj, child_tree);
330 template <
typename T,
typename MapType>
334 std::string wrapper_name,
339 ptree& child_tree = parent.add_child(wrapper_name, ptree());
340 this->write_to_xml(obj, child_tree);
341 for(
auto it : attrs) {
342 child_tree.put(
"<xmlattr>." + it.first, it.second);
347 template <
typename T,
typename... Args>
348 ptree& insert_child_default(
353 assert(not writing_done_);
354 return insert_child(*current_root_, obj, args...);
363 template <
typename T>
364 ptree& write_to_xml(T&& obj, ptree& parent)
const
367 return write_xml(std::forward<T>(obj), parent, *
this);
371 inline typename boost::enable_if<boost::is_base_of<RefCount, T>, ptree&>::type
372 write_to_xml(
const Ref<T>& obj, ptree& parent)
const {
373 return write_to_xml_impl(obj, parent, boost::is_base_of<XMLWritable, T>());
377 ptree& write_to_xml(T&& obj)
const {
378 assert(not writing_done_);
379 return write_to_xml(std::forward<T>(obj), *current_root_);
385 void begin_writing_context(
const std::string& root_name);
387 void end_writing_context();
389 static Ref<XMLWriter> current_writer;
390 static std::stack<Ref<XMLWriter>> writer_stack;
391 static std::string current_context_name;
392 static std::stack<std::string> context_name_stack;
397 inline ptree& write_to_xml_impl(
const Ref<T>& obj, ptree& parent,
const boost::true_type is_writable)
const {
398 Ref<XMLWritable> obj_write = obj;
399 return write_to_xml(obj_write, parent);
403 inline ptree& write_to_xml_impl(
const Ref<T>& obj, ptree& parent,
const boost::false_type is_writable)
const {
404 return write_to_xml(*obj, parent);
412 template <
typename T>
413 typename boost::enable_if<
414 boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
420 const XMLWriter& writer
423 return obj->write_xml(parent, writer);
426 template <
typename T>
430 typename boost::disable_if_c<
431 boost::is_base_of<XMLWritable,
typename boost::decay<T>::type>::value
432 or not boost::is_base_of<RefCount,
typename boost::decay<T>::type>::value,
434 >::type
const& parent,
435 const XMLWriter& writer
438 return write_xml(*obj, parent, writer);
441 template<
typename Derived>
442 ptree& write_xml(
const Eigen::MatrixBase<Derived>& obj, ptree& parent,
const XMLWriter& writer)
444 typedef Eigen::MatrixBase<Derived> MatrixType;
445 typedef typename Eigen::internal::traits<Derived>::Scalar Scalar;
447 ptree& child = parent.add_child(
"EigenDerived", ptree());
448 const int ninner = obj.innerSize();
449 const int nouter = obj.outerSize();
450 child.put(
"<xmlattr>.ninner", ninner);
451 child.put(
"<xmlattr>.nouter", nouter);
452 child.put(
"<xmlattr>.row_major",
int(MatrixType::IsRowMajor));
453 child.put(
"<xmlattr>.is_vector",
int(MatrixType::IsVectorAtCompileTime));
454 child.put(
"<xmlattr>.signed",
455 int(std::is_signed<Scalar>::value)
460 for(
int i = 0; i < nouter; ++i){
461 for(
int j = 0; j < ninner; ++j){
462 if(MatrixType::IsRowMajor) {
463 data[i*ninner + j] = obj(i, j);
466 data[i*ninner + j] = obj(j, i);
473 writer.put_binary_data(child.add_child(
"data", ptree()), data, nouter*ninner);
479 template<
typename Derived,
unsigned int ViewMode>
482 template<
typename Derived>
485 const Eigen::TriangularView<Derived, Eigen::Lower>& obj,
490 const int nrows = obj.rows();
491 const int ncols = obj.cols();
493 ptree& my_tree = pt.add_child(
"EigenDerived", ptree());
494 my_tree.put(
"<xmlattr>.n", nrows);
495 my_tree.put(
"<xmlattr>.lower_triangle",
true);
496 ptree& data_tree = my_tree.add_child(
"data", ptree());
497 long ndata = nrows * (nrows+1) / 2;
499 double* data_spot = data;
500 for(
int irow = 0; irow < nrows; ++irow) {
501 for(
int icol = 0; icol <= irow; ++icol) {
502 (*data_spot) = obj.coeff(irow, icol);
508 writer.put_binary_data<
double>(data_tree, data, ndata);
512 typedef Derived MatrixType;
515 ptree& child = pt.add_child(
"EigenDerived", ptree());
516 child.put(
"<xmlattr>.ninner", ncols);
517 child.put(
"<xmlattr>.nouter", nrows);
518 child.put(
"<xmlattr>.row_major",
true);
519 child.put(
"<xmlattr>.is_vector",
int(MatrixType::IsVectorAtCompileTime));
520 ptree& data_tree = child.add_child(
"data", ptree());
522 double* data_spot = data;
523 for(
int irow = 0; irow < nrows; ++irow) {
524 for(
int icol = 0; icol < ncols; ++icol) {
526 (*data_spot) = obj.coeff(irow, icol);
528 else if(icol < nrows) {
529 (*data_spot) = obj.coeff(icol, irow);
539 writer.put_binary_data<
double>(data_tree, data, nrows*ncols);
548 template<
typename Derived,
unsigned int ViewMode>
549 ptree& write_xml(
const Eigen::TriangularView<Derived, ViewMode>& obj, ptree& parent,
const XMLWriter& writer) {
554 template<
template<
typename...>
class Container,
template<
typename...>
class TupleType,
typename... NumTypes>
555 typename boost::enable_if_c<
556 boost::is_convertible<
557 Container<TupleType<NumTypes...>>,
558 std::vector<TupleType<NumTypes...>>
563 boost::is_integral<NumTypes>,
564 boost::is_floating_point<NumTypes>
570 const Container<TupleType<NumTypes...>>& obj,
572 const XMLWriter& writer
575 typedef Container<TupleType<NumTypes...>> input_type;
576 typedef std::vector<TupleType<NumTypes...>> vect_type;
580 const auto& the_function = [](
581 const vect_type& obj,
583 const XMLWriter& writer
587 if(writer.fold_in_class_name()) {
588 parent.put(
"<xmlattr>.type",
"std::vector<double>");
589 child_ptr = &(parent);
592 ptree& tmp = parent.add_child(
"data", ptree());
595 ptree& child = *child_ptr;
596 writer.put_binary_data(child, obj.data(), obj.size(),
true);
597 child.put(
"<xmlattr>.nperdatum",
sizeof...(NumTypes));
601 return the_function(obj, parent, writer);
608 using boost::is_convertible;
609 namespace mpl = boost::mpl;
611 #define XMLWRITER_FILENAME_NOT_GIVEN "__FILENAME_NOT_GIVEN__"
614 #define XMLWRITER_KV_OPTIONAL_PARAMS \
615 (outfile, *(is_convertible<mpl::_, std::string>), XMLWRITER_FILENAME_NOT_GIVEN) \
616 (compress_data, (bool), false) \
617 (pretty_print, (bool), true) \
618 (indent_spaces, (int), 2) \
619 (use_tabs, (bool), false) \
620 (human_readable, (bool), false) \
621 (fold_in_class_names, (bool), true)
623 #define XMLWRITER_CREATE_FROM_PARAMS(VARNAME) \
624 std::string __fname = outfile; \
625 Ref<AssignedKeyVal> akv = new AssignedKeyVal; \
626 akv->assign("filename", \
627 __fname == XMLWRITER_FILENAME_NOT_GIVEN ? "-" : __fname \
629 akv->assignboolean("compress_data", (bool)compress_data); \
630 akv->assignboolean("pretty_print", (bool)pretty_print); \
631 akv->assignboolean("indent_spaces", (bool)indent_spaces); \
632 akv->assignboolean("use_tabs", (bool)use_tabs); \
633 akv->assignboolean("human_readable", (bool)human_readable); \
634 akv->assignboolean("fold_in_class_names", (bool)fold_in_class_names); \
635 Ref<XMLWriter> VARNAME(new XMLWriter(akv));
637 BOOST_PARAMETER_FUNCTION(
647 XMLWRITER_KV_OPTIONAL_PARAMS
649 *(is_convertible<mpl::_, std::string>), std::string(
"mpqc")
655 XMLWRITER_CREATE_FROM_PARAMS(writer)
657 writer->begin_writing_context(std::string(root_name));
658 writer->write_to_xml(
object);
659 writer->end_writing_context();
664 BOOST_PARAMETER_FUNCTION(
669 (name, *(is_convertible<mpl::_, std::string>))
672 XMLWRITER_KV_OPTIONAL_PARAMS
676 std::string fname = outfile;
677 std::string tag_name = name;
678 bool fname_not_given = fname == XMLWRITER_FILENAME_NOT_GIVEN;
679 if(!XMLWriter::current_writer.null() and not XMLWriter::current_writer->writing_done()){
680 if(fname_not_given || XMLWriter::current_writer->filename() == fname){
681 XMLWriter::current_writer->begin_writing_context(tag_name);
685 XMLWriter::writer_stack.push(XMLWriter::current_writer);
687 XMLWRITER_CREATE_FROM_PARAMS(writer)
689 XMLWriter::current_writer = writer;
690 writer->begin_writing_context(tag_name);
695 XMLWRITER_CREATE_FROM_PARAMS(writer)
697 XMLWriter::current_writer = writer;
698 writer->begin_writing_context(tag_name);
701 XMLWriter::context_name_stack.push(XMLWriter::current_context_name);
702 XMLWriter::current_context_name = tag_name;
706 BOOST_PARAMETER_FUNCTION(
711 (name, *(is_convertible<mpl::_, std::string>), XMLWRITER_FILENAME_NOT_GIVEN)
715 std::string tag_name = name;
717 (tag_name == XMLWRITER_FILENAME_NOT_GIVEN or tag_name == XMLWriter::current_context_name)
718 and !XMLWriter::current_writer.null()
719 and not XMLWriter::context_name_stack.empty()
721 XMLWriter::current_writer->end_writing_context();
722 if(not XMLWriter::current_writer->has_active_context()){
723 if(XMLWriter::writer_stack.size() > 0) {
724 XMLWriter::current_writer = XMLWriter::writer_stack.top();
725 XMLWriter::writer_stack.pop();
728 XMLWriter::current_writer = 0;
733 throw ProgrammingError(
"Mismatched transparent XML contexts", __FILE__, __LINE__);
736 XMLWriter::current_context_name = XMLWriter::context_name_stack.top();
737 XMLWriter::context_name_stack.pop();
740 template <
typename T,
typename MapType>
741 inline typename boost::enable_if<is_convertible<MapType, bool>,
void>::type
742 _write_as_xml_impl(T&&
object,
const std::string& tag_name,
const MapType& attrs)
744 XMLWriter::current_writer->insert_child_default(
object, tag_name);
747 template <
typename T,
typename MapType>
748 inline typename boost::enable_if<boost::mpl::not_<is_convertible<MapType, bool>>,
void>::type
749 _write_as_xml_impl(T&&
object,
const std::string& tag_name,
const MapType& attrs)
751 XMLWriter::current_writer->insert_child_default(
object, tag_name, attrs);
754 BOOST_PARAMETER_FUNCTION(
763 (attributes, *,
false)
767 if(XMLWriter::current_writer.null()) {
768 throw ProgrammingError(
"No current XML context", __FILE__, __LINE__);
771 std::string tag_name = name;
772 _write_as_xml_impl(
object, tag_name, attributes);
776 template<
typename Value=std::
string>
777 using attrs = std::map<std::string, Value>;
783 get_human_readable_data(
792 get_human_readable_data(
802 get_human_readable_data(
810 throw FeatureNotImplemented(
"get_human_readable_data", __FILE__, __LINE__);
819 typedef std::string internal_type;
822 boost::optional<external_type> get_value(
const internal_type& str)
826 assert(str.length()*
sizeof(
char) %
sizeof(T) == 0);
829 unsigned long ndata = str.length() *
sizeof(char) /
sizeof(T);
830 T* rv_data =
new T[ndata];
831 ::memcpy(rv_data, &(str.c_str()[0]), ndata *
sizeof(T));
832 return boost::optional<external_type>(
external_type(rv_data, ndata));
835 return boost::optional<external_type>(boost::none);
840 boost::optional<internal_type> put_value(
const external_type& xds)
842 if(xds.human_readable()){
843 return boost::optional<internal_type>(
844 detail::get_human_readable_data(
852 using namespace boost::archive::iterators;
856 transform_width<const char*, 6, 8>
859 typedef insert_linebreaks<base64_text, 72> base64_text_linebreaks;
861 std::stringstream sstr;
862 if(xds.pretty_print()){
864 base64_text_linebreaks(xds.data()),
865 base64_text_linebreaks(xds.data() + xds.n()),
866 boost::archive::iterators::ostream_iterator<char>(sstr)
868 if(xds.n() * 8 *
sizeof(T) % 6 == 2)
869 return boost::optional<internal_type>(internal_type(
"\n" + sstr.str() +
"==\n"));
870 else if(xds.n() * 8 *
sizeof(T) % 6 == 4)
871 return boost::optional<internal_type>(internal_type(
"\n" + sstr.str() +
"=\n"));
873 return boost::optional<internal_type>(internal_type(
"\n" + sstr.str() +
"\n"));
877 base64_text(xds.data()),
878 base64_text(xds.data() + xds.n()),
879 boost::archive::iterators::ostream_iterator<char>(sstr)
881 if(xds.n() * 8 *
sizeof(T) % 6 == 2)
882 return boost::optional<internal_type>(internal_type(sstr.str() +
"=="));
883 else if(xds.n() * 8 *
sizeof(T) % 6 == 4)
884 return boost::optional<internal_type>(internal_type(sstr.str() +
"="));
886 return boost::optional<internal_type>(internal_type(sstr.str()));
898 namespace property_tree {
900 template<
typename Ch,
typename Traits,
typename Alloc,
typename T,
bool val>
static std::ostream & out0()
Return an ostream that writes from node 0.
The Grid class defines a finite regular Carthesian grid.
Definition grid.h:35
The base class for all reference counted objects.
Definition ref.h:192
A template class that maintains references counts.
Definition ref.h:361
The Runnable class is a DescribedClass with a pure virtual run member.
Definition runnable.h:36
a 3-element version of SCVector
Definition vector3.h:44
The SCVector class is the abstract base class for double valued vectors.
Definition abstract.h:97
The Units class is used to perform unit conversions.
Definition units.h:38
Definition xmlwriter.h:145
Definition xmlwriter.h:223
void run()
Executes an action as specified in the derived class.
Contains all MPQC code up to version 3.
Definition mpqcin.h:14
void deallocate(T *&array)
this version will set array to 0 upon return
Definition consumableresources.h:452
T * allocate(std::size_t size)
allocate and deallocate array of data using new or new[] (delete or delete[]) and using default Consu...
Definition consumableresources.h:448
Definition xmlwriter.h:818
Definition xmlwriter.h:480