aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-05-11 12:20:11 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-05-11 12:20:11 +0200
commit2e501c68a8641a2b3c430b55f13491a9c1c5d0f5 (patch)
tree49c2748443fe3c1f01108756b647440e0647a11b /examples
parent161beba6cdb0d91b15ad19fa8b3e51d986203915 (diff)
Add support for custom allocators
New example: examples/cxx/hybrid/allocator.
Diffstat (limited to 'examples')
-rw-r--r--examples/cxx/hybrid/README11
-rw-r--r--examples/cxx/hybrid/allocator/README62
-rw-r--r--examples/cxx/hybrid/allocator/arena.cxx167
-rw-r--r--examples/cxx/hybrid/allocator/arena.hxx52
-rw-r--r--examples/cxx/hybrid/allocator/driver.cxx325
-rw-r--r--examples/cxx/hybrid/allocator/makefile108
-rw-r--r--examples/cxx/hybrid/allocator/people.xml28
-rw-r--r--examples/cxx/hybrid/allocator/people.xsd37
-rw-r--r--examples/cxx/hybrid/makefile22
9 files changed, 806 insertions, 6 deletions
diff --git a/examples/cxx/hybrid/README b/examples/cxx/hybrid/README
index 7d9312d..dabc11f 100644
--- a/examples/cxx/hybrid/README
+++ b/examples/cxx/hybrid/README
@@ -1,7 +1,7 @@
-This directory contains a number of examples that show how to
-use the Embedded C++/Hybrid mapping. The following list gives
-an overview of each example. See the README files in example
-directories for more information on each example.
+This directory contains a number of examples that show how to use the
+Embedded C++/Hybrid mapping. The following list gives an overview of
+each example. See the README files in example directories for more
+information on each example.
hello
A simple "Hello, world!" example that shows how to parse XML
@@ -44,6 +44,9 @@ polyroot
Shows how to handle XML vocabularies with polymorphic document root
elements.
+allocator
+ Shows how to use a custom memory allocator implementation.
+
custom/
A collection of examples that show how to customize the C++/Hybrid
object model by using custom C++ classes instead of or in addition
diff --git a/examples/cxx/hybrid/allocator/README b/examples/cxx/hybrid/allocator/README
new file mode 100644
index 0000000..f2ea51c
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/README
@@ -0,0 +1,62 @@
+This example shows how to use a custom memory allocator implementation
+with the Embedded C++/Hybrid mapping. It is based on the 'minimal' example
+(so the support for STL, iostream, and C++ exceptions is disabled) and the
+only changes made are to the memory management.
+
+The example consists of the following files:
+
+people.xsd
+ XML Schema which describes a collection of person records.
+
+people.xml
+ Sample XML instance document.
+
+people.hxx
+people.cxx
+
+people-pskel.hxx
+people-pskel.cxx
+people-pimpl.hxx
+people-pimpl.cxx
+
+people-pskel.hxx
+people-pskel.cxx
+people-pimpl.hxx
+people-pimpl.cxx
+ Object model (the first pair of files), parser skeletons (the second
+ pair), parser implementations (the third pair), serializer skeletons
+ (the fourth pair), and serializer implementations (the fifth pair).
+ These files are generated by the XSD/e compiler from people.xsd. The
+ --generate-parser, --generate-serializer, --generate-aggregate,
+ --no-stl, --no-iostream, and --no-exceptions options were used to
+ request the generation of the parsing and serialization code as well
+ as to disable the use of STL, iostream, and C++ exceptions. Furthermore,
+ the --custom-allocator option was specific to make the generated code
+ use custom memory management functions instead of the standard new and
+ delete operators.
+
+arena.hxx
+arena.cxx
+ An implementation of a simple pooled memory allocator.
+
+driver.cxx
+ Driver for the example. Besides the implementation of the main()
+ function, this file also provides the implementations of the custom
+ memory management function, xsde_alloc, xsde_realloc, and xsde_free,
+ that are used by the XSD/e runtime and the generated code.
+
+ The driver first sets up the memory pool using a stack-allocated memory
+ region. It then calls the parser that constructs the object model from
+ the input XML file. After that the driver prints the content of the
+ object model to STDERR. Finally, the driver modifies the object model
+ and calls the serializer to serialize it back to XML. The implementation
+ also prints the memory usage statistics after parsing and after
+ serialization.
+
+To run the example on the sample XML instance document simply execute:
+
+$ ./driver people.xml
+
+The example reads from STDIN if input file is not specified:
+
+$ ./driver <people.xml
diff --git a/examples/cxx/hybrid/allocator/arena.cxx b/examples/cxx/hybrid/allocator/arena.cxx
new file mode 100644
index 0000000..facb852
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/arena.cxx
@@ -0,0 +1,167 @@
+// file : examples/cxx/hybrid/allocator/arena.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <stdio.h>
+#include <string.h> // memcpy
+
+#include "arena.hxx"
+
+arena::
+arena (void* memory, size_t size)
+ : alloc_count_ (0),
+ realloc_count_ (0),
+ free_count_ (0),
+ cur_allocated_ (0),
+ max_allocated_ (0)
+{
+ head_ = static_cast<block*> (memory);
+ head_->cap = size - sizeof (block);
+ head_->next = 0;
+ head_->used = false;
+}
+
+void* arena::
+allocate (size_t size)
+{
+ block* b = head_;
+
+ while (b != 0)
+ {
+ if (!b->used)
+ {
+ if (b->cap >= size)
+ {
+ // See if it makes sense to fragment this block.
+ //
+ if (b->cap - size >= sizeof (block) * 2)
+ {
+ block* b1 = reinterpret_cast<block*> (
+ reinterpret_cast<char*> (b) + sizeof (block) + size);
+
+ b1->cap = b->cap - size - sizeof (block);
+ b1->next = b->next;
+ b1->used = false;
+
+ b->next = b1;
+ b->cap = size;
+ }
+
+ b->used = true;
+ b->size = size;
+
+ alloc_count_++;
+ cur_allocated_ += size;
+
+ if (cur_allocated_ > max_allocated_)
+ max_allocated_ = cur_allocated_;
+
+ return b + 1;
+ }
+
+ // This block is not big enough. See if we can merge it
+ // with the next block.
+ //
+ if (b->next != 0 && !b->next->used)
+ {
+ block* b1 = b->next;
+ b->cap += b1->cap + sizeof (block);
+ b->next = b1->next;
+
+ // Try the merged block again.
+ //
+ continue;
+ }
+ }
+
+ // This block is either in use or not big enough. Continue
+ // searching.
+ //
+ b = b->next;
+ }
+
+ return 0;
+}
+
+void* arena::
+reallocate (void* p, size_t size)
+{
+ // If the passed pointer is NULL, reallocate is equivalent to
+ // allocate.
+ //
+ if (!p)
+ return allocate (size);
+
+ block* b = static_cast<block*> (p) - 1;
+
+ // If the passed size is NULL, reallocate is equivalent to free.
+ //
+ if (size == 0)
+ {
+ free (p);
+ return 0;
+ }
+
+ // If this block is not large enough to satisfy the request, try to
+ // merge it with the next block(s).
+ //
+ while (b->cap < size && b->next != 0 && !b->next->used)
+ {
+ block* b1 = b->next;
+ b->cap += b1->cap + sizeof (block);
+ b->next = b1->next;
+ }
+
+ // If this block is now large enough then we can reuse the same
+ // memory region.
+ //
+ if (b->cap >= size)
+ {
+ realloc_count_++;
+ cur_allocated_ += size - b->size;
+
+ if (cur_allocated_ > max_allocated_)
+ max_allocated_ = cur_allocated_;
+
+ b->size = size;
+ return p;
+ }
+
+ // Otherwise allocate a new block and copy the data over.
+ //
+ void* r = allocate (size);
+
+ if (r)
+ {
+ memcpy (r, p, b->size);
+ free (p);
+ }
+
+ return r;
+}
+
+void arena::
+free (void* p)
+{
+ if (p)
+ {
+ block* b = static_cast<block*> (p) - 1;
+
+ cur_allocated_ -= b->size;
+ free_count_++;
+
+ b->used = false;
+ }
+}
+
+void arena::
+print_statistics ()
+{
+ printf ("\n");
+ printf ("allocations: %lu\n", alloc_count_);
+ printf ("reallocations: %lu\n", realloc_count_);
+ printf ("deallocations: %lu\n", free_count_);
+ printf ("currently in use: %lu bytes\n", cur_allocated_);
+ printf ("maximum in use: %lu bytes\n", max_allocated_);
+ printf ("\n");
+}
diff --git a/examples/cxx/hybrid/allocator/arena.hxx b/examples/cxx/hybrid/allocator/arena.hxx
new file mode 100644
index 0000000..0463a38
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/arena.hxx
@@ -0,0 +1,52 @@
+// file : examples/cxx/hybrid/allocator/arena.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef ARENA_HXX
+#define ARENA_HXX
+
+#include <stddef.h> // size_t
+
+// Sample pooled memory arena. The primary goal here is to provide a
+// simple, if naive, implementation. As a result, it probably shouldn't
+// be used in production.
+//
+class arena
+{
+public:
+ arena (void* memory, size_t size);
+
+ void*
+ allocate (size_t);
+
+ void*
+ reallocate (void*, size_t);
+
+ void
+ free (void*);
+
+ void
+ print_statistics ();
+
+private:
+ struct block
+ {
+ size_t cap; // block capacity
+ size_t size; // allocated size
+ block* next; // next block
+ size_t used; // used flag
+ };
+
+ block* head_; // Linked list of blocks.
+
+ // Statistics.
+ //
+ size_t alloc_count_;
+ size_t realloc_count_;
+ size_t free_count_;
+
+ size_t cur_allocated_;
+ size_t max_allocated_;
+};
+
+#endif // ARENA_HXX
diff --git a/examples/cxx/hybrid/allocator/driver.cxx b/examples/cxx/hybrid/allocator/driver.cxx
new file mode 100644
index 0000000..933784e
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/driver.cxx
@@ -0,0 +1,325 @@
+// file : examples/cxx/hybrid/allocator/driver.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <stdio.h>
+
+#include "arena.hxx"
+
+#include "people.hxx"
+#include "people-pimpl.hxx"
+#include "people-simpl.hxx"
+
+// eVC++ 4.0 does not like using xml_schema::strdupx; Note also that
+// xml_schema::strdupx will use the custom allocator to allocate the
+// memory.
+//
+inline char*
+strdupx (const char* s)
+{
+ return xml_schema::strdupx (s);
+}
+
+// Implementation of the XSD/e custom allocator functions.
+//
+arena* xsde_arena;
+
+extern "C" void*
+xsde_alloc (size_t n)
+{
+ return xsde_arena->allocate (n);
+}
+
+extern "C" void*
+xsde_realloc (void* p, size_t n)
+{
+ return xsde_arena->reallocate (p, n);
+}
+
+extern "C" void
+xsde_free (void* p)
+{
+ return xsde_arena->free (p);
+}
+
+//
+//
+struct writer: xml_schema::writer
+{
+ virtual bool
+ write (const char* s, size_t n)
+ {
+ return fwrite (s, n, 1, stdout) == 1;
+ }
+
+ virtual bool
+ flush ()
+ {
+ return fflush (stdout) == 0;
+ }
+};
+
+int
+main (int argc, char* argv[])
+{
+ const char* input;
+
+ if (argc < 2)
+ {
+ input = "STDIN";
+ fprintf (stderr, "XML file not specified, reading from STDIN\n");
+ }
+ else
+ input = argv[1];
+
+ // Set up the memory pool.
+ //
+ char pool[65536 * 2];
+ arena ar (pool, sizeof (pool));
+ xsde_arena = &ar;
+
+ // Open the file or use STDIN.
+ //
+ FILE* f = argc > 1 ? fopen (argv[1], "rb") : stdin;
+
+ if (f == 0)
+ {
+ fprintf (stderr, "%s: unable to open\n", input);
+ return 1;
+ }
+
+ // Parse.
+ //
+ using xml_schema::parser_error;
+
+ parser_error pe;
+ bool io_error = false;
+ people* ppl = 0;
+
+ do
+ {
+ people_paggr people_p;
+ xml_schema::document_pimpl doc_p (people_p.root_parser (),
+ people_p.root_name ());
+
+ if (pe = doc_p._error ())
+ break;
+
+ people_p.pre ();
+
+ if (pe = people_p._error ())
+ break;
+
+ char buf[4096];
+
+ do
+ {
+ size_t s = fread (buf, 1, sizeof (buf), f);
+
+ if (s != sizeof (buf) && ferror (f))
+ {
+ io_error = true;
+ break;
+ }
+
+ doc_p.parse (buf, s, feof (f) != 0);
+ pe = doc_p._error ();
+
+ } while (!pe && !feof (f));
+
+ if (io_error || pe)
+ break;
+
+ ppl = people_p.post ();
+
+ pe = people_p._error ();
+
+ } while (false);
+
+ if (argc > 1)
+ fclose (f);
+
+ // Handle parsing errors.
+ //
+ if (io_error)
+ {
+ fprintf (stderr, "%s: read failure\n", input);
+ return 1;
+ }
+
+ if (pe)
+ {
+ switch (pe.type ())
+ {
+ case parser_error::sys:
+ {
+ fprintf (stderr, "%s: %s\n", input, pe.sys_text ());
+ break;
+ }
+ case parser_error::xml:
+ {
+ fprintf (stderr, "%s:%lu:%lu: %s\n",
+ input, pe.line (), pe.column (), pe.xml_text ());
+ break;
+ }
+#ifdef XSDE_PARSER_VALIDATION
+ case parser_error::schema:
+ {
+ fprintf (stderr, "%s:%lu:%lu: %s\n",
+ input, pe.line (), pe.column (), pe.schema_text ());
+ break;
+ }
+#endif
+ case parser_error::app:
+ {
+ fprintf (stderr, "%s:%lu:%lu: application error %d\n",
+ input, pe.line (), pe.column (), pe.app_code ());
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 1;
+ }
+
+ // Print memory usage statistics.
+ //
+ xsde_arena->print_statistics ();
+
+ // Print what we've got.
+ //
+ people::person_sequence& ps = ppl->person ();
+
+ for (people::person_const_iterator i = ps.begin (); i != ps.end (); ++i)
+ {
+ printf ("first: %s\n" "last: %s\n" "gender: %s\n" "age: %hu\n\n",
+ i->first_name (),
+ i->last_name (),
+ i->gender ().string (),
+ i->age ());
+ }
+
+ // Remove people that are younger than 30.
+ //
+ for (people::person_iterator j = ps.begin (); j != ps.end ();)
+ {
+ if (j->age () < 30)
+ j = ps.erase (j);
+ else
+ ++j;
+ }
+
+ // Insert a new person. Note that we need to allocate the
+ // object using the XSD/e allocator.
+ //
+ {
+ void* mem = xsde_alloc (sizeof (person));
+
+ if (!mem)
+ {
+ fprintf (stderr, "no memory\n");
+ return 1;
+ }
+
+ person* p = new (mem) person;
+
+ p->first_name (strdupx ("Joe")); // No out of memory check.
+ p->last_name (strdupx ("Dirt")); // No out of memory check.
+ p->age (36);
+ p->gender (gender::male);
+
+ ps.insert (ps.begin (), p); // No out of memory check.
+ }
+
+ // Serialize.
+ //
+ using xml_schema::serializer_error;
+
+ serializer_error se;
+ writer w;
+
+ do
+ {
+ people_saggr people_s;
+ xml_schema::document_simpl doc_s (people_s.root_serializer (),
+ people_s.root_name ());
+
+ doc_s.add_no_namespace_schema ("people.xsd");
+
+ se = doc_s._error ();
+ if (se)
+ break;
+
+ people_s.pre (*ppl);
+
+ se = people_s._error ();
+ if (se)
+ break;
+
+ doc_s.serialize (w, xml_schema::document_simpl::pretty_print);
+
+ se = doc_s._error ();
+ if (se)
+ break;
+
+ people_s.post ();
+
+ se = people_s._error ();
+
+ } while (false);
+
+
+ // Delete the people object model. Here we can explicitly call the
+ // destructor and then free the memory using the custom allocator
+ // function. Alternatively, if the arena is used to hold only one
+ // object model, then we can simply destroy the arena since all
+ // the dynamic memory allocated by the object model is inside
+ // this arena.
+ //
+ //
+ ppl->~people ();
+ xsde_free (ppl);
+
+ // Print memory usage statistics.
+ //
+ xsde_arena->print_statistics ();
+ xsde_arena = 0;
+
+ // Handle serializer errors.
+ //
+ if (se)
+ {
+ switch (se.type ())
+ {
+ case serializer_error::sys:
+ {
+ fprintf (stderr, "error: %s\n", se.sys_text ());
+ break;
+ }
+ case serializer_error::xml:
+ {
+ fprintf (stderr, "error: %s\n", se.xml_text ());
+ break;
+ }
+#ifdef XSDE_SERIALIZER_VALIDATION
+ case serializer_error::schema:
+ {
+ fprintf (stderr, "error: %s\n", se.schema_text ());
+ break;
+ }
+#endif
+ case serializer_error::app:
+ {
+ fprintf (stderr, "application error: %d\n", se.app_code ());
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/examples/cxx/hybrid/allocator/makefile b/examples/cxx/hybrid/allocator/makefile
new file mode 100644
index 0000000..d6a1cd6
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/makefile
@@ -0,0 +1,108 @@
+# file : examples/cxx/hybrid/allocator/makefile
+# author : Boris Kolpackov <boris@codesynthesis.com>
+# copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC
+# license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../../build/bootstrap.make
+
+xsd := people.xsd
+cxx := driver.cxx arena.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
+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): xsde_options += --generate-parser --generate-serializer \
+--generate-aggregate
+
+$(call include-dep,$(dep))
+
+# Convenience alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Dist.
+#
+dist-common := $(out_base)/.dist-common
+$(dist) $(dist-win) $(dist-common): path := $(subst $(src_root)/,,$(src_base))
+
+$(dist-common):
+ $(call install-data,$(src_base)/driver.cxx,$(dist_prefix)/$(path)/driver.cxx)
+ $(call install-data,$(src_base)/arena.cxx,$(dist_prefix)/$(path)/arena.cxx)
+ $(call install-data,$(src_base)/arena.hxx,$(dist_prefix)/$(path)/arena.hxx)
+ $(call install-data,$(src_base)/people.xsd,$(dist_prefix)/$(path)/people.xsd)
+ $(call install-data,$(src_base)/people.xml,$(dist_prefix)/$(path)/people.xml)
+
+$(dist): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README)
+
+$(dist-win): $(dist-common)
+ $(call install-data,$(src_base)/README,$(dist_prefix)/$(path)/README.txt)
+ $(call message,,unix2dos $(dist_prefix)/$(path)/README.txt)
+
+
+# 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,$(bld_root)/install.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/examples/cxx/hybrid/allocator/people.xml b/examples/cxx/hybrid/allocator/people.xml
new file mode 100644
index 0000000..ad4135a
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/people.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/allocator/people.xml
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="people.xsd">
+
+ <person>
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <gender>male</gender>
+ <age>32</age>
+ </person>
+
+ <person>
+ <first-name>Jane</first-name>
+ <last-name>Doe</last-name>
+ <gender>female</gender>
+ <age>28</age>
+ </person>
+
+</people>
diff --git a/examples/cxx/hybrid/allocator/people.xsd b/examples/cxx/hybrid/allocator/people.xsd
new file mode 100644
index 0000000..131be7b
--- /dev/null
+++ b/examples/cxx/hybrid/allocator/people.xsd
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+
+<!--
+
+file : examples/cxx/hybrid/allocator/people.xsd
+author : Boris Kolpackov <boris@codesynthesis.com>
+copyright : not copyrighted - public domain
+
+-->
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:simpleType name="gender">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="male"/>
+ <xsd:enumeration value="female"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="person">
+ <xsd:sequence>
+ <xsd:element name="first-name" type="xsd:string"/>
+ <xsd:element name="last-name" type="xsd:string"/>
+ <xsd:element name="gender" type="gender"/>
+ <xsd:element name="age" type="xsd:unsignedShort"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="people">
+ <xsd:sequence>
+ <xsd:element name="person" type="person" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:element name="people" type="people"/>
+
+</xsd:schema>
diff --git a/examples/cxx/hybrid/makefile b/examples/cxx/hybrid/makefile
index c82a2ec..8bdb2de 100644
--- a/examples/cxx/hybrid/makefile
+++ b/examples/cxx/hybrid/makefile
@@ -5,8 +5,20 @@
include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
-all_examples := binary compositors custom hello multiroot polymorphism \
-polyroot streaming library wildcard filter minimal
+all_examples := \
+allocator \
+binary \
+compositors \
+custom \
+hello \
+multiroot \
+polymorphism \
+polyroot \
+streaming \
+library \
+wildcard \
+filter \
+minimal
build_examples := binary compositors custom
@@ -29,9 +41,15 @@ endif
ifeq ($(xsde_stl),n)
ifeq ($(xsde_exceptions),n)
build_examples += minimal
+
+ifeq ($(xsde_custom_allocator),y)
+build_examples += allocator
+endif
+
endif
endif
+
default := $(out_base)/
dist := $(out_base)/.dist
dist-win := $(out_base)/.dist-win