lmi-commits
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]