diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-10-07 14:48:13 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-10-07 14:48:13 +0200 |
commit | 4f38adc11ab1a3a1ab2dd3f958c917182be7d71f (patch) | |
tree | fd4242b2fb5648536a6307a18442abfcaf280573 | |
parent | 0baca4b033509b6c4ebfabfb74bf6518c3b1182c (diff) |
Implement generation of clone functions
New test: clone.
36 files changed, 2734 insertions, 117 deletions
@@ -44,6 +44,10 @@ Version 3.2.0 Section 4.3, "Enumerations" in the Getting Started Guide for more information. + * New option, --generate-clone, triggers the generation of clone functions + for variable-length types. These functions allow you to make dynamically- + allocated copies of variable-length objects. + * New configuration parameter, XSDE_STL_ITERATOR, makes iterators provided by the mapping conform to the STL requirements. This feature requires working <iterator> header and allows you to use the standard diff --git a/dist/tests/cxx/hybrid/makefile b/dist/tests/cxx/hybrid/makefile index ddcf464..7e78d9f 100644 --- a/dist/tests/cxx/hybrid/makefile +++ b/dist/tests/cxx/hybrid/makefile @@ -30,7 +30,7 @@ dirs += binary/xdr endif ifeq ($(XSDE_PARSER_VALIDATION),y) -dirs += choice recursive +dirs += choice recursive clone endif endif # XSDE_IOSTREAM diff --git a/dist/tests/cxx/hybrid/nmakefile b/dist/tests/cxx/hybrid/nmakefile index 1127649..b31619b 100644 --- a/dist/tests/cxx/hybrid/nmakefile +++ b/dist/tests/cxx/hybrid/nmakefile @@ -30,7 +30,7 @@ dirs = $(dirs) binary/xdr !endif !if "$(XSDE_PARSER_VALIDATION)" == "y" -dirs = $(dirs) choice recursive +dirs = $(dirs) choice recursive clone !endif !endif # XSDE_IOSTREAM diff --git a/documentation/cxx/hybrid/guide/index.xhtml b/documentation/cxx/hybrid/guide/index.xhtml index 39d7e9b..7d33a4e 100644 --- a/documentation/cxx/hybrid/guide/index.xhtml +++ b/documentation/cxx/hybrid/guide/index.xhtml @@ -2024,10 +2024,21 @@ private: (see <a href="#3.8">Section 3.8, "Custom Allocators"</a>), the object model expects you to allocate such an object with operator <code>new</code> and will eventually delete it - with operator <code>delete</code>. You can also request generation - of detach functions with the <code>--generate-detach</code> compiler - option. These functions allow you to detach a variable-length - object from the object model. As an example, let us extend + with operator <code>delete</code>.</p> + + <p>If you wish to make copies of variable-length objects, then + you can request the generation of the object cloning functions + with the <code>--generate-clone</code> compiler + option. When this option is specified, each variable-length + type implements the <code>_clone()</code> function which returns + a dynamically-allocated copy of the object or <code>NULL</code> + if the allocation failed and C++ exceptions are disabled (see + <a href="#3.3">Section 3.3, "C++ Exceptions"</a>). </p> + + <p>You can also request generation of detach functions with the + <code>--generate-detach</code> compiler option. These functions + allow you to detach a variable-length object from the object model. + As an example, let us extend our <code>people.xsd</code> schema with the following type:</p> <pre class="xml"> @@ -2039,8 +2050,9 @@ private: </xs:complexType> </pre> - <p>If we compile it with XSD/e and specify the <code>--generate-detach</code> - option, we will get the following C++ class:</p> + <p>If we compile it with XSD/e and specify the + <code>--generate-clone</code> and <code>--generate-detach</code> + options, we will get the following C++ class:</p> <pre class="c++"> // staff (variable-length) @@ -2050,6 +2062,9 @@ class staff public: staff (); + staff* + _clone () const; + private: staff (const staff&); staff& operator= (const staff&); @@ -4143,7 +4158,9 @@ for (people::person_iterator i = ps.begin (); i != ps.end (); ++i) type is always variable-length which means objects of polymorphic types are allocated dynamically and are stored and passed around as pointers or references. A polymorphic type also defines a - virtual destructor which allows you to delete an instance of a + virtual <code>_clone()</code> function (see <a href="#4.2">Section 4.2, + "Memory Management"</a>) and a virtual destructor + which allow you to copy and delete an instance of a polymorphic type via a pointer to its base. The following code fragment shows how we can parse, access, modify, and serialize the above XML document:</p> @@ -4957,11 +4974,15 @@ namespace xml_schema public: void + assign (void* data, size_t size); + + void attach (void* data, size_t size, size_t capacity); void* detach (); + void swap (buffer&); @@ -5048,6 +5069,9 @@ namespace xml_schema public: error + assign (void* data, size_t size); + + error attach (void* data, size_t size, size_t capacity); void* diff --git a/documentation/xsde.1 b/documentation/xsde.1 index a4b55dc..4257882 100644 --- a/documentation/xsde.1 +++ b/documentation/xsde.1 @@ -1006,6 +1006,10 @@ documents. .IP "\fB\--suppress-enum\fR" Suppress the generation of the XML Schema enumeration to C++ enum mapping. +.IP "\fB\--generate-clone\fR" +Generate clone functions for variable-length types. These functions allow +you to make dynamically-allocated copies of variable-length objects. + .IP "\fB\--generate-detach\fR" Generate detach functions for elements and attributes of variable-length types. These functions, for example, allow you to move sub-trees in the diff --git a/documentation/xsde.xhtml b/documentation/xsde.xhtml index 859719e..9797ba9 100644 --- a/documentation/xsde.xhtml +++ b/documentation/xsde.xhtml @@ -870,6 +870,11 @@ <dd>Suppress the generation of the XML Schema enumeration to C++ enum mapping.</dd> + <dt><code><b>--generate-clone</b></code></dt> + <dd>Generate clone functions for variable-length types. These + functions allow you to make dynamically-allocated copies of + variable-length objects.</dd> + <dt><code><b>--generate-detach</b></code></dt> <dd>Generate detach functions for elements and attributes of variable-length types. These functions, for example, allow diff --git a/libxsde/xsde/cxx/buffer.cxx b/libxsde/xsde/cxx/buffer.cxx index d9102ae..4084cde 100644 --- a/libxsde/xsde/cxx/buffer.cxx +++ b/libxsde/xsde/cxx/buffer.cxx @@ -110,6 +110,58 @@ namespace xsde return true; } } + + void buffer:: + assign (void* data, size_t size) + { + capacity (size); + size_ = size; + + if (size_) + memcpy (data_, data, size_); + } + + struct buffer_guard + { + buffer_guard (buffer* p) : p_ (p) {} + + ~buffer_guard () + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete p_; +#else + if (p_ != 0) + { + p_->~buffer (); + cxx::free (p_); + } +#endif + } + + void + release () { p_ = 0; } + + private: + buffer* p_; + }; + + buffer* buffer:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + buffer* c = new buffer; +#else + // Default buffer c-tor cannot throw so we don't need alloc_guard. + // + buffer* c = static_cast<buffer*> (cxx::alloc (sizeof (buffer))); + new (c) buffer; +#endif + buffer_guard g (c); + _copy (*c); + g.release (); + return c; + } + #else buffer::error buffer:: capacity (size_t capacity, bool copy, bool* moved) @@ -156,6 +208,50 @@ namespace xsde return error_none; } + + buffer::error buffer:: + assign (void* data, size_t size) + { + if (error r = capacity (size)) + return r; + + size_ = size; + + if (size_) + memcpy (data_, data, size_); + + return error_none; + } + + buffer* buffer:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + buffer* c = new buffer; +#else + buffer* c = static_cast<buffer*> (cxx::alloc (sizeof (buffer))); +#endif + + if (c == 0) + return 0; + +#ifdef XSDE_CUSTOM_ALLOCATOR + new (c) buffer; +#endif + + if (!_copy (*c)) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete c; +#else + c->~buffer (); + cxx::free (c); +#endif + return 0; + } + + return c; + } #endif } } diff --git a/libxsde/xsde/cxx/buffer.hxx b/libxsde/xsde/cxx/buffer.hxx index 7ea1adf..2957a0a 100644 --- a/libxsde/xsde/cxx/buffer.hxx +++ b/libxsde/xsde/cxx/buffer.hxx @@ -60,6 +60,13 @@ namespace xsde #else void #endif + assign (void* data, size_t size); + +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif attach (void* data, size_t size, size_t capacity); void* @@ -68,6 +75,16 @@ namespace xsde void swap (buffer&); + buffer* + _clone () const; + +#ifndef XSDE_EXCEPTIONS + bool +#else + void +#endif + _copy (buffer&) const; + public: size_t capacity () const; diff --git a/libxsde/xsde/cxx/buffer.ixx b/libxsde/xsde/cxx/buffer.ixx index 2229396..d9c71eb 100644 --- a/libxsde/xsde/cxx/buffer.ixx +++ b/libxsde/xsde/cxx/buffer.ixx @@ -220,5 +220,21 @@ namespace xsde { return !(x == y); } + + // + // +#ifndef XSDE_EXCEPTIONS + inline bool buffer:: + _copy (buffer& c) const + { + return c.assign (data_, size_) == error_none; + } +#else + inline void buffer:: + _copy (buffer& c) const + { + c.assign (data_, size_); + } +#endif } } diff --git a/libxsde/xsde/cxx/guard.hxx b/libxsde/xsde/cxx/guard.hxx new file mode 100644 index 0000000..3190983 --- /dev/null +++ b/libxsde/xsde/cxx/guard.hxx @@ -0,0 +1,48 @@ +// file : xsde/cxx/guard.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSDE_CXX_GUARD_HXX +#define XSDE_CXX_GUARD_HXX + +#include <xsde/cxx/config.hxx> + +#ifdef XSDE_CUSTOM_ALLOCATOR +# include <xsde/cxx/allocator.hxx> +#endif + +namespace xsde +{ + namespace cxx + { +#ifdef XSDE_EXCEPTIONS + template <typename T> + struct guard + { + guard (T* p) : p_ (p) {} + + ~guard () + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete p_; +#else + if (p_ != 0) + { + p_->~T (); + cxx::free (p_); + } +#endif + } + + void + release () { p_ = 0; } + + private: + T* p_; + }; +#endif // XSDE_EXCEPTIONS + } +} + +#endif // XSDE_CXX_GUARD_HXX diff --git a/libxsde/xsde/cxx/hybrid/base.hxx b/libxsde/xsde/cxx/hybrid/base.hxx index 89431a2..a7b1e2a 100644 --- a/libxsde/xsde/cxx/hybrid/base.hxx +++ b/libxsde/xsde/cxx/hybrid/base.hxx @@ -10,6 +10,7 @@ #ifndef XSDE_STL # include <string.h> // strcmp +# include <xsde/cxx/strdupx.hxx> #endif #ifdef XSDE_CUSTOM_ALLOCATOR @@ -599,6 +600,26 @@ namespace xsde string_base& operator= (char* x) {base_value (x); return *this;} +#ifndef XSDE_EXCEPTIONS + bool +#else + void +#endif + _copy (string_base& c) const + { + char* x = strdupx (x_); + +#ifndef XSDE_EXCEPTIONS + if (x == 0) + return false; +#endif + c.base_value (x); + +#ifndef XSDE_EXCEPTIONS + return true; +#endif + } + protected: char* x_; }; diff --git a/libxsde/xsde/cxx/hybrid/sequence.cxx b/libxsde/xsde/cxx/hybrid/sequence.cxx index bf5f3c7..5293616 100644 --- a/libxsde/xsde/cxx/hybrid/sequence.cxx +++ b/libxsde/xsde/cxx/hybrid/sequence.cxx @@ -26,6 +26,51 @@ namespace xsde size_ = 0; } + +#ifdef XSDE_EXCEPTIONS + void data_sequence:: + copy (data_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + c.destructor_ = destructor_; + c.clone_ = clone_; + + c.reserve (size_); + + for (; c.size_ < size_; ++c.size_) + { + static_cast<void**> (c.data_)[c.size_] = + clone_ (static_cast<void**> (data_)[c.size_], c.size_); + } + } +#else + sequence_base::error data_sequence:: + copy (data_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + c.destructor_ = destructor_; + c.clone_ = clone_; + + if (error r = c.reserve (size_)) + return r; + + for (; c.size_ < size_; ++c.size_) + { + void* x = clone_ (static_cast<void**> (data_)[c.size_], c.size_); + + if (x == 0) + return error_no_memory; + + static_cast<void**> (c.data_)[c.size_] = x; + } + + return error_none; + } +#endif } } } diff --git a/libxsde/xsde/cxx/hybrid/sequence.hxx b/libxsde/xsde/cxx/hybrid/sequence.hxx index fa5c697..e21f219 100644 --- a/libxsde/xsde/cxx/hybrid/sequence.hxx +++ b/libxsde/xsde/cxx/hybrid/sequence.hxx @@ -128,6 +128,13 @@ namespace xsde void swap (pod_sequence&); + +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (pod_sequence&) const; }; // Sequence with fixed-length elements. @@ -230,6 +237,13 @@ namespace xsde void swap (fix_sequence&); +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (fix_sequence&) const; + private: static void move_ (void* dst, void* src, size_t n); @@ -831,6 +845,13 @@ namespace xsde void swap (var_sequence&); +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (var_sequence&) const; + #ifdef XSDE_EXCEPTIONS public: struct guard @@ -877,10 +898,14 @@ namespace xsde data_sequence (); typedef void (*destroy_func) (void* data, size_t pos); + typedef void* (*clone_func) (void* data, size_t pos); void destructor (destroy_func); + void + clone (clone_func); + public: iterator begin (); @@ -953,8 +978,16 @@ namespace xsde void swap (data_sequence&); +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (data_sequence&) const; + private: destroy_func destructor_; + clone_func clone_; }; } } diff --git a/libxsde/xsde/cxx/hybrid/sequence.ixx b/libxsde/xsde/cxx/hybrid/sequence.ixx index 1ec2a4c..e53b774 100644 --- a/libxsde/xsde/cxx/hybrid/sequence.ixx +++ b/libxsde/xsde/cxx/hybrid/sequence.ixx @@ -167,6 +167,13 @@ namespace xsde memcpy (data_, p, n * sizeof (T)); size_ = n; } + + template <typename T> + inline void pod_sequence<T>:: + copy (pod_sequence& c) const + { + c.assign (begin (), size ()); + } #else template <typename T> inline sequence_base::error pod_sequence<T>:: @@ -238,6 +245,13 @@ namespace xsde size_ = n; return error_none; } + + template <typename T> + inline sequence_base::error pod_sequence<T>:: + copy (pod_sequence& c) const + { + return c.assign (begin (), size ()); + } #endif // @@ -387,6 +401,13 @@ namespace xsde if (capacity_ < n) grow_ (n, sizeof (T), &move_); } + + template <typename T> + inline void fix_sequence<T>:: + copy (fix_sequence& c) const + { + c.assign (begin (), size ()); + } #else template <typename T> inline sequence_base::error fix_sequence<T>:: @@ -448,6 +469,13 @@ namespace xsde r = grow_ (n, sizeof (T), &move_); return r; } + + template <typename T> + inline sequence_base::error fix_sequence<T>:: + copy (fix_sequence& c) const + { + return c.assign (begin (), size ()); + } #endif // @@ -741,7 +769,7 @@ namespace xsde inline data_sequence:: data_sequence () - : destructor_ (0) + : destructor_ (0), clone_ (0) { } @@ -751,6 +779,12 @@ namespace xsde destructor_ = d; } + inline void data_sequence:: + clone (data_sequence::clone_func c) + { + clone_ = c; + } + inline size_t data_sequence:: max_size () const { diff --git a/libxsde/xsde/cxx/hybrid/sequence.txx b/libxsde/xsde/cxx/hybrid/sequence.txx index b79e9d5..5d7df7d 100644 --- a/libxsde/xsde/cxx/hybrid/sequence.txx +++ b/libxsde/xsde/cxx/hybrid/sequence.txx @@ -30,7 +30,9 @@ namespace xsde void fix_sequence<T>:: assign (const T* p, size_t n) { - clear (); + if (size_ != 0) + clear (); + reserve (n); for (; size_ < n; ++size_) @@ -41,7 +43,8 @@ namespace xsde sequence_base::error fix_sequence<T>:: assign (const T* p, size_t n) { - clear (); + if (size_ != 0) + clear (); if (error r = reserve (n)) return r; @@ -166,6 +169,47 @@ namespace xsde size_ = 0; } + +#ifdef XSDE_EXCEPTIONS + template <typename T> + void var_sequence<T>:: + copy (var_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + c.reserve (size_); + + for (; c.size_ < size_; ++c.size_) + { + static_cast<T**> (c.data_)[c.size_] = + static_cast<T**> (data_)[c.size_]->_clone (); + } + } +#else + template <typename T> + sequence_base::error var_sequence<T>:: + copy (var_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + if (error r = c.reserve (size_)) + return r; + + for (; c.size_ < size_; ++c.size_) + { + T* x = static_cast<T**> (data_)[c.size_]->_clone (); + + if (x == 0) + return error_no_memory; + + static_cast<T**> (c.data_)[c.size_] = x; + } + + return error_none; + } +#endif } } } diff --git a/libxsde/xsde/cxx/qname.cxx b/libxsde/xsde/cxx/qname.cxx index be196be..f1e4238 100644 --- a/libxsde/xsde/cxx/qname.cxx +++ b/libxsde/xsde/cxx/qname.cxx @@ -10,11 +10,83 @@ namespace xsde { namespace cxx { -#ifndef XSDE_EXCEPTIONS - qname::error qname:: + +#ifdef XSDE_EXCEPTIONS + + void qname:: + prefix_copy (const char* prefix) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete[] prefix_; #else + cxx::free (prefix_); +#endif + + if (prefix) + prefix_ = strdupx (prefix); + else + prefix_ = 0; + } + void qname:: + name_copy (const char* name) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete[] name_; +#else + cxx::free (name_); +#endif + + if (name) + name_ = strdupx (name); + else + name_ = 0; + } + + struct qname_guard + { + qname_guard (qname* p) : p_ (p) {} + + ~qname_guard () + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete p_; +#else + if (p_ != 0) + { + p_->~qname (); + cxx::free (p_); + } #endif + } + + void + release () { p_ = 0; } + + private: + qname* p_; + }; + + qname* qname:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + qname* c = new qname; +#else + // Default qname c-tor cannot throw so we don't need alloc_guard. + // + qname* c = static_cast<qname*> (cxx::alloc (sizeof (qname))); + new (c) qname; +#endif + qname_guard g (c); + _copy (*c); + g.release (); + return c; + } + +#else + + qname::error qname:: prefix_copy (const char* prefix) { #ifndef XSDE_CUSTOM_ALLOCATOR @@ -27,24 +99,16 @@ namespace xsde { prefix_ = strdupx (prefix); -#ifndef XSDE_EXCEPTIONS if (prefix_ == 0) return error_no_memory; -#endif } else prefix_ = 0; -#ifndef XSDE_EXCEPTIONS return error_none; -#endif } -#ifndef XSDE_EXCEPTIONS qname::error qname:: -#else - void qname:: -#endif name_copy (const char* name) { #ifndef XSDE_CUSTOM_ALLOCATOR @@ -57,17 +121,45 @@ namespace xsde { name_ = strdupx (name); -#ifndef XSDE_EXCEPTIONS if (name_ == 0) return error_no_memory; -#endif } else name_ = 0; -#ifndef XSDE_EXCEPTIONS return error_none; + } + + qname* qname:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + qname* c = new qname; +#else + qname* c = static_cast<qname*> (cxx::alloc (sizeof (qname))); +#endif + + if (c == 0) + return 0; + +#ifdef XSDE_CUSTOM_ALLOCATOR + new (c) qname; #endif + + if (!_copy (*c)) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete c; +#else + c->~qname (); + cxx::free (c); +#endif + return 0; + } + + return c; } + +#endif } } diff --git a/libxsde/xsde/cxx/qname.hxx b/libxsde/xsde/cxx/qname.hxx index 0b2d5f5..85b53bd 100644 --- a/libxsde/xsde/cxx/qname.hxx +++ b/libxsde/xsde/cxx/qname.hxx @@ -81,6 +81,16 @@ namespace xsde char* name_detach (); + qname* + _clone () const; + +#ifndef XSDE_EXCEPTIONS + bool +#else + void +#endif + _copy (qname&) const; + private: char* prefix_; char* name_; diff --git a/libxsde/xsde/cxx/qname.ixx b/libxsde/xsde/cxx/qname.ixx index f449ef3..7a374c6 100644 --- a/libxsde/xsde/cxx/qname.ixx +++ b/libxsde/xsde/cxx/qname.ixx @@ -124,6 +124,24 @@ namespace xsde return r; } +#ifdef XSDE_EXCEPTIONS + inline void qname:: + _copy (qname& c) const + { + c.prefix_copy (prefix_); + c.name_copy (name_); + } +#else + inline bool qname:: + _copy (qname& c) const + { + if (c.prefix_copy (prefix_) || c.name_copy (name_)) + return false; + + return true; + } +#endif + // // inline bool diff --git a/libxsde/xsde/cxx/string-sequence-stl.cxx b/libxsde/xsde/cxx/string-sequence-stl.cxx index 255b341..2fd8a02 100644 --- a/libxsde/xsde/cxx/string-sequence-stl.cxx +++ b/libxsde/xsde/cxx/string-sequence-stl.cxx @@ -5,6 +5,10 @@ #include <xsde/cxx/string-sequence-stl.hxx> +#ifdef XSDE_CUSTOM_ALLOCATOR +# include <xsde/cxx/allocator.hxx> +#endif + namespace xsde { namespace cxx @@ -20,6 +24,115 @@ namespace xsde } #ifdef XSDE_EXCEPTIONS + void string_sequence:: + copy (string_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + c.reserve (size_); + + for (; c.size_ < size_; ++c.size_) + { + new (static_cast<std::string*> (c.data_) + c.size_) std::string ( + static_cast<std::string*> (data_)[c.size_]); + } + } + + struct string_sequence_guard + { + string_sequence_guard (string_sequence* p) : p_ (p) {} + + ~string_sequence_guard () + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete p_; +#else + if (p_ != 0) + { + p_->~string_sequence (); + cxx::free (p_); + } +#endif + } + + void + release () { p_ = 0; } + + private: + string_sequence* p_; + }; + + string_sequence* string_sequence:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + string_sequence* c = new string_sequence; +#else + // Default string_sequence c-tor cannot throw so we don't need + // alloc_guard. + // + string_sequence* c = static_cast<string_sequence*> ( + cxx::alloc (sizeof (string_sequence))); + new (c) string_sequence; +#endif + string_sequence_guard g (c); + _copy (*c); + g.release (); + return c; + } +#else + sequence_base::error string_sequence:: + copy (string_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + if (error r = c.reserve (size_)) + return r; + + for (; c.size_ < size_; ++c.size_) + { + new (static_cast<std::string*> (c.data_) + c.size_) std::string ( + static_cast<std::string*> (data_)[c.size_]); + } + + return error_none; + } + + string_sequence* string_sequence:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + string_sequence* c = new string_sequence; +#else + string_sequence* c = static_cast<string_sequence*> ( + cxx::alloc (sizeof (string_sequence))); +#endif + + if (c == 0) + return 0; + +#ifdef XSDE_CUSTOM_ALLOCATOR + new (c) string_sequence; +#endif + + if (!_copy (*c)) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete c; +#else + c->~string_sequence (); + cxx::free (c); +#endif + return 0; + } + + return c; + } +#endif + +#ifdef XSDE_EXCEPTIONS struct guard { guard (std::string* p, size_t& n) : p_ (p), n_ (n) {} diff --git a/libxsde/xsde/cxx/string-sequence-stl.hxx b/libxsde/xsde/cxx/string-sequence-stl.hxx index 305fd0d..5e75ad8 100644 --- a/libxsde/xsde/cxx/string-sequence-stl.hxx +++ b/libxsde/xsde/cxx/string-sequence-stl.hxx @@ -106,6 +106,23 @@ namespace xsde void swap (string_sequence&); +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (string_sequence&) const; + + string_sequence* + _clone () const; + +#ifndef XSDE_EXCEPTIONS + bool +#else + void +#endif + _copy (string_sequence&) const; + private: static void move_ (void* dst, void* src, size_t n); diff --git a/libxsde/xsde/cxx/string-sequence-stl.ixx b/libxsde/xsde/cxx/string-sequence-stl.ixx index 55e3d5d..ae09d04 100644 --- a/libxsde/xsde/cxx/string-sequence-stl.ixx +++ b/libxsde/xsde/cxx/string-sequence-stl.ixx @@ -134,8 +134,15 @@ namespace xsde reserve (size_t n) { if (capacity_ < n) - grow_ (n, sizeof (std::string*), &move_); + grow_ (n, sizeof (std::string), &move_); } + + inline void string_sequence:: + _copy (string_sequence& c) const + { + copy (c); + } + #else inline sequence_base::error string_sequence:: push_back (const std::string& x) @@ -193,6 +200,12 @@ namespace xsde r = grow_ (n, sizeof (std::string), &move_); return r; } + + inline bool string_sequence:: + _copy (string_sequence& c) const + { + return copy (c) == error_none; + } #endif inline bool diff --git a/libxsde/xsde/cxx/string-sequence.cxx b/libxsde/xsde/cxx/string-sequence.cxx index 5387e79..63944fb 100644 --- a/libxsde/xsde/cxx/string-sequence.cxx +++ b/libxsde/xsde/cxx/string-sequence.cxx @@ -34,6 +34,64 @@ namespace xsde static_cast<char**> (data_)[size_++] = strdupx (cs); } + + void string_sequence:: + copy (string_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + c.reserve (size_); + + for (; c.size_ < size_; ++c.size_) + { + static_cast<char**> (c.data_)[c.size_] = + strdupx (static_cast<char**> (data_)[c.size_]); + } + } + + struct string_sequence_guard + { + string_sequence_guard (string_sequence* p) : p_ (p) {} + + ~string_sequence_guard () + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete p_; +#else + if (p_ != 0) + { + p_->~string_sequence (); + cxx::free (p_); + } +#endif + } + + void + release () { p_ = 0; } + + private: + string_sequence* p_; + }; + + string_sequence* string_sequence:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + string_sequence* c = new string_sequence; +#else + // Default string_sequence c-tor cannot throw so we don't need + // alloc_guard. + // + string_sequence* c = static_cast<string_sequence*> ( + cxx::alloc (sizeof (string_sequence))); + new (c) string_sequence; +#endif + string_sequence_guard g (c); + _copy (*c); + g.release (); + return c; + } #else string_sequence::error string_sequence:: push_back_copy (const char* cs) @@ -55,6 +113,59 @@ namespace xsde return r; } + + sequence_base::error string_sequence:: + copy (string_sequence& c) const + { + if (c.size_ != 0) + c.clear (); + + if (error r = c.reserve (size_)) + return r; + + for (; c.size_ < size_; ++c.size_) + { + char* x = strdupx (static_cast<char**> (data_)[c.size_]); + + if (x == 0) + return error_no_memory; + + static_cast<char**> (c.data_)[c.size_] = x; + } + + return error_none; + } + + string_sequence* string_sequence:: + _clone () const + { +#ifndef XSDE_CUSTOM_ALLOCATOR + string_sequence* c = new string_sequence; +#else + string_sequence* c = static_cast<string_sequence*> ( + cxx::alloc (sizeof (string_sequence))); +#endif + + if (c == 0) + return 0; + +#ifdef XSDE_CUSTOM_ALLOCATOR + new (c) string_sequence; +#endif + + if (!_copy (*c)) + { +#ifndef XSDE_CUSTOM_ALLOCATOR + delete c; +#else + c->~string_sequence (); + cxx::free (c); +#endif + return 0; + } + + return c; + } #endif bool diff --git a/libxsde/xsde/cxx/string-sequence.hxx b/libxsde/xsde/cxx/string-sequence.hxx index c9a33e4..a94418a 100644 --- a/libxsde/xsde/cxx/string-sequence.hxx +++ b/libxsde/xsde/cxx/string-sequence.hxx @@ -123,6 +123,23 @@ namespace xsde void swap (string_sequence&); + +#ifndef XSDE_EXCEPTIONS + error +#else + void +#endif + copy (string_sequence&) const; + + string_sequence* + _clone () const; + +#ifndef XSDE_EXCEPTIONS + bool +#else + void +#endif + _copy (string_sequence&) const; }; bool diff --git a/libxsde/xsde/cxx/string-sequence.ixx b/libxsde/xsde/cxx/string-sequence.ixx index b902bd7..b74adf2 100644 --- a/libxsde/xsde/cxx/string-sequence.ixx +++ b/libxsde/xsde/cxx/string-sequence.ixx @@ -172,6 +172,12 @@ namespace xsde if (capacity_ < n) grow_ (n, sizeof (char*), 0); } + + inline void string_sequence:: + _copy (string_sequence& c) const + { + copy (c); + } #else inline sequence_base::error string_sequence:: push_back (char* x) @@ -244,6 +250,12 @@ namespace xsde r = grow_ (n, sizeof (char*), 0); return r; } + + inline bool string_sequence:: + _copy (string_sequence& c) const + { + return copy (c) == error_none; + } #endif inline char* string_sequence:: diff --git a/tests/cxx/hybrid/clone/driver.cxx b/tests/cxx/hybrid/clone/driver.cxx new file mode 100644 index 0000000..5d044ca --- /dev/null +++ b/tests/cxx/hybrid/clone/driver.cxx @@ -0,0 +1,79 @@ +// file : tests/cxx/hybrid/clone/driver.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +// Test _clone() functionality. +// + +#include <assert.h> +#include <iostream> + +#include "test.hxx" +#include "test-pimpl.hxx" +#include "test-simpl.hxx" + +using namespace std; +using namespace test; + +void +data_destructor (void* p, size_t) +{ + delete static_cast<int*> (p); +} + +void* +data_clone (void* p, size_t) +{ + return new int (*static_cast<int*> (p)); +} + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " test.xml" << endl; + return 1; + } + + // Parse. + // + root_paggr root_p; + + xml_schema::document_pimpl doc_p ( + root_p.root_parser (), + root_p.root_namespace (), + root_p.root_name ()); + + root_p.pre (); + doc_p.parse (argv[1]); + type* r = root_p.post (); + + r->complex ().custom_data ().destructor (&data_destructor); + r->complex ().custom_data ().clone (&data_clone); + r->complex ().custom_data ().push_back (new int (123)); + + type* c = r->_clone (); + delete r; + + assert (c->complex ().custom_data ().size () == 1); + assert (*static_cast<int*> (c->complex ().custom_data ()[0]) == 123); + + // Serialize. + // + root_saggr root_s; + + xml_schema::document_simpl doc_s ( + root_s.root_serializer (), + root_s.root_namespace (), + root_s.root_name ()); + + doc_s.add_prefix ("t", "test"); + + root_s.pre (*c); + doc_s.serialize (cout, xml_schema::document_simpl::pretty_print); + root_s.post (); + + delete c; +} diff --git a/tests/cxx/hybrid/clone/makefile b/tests/cxx/hybrid/clone/makefile new file mode 100644 index 0000000..7138869 --- /dev/null +++ b/tests/cxx/hybrid/clone/makefile @@ -0,0 +1,109 @@ +# file : tests/cxx/hybrid/clone/makefile +# author : Boris Kolpackov <boris@codesynthesis.com> +# copyright : Copyright (c) 2006-2010 Code Synthesis Tools CC +# license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make + +xsd := test.xsd +cxx := driver.cxx + +obj := $(addprefix $(out_base)/,\ +$(cxx:.cxx=.o) \ +$(xsd:.xsd=.o) \ +$(xsd:.xsd=-pskel.o) \ +$(xsd:.xsd=-pimpl.o) \ +$(xsd:.xsd=-sskel.o) \ +$(xsd:.xsd=-simpl.o)) + +dep := $(obj:.o=.o.d) + +xsde.l := $(out_root)/libxsde/xsde/xsde.l +xsde.l.cpp-options := $(out_root)/libxsde/xsde/xsde.l.cpp-options + +driver := $(out_base)/driver +test := $(out_base)/.test +dist := $(out_base)/.dist +dist-win := $(out_base)/.dist-win +clean := $(out_base)/.clean + + +# Build. +# +$(driver): $(obj) $(xsde.l) + +$(obj) $(dep): $(xsde.l.cpp-options) + +genf := $(xsd:.xsd=.hxx) $(xsd:.xsd=.cxx) \ + $(xsd:.xsd=-pskel.hxx) $(xsd:.xsd=-pskel.cxx) \ + $(xsd:.xsd=-pimpl.hxx) $(xsd:.xsd=-pimpl.cxx) \ + $(xsd:.xsd=-sskel.hxx) $(xsd:.xsd=-sskel.cxx) \ + $(xsd:.xsd=-simpl.hxx) $(xsd:.xsd=-simpl.cxx) + +gen := $(addprefix $(out_base)/,$(genf)) + +$(gen): $(out_root)/xsde/xsde +$(gen): xsde := $(out_root)/xsde/xsde +$(gen) $(dist) $(dist-win): xsde_options += --generate-parser \ +--generate-serializer --generate-aggregate --generate-clone \ +--custom-data complex + +$(call include-dep,$(dep)) + +# Convenience alias for default target. +# +$(out_base)/: $(driver) + + +# Test. +# +$(test): driver := $(driver) +$(test): $(driver) $(src_base)/test-000.xml $(src_base)/test-000.std + $(call message,test $$1,$$1 $(src_base)/test-000.xml | diff -u $(src_base)/test-000.std -,$(driver)) + + +# Dist. +# +$(dist) $(dist-win): opt := -src $(src_base) -cmd cxx-hybrid -xsd "$(xsd)" \ +-cxx "$(cxx)" -gen "$(genf)" -opt "$(xsde_options)" -out $(dist_prefix) + +$(dist): + $(call message,install $(src_base),$(scf_root)/dist $(opt)) + +$(dist-win): + $(call message,install $(src_base),$(scf_root)/dist -win $(opt)) + + +# Clean. +# +$(clean): $(driver).o.clean \ + $(addsuffix .cxx.clean,$(obj)) \ + $(addsuffix .cxx.clean,$(dep)) \ + $(addprefix $(out_base)/,$(xsd:.xsd=.cxx.xsd.clean)) + + +# Generated .gitignore. +# +ifeq ($(out_base),$(src_base)) +$(gen): | $(out_base)/.gitignore +$(driver): | $(out_base)/.gitignore + +$(out_base)/.gitignore: files := driver $(genf) +$(clean): $(out_base)/.gitignore.clean + +$(call include,$(bld_root)/git/gitignore.make) +endif + + +# How to. +# +$(call include,$(bld_root)/cxx/o-e.make) +$(call include,$(bld_root)/cxx/cxx-o.make) +$(call include,$(bld_root)/cxx/cxx-d.make) +$(call include,$(scf_root)/xsde/hybrid/xsd-cxx.make) + + +# Dependencies. +# +$(call import,$(src_root)/xsde/makefile) +$(call import,$(src_root)/libxsde/xsde/makefile) diff --git a/tests/cxx/hybrid/clone/test-000.std b/tests/cxx/hybrid/clone/test-000.std new file mode 100644 index 0000000..f50ea2f --- /dev/null +++ b/tests/cxx/hybrid/clone/test-000.std @@ -0,0 +1,71 @@ +<t:root xmlns:t="test"> + <complex af="123" afixed="abc" av="abc def"> + <f>123</f> + <v>abc def ghq</v> + <of>123</of> + <ov>abc def ghq</ov> + <pod>1</pod> + <pod>2</pod> + <pod>3</pod> + <fix> + <x>1</x> + <y>1</y> + </fix> + <fix> + <x>2</x> + <y>2</y> + </fix> + <fix> + <x>3</x> + <y>3</y> + </fix> + <var>a1 b1 c1</var> + <var>a2 b2 c2</var> + <var>a3 b3 c3</var> + <str>aaa</str> + <str>bbb</str> + <str>ccc</str> + <cv>abc def ghq</cv> + </complex> + <all> + <f>123</f> + <v>abc def ghq</v> + <of>123</of> + <ov>abc def ghq</ov> + </all> + <sequence> + <f>123</f> + <v>abc def ghq</v> + <f>123</f> + <v>abc def ghq</v> + <c1v>abc def ghq</c1v> + <c2f>123</c2f> + </sequence> + <choice> + <cf>123</cf> + </choice> + <choice> + <cv>abc def ghq</cv> + </choice> + <choice> + <f>123</f> + <v>abc def ghq</v> + <f>123</f> + <v>abc def ghq</v> + </choice> + <fixder> + <x>1</x> + <y>1</y> + <v>abc def ghq</v> + </fixder> + <varder> + <x>1</x> + <y>abc def ghq</y> + <f>123</f> + </varder> + <strder v="abc def ghq">str str</strder> + <list>abc def ghq</list> + <union>abc</union> + <enum>c</enum> + <enumder>b</enumder> +</t:root>
\ No newline at end of file diff --git a/tests/cxx/hybrid/clone/test-000.xml b/tests/cxx/hybrid/clone/test-000.xml new file mode 100644 index 0000000..c10c1b7 --- /dev/null +++ b/tests/cxx/hybrid/clone/test-000.xml @@ -0,0 +1,79 @@ +<t:root xmlns:t="test"> + <complex af="123" av="abc def"> + <f>123</f> + <v>abc def ghq</v> + <of>123</of> + <ov>abc def ghq</ov> + + <pod>1</pod> + <pod>2</pod> + <pod>3</pod> + + <fix><x>1</x><y>1</y></fix> + <fix><x>2</x><y>2</y></fix> + <fix><x>3</x><y>3</y></fix> + + <var>a1 b1 c1</var> + <var>a2 b2 c2</var> + <var>a3 b3 c3</var> + + <str>aaa</str> + <str>bbb</str> + <str>ccc</str> + + <cv>abc def ghq</cv> + </complex> + + <all> + <f>123</f> + <v>abc def ghq</v> + <of>123</of> + <ov>abc def ghq</ov> + </all> + + <sequence> + <f>123</f> + <v>abc def ghq</v> + <f>123</f> + <v>abc def ghq</v> + + <c1v>abc def ghq</c1v> + + <c2f>123</c2f> + </sequence> + + <choice> + <cf>123</cf> + </choice> + + <choice> + <cv>abc def ghq</cv> + </choice> + + <choice> + <f>123</f> + <v>abc def ghq</v> + <f>123</f> + <v>abc def ghq</v> + </choice> + + <fixder> + <x>1</x> + <y>1</y> + <v>abc def ghq</v> + </fixder> + + <varder> + <x>1</x> + <y>abc def ghq</y> + <f>123</f> + </varder> + + <strder v="abc def ghq">str str</strder> + + <list>abc def ghq</list> + <union>abc</union> + <enum>c</enum> + <enumder>b</enumder> + +</t:root> diff --git a/tests/cxx/hybrid/clone/test.xsd b/tests/cxx/hybrid/clone/test.xsd new file mode 100644 index 0000000..cc4bc12 --- /dev/null +++ b/tests/cxx/hybrid/clone/test.xsd @@ -0,0 +1,148 @@ +<?xml version="1.0"?> +<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:t="test" targetNamespace="test"> + + <complexType name="fix"> + <sequence> + <element name="x" type="int"/> + <element name="y" type="int"/> + </sequence> + </complexType> + + <complexType name="var"> + <sequence> + <element name="x" type="int"/> + <element name="y" type="NMTOKENS"/> + </sequence> + </complexType> + + <complexType name="all"> + <all minOccurs="0"> + <element name="f" type="int"/> + <element name="v" type="NMTOKENS"/> + <element name="of" type="int" minOccurs="0"/> + <element name="ov" type="NMTOKENS" minOccurs="0"/> + </all> + </complexType> + + <complexType name="sequence"> + <sequence> + <sequence maxOccurs="unbounded"> + <element name="f" type="int"/> + <element name="v" type="NMTOKENS"/> + </sequence> + <choice> + <element name="c1f" type="int"/> + <element name="c1v" type="NMTOKENS"/> + </choice> + <choice minOccurs="0"> + <element name="c2f" type="int"/> + <element name="c2v" type="NMTOKENS"/> + </choice> + </sequence> + </complexType> + + <complexType name="choice"> + <choice> + <choice> + <element name="cf" type="int"/> + <element name="cv" type="NMTOKENS"/> + </choice> + <sequence maxOccurs="unbounded"> + <element name="f" type="int"/> + <element name="v" type="NMTOKENS"/> + </sequence> + </choice> + </complexType> + + <complexType name="complex"> + <sequence> + <element name="f" type="int"/> + <element name="v" type="NMTOKENS"/> + <element name="of" type="int" minOccurs="0"/> + <element name="ov" type="NMTOKENS" minOccurs="0"/> + <element name="pod" type="int" maxOccurs="unbounded"/> + <element name="fix" type="t:var" maxOccurs="unbounded"/> + <element name="var" type="NMTOKENS" maxOccurs="unbounded"/> + <element name="str" type="string" maxOccurs="unbounded"/> + <choice> + <element name="cf" type="int"/> + <element name="cv" type="NMTOKENS"/> + </choice> + </sequence> + <attribute name="af" type="int" use="required"/> + <attribute name="av" type="NMTOKENS" default="abc"/> + <attribute name="afixed" type="NMTOKENS" default="abc"/> + </complexType> + + <complexType name="fixder"> + <complexContent> + <extension base="t:fix"> + <sequence> + <element name="v" type="NMTOKENS"/> + </sequence> + </extension> + </complexContent> + </complexType> + + <complexType name="varder"> + <complexContent> + <extension base="t:var"> + <sequence> + <element name="f" type="int"/> + </sequence> + </extension> + </complexContent> + </complexType> + + <complexType name="strder"> + <simpleContent> + <extension base="string"> + <attribute name="v" type="NMTOKENS"/> + </extension> + </simpleContent> + </complexType> + + <simpleType name="list"> + <list itemType="string"/> + </simpleType> + + <simpleType name="union"> + <union memberTypes="int string"/> + </simpleType> + + <simpleType name="enum"> + <restriction base="string"> + <enumeration value="a"/> + <enumeration value="b"/> + <enumeration value="c"/> + </restriction> + </simpleType> + + <simpleType name="enumder"> + <restriction base="t:enum"> + <enumeration value="a"/> + <enumeration value="b"/> + </restriction> + </simpleType> + + <complexType name="type"> + <sequence> + <element name="complex" type="t:complex"/> + <element name="all" type="t:all"/> + <element name="sequence" type="t:sequence"/> + <element name="choice" type="t:choice" maxOccurs="unbounded"/> + + <element name="fixder" type="t:fixder"/> + <element name="varder" type="t:varder"/> + <element name="strder" type="t:strder"/> + + <element name="list" type="t:list"/> + <element name="union" type="t:union"/> + <element name="enum" type="t:enum"/> + <element name="enumder" type="t:enumder"/> + </sequence> + </complexType> + + <element name="root" type="t:type"/> + +</schema> diff --git a/tests/cxx/hybrid/makefile b/tests/cxx/hybrid/makefile index 8fb3f3f..88d89a2 100644 --- a/tests/cxx/hybrid/makefile +++ b/tests/cxx/hybrid/makefile @@ -10,7 +10,8 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make # all_tests := sequences polymorphism iterator built-in default enumeration \ -iso8859-1 list recursive test-template union binary/cdr binary/xdr choice +iso8859-1 list recursive test-template union binary/cdr binary/xdr choice \ +clone build_tests := sequences @@ -40,7 +41,7 @@ build_tests += binary/xdr endif ifeq ($(xsde_parser_validation),y) -build_tests += choice recursive +build_tests += choice recursive clone endif endif # xsde_iostream diff --git a/xsde/cxx/hybrid/cli.hxx b/xsde/cxx/hybrid/cli.hxx index 5de1692..5d691d6 100644 --- a/xsde/cxx/hybrid/cli.hxx +++ b/xsde/cxx/hybrid/cli.hxx @@ -36,6 +36,7 @@ namespace CXX extern Key suppress_serializer_val; extern Key omit_default_attributes; extern Key suppress_enum; + extern Key generate_clone; extern Key generate_detach; extern Key generate_insertion; extern Key generate_extraction; @@ -127,6 +128,7 @@ namespace CXX suppress_serializer_val, Boolean, omit_default_attributes, Boolean, suppress_enum, Boolean, + generate_clone, Boolean, generate_detach, Boolean, generate_insertion, Cult::Containers::Vector<NarrowString>, generate_extraction, Cult::Containers::Vector<NarrowString>, diff --git a/xsde/cxx/hybrid/elements.cxx b/xsde/cxx/hybrid/elements.cxx index fe5c97e..b8c109a 100644 --- a/xsde/cxx/hybrid/elements.cxx +++ b/xsde/cxx/hybrid/elements.cxx @@ -40,6 +40,7 @@ namespace CXX poly_code (ops.value<CLI::generate_polymorphic> ()), poly_runtime (poly_code || ops.value<CLI::runtime_polymorphic> ()), reset (!ops.value<CLI::suppress_reset> ()), + clone (ops.value<CLI::generate_clone> ()), detach (ops.value<CLI::generate_detach> ()), mixin (ops.value<CLI::reuse_style_mixin> ()), tiein (!mixin), diff --git a/xsde/cxx/hybrid/elements.hxx b/xsde/cxx/hybrid/elements.hxx index 60211e8..7bd8bd1 100644 --- a/xsde/cxx/hybrid/elements.hxx +++ b/xsde/cxx/hybrid/elements.hxx @@ -45,6 +45,7 @@ namespace CXX poly_code (c.poly_code), poly_runtime (c.poly_runtime), reset (c.reset), + clone (c.clone), detach (c.detach), typeinfo (c.typeinfo), mixin (c.mixin), @@ -76,6 +77,7 @@ namespace CXX poly_code (c.poly_code), poly_runtime (c.poly_runtime), reset (c.reset), + clone (c.clone), detach (c.detach), typeinfo (c.typeinfo), mixin (c.mixin), @@ -594,6 +596,7 @@ namespace CXX Boolean poly_code; Boolean poly_runtime; Boolean reset; + Boolean clone; Boolean detach; Boolean typeinfo; Boolean mixin; @@ -2060,6 +2063,73 @@ namespace CXX // // + struct TypeClone: TypeOpsBase, Context + { + TypeClone (Context& c) + : Context (c) + { + } + + // Copy member from 'this' to 'c'. + // + Void + dispatch (SemanticGraph::Node& type, SemanticGraph::Member& member) + { + member_ = &member; + Traversal::NodeBase::dispatch (type); + } + + protected: + virtual Void + type (SemanticGraph::Type& t) + { + String const& name (ename (*member_)); + + os << "{" + << fq_name (t) << "* m = this->" << name << " ()._clone ();"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + + virtual Void + fund_type (SemanticGraph::Type& t) + { + type (t); + } + + virtual Void + string_type (SemanticGraph::Type&) + { + // We can only get here if STL is disabled. + // + String const& name (ename (*member_)); + + os << "{" + << "char* m = ::xsde::cxx::strdupx (this->" << name << " ());"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + + private: + SemanticGraph::Member* member_; + }; + + // + // struct TypeForward: Traversal::Type, Context { TypeForward (Context& c) diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx index 0ccbb91..ee39079 100644 --- a/xsde/cxx/hybrid/generator.cxx +++ b/xsde/cxx/hybrid/generator.cxx @@ -124,6 +124,7 @@ namespace CXX extern Key suppress_serializer_val = "suppress-serializer-val"; extern Key omit_default_attributes = "omit-default-attributes"; extern Key suppress_enum = "suppress-enum"; + extern Key generate_clone = "generate-clone"; extern Key generate_detach = "generate-detach"; extern Key generate_insertion = "generate-insertion"; extern Key generate_extraction = "generate-extraction"; @@ -271,6 +272,11 @@ namespace CXX << " enumeration to C++ enum mapping." << endl; + e << "--generate-clone" << endl + << " Generate clone functions for variable-length\n" + << " types." + << endl; + e << "--generate-detach" << endl << " Generate detach functions for elements and\n" << " attributes of variable-length types." diff --git a/xsde/cxx/hybrid/tree-header.cxx b/xsde/cxx/hybrid/tree-header.cxx index 7e748bb..c596ab0 100644 --- a/xsde/cxx/hybrid/tree-header.cxx +++ b/xsde/cxx/hybrid/tree-header.cxx @@ -112,6 +112,13 @@ namespace CXX << name << " (" << vt << ");" << endl; + // _clone + // + if (!fl && clone) + os << (poly ? "virtual " : "") << name << "*" << endl + << "_clone () const;" + << endl; + // value (value_type) // if (!base_enum) @@ -197,6 +204,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << name << "&) const;" + << endl; + if (!base_enum || cd) os << "private:" << endl; @@ -274,15 +288,22 @@ namespace CXX // c-tor // os << "public:" << endl - << name << " ();"; + << name << " ();" + << endl; + + // _clone + // + if (clone) + os << (poly ? "virtual " : "") << name << "*" << endl + << "_clone () const;" + << endl; // d-tor // if (poly) os << "virtual" << endl - << "~" << name << " ();"; - - os << endl; + << "~" << name << " ();" + << endl; // Custom data. // @@ -335,6 +356,13 @@ namespace CXX << endl; } + // _copy + // + if (clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << name << "&) const;" + << endl; + if (cd) { os << "private:" << endl @@ -401,7 +429,15 @@ namespace CXX // c-tor // - os << name << " ();"; + os << name << " ();" + << endl; + + // _clone + // + if (!fl && clone) + os << (poly ? "virtual " : "") << name << "*" << endl + << "_clone () const;" + << endl; // d-tor // @@ -521,6 +557,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << name << "&) const;" + << endl; + if (stl) { os << "private:" << endl @@ -634,7 +677,7 @@ namespace CXX belongs_ >> *this; } - // Type alignment ranking (the high the rank, the stricter + // Type alignment ranking (the higher the rank, the stricter // the alignment requirements): // // char 1 @@ -1315,7 +1358,7 @@ namespace CXX traverse (SemanticGraph::Attribute& a) { os << "// " << comment (a.name ()) << endl - << "// " << endl; + << "//" << endl; Boolean def (a.default_p ()); Boolean fix (a.fixed_p ()); @@ -1413,7 +1456,7 @@ namespace CXX traverse (SemanticGraph::Element& e) { os << "// " << comment (e.name ()) << endl - << "// " << endl; + << "//" << endl; String const& name (ename (e)); SemanticGraph::Type& t (e.type ()); @@ -1535,22 +1578,33 @@ namespace CXX os << "// " << comment (name) << " (" << (fl ? "fixed-length" : "variable-length") << ")" << endl - << "// " << endl; + << "//" << endl; os << "class " << type << "{"; - // c-tor & d-tor + // c-tor // os << "public:" << endl << type << " ();" - << "~" << type << " ();"; + << endl; + + // _clone + // + if (!fl && clone) + os << type << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + os << "~" << type << " ();" + << endl; // copy c-tor & operator= // if (!fl) - os << endl - << "private:" << endl; + os << "private:" << endl; os << type << " (const " << type << "&);" << type << "& operator= (const " << type << "&);" @@ -1596,6 +1650,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << type << "&) const;" + << endl; + os << "private:" << endl; All::contains (a, contains_data_); @@ -1739,22 +1800,33 @@ namespace CXX os << "// " << comment (name) << " (" << (fl ? "fixed-length" : "variable-length") << ")" << endl - << "// " << endl; + << "//" << endl; os << "class " << type << "{"; - // c-tor & d-tor + // c-tor // os << "public:" << endl << type << " ();" - << "~" << type << " ();"; + << endl; + + // _clone + // + if (!fl && clone) + os << type << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + os << "~" << type << " ();" + << endl; // copy c-tor & operator= // if (!fl) - os << endl - << "private:" << endl; + os << "private:" << endl; os << type << " (const " << type << "&);" << type << "& operator= (const " << type << "&);" @@ -1766,7 +1838,7 @@ namespace CXX else { os << "// " << comment (name) << endl - << "// " << endl; + << "//" << endl; } String const& arm_tag (earm_tag (c)); @@ -1838,6 +1910,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << type << "&) const;" + << endl; + os << "private:" << endl << "union" << "{"; @@ -1967,22 +2046,33 @@ namespace CXX os << "// " << comment (name) << " (" << (fl ? "fixed-length" : "variable-length") << ")" << endl - << "// " << endl; + << "//" << endl; os << "class " << type << "{"; - // c-tor & d-tor + // c-tor // os << "public:" << endl << type << " ();" - << "~" << type << " ();"; + << endl; + + // _clone + // + if (!fl && clone) + os << type << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + os << "~" << type << " ();" + << endl; // copy c-tor & operator= // if (!fl) - os << endl - << "private:" << endl; + os << "private:" << endl; os << type << " (const " << type << "&);" << type << "& operator= (const " << type << "&);" @@ -2056,6 +2146,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << type << "&) const;" + << endl; + os << "private:" << endl << "union" << "{"; @@ -2190,22 +2287,33 @@ namespace CXX os << "// " << comment (name) << " (" << (fl ? "fixed-length" : "variable-length") << ")" << endl - << "// " << endl; + << "//" << endl; os << "class " << type << "{"; - // c-tor & d-tor + // c-tor // os << "public:" << endl << type << " ();" - << "~" << type << " ();"; + << endl; + + // _clone + // + if (!fl && clone) + os << type << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + os << "~" << type << " ();" + << endl; // copy c-tor & operator= // if (!fl) - os << endl - << "private:" << endl; + os << "private:" << endl; os << type << " (const " << type << "&);" << type << "& operator= (const " << type << "&);" @@ -2251,6 +2359,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << type << "&) const;" + << endl; + os << "private:" << endl; Sequence::contains (s, contains_data_); @@ -2372,22 +2487,33 @@ namespace CXX os << "// " << comment (name) << " (" << (fl ? "fixed-length" : "variable-length") << ")" << endl - << "// " << endl; + << "//" << endl; os << "class " << type << "{"; - // c-tor & d-tor + // c-tor // os << "public:" << endl << type << " ();" - << "~" << type << " ();"; + << endl; + + // _clone + // + if (!fl && clone) + os << type << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + os << "~" << type << " ();" + << endl; // copy c-tor & operator= // if (!fl) - os << endl - << "private:" << endl; + os << "private:" << endl; os << type << " (const " << type << "&);" << type << "& operator= (const " << type << "&);" @@ -2431,6 +2557,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << type << "&) const;" + << endl; + os << "private:" << endl; Sequence::contains (s, contains_data_); @@ -2533,7 +2666,7 @@ namespace CXX Traversal::ContainsParticle& contains_data_; }; - struct Complex : Traversal::Complex, Context + struct Complex: Traversal::Complex, Context { Complex (Context& c) : Context (c), @@ -2646,20 +2779,28 @@ namespace CXX // c-tor // os << "public:" << endl - << name << " ();"; - - // d-tor - // - if (!restriction || poly) - os << (poly ? "virtual\n" : "") << "~" << name << " ();"; + << name << " ();" + << endl; // copy c-tor & operator= (public) // if (fl && !restriction) os << name << " (const " << name << "&);" - << name << "& operator= (const " << name << "&);"; + << name << "& operator= (const " << name << "&);" + << endl; - os << endl; + // _clone + // + if (!fl && clone) + os << (poly ? "virtual " : "") << name << "*" << endl + << "_clone () const;" + << endl; + + // d-tor + // + if (!restriction || poly) + os << (poly ? "virtual\n" : "") << "~" << name << " ();" + << endl; if (!restriction) { @@ -2720,6 +2861,13 @@ namespace CXX << endl; } + // _copy + // + if (!fl && clone) + os << (exceptions ? "void" : "bool") << endl + << "_copy (" << name << "&) const;" + << endl; + if (!restriction || cd) os << "private:" << endl; diff --git a/xsde/cxx/hybrid/tree-source.cxx b/xsde/cxx/hybrid/tree-source.cxx index 5887d32..33995c5 100644 --- a/xsde/cxx/hybrid/tree-source.cxx +++ b/xsde/cxx/hybrid/tree-source.cxx @@ -32,7 +32,10 @@ namespace CXX struct Enumeration: Traversal::Enumeration, Context { Enumeration (Context& c, Traversal::Complex& complex) - : Context (c), complex_ (complex), enumerator_ (c) + : Context (c), + complex_ (complex), + base_name_ (c, TypeName::base), + enumerator_ (c) { names_ >> enumerator_; } @@ -129,6 +132,123 @@ namespace CXX << "}"; } } + + // _clone + // + if (clone && !fixed_length (e)) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << name << "::" << endl + << "_copy (" << name << "& c) const" + << "{"; + + // Copy the base or enum value. + // + if (base_enum) + { + SemanticGraph::Type& b (e.inherits ().base ()); + + if (fixed_length (b)) + { + os << "static_cast< "; + base_name_.dispatch (b); + os << "& > (c) = *this;"; + } + else + { + os << "const "; + base_name_.dispatch (b); + os << "& b = *this;"; + + if (exceptions) + os << "b._copy (c);"; + else + os << "if (!b._copy (c))" << endl + << "return false;" + << endl; + } + } + else + { + String const& m (ec.get<String> ("value-member")); + os << "c." << m << " = this->" << m << ";"; + } + + // Copy custom data. + // + if (ec.count ("cd-name")) + { + String const& m (ecd_member (e)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << name << "* " << name << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << name << "* c = new " << name << ";"; + else + os << name << "* c = static_cast< " << name << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << name << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << name << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << name << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << name << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } } virtual Void @@ -140,6 +260,8 @@ namespace CXX private: Traversal::Complex& complex_; + TypeName base_name_; + Traversal::Names names_; Enumerator enumerator_; }; @@ -147,7 +269,7 @@ namespace CXX struct List : Traversal::List, Context { List (Context& c) - : Context (c) + : Context (c), base_name_ (c, TypeName::seq) { } @@ -162,12 +284,16 @@ namespace CXX if (!name) return; - if (polymorphic (l)) - { + Boolean poly (polymorphic (l)); + SemanticGraph::Context& lc (l.context ()); + + if (poly || clone) os << "// " << comment (l.name ()) << endl << "//" << endl << endl; + if (poly) + { // d-tor // os << name << "::" << endl @@ -214,7 +340,108 @@ namespace CXX << "}"; } } + + // _clone + // + if (clone) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << name << "::" << endl + << "_copy (" << name << "& c) const" + << "{"; + + // Copy the base. + // + os << "const "; + base_name_.dispatch (l.argumented ().type ()); + os << "& b = *this;"; + + if (exceptions) + os << "b.copy (c);"; + else + os << "if (b.copy (c))" << endl + << "return false;" + << endl; + + // Copy custom data. + // + if (lc.count ("cd-name")) + { + String const& m (ecd_member (l)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << name << "* " << name << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << name << "* c = new " << name << ";"; + else + os << name << "* c = static_cast< " << name << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << name << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << name << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << name << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << name << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } } + + private: + TypeName base_name_; }; // @@ -238,13 +465,14 @@ namespace CXX return; Boolean poly (polymorphic (u)); + SemanticGraph::Context& uc (u.context ()); + + os << "// " << comment (u.name ()) << endl + << "//" << endl + << endl; if (!stl || poly) { - os << "// " << comment (u.name ()) << endl - << "//" << endl - << endl; - // d-tor // os << name << "::" << endl @@ -302,6 +530,108 @@ namespace CXX << "}"; } } + + // _clone + // + if (clone && !fixed_length (u)) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << name << "::" << endl + << "_copy (" << name << "& c) const" + << "{"; + + // Copy the value. + // + String const& m (uc.get<String> ("value-member")); + + if (stl) + os << "c." << m << " = this->" << m << ";"; + else + { + os << "c." << m << " = ::xsde::cxx::strdupx (this->" << m << ");"; + + if (!exceptions) + os << endl + << "if (c." << m << " == 0)" << endl + << "return false;" + << endl; + } + + // Copy custom data. + // + if (uc.count ("cd-name")) + { + String const& m (ecd_member (u)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << name << "* " << name << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << name << "* c = new " << name << ";"; + else + os << name << "* c = static_cast< " << name << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << name << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << name << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << name << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << name << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } } }; @@ -1379,6 +1709,324 @@ namespace CXX }; // + // Clone. + // + + struct AttributeClone: Traversal::Attribute, Context + { + AttributeClone (Context& c) + : Context (c), clone_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Attribute& a) + { + if (!a.fixed_p ()) + { + String const& name (ename (a)); + SemanticGraph::Type& t (a.type ()); + + Boolean opt (a.optional_p () && !a.default_p ()); + + if (opt) + os << "if (this->" << epresent (a) << " ())"; + + if (fixed_length (t)) + os << (opt ? "\n" : "") + << "c." << name << " (this->" << name << " ());" + << endl; + else + clone_.dispatch (t, a); + } + } + + private: + TypeClone clone_; + }; + + + struct ElementClone: Traversal::Element, Context + { + ElementClone (Context& c) + : Context (c), clone_ (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + String const& name (ename (e)); + + if (e.max () != 1) + { + if (exceptions) + os << "this->" << name << " ().copy (c." << name << " ());" + << endl; + else + os << "if (this->" << name << " ().copy (c." << name << " ()))" << endl + << "return false;" + << endl; + } + else + { + SemanticGraph::Type& t (e.type ()); + + Boolean opt (e.min () == 0); + + if (opt) + os << "if (this->" << epresent (e) << " ())"; + + if (fixed_length (t)) + os << (opt ? "\n" : "") + << "c." << name << " (this->" << name << " ());" + << endl; + else + clone_.dispatch (t, e); + } + } + + private: + TypeClone clone_; + }; + + struct AllClone: Traversal::All, Context + { + AllClone (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::All& a) + { + // For the all compositor, maxOccurs=1 and minOccurs={0,1} + // and it can only contain particles. + // + if (a.min () == 0) + { + String const& name (ename (a)); + + os << "if (this->" << epresent (a) << " ())"; + + if (fixed_length (a)) + os << endl + << "c." << name << " (this->" << name << " ());" + << endl; + else + { + os << "{" + << etype (a) << "* m = this->" << name << " ()._clone ();"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + } + else + All::contains (a); + } + }; + + struct SequenceInSequenceClone: Traversal::Sequence, Context + { + SequenceInSequenceClone (Context& c) + : Context (c) + { + } + + virtual Void + traverse (SemanticGraph::Sequence& s) + { + if (s.max () != 1) + { + String const& name (ename (s)); + + if (exceptions) + os << "this->" << name << " ().copy (c." << name << " ());" + << endl; + else + os << "if (this->" << name << " ().copy (c." << name << " ()))" << endl + << "return false;" + << endl; + } + else if (s.min () == 0) + { + String const& name (ename (s)); + + os << "if (this->" << epresent (s) << " ())"; + + if (fixed_length (s)) + os << endl + << "c." << name << " (this->" << name << " ());" + << endl; + else + { + os << "{" + << etype (s) << "* m = this->" << name << " ()._clone ();"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + } + else + Sequence::contains (s); + } + }; + + struct ParticleInChoiceClone: ElementClone, Traversal::Compositor + { + ParticleInChoiceClone (Context& c) + : ElementClone (c) + { + } + + virtual Void + traverse (SemanticGraph::Element& e) + { + os << "case " << etag (e) << ":" + << "{"; + + ElementClone::traverse (e); + + os << "break;" + << "}"; + } + + virtual Void + traverse (SemanticGraph::Compositor& c) + { + // In choice there are no inline compositors. + // + os << "case " << etag (c) << ":" + << "{"; + + String const& name (ename (c)); + + if (c.max () != 1) + { + if (exceptions) + os << "this->" << name << " ().copy (c." << name << " ());"; + else + os << "if (this->" << name << " ().copy (c." << name << " ()))" << endl + << "return false;"; + } + else + { + Boolean opt (c.min () == 0); + + if (opt) + os << "if (this->" << epresent (c) << " ())"; + + if (fixed_length (c)) + os << (opt ? "\n" : "") + << "c." << name << " (this->" << name << " ());" + << endl; + else + { + os << "{" + << etype (c) << "* m = this->" << name << " ()._clone ();"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + } + + os << "break;" + << "}"; + } + }; + + struct ChoiceInSequenceClone: Traversal::Choice, Context + { + ChoiceInSequenceClone (Context& c) + : Context (c), particle_ (c) + { + contains_particle_ >> particle_; + } + + virtual Void + traverse (SemanticGraph::Choice& c) + { + if (c.max () != 1) + { + String const& name (ename (c)); + + if (exceptions) + os << "this->" << name << " ().copy (c." << name << " ());" + << endl; + else + os << "if (this->" << name << " ().copy (c." << name << " ()))" << endl + << "return false;" + << endl; + } + else if (c.min () == 0) + { + String const& name (ename (c)); + + os << "if (this->" << epresent (c) << " ())"; + + if (fixed_length (c)) + os << endl + << "c." << name << " (this->" << name << " ());" + << endl; + else + { + os << "{" + << etype (c) << "* m = this->" << name << " ()._clone ();"; + + if (!exceptions) + os << endl + << "if (m == 0)" << endl + << "return false;" + << endl; + + os << "c." << name << " (m);" + << "}"; + } + } + else + { + // Inline choice. + // + String const& arm (earm (c)); + + os << "c." << arm << " (this->" << arm << " ());" + << endl + << "switch (this->" << arm << " ())" + << "{"; + + Choice::contains (c, contains_particle_); + + os << "default:" << endl + << "break;" + << "}"; + } + } + + private: + ParticleInChoiceClone particle_; + Traversal::ContainsParticle contains_particle_; + }; + + // // Nested classes. // @@ -1388,12 +2036,14 @@ namespace CXX Traversal::ContainsParticle& contains_ctor, Traversal::ContainsParticle& contains_dtor, Traversal::ContainsParticle& contains_copy, - Traversal::ContainsParticle& contains_assign) + Traversal::ContainsParticle& contains_assign, + Traversal::ContainsParticle& contains_clone) : Context (c), contains_ctor_ (contains_ctor), contains_dtor_ (contains_dtor), contains_copy_ (contains_copy), - contains_assign_ (contains_assign) + contains_assign_ (contains_assign), + contains_clone_ (contains_clone) { } @@ -1403,57 +2053,147 @@ namespace CXX // For the all compositor, maxOccurs=1 and minOccurs={0,1} // and it can only contain particles. // - if (a.min () == 0) - { - String const& type (etype (a)); - String const& scope (Context::scope (a)); + if (a.min () != 0) + return; + + Boolean fl (fixed_length (a)); + String const& type (etype (a)); + String const& scope (Context::scope (a)); + + // c-tor + // + os << scope << "::" << type << "::" << endl + << type << " ()" + << "{"; + + All::contains (a, contains_ctor_); + + os << "}"; - // c-tor + // d-tor + // + os << scope << "::" << type << "::" << endl + << "~" << type << " ()" + << "{"; + + All::contains (a, contains_dtor_); + + os << "}"; + + if (fl) + { + // copy c-tor // os << scope << "::" << type << "::" << endl - << type << " ()" - << "{"; + << type << " (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; - All::contains (a, contains_ctor_); + All::contains (a, contains_copy_); os << "}"; - // d-tor + // operator= // - os << scope << "::" << type << "::" << endl - << "~" << type << " ()" + os << scope << "::" << type << "& " << scope << "::" << + type << "::" << endl + << "operator= (const " << type << "& x)" + << "{" + << "XSDE_UNUSED (x);"; + + All::contains (a, contains_assign_); + + os << "return *this;" + << "}"; + } + + // _clone + // + if (!fl && clone) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << scope << "::" << + type << "::" << endl + << "_copy (" << type << "& c) const" << "{"; - All::contains (a, contains_dtor_); + All::contains (a, contains_clone_); + + // Copy custom data. + // + if (a.context ().count ("cd-name")) + { + String const& m (ecd_member (a)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; os << "}"; - if (fixed_length (a)) + // + // _clone + // + + os << scope << "::" << type << "* " << scope << "::" << + type << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << type << "* c = new " << type << ";"; + else + os << type << "* c = static_cast< " << type << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << type << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) { - // copy c-tor - // - os << scope << "::" << type << "::" << endl - << type << " (const " << type << "& x)" - << "{" - << "XSDE_UNUSED (x);"; + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; - All::contains (a, contains_copy_); + os << "new (c) " << type << ";"; - os << "}"; + if (exceptions) + os << "ag.release ();"; + } - // operator= - // - os << scope << "::" << type << "& " << scope << "::" << - type << "::" << endl - << "operator= (const " << type << "& x)" - << "{" - << "XSDE_UNUSED (x);"; + if (exceptions) + os << "::xsde::cxx::guard< " << type << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; - All::contains (a, contains_assign_); + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << type << " ();" + << "::xsde::cxx::free (c);"; - os << "return *this;" + os << "return 0;" << "}"; } + + os << "return c;" + << "}"; } } @@ -1462,6 +2202,7 @@ namespace CXX Traversal::ContainsParticle& contains_dtor_; Traversal::ContainsParticle& contains_copy_; Traversal::ContainsParticle& contains_assign_; + Traversal::ContainsParticle& contains_clone_; }; struct Choice: Traversal::Choice, Context @@ -1475,12 +2216,14 @@ namespace CXX particle_free_ (c, ChoiceParticle::free), particle_alloc_ (c, ChoiceParticle::alloc), particle_copy_ (c, ChoiceParticle::copy), - particle_assign_ (c, ChoiceParticle::assign) + particle_assign_ (c, ChoiceParticle::assign), + particle_clone_ (c) { contains_free_ >> particle_free_; contains_alloc_ >> particle_alloc_; contains_copy_ >> particle_copy_; contains_assign_ >> particle_assign_; + contains_clone_ >> particle_clone_; } virtual Void @@ -1499,6 +2242,8 @@ namespace CXX String const& scope (Context::scope (c)); + Boolean fl (fixed_length (c)); + // c-tor () // os << scope << "::" << type << "::" << endl @@ -1517,7 +2262,7 @@ namespace CXX arm_tag << " (" << bad_tag << "));" << "}"; - if (fixed_length (c)) + if (fl) { // copy c-tor // @@ -1586,6 +2331,104 @@ namespace CXX << "}"; Choice::contains (c, contains_func_); + + // _clone + // + if (!fl && clone) + { + // + // _copy + // + String const& arm (earm (c)); + + os << (exceptions ? "void " : "bool ") << scope << "::" << + type << "::" << endl + << "_copy (" << type << "& c) const" + << "{" + << "c." << arm << " (this->" << arm << " ());" + << endl + << "switch (this->" << arm << " ())" + << "{"; + + Choice::contains (c, contains_clone_); + + os << "default:" << endl + << "break;" + << "}"; + + // Copy custom data. + // + if (c.context ().count ("cd-name")) + { + String const& m (ecd_member (c)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << scope << "::" << type << "* " << scope << "::" << + type << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << type << "* c = new " << type << ";"; + else + os << type << "* c = static_cast< " << type << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << type << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << type << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << type << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << type << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } } Choice::contains (c); @@ -1606,6 +2449,9 @@ namespace CXX ChoiceParticle particle_assign_; Traversal::ContainsParticle contains_assign_; + + ParticleInChoiceClone particle_clone_; + Traversal::ContainsParticle contains_clone_; }; @@ -1617,6 +2463,7 @@ namespace CXX Traversal::ContainsParticle& contains_dtor, Traversal::ContainsParticle& contains_copy, Traversal::ContainsParticle& contains_assign, + Traversal::ContainsParticle& contains_clone, Traversal::ContainsParticle& contains_func) : Context (c), in_choice_ (in_choice), @@ -1624,6 +2471,7 @@ namespace CXX contains_dtor_ (contains_dtor), contains_copy_ (contains_copy), contains_assign_ (contains_assign), + contains_clone_ (contains_clone), contains_func_ (contains_func) { } @@ -1639,6 +2487,8 @@ namespace CXX String const& type (etype (s)); String const& scope (Context::scope (s)); + Boolean fl (fixed_length (s)); + // c-tor () // os << scope << "::" << type << "::" << endl @@ -1659,7 +2509,7 @@ namespace CXX os << "}"; - if (fixed_length (s)) + if (fl) { // copy c-tor // @@ -1686,6 +2536,95 @@ namespace CXX << "}"; } + // _clone + // + if (!fl && clone) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << scope << "::" << + type << "::" << endl + << "_copy (" << type << "& c) const" + << "{"; + + Sequence::contains (s, contains_clone_); + + // Copy custom data. + // + if (s.context ().count ("cd-name")) + { + String const& m (ecd_member (s)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << scope << "::" << type << "* " << scope << "::" << + type << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << type << "* c = new " << type << ";"; + else + os << type << "* c = static_cast< " << type << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << type << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << type << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << type << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << type << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } + Sequence::contains (s, contains_func_); } @@ -1698,10 +2637,11 @@ namespace CXX Traversal::ContainsParticle& contains_dtor_; Traversal::ContainsParticle& contains_copy_; Traversal::ContainsParticle& contains_assign_; + Traversal::ContainsParticle& contains_clone_; Traversal::ContainsParticle& contains_func_; }; - struct Complex : Traversal::Complex, Context + struct Complex: Traversal::Complex, Context { Complex (Context& c) : Context (c), @@ -1747,13 +2687,22 @@ namespace CXX choice_in_sequence_assign_ (c), sequence_in_sequence_assign_ (c), + // Clone. + // + attribute_clone_ (c), + element_clone_ (c), + all_clone_ (c), + choice_in_sequence_clone_ (c), + sequence_in_sequence_clone_ (c), + // Nested c-tors, etc. // all_ (c, all_contains_ctor_, all_contains_dtor_, all_contains_copy_, - all_contains_assign_), + all_contains_assign_, + all_contains_clone_), choice_in_choice_ (c, true, choice_contains_func_), choice_in_sequence_ (c, false, choice_contains_func_), sequence_in_choice_ ( @@ -1763,6 +2712,7 @@ namespace CXX sequence_contains_dtor_, sequence_contains_copy_, sequence_contains_assign_, + sequence_contains_clone_, sequence_contains_func_), sequence_in_sequence_ ( c, @@ -1771,6 +2721,7 @@ namespace CXX sequence_contains_dtor_, sequence_contains_copy_, sequence_contains_assign_, + sequence_contains_clone_, sequence_contains_func_) { // Functions. @@ -1850,6 +2801,21 @@ namespace CXX contains_compositor_assign_ >> choice_in_sequence_assign_; contains_compositor_assign_ >> sequence_in_sequence_assign_; + // Clone. + // + attribute_names_clone_ >> attribute_clone_; + + all_clone_ >> all_contains_clone_ >> element_clone_; + + sequence_in_sequence_clone_ >> sequence_contains_clone_; + sequence_contains_clone_ >> element_clone_; + sequence_contains_clone_ >> choice_in_sequence_clone_; + sequence_contains_clone_ >> sequence_in_sequence_clone_; + + contains_compositor_clone_ >> all_clone_; + contains_compositor_clone_ >> choice_in_sequence_clone_; + contains_compositor_clone_ >> sequence_in_sequence_clone_; + // Nested c-tors, etc. // all_ >> all_contains_; @@ -1880,6 +2846,7 @@ namespace CXX if (!name) return; + Boolean fl (fixed_length (c)); Boolean poly (polymorphic (c)); Boolean restriction (restriction_p (c)); @@ -1924,7 +2891,7 @@ namespace CXX if (!restriction) { - if (fixed_length (c)) + if (fl) { // copy c-tor // @@ -1980,6 +2947,130 @@ namespace CXX Complex::contains_compositor (c, contains_compositor_func_); } + // _clone + // + if (!fl && clone) + { + // + // _copy + // + + os << (exceptions ? "void " : "bool ") << name << "::" << endl + << "_copy (" << name << "& c) const" + << "{" + << "XSDE_UNUSED (c);" + << endl; + + // Copy the base. + // + if (c.inherits_p ()) + { + SemanticGraph::Type& b (c.inherits ().base ()); + + if (fixed_length (b)) + { + os << "static_cast< "; + base_name_.dispatch (b); + os << "& > (c) = *this;"; + } + else + { + os << "const "; + base_name_.dispatch (b); + os << "& b = *this;"; + + if (exceptions) + os << "b._copy (c);"; + else + os << "if (!b._copy (c))" << endl + << "return false;" + << endl; + } + } + + // Copy members. + // + if (!restriction) + { + Complex::names (c, attribute_names_clone_); + + if (c.contains_compositor_p ()) + Complex::contains_compositor (c, contains_compositor_clone_); + } + + // Copy custom data. + // + if (c.context ().count ("cd-name")) + { + String const& m (ecd_member (c)); + + if (exceptions) + os << "this->" << m << ".copy (c." << m << ");"; + else + os << "if (this->" << m << ".copy (c." << m << "))" << endl + << "return false;" + << endl; + } + + if (!exceptions) + os << "return true;"; + + os << "}"; + + // + // _clone + // + + os << name << "* " << name << "::" << endl + << "_clone () const" + << "{"; + + if (!custom_alloc) + os << name << "* c = new " << name << ";"; + else + os << name << "* c = static_cast< " << name << "* > (" << endl + << "::xsde::cxx::alloc (sizeof (" << name << ")));"; + + if (!exceptions) + os << endl + << "if (c == 0)" << endl + << "return 0;" + << endl; + + if (custom_alloc) + { + if (exceptions) + os << "::xsde::cxx::alloc_guard ag (c);"; + + os << "new (c) " << name << ";"; + + if (exceptions) + os << "ag.release ();"; + } + + if (exceptions) + os << "::xsde::cxx::guard< " << name << " > g (c);" + << "this->_copy (*c);" + << "g.release ();"; + else + { + os << "if (!this->_copy (*c))" + << "{"; + + if (!custom_alloc) + os << "delete c;"; + else + os << "c->~" << name << " ();" + << "::xsde::cxx::free (c);"; + + os << "return 0;" + << "}"; + } + + os << "return c;" + << "}"; + } + if (poly && typeinfo) { String id (c.name ()); @@ -2101,6 +3192,20 @@ namespace CXX Traversal::ContainsCompositor contains_compositor_assign_; + // Clone. + // + AttributeClone attribute_clone_; + Traversal::Names attribute_names_clone_; + + ElementClone element_clone_; + AllClone all_clone_; + ChoiceInSequenceClone choice_in_sequence_clone_; + SequenceInSequenceClone sequence_in_sequence_clone_; + Traversal::ContainsParticle all_contains_clone_; + Traversal::ContainsParticle sequence_contains_clone_; + + Traversal::ContainsCompositor contains_compositor_clone_; + // Nested c-tors, etc. // All all_; @@ -2129,6 +3234,10 @@ namespace CXX ctx.os << "#include <new>" << endl << endl; + if (ctx.clone && ctx.exceptions) + ctx.os << "#include <xsde/cxx/guard.hxx>" << endl + << endl; + Traversal::Schema schema; Traversal::Sources sources; Traversal::Names names_ns, names; |