[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [4783] Support xml serialization (VS)
From: |
Greg Chicares |
Subject: |
[lmi-commits] [4783] Support xml serialization (VS) |
Date: |
Tue, 16 Mar 2010 01:57:54 +0000 |
Revision: 4783
http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=4783
Author: chicares
Date: 2010-03-16 01:57:53 +0000 (Tue, 16 Mar 2010)
Log Message:
-----------
Support xml serialization (VS)
Modified Paths:
--------------
lmi/trunk/ChangeLog
lmi/trunk/objects.make
Added Paths:
-----------
lmi/trunk/xml_serialize.hpp
lmi/trunk/xml_serialize_test.cpp
Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2010-03-16 01:56:25 UTC (rev 4782)
+++ lmi/trunk/ChangeLog 2010-03-16 01:57:53 UTC (rev 4783)
@@ -24403,3 +24403,16 @@
round_to.hpp
Add mc_enum<rounding_style> (VS).
+20100316T0156Z <address@hidden> [762]
+
+ xml_lmi.cpp
+ xml_lmi.hpp
+Add some capabilities that will soon become useful.
+
+20100316T0157Z <address@hidden> [762]
+
+ objects.make
+ xml_serialize.hpp [new file]
+ xml_serialize_test.cpp [new file]
+Support xml serialization (VS).
+
Modified: lmi/trunk/objects.make
===================================================================
--- lmi/trunk/objects.make 2010-03-16 01:56:25 UTC (rev 4782)
+++ lmi/trunk/objects.make 2010-03-16 01:57:53 UTC (rev 4783)
@@ -503,6 +503,7 @@
value_cast_test \
vector_test \
wx_new_test \
+ xml_serialize_test \
zero_test \
unit_test_targets := \
@@ -858,6 +859,14 @@
$(common_test_objects) \
wx_new_test.o \
+xml_serialize_test$(EXEEXT): \
+ $(common_test_objects) \
+ $(xmlwrapp_objects) \
+ facets.o \
+ timer.o \
+ xml_lmi.o \
+ xml_serialize_test.o \
+
zero_test$(EXEEXT): \
$(common_test_objects) \
null_stream.o \
Added: lmi/trunk/xml_serialize.hpp
===================================================================
--- lmi/trunk/xml_serialize.hpp (rev 0)
+++ lmi/trunk/xml_serialize.hpp 2010-03-16 01:57:53 UTC (rev 4783)
@@ -0,0 +1,176 @@
+// Serialization to and from xml.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifndef xml_serialize_hpp
+#define xml_serialize_hpp
+
+#include "config.hpp"
+
+#include "assert_lmi.hpp"
+#include "value_cast.hpp"
+#include "xml_lmi.hpp"
+
+#include <xmlwrapp/nodes_view.h>
+
+#include <string>
+#include <vector>
+
+/// Serialization to and from xml.
+
+namespace xml_serialize
+{
+/// Serialization for built-in and other streamable types.
+///
+/// This class template is intended to be specialized for other types.
+///
+/// Member functions to_xml() and from_xml() might return an xml
+/// element and a T, respectively, instead of taking them as
+/// arguments; but that would entail copy-construction overhead.
+///
+/// Free function templates might have been used instead, but a class
+/// template is more amenable to specialization.
+///
+/// value_cast<>() is already specialized for string-to-string
+/// conversions, both for efficiency and to ensure correct handling
+/// of strings with embedded whitespace.
+
+template<typename T>
+struct xml_io
+{
+ static void to_xml(xml::element& e, T const& t)
+ {
+ // XMLWRAPP !! Someday, this might be rewritten thus:
+ // e.set_content(value_cast<std::string>(t).c_str());
+ // but for now that doesn't work with embedded ampersands.
+
e.push_back(xml::node(xml::node::text(value_cast<std::string>(t).c_str())));
+ }
+
+ static void from_xml(xml::element const& e, T& t)
+ {
+ t = value_cast<T>(xml_lmi::get_content(e));
+ }
+};
+
+/// Serialization for sequences [23.1.1].
+///
+/// Derive publicly from this to use its implementation when
+/// specializing class template xml_io for a particular sequence.
+///
+/// from_xml() reads only <item> elements, ignoring other elements
+/// (and non-element nodes) that might have been added manually,
+/// e.g., as documentation.
+
+template<typename T>
+struct xml_sequence_io
+{
+ typedef typename T::value_type item_t;
+
+ static void to_xml(xml::element& e, T const& t)
+ {
+ LMI_ASSERT(e.elements("item").empty());
+ typedef typename T::const_iterator tci;
+ for(tci i = t.begin(); i != t.end(); ++i)
+ {
+ // This is equivalent to calling set_element();
+ // it's written out to avoid obscurity.
+ xml::element z("item");
+ xml_io<item_t>::to_xml(z, *i);
+ e.push_back(z);
+ }
+ }
+
+ static void from_xml(xml::element const& e, T& t)
+ {
+ LMI_ASSERT(t.empty());
+ xml::const_nodes_view const items(e.elements("item"));
+ typedef xml::const_nodes_view::const_iterator cnvi;
+ for(cnvi i = items.begin(); i != items.end(); ++i)
+ {
+ item_t z;
+ xml_io<item_t>::from_xml(*i, z);
+ t.push_back(z);
+ }
+ }
+};
+
+template<typename T>
+struct xml_io<std::vector<T> >
+ :public xml_sequence_io<std::vector<T> >
+{};
+
+/// Serialize a datum into a subelement of the given xml element.
+///
+/// Many elements should be unique: e.g.,
+/// <DateOfBirth>19990101</DateOfBirth>
+/// <DateOfBirth>19871230</DateOfBirth>
+/// is a semantic error because one's birthdate is single-valued;
+/// however, it's valid syntactically, and indeed class template
+/// xml_sequence_io must support multiple <item> elements. Therefore,
+/// parent.erase(name.c_str());
+/// would be incorrect here, and an assertion that it returns zero
+/// would fail. Semantic correctness is the responsibility of code
+/// that uses the present facility.
+
+template<typename T>
+void set_element(xml::element& parent, std::string const& name, T const& t)
+{
+ xml::element z(name.c_str());
+ xml_io<T>::to_xml(z, t);
+ parent.push_back(z);
+}
+
+/// Deserialize a datum from a subelement of the given xml element.
+///
+/// retrieve_element() throws if the element isn't found.
+
+template<typename T>
+void get_element(xml::element const& parent, std::string const& name, T& t)
+{
+ xml::node::const_iterator i = xml_lmi::retrieve_element(parent,
name.c_str());
+ xml_io<T>::from_xml(*i, t);
+}
+
+// Implementation note. These convenience wrappers are intended for
+// use outside this header. With early forward declarations, they
+// could replace some occurrences of 'xml_io<...>::[to|from]_xml'
+// above, but the benefit doesn't seem worth the loss of clarity.
+
+/// Convenience wrapper for serialization to xml.
+
+template<typename T>
+void to_xml(xml::element& e, T const& t)
+{
+ xml_io<T>::to_xml(e, t);
+}
+
+/// Convenience wrapper for deserialization from xml.
+
+template<typename T>
+void from_xml(xml::element const& e, T& t)
+{
+ xml_io<T>::from_xml(t, e);
+}
+} // Namespace xml_serialize.
+
+#endif // xml_serialize_hpp
+
Property changes on: lmi/trunk/xml_serialize.hpp
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:keywords
+ Id
Added: lmi/trunk/xml_serialize_test.cpp
===================================================================
--- lmi/trunk/xml_serialize_test.cpp (rev 0)
+++ lmi/trunk/xml_serialize_test.cpp 2010-03-16 01:57:53 UTC (rev 4783)
@@ -0,0 +1,218 @@
+// Serialization to and from xml--unit test.
+//
+// Copyright (C) 2010 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifdef __BORLANDC__
+# include "pchfile.hpp"
+# pragma hdrstop
+#endif // __BORLANDC__
+
+#include "xml_serialize.hpp"
+
+#include "miscellany.hpp" // lmi_array_size(),
stifle_warning_for_unused_variable()
+#include "test_tools.hpp"
+#include "timer.hpp"
+
+#include <string>
+#include <vector>
+
+// All /write.*/ functions save xml to this string.
+
+std::string dom_string;
+
+// Repetition count for /mete.*/ functions, tuned for speed and accuracy.
+
+int const number_of_elements = 20;
+
+// http://www.drpeppermuseum.com/Learn/10-2-4-Club.aspx
+
+int const dr_pepper[] = {10, 2, 4};
+
+// /[dsv]0/: constant values for /write.*/ functions.
+// /[dsv]1/: variables for /read.*/ functions.
+
+double const d0(2.718281828459045235360);
+std::string const s0("string with ampersand & embedded spaces");
+std::vector<int> const v0(dr_pepper, dr_pepper + lmi_array_size(dr_pepper));
+
+double d1;
+std::string s1;
+std::vector<int> v1;
+
+void write()
+{
+ xml_lmi::xml_document document("eraseme");
+ xml::element& root = document.root_node();
+ xml_serialize::set_element(root, "d", d0);
+ xml_serialize::set_element(root, "s", s0);
+ xml_serialize::set_element(root, "v", v0);
+ dom_string = document.str();
+}
+
+void read()
+{
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ xml_serialize::get_element(root, "d", d1);
+ xml_serialize::get_element(root, "s", s1);
+ xml_serialize::get_element(root, "v", v1);
+}
+
+void read_erroneous()
+{
+ float f1; // Erroneous because there's no <f> in the xml.
+
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ xml_serialize::get_element(root, "d", d1);
+ xml_serialize::get_element(root, "s", s1);
+ xml_serialize::get_element(root, "v", v1);
+ xml_serialize::get_element(root, "f", f1);
+}
+
+// These /mete_[write|read]/ functions are like write() and read()
+// except that they don't actually do anything: they serve only to
+// measure overhead.
+
+void mete_write()
+{
+ xml_lmi::xml_document document("eraseme");
+ xml::element& root = document.root_node();
+ stifle_warning_for_unused_variable(root);
+ dom_string = document.str();
+}
+
+void mete_read()
+{
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ stifle_warning_for_unused_variable(root);
+}
+
+// These /mete_._[write|read]/ functions are like write() and read()
+// except that they each test a single datatype repeatedly.
+
+void mete_s_write()
+{
+ xml_lmi::xml_document document("eraseme");
+ xml::element& root = document.root_node();
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ xml_serialize::set_element(root, "s", s0);
+ }
+ dom_string = document.str();
+}
+
+void mete_s_read()
+{
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ xml_serialize::get_element(root, "s", s1);
+ }
+}
+
+void mete_d_write()
+{
+ xml_lmi::xml_document document("eraseme");
+ xml::element& root = document.root_node();
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ xml_serialize::set_element(root, "d", d0);
+ }
+ dom_string = document.str();
+}
+
+void mete_d_read()
+{
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ xml_serialize::get_element(root, "d", d1);
+ }
+}
+
+void mete_v_write()
+{
+ xml_lmi::xml_document document("eraseme");
+ xml::element& root = document.root_node();
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ xml_serialize::set_element(root, "v", v0);
+ }
+ dom_string = document.str();
+}
+
+void mete_v_read()
+{
+ xml_lmi::dom_parser parser(dom_string.c_str(), dom_string.size());
+ xml::element const& root = parser.root_node("eraseme");
+ for(int j = 0; j < number_of_elements; ++j)
+ {
+ v1.clear();
+ xml_serialize::get_element(root, "v", v1);
+ }
+}
+
+int test_main(int, char*[])
+{
+ write();
+ read();
+
+ // Not every floating-point number would remain invariant through
+ // serialization, but the base of natural logarithms does: see the
+ // documentation for value_cast<>().
+ BOOST_TEST(d0 == d1);
+ BOOST_TEST_EQUAL(d0, d1);
+ BOOST_TEST(s0 == s1);
+ BOOST_TEST_EQUAL(s0, s1);
+ // BOOST_TEST_EQUAL(v0, v1); // No--couldn't display if not equal.
+ BOOST_TEST(v0 == v1);
+ BOOST_TEST_EQUAL(v0.size(), v1.size());
+
+ // Reading into a nonempty vector is forbidden because it probably
+ // indicates an error.
+ std::string not_empty("Assertion 't.empty()' failed.");
+ BOOST_TEST_THROW(read(), std::runtime_error, not_empty);
+ v1.clear();
+ read();
+
+ v1.clear();
+ std::string not_found("Required element 'f' not found.");
+ BOOST_TEST_THROW(read_erroneous(), std::runtime_error, not_found);
+
+ std::cout << " Speed tests...\n";
+ std::cout << " Write : " << TimeAnAliquot(mete_write ) << '\n';
+ std::cout << " Read : " << TimeAnAliquot(mete_read ) << '\n';
+ std::cout << " Write s : " << TimeAnAliquot(mete_s_write) << '\n';
+ std::cout << " Read s : " << TimeAnAliquot(mete_s_read ) << '\n';
+ std::cout << " Write d : " << TimeAnAliquot(mete_d_write) << '\n';
+ std::cout << " Read d : " << TimeAnAliquot(mete_d_read ) << '\n';
+ std::cout << " Write v : " << TimeAnAliquot(mete_v_write) << '\n';
+ std::cout << " Read v : " << TimeAnAliquot(mete_v_read ) << '\n';
+ std::cout << std::endl;
+
+ return 0;
+}
+
Property changes on: lmi/trunk/xml_serialize_test.cpp
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:keywords
+ Id
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [4783] Support xml serialization (VS),
Greg Chicares <=