MPQC  3.0.0-alpha
xmlwriter.h
1 //
2 // xmlwriter.h
3 //
4 // Copyright (C) 2013 David Hollman
5 //
6 // Author: David Hollman
7 //
8 // This file is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2, or (at your option)
11 // any later version.
12 //
13 // This file is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with the MPQC; see the file COPYING. If not, write to
20 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 
23 #ifndef _util_misc_xmlwriter_h
24 #define _util_misc_xmlwriter_h
25 
26 #define BOOST_PARAMETER_MAX_ARITY 15
27 
28 #include <algorithm>
29 #include <stack>
30 #include <tuple>
31 
32 // boost archive iterators for base64 conversion
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>
37 
38 // boost::property_tree
39 #include <boost/property_tree/ptree.hpp>
40 #include <boost/property_tree/xml_parser.hpp>
41 
42 // boost type traits and mpl
43 #include <boost/type_traits.hpp>
44 #include <boost/mpl/not.hpp>
45 #include <boost/mpl/or.hpp>
46 #include <boost/mpl/and.hpp>
47 
48 // boost parameter library
49 #include <boost/parameter/name.hpp>
50 #include <boost/parameter/preprocessor.hpp>
51 #include <boost/version.hpp>
52 
53 // Eigen
54 #include <Eigen/Dense>
55 
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>
62 
63 #ifndef NO_USE_BOOST_ENDIAN
64 # include <boost/detail/endian.hpp>
65 # if defined(BOOST_LITTLE_ENDIAN)
66 # define IS_BIG_ENDIAN false
67 # elif defined(BOOST_BIG_ENDIAN)
68 # define IS_BIG_ENDIAN true
69 # else
70 # include <arpa/inet.h>
71 # define IS_BIG_ENDIAN htonl(47) == 47
72 # endif
73 #else
74 # include <arpa/inet.h>
75 # define IS_BIG_ENDIAN htonl(47) == 47
76 #endif
77 
78 
79 namespace sc {
80 
81  using boost::property_tree::ptree;
82 #if BOOST_VERSION >= 105600
83  typedef boost::property_tree::xml_writer_settings<std::string> xml_writer_settings;
84 #else
85  typedef boost::property_tree::xml_writer_settings<char> xml_writer_settings;
86 #endif
87 
89 
90  namespace parameter {
91  // Parameters for boost::parameter parameters are always wrapped in namespace
92  // sc::parameter in MPQC.
93 
94  // Parameters for generic function that quickly writes an object to a given
95  // XML file; extremely useful for debugging and matching old code. These
96  // are basically just the keyval arguments to XMLWriter
97  BOOST_PARAMETER_NAME(object)
98  BOOST_PARAMETER_NAME(outfile)
99  BOOST_PARAMETER_NAME(out)
100  BOOST_PARAMETER_NAME(compress_data)
101  BOOST_PARAMETER_NAME(pretty_print)
102  BOOST_PARAMETER_NAME(indent_spaces)
103  BOOST_PARAMETER_NAME(use_tabs)
104  BOOST_PARAMETER_NAME(human_readable)
105  BOOST_PARAMETER_NAME(fold_in_class_names)
106  BOOST_PARAMETER_NAME(root_name)
107  BOOST_PARAMETER_NAME(name)
108  BOOST_PARAMETER_NAME(attributes)
109  }
110 
112 
113  class SCVector3;
114  class Grid;
115  class Units;
116  class XMLWritable;
117  class SCVector;
118 
120 
121  namespace {
122  template<typename T, bool do_it>
123  struct destroy_data {
124  void operator()(T* data) const { };
125  };
126 
127  template<typename T>
128  struct destroy_data<T, true> {
129  void operator()(T* data) const {
130  deallocate(data);
131  }
132  };
133 
134  }
135 
136  template<typename T, bool deallocate_when_destroyed=not std::is_const<T>::value>
138  private:
139  T* data_;
140  unsigned long n_;
141  bool human_readable_;
142  bool pretty_print_;
143 
144  public:
146  T* data,
147  unsigned long n,
148  bool human_readable=false,
149  bool pretty_print=false
150  ) :
151  data_(data),
152  n_(n),
153  human_readable_(human_readable),
154  pretty_print_(pretty_print)
155  { }
156 
157  ~XMLDataStream() {
158  destroy_data<T, deallocate_when_destroyed>()(data_);
159  }
160 
161  unsigned long n() const { return n_; }
162  T* data() const { return data_; }
163  bool human_readable() const { return human_readable_; }
164  bool pretty_print() const { return pretty_print_; }
165 
166  private:
167 
168  };
169 
170 
172 
173  class XMLWriter;
174 
175  template <typename T>
176  typename boost::enable_if<
177  boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
178  ptree&
179  >::type
180  write_xml(
181  const Ref<T>& obj,
182  ptree& parent,
183  const XMLWriter& writer
184  );
185 
186  template <typename T>
187  ptree&
188  write_xml(
189  const Ref<T>& obj,
190  typename boost::disable_if_c<
191  boost::is_base_of<XMLWritable, typename boost::decay<T>::type>::value
192  or not boost::is_base_of<RefCount, typename boost::decay<T>::type>::value,
193  ptree&
194  >::type const& parent,
195  const XMLWriter& writer
196  );
197 
198  ptree& write_xml(XMLWritable&, ptree&, const XMLWriter&);
199  ptree& write_xml(const SCVector3&, ptree&, const XMLWriter&);
200  ptree& write_xml(const SCVector&, ptree&, const XMLWriter&);
201  ptree& write_xml(const Grid&, ptree&, const XMLWriter&);
202  ptree& write_xml(const Units&, ptree&, const XMLWriter&);
203  ptree& write_xml(const Eigen::MatrixXd&, ptree&, const XMLWriter&);
204  ptree& write_xml(const Eigen::VectorXd&, ptree&, const XMLWriter&);
205  ptree& write_xml(const std::vector<double>&, ptree&, const XMLWriter&);
206 
207  template<typename Derived>
208  ptree& write_xml(const Eigen::MatrixBase<Derived>&, ptree&, const XMLWriter&);
209 
211 
212  // TODO gzip compression, turned on and off by the writer
213  // TODO write as data is received?
214  // TODO perfect forwarding of objects; make sure copies aren't happening
215  class XMLWriter : public Runnable {
216 
217  protected:
218 
219  std::ostream* out_;
220 
221  ptree* current_root_;
222  std::stack<ptree*> pt_stack_;
223 
224  bool delete_out_;
225  bool delete_pt_ = false;
226  bool compress_data_;
227  bool pretty_print_;
228  bool human_readable_;
229  bool fold_in_class_name_;
230  bool writing_done_ = false;
231 
232  int pretty_print_spaces_;
233  char pretty_print_space_char_;
234  std::vector< Ref<XMLWritable> > data_;
235  xml_writer_settings write_settings_;
236 
237  void init();
238 
239  void init_filename(const std::string& filename);
240 
241  std::string filename_;
242 
243  public:
244 
245  XMLWriter() = delete;
246 
247  XMLWriter(const XMLWriter&) = delete;
248 
249  XMLWriter(const Ref<KeyVal>& keyval);
250 
251  XMLWriter(std::ostream& out=ExEnv::out0());
252 
253  XMLWriter(ptree* pt, std::ostream& out=ExEnv::out0());
254 
255  XMLWriter(const std::string& filename);
256 
257  virtual ~XMLWriter();
258 
259  bool fold_in_class_name() const { return fold_in_class_name_; }
260  const std::string& filename() const { return filename_; }
261  bool writing_done() const { return writing_done_; }
262  bool has_active_context() const { return pt_stack_.size() > 1; }
263 
264  template<typename T>
265  void
266  put_binary_data(
267  ptree& pt,
268  T* data,
269  long ndata,
270  bool preserve_data_pointer = false
271  ) const
272  {
273  assert(!compress_data_); // Not implemented
274  if(!human_readable_){
275  pt.put("<xmlattr>.ndata", ndata);
276  pt.put("<xmlattr>.datum_size", sizeof(T));
277  pt.put("<xmlattr>.big_endian", IS_BIG_ENDIAN);
278  }
279  else{
280  pt.put("<xmlattr>.ndata", ndata);
281  pt.put("<xmlattr>.human_readable", true);
282  }
283 
284  if(preserve_data_pointer) {
285  XMLDataStream<const T> xds(const_cast<const T*>(data), ndata,
286  /* human_readable = */ human_readable_,
287  /* pretty_print = */ pretty_print_
288  );
289  pt.put_value(xds);
290  }
291  else {
292  XMLDataStream<T> xds(data, ndata,
293  /* human_readable = */ human_readable_,
294  /* pretty_print = */ pretty_print_
295  );
296  pt.put_value(xds);
297  }
298  }
299 
300  template <typename T>
301  ptree& insert_child(
302  ptree& parent,
303  T&& obj
304  ) const
305  {
306  return this->write_to_xml(obj, parent);
307  }
308 
309  template <typename T>
310  ptree& insert_child(
311  ptree& parent,
312  T&& obj,
313  std::string wrapper_name
314  ) const
315  {
316  // Wrap the object in a ptree named wrapper_name
317  ptree& child_tree = parent.add_child(wrapper_name, ptree());
318  this->write_to_xml(obj, child_tree);
319  return child_tree;
320  }
321 
322  template <typename T, typename MapType>
323  ptree& insert_child(
324  ptree& parent,
325  T&& obj,
326  std::string wrapper_name,
327  const MapType& attrs
328  ) const
329  {
330  // Wrap the object in a ptree named wrapper_name
331  ptree& child_tree = parent.add_child(wrapper_name, ptree());
332  this->write_to_xml(obj, child_tree);
333  for(auto it : attrs) {
334  child_tree.put("<xmlattr>." + it.first, it.second);
335  }
336  return child_tree;
337  }
338 
339  template <typename T, typename... Args>
340  ptree& insert_child_default(
341  T&& obj,
342  Args... args
343  ) const
344  {
345  assert(not writing_done_);
346  return insert_child(*current_root_, obj, args...);
347  }
348 
349  void add_data(const Ref<XMLWritable>& datum) { data_.push_back(datum); }
350 
351  void do_write();
352 
353  void run();
354 
355  template <typename T>
356  ptree& write_to_xml(T&& obj, ptree& parent) const
357  {
358  // Call the non-intrusive interface
359  return write_xml(std::forward<T>(obj), parent, *this);
360  }
361 
362  template<typename T>
363  inline typename boost::enable_if<boost::is_base_of<RefCount, T>, ptree&>::type
364  write_to_xml(const Ref<T>& obj, ptree& parent) const {
365  return write_to_xml_impl(obj, parent, boost::is_base_of<XMLWritable, T>());
366  }
367 
368  template<typename T>
369  ptree& write_to_xml(T&& obj) const {
370  assert(not writing_done_);
371  return write_to_xml(std::forward<T>(obj), *current_root_);
372  }
373 
374  //----------------------------------------------------------------------------//
375  // Transparent context for writing objects
376 
377  void begin_writing_context(const std::string& root_name);
378 
379  void end_writing_context();
380 
381  static Ref<XMLWriter> current_writer;
382  static std::stack<Ref<XMLWriter>> writer_stack;
383  static std::string current_context_name;
384  static std::stack<std::string> context_name_stack;
385 
386  private:
387 
388  template<typename T>
389  inline ptree& write_to_xml_impl(const Ref<T>& obj, ptree& parent, const boost::true_type is_writable) const {
390  Ref<XMLWritable> obj_write = obj;
391  return write_to_xml(obj_write, parent);
392  }
393 
394  template<typename T>
395  inline ptree& write_to_xml_impl(const Ref<T>& obj, ptree& parent, const boost::false_type is_writable) const {
396  return write_to_xml(*obj, parent);
397  }
398 
399 
400  };
401 
403 
404  template <typename T>
405  typename boost::enable_if<
406  boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
407  ptree&
408  >::type
409  write_xml(
410  const Ref<T>& obj,
411  ptree& parent,
412  const XMLWriter& writer
413  )
414  {
415  return obj->write_xml(parent, writer);
416  }
417 
418  template <typename T>
419  ptree&
420  write_xml(
421  const Ref<T>& obj,
422  typename boost::disable_if_c<
423  boost::is_base_of<XMLWritable, typename boost::decay<T>::type>::value
424  or not boost::is_base_of<RefCount, typename boost::decay<T>::type>::value,
425  ptree&
426  >::type const& parent,
427  const XMLWriter& writer
428  )
429  {
430  return write_xml(*obj, parent, writer);
431  }
432 
433  template<typename Derived>
434  ptree& write_xml(const Eigen::MatrixBase<Derived>& obj, ptree& parent, const XMLWriter& writer)
435  {
436  typedef Eigen::MatrixBase<Derived> MatrixType;
437  typedef typename Eigen::internal::traits<Derived>::Scalar Scalar;
438 
439  ptree& child = parent.add_child("EigenDerived", ptree());
440  const int ninner = obj.innerSize();
441  const int nouter = obj.outerSize();
442  child.put("<xmlattr>.ninner", ninner);
443  child.put("<xmlattr>.nouter", nouter);
444  child.put("<xmlattr>.row_major", int(MatrixType::IsRowMajor));
445  child.put("<xmlattr>.is_vector", int(MatrixType::IsVectorAtCompileTime));
446  child.put("<xmlattr>.signed",
447  int(std::is_signed<Scalar>::value)
448  );
449 
450  // Just iterate over everything so we don't have to think about strides and such
451  Scalar* data = allocate<Scalar>(nouter*ninner);
452  for(int i = 0; i < nouter; ++i){
453  for(int j = 0; j < ninner; ++j){
454  if(MatrixType::IsRowMajor) {
455  data[i*ninner + j] = obj(i, j);
456  }
457  else {
458  data[i*ninner + j] = obj(j, i);
459  }
460  }
461  }
462 
463  // Note: the XMLDataStream created by put_binary_data now owns
464  // the pointer 'data'
465  writer.put_binary_data(child.add_child("data", ptree()), data, nouter*ninner);
466  return child;
467  }
468 
469  namespace detail {
470 
471  template<typename Derived, unsigned int ViewMode>
472  struct TriangleWriter { };
473 
474  template<typename Derived>
475  struct TriangleWriter<Derived, Eigen::Lower> {
476  ptree& operator()(
477  const Eigen::TriangularView<Derived, Eigen::Lower>& obj,
478  ptree& pt,
479  const XMLWriter& writer
480  ) const
481  {
482  const int nrows = obj.rows();
483  const int ncols = obj.cols();
484  if(nrows == ncols) {
485  ptree& my_tree = pt.add_child("EigenDerived", ptree());
486  my_tree.put("<xmlattr>.n", nrows);
487  my_tree.put("<xmlattr>.lower_triangle", true);
488  ptree& data_tree = my_tree.add_child("data", ptree());
489  long ndata = nrows * (nrows+1) / 2;
490  double* data = allocate<double>(ndata);
491  double* data_spot = data;
492  for(int irow = 0; irow < nrows; ++irow) {
493  for(int icol = 0; icol <= irow; ++icol) {
494  (*data_spot) = obj.coeff(irow, icol);
495  ++data_spot;
496  }
497  }
498  // The XMLDataStream object created by this function call
499  // owns the pointer data after this.
500  writer.put_binary_data<double>(data_tree, data, ndata);
501  return my_tree;
502  }
503  else {
504  typedef Derived MatrixType;
505  // Just write the unraveled version
506 
507  ptree& child = pt.add_child("EigenDerived", ptree());
508  child.put("<xmlattr>.ninner", ncols);
509  child.put("<xmlattr>.nouter", nrows);
510  child.put("<xmlattr>.row_major", true);
511  child.put("<xmlattr>.is_vector", int(MatrixType::IsVectorAtCompileTime));
512  ptree& data_tree = child.add_child("data", ptree());
513  double* data = allocate<double>(nrows*ncols);
514  double* data_spot = data;
515  for(int irow = 0; irow < nrows; ++irow) {
516  for(int icol = 0; icol < ncols; ++icol) {
517  if(icol <= irow) {
518  (*data_spot) = obj.coeff(irow, icol);
519  }
520  else if(icol < nrows) {
521  (*data_spot) = obj.coeff(icol, irow);
522  }
523  else {
524  (*data_spot) = 0.0;
525  }
526  ++data_spot;
527  }
528  }
529  // The XMLDataStream object created by this function call
530  // owns the pointer data after this.
531  writer.put_binary_data<double>(data_tree, data, nrows*ncols);
532  return child;
533  }
534  }
535 
536  };
537 
538  }
539 
540  template<typename Derived, unsigned int ViewMode>
541  ptree& write_xml(const Eigen::TriangularView<Derived, ViewMode>& obj, ptree& parent, const XMLWriter& writer) {
542  return detail::TriangleWriter<Derived, ViewMode>()(obj, parent, writer);
543  }
544 
545 
546  template<template<typename...> class Container, template<typename...> class TupleType, typename... NumTypes>
547  typename boost::enable_if_c<
548  boost::is_convertible<
549  Container<TupleType<NumTypes...>>,
550  std::vector<TupleType<NumTypes...>>
551  >::value
552  and
553  boost::mpl::and_<
554  boost::mpl::or_<
555  boost::is_integral<NumTypes>,
556  boost::is_floating_point<NumTypes>
557  >...
558  >::value,
559  ptree&
560  >::type
561  write_xml(
562  const Container<TupleType<NumTypes...>>& obj,
563  ptree& parent,
564  const XMLWriter& writer
565  )
566  {
567  typedef Container<TupleType<NumTypes...>> input_type;
568  typedef std::vector<TupleType<NumTypes...>> vect_type;
569 
570  // Cheesy but effective way to do automatic type conversion without
571  // unnecessary copies
572  const auto& the_function = [](
573  const vect_type& obj,
574  ptree& parent,
575  const XMLWriter& writer
576  ) -> ptree&
577  {
578  ptree* child_ptr;
579  if(writer.fold_in_class_name()) {
580  parent.put("<xmlattr>.type", "std::vector<double>");
581  child_ptr = &(parent);
582  }
583  else{
584  ptree& tmp = parent.add_child("data", ptree());
585  child_ptr = &tmp;
586  }
587  ptree& child = *child_ptr;
588  writer.put_binary_data(child, obj.data(), obj.size(), true);
589  child.put("<xmlattr>.nperdatum", sizeof...(NumTypes));
590  return child;
591  };
592 
593  return the_function(obj, parent, writer);
594  }
595 
597 
598 
599 
600  using boost::is_convertible;
601  namespace mpl = boost::mpl;
602 
603  #define XMLWRITER_FILENAME_NOT_GIVEN "__FILENAME_NOT_GIVEN__"
604 
605  // optional parameters mirroring the keyval contructor parameters for XMLWriter
606  #define XMLWRITER_KV_OPTIONAL_PARAMS \
607  (outfile, *(is_convertible<mpl::_, std::string>), XMLWRITER_FILENAME_NOT_GIVEN) \
608  (compress_data, (bool), false) \
609  (pretty_print, (bool), true) \
610  (indent_spaces, (int), 2) \
611  (use_tabs, (bool), false) \
612  (human_readable, (bool), false) \
613  (fold_in_class_names, (bool), true)
614 
615  #define XMLWRITER_CREATE_FROM_PARAMS(VARNAME) \
616  std::string __fname = outfile; \
617  Ref<AssignedKeyVal> akv = new AssignedKeyVal; \
618  akv->assign("filename", \
619  __fname == XMLWRITER_FILENAME_NOT_GIVEN ? "-" : __fname \
620  ); \
621  akv->assignboolean("compress_data", (bool)compress_data); \
622  akv->assignboolean("pretty_print", (bool)pretty_print); \
623  akv->assignboolean("indent_spaces", (bool)indent_spaces); \
624  akv->assignboolean("use_tabs", (bool)use_tabs); \
625  akv->assignboolean("human_readable", (bool)human_readable); \
626  akv->assignboolean("fold_in_class_names", (bool)fold_in_class_names); \
627  Ref<XMLWriter> VARNAME(new XMLWriter(akv));
628 
629  BOOST_PARAMETER_FUNCTION(
630  (void), // Return type
631  write_to_xml_file, // Name of the function
632  sc::parameter::tag, // Namespace of the tag types
633 
634  (required // required parameters
635  (object, *) // an object of any type. Will not compile if the
636  // object can't be written to XML by some means
637  )
638  (optional
639  XMLWRITER_KV_OPTIONAL_PARAMS
640  (root_name, // root_name is the name of the root node on the xml output
641  *(is_convertible<mpl::_, std::string>), std::string("mpqc")
642  )
643  )
644  )
645  {
646 
647  XMLWRITER_CREATE_FROM_PARAMS(writer)
648 
649  writer->begin_writing_context(std::string(root_name));
650  writer->write_to_xml(object);
651  writer->end_writing_context();
652  }
653 
654 
655  // Transparent context for writing
656  BOOST_PARAMETER_FUNCTION(
657  (void),
658  begin_xml_context,
659  parameter::tag,
660  (required
661  (name, *(is_convertible<mpl::_, std::string>))
662  )
663  (optional
664  XMLWRITER_KV_OPTIONAL_PARAMS
665  )
666  )
667  {
668  std::string fname = outfile;
669  std::string tag_name = name;
670  bool fname_not_given = fname == XMLWRITER_FILENAME_NOT_GIVEN;
671  if(!XMLWriter::current_writer.null() and not XMLWriter::current_writer->writing_done()){
672  if(fname_not_given || XMLWriter::current_writer->filename() == fname){
673  XMLWriter::current_writer->begin_writing_context(tag_name);
674  }
675  else {
676  // Save the current writer, switch to new writer
677  XMLWriter::writer_stack.push(XMLWriter::current_writer);
678 
679  XMLWRITER_CREATE_FROM_PARAMS(writer)
680 
681  XMLWriter::current_writer = writer;
682  writer->begin_writing_context(tag_name);
683  }
684  }
685  else {
686  // TODO fail if there is an unclosed inner context that doesn't make sense
687  XMLWRITER_CREATE_FROM_PARAMS(writer)
688 
689  XMLWriter::current_writer = writer;
690  writer->begin_writing_context(tag_name);
691  }
692 
693  XMLWriter::context_name_stack.push(XMLWriter::current_context_name);
694  XMLWriter::current_context_name = tag_name;
695  }
696 
697  // Transparent context for writing
698  BOOST_PARAMETER_FUNCTION(
699  (void),
700  end_xml_context,
701  parameter::tag,
702  (optional
703  (name, *(is_convertible<mpl::_, std::string>), XMLWRITER_FILENAME_NOT_GIVEN)
704  )
705  )
706  {
707  std::string tag_name = name;
708  if(
709  (tag_name == XMLWRITER_FILENAME_NOT_GIVEN or tag_name == XMLWriter::current_context_name)
710  and !XMLWriter::current_writer.null()
711  and not XMLWriter::context_name_stack.empty()
712  ) {
713  XMLWriter::current_writer->end_writing_context();
714  if(not XMLWriter::current_writer->has_active_context()){
715  if(XMLWriter::writer_stack.size() > 0) {
716  XMLWriter::current_writer = XMLWriter::writer_stack.top();
717  XMLWriter::writer_stack.pop();
718  }
719  else{
720  XMLWriter::current_writer = 0;
721  }
722  }
723  }
724  else {
725  throw ProgrammingError("Mismatched transparent XML contexts", __FILE__, __LINE__);
726  }
727 
728  XMLWriter::current_context_name = XMLWriter::context_name_stack.top();
729  XMLWriter::context_name_stack.pop();
730  }
731 
732  template <typename T, typename MapType>
733  inline typename boost::enable_if<is_convertible<MapType, bool>, void>::type
734  _write_as_xml_impl(T&& object, const std::string& tag_name, const MapType& attrs)
735  {
736  XMLWriter::current_writer->insert_child_default(object, tag_name);
737  }
738 
739  template <typename T, typename MapType>
740  inline typename boost::enable_if<boost::mpl::not_<is_convertible<MapType, bool>>, void>::type
741  _write_as_xml_impl(T&& object, const std::string& tag_name, const MapType& attrs)
742  {
743  XMLWriter::current_writer->insert_child_default(object, tag_name, attrs);
744  }
745 
746  BOOST_PARAMETER_FUNCTION(
747  (void),
748  write_as_xml,
749  parameter::tag,
750  (required
751  (name, *)
752  (object, *)
753  )
754  (optional
755  (attributes, *, false)
756  )
757  )
758  {
759  if(XMLWriter::current_writer.null()) {
760  throw ProgrammingError("No current XML context", __FILE__, __LINE__);
761  }
762  else{
763  std::string tag_name = name;
764  _write_as_xml_impl(object, tag_name, attributes);
765  }
766  }
767 
768  template<typename Value=std::string>
769  using attrs = std::map<std::string, Value>;
770 
772 
773  namespace detail {
774  std::string
775  get_human_readable_data(
776  double* data,
777  long ndata,
778  int nperline=8,
779  int precision=8,
780  int width=15
781  );
782 
783  std::string
784  get_human_readable_data(
785  int* data,
786  long ndata,
787  int nperline=8,
788  int precision=8, // ignored
789  int width=15
790  );
791 
792  template<typename T>
793  std::string
794  get_human_readable_data(
795  T* data,
796  long ndata,
797  int nperline=8,
798  int precision=8,
799  int width=15
800  )
801  {
802  throw FeatureNotImplemented("get_human_readable_data", __FILE__, __LINE__);
803  return " "; // unreachable
804  }
805  }
806 
808 
809  template<typename T>
811  typedef std::string internal_type;
813 
814  boost::optional<external_type> get_value(const internal_type& str)
815  {
816  if (!str.empty()) {
817  // Require the string to be aligned to the sizeof(T)
818  assert(str.length()*sizeof(char) % sizeof(T) == 0);
819 
820  // Transfer the data to it's new home
821  unsigned long ndata = str.length() * sizeof(char) / sizeof(T);
822  T* rv_data = new T[ndata];
823  ::memcpy(rv_data, &(str.c_str()[0]), ndata * sizeof(T));
824  return boost::optional<external_type>(external_type(rv_data, ndata));
825  }
826  else {
827  return boost::optional<external_type>(boost::none);
828  }
829 
830  }
831 
832  boost::optional<internal_type> put_value(const external_type& xds)
833  {
834  if(xds.human_readable()){
835  return boost::optional<internal_type>(
836  detail::get_human_readable_data(
837  xds.data(),
838  xds.n()
839  )
840  );
841 
842  }
843  else{
844  using namespace boost::archive::iterators;
845 
846  typedef
847  base64_from_binary<
848  transform_width<const char*, 6, 8>
849  >
850  base64_text;
851  typedef insert_linebreaks<base64_text, 72> base64_text_linebreaks;
852 
853  std::stringstream sstr;
854  if(xds.pretty_print()){
855  std::copy(
856  base64_text_linebreaks(xds.data()),
857  base64_text_linebreaks(xds.data() + xds.n()),
858  boost::archive::iterators::ostream_iterator<char>(sstr)
859  );
860  if(xds.n() * 8 * sizeof(T) % 6 == 2)
861  return boost::optional<internal_type>(internal_type("\n" + sstr.str() + "==\n"));
862  else if(xds.n() * 8 * sizeof(T) % 6 == 4)
863  return boost::optional<internal_type>(internal_type("\n" + sstr.str() + "=\n"));
864  else
865  return boost::optional<internal_type>(internal_type("\n" + sstr.str() + "\n"));
866  }
867  else{
868  std::copy(
869  base64_text(xds.data()),
870  base64_text(xds.data() + xds.n()),
871  boost::archive::iterators::ostream_iterator<char>(sstr)
872  );
873  if(xds.n() * 8 * sizeof(T) % 6 == 2)
874  return boost::optional<internal_type>(internal_type(sstr.str() + "=="));
875  else if(xds.n() * 8 * sizeof(T) % 6 == 4)
876  return boost::optional<internal_type>(internal_type(sstr.str() + "="));
877  else
878  return boost::optional<internal_type>(internal_type(sstr.str()));
879  }
880  }
881 
882  }
883  };
884 
885 } // end namespace sc
886 
888 
889 namespace boost {
890  namespace property_tree {
891 
892  template<typename Ch, typename Traits, typename Alloc, typename T, bool val>
893  struct translator_between<std::basic_string<Ch, Traits, Alloc>, sc::XMLDataStream<T, val> >
894  {
896  };
897 
898  //template<typename Ch, typename Traits, typename Alloc, bool val>
899  //struct translator_between<std::basic_string<Ch, Traits, Alloc>, sc::XMLDataStream<const double, val> >
900  //{
901  // typedef sc::XMLDataStreamTranslator<const double> type;
902  //};
903 
904 
905 
906  }
907 }
908 
909 
910 
911 #endif /* _util_misc_xmlwriter_h */
sc::SCVector
The SCVector class is the abstract base class for double valued vectors.
Definition: abstract.h:97
sc::XMLDataStream
Definition: xmlwriter.h:137
sc::XMLWriter::run
void run()
Executes an action as specified in the derived class.
sc::XMLWritable
Definition: xml.h:44
sc::Ref
A template class that maintains references counts.
Definition: ref.h:361
sc::XMLDataStreamTranslator
Definition: xmlwriter.h:810
sc::Grid
The Grid class defines a finite regular Carthesian grid.
Definition: grid.h:35
sc::Runnable
The Runnable class is a DescribedClass with a pure virtual run member.
Definition: runnable.h:36
sc::XMLWriter
Definition: xmlwriter.h:215
sc::SCVector3
a 3-element version of SCVector
Definition: vector3.h:43
sc::ExEnv::out0
static std::ostream & out0()
Return an ostream that writes from node 0.
sc::deallocate
void deallocate(T *&array)
this version will set array to 0 upon return
Definition: consumableresources.h:452
sc::RefCount
The base class for all reference counted objects.
Definition: ref.h:192
sc::detail::TriangleWriter
Definition: xmlwriter.h:472
sc
Contains all MPQC code up to version 3.
Definition: mpqcin.h:14
sc::Units
The Units class is used to perform unit conversions.
Definition: units.h:38

Generated at Sun Jan 26 2020 23:24:02 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.8.16.