MPQC 3.0.0-alpha
Loading...
Searching...
No Matches
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# ifdef __has_include
65# if __has_include(<boost/detail/endian.hpp>)
66# include <boost/detail/endian.hpp>
67# else
68# include <boost/endian.hpp>
69# endif
70# else
71# include <boost/endian.hpp>
72# endif
73# if defined(BOOST_LITTLE_ENDIAN)
74# define IS_BIG_ENDIAN false
75# elif defined(BOOST_BIG_ENDIAN)
76# define IS_BIG_ENDIAN true
77# else
78# include <arpa/inet.h>
79# define IS_BIG_ENDIAN htonl(47) == 47
80# endif
81#else
82# include <arpa/inet.h>
83# define IS_BIG_ENDIAN htonl(47) == 47
84#endif
85
86
87namespace sc {
88
89 using boost::property_tree::ptree;
90#if BOOST_VERSION >= 105600
91 typedef boost::property_tree::xml_writer_settings<std::string> xml_writer_settings;
92#else
93 typedef boost::property_tree::xml_writer_settings<char> xml_writer_settings;
94#endif
95
97
98 namespace parameter {
99 // Parameters for boost::parameter parameters are always wrapped in namespace
100 // sc::parameter in MPQC.
101
102 // Parameters for generic function that quickly writes an object to a given
103 // XML file; extremely useful for debugging and matching old code. These
104 // are basically just the keyval arguments to XMLWriter
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)
117 }
118
120
121 class SCVector3;
122 class Grid;
123 class Units;
124 class XMLWritable;
125 class SCVector;
126
128
129 namespace {
130 template<typename T, bool do_it>
131 struct destroy_data {
132 void operator()(T* data) const { };
133 };
134
135 template<typename T>
136 struct destroy_data<T, true> {
137 void operator()(T* data) const {
138 deallocate(data);
139 }
140 };
141
142 }
143
144 template<typename T, bool deallocate_when_destroyed=not std::is_const<T>::value>
146 private:
147 T* data_;
148 unsigned long n_;
149 bool human_readable_;
150 bool pretty_print_;
151
152 public:
154 T* data,
155 unsigned long n,
156 bool human_readable=false,
157 bool pretty_print=false
158 ) :
159 data_(data),
160 n_(n),
161 human_readable_(human_readable),
162 pretty_print_(pretty_print)
163 { }
164
166 destroy_data<T, deallocate_when_destroyed>()(data_);
167 }
168
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_; }
173
174 private:
175
176 };
177
178
180
181 class XMLWriter;
182
183 template <typename T>
184 typename boost::enable_if<
185 boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
186 ptree&
187 >::type
188 write_xml(
189 const Ref<T>& obj,
190 ptree& parent,
191 const XMLWriter& writer
192 );
193
194 template <typename T>
195 ptree&
196 write_xml(
197 const Ref<T>& obj,
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,
201 ptree&
202 >::type const& parent,
203 const XMLWriter& writer
204 );
205
206 ptree& write_xml(XMLWritable&, ptree&, const XMLWriter&);
207 ptree& write_xml(const SCVector3&, ptree&, const XMLWriter&);
208 ptree& write_xml(const SCVector&, ptree&, const XMLWriter&);
209 ptree& write_xml(const Grid&, ptree&, const XMLWriter&);
210 ptree& write_xml(const Units&, ptree&, const XMLWriter&);
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&);
214
215 template<typename Derived>
216 ptree& write_xml(const Eigen::MatrixBase<Derived>&, ptree&, const XMLWriter&);
217
219
220 // TODO gzip compression, turned on and off by the writer
221 // TODO write as data is received?
222 // TODO perfect forwarding of objects; make sure copies aren't happening
223 class XMLWriter : public Runnable {
224
225 protected:
226
227 std::ostream* out_;
228
229 ptree* current_root_;
230 std::stack<ptree*> pt_stack_;
231
232 bool delete_out_;
233 bool delete_pt_ = false;
234 bool compress_data_;
235 bool pretty_print_;
236 bool human_readable_;
237 bool fold_in_class_name_;
238 bool writing_done_ = false;
239
240 int pretty_print_spaces_;
241 char pretty_print_space_char_;
242 std::vector< Ref<XMLWritable> > data_;
243 xml_writer_settings write_settings_;
244
245 void init();
246
247 void init_filename(const std::string& filename);
248
249 std::string filename_;
250
251 public:
252
253 XMLWriter() = delete;
254
255 XMLWriter(const XMLWriter&) = delete;
256
257 XMLWriter(const Ref<KeyVal>& keyval);
258
259 XMLWriter(std::ostream& out=ExEnv::out0());
260
261 XMLWriter(ptree* pt, std::ostream& out=ExEnv::out0());
262
263 XMLWriter(const std::string& filename);
264
265 virtual ~XMLWriter();
266
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; }
271
272 template<typename T>
273 void
274 put_binary_data(
275 ptree& pt,
276 T* data,
277 long ndata,
278 bool preserve_data_pointer = false
279 ) const
280 {
281 assert(!compress_data_); // Not implemented
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);
286 }
287 else{
288 pt.put("<xmlattr>.ndata", ndata);
289 pt.put("<xmlattr>.human_readable", true);
290 }
291
292 if(preserve_data_pointer) {
293 XMLDataStream<const T> xds(const_cast<const T*>(data), ndata,
294 /* human_readable = */ human_readable_,
295 /* pretty_print = */ pretty_print_
296 );
297 pt.put_value(xds);
298 }
299 else {
300 XMLDataStream<T> xds(data, ndata,
301 /* human_readable = */ human_readable_,
302 /* pretty_print = */ pretty_print_
303 );
304 pt.put_value(xds);
305 }
306 }
307
308 template <typename T>
309 ptree& insert_child(
310 ptree& parent,
311 T&& obj
312 ) const
313 {
314 return this->write_to_xml(obj, parent);
315 }
316
317 template <typename T>
318 ptree& insert_child(
319 ptree& parent,
320 T&& obj,
321 std::string wrapper_name
322 ) const
323 {
324 // Wrap the object in a ptree named wrapper_name
325 ptree& child_tree = parent.add_child(wrapper_name, ptree());
326 this->write_to_xml(obj, child_tree);
327 return child_tree;
328 }
329
330 template <typename T, typename MapType>
331 ptree& insert_child(
332 ptree& parent,
333 T&& obj,
334 std::string wrapper_name,
335 const MapType& attrs
336 ) const
337 {
338 // Wrap the object in a ptree named 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);
343 }
344 return child_tree;
345 }
346
347 template <typename T, typename... Args>
348 ptree& insert_child_default(
349 T&& obj,
350 Args... args
351 ) const
352 {
353 assert(not writing_done_);
354 return insert_child(*current_root_, obj, args...);
355 }
356
357 void add_data(const Ref<XMLWritable>& datum) { data_.push_back(datum); }
358
359 void do_write();
360
361 void run();
362
363 template <typename T>
364 ptree& write_to_xml(T&& obj, ptree& parent) const
365 {
366 // Call the non-intrusive interface
367 return write_xml(std::forward<T>(obj), parent, *this);
368 }
369
370 template<typename T>
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>());
374 }
375
376 template<typename 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_);
380 }
381
382 //----------------------------------------------------------------------------//
383 // Transparent context for writing objects
384
385 void begin_writing_context(const std::string& root_name);
386
387 void end_writing_context();
388
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;
393
394 private:
395
396 template<typename T>
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);
400 }
401
402 template<typename T>
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);
405 }
406
407
408 };
409
411
412 template <typename T>
413 typename boost::enable_if<
414 boost::is_base_of<XMLWritable, typename boost::decay<T>::type>,
415 ptree&
416 >::type
417 write_xml(
418 const Ref<T>& obj,
419 ptree& parent,
420 const XMLWriter& writer
421 )
422 {
423 return obj->write_xml(parent, writer);
424 }
425
426 template <typename T>
427 ptree&
428 write_xml(
429 const Ref<T>& obj,
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,
433 ptree&
434 >::type const& parent,
435 const XMLWriter& writer
436 )
437 {
438 return write_xml(*obj, parent, writer);
439 }
440
441 template<typename Derived>
442 ptree& write_xml(const Eigen::MatrixBase<Derived>& obj, ptree& parent, const XMLWriter& writer)
443 {
444 typedef Eigen::MatrixBase<Derived> MatrixType;
445 typedef typename Eigen::internal::traits<Derived>::Scalar Scalar;
446
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)
456 );
457
458 // Just iterate over everything so we don't have to think about strides and such
459 Scalar* data = allocate<Scalar>(nouter*ninner);
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);
464 }
465 else {
466 data[i*ninner + j] = obj(j, i);
467 }
468 }
469 }
470
471 // Note: the XMLDataStream created by put_binary_data now owns
472 // the pointer 'data'
473 writer.put_binary_data(child.add_child("data", ptree()), data, nouter*ninner);
474 return child;
475 }
476
477 namespace detail {
478
479 template<typename Derived, unsigned int ViewMode>
480 struct TriangleWriter { };
481
482 template<typename Derived>
483 struct TriangleWriter<Derived, Eigen::Lower> {
484 ptree& operator()(
485 const Eigen::TriangularView<Derived, Eigen::Lower>& obj,
486 ptree& pt,
487 const XMLWriter& writer
488 ) const
489 {
490 const int nrows = obj.rows();
491 const int ncols = obj.cols();
492 if(nrows == ncols) {
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;
498 double* data = allocate<double>(ndata);
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);
503 ++data_spot;
504 }
505 }
506 // The XMLDataStream object created by this function call
507 // owns the pointer data after this.
508 writer.put_binary_data<double>(data_tree, data, ndata);
509 return my_tree;
510 }
511 else {
512 typedef Derived MatrixType;
513 // Just write the unraveled version
514
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());
521 double* data = allocate<double>(nrows*ncols);
522 double* data_spot = data;
523 for(int irow = 0; irow < nrows; ++irow) {
524 for(int icol = 0; icol < ncols; ++icol) {
525 if(icol <= irow) {
526 (*data_spot) = obj.coeff(irow, icol);
527 }
528 else if(icol < nrows) {
529 (*data_spot) = obj.coeff(icol, irow);
530 }
531 else {
532 (*data_spot) = 0.0;
533 }
534 ++data_spot;
535 }
536 }
537 // The XMLDataStream object created by this function call
538 // owns the pointer data after this.
539 writer.put_binary_data<double>(data_tree, data, nrows*ncols);
540 return child;
541 }
542 }
543
544 };
545
546 }
547
548 template<typename Derived, unsigned int ViewMode>
549 ptree& write_xml(const Eigen::TriangularView<Derived, ViewMode>& obj, ptree& parent, const XMLWriter& writer) {
550 return detail::TriangleWriter<Derived, ViewMode>()(obj, parent, writer);
551 }
552
553
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...>>
559 >::value
560 and
561 boost::mpl::and_<
562 boost::mpl::or_<
563 boost::is_integral<NumTypes>,
564 boost::is_floating_point<NumTypes>
565 >...
566 >::value,
567 ptree&
568 >::type
569 write_xml(
570 const Container<TupleType<NumTypes...>>& obj,
571 ptree& parent,
572 const XMLWriter& writer
573 )
574 {
575 typedef Container<TupleType<NumTypes...>> input_type;
576 typedef std::vector<TupleType<NumTypes...>> vect_type;
577
578 // Cheesy but effective way to do automatic type conversion without
579 // unnecessary copies
580 const auto& the_function = [](
581 const vect_type& obj,
582 ptree& parent,
583 const XMLWriter& writer
584 ) -> ptree&
585 {
586 ptree* child_ptr;
587 if(writer.fold_in_class_name()) {
588 parent.put("<xmlattr>.type", "std::vector<double>");
589 child_ptr = &(parent);
590 }
591 else{
592 ptree& tmp = parent.add_child("data", ptree());
593 child_ptr = &tmp;
594 }
595 ptree& child = *child_ptr;
596 writer.put_binary_data(child, obj.data(), obj.size(), true);
597 child.put("<xmlattr>.nperdatum", sizeof...(NumTypes));
598 return child;
599 };
600
601 return the_function(obj, parent, writer);
602 }
603
605
606
607
608 using boost::is_convertible;
609 namespace mpl = boost::mpl;
610
611 #define XMLWRITER_FILENAME_NOT_GIVEN "__FILENAME_NOT_GIVEN__"
612
613 // optional parameters mirroring the keyval contructor parameters for XMLWriter
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)
622
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 \
628 ); \
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));
636
637 BOOST_PARAMETER_FUNCTION(
638 (void), // Return type
639 write_to_xml_file, // Name of the function
640 sc::parameter::tag, // Namespace of the tag types
641
642 (required // required parameters
643 (object, *) // an object of any type. Will not compile if the
644 // object can't be written to XML by some means
645 )
646 (optional
647 XMLWRITER_KV_OPTIONAL_PARAMS
648 (root_name, // root_name is the name of the root node on the xml output
649 *(is_convertible<mpl::_, std::string>), std::string("mpqc")
650 )
651 )
652 )
653 {
654
655 XMLWRITER_CREATE_FROM_PARAMS(writer)
656
657 writer->begin_writing_context(std::string(root_name));
658 writer->write_to_xml(object);
659 writer->end_writing_context();
660 }
661
662
663 // Transparent context for writing
664 BOOST_PARAMETER_FUNCTION(
665 (void),
666 begin_xml_context,
667 parameter::tag,
668 (required
669 (name, *(is_convertible<mpl::_, std::string>))
670 )
671 (optional
672 XMLWRITER_KV_OPTIONAL_PARAMS
673 )
674 )
675 {
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);
682 }
683 else {
684 // Save the current writer, switch to new writer
685 XMLWriter::writer_stack.push(XMLWriter::current_writer);
686
687 XMLWRITER_CREATE_FROM_PARAMS(writer)
688
689 XMLWriter::current_writer = writer;
690 writer->begin_writing_context(tag_name);
691 }
692 }
693 else {
694 // TODO fail if there is an unclosed inner context that doesn't make sense
695 XMLWRITER_CREATE_FROM_PARAMS(writer)
696
697 XMLWriter::current_writer = writer;
698 writer->begin_writing_context(tag_name);
699 }
700
701 XMLWriter::context_name_stack.push(XMLWriter::current_context_name);
702 XMLWriter::current_context_name = tag_name;
703 }
704
705 // Transparent context for writing
706 BOOST_PARAMETER_FUNCTION(
707 (void),
708 end_xml_context,
709 parameter::tag,
710 (optional
711 (name, *(is_convertible<mpl::_, std::string>), XMLWRITER_FILENAME_NOT_GIVEN)
712 )
713 )
714 {
715 std::string tag_name = name;
716 if(
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()
720 ) {
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();
726 }
727 else{
728 XMLWriter::current_writer = 0;
729 }
730 }
731 }
732 else {
733 throw ProgrammingError("Mismatched transparent XML contexts", __FILE__, __LINE__);
734 }
735
736 XMLWriter::current_context_name = XMLWriter::context_name_stack.top();
737 XMLWriter::context_name_stack.pop();
738 }
739
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)
743 {
744 XMLWriter::current_writer->insert_child_default(object, tag_name);
745 }
746
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)
750 {
751 XMLWriter::current_writer->insert_child_default(object, tag_name, attrs);
752 }
753
754 BOOST_PARAMETER_FUNCTION(
755 (void),
756 write_as_xml,
757 parameter::tag,
758 (required
759 (name, *)
760 (object, *)
761 )
762 (optional
763 (attributes, *, false)
764 )
765 )
766 {
767 if(XMLWriter::current_writer.null()) {
768 throw ProgrammingError("No current XML context", __FILE__, __LINE__);
769 }
770 else{
771 std::string tag_name = name;
772 _write_as_xml_impl(object, tag_name, attributes);
773 }
774 }
775
776 template<typename Value=std::string>
777 using attrs = std::map<std::string, Value>;
778
780
781 namespace detail {
782 std::string
783 get_human_readable_data(
784 double* data,
785 long ndata,
786 int nperline=8,
787 int precision=8,
788 int width=15
789 );
790
791 std::string
792 get_human_readable_data(
793 int* data,
794 long ndata,
795 int nperline=8,
796 int precision=8, // ignored
797 int width=15
798 );
799
800 template<typename T>
801 std::string
802 get_human_readable_data(
803 T* data,
804 long ndata,
805 int nperline=8,
806 int precision=8,
807 int width=15
808 )
809 {
810 throw FeatureNotImplemented("get_human_readable_data", __FILE__, __LINE__);
811 return " "; // unreachable
812 }
813 }
814
816
817 template<typename T>
819 typedef std::string internal_type;
821
822 boost::optional<external_type> get_value(const internal_type& str)
823 {
824 if (!str.empty()) {
825 // Require the string to be aligned to the sizeof(T)
826 assert(str.length()*sizeof(char) % sizeof(T) == 0);
827
828 // Transfer the data to it's new home
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));
833 }
834 else {
835 return boost::optional<external_type>(boost::none);
836 }
837
838 }
839
840 boost::optional<internal_type> put_value(const external_type& xds)
841 {
842 if(xds.human_readable()){
843 return boost::optional<internal_type>(
844 detail::get_human_readable_data(
845 xds.data(),
846 xds.n()
847 )
848 );
849
850 }
851 else{
852 using namespace boost::archive::iterators;
853
854 typedef
855 base64_from_binary<
856 transform_width<const char*, 6, 8>
857 >
858 base64_text;
859 typedef insert_linebreaks<base64_text, 72> base64_text_linebreaks;
860
861 std::stringstream sstr;
862 if(xds.pretty_print()){
863 std::copy(
864 base64_text_linebreaks(xds.data()),
865 base64_text_linebreaks(xds.data() + xds.n()),
866 boost::archive::iterators::ostream_iterator<char>(sstr)
867 );
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"));
872 else
873 return boost::optional<internal_type>(internal_type("\n" + sstr.str() + "\n"));
874 }
875 else{
876 std::copy(
877 base64_text(xds.data()),
878 base64_text(xds.data() + xds.n()),
879 boost::archive::iterators::ostream_iterator<char>(sstr)
880 );
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() + "="));
885 else
886 return boost::optional<internal_type>(internal_type(sstr.str()));
887 }
888 }
889
890 }
891 };
892
893} // end namespace sc
894
896
897namespace boost {
898 namespace property_tree {
899
900 template<typename Ch, typename Traits, typename Alloc, typename T, bool val>
901 struct translator_between<std::basic_string<Ch, Traits, Alloc>, sc::XMLDataStream<T, val> >
902 {
904 };
905
906 //template<typename Ch, typename Traits, typename Alloc, bool val>
907 //struct translator_between<std::basic_string<Ch, Traits, Alloc>, sc::XMLDataStream<const double, val> >
908 //{
909 // typedef sc::XMLDataStreamTranslator<const double> type;
910 //};
911
912
913
914 }
915}
916
917
918
919#endif /* _util_misc_xmlwriter_h */
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 xml.h:44
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
STL namespace.
Definition xmlwriter.h:818
Definition xmlwriter.h:480

Generated at Wed Sep 25 2024 02:45:31 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.12.0.