[med-svn] [cereal] 01/02: Imported Upstream version 1.1.2

Michael Crusoe misterc-guest at moszumanska.debian.org
Sat Sep 19 03:25:29 UTC 2015


This is an automated email from the git hooks/post-receive script.

misterc-guest pushed a commit to branch master
in repository cereal.

commit baaf5cdd9992c4661fba97cc814652005054fde8
Author: Michael R. Crusoe <crusoe at ucdavis.edu>
Date:   Fri Sep 18 19:11:35 2015 -0700

    Imported Upstream version 1.1.2
---
 .gitignore                                         |   44 +
 .travis.yml                                        |   50 +
 CMakeLists.txt                                     |   37 +
 LICENSE                                            |   24 +
 README.md                                          |   84 +
 doc/DoxygenLayout.xml                              |  190 ++
 doc/doxygen.in                                     | 1870 ++++++++++++++
 doc/footer.html                                    |   31 +
 doc/mainpage.dox                                   |   43 +
 include/cereal/access.hpp                          |  427 ++++
 include/cereal/archives/adapters.hpp               |  163 ++
 include/cereal/archives/binary.hpp                 |  165 ++
 include/cereal/archives/json.hpp                   |  912 +++++++
 include/cereal/archives/portable_binary.hpp        |  245 ++
 include/cereal/archives/xml.hpp                    |  882 +++++++
 include/cereal/cereal.hpp                          |  955 +++++++
 include/cereal/details/helpers.hpp                 |  360 +++
 include/cereal/details/polymorphic_impl.hpp        |  437 ++++
 include/cereal/details/static_object.hpp           |   90 +
 include/cereal/details/traits.hpp                  | 1325 ++++++++++
 include/cereal/details/util.hpp                    |   84 +
 include/cereal/external/base64.hpp                 |  125 +
 include/cereal/external/rapidjson/document.h       |  821 ++++++
 include/cereal/external/rapidjson/filestream.h     |   47 +
 include/cereal/external/rapidjson/genericstream.h  |  105 +
 include/cereal/external/rapidjson/internal/pow10.h |   54 +
 include/cereal/external/rapidjson/internal/stack.h |   82 +
 .../cereal/external/rapidjson/internal/strfunc.h   |   24 +
 include/cereal/external/rapidjson/license.txt      |   19 +
 include/cereal/external/rapidjson/prettywriter.h   |  156 ++
 include/cereal/external/rapidjson/rapidjson.h      |  525 ++++
 include/cereal/external/rapidjson/reader.h         |  749 ++++++
 include/cereal/external/rapidjson/stringbuffer.h   |   49 +
 include/cereal/external/rapidjson/writer.h         |  330 +++
 include/cereal/external/rapidxml/license.txt       |   52 +
 include/cereal/external/rapidxml/manual.html       |  406 +++
 include/cereal/external/rapidxml/rapidxml.hpp      | 2618 ++++++++++++++++++++
 .../external/rapidxml/rapidxml_iterators.hpp       |  173 ++
 .../cereal/external/rapidxml/rapidxml_print.hpp    |  424 ++++
 .../cereal/external/rapidxml/rapidxml_utils.hpp    |  121 +
 include/cereal/macros.hpp                          |   82 +
 include/cereal/types/array.hpp                     |   79 +
 include/cereal/types/base_class.hpp                |  164 ++
 include/cereal/types/bitset.hpp                    |  112 +
 include/cereal/types/boost_variant.hpp             |  106 +
 include/cereal/types/chrono.hpp                    |   72 +
 include/cereal/types/common.hpp                    |  129 +
 include/cereal/types/complex.hpp                   |   56 +
 include/cereal/types/deque.hpp                     |   62 +
 include/cereal/types/forward_list.hpp              |   68 +
 include/cereal/types/list.hpp                      |   62 +
 include/cereal/types/map.hpp                       |  108 +
 include/cereal/types/memory.hpp                    |  392 +++
 include/cereal/types/polymorphic.hpp               |  462 ++++
 include/cereal/types/queue.hpp                     |  130 +
 include/cereal/types/set.hpp                       |  103 +
 include/cereal/types/stack.hpp                     |   76 +
 include/cereal/types/string.hpp                    |   61 +
 include/cereal/types/tuple.hpp                     |  123 +
 include/cereal/types/unordered_map.hpp             |  100 +
 include/cereal/types/unordered_set.hpp             |   99 +
 include/cereal/types/utility.hpp                   |   47 +
 include/cereal/types/valarray.hpp                  |   89 +
 include/cereal/types/vector.hpp                    |  112 +
 sandbox/CMakeLists.txt                             |   14 +
 sandbox/performance.cpp                            |  469 ++++
 sandbox/sandbox.cpp                                |  820 ++++++
 sandbox/sandbox_json.cpp                           |  475 ++++
 sandbox/sandbox_rtti.cpp                           |  229 ++
 sandbox/sandbox_shared_lib/CMakeLists.txt          |    1 +
 sandbox/sandbox_shared_lib/base.cpp                |    9 +
 sandbox/sandbox_shared_lib/base.hpp                |   43 +
 sandbox/sandbox_shared_lib/derived.cpp             |   10 +
 sandbox/sandbox_shared_lib/derived.hpp             |   19 +
 sandbox/sandbox_vs.cpp                             |  277 +++
 scripts/renameincludes.sh                          |   12 +
 scripts/updatecoverage.sh                          |   33 +
 scripts/updatedoc.in                               |   25 +
 unittests/CMakeLists.txt                           |   77 +
 unittests/array.cpp                                |  113 +
 unittests/basic_string.cpp                         |  227 ++
 unittests/bitset.cpp                               |   94 +
 unittests/chrono.cpp                               |  123 +
 unittests/common.hpp                               |  212 ++
 unittests/complex.cpp                              |   96 +
 unittests/deque.cpp                                |  118 +
 unittests/forward_list.cpp                         |  112 +
 unittests/list.cpp                                 |  113 +
 unittests/load_construct.cpp                       |  195 ++
 unittests/map.cpp                                  |  206 ++
 unittests/memory.cpp                               |  154 ++
 unittests/memory_cycles.cpp                        |  161 ++
 unittests/multimap.cpp                             |  147 ++
 unittests/multiset.cpp                             |  153 ++
 unittests/pair.cpp                                 |  109 +
 unittests/pod.cpp                                  |  164 ++
 unittests/polymorphic.cpp                          |  212 ++
 unittests/portability_test.cpp                     |  202 ++
 unittests/portable_binary_archive.cpp              |  155 ++
 unittests/priority_queue.cpp                       |  125 +
 unittests/queue.cpp                                |  125 +
 unittests/run_portability_test.sh                  |    9 +
 unittests/run_valgrind.sh                          |   10 +
 unittests/set.cpp                                  |  113 +
 unittests/stack.cpp                                |  125 +
 unittests/structs.cpp                              |   85 +
 unittests/structs_minimal.cpp                      |  271 ++
 unittests/structs_specialized.cpp                  |  478 ++++
 unittests/tuple.cpp                                |  119 +
 unittests/unordered_loads.cpp                      |  157 ++
 unittests/unordered_map.cpp                        |  142 ++
 unittests/unordered_multimap.cpp                   |  172 ++
 unittests/unordered_multiset.cpp                   |  152 ++
 unittests/unordered_set.cpp                        |  133 +
 unittests/user_data_adapters.cpp                   |  137 +
 unittests/valarray.cpp                             |  119 +
 unittests/vector.cpp                               |  129 +
 unittests/versioning.cpp                           |  205 ++
 vs2013/.gitignore                                  |    3 +
 vs2013/performance/performance.vcxproj             |  138 ++
 vs2013/performance/performance.vcxproj.filters     |   22 +
 vs2013/sandbox/sandbox.vcxproj                     |  138 ++
 vs2013/sandbox/sandbox.vcxproj.filters             |   22 +
 vs2013/sandbox_json/sandbox_json.vcxproj           |  134 +
 vs2013/sandbox_json/sandbox_json.vcxproj.filters   |   22 +
 vs2013/sandbox_rtti/sandbox_rtti.vcxproj           |  136 +
 vs2013/sandbox_rtti/sandbox_rtti.vcxproj.filters   |   22 +
 vs2013/sandbox_vs/sandbox_vs.vcxproj               |  143 ++
 vs2013/sandbox_vs/sandbox_vs.vcxproj.filters       |   22 +
 vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj       |  143 ++
 .../sandbox_vs_dll/sandbox_vs_dll.vcxproj.filters  |   33 +
 vs2013/unittests/main.cpp                          |   32 +
 vs2013/unittests/unittests.vcxproj                 |  191 ++
 vs2013/unittests/unittests.vcxproj.filters         |  127 +
 vs2013/vs2013.sln                                  |   90 +
 135 files changed, 27995 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5d4370d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+
+# Visual studio cruft
+*.opensdf
+*.sdf
+*.suo
+*.user
+*/x64
+*/Debug*
+*/Release*
+*.log
+*.tlog*
+
+# misc files mostly used for testing
+out.txt
+ptr.txt
+test.txt
+boost_serialize
+arr.txt
+performance
+include_renamed
+.ycm_extra_conf.py*
+doc/html
+rtti.txt
+doc/latex
+portability64
+portability32
+file.json
+out.xml
+cereal_version.out
+xml_ordering.out
+build
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..aa58c5d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,50 @@
+language: cpp
+
+compiler:
+  # TODO: Clang is currently giving issues
+  #- clang
+  - gcc
+
+before_install:
+  # Always install g++4.8.1
+  - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+  
+  # Install recent version of Boost
+  - sudo add-apt-repository -y ppa:boost-latest/ppa 
+
+  # clang 3.3
+  - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi
+
+  - sudo apt-get update -qq
+
+install: 
+  - sudo apt-get install cmake
+  - sudo apt-get install libboost1.54-all-dev
+
+  # Always install valgrind
+  - sudo apt-get install valgrind
+
+  # Always install g++4.8.1
+  - sudo apt-get install -qq g++-4.8
+  - sudo apt-get install -qq g++-4.8-multilib
+  - if [ "$CXX" = "g++" ]; then export CMAKE_CXX_COMPILER="g++-4.8"; fi
+  - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi
+
+  # clang 3.3
+  - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.3; fi
+  - if [ "$CXX" == "clang++" ]; then export CMAKE_CXX_COMPILER="clang++-3.3"; fi
+  - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.3"; fi
+
+script:
+  - mkdir build 
+  - cd build 
+  - cmake .. 
+  - make
+
+after_script:
+  - ctest .
+  # - make valgrind
+
+branches:
+  only:
+    - develop
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4838b97
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required (VERSION 2.6.2)
+project (cereal)
+
+option(SKIP_PORTABILITY_TEST "Skip portability tests" OFF)
+
+set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Werror -g -Wextra -Wshadow -pedantic ${CMAKE_CXX_FLAGS}")
+
+include_directories(./include)
+
+find_package(Boost COMPONENTS serialization unit_test_framework)
+
+if(Boost_FOUND)
+  include_directories(${Boost_INCLUDE_DIRS})
+  enable_testing()
+  add_subdirectory(unittests)
+endif(Boost_FOUND)
+
+add_subdirectory(sandbox)
+
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+
+  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen.in" "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg" @ONLY)
+  add_custom_target(doc
+    COMMAND ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+    COMMENT "Generating API documentation with Doxygen" VERBATIM
+    )
+
+  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scripts/updatedoc.in" "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh" @ONLY)
+  add_custom_target(update-doc
+    COMMAND "${CMAKE_CURRENT_BINARY_DIR}/updatedoc.sh"
+    DEPENDS doc
+    COMMENT "Copying documentation to gh-pages branch" VERBATIM
+    )
+
+endif(DOXYGEN_FOUND)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..acc4fd8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2014, Randolph Voorhies, Shane Grant
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of cereal nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c4aaf2a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,84 @@
+cereal - A C++11 library for serialization
+==========================================
+
+<img src="http://uscilab.github.io/cereal/assets/img/cerealboxside.png" align="right"/><p>cereal is a header-only C++11 serialization library.  cereal takes arbitrary data types and reversibly turns them into different representations, such as compact binary encodings, XML, or JSON.  cereal was designed to be fast, light-weight, and easy to extend - it has no external dependencies and can be easily bundled with other code or used standalone.</p>
+
+### cereal has great documentation
+
+Looking for more information on how cereal works and its documentation?  Visit [cereal's web page](http://USCiLab.github.com/cereal) to get the latest information.
+
+### cereal is easy to use
+
+Installation and use of of cereal is fully documented on the [main web page](http://USCiLab.github.com/cereal), but this is a quick and dirty version:
+
+* Download cereal and place the headers somewhere your code can see them
+* Write serialization functions for your custom types or use the built in support for the standard library cereal provides
+* Use the serialization archives to load and save data
+
+```cpp
+#include <cereal/types/unordered_map.hpp>
+#include <cereal/types/memory.hpp>
+#include <cereal/archives/binary.hpp>
+#include <fstream>
+    
+struct MyRecord
+{
+  uint8_t x, y;
+  float z;
+  
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x, y, z );
+  }
+};
+    
+struct SomeData
+{
+  int32_t id;
+  std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
+  
+  template <class Archive>
+  void save( Archive & ar ) const
+  {
+    ar( data );
+  }
+      
+  template <class Archive>
+  void load( Archive & ar )
+  {
+    static int32_t idGen = 0;
+    id = idGen++;
+    ar( data );
+  }
+};
+
+int main()
+{
+  std::ofstream os("out.cereal", std::ios::binary);
+  cereal::BinaryOutputArchive archive( os );
+
+  SomeData myData;
+  archive( myData );
+
+  return 0;
+}
+```    
+
+### cereal has a mailing list
+
+Either get in touch over <a href="mailto:cerealcpp at googlegroups.com">email</a> or [on the web](https://groups.google.com/forum/#!forum/cerealcpp).
+
+
+
+## cereal has a permissive license
+
+cereal is licensed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause).
+
+## cereal build status
+
+* develop : [![Build Status](https://travis-ci.org/USCiLab/cereal.png?branch=develop)](https://travis-ci.org/USCiLab/cereal)
+
+---
+
+Were you looking for the Haskell cereal?  Go <a href="https://github.com/GaloisInc/cereal">here</a>.
diff --git a/doc/DoxygenLayout.xml b/doc/DoxygenLayout.xml
new file mode 100644
index 0000000..819c4f4
--- /dev/null
+++ b/doc/DoxygenLayout.xml
@@ -0,0 +1,190 @@
+<doxygenlayout version="1.0">
+  <!-- Generated by doxygen 1.8.3.1-20130402 -->
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="user" visible="true" title="cereal" url="../../index.html"/>
+    <tab type="mainpage" visible="yes" title="Doxygen Documentation"/>
+    <tab type="pages" visible="no" title="" intro=""/>
+    <tab type="modules" visible="yes" title="Code Modules" intro=""/>
+    <tab type="namespaces" visible="no" title="">
+      <tab type="namespacelist" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="no" title="">
+      <tab type="classlist" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="Source File Documentation">
+      <tab type="filelist" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="examples" visible="no" title="" intro=""/>
+    <tab type="user" visible="true" title="Github" url="https://github.com/USCiLab/cereal"/>
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <allmemberslink visible="yes"/>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <memberdecl>
+      <nestedgroups visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/doc/doxygen.in b/doc/doxygen.in
new file mode 100644
index 0000000..55fc748
--- /dev/null
+++ b/doc/doxygen.in
@@ -0,0 +1,1870 @@
+# Doxyfile 1.8.3.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "cereal"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "A C++11 library for serialization"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = include
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+#SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = "@CMAKE_CURRENT_SOURCE_DIR@/doc/DoxygenLayout.xml"
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@/doc #include doc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.hpp
+FILE_PATTERNS          += *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = external
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = .* *.cpp */external/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page (index.html).
+# This can be useful if you have a project on for instance GitHub and want reuse
+# the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            ="@CMAKE_CURRENT_SOURCE_DIR@/doc/footer.html"
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search engine
+# library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/footer.html b/doc/footer.html
new file mode 100644
index 0000000..e76312e
--- /dev/null
+++ b/doc/footer.html
@@ -0,0 +1,31 @@
+<!-- HTML footer for doxygen 1.8.3.1-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby
+    <a href="http://www.doxygen.org/index.html">
+    <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby  <a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+  ga('create', 'UA-42360142-1', 'uscilab.github.io');
+  ga('send', 'pageview');
+
+</script>
+</body>
+</html>
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
new file mode 100644
index 0000000..bfc6b26
--- /dev/null
+++ b/doc/mainpage.dox
@@ -0,0 +1,43 @@
+/**
+\mainpage cereal code documentation
+
+\tableofcontents
+
+Aside from the <a href="../../index.html">documentation</a> presented on the main cereal site, this doxygen
+page offers code level documentation.
+
+\section modules Browse modules
+
+cereal's code is organized into modules of similar functionality.  Take a look at the <a href="modules.html">modules</a>
+section to learn more.  Average users will not need to understand the workings of any code that falls under the
+<i>internal</i> module.
+
+\section files Browse files
+
+If you need reference on a specific file, the <a href="files.html">files</a> page lists all files in cereal.
+*/
+
+  //! \defgroup Archives Input and Output Archive Types
+
+  /*! \defgroup Access Access Control and Disambiguation
+      Provides ways to give cereal access to protected member functions, disambiguate
+      which serialization function cereal should use, and provide ways of using smart
+      pointers with types that have no default constructor */
+
+  /*! \defgroup Utility Utility Functionality
+      Name-value pairs, binary data wrappers, exceptions, and other utility functions */
+
+  /*! \defgroup TypeSupport Support for Serializing Various Types
+      Serialization of many types is shipped with cereal, including most of the standard library as well as a few others.  */
+
+  /*! \defgroup STLSupport Standard Library Support
+      Serialization methods for nearly all types found in the C++ standard library
+      \ingroup TypeSupport */
+
+  /*! \defgroup OtherTypes Miscellaneous Types Support
+      Support for various other types such as smart pointers to polymorphic base classes, boost::variant, etc.
+      \ingroup TypeSupport */
+
+  /*! \defgroup Internal Internal Functionality
+      Various classes and functions that are critical for the operation of cereal but of no
+      interest to users */
diff --git a/include/cereal/access.hpp b/include/cereal/access.hpp
new file mode 100644
index 0000000..60437e6
--- /dev/null
+++ b/include/cereal/access.hpp
@@ -0,0 +1,427 @@
+/*! \file access.hpp
+    \brief Access control, default construction, and serialization disambiguation */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ACCESS_HPP_
+#define CEREAL_ACCESS_HPP_
+
+#include <type_traits>
+#include <iostream>
+#include <cstdint>
+
+#include <cereal/macros.hpp>
+#include <cereal/details/helpers.hpp>
+
+namespace cereal
+{
+  // ######################################################################
+  //! A class that allows cereal to load smart pointers to types that have no default constructor
+  /*! If your class does not have a default constructor, cereal will not be able
+      to load any smart pointers to it unless you overload LoadAndConstruct
+      for your class, and provide an appropriate load_and_construct method.  You can also
+      choose to define a member static function instead of specializing this class.
+
+      The specialization of LoadAndConstruct must be placed within the cereal namespace:
+
+      @code{.cpp}
+      struct MyType
+      {
+        MyType( int x ); // note: no default ctor
+        int myX;
+
+        // Define a serialize or load/save pair as you normally would
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( myX );
+        }
+      };
+
+      // Provide a specialization for LoadAndConstruct for your type
+      namespace cereal
+      {
+        template <> struct LoadAndConstruct<MyType>
+        {
+          // load_and_construct will be passed the archive that you will be loading
+          // from as well as a construct object which you can use as if it were the
+          // constructor for your type.  cereal will handle all memory management for you.
+          template <class Archive>
+          static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
+          {
+            int x;
+            ar( x );
+            construct( x );
+          }
+        };
+      } // end namespace cereal
+      @endcode
+
+      Please note that just as in using external serialization functions, you cannot get
+      access to non-public members of your class by befriending cereal::access.  If you
+      have the ability to modify the class you wish to serialize, it is recommended that you
+      use member serialize functions and a static member load_and_construct function.
+
+      @tparam T The type to specialize for
+      @ingroup Access */
+  template <class T>
+  struct LoadAndConstruct
+  {
+    //! Called by cereal if no default constructor exists to load and construct data simultaneously
+    /*! Overloads of this should return a pointer to T and expect an archive as a parameter */
+    static std::false_type load_and_construct(...)
+    { return std::false_type(); }
+  };
+
+  // forward decl for construct
+  //! @cond PRIVATE_NEVERDEFINED
+  namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
+  //! @endcond
+
+  //! Used to construct types with no default constructor
+  /*! When serializing a type that has no default constructor, cereal
+      will attempt to call either the class static function load_and_construct
+      or the appropriate template specialization of LoadAndConstruct.  cereal
+      will pass that function a reference to the archive as well as a reference
+      to a construct object which should be used to perform the allocation once
+      data has been appropriately loaded.
+
+      @code{.cpp}
+      struct MyType
+      {
+        // note the lack of default constructor
+        MyType( int xx, int yy );
+
+        int x, y;
+        double notInConstructor;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( x, y );
+          ar( notInConstructor );
+        }
+
+        template <class Archive>
+        static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct )
+        {
+          int x, y;
+          ar( x, y );
+
+          // use construct object to initialize with loaded data
+          construct( x, y );
+
+          // access to member variables and functions via -> operator
+          ar( construct->notInConstructor );
+
+          // could also do the above section by:
+          double z;
+          ar( z );
+          construct->notInConstructor = z;
+        }
+      };
+      @endcode
+
+      @tparam T The class type being serialized
+      */
+  template <class T>
+  class construct
+  {
+    public:
+      //! Construct and initialize the type T with the given arguments
+      /*! This will forward all arguments to the underlying type T,
+          calling an appropriate constructor.
+
+          Calling this function more than once will result in an exception
+          being thrown.
+
+          @param args The arguments to the constructor for T
+          @throw Exception If called more than once */
+      template <class ... Args>
+      void operator()( Args && ... args );
+      // implementation deferred due to reliance on cereal::access
+
+      //! Get a reference to the initialized underlying object
+      /*! This must be called after the object has been initialized.
+
+          @return A reference to the initialized object
+          @throw Exception If called before initialization */
+      T * operator->()
+      {
+        if( !itsValid )
+          throw Exception("Object must be initialized prior to accessing members");
+
+        return itsPtr;
+      }
+
+      //! Returns a raw pointer to the initialized underlying object
+      /*! This is mainly intended for use with passing an instance of
+          a constructed object to cereal::base_class.
+
+          It is strongly recommended to avoid using this function in
+          any other circumstance.
+
+          @return A raw pointer to the initialized type */
+      T * ptr()
+      {
+        return operator->();
+      }
+
+    private:
+      template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
+
+      construct( T * p ) : itsPtr( p ), itsValid( false ) {}
+      construct( construct const & ) = delete;
+      construct & operator=( construct const & ) = delete;
+
+      T * itsPtr;
+      bool itsValid;
+  };
+
+  // ######################################################################
+  //! A class that can be made a friend to give cereal access to non public functions
+  /*! If you desire non-public serialization functions within a class, cereal can only
+      access these if you declare cereal::access a friend.
+
+      @code{.cpp}
+      class MyClass
+      {
+        private:
+          friend class cereal::access; // gives access to the private serialize
+
+          template <class Archive>
+          void serialize( Archive & ar )
+          {
+            // some code
+          }
+      };
+      @endcode
+      @ingroup Access */
+  class access
+  {
+    public:
+      // ####### Standard Serialization ########################################
+      template<class Archive, class T> inline
+      static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
+      { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T> inline
+      static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
+      { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T> inline
+      static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
+      { return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T> inline
+      static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
+      { return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T> inline
+      static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
+      { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T> inline
+      static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
+      { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
+
+      template<class Archive, class T, class U> inline
+      static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
+      { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
+
+      // ####### Versioned Serialization #######################################
+      template<class Archive, class T> inline
+      static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T> inline
+      static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T> inline
+      static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T> inline
+      static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T> inline
+      static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T> inline
+      static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
+      { return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
+
+      template<class Archive, class T, class U> inline
+      static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version))
+      { return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
+
+      // ####### Other Functionality ##########################################
+      // for detecting inheritance from enable_shared_from_this
+      template <class T> inline
+      static auto shared_from_this(T & t) -> decltype(t.shared_from_this());
+
+      // for placement new
+      template <class T, class ... Args> inline
+      static void construct( T *& ptr, Args && ... args )
+      {
+        new (ptr) T( std::forward<Args>( args )... );
+      }
+
+      // for non-placement new with a default constructor
+      template <class T> inline
+      static T * construct()
+      {
+        return new T();
+      }
+
+      template <class T> inline
+      static std::false_type load_and_construct(...)
+      { return std::false_type(); }
+
+      template<class T, class Archive> inline
+      static auto load_and_construct(Archive & ar, ::cereal::construct<T> & construct) -> decltype(T::load_and_construct(ar, construct))
+      {
+        T::load_and_construct( ar, construct );
+      }
+  }; // end class access
+
+  // ######################################################################
+  //! A specifier used in conjunction with cereal::specialize to disambiguate
+  //! serialization in special cases
+  /*! @relates specialize
+      @ingroup Access */
+  enum class specialization
+  {
+    member_serialize,            //!< Force the use of a member serialize function
+    member_load_save,            //!< Force the use of a member load/save pair
+    member_load_save_minimal,    //!< Force the use of a member minimal load/save pair
+    non_member_serialize,        //!< Force the use of a non-member serialize function
+    non_member_load_save,        //!< Force the use of a non-member load/save pair
+    non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
+  };
+
+  //! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
+  /*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
+      or load/save pair) at compile time.  If for some reason cereal cannot find a non-ambiguous way
+      of serializing a type, it will produce a static assertion complaining about this.
+
+      This can happen because you have both a serialize and load/save pair, or even because a base
+      class has a serialize (public or private with friend access) and a derived class does not
+      overwrite this due to choosing some other serialization type.
+
+      Specializing this class will tell cereal to explicitly use the serialization type you specify
+      and it will not complain about ambiguity in its compile time selection.  However, if cereal detects
+      an ambiguity in specializations, it will continue to issue a static assertion.
+
+      @code{.cpp}
+      class MyParent
+      {
+        friend class cereal::access;
+        template <class Archive>
+        void serialize( Archive & ar ) {}
+      };
+
+      // Although serialize is private in MyParent, to cereal::access it will look public,
+      // even through MyDerived
+      class MyDerived : public MyParent
+      {
+        public:
+          template <class Archive>
+          void load( Archive & ar ) {}
+
+          template <class Archive>
+          void save( Archive & ar ) {}
+      };
+
+      // The load/save pair in MyDerived is ambiguous because serialize in MyParent can
+      // be accessed from cereal::access.  This looks the same as making serialize public
+      // in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
+      // cereal will complain about this at compile time unless we disambiguate:
+
+      namespace cereal
+      {
+        // This struct specialization will tell cereal which is the right way to serialize the ambiguity
+        template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
+
+        // If we only had a disambiguation for a specific archive type, it would look something like this
+        template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
+      }
+      @endcode
+
+      You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
+      CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
+
+      @tparam T The type to specialize the serialization for
+      @tparam S The specialization type to use for T
+      @ingroup Access */
+  template <class Archive, class T, specialization S>
+  struct specialize : public std::false_type {};
+
+  //! Convenient macro for performing specialization for all archive types
+  /*! This performs specialization for the specific type for all types of archives.
+      This macro should be placed at the global namespace.
+
+      @code{cpp}
+      struct MyType {};
+      CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
+      @endcode
+
+      @relates specialize
+      @ingroup Access */
+  #define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization )                                \
+  namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
+
+  //! Convenient macro for performing specialization for a single archive type
+  /*! This performs specialization for the specific type for a single type of archive.
+      This macro should be placed at the global namespace.
+
+      @code{cpp}
+      struct MyType {};
+      CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
+      @endcode
+
+      @relates specialize
+      @ingroup Access */
+  #define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization )               \
+  namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
+
+  // ######################################################################
+  // Deferred Implementation, see construct for more information
+  template <class T> template <class ... Args> inline
+  void construct<T>::operator()( Args && ... args )
+  {
+    if( itsValid )
+      throw Exception("Attempting to construct an already initialized object");
+
+    ::cereal::access::construct( itsPtr, std::forward<Args>( args )... );
+    itsValid = true;
+  }
+} // namespace cereal
+
+#endif // CEREAL_ACCESS_HPP_
diff --git a/include/cereal/archives/adapters.hpp b/include/cereal/archives/adapters.hpp
new file mode 100644
index 0000000..d9558ad
--- /dev/null
+++ b/include/cereal/archives/adapters.hpp
@@ -0,0 +1,163 @@
+/*! \file adapters.hpp
+    \brief Archive adapters that provide additional functionality
+           on top of an existing archive */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_
+#define CEREAL_ARCHIVES_ADAPTERS_HPP_
+
+#include <cereal/details/helpers.hpp>
+#include <utility>
+
+namespace cereal
+{
+  #ifdef CEREAL_FUTURE_EXPERIMENTAL
+
+  // Forward declaration for friend access
+  template <class U, class A> U & get_user_data( A & );
+
+  //! Wraps an archive and gives access to user data
+  /*! This adapter is useful if you require access to
+      either raw pointers or references within your
+      serialization functions.
+
+      While cereal does not directly support serialization
+      raw pointers or references, it is sometimes the case
+      that you may want to supply something such as a raw
+      pointer or global reference to some constructor.
+      In this situation this adapter would likely be used
+      with the construct class to allow for non-default
+      constructors.
+
+      @note This feature is experimental and may be altered or removed in a future release. See issue #46.
+
+      @code{.cpp}
+      struct MyUserData
+      {
+        int * myRawPointer;
+        std::reference_wrapper<MyOtherType> myReference;
+      };
+
+      struct MyClass
+      {
+        // Note the raw pointer parameter
+        MyClass( int xx, int * rawP );
+
+        int x;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        { ar( x ); }
+
+        template <class Archive>
+        static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
+        {
+          int xx;
+          ar( xx );
+          // note the need to use get_user_data to retrieve user data from the archive
+          construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
+        }
+      };
+
+      int main()
+      {
+        {
+          MyUserData md;
+          md.myRawPointer = &something;
+          md.myReference = someInstanceOfType;
+
+          std::ifstream is( "data.xml" );
+          cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
+
+          std::unique_ptr<MyClass> sc;
+          ar( sc ); // use as normal
+        }
+
+        return 0;
+      }
+      @endcode
+
+      @relates get_user_data
+
+      @tparam UserData The type to give the archive access to
+      @tparam Archive The archive to wrap */
+  template <class UserData, class Archive>
+  class UserDataAdapter : public Archive
+  {
+    public:
+      //! Construct the archive with some user data struct
+      /*! This will forward all arguments (other than the user
+          data) to the wrapped archive type.  The UserDataAdapter
+          can then be used identically to the wrapped archive type
+
+          @tparam Args The arguments to pass to the constructor of
+                       the archive. */
+      template <class ... Args>
+      UserDataAdapter( UserData & ud, Args && ... args ) :
+        Archive( std::forward<Args>( args )... ),
+        userdata( ud )
+      { }
+
+    private:
+      //! Overload the rtti function to enable dynamic_cast
+      void rtti() {}
+      friend UserData & get_user_data<UserData>( Archive & ar );
+      UserData & userdata; //!< The actual user data
+  };
+
+  //! Retrieves user data from an archive wrapped by UserDataAdapter
+  /*! This will attempt to retrieve the user data associated with
+      some archive wrapped by UserDataAdapter.  If this is used on
+      an archive that is not wrapped, a run-time exception will occur.
+
+      @note This feature is experimental and may be altered or removed in a future release. See issue #46.
+
+      @note The correct use of this function cannot be enforced at compile
+            time.
+
+      @relates UserDataAdapter
+      @tparam UserData The data struct contained in the archive
+      @tparam Archive The archive, which should be wrapped by UserDataAdapter
+      @param ar The archive
+      @throws Exception if the archive this is used upon is not wrapped with
+                        UserDataAdapter. */
+  template <class UserData, class Archive>
+  UserData & get_user_data( Archive & ar )
+  {
+    try
+    {
+      return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
+    }
+    catch( std::bad_cast const & )
+    {
+      throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
+    }
+  }
+  #endif // CEREAL_FUTURE_EXPERIMENTAL
+} // namespace cereal
+
+#endif // CEREAL_ARCHIVES_ADAPTERS_HPP_
diff --git a/include/cereal/archives/binary.hpp b/include/cereal/archives/binary.hpp
new file mode 100644
index 0000000..f284582
--- /dev/null
+++ b/include/cereal/archives/binary.hpp
@@ -0,0 +1,165 @@
+/*! \file binary.hpp
+    \brief Binary input and output archives */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ARCHIVES_BINARY_HPP_
+#define CEREAL_ARCHIVES_BINARY_HPP_
+
+#include <cereal/cereal.hpp>
+#include <sstream>
+
+namespace cereal
+{
+  // ######################################################################
+  //! An output archive designed to save data in a compact binary representation
+  /*! This archive outputs data to a stream in an extremely compact binary
+      representation with as little extra metadata as possible.
+
+      This archive does nothing to ensure that the endianness of the saved
+      and loaded data is the same.  If you need to have portability over
+      architectures with different endianness, use PortableBinaryOutputArchive.
+
+      When using a binary archive and a file stream, you must use the
+      std::ios::binary format flag to avoid having your data altered
+      inadvertently.
+
+      \ingroup Archives */
+  class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>
+  {
+    public:
+      //! Construct, outputting to the provided stream
+      /*! @param stream The stream to output to.  Can be a stringstream, a file stream, or
+                        even cout! */
+      BinaryOutputArchive(std::ostream & stream) :
+        OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>(this),
+        itsStream(stream)
+      { }
+
+      //! Writes size bytes of data to the output stream
+      void saveBinary( const void * data, std::size_t size )
+      {
+        auto const writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
+
+        if(writtenSize != size)
+          throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
+      }
+
+    private:
+      std::ostream & itsStream;
+  };
+
+  // ######################################################################
+  //! An input archive designed to load data saved using BinaryOutputArchive
+  /*  This archive does nothing to ensure that the endianness of the saved
+      and loaded data is the same.  If you need to have portability over
+      architectures with different endianness, use PortableBinaryOutputArchive.
+
+      When using a binary archive and a file stream, you must use the
+      std::ios::binary format flag to avoid having your data altered
+      inadvertently.
+
+      \ingroup Archives */
+  class BinaryInputArchive : public InputArchive<BinaryInputArchive, AllowEmptyClassElision>
+  {
+    public:
+      //! Construct, loading from the provided stream
+      BinaryInputArchive(std::istream & stream) :
+        InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
+        itsStream(stream)
+    { }
+
+      //! Reads size bytes of data from the input stream
+      void loadBinary( void * const data, std::size_t size )
+      {
+        auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
+
+        if(readSize != size)
+          throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
+      }
+
+    private:
+      std::istream & itsStream;
+  };
+
+  // ######################################################################
+  // Common BinaryArchive serialization functions
+
+  //! Saving for POD types to binary
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, T const & t)
+  {
+    ar.saveBinary(std::addressof(t), sizeof(t));
+  }
+
+  //! Loading for POD types from binary
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, T & t)
+  {
+    ar.loadBinary(std::addressof(t), sizeof(t));
+  }
+
+  //! Serializing NVP types to binary
+  template <class Archive, class T> inline
+  CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
+  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
+  {
+    ar( t.value );
+  }
+
+  //! Serializing SizeTags to binary
+  template <class Archive, class T> inline
+  CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
+  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
+  {
+    ar( t.size );
+  }
+
+  //! Saving binary data
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, BinaryData<T> const & bd)
+  {
+    ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
+  }
+
+  //! Loading binary data
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, BinaryData<T> & bd)
+  {
+    ar.loadBinary(bd.data, static_cast<std::size_t>(bd.size));
+  }
+} // namespace cereal
+
+// register archives for polymorphic support
+CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
+CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
+
+// tie input and output archives together
+CEREAL_SETUP_ARCHIVE_TRAITS(cereal::BinaryInputArchive, cereal::BinaryOutputArchive)
+
+#endif // CEREAL_ARCHIVES_BINARY_HPP_
diff --git a/include/cereal/archives/json.hpp b/include/cereal/archives/json.hpp
new file mode 100644
index 0000000..49556cc
--- /dev/null
+++ b/include/cereal/archives/json.hpp
@@ -0,0 +1,912 @@
+/*! \file json.hpp
+    \brief JSON input and output archives */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ARCHIVES_JSON_HPP_
+#define CEREAL_ARCHIVES_JSON_HPP_
+
+#include <cereal/cereal.hpp>
+#include <cereal/details/util.hpp>
+
+namespace cereal
+{
+  //! An exception thrown when rapidjson fails an internal assertion
+  /*! @ingroup Utility */
+  struct RapidJSONException : Exception
+  { RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
+}
+
+// Override rapidjson assertions to throw exceptions by default
+#ifndef RAPIDJSON_ASSERT
+#define RAPIDJSON_ASSERT(x) if(!(x)){ \
+  throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
+#endif // RAPIDJSON_ASSERT
+
+#include <cereal/external/rapidjson/prettywriter.h>
+#include <cereal/external/rapidjson/genericstream.h>
+#include <cereal/external/rapidjson/reader.h>
+#include <cereal/external/rapidjson/document.h>
+#include <cereal/external/base64.hpp>
+
+#include <limits>
+#include <sstream>
+#include <stack>
+#include <vector>
+#include <string>
+
+namespace cereal
+{
+  // ######################################################################
+  //! An output archive designed to save data to JSON
+  /*! This archive uses RapidJSON to build serialie data to JSON.
+
+      JSON archives provides a human readable output but at decreased
+      performance (both in time and space) compared to binary archives.
+
+      JSON benefits greatly from name-value pairs, which if present, will
+      name the nodes in the output.  If these are not present, each level
+      of the output will be given an automatically generated delimited name.
+
+      The precision of the output archive controls the number of decimals output
+      for floating point numbers and should be sufficiently large (i.e. at least 20)
+      if there is a desire to have binary equality between the numbers output and
+      those read in.  In general you should expect a loss of precision when going
+      from floating point to text and back.
+
+      JSON archives do not output the size information for any dynamically sized structure
+      and instead infer it from the number of children for a node.  This means that data
+      can be hand edited for dynamic sized structures and will still be readable.  This
+      is accomplished through the cereal::SizeTag object, which will cause the archive
+      to output the data as a JSON array (e.g. marked by [] instead of {}), which indicates
+      that the container is variable sized and may be edited.
+
+      \ingroup Archives */
+  class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
+  {
+    enum class NodeType { StartObject, InObject, StartArray, InArray };
+
+    typedef rapidjson::GenericWriteStream WriteStream;
+    typedef rapidjson::PrettyWriter<WriteStream> JSONWriter;
+
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an JSONOutputArchive */
+      //! @{
+
+      //! A class containing various advanced options for the JSON archive
+      class Options
+      {
+        public:
+          //! Default options
+          static Options Default(){ return Options(); }
+
+          //! Default options with no indentation
+          static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, IndentChar::space, 0 ); }
+
+          //! The character to use for indenting
+          enum class IndentChar : char
+          {
+            space = ' ',
+            tab = '\t',
+            newline = '\n',
+            carriage_return = '\r'
+          };
+
+          //! Specify specific options for the JSONOutputArchive
+          /*! @param precision The precision used for floating point numbers
+              @param indentChar The type of character to indent with
+              @param indentLength The number of indentChar to use for indentation
+                             (0 corresponds to no indentation) */
+          explicit Options( int precision = std::numeric_limits<double>::max_digits10,
+                            IndentChar indentChar = IndentChar::space,
+                            unsigned int indentLength = 4 ) :
+            itsPrecision( precision ),
+            itsIndentChar( static_cast<char>(indentChar) ),
+            itsIndentLength( indentLength ) { }
+
+        private:
+          friend class JSONOutputArchive;
+          int itsPrecision;
+          char itsIndentChar;
+          unsigned int itsIndentLength;
+      };
+
+      //! Construct, outputting to the provided stream
+      /*! @param stream The stream to output to.
+          @param options The JSON specific options to use.  See the Options struct
+                         for the values of default parameters */
+      JSONOutputArchive(std::ostream & stream, Options const & options = Options::Default() ) :
+        OutputArchive<JSONOutputArchive>(this),
+        itsWriteStream(stream),
+        itsWriter(itsWriteStream, options.itsPrecision),
+        itsNextName(nullptr)
+      {
+        itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
+        itsNameCounter.push(0);
+        itsNodeStack.push(NodeType::StartObject);
+      }
+
+      //! Destructor, flushes the JSON
+      ~JSONOutputArchive()
+      {
+        if (itsNodeStack.top() == NodeType::InObject)
+          itsWriter.EndObject();
+      }
+
+      //! Saves some binary data, encoded as a base64 string, with an optional name
+      /*! This will create a new node, optionally named, and insert a value that consists of
+          the data encoded as a base64 string */
+      void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
+      {
+        setNextName( name );
+        writeName();
+
+        auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
+        saveValue( base64string );
+      };
+
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the JSONOutputArchive */
+      //! @{
+
+      //! Starts a new node in the JSON output
+      /*! The node can optionally be given a name by calling setNextName prior
+          to creating the node
+
+          Nodes only need to be started for types that are themselves objects or arrays */
+      void startNode()
+      {
+        writeName();
+        itsNodeStack.push(NodeType::StartObject);
+        itsNameCounter.push(0);
+      }
+
+      //! Designates the most recently added node as finished
+      void finishNode()
+      {
+        // if we ended up serializing an empty object or array, writeName
+        // will never have been called - so start and then immediately end
+        // the object/array.
+        //
+        // We'll also end any object/arrays we happen to be in
+        switch(itsNodeStack.top())
+        {
+          case NodeType::StartArray:
+            itsWriter.StartArray();
+          case NodeType::InArray:
+            itsWriter.EndArray();
+            break;
+          case NodeType::StartObject:
+            itsWriter.StartObject();
+          case NodeType::InObject:
+            itsWriter.EndObject();
+            break;
+        }
+
+        itsNodeStack.pop();
+        itsNameCounter.pop();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNextName = name;
+      }
+
+      //! Saves a bool to the current node
+      void saveValue(bool b)                { itsWriter.Bool_(b);                                                         }
+      //! Saves an int to the current node
+      void saveValue(int i)                 { itsWriter.Int(i);                                                          }
+      //! Saves a uint to the current node
+      void saveValue(unsigned u)            { itsWriter.Uint(u);                                                         }
+      //! Saves an int64 to the current node
+      void saveValue(int64_t i64)           { itsWriter.Int64(i64);                                                      }
+      //! Saves a uint64 to the current node
+      void saveValue(uint64_t u64)          { itsWriter.Uint64(u64);                                                     }
+      //! Saves a double to the current node
+      void saveValue(double d)              { itsWriter.Double(d);                                                       }
+      //! Saves a string to the current node
+      void saveValue(std::string const & s) { itsWriter.String(s.c_str(), static_cast<rapidjson::SizeType>( s.size() )); }
+      //! Saves a const char * to the current node
+      void saveValue(char const * s)        { itsWriter.String(s);                                                       }
+
+    private:
+      // Some compilers/OS have difficulty disambiguating the above for various flavors of longs, so we provide
+      // special overloads to handle these cases.
+
+      //! 32 bit signed long saving to current node
+      template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
+                                          std::is_signed<T>::value> = traits::sfinae> inline
+      void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
+
+      //! non 32 bit signed long saving to current node
+      template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
+                                          std::is_signed<T>::value> = traits::sfinae> inline
+      void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
+
+      //! 32 bit unsigned long saving to current node
+      template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
+                                          std::is_unsigned<T>::value> = traits::sfinae> inline
+      void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
+
+      //! non 32 bit unsigned long saving to current node
+      template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
+                                          std::is_unsigned<T>::value> = traits::sfinae> inline
+      void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
+
+    public:
+#ifdef _MSC_VER
+      //! MSVC only long overload to current node
+      void saveValue( unsigned long lu ){ saveLong( lu ); };
+#else // _MSC_VER
+      //! Serialize a long if it would not be caught otherwise
+      template <class T, traits::EnableIf<std::is_same<T, long>::value,
+                                          !std::is_same<T, std::int32_t>::value,
+                                          !std::is_same<T, std::int64_t>::value> = traits::sfinae> inline
+      void saveValue( T t ){ saveLong( t ); }
+
+      //! Serialize an unsigned long if it would not be caught otherwise
+      template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
+                                          !std::is_same<T, std::uint32_t>::value,
+                                          !std::is_same<T, std::uint64_t>::value> = traits::sfinae> inline
+      void saveValue( T t ){ saveLong( t ); }
+#endif // _MSC_VER
+
+      //! Save exotic arithmetic as strings to current node
+      /*! Handles long long (if distinct from other types), unsigned long (if distinct), and long double */
+      template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
+                                          !std::is_same<T, long>::value,
+                                          !std::is_same<T, unsigned long>::value,
+                                          !std::is_same<T, std::int64_t>::value,
+                                          !std::is_same<T, std::uint64_t>::value,
+                                          (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae> inline
+      void saveValue(T const & t)
+      {
+        std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
+        ss << t;
+        saveValue( ss.str() );
+      }
+
+      //! Write the name of the upcoming node and prepare object/array state
+      /*! Since writeName is called for every value that is output, regardless of
+          whether it has a name or not, it is the place where we will do a deferred
+          check of our node state and decide whether we are in an array or an object.
+
+          The general workflow of saving to the JSON archive is:
+
+            1. (optional) Set the name for the next node to be created, usually done by an NVP
+            2. Start the node
+            3. (if there is data to save) Write the name of the node (this function)
+            4. (if there is data to save) Save the data (with saveValue)
+            5. Finish the node
+          */
+      void writeName()
+      {
+        NodeType const & nodeType = itsNodeStack.top();
+
+        // Start up either an object or an array, depending on state
+        if(nodeType == NodeType::StartArray)
+        {
+          itsWriter.StartArray();
+          itsNodeStack.top() = NodeType::InArray;
+        }
+        else if(nodeType == NodeType::StartObject)
+        {
+          itsNodeStack.top() = NodeType::InObject;
+          itsWriter.StartObject();
+        }
+
+        // Array types do not output names
+        if(nodeType == NodeType::InArray) return;
+
+        if(itsNextName == nullptr)
+        {
+          std::string name = "value" + std::to_string( itsNameCounter.top()++ ) + "\0";
+          saveValue(name);
+        }
+        else
+        {
+          saveValue(itsNextName);
+          itsNextName = nullptr;
+        }
+      }
+
+      //! Designates that the current node should be output as an array, not an object
+      void makeArray()
+      {
+        itsNodeStack.top() = NodeType::StartArray;
+      }
+
+      //! @}
+
+    private:
+      WriteStream itsWriteStream;          //!< Rapidjson write stream
+      JSONWriter itsWriter;                //!< Rapidjson writer
+      char const * itsNextName;            //!< The next name
+      std::stack<uint32_t> itsNameCounter; //!< Counter for creating unique names for unnamed nodes
+      std::stack<NodeType> itsNodeStack;
+  }; // JSONOutputArchive
+
+  // ######################################################################
+  //! An input archive designed to load data from JSON
+  /*! This archive uses RapidJSON to read in a JSON archive.
+
+      Input JSON should have been produced by the JSONOutputArchive.  Data can
+      only be added to dynamically sized containers (marked by JSON arrays) -
+      the input archive will determine their size by looking at the number of child nodes.
+      Only JSON originating from a JSONOutputArchive is officially supported, but data
+      from other sources may work if properly formatted.
+
+      The JSONInputArchive does not require that nodes are loaded in the same
+      order they were saved by JSONOutputArchive.  Using name value pairs (NVPs),
+      it is possible to load in an out of order fashion or otherwise skip/select
+      specific nodes to load.
+
+      The default behavior of the input archive is to read sequentially starting
+      with the first node and exploring its children.  When a given NVP does
+      not match the read in name for a node, the archive will search for that
+      node at the current level and load it if it exists.  After loading an out of
+      order node, the archive will then proceed back to loading sequentially from
+      its new position.
+
+      Consider this simple example where loading of some data is skipped:
+
+      @code{cpp}
+      // imagine the input file has someData(1-9) saved in order at the top level node
+      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
+      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
+                                                    // match expected NVP name, so we search
+                                                    // for the given NVP and load that value
+      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
+                                                    // current location, proceeding sequentially
+      @endcode
+
+      \ingroup Archives */
+  class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
+  {
+    private:
+      typedef rapidjson::GenericReadStream ReadStream;
+      typedef rapidjson::GenericValue<rapidjson::UTF8<>> JSONValue;
+      typedef JSONValue::ConstMemberIterator MemberIterator;
+      typedef JSONValue::ConstValueIterator ValueIterator;
+      typedef rapidjson::Document::GenericValue GenericValue;
+
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an JSONInputArchive */
+      //! @{
+
+      //! Construct, reading from the provided stream
+      /*! @param stream The stream to read from */
+      JSONInputArchive(std::istream & stream) :
+        InputArchive<JSONInputArchive>(this),
+        itsNextName( nullptr ),
+        itsReadStream(stream)
+      {
+        itsDocument.ParseStream<0>(itsReadStream);
+        itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
+      }
+
+      //! Loads some binary data, encoded as a base64 string
+      /*! This will automatically start and finish a node to load the data, and can be called directly by
+          users.
+
+          Note that this follows the same ordering rules specified in the class description in regards
+          to loading in/out of order */
+      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
+      {
+        itsNextName = name;
+
+        std::string encoded;
+        loadValue( encoded );
+        auto decoded = base64::decode( encoded );
+
+        if( size != decoded.size() )
+          throw Exception("Decoded binary data size does not match specified size");
+
+        std::memcpy( data, decoded.data(), decoded.size() );
+        itsNextName = nullptr;
+      };
+
+    private:
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the JSONInputArchive */
+      //! @{
+
+      //! An internal iterator that handles both array and object types
+      /*! This class is a variant and holds both types of iterators that
+          rapidJSON supports - one for arrays and one for objects. */
+      class Iterator
+      {
+        public:
+          Iterator() : itsIndex( 0 ), itsType(Null_) {}
+
+          Iterator(MemberIterator begin, MemberIterator end) :
+            itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
+          { }
+
+          Iterator(ValueIterator begin, ValueIterator end) :
+            itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
+          { }
+
+          //! Advance to the next node
+          Iterator & operator++()
+          {
+            ++itsIndex;
+            return *this;
+          }
+
+          //! Get the value of the current node
+          GenericValue const & value()
+          {
+            switch(itsType)
+            {
+              case Value : return itsValueItBegin[itsIndex];
+              case Member: return itsMemberItBegin[itsIndex].value;
+              default: throw cereal::Exception("Invalid Iterator Type!");
+            }
+          }
+
+          //! Get the name of the current node, or nullptr if it has no name
+          const char * name() const
+          {
+            if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
+              return itsMemberItBegin[itsIndex].name.GetString();
+            else
+              return nullptr;
+          }
+
+          //! Adjust our position such that we are at the node with the given name
+          /*! @throws Exception if no such named node exists */
+          inline void search( const char * searchName )
+          {
+            const auto len = std::strlen( searchName );
+            size_t index = 0;
+            for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
+            {
+              const auto currentName = it->name.GetString();
+              if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
+                  ( std::strlen( currentName ) == len ) )
+              {
+                itsIndex = index;
+                return;
+              }
+            }
+
+            throw Exception("JSON Parsing failed - provided NVP not found");
+          }
+
+        private:
+          MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
+          ValueIterator itsValueItBegin, itsValueItEnd;    //!< The value iterator (array)
+          size_t itsIndex;                                 //!< The current index of this iterator
+          enum Type {Value, Member, Null_} itsType;    //!< Whether this holds values (array) or members (objects) or nothing
+      };
+
+      //! Searches for the expectedName node if it doesn't match the actualName
+      /*! This needs to be called before every load or node start occurs.  This function will
+          check to see if an NVP has been provided (with setNextName) and if so, see if that name matches the actual
+          next name given.  If the names do not match, it will search in the current level of the JSON for that name.
+          If the name is not found, an exception will be thrown.
+
+          Resets the NVP name after called.
+
+          @throws Exception if an expectedName is given and not found */
+      inline void search()
+      {
+        // The name an NVP provided with setNextName()
+        if( itsNextName )
+        {
+          // The actual name of the current node
+          auto const actualName = itsIteratorStack.back().name();
+
+          // Do a search if we don't see a name coming up, or if the names don't match
+          if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
+            itsIteratorStack.back().search( itsNextName );
+        }
+
+        itsNextName = nullptr;
+      }
+
+    public:
+      //! Starts a new node, going into its proper iterator
+      /*! This places an iterator for the next node to be parsed onto the iterator stack.  If the next
+          node is an array, this will be a value iterator, otherwise it will be a member iterator.
+
+          By default our strategy is to start with the document root node and then recursively iterate through
+          all children in the order they show up in the document.
+          We don't need to know NVPs to do this; we'll just blindly load in the order things appear in.
+
+          If we were given an NVP, we will search for it if it does not match our the name of the next node
+          that would normally be loaded.  This functionality is provided by search(). */
+      void startNode()
+      {
+        search();
+
+        if(itsIteratorStack.back().value().IsArray())
+          itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
+        else
+          itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
+      }
+
+      //! Finishes the most recently started node
+      void finishNode()
+      {
+        itsIteratorStack.pop_back();
+        ++itsIteratorStack.back();
+      }
+
+      //! Retrieves the current node name
+      /*! @return nullptr if no name exists */
+      const char * getNodeName() const
+      {
+        return itsIteratorStack.back().name();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNextName = name;
+      }
+
+      //! Loads a value from the current node - small signed overload
+      template <class T, traits::EnableIf<std::is_signed<T>::value,
+                                          sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
+      void loadValue(T & val)
+      {
+        search();
+
+        val = static_cast<T>( itsIteratorStack.back().value().GetInt() );
+        ++itsIteratorStack.back();
+      }
+
+      //! Loads a value from the current node - small unsigned overload
+      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
+                                          sizeof(T) < sizeof(uint64_t),
+                                          !std::is_same<bool, T>::value> = traits::sfinae> inline
+      void loadValue(T & val)
+      {
+        search();
+
+        val = static_cast<T>( itsIteratorStack.back().value().GetUint() );
+        ++itsIteratorStack.back();
+      }
+
+      //! Loads a value from the current node - bool overload
+      void loadValue(bool & val)        { search(); val = itsIteratorStack.back().value().GetBool_();   ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - int64 overload
+      void loadValue(int64_t & val)     { search(); val = itsIteratorStack.back().value().GetInt64();  ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - uint64 overload
+      void loadValue(uint64_t & val)    { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - float overload
+      void loadValue(float & val)       { search(); val = static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - double overload
+      void loadValue(double & val)      { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
+      //! Loads a value from the current node - string overload
+      void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
+
+      // Special cases to handle various flavors of long, which tend to conflict with
+      // the int32_t or int64_t on various compiler/OS combinations.  MSVC doesn't need any of this.
+      #ifndef _MSC_VER
+    private:
+      //! 32 bit signed long loading from current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
+      loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
+
+      //! non 32 bit signed long loading from current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
+      loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
+
+      //! 32 bit unsigned long loading from current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
+      loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
+
+      //! non 32 bit unsigned long loading from current node
+      template <class T> inline
+      typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
+      loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
+            
+    public:
+      //! Serialize a long if it would not be caught otherwise
+      template <class T> inline
+      typename std::enable_if<std::is_same<T, long>::value &&
+                              !std::is_same<T, std::int32_t>::value &&
+                              !std::is_same<T, std::int64_t>::value, void>::type
+      loadValue( T & t ){ loadLong(t); }
+
+      //! Serialize an unsigned long if it would not be caught otherwise
+      template <class T> inline
+      typename std::enable_if<std::is_same<T, unsigned long>::value &&
+                              !std::is_same<T, std::uint32_t>::value &&
+                              !std::is_same<T, std::uint64_t>::value, void>::type
+      loadValue( T & t ){ loadLong(t); }
+      #endif // _MSC_VER
+
+    private:
+      //! Convert a string to a long long
+      void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
+      //! Convert a string to an unsigned long long
+      void stringToNumber( std::string const & str, unsigned long long & val ) { val = std::stoull( str ); }
+      //! Convert a string to a long double
+      void stringToNumber( std::string const & str, long double & val ) { val = std::stold( str ); }
+
+    public:
+      //! Loads a value from the current node - long double and long long overloads
+      template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
+                                          !std::is_same<T, long>::value,
+                                          !std::is_same<T, unsigned long>::value,
+                                          !std::is_same<T, std::int64_t>::value,
+                                          !std::is_same<T, std::uint64_t>::value,
+                                          (sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
+      inline void loadValue(T & val)
+      {
+        std::string encoded;
+        loadValue( encoded );
+        stringToNumber( encoded, val );
+      }
+
+      //! Loads the size for a SizeTag
+      void loadSize(size_type & size)
+      {
+        size = (itsIteratorStack.rbegin() + 1)->value().Size();
+      }
+
+      //! @}
+
+    private:
+      const char * itsNextName;               //!< Next name set by NVP
+      ReadStream itsReadStream;               //!< Rapidjson write stream
+      std::vector<Iterator> itsIteratorStack; //!< 'Stack' of rapidJSON iterators
+      rapidjson::Document itsDocument;        //!< Rapidjson document
+  };
+
+  // ######################################################################
+  // JSONArchive prologue and epilogue functions
+  // ######################################################################
+
+  // ######################################################################
+  //! Prologue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void prologue( JSONOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Prologue for NVPs for JSON archives
+  template <class T> inline
+  void prologue( JSONInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void epilogue( JSONOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Epilogue for NVPs for JSON archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void epilogue( JSONInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for SizeTags for JSON archives
+  /*! SizeTags are strictly ignored for JSON, they just indicate
+      that the current node should be made into an array */
+  template <class T> inline
+  void prologue( JSONOutputArchive & ar, SizeTag<T> const & )
+  {
+    ar.makeArray();
+  }
+
+  //! Prologue for SizeTags for JSON archives
+  template <class T> inline
+  void prologue( JSONInputArchive &, SizeTag<T> const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for SizeTags for JSON archives
+  /*! SizeTags are strictly ignored for JSON */
+  template <class T> inline
+  void epilogue( JSONOutputArchive &, SizeTag<T> const & )
+  { }
+
+  //! Epilogue for SizeTags for JSON archives
+  template <class T> inline
+  void epilogue( JSONInputArchive &, SizeTag<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for all other types for JSON archives (except minimal types)
+  /*! Starts a new node, named either automatically or by some NVP,
+      that may be given data by the type about to be archived
+
+      Minimal types do not start or finish nodes */
+  template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
+                                       traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
+                                       traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
+  inline void prologue( JSONOutputArchive & ar, T const & )
+  {
+    ar.startNode();
+  }
+
+  //! Prologue for all other types for JSON archives
+  template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
+                                       traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
+                                       traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
+  inline void prologue( JSONInputArchive & ar, T const & )
+  {
+    ar.startNode();
+  }
+
+  // ######################################################################
+  //! Epilogue for all other types other for JSON archives (except minimal types
+  /*! Finishes the node created in the prologue
+
+      Minimal types do not start or finish nodes */
+  template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
+                                       traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
+                                       traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
+  inline void epilogue( JSONOutputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  //! Epilogue for all other types other for JSON archives
+  template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
+                                       traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
+                                       traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
+  inline void epilogue( JSONInputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  // ######################################################################
+  //! Prologue for arithmetic types for JSON archives
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void prologue( JSONOutputArchive & ar, T const & )
+  {
+    ar.writeName();
+  }
+
+  //! Prologue for arithmetic types for JSON archives
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void prologue( JSONInputArchive &, T const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for arithmetic types for JSON archives
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void epilogue( JSONOutputArchive &, T const & )
+  { }
+
+  //! Epilogue for arithmetic types for JSON archives
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void epilogue( JSONInputArchive &, T const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void prologue(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const &)
+  {
+    ar.writeName();
+  }
+
+  //! Prologue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void prologue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  // ######################################################################
+  //! Epilogue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void epilogue(JSONOutputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  //! Epilogue for strings for JSON archives
+  template<class CharT, class Traits, class Alloc> inline
+  void epilogue(JSONInputArchive &, std::basic_string<CharT, Traits, Alloc> const &)
+  { }
+
+  // ######################################################################
+  // Common JSONArchive serialization functions
+  // ######################################################################
+  //! Serializing NVP types to JSON
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  //! Saving for arithmetic to JSON
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
+  {
+    ar.saveValue( t );
+  }
+
+  //! Loading arithmetic from JSON
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
+  {
+    ar.loadValue( t );
+  }
+
+  //! saving string to JSON
+  template<class CharT, class Traits, class Alloc> inline
+  void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
+  {
+    ar.saveValue( str );
+  }
+
+  //! loading string from JSON
+  template<class CharT, class Traits, class Alloc> inline
+  void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
+  {
+    ar.loadValue( str );
+  }
+
+  // ######################################################################
+  //! Saving SizeTags to JSON
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
+  {
+    // nothing to do here, we don't explicitly save the size
+  }
+
+  //! Loading SizeTags from JSON
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
+  {
+    ar.loadSize( st.size );
+  }
+} // namespace cereal
+
+// register archives for polymorphic support
+CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
+CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
+
+// tie input and output archives together
+CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
+
+#endif // CEREAL_ARCHIVES_JSON_HPP_
diff --git a/include/cereal/archives/portable_binary.hpp b/include/cereal/archives/portable_binary.hpp
new file mode 100644
index 0000000..36fb149
--- /dev/null
+++ b/include/cereal/archives/portable_binary.hpp
@@ -0,0 +1,245 @@
+/*! \file binary.hpp
+    \brief Binary input and output archives */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
+#define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
+
+#include <cereal/cereal.hpp>
+#include <sstream>
+#include <limits>
+
+namespace cereal
+{
+  namespace portable_binary_detail
+  {
+    //! Returns true if the current machine is little endian
+    /*! @ingroup Internal */
+    inline bool is_little_endian()
+    {
+      static std::int32_t test = 1;
+      return *reinterpret_cast<std::int8_t*>( &test ) == 1;
+    }
+
+    //! Swaps the order of bytes for some chunk of memory
+    /*! @param data The data as a uint8_t pointer
+        @tparam DataSize The true size of the data
+        @ingroup Internal */
+    template <std::size_t DataSize>
+    inline void swap_bytes( std::uint8_t * data )
+    {
+      for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
+        std::swap( data[i], data[DataSize - i - 1] );
+    }
+  } // end namespace portable_binary_detail
+
+  // ######################################################################
+  //! An output archive designed to save data in a compact binary representation portable over different architectures
+  /*! This archive outputs data to a stream in an extremely compact binary
+      representation with as little extra metadata as possible.
+
+      This archive will record the endianness of the data and assuming that
+      the user takes care of ensuring serialized types are the same size
+      across machines, is portable over different architectures.
+
+      When using a binary archive and a file stream, you must use the
+      std::ios::binary format flag to avoid having your data altered
+      inadvertently.
+
+      \warning This archive has not been thoroughly tested across different architectures.
+               Please report any issues, optimizations, or feature requests at
+               <a href="www.github.com/USCiLab/cereal">the project github</a>.
+
+    \ingroup Archives */
+  class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
+  {
+    public:
+      //! Construct, outputting to the provided stream
+      /*! @param stream The stream to output to.  Can be a stringstream, a file stream, or
+        even cout! */
+      PortableBinaryOutputArchive(std::ostream & stream) :
+        OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
+        itsStream(stream)
+      {
+        this->operator()( portable_binary_detail::is_little_endian() );
+      }
+
+      //! Writes size bytes of data to the output stream
+      void saveBinary( const void * data, std::size_t size )
+      {
+        auto const writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
+
+        if(writtenSize != size)
+          throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
+      }
+
+    private:
+      std::ostream & itsStream;
+  };
+
+  // ######################################################################
+  //! An input archive designed to load data saved using PortableBinaryOutputArchive
+  /*! This archive outputs data to a stream in an extremely compact binary
+      representation with as little extra metadata as possible.
+
+      This archive will load the endianness of the serialized data and
+      if necessary transform it to match that of the local machine.  This comes
+      at a significant performance cost compared to non portable archives if
+      the transformation is necessary, and also causes a small performance hit
+      even if it is not necessary.
+
+      It is recommended to use portable archives only if you know that you will
+      be sending binary data to machines with different endianness.
+
+      The archive will do nothing to ensure types are the same size - that is
+      the responsibility of the user.
+
+      When using a binary archive and a file stream, you must use the
+      std::ios::binary format flag to avoid having your data altered
+      inadvertently.
+
+      \warning This archive has not been thoroughly tested across different architectures.
+               Please report any issues, optimizations, or feature requests at
+               <a href="www.github.com/USCiLab/cereal">the project github</a>.
+
+    \ingroup Archives */
+  class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
+  {
+    public:
+      //! Construct, loading from the provided stream
+      /*! @param stream The stream to read from. */
+      PortableBinaryInputArchive(std::istream & stream) :
+        InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
+        itsStream(stream),
+        itsConvertEndianness( false )
+      {
+        bool streamLittleEndian;
+        this->operator()( streamLittleEndian );
+        itsConvertEndianness = portable_binary_detail::is_little_endian() ^ streamLittleEndian;
+      }
+
+      //! Reads size bytes of data from the input stream
+      /*! @param data The data to save
+          @param size The number of bytes in the data
+          @tparam DataSize T The size of the actual type of the data elements being loaded */
+      template <std::size_t DataSize>
+      void loadBinary( void * const data, std::size_t size )
+      {
+        // load data
+        auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
+
+        if(readSize != size)
+          throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
+
+        // flip bits if needed
+        if( itsConvertEndianness )
+        {
+          std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
+          for( std::size_t i = 0; i < size; i += DataSize )
+            portable_binary_detail::swap_bytes<DataSize>( ptr );
+        }
+      }
+
+    private:
+      std::istream & itsStream;
+      bool itsConvertEndianness; //!< If set to true, we will need to swap bytes upon loading
+  };
+
+  // ######################################################################
+  // Common BinaryArchive serialization functions
+
+  //! Saving for POD types to portable binary
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
+  {
+    static_assert( !std::is_floating_point<T>::value ||
+                   (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
+                   "Portable binary only supports IEEE 754 standardized floating point" );
+    ar.saveBinary(std::addressof(t), sizeof(t));
+  }
+
+  //! Loading for POD types from portable binary
+  template<class T> inline
+  typename std::enable_if<std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
+  {
+    static_assert( !std::is_floating_point<T>::value ||
+                   (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
+                   "Portable binary only supports IEEE 754 standardized floating point" );
+    ar.template loadBinary<sizeof(T)>(std::addressof(t), sizeof(t));
+  }
+
+  //! Serializing NVP types to portable binary
+  template <class Archive, class T> inline
+  CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
+  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
+  {
+    ar( t.value );
+  }
+
+  //! Serializing SizeTags to portable binary
+  template <class Archive, class T> inline
+  CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
+  CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
+  {
+    ar( t.size );
+  }
+
+  //! Saving binary data to portable binary
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
+  {
+    typedef typename std::remove_pointer<T>::type TT;
+    static_assert( !std::is_floating_point<TT>::value ||
+                   (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
+                   "Portable binary only supports IEEE 754 standardized floating point" );
+
+    ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
+  }
+
+  //! Loading binary data from portable binary
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
+  {
+    typedef typename std::remove_pointer<T>::type TT;
+    static_assert( !std::is_floating_point<TT>::value ||
+                   (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
+                   "Portable binary only supports IEEE 754 standardized floating point" );
+
+    ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::size_t>( bd.size ) );
+  }
+} // namespace cereal
+
+// register archives for polymorphic support
+CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
+CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
+
+// tie input and output archives together
+CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
+
+#endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp
new file mode 100644
index 0000000..d04cf6a
--- /dev/null
+++ b/include/cereal/archives/xml.hpp
@@ -0,0 +1,882 @@
+/*! \file xml.hpp
+    \brief XML input and output archives */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_ARCHIVES_XML_HPP_
+#define CEREAL_ARCHIVES_XML_HPP_
+#include <cereal/cereal.hpp>
+#include <cereal/details/util.hpp>
+
+#include <cereal/external/rapidxml/rapidxml.hpp>
+#include <cereal/external/rapidxml/rapidxml_print.hpp>
+#include <cereal/external/base64.hpp>
+
+#include <sstream>
+#include <stack>
+#include <vector>
+#include <limits>
+#include <string>
+#include <cstring>
+#include <cmath>
+
+namespace cereal
+{
+  namespace xml_detail
+  {
+    #ifndef CEREAL_XML_STRING_VALUE
+    //! The default name for the root node in a cereal xml archive.
+    /*! You can define CEREAL_XML_STRING_VALUE to be different assuming you do so
+        before this file is included. */
+    #define CEREAL_XML_STRING_VALUE "cereal"
+    #endif // CEREAL_XML_STRING_VALUE
+
+    //! The name given to the root node in a cereal xml archive
+    static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
+
+    //! Returns true if the character is whitespace
+    inline bool isWhitespace( char c )
+    {
+      return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+    }
+  }
+
+  // ######################################################################
+  //! An output archive designed to save data to XML
+  /*! This archive uses RapidXML to build an in memory XML tree of the
+      data it serializes before outputting it to its stream upon destruction.
+      The envisioned way of using this archive is in an RAII fashion, letting
+      the automatic destruction of the object cause the flush to its stream.
+
+      XML archives provides a human readable output but at decreased
+      performance (both in time and space) compared to binary archives.
+
+      XML benefits greatly from name-value pairs, which if present, will
+      name the nodes in the output.  If these are not present, each level
+      of the output tree will be given an automatically generated delimited name.
+
+      The precision of the output archive controls the number of decimals output
+      for floating point numbers and should be sufficiently large (i.e. at least 20)
+      if there is a desire to have binary equality between the numbers output and
+      those read in.  In general you should expect a loss of precision when going
+      from floating point to text and back.
+
+      XML archives can optionally print the type of everything they serialize, which
+      adds an attribute to each node.
+
+      XML archives do not output the size information for any dynamically sized structure
+      and instead infer it from the number of children for a node.  This means that data
+      can be hand edited for dynamic sized structures and will still be readable.  This
+      is accomplished through the cereal::SizeTag object, which will also add an attribute
+      to its parent field.
+      \ingroup Archives */
+  class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
+  {
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an XMLOutputArchive */
+      //! @{
+
+      //! A class containing various advanced options for the XML archive
+      class Options
+      {
+        public:
+          //! Default options
+          static Options Default(){ return Options(); }
+
+          //! Default options with no indentation
+          static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, false ); }
+
+          //! Specify specific options for the XMLOutputArchive
+          /*! @param precision The precision used for floating point numbers
+              @param indent Whether to indent each line of XML
+              @param outputType Whether to output the type of each serialized object as an attribute */
+          explicit Options( int precision = std::numeric_limits<double>::max_digits10,
+                            bool indent = true,
+                            bool outputType = false ) :
+            itsPrecision( precision ),
+            itsIndent( indent ),
+            itsOutputType( outputType ) { }
+
+        private:
+          friend class XMLOutputArchive;
+          int itsPrecision;
+          bool itsIndent;
+          bool itsOutputType;
+      };
+
+      //! Construct, outputting to the provided stream upon destruction
+      /*! @param stream  The stream to output to.  Note that XML is only guaranteed to flush
+                         its output to the stream upon destruction.
+          @param options The XML specific options to use.  See the Options struct
+                         for the values of default parameters */
+      XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
+        OutputArchive<XMLOutputArchive>(this),
+        itsStream(stream),
+        itsOutputType( options.itsOutputType ),
+        itsIndent( options.itsIndent )
+      {
+        // rapidxml will delete all allocations when xml_document is cleared
+        auto node = itsXML.allocate_node( rapidxml::node_declaration );
+        node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
+        node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
+        itsXML.append_node( node );
+
+        // allocate root node
+        auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
+        itsXML.append_node( root );
+        itsNodes.emplace( root );
+
+        // set attributes on the streams
+        itsStream << std::boolalpha;
+        itsStream.precision( options.itsPrecision );
+        itsOS << std::boolalpha;
+        itsOS.precision( options.itsPrecision );
+      }
+
+      //! Destructor, flushes the XML
+      ~XMLOutputArchive()
+      {
+        const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
+        rapidxml::print( itsStream, itsXML, flags );
+        itsXML.clear();
+      }
+
+      //! Saves some binary data, encoded as a base64 string, with an optional name
+      /*! This can be called directly by users and it will automatically create a child node for
+          the current XML node, populate it with a base64 encoded string, and optionally name
+          it.  The node will be finished after it has been populated.  */
+      void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
+      {
+        itsNodes.top().name = name;
+
+        startNode();
+
+        auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
+        saveValue( base64string );
+
+        if( itsOutputType )
+          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
+
+        finishNode();
+      };
+
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the XMLOutputArchive */
+      //! @{
+
+      //! Creates a new node that is a child of the node at the top of the stack
+      /*! Nodes will be given a name that has either been pre-set by a name value pair,
+          or generated based upon a counter unique to the parent node.  If you want to
+          give a node a specific name, use setNextName prior to calling startNode.
+
+          The node will then be pushed onto the node stack. */
+      void startNode()
+      {
+        // generate a name for this new node
+        const auto nameString = itsNodes.top().getValueName();
+
+        // allocate strings for all of the data in the XML object
+        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
+
+        // insert into the XML
+        auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
+        itsNodes.top().node->append_node( node );
+        itsNodes.emplace( node );
+      }
+
+      //! Designates the most recently added node as finished
+      void finishNode()
+      {
+        itsNodes.pop();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNodes.top().name = name;
+      }
+
+      //! Saves some data, encoded as a string, into the current top level node
+      /*! The data will be be named with the most recent name if one exists,
+          otherwise it will be given some default delimited value that depends upon
+          the parent node */
+      template <class T> inline
+      void saveValue( T const & value )
+      {
+        itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
+        itsOS << value << std::ends;
+
+        const auto strValue = itsOS.str();
+
+        // If the first or last character is a whitespace, add xml:space attribute
+        // the string always contains a '\0' added by std::ends, so the last character is at len-2 and an 'empty' 
+        // string has a length of 1 or lower
+        const auto len = strValue.length();
+        if ( len > 1 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 2] ) ) )
+        {
+          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
+        }
+
+        // allocate strings for all of the data in the XML object
+        auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 );
+
+        // insert into the XML
+        itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
+      }
+
+      //! Overload for uint8_t prevents them from being serialized as characters
+      void saveValue( uint8_t const & value )
+      {
+        saveValue( static_cast<uint32_t>( value ) );
+      }
+
+      //! Overload for int8_t prevents them from being serialized as characters
+      void saveValue( int8_t const & value )
+      {
+        saveValue( static_cast<int32_t>( value ) );
+      }
+
+      //! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
+      template <class T> inline
+      void insertType()
+      {
+        if( !itsOutputType )
+          return;
+
+        // generate a name for this new node
+        const auto nameString = util::demangledName<T>();
+
+        // allocate strings for all of the data in the XML object
+        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
+
+        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
+      }
+
+      //! Appends an attribute to the current top level node
+      void appendAttribute( const char * name, const char * value )
+      {
+        auto namePtr =  itsXML.allocate_string( name );
+        auto valuePtr = itsXML.allocate_string( value );
+        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
+      }
+
+    protected:
+      //! A struct that contains metadata about a node
+      struct NodeInfo
+      {
+        NodeInfo( rapidxml::xml_node<> * n = nullptr,
+                  const char * nm = nullptr ) :
+          node( n ),
+          counter( 0 ),
+          name( nm )
+        { }
+
+        rapidxml::xml_node<> * node; //!< A pointer to this node
+        size_t counter;              //!< The counter for naming child nodes
+        const char * name;           //!< The name for the next child node
+
+        //! Gets the name for the next child node created from this node
+        /*! The name will be automatically generated using the counter if
+            a name has not been previously set.  If a name has been previously
+            set, that name will be returned only once */
+        std::string getValueName()
+        {
+          if( name )
+          {
+            auto n = name;
+            name = nullptr;
+            return {n};
+          }
+          else
+            return "value" + std::to_string( counter++ ) + "\0";
+        }
+      }; // NodeInfo
+
+      //! @}
+
+    private:
+      std::ostream & itsStream;        //!< The output stream
+      rapidxml::xml_document<> itsXML; //!< The XML document
+      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes added to the document
+      std::ostringstream itsOS;        //!< Used to format strings internally
+      bool itsOutputType;              //!< Controls whether type information is printed
+      bool itsIndent;                  //!< Controls whether indenting is used
+  }; // XMLOutputArchive
+
+  // ######################################################################
+  //! An output archive designed to load data from XML
+  /*! This archive uses RapidXML to build an in memory XML tree of the
+      data in the stream it is given before loading any types serialized.
+
+      Input XML should have been produced by the XMLOutputArchive.  Data can
+      only be added to dynamically sized containers - the input archive will
+      determine their size by looking at the number of child nodes.  Data that
+      did not originate from an XMLOutputArchive is not officially supported,
+      but may be possible to use if properly formatted.
+
+      The XMLInputArchive does not require that nodes are loaded in the same
+      order they were saved by XMLOutputArchive.  Using name value pairs (NVPs),
+      it is possible to load in an out of order fashion or otherwise skip/select
+      specific nodes to load.
+
+      The default behavior of the input archive is to read sequentially starting
+      with the first node and exploring its children.  When a given NVP does
+      not match the read in name for a node, the archive will search for that
+      node at the current level and load it if it exists.  After loading an out of
+      order node, the archive will then proceed back to loading sequentially from
+      its new position.
+
+      Consider this simple example where loading of some data is skipped:
+
+      @code{cpp}
+      // imagine the input file has someData(1-9) saved in order at the top level node
+      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
+      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
+                                                    // match expected NVP name, so we search
+                                                    // for the given NVP and load that value
+      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
+                                                    // current location, proceeding sequentially
+      @endcode
+
+      \ingroup Archives */
+  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
+  {
+    public:
+      /*! @name Common Functionality
+          Common use cases for directly interacting with an XMLInputArchive */
+      //! @{
+
+      //! Construct, reading in from the provided stream
+      /*! Reads in an entire XML document from some stream and parses it as soon
+          as serialization starts
+
+          @param stream The stream to read from.  Can be a stringstream or a file. */
+      XMLInputArchive( std::istream & stream ) :
+        InputArchive<XMLInputArchive>( this ),
+        itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
+      {
+        try
+        {
+          itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
+          itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
+        }
+        catch( rapidxml::parse_error const & )
+        {
+          //std::cerr << "-----Original-----" << std::endl;
+          //stream.seekg(0);
+          //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
+
+          //std::cerr << "-----Error-----" << std::endl;
+          //std::cerr << e.what() << std::endl;
+          //std::cerr << e.where<char>() << std::endl;
+          throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
+        }
+
+        // Parse the root
+        auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
+        if( root == nullptr )
+          throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
+        else
+          itsNodes.emplace( root );
+      }
+
+      //! Loads some binary data, encoded as a base64 string, optionally specified by some name
+      /*! This will automatically start and finish a node to load the data, and can be called directly by
+          users.
+
+          Note that this follows the same ordering rules specified in the class description in regards
+          to loading in/out of order */
+      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
+      {
+        setNextName( name );
+        startNode();
+
+        std::string encoded;
+        loadValue( encoded );
+
+        auto decoded = base64::decode( encoded );
+
+        if( size != decoded.size() )
+          throw Exception("Decoded binary data size does not match specified size");
+
+        std::memcpy( data, decoded.data(), decoded.size() );
+
+        finishNode();
+      };
+
+      //! @}
+      /*! @name Internal Functionality
+          Functionality designed for use by those requiring control over the inner mechanisms of
+          the XMLInputArchive */
+      //! @{
+
+      //! Prepares to start reading the next node
+      /*! This places the next node to be parsed onto the nodes stack.
+
+          By default our strategy is to start with the document root node and then
+          recursively iterate through all children in the order they show up in the document.
+          We don't need to know NVPs do to this; we'll just blindly load in the order things appear in.
+
+          We check to see if the specified NVP matches what the next automatically loaded node is.  If they
+          match, we just continue as normal, going in order.  If they don't match, we attempt to find a node
+          named after the NVP that is being loaded.  If that NVP does not exist, we throw an exception. */
+      void startNode()
+      {
+        auto next = itsNodes.top().child; // By default we would move to the next child node
+        auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
+
+        // If we were given an NVP name, look for it in the current level of the document.
+        //    We only need to do this if either we have exhausted the siblings of the current level or
+        //    the NVP name does not match the name of the node we would normally read next
+        if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
+        {
+          next = itsNodes.top().search( expectedName );
+
+          if( next == nullptr )
+            throw Exception("XML Parsing failed - provided NVP not found");
+        }
+
+        itsNodes.emplace( next );
+      }
+
+      //! Finishes reading the current node
+      void finishNode()
+      {
+        // remove current
+        itsNodes.pop();
+
+        // advance parent
+        itsNodes.top().advance();
+
+        // Reset name
+        itsNodes.top().name = nullptr;
+      }
+
+      //! Retrieves the current node name
+      //! will return @c nullptr if the node does not have a name
+      const char * getNodeName() const
+      {
+        return itsNodes.top().node->name();
+      }
+
+      //! Sets the name for the next node created with startNode
+      void setNextName( const char * name )
+      {
+        itsNodes.top().name = name;
+      }
+
+      //! Loads a bool from the current top node
+      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
+                                          std::is_same<T, bool>::value> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        std::istringstream is( itsNodes.top().node->value() );
+        is.setf( std::ios::boolalpha );
+        is >> value;
+      }
+
+      //! Loads a char (signed or unsigned) from the current top node
+      template <class T, traits::EnableIf<std::is_integral<T>::value,
+                                          !std::is_same<T, bool>::value,
+                                          sizeof(T) == sizeof(char)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
+      }
+
+      //! Load an int8_t from the current top node (ensures we parse entire number)
+      void loadValue( int8_t & value )
+      {
+        int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
+      }
+
+      //! Load a uint8_t from the current top node (ensures we parse entire number)
+      void loadValue( uint8_t & value )
+      {
+        uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
+      }
+
+      //! Loads a type best represented as an unsigned long from the current top node
+      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
+                                          !std::is_same<T, bool>::value,
+                                          !std::is_same<T, unsigned char>::value,
+                                          sizeof(T) < sizeof(long long)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
+      }
+
+      //! Loads a type best represented as an unsigned long long from the current top node
+      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
+                                          !std::is_same<T, bool>::value,
+                                          sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
+      }
+
+      //! Loads a type best represented as an int from the current top node
+      template <class T, traits::EnableIf<std::is_signed<T>::value,
+                                          !std::is_same<T, char>::value,
+                                          sizeof(T) <= sizeof(int)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
+      }
+
+      //! Loads a type best represented as a long from the current top node
+      template <class T, traits::EnableIf<std::is_signed<T>::value,
+                                          (sizeof(T) > sizeof(int)),
+                                          sizeof(T) <= sizeof(long)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
+      }
+
+      //! Loads a type best represented as a long long from the current top node
+      template <class T, traits::EnableIf<std::is_signed<T>::value,
+                                          (sizeof(T) > sizeof(long)),
+                                          sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
+      void loadValue( T & value )
+      {
+        value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
+      }
+
+      //! Loads a type best represented as a float from the current top node
+      void loadValue( float & value )
+      {
+        try
+        {
+          value = std::stof( itsNodes.top().node->value() );
+        }
+        catch( std::out_of_range const & )
+        {
+          // special case for denormalized values
+          std::istringstream is( itsNodes.top().node->value() );
+          is >> value;
+          if( std::fpclassify( value ) != FP_SUBNORMAL )
+            throw;
+        }
+      }
+
+      //! Loads a type best represented as a double from the current top node
+      void loadValue( double & value )
+      {
+        try
+        {
+          value = std::stod( itsNodes.top().node->value() );
+        }
+        catch( std::out_of_range const & )
+        {
+          // special case for denormalized values
+          std::istringstream is( itsNodes.top().node->value() );
+          is >> value;
+          if( std::fpclassify( value ) != FP_SUBNORMAL )
+            throw;
+        }
+      }
+
+      //! Loads a type best represented as a long double from the current top node
+      void loadValue( long double & value )
+      {
+        try
+        {
+          value = std::stold( itsNodes.top().node->value() );
+        }
+        catch( std::out_of_range const & )
+        {
+          // special case for denormalized values
+          std::istringstream is( itsNodes.top().node->value() );
+          is >> value;
+          if( std::fpclassify( value ) != FP_SUBNORMAL )
+            throw;
+        }
+      }
+
+      //! Loads a string from the current node from the current top node
+      template<class CharT, class Traits, class Alloc> inline
+      void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
+      {
+        std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
+
+        str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
+                    std::istreambuf_iterator<CharT, Traits>() );
+      }
+
+      //! Loads the size of the current top node
+      template <class T> inline
+      void loadSize( T & value )
+      {
+        value = getNumChildren( itsNodes.top().node );
+      }
+
+    protected:
+      //! Gets the number of children (usually interpreted as size) for the specified node
+      static size_t getNumChildren( rapidxml::xml_node<> * node )
+      {
+        size_t size = 0;
+        node = node->first_node(); // get first child
+
+        while( node != nullptr )
+        {
+          ++size;
+          node = node->next_sibling();
+        }
+
+        return size;
+      }
+
+      //! A struct that contains metadata about a node
+      /*! Keeps track of some top level node, its number of
+          remaining children, and the current active child node */
+      struct NodeInfo
+      {
+        NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
+          node( n ),
+          child( n->first_node() ),
+          size( XMLInputArchive::getNumChildren( n ) ),
+          name( nullptr )
+        { }
+
+        //! Advances to the next sibling node of the child
+        /*! If this is the last sibling child will be null after calling */
+        void advance()
+        {
+          if( size > 0 )
+          {
+            --size;
+            child = child->next_sibling();
+          }
+        }
+
+        //! Searches for a child with the given name in this node
+        /*! @param searchName The name to search for (must be null terminated)
+            @return The node if found, nullptr otherwise */
+        rapidxml::xml_node<> * search( const char * searchName )
+        {
+          if( searchName )
+          {
+            size_t new_size = XMLInputArchive::getNumChildren( node );
+            const size_t name_size = rapidxml::internal::measure( searchName );
+
+            for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
+            {
+              if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
+              {
+                size = new_size;
+                child = new_child;
+
+                return new_child;
+              }
+              --new_size;
+            }
+          }
+
+          return nullptr;
+        }
+
+        rapidxml::xml_node<> * node;  //!< A pointer to this node
+        rapidxml::xml_node<> * child; //!< A pointer to its current child
+        size_t size;                  //!< The remaining number of children for this node
+        const char * name;            //!< The NVP name for next next child node
+      }; // NodeInfo
+
+      //! @}
+
+    private:
+      std::vector<char> itsData;       //!< The raw data loaded
+      rapidxml::xml_document<> itsXML; //!< The XML document
+      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes read from the document
+  };
+
+  // ######################################################################
+  // XMLArchive prologue and epilogue functions
+  // ######################################################################
+
+  // ######################################################################
+  //! Prologue for NVPs for XML output archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Prologue for NVPs for XML input archives
+  template <class T> inline
+  void prologue( XMLInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Epilogue for NVPs for XML output archives
+  /*! NVPs do not start or finish nodes - they just set up the names */
+  template <class T> inline
+  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
+  { }
+
+  //! Epilogue for NVPs for XML input archives
+  template <class T> inline
+  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for SizeTags for XML output archives
+  /*! SizeTags do not start or finish nodes */
+  template <class T> inline
+  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
+  {
+    ar.appendAttribute( "size", "dynamic" );
+  }
+
+  template <class T> inline
+  void prologue( XMLInputArchive &, SizeTag<T> const & )
+  { }
+
+  //! Epilogue for SizeTags for XML output archives
+  /*! SizeTags do not start or finish nodes */
+  template <class T> inline
+  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
+  { }
+
+  template <class T> inline
+  void epilogue( XMLInputArchive &, SizeTag<T> const & )
+  { }
+
+  // ######################################################################
+  //! Prologue for all other types for XML output archives (except minimal types)
+  /*! Starts a new node, named either automatically or by some NVP,
+      that may be given data by the type about to be archived
+
+      Minimal types do not start or end nodes */
+  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
+                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
+  void prologue( XMLOutputArchive & ar, T const & )
+  {
+    ar.startNode();
+    ar.insertType<T>();
+  }
+
+  //! Prologue for all other types for XML input archives (except minimal types)
+  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
+                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
+  void prologue( XMLInputArchive & ar, T const & )
+  {
+    ar.startNode();
+  }
+
+  // ######################################################################
+  //! Epilogue for all other types other for XML output archives (except minimal types)
+  /*! Finishes the node created in the prologue
+
+      Minimal types do not start or end nodes */
+  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
+                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
+  void epilogue( XMLOutputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  //! Epilogue for all other types other for XML output archives (except minimal types)
+  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
+                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
+  void epilogue( XMLInputArchive & ar, T const & )
+  {
+    ar.finishNode();
+  }
+
+  // ######################################################################
+  // Common XMLArchive serialization functions
+  // ######################################################################
+
+  //! Saving NVP types to XML
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  //! Loading NVP types from XML
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
+  {
+    ar.setNextName( t.name );
+    ar( t.value );
+  }
+
+  // ######################################################################
+  //! Saving SizeTags to XML
+  template <class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
+  { }
+
+  //! Loading SizeTags from XML
+  template <class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
+  {
+    ar.loadSize( st.size );
+  }
+
+  // ######################################################################
+  //! Saving for POD types to xml
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
+  {
+    ar.saveValue( t );
+  }
+
+  //! Loading for POD types from xml
+  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
+  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
+  {
+    ar.loadValue( t );
+  }
+
+  // ######################################################################
+  //! saving string to xml
+  template<class CharT, class Traits, class Alloc> inline
+  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
+  {
+    ar.saveValue( str );
+  }
+
+  //! loading string from xml
+  template<class CharT, class Traits, class Alloc> inline
+  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
+  {
+    ar.loadValue( str );
+  }
+} // namespace cereal
+
+// register archives for polymorphic support
+CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
+CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
+
+// tie input and output archives together
+CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
+
+#endif // CEREAL_ARCHIVES_XML_HPP_
diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp
new file mode 100644
index 0000000..040366d
--- /dev/null
+++ b/include/cereal/cereal.hpp
@@ -0,0 +1,955 @@
+/*! \file cereal.hpp
+    \brief Main cereal functionality */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_CEREAL_HPP_
+#define CEREAL_CEREAL_HPP_
+
+#include <type_traits>
+#include <string>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+
+#include <cereal/macros.hpp>
+#include <cereal/details/traits.hpp>
+#include <cereal/details/helpers.hpp>
+#include <cereal/types/base_class.hpp>
+
+namespace cereal
+{
+  // ######################################################################
+  //! Creates a name value pair
+  /*! @relates NameValuePair
+      @ingroup Utility */
+  template <class T> inline
+  NameValuePair<T> make_nvp( std::string const & name, T && value )
+  {
+    return {name.c_str(), std::forward<T>(value)};
+  }
+
+  //! Creates a name value pair
+  /*! @relates NameValuePair
+      @ingroup Utility */
+  template <class T> inline
+  NameValuePair<T> make_nvp( const char * name, T && value )
+  {
+    return {name, std::forward<T>(value)};
+  }
+
+  //! Creates a name value pair for the variable T with the same name as the variable
+  /*! @relates NameValuePair
+      @ingroup Utility */
+  #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
+
+  // ######################################################################
+  //! Convenience function to create binary data for both const and non const pointers
+  /*! @param data Pointer to beginning of the data
+      @param size The size in bytes of the data
+      @relates BinaryData
+      @ingroup Utility */
+  template <class T> inline
+  BinaryData<T> binary_data( T && data, size_t size )
+  {
+    return {std::forward<T>(data), size};
+  }
+
+  // ######################################################################
+  //! Creates a size tag from some variable.
+  /*! Will normally be used to serialize size (e.g. size()) information for
+      variable size containers.  If you have a variable sized container,
+      the very first thing it serializes should be its size, wrapped in
+      a SizeTag.
+
+      @relates SizeTag
+      @ingroup Utility */
+  template <class T>
+  SizeTag<T> make_size_tag( T && sz )
+  {
+    return {std::forward<T>(sz)};
+  }
+
+  // ######################################################################
+  //! Called before a type is serialized to set up any special archive state
+  //! for processing some type
+  /*! If designing a serializer that needs to set up any kind of special
+      state or output extra information for a type, specialize this function
+      for the archive type and the types that require the extra information.
+      @ingroup Internal */
+  template <class Archive, class T>
+  void prologue( Archive & /* archive */, T const & /* data */)
+  { }
+
+  //! Called after a type is serialized to tear down any special archive state
+  //! for processing some type
+  /*! @ingroup Internal */
+  template <class Archive, class T>
+  void epilogue( Archive & /* archive */, T const & /* data */)
+  { }
+
+  // ######################################################################
+  //! Special flags for archives
+  /*! AllowEmptyClassElision
+        This allows for empty classes to be serialized even if they do not provide
+        a serialization function.  Classes with no data members are considered to be
+        empty.  Be warned that if this is enabled and you attempt to serialize an
+        empty class with improperly formed serialize or load/save functions, no
+        static error will occur - the error will propogate silently and your
+        intended serialization functions may not be called.  You can manually
+        ensure that your classes that have custom serialization are correct
+        by using the traits is_output_serializable and is_input_serializable
+        in cereal/details/traits.hpp.
+      @ingroup Internal */
+  enum Flags { AllowEmptyClassElision = 1 };
+
+  // ######################################################################
+  //! Registers a specific Archive type with cereal
+  /*! This registration should be done once per archive.  A good place to
+      put this is immediately following the definition of your archive.
+      Archive registration is only strictly necessary if you wish to
+      support pointers to polymorphic data types.  All archives that
+      come with cereal are already registered.
+      @ingroup Internal */
+  #define CEREAL_REGISTER_ARCHIVE(Archive)                              \
+  namespace cereal { namespace detail {                                 \
+  template <class T, class BindingTag>                                  \
+  typename polymorphic_serialization_support<Archive, T>::type          \
+  instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
+  } } /* end namespaces */
+
+  // ######################################################################
+  //! Defines a class version for some type
+  /*! Versioning information is optional and adds some small amount of
+      overhead to serialization.  This overhead will occur both in terms of
+      space in the archive (the version information for each class will be
+      stored exactly once) as well as runtime (versioned serialization functions
+      must check to see if they need to load or store version information).
+
+      Versioning is useful if you plan on fundamentally changing the way some
+      type is serialized in the future.  Versioned serialization functions
+      cannot be used to load non-versioned data.
+
+      By default, all types have an assumed version value of zero.  By
+      using this macro, you may change the version number associated with
+      some type.  cereal will then use this value as a second parameter
+      to your serialization functions.
+
+      The interface for the serialization functions is nearly identical
+      to non-versioned serialization with the addition of a second parameter,
+      const std::uint32_t version, which will be supplied with the correct
+      version number.  Serializing the version number on a save happens
+      automatically.
+
+      Versioning cannot be mixed with non-versioned serialization functions.
+      Having both types will result result in a compile time error.  Data
+      serialized without versioning cannot be loaded by a serialization
+      function with added versioning support.
+
+      Example interface for versioning on a non-member serialize function:
+
+      @code{cpp}
+      CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
+
+      template <class Archive>
+      void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
+      {
+        // When performing a load, the version associated with the class
+        // is whatever it was when that data was originally serialized
+        //
+        // When we save, we'll use the version that is defined in the macro
+
+        if( version >= some_number )
+          // do this
+        else
+          // do that
+      }
+      @endcode
+
+      Interfaces for other forms of serialization functions is similar.  This
+      macro should be placed at global scope.
+      @ingroup Utility */
+  #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
+  namespace cereal { namespace detail {                                          \
+    template <> struct Version<TYPE>                                             \
+    {                                                                            \
+      static const std::uint32_t version;                                        \
+      static std::uint32_t registerVersion()                                     \
+      {                                                                          \
+        ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
+             std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
+        return VERSION_NUMBER;                                                   \
+      }                                                                          \
+      static void unused() { (void)version; }                                    \
+    }; /* end Version */                                                         \
+    const std::uint32_t Version<TYPE>::version =                                 \
+      Version<TYPE>::registerVersion();                                          \
+  } } // end namespaces
+
+  // ######################################################################
+  //! The base output archive class
+  /*! This is the base output archive for all output archives.  If you create
+      a custom archive class, it should derive from this, passing itself as
+      a template parameter for the ArchiveType.
+
+      The base class provides all of the functionality necessary to
+      properly forward data to the correct serialization functions.
+
+      Individual archives should use a combination of prologue and
+      epilogue functions together with specializations of serialize, save,
+      and load to alter the functionality of their serialization.
+
+      @tparam ArchiveType The archive type that derives from OutputArchive
+      @tparam Flags Flags to control advanced functionality.  See the Flags
+                    enum for more information.
+      @ingroup Internal */
+  template<class ArchiveType, std::uint32_t Flags = 0>
+  class OutputArchive : public detail::OutputArchiveBase
+  {
+    public:
+      //! Construct the output archive
+      /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
+      OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
+      { }
+
+      OutputArchive & operator=( OutputArchive const & ) = delete;
+
+      //! Serializes all passed in data
+      /*! This is the primary interface for serializing data with an archive */
+      template <class ... Types> inline
+      ArchiveType & operator()( Types && ... args )
+      {
+        self->process( std::forward<Types>( args )... );
+        return *self;
+      }
+
+      /*! @name Boost Transition Layer
+          Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
+          a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
+      //! @{
+
+      //! Serializes passed in data
+      /*! This is a boost compatability layer and is not the preferred way of using
+          cereal.  If you are transitioning from boost, use this until you can
+          transition to the operator() overload */
+      template <class T> inline
+      ArchiveType & operator&( T && arg )
+      {
+        self->process( std::forward<T>( arg ) );
+        return *self;
+      }
+
+      //! Serializes passed in data
+      /*! This is a boost compatability layer and is not the preferred way of using
+          cereal.  If you are transitioning from boost, use this until you can
+          transition to the operator() overload */
+      template <class T> inline
+      ArchiveType & operator<<( T && arg )
+      {
+        self->process( std::forward<T>( arg ) );
+        return *self;
+      }
+
+      //! @}
+
+      //! Registers a shared pointer with the archive
+      /*! This function is used to track shared pointer targets to prevent
+          unnecessary saves from taking place if multiple shared pointers
+          point to the same data.
+
+          @internal
+          @param addr The address (see shared_ptr get()) pointed to by the shared pointer
+          @return A key that uniquely identifies the pointer */
+      inline std::uint32_t registerSharedPointer( void const * addr )
+      {
+        // Handle null pointers by just returning 0
+        if(addr == 0) return 0;
+
+        auto id = itsSharedPointerMap.find( addr );
+        if( id == itsSharedPointerMap.end() )
+        {
+          auto ptrId = itsCurrentPointerId++;
+          itsSharedPointerMap.insert( {addr, ptrId} );
+          return ptrId | detail::msb_32bit; // mask MSB to be 1
+        }
+        else
+          return id->second;
+      }
+
+      //! Registers a polymorphic type name with the archive
+      /*! This function is used to track polymorphic types to prevent
+          unnecessary saves of identifying strings used by the polymorphic
+          support functionality.
+
+          @internal
+          @param name The name to associate with a polymorphic type
+          @return A key that uniquely identifies the polymorphic type name */
+      inline std::uint32_t registerPolymorphicType( char const * name )
+      {
+        auto id = itsPolymorphicTypeMap.find( name );
+        if( id == itsPolymorphicTypeMap.end() )
+        {
+          auto polyId = itsCurrentPolymorphicTypeId++;
+          itsPolymorphicTypeMap.insert( {name, polyId} );
+          return polyId | detail::msb_32bit; // mask MSB to be 1
+        }
+        else
+          return id->second;
+      }
+
+    private:
+      //! Serializes data after calling prologue, then calls epilogue
+      template <class T> inline
+      void process( T && head )
+      {
+        prologue( *self, head );
+        self->processImpl( head );
+        epilogue( *self, head );
+      }
+
+      //! Unwinds to process all data
+      template <class T, class ... Other> inline
+      void process( T && head, Other && ... tail )
+      {
+        self->process( std::forward<T>( head ) );
+        self->process( std::forward<Other>( tail )... );
+      }
+
+      //! Serialization of a virtual_base_class wrapper
+      /*! \sa virtual_base_class */
+      template <class T> inline
+      ArchiveType & processImpl(virtual_base_class<T> const & b)
+      {
+        traits::detail::base_class_id id(b.base_ptr);
+        if(itsBaseClassSet.count(id) == 0)
+        {
+          itsBaseClassSet.insert(id);
+          self->processImpl( *b.base_ptr );
+        }
+        return *self;
+      }
+
+      //! Serialization of a base_class wrapper
+      /*! \sa base_class */
+      template <class T> inline
+      ArchiveType & processImpl(base_class<T> const & b)
+      {
+        self->processImpl( *b.base_ptr );
+        return *self;
+      }
+
+      //! Helper macro that expands the requirements for activating an overload
+      /*! Requirements:
+            Has the requested serialization function
+            Does not have version and unversioned at the same time
+            Is output serializable AND
+              is specialized for this type of function OR
+              has no specialization at all */
+      #define PROCESS_IF(name)                                                             \
+      traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                          \
+                       !traits::has_invalid_output_versioning<T, ArchiveType>::value,      \
+                       (traits::is_output_serializable<T, ArchiveType>::value &&           \
+                        (traits::is_specialized_##name<T, ArchiveType>::value ||           \
+                         !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
+
+      //! Member serialization
+      template <class T, PROCESS_IF(member_serialize)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        access::member_serialize(*self, const_cast<T &>(t));
+        return *self;
+      }
+
+      //! Non member serialization
+      template <class T, PROCESS_IF(non_member_serialize)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
+        return *self;
+      }
+
+      //! Member split (save)
+      template <class T, PROCESS_IF(member_save)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        access::member_save(*self, t);
+        return *self;
+      }
+
+      //! Non member split (save)
+      template <class T, PROCESS_IF(non_member_save)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        CEREAL_SAVE_FUNCTION_NAME(*self, t);
+        return *self;
+      }
+
+      //! Member split (save_minimal)
+      template <class T, PROCESS_IF(member_save_minimal)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        self->process( access::member_save_minimal(*self, t) );
+        return *self;
+      }
+
+      //! Non member split (save_minimal)
+      template <class T, PROCESS_IF(non_member_save_minimal)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
+        return *self;
+      }
+
+      //! Empty class specialization
+      template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
+                                          !traits::is_output_serializable<T, ArchiveType>::value,
+                                          std::is_empty<T>::value> = traits::sfinae> inline
+      ArchiveType & processImpl(T const &)
+      {
+        return *self;
+      }
+
+      //! No matching serialization
+      /*! Invalid if we have invalid output versioning or
+          we are not output serializable, and either
+          don't allow empty class ellision or allow it but are not serializing an empty class */
+      template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
+                                          (!traits::is_output_serializable<T, ArchiveType>::value &&
+                                           (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
+      ArchiveType & processImpl(T const &)
+      {
+        static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
+            "cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
+            "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
+            "Serialize functions generally have the following signature: \n\n "
+            "template<class Archive> \n "
+            "  void serialize(Archive & ar) \n "
+            "  { \n "
+            "    ar( member1, member2, member3 ); \n "
+            "  } \n\n " );
+
+        static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
+            "cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
+            "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
+            "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
+            "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
+            "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
+
+        return *self;
+      }
+
+      //! Registers a class version with the archive and serializes it if necessary
+      /*! If this is the first time this class has been serialized, we will record its
+          version number and serialize that.
+
+          @tparam T The type of the class being serialized
+          @param version The version number associated with it */
+      template <class T> inline
+      std::uint32_t registerClassVersion()
+      {
+        static const auto hash = std::type_index(typeid(T)).hash_code();
+        const auto insertResult = itsVersionedTypes.insert( hash );
+        const auto version =
+          detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
+
+        if( insertResult.second ) // insertion took place, serialize the version number
+          process( make_nvp<ArchiveType>("cereal_class_version", version) );
+
+        return version;
+      }
+
+      //! Member serialization
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_serialize)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
+        return *self;
+      }
+
+      //! Non member serialization
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
+        return *self;
+      }
+
+      //! Member split (save)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_save)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        access::member_save(*self, t, registerClassVersion<T>());
+        return *self;
+      }
+
+      //! Non member split (save)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_save)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
+        return *self;
+      }
+
+      //! Member split (save_minimal)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
+        return *self;
+      }
+
+      //! Non member split (save_minimal)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
+      ArchiveType & processImpl(T const & t)
+      {
+        self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
+        return *self;
+      }
+
+    #undef PROCESS_IF
+
+    private:
+      ArchiveType * const self;
+
+      //! A set of all base classes that have been serialized
+      std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
+
+      //! Maps from addresses to pointer ids
+      std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
+
+      //! The id to be given to the next pointer
+      std::uint32_t itsCurrentPointerId;
+
+      //! Maps from polymorphic type name strings to ids
+      std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
+
+      //! The id to be given to the next polymorphic type name
+      std::uint32_t itsCurrentPolymorphicTypeId;
+
+      //! Keeps track of classes that have versioning information associated with them
+      std::unordered_set<size_type> itsVersionedTypes;
+  }; // class OutputArchive
+
+  // ######################################################################
+  //! The base input archive class
+  /*! This is the base input archive for all input archives.  If you create
+      a custom archive class, it should derive from this, passing itself as
+      a template parameter for the ArchiveType.
+
+      The base class provides all of the functionality necessary to
+      properly forward data to the correct serialization functions.
+
+      Individual archives should use a combination of prologue and
+      epilogue functions together with specializations of serialize, save,
+      and load to alter the functionality of their serialization.
+
+      @tparam ArchiveType The archive type that derives from InputArchive
+      @tparam Flags Flags to control advanced functionality.  See the Flags
+                    enum for more information.
+      @ingroup Internal */
+  template<class ArchiveType, std::uint32_t Flags = 0>
+  class InputArchive : public detail::InputArchiveBase
+  {
+    public:
+      //! Construct the output archive
+      /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
+      InputArchive(ArchiveType * const derived) :
+        self(derived),
+        itsBaseClassSet(),
+        itsSharedPointerMap(),
+        itsPolymorphicTypeMap(),
+        itsVersionedTypes()
+      { }
+
+      InputArchive & operator=( InputArchive const & ) = delete;
+
+      //! Serializes all passed in data
+      /*! This is the primary interface for serializing data with an archive */
+      template <class ... Types> inline
+      ArchiveType & operator()( Types && ... args )
+      {
+        process( std::forward<Types>( args )... );
+        return *self;
+      }
+
+      /*! @name Boost Transition Layer
+          Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
+          a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
+      //! @{
+
+      //! Serializes passed in data
+      /*! This is a boost compatability layer and is not the preferred way of using
+          cereal.  If you are transitioning from boost, use this until you can
+          transition to the operator() overload */
+      template <class T> inline
+      ArchiveType & operator&( T && arg )
+      {
+        self->process( std::forward<T>( arg ) );
+        return *self;
+      }
+
+      //! Serializes passed in data
+      /*! This is a boost compatability layer and is not the preferred way of using
+          cereal.  If you are transitioning from boost, use this until you can
+          transition to the operator() overload */
+      template <class T> inline
+      ArchiveType & operator>>( T && arg )
+      {
+        self->process( std::forward<T>( arg ) );
+        return *self;
+      }
+
+      //! @}
+
+      //! Retrieves a shared pointer given a unique key for it
+      /*! This is used to retrieve a previously registered shared_ptr
+          which has already been loaded.
+
+          @param id The unique id that was serialized for the pointer
+          @return A shared pointer to the data
+          @throw Exception if the id does not exist */
+      inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
+      {
+        if(id == 0) return std::shared_ptr<void>(nullptr);
+
+        auto iter = itsSharedPointerMap.find( id );
+        if(iter == itsSharedPointerMap.end())
+          throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
+
+        return iter->second;
+      }
+
+      //! Registers a shared pointer to its unique identifier
+      /*! After a shared pointer has been allocated for the first time, it should
+          be registered with its loaded id for future references to it.
+
+          @param id The unique identifier for the shared pointer
+          @param ptr The actual shared pointer */
+      inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
+      {
+        std::uint32_t const stripped_id = id & ~detail::msb_32bit;
+        itsSharedPointerMap[stripped_id] = ptr;
+      }
+
+      //! Retrieves the string for a polymorphic type given a unique key for it
+      /*! This is used to retrieve a string previously registered during
+          a polymorphic load.
+
+          @param id The unique id that was serialized for the polymorphic type
+          @return The string identifier for the tyep */
+      inline std::string getPolymorphicName(std::uint32_t const id)
+      {
+        auto name = itsPolymorphicTypeMap.find( id );
+        if(name == itsPolymorphicTypeMap.end())
+        {
+          throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
+        }
+        return name->second;
+      }
+
+      //! Registers a polymorphic name string to its unique identifier
+      /*! After a polymorphic type has been loaded for the first time, it should
+          be registered with its loaded id for future references to it.
+
+          @param id The unique identifier for the polymorphic type
+          @param name The name associated with the tyep */
+      inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
+      {
+        std::uint32_t const stripped_id = id & ~detail::msb_32bit;
+        itsPolymorphicTypeMap.insert( {stripped_id, name} );
+      }
+
+    private:
+      //! Serializes data after calling prologue, then calls epilogue
+      template <class T> inline
+      void process( T && head )
+      {
+        prologue( *self, head );
+        self->processImpl( head );
+        epilogue( *self, head );
+      }
+
+      //! Unwinds to process all data
+      template <class T, class ... Other> inline
+      void process( T && head, Other && ... tail )
+      {
+        process( std::forward<T>( head ) );
+        process( std::forward<Other>( tail )... );
+      }
+
+      //! Serialization of a virtual_base_class wrapper
+      /*! \sa virtual_base_class */
+      template <class T> inline
+      ArchiveType & processImpl(virtual_base_class<T> & b)
+      {
+        traits::detail::base_class_id id(b.base_ptr);
+        if(itsBaseClassSet.count(id) == 0)
+        {
+          itsBaseClassSet.insert(id);
+          self->processImpl( *b.base_ptr );
+        }
+        return *self;
+      }
+
+      //! Serialization of a base_class wrapper
+      /*! \sa base_class */
+      template <class T> inline
+      ArchiveType & processImpl(base_class<T> & b)
+      {
+        self->processImpl( *b.base_ptr );
+        return *self;
+      }
+
+      //! Helper macro that expands the requirements for activating an overload
+      /*! Requirements:
+            Has the requested serialization function
+            Does not have version and unversioned at the same time
+            Is input serializable AND
+              is specialized for this type of function OR
+              has no specialization at all */
+      #define PROCESS_IF(name)                                                              \
+      traits::EnableIf<traits::has_##name<T, ArchiveType>::value,                           \
+                       !traits::has_invalid_input_versioning<T, ArchiveType>::value,        \
+                       (traits::is_input_serializable<T, ArchiveType>::value &&             \
+                        (traits::is_specialized_##name<T, ArchiveType>::value ||            \
+                         !traits::is_specialized<T, ArchiveType>::value))> = traits::sfinae
+
+      //! Member serialization
+      template <class T, PROCESS_IF(member_serialize)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        access::member_serialize(*self, t);
+        return *self;
+      }
+
+      //! Non member serialization
+      template <class T, PROCESS_IF(non_member_serialize)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
+        return *self;
+      }
+
+      //! Member split (load)
+      template <class T, PROCESS_IF(member_load)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        access::member_load(*self, t);
+        return *self;
+      }
+
+      //! Non member split (load)
+      template <class T, PROCESS_IF(non_member_load)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        CEREAL_LOAD_FUNCTION_NAME(*self, t);
+        return *self;
+      }
+
+      //! Member split (load_minimal)
+      template <class T, PROCESS_IF(member_load_minimal)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
+        typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
+        self->process( value );
+        access::member_load_minimal(*self, t, value);
+        return *self;
+      }
+
+      //! Non member split (load_minimal)
+      template <class T, PROCESS_IF(non_member_load_minimal)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
+        typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
+        self->process( value );
+        CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
+        return *self;
+      }
+
+      //! Empty class specialization
+      template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
+                                          !traits::is_input_serializable<T, ArchiveType>::value,
+                                          std::is_empty<T>::value> = traits::sfinae> inline
+      ArchiveType & processImpl(T const &)
+      {
+        return *self;
+      }
+
+      //! No matching serialization
+      /*! Invalid if we have invalid input versioning or
+          we are not input serializable, and either
+          don't allow empty class ellision or allow it but are not serializing an empty class */
+      template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
+                                          (!traits::is_input_serializable<T, ArchiveType>::value &&
+                                           (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
+      ArchiveType & processImpl(T const &)
+      {
+        static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
+            "cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
+            "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
+            "Serialize functions generally have the following signature: \n\n "
+            "template<class Archive> \n "
+            "  void serialize(Archive & ar) \n "
+            "  { \n "
+            "    ar( member1, member2, member3 ); \n "
+            "  } \n\n " );
+
+        static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
+            "cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
+            "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
+            "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
+            "Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
+            "In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
+
+        return *self;
+      }
+
+      //! Registers a class version with the archive and serializes it if necessary
+      /*! If this is the first time this class has been serialized, we will record its
+          version number and serialize that.
+
+          @tparam T The type of the class being serialized
+          @param version The version number associated with it */
+      template <class T> inline
+      std::uint32_t loadClassVersion()
+      {
+        static const auto hash = std::type_index(typeid(T)).hash_code();
+        auto lookupResult = itsVersionedTypes.find( hash );
+
+        if( lookupResult != itsVersionedTypes.end() ) // already exists
+          return lookupResult->second;
+        else // need to load
+        {
+          std::uint32_t version;
+
+          process( make_nvp<ArchiveType>("cereal_class_version", version) );
+          itsVersionedTypes.emplace_hint( lookupResult, hash, version );
+
+          return version;
+        }
+      }
+
+      //! Member serialization
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_serialize)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        const auto version = loadClassVersion<T>();
+        access::member_serialize(*self, t, version);
+        return *self;
+      }
+
+      //! Non member serialization
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        const auto version = loadClassVersion<T>();
+        CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
+        return *self;
+      }
+
+      //! Member split (load)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_load)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        const auto version = loadClassVersion<T>();
+        access::member_load(*self, t, version);
+        return *self;
+      }
+
+      //! Non member split (load)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_load)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        const auto version = loadClassVersion<T>();
+        CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
+        return *self;
+      }
+
+      //! Member split (load_minimal)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
+        const auto version = loadClassVersion<T>();
+        typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
+        self->process(value);
+        access::member_load_minimal(*self, t, value, version);
+        return *self;
+      }
+
+      //! Non member split (load_minimal)
+      /*! Versioning implementation */
+      template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
+      ArchiveType & processImpl(T & t)
+      {
+        using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
+        const auto version = loadClassVersion<T>();
+        typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
+        self->process(value);
+        CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
+        return *self;
+      }
+
+      #undef PROCESS_IF
+
+    private:
+      ArchiveType * const self;
+
+      //! A set of all base classes that have been serialized
+      std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
+
+      //! Maps from pointer ids to metadata
+      std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
+
+      //! Maps from name ids to names
+      std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
+
+      //! Maps from type hash codes to version numbers
+      std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
+  }; // class InputArchive
+} // namespace cereal
+
+// This include needs to come after things such as binary_data, make_nvp, etc
+#include <cereal/types/common.hpp>
+
+#endif // CEREAL_CEREAL_HPP_
diff --git a/include/cereal/details/helpers.hpp b/include/cereal/details/helpers.hpp
new file mode 100644
index 0000000..5ed8b6b
--- /dev/null
+++ b/include/cereal/details/helpers.hpp
@@ -0,0 +1,360 @@
+/*! \file helpers.hpp
+    \brief Internal helper functionality
+    \ingroup Internal */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_DETAILS_HELPERS_HPP_
+#define CEREAL_DETAILS_HELPERS_HPP_
+
+#include <type_traits>
+#include <cstdint>
+#include <utility>
+#include <memory>
+#include <unordered_map>
+#include <stdexcept>
+
+#include <cereal/macros.hpp>
+#include <cereal/details/static_object.hpp>
+
+namespace cereal
+{
+  // ######################################################################
+  //! An exception class thrown when things go wrong at runtime
+  /*! @ingroup Utility */
+  struct Exception : public std::runtime_error
+  {
+    explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
+    explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
+  };
+
+  // ######################################################################
+  //! The size type used by cereal
+  /*! To ensure compatability between 32, 64, etc bit machines, we need to use
+      a fixed size type instead of size_t, which may vary from machine to
+      machine. */
+  using size_type = uint64_t;
+
+  // forward decls
+  class BinaryOutputArchive;
+  class BinaryInputArchive;
+
+  // ######################################################################
+  namespace detail
+  {
+    struct NameValuePairCore {}; //!< Traits struct for NVPs
+  }
+
+  //! For holding name value pairs
+  /*! This pairs a name (some string) with some value such that an archive
+      can potentially take advantage of the pairing.
+
+      In serialization functions, NameValuePairs are usually created like so:
+      @code{.cpp}
+      struct MyStruct
+      {
+        int a, b, c, d, e;
+
+        template<class Archive>
+        void serialize(Archive & archive)
+        {
+          archive( CEREAL_NVP(a),
+                   CEREAL_NVP(b),
+                   CEREAL_NVP(c),
+                   CEREAL_NVP(d),
+                   CEREAL_NVP(e) );
+        }
+      };
+      @endcode
+
+      Alternatively, you can give you data members custom names like so:
+      @code{.cpp}
+      struct MyStruct
+      {
+        int a, b, my_embarrassing_variable_name, d, e;
+
+        template<class Archive>
+        void serialize(Archive & archive)
+        {
+          archive( CEREAL_NVP(a),
+                   CEREAL_NVP(b),
+                   cereal::make_nvp("var", my_embarrassing_variable_name) );
+                   CEREAL_NVP(d),
+                   CEREAL_NVP(e) );
+        }
+      };
+      @endcode
+
+      There is a slight amount of overhead to creating NameValuePairs, so there
+      is a third method which will elide the names when they are not used by
+      the Archive:
+
+      @code{.cpp}
+      struct MyStruct
+      {
+        int a, b;
+
+        template<class Archive>
+        void serialize(Archive & archive)
+        {
+          archive( cereal::make_nvp<Archive>(a),
+                   cereal::make_nvp<Archive>(b) );
+        }
+      };
+      @endcode
+
+      This third method is generally only used when providing generic type
+      support.  Users writing their own serialize functions will normally
+      explicitly control whether they want to use NVPs or not.
+
+      @internal */
+  template <class T>
+  class NameValuePair : detail::NameValuePairCore
+  {
+    private:
+      // If we get passed an array, keep the type as is, otherwise store
+      // a reference if we were passed an l value reference, else copy the value
+      using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
+                                             typename std::remove_cv<T>::type,
+                                             typename std::conditional<std::is_lvalue_reference<T>::value,
+                                                                       T,
+                                                                       typename std::decay<T>::type>::type>::type;
+
+      // prevent nested nvps
+      static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
+                     "Cannot pair a name to a NameValuePair" );
+
+      NameValuePair & operator=( NameValuePair const & ) = delete;
+
+    public:
+      //! Constructs a new NameValuePair
+      /*! @param n The name of the pair
+          @param v The value to pair.  Ideally this should be an l-value reference so that
+                   the value can be both loaded and saved to.  If you pass an r-value reference,
+                   the NameValuePair will store a copy of it instead of a reference.  Thus you should
+                   only pass r-values in cases where this makes sense, such as the result of some
+                   size() call.
+          @internal */
+      NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
+
+      char const * name;
+      Type value;
+  };
+
+  //! A specialization of make_nvp<> that simply forwards the value for binary archives
+  /*! @relates NameValuePair
+      @internal */
+  template<class Archive, class T> inline
+  typename
+  std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
+                 std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
+  T && >::type
+  make_nvp( const char *, T && value )
+  {
+    return std::forward<T>(value);
+  }
+
+  //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
+  /*! @relates NameValuePair
+      @internal */
+  template<class Archive, class T> inline
+  typename
+  std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
+                 !std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
+  NameValuePair<T> >::type
+  make_nvp( const char * name, T && value)
+  {
+    return {name, std::forward<T>(value)};
+  }
+
+  //! Convenience for creating a templated NVP
+  /*! For use in inteneral generic typing functions which have an
+      Archive type declared
+      @internal */
+  #define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
+
+  // ######################################################################
+  //! A wrapper around data that can be serialized in a binary fashion
+  /*! This class is used to demarcate data that can safely be serialized
+      as a binary chunk of data.  Individual archives can then choose how
+      best represent this during serialization.
+
+      @internal */
+  template <class T>
+  struct BinaryData
+  {
+    //! Internally store the pointer as a void *, keeping const if created with
+    //! a const pointer
+    using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
+                                         const void *,
+                                         void *>::type;
+
+    BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
+
+    PT data;       //!< pointer to beginning of data
+    uint64_t size; //!< size in bytes
+  };
+
+  // ######################################################################
+  namespace detail
+  {
+    // base classes for type checking
+    /* The rtti virtual function only exists to enable an archive to
+       be used in a polymorphic fashion, if necessary.  See the
+       archive adapters for an example of this */
+    class OutputArchiveBase { private: virtual void rtti(){} };
+    class InputArchiveBase { private: virtual void rtti(){} };
+
+    // forward decls for polymorphic support
+    template <class Archive, class T> struct polymorphic_serialization_support;
+    struct adl_tag;
+
+    // used during saving pointers
+    static const int32_t msb_32bit  = 0x80000000;
+    static const int32_t msb2_32bit = 0x40000000;
+  }
+
+  // ######################################################################
+  //! A wrapper around size metadata
+  /*! This class provides a way for archives to have more flexibility over how
+      they choose to serialize size metadata for containers.  For some archive
+      types, the size may be implicitly encoded in the output (e.g. JSON) and
+      not need an explicit entry.  Specializing serialize or load/save for
+      your archive and SizeTags allows you to choose what happens.
+
+      @internal */
+  template <class T>
+  class SizeTag
+  {
+    private:
+      // Store a reference if passed an lvalue reference, otherwise
+      // make a copy of the data
+      using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
+                                             T,
+                                             typename std::decay<T>::type>::type;
+
+      SizeTag & operator=( SizeTag const & ) = delete;
+
+    public:
+      SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
+
+      Type size;
+  };
+
+  // ######################################################################
+  //! A wrapper around a key and value for serializing data into maps.
+  /*! This class just provides a grouping of keys and values into a struct for
+      human readable archives. For example, XML archives will use this wrapper
+      to write maps like so:
+
+      @code{.xml}
+      <mymap>
+        <item0>
+          <key>MyFirstKey</key>
+          <value>MyFirstValue</value>
+        </item0>
+        <item1>
+          <key>MySecondKey</key>
+          <value>MySecondValue</value>
+        </item1>
+      </mymap>
+      @endcode
+
+      \sa make_map_item
+      @internal */
+  template <class Key, class Value>
+  struct MapItem
+  {
+    using KeyType = typename std::conditional<
+      std::is_lvalue_reference<Key>::value,
+      Key,
+      typename std::decay<Key>::type>::type;
+
+    using ValueType = typename std::conditional<
+      std::is_lvalue_reference<Value>::value,
+      Value,
+      typename std::decay<Value>::type>::type;
+
+    //! Construct a MapItem from a key and a value
+    /*! @internal */
+    MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
+
+    MapItem & operator=( MapItem const & ) = delete;
+
+    KeyType key;
+    ValueType value;
+
+    //! Serialize the MapItem with the NVPs "key" and "value"
+    template <class Archive> inline
+    void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
+    {
+      archive( make_nvp<Archive>("key",   key),
+               make_nvp<Archive>("value", value) );
+    }
+  };
+
+  //! Create a MapItem so that human readable archives will group keys and values together
+  /*! @internal
+      @relates MapItem */
+  template <class KeyType, class ValueType> inline
+  MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
+  {
+    return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
+  }
+
+  namespace detail
+  {
+    //! Tag for Version, which due to its anonymous namespace, becomes a different
+    //! type in each translation unit
+    /*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
+    namespace{ struct version_binding_tag {}; }
+
+    // ######################################################################
+    //! Version information class
+    /*! This is the base case for classes that have not been explicitly
+        registered */
+    template <class T, class BindingTag = version_binding_tag> struct Version
+    {
+      static const std::uint32_t version = 0;
+      // we don't need to explicitly register these types since they
+      // always get a version number of 0
+    };
+
+    //! Holds all registered version information
+    struct Versions
+    {
+      std::unordered_map<std::size_t, std::uint32_t> mapping;
+
+      std::uint32_t find( std::size_t hash, std::uint32_t version )
+      {
+        const auto result = mapping.emplace( hash, version );
+        return result.first->second;
+      }
+    }; // struct Versions
+  } // namespace detail
+} // namespace cereal
+
+#endif // CEREAL_DETAILS_HELPERS_HPP_
diff --git a/include/cereal/details/polymorphic_impl.hpp b/include/cereal/details/polymorphic_impl.hpp
new file mode 100644
index 0000000..cd05ccb
--- /dev/null
+++ b/include/cereal/details/polymorphic_impl.hpp
@@ -0,0 +1,437 @@
+/*! \file polymorphic_impl.hpp
+    \brief Internal polymorphism support
+    \ingroup Internal */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This code is heavily inspired by the boost serialization implementation by the following authors
+
+   (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
+   Use, modification and distribution is subject to the Boost Software
+   License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
+
+    See http://www.boost.org for updates, documentation, and revision history.
+
+   (C) Copyright 2006 David Abrahams - http://www.boost.org.
+
+   See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
+   implementation.
+*/
+#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
+#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
+
+#include <cereal/details/static_object.hpp>
+#include <cereal/types/memory.hpp>
+#include <cereal/types/string.hpp>
+#include <functional>
+#include <typeindex>
+#include <map>
+
+//! Binds a polymorhic type to all registered archives
+/*! This binds a polymorphic type to all compatible registered archives that
+    have been registered with CEREAL_REGISTER_ARCHIVE.  This must be called
+    after all archives are registered (usually after the archives themselves
+    have been included). */
+#define CEREAL_BIND_TO_ARCHIVES(T)                   \
+    namespace cereal {                               \
+    namespace detail {                               \
+    template<>                                       \
+    struct init_binding<T> {                         \
+        static bind_to_archives<T> const & b;        \
+        static void unused() { (void)b; }            \
+    };                                               \
+    bind_to_archives<T> const & init_binding<T>::b = \
+        ::cereal::detail::StaticObject<              \
+            bind_to_archives<T>                      \
+        >::getInstance().bind();                     \
+    }} /* end namespaces */
+
+namespace cereal
+{
+  namespace detail
+  {
+    //! Binds a compile time type with a user defined string
+    template <class T>
+    struct binding_name {};
+
+    //! A structure holding a map from type_indices to output serializer functions
+    /*! A static object of this map should be created for each registered archive
+        type, containing entries for every registered type that describe how to
+        properly cast the type to its real type in polymorphic scenarios for
+        shared_ptr, weak_ptr, and unique_ptr. */
+    template <class Archive>
+    struct OutputBindingMap
+    {
+      //! A serializer function
+      /*! Serializer functions return nothing and take an archive as
+          their first parameter (will be cast properly inside the function,
+          and a pointer to actual data (contents of smart_ptr's get() function)
+          as their second parameter */
+      typedef std::function<void(void*, void const *)> Serializer;
+
+      //! Struct containing the serializer functions for all pointer types
+      struct Serializers
+      {
+        Serializer shared_ptr, //!< Serializer function for shared/weak pointers
+                   unique_ptr; //!< Serializer function for unique pointers
+      };
+
+      //! A map of serializers for pointers of all registered types
+      std::map<std::type_index, Serializers> map;
+    };
+
+    //! An empty noop deleter
+    template<class T> struct EmptyDeleter { void operator()(T *) const {} };
+
+    //! A structure holding a map from type name strings to input serializer functions
+    /*! A static object of this map should be created for each registered archive
+        type, containing entries for every registered type that describe how to
+        properly cast the type to its real type in polymorphic scenarios for
+        shared_ptr, weak_ptr, and unique_ptr. */
+    template <class Archive>
+    struct InputBindingMap
+    {
+      //! Shared ptr serializer function
+      /*! Serializer functions return nothing and take an archive as
+          their first parameter (will be cast properly inside the function,
+          and a shared_ptr (or unique_ptr for the unique case) of any base
+          type.  Internally it will properly be loaded and cast to the
+          correct type. */
+      typedef std::function<void(void*, std::shared_ptr<void> & )> SharedSerializer;
+      //! Unique ptr serializer function
+      typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> & )> UniqueSerializer;
+
+      //! Struct containing the serializer functions for all pointer types
+      struct Serializers
+      {
+        SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
+        UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
+      };
+
+      //! A map of serializers for pointers of all registered types
+      std::map<std::string, Serializers> map;
+    };
+
+    // forward decls for archives from cereal.hpp
+    class InputArchiveBase;
+    class OutputArchiveBase;
+
+    //! Creates a binding (map entry) between an input archive type and a polymorphic type
+    /*! Bindings are made when types are registered, assuming that at least one
+        archive has already been registered.  When this struct is created,
+        it will insert (at run time) an entry into a map that properly handles
+        casting for serializing polymorphic objects */
+    template <class Archive, class T> struct InputBindingCreator
+    {
+      //! Initialize the binding
+      InputBindingCreator()
+      {
+        auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
+        auto key = std::string(binding_name<T>::name());
+        auto lb = map.lower_bound(key);
+
+        if (lb != map.end() && lb->first == key)
+          return;
+
+        typename InputBindingMap<Archive>::Serializers serializers;
+
+        serializers.shared_ptr =
+          [](void * arptr, std::shared_ptr<void> & dptr)
+          {
+            Archive & ar = *static_cast<Archive*>(arptr);
+            std::shared_ptr<T> ptr;
+
+            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
+
+            dptr = ptr;
+          };
+
+        serializers.unique_ptr =
+          [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr)
+          {
+            Archive & ar = *static_cast<Archive*>(arptr);
+            std::unique_ptr<T> ptr;
+
+            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
+
+            dptr.reset(ptr.release());
+          };
+
+        map.insert( lb, { std::move(key), std::move(serializers) } );
+      }
+    };
+
+    //! Creates a binding (map entry) between an output archive type and a polymorphic type
+    /*! Bindings are made when types are registered, assuming that at least one
+        archive has already been registered.  When this struct is created,
+        it will insert (at run time) an entry into a map that properly handles
+        casting for serializing polymorphic objects */
+    template <class Archive, class T> struct OutputBindingCreator
+    {
+      //! Writes appropriate metadata to the archive for this polymorphic type
+      static void writeMetadata(Archive & ar)
+      {
+        // Register the polymorphic type name with the archive, and get the id
+        char const * name = binding_name<T>::name();
+        std::uint32_t id = ar.registerPolymorphicType(name);
+
+        // Serialize the id
+        ar( CEREAL_NVP_("polymorphic_id", id) );
+
+        // If the msb of the id is 1, then the type name is new, and we should serialize it
+        if( id & detail::msb_32bit )
+        {
+          std::string namestring(name);
+          ar( CEREAL_NVP_("polymorphic_name", namestring) );
+        }
+      }
+
+      //! Holds a properly typed shared_ptr to the polymorphic type
+      class PolymorphicSharedPointerWrapper
+      {
+        public:
+          /*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
+
+              The wrapped pointer will not be responsible for ownership of the held pointer
+              so it will not attempt to destroy it; instead the refcount of the wrapped
+              pointer will be tied to a fake 'ownership pointer' that will do nothing
+              when it ultimately goes out of scope.
+
+              The main reason for doing this, other than not to destroy the true object
+              with our wrapper pointer, is to avoid meddling with the internal reference
+              count in a polymorphic type that inherits from std::enable_shared_from_this.
+
+              @param dptr A void pointer to the contents of the shared_ptr to serialize */
+          PolymorphicSharedPointerWrapper( void const * dptr ) : refCount()
+          {
+            #ifdef _LIBCPP_VERSION
+            // libc++ needs this hacky workaround, see http://llvm.org/bugs/show_bug.cgi?id=18843
+            wrappedPtr = std::shared_ptr<T const>(
+                std::const_pointer_cast<T const>(
+                  std::shared_ptr<T>( refCount, static_cast<T *>(const_cast<void *>(dptr) ))));
+            #else // NOT _LIBCPP_VERSION
+            wrappedPtr = std::shared_ptr<T const>( refCount, static_cast<T const *>(dptr) );
+            #endif // _LIBCPP_VERSION
+          }
+
+          //! Get the wrapped shared_ptr */
+          inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
+
+        private:
+          std::shared_ptr<void> refCount;      //!< The ownership pointer
+          std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
+      };
+
+      //! Does the actual work of saving a polymorphic shared_ptr
+      /*! This function will properly create a shared_ptr from the void * that is passed in
+          before passing it to the archive for serialization.
+
+          In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
+
+          @param ar The archive to serialize to
+          @param dptr Pointer to the actual data held by the shared_ptr */
+      static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::true_type /* has_shared_from_this */ )
+      {
+        ::cereal::memory_detail::EnableSharedStateHelper<T> state( static_cast<T *>(const_cast<void *>(dptr)) );
+        PolymorphicSharedPointerWrapper psptr( dptr );
+        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
+      }
+
+      //! Does the actual work of saving a polymorphic shared_ptr
+      /*! This function will properly create a shared_ptr from the void * that is passed in
+          before passing it to the archive for serialization.
+
+          This version is for types that do not inherit from std::enable_shared_from_this.
+
+          @param ar The archive to serialize to
+          @param dptr Pointer to the actual data held by the shared_ptr */
+      static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::false_type /* has_shared_from_this */ )
+      {
+        PolymorphicSharedPointerWrapper psptr( dptr );
+        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
+      }
+
+      //! Initialize the binding
+      OutputBindingCreator()
+      {
+        auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
+        auto key = std::type_index(typeid(T));
+        auto lb = map.lower_bound(key);
+
+        if (lb != map.end() && lb->first == key)
+          return;
+
+        typename OutputBindingMap<Archive>::Serializers serializers;
+
+        serializers.shared_ptr =
+          [&](void * arptr, void const * dptr)
+          {
+            Archive & ar = *static_cast<Archive*>(arptr);
+
+            writeMetadata(ar);
+
+            #ifdef _MSC_VER
+            savePolymorphicSharedPtr( ar, dptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
+            #else // not _MSC_VER
+            savePolymorphicSharedPtr( ar, dptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
+            #endif // _MSC_VER
+          };
+
+        serializers.unique_ptr =
+          [&](void * arptr, void const * dptr)
+          {
+            Archive & ar = *static_cast<Archive*>(arptr);
+
+            writeMetadata(ar);
+
+            std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
+
+            ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
+          };
+
+        map.insert( { std::move(key), std::move(serializers) } );
+      }
+    };
+
+    //! Used to help out argument dependent lookup for finding potential overloads
+    //! of instantiate_polymorphic_binding
+    struct adl_tag {};
+
+    //! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
+    //! namespace it becomes a different type in each translation unit.
+    namespace { struct polymorphic_binding_tag {}; }
+
+    //! Causes the static object bindings between an archive type and a serializable type T
+    template <class Archive, class T>
+    struct create_bindings
+    {
+      static const InputBindingCreator<Archive, T> &
+      load(std::true_type)
+      {
+        return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
+      }
+
+      static const OutputBindingCreator<Archive, T> &
+      save(std::true_type)
+      {
+        return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
+      }
+
+      inline static void load(std::false_type) {}
+      inline static void save(std::false_type) {}
+    };
+
+    //! When specialized, causes the compiler to instantiate its parameter
+    template <void(*)()>
+    struct instantiate_function {};
+
+    /*! This struct is used as the return type of instantiate_polymorphic_binding
+        for specific Archive types.  When the compiler looks for overloads of
+        instantiate_polymorphic_binding, it will be forced to instantiate this
+        struct during overload resolution, even though it will not be part of a valid
+        overload */
+    template <class Archive, class T>
+    struct polymorphic_serialization_support
+    {
+      #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+      //! Creates the appropriate bindings depending on whether the archive supports
+      //! saving or loading
+      virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
+      #else // NOT _MSC_VER
+      //! Creates the appropriate bindings depending on whether the archive supports
+      //! saving or loading
+      static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
+      //! This typedef causes the compiler to instantiate this static function
+      typedef instantiate_function<instantiate> unused;
+      #endif // _MSC_VER
+    };
+
+    // instantiate implementation
+    template <class Archive, class T>
+    CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
+    {
+      create_bindings<Archive,T>::save( std::integral_constant<bool,
+                                          std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
+                                          traits::is_output_serializable<T, Archive>::value>{} );
+
+      create_bindings<Archive,T>::load( std::integral_constant<bool,
+                                          std::is_base_of<detail::InputArchiveBase, Archive>::value &&
+                                          traits::is_input_serializable<T, Archive>::value>{} );
+    }
+
+    //! Begins the binding process of a type to all registered archives
+    /*! Archives need to be registered prior to this struct being instantiated via
+        the CEREAL_REGISTER_ARCHIVE macro.  Overload resolution will then force
+        several static objects to be made that allow us to bind together all
+        registered archive types with the parameter type T. */
+    template <class T, class Tag = polymorphic_binding_tag>
+    struct bind_to_archives
+    {
+      //! Binding for non abstract types
+      void bind(std::false_type) const
+	    {
+		    instantiate_polymorphic_binding((T*) 0, 0, Tag{}, adl_tag{});
+      }
+
+      //! Binding for abstract types
+      void bind(std::true_type) const
+      { }
+
+      //! Binds the type T to all registered archives
+      /*! If T is abstract, we will not serialize it and thus
+          do not need to make a binding */
+      bind_to_archives const & bind() const
+      {
+        static_assert( std::is_polymorphic<T>::value,
+                       "Attempting to register non polymorphic type" );
+        bind( std::is_abstract<T>() );
+        return *this;
+      }
+    };
+
+    //! Used to hide the static object used to bind T to registered archives
+    template <class T, class Tag = polymorphic_binding_tag>
+    struct init_binding;
+
+    //! Base case overload for instantiation
+    /*! This will end up always being the best overload due to the second
+        parameter always being passed as an int.  All other overloads will
+        accept pointers to archive types and have lower precedence than int.
+
+        Since the compiler needs to check all possible overloads, the
+        other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
+        lower precedence due to requring a conversion from int to (Archive*),
+        will cause their return types to be instantiated through the static object
+        mechanisms even though they are never called.
+
+        See the documentation for the other functions to try and understand this */
+    template <class T, typename BindingTag>
+    void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
+  } // namespace detail
+} // namespace cereal
+
+#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
diff --git a/include/cereal/details/static_object.hpp b/include/cereal/details/static_object.hpp
new file mode 100644
index 0000000..c172ac3
--- /dev/null
+++ b/include/cereal/details/static_object.hpp
@@ -0,0 +1,90 @@
+/*! \file static_object.hpp
+    \brief Internal polymorphism static object support
+    \ingroup Internal */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
+#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
+
+//! Prevent link optimization from removing non-referenced static objects
+/*! Especially for polymorphic support, we create static objects which
+    may not ever be explicitly referenced.  Most linkers will detect this
+    and remove the code causing various unpleasant runtime errors.  These
+    macros, adopted from Boost (see force_include.hpp) prevent this
+    (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
+    Use, modification and distribution is subject to the Boost Software
+    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+    http://www.boost.org/LICENSE_1_0.txt) */
+
+#ifdef _MSC_VER
+#   define CEREAL_DLL_EXPORT __declspec(dllexport)
+#   define CEREAL_USED
+#else // clang or gcc
+#   define CEREAL_DLL_EXPORT
+#   define CEREAL_USED __attribute__ ((__used__))
+#endif
+
+namespace cereal
+{
+  namespace detail
+  {
+    //! A static, pre-execution object
+    /*! This class will create a single copy (singleton) of some
+        type and ensures that merely referencing this type will
+        cause it to be instantiated and initialized pre-execution.
+        For example, this is used heavily in the polymorphic pointer
+        serialization mechanisms to bind various archive types with
+        different polymorphic classes */
+    template <class T>
+    class CEREAL_DLL_EXPORT StaticObject
+    {
+      private:
+        //! Forces instantiation at pre-execution time
+        static void instantiate( T const & ) {}
+
+        static T & create()
+        {
+          static T t;
+          instantiate(instance);
+          return t;
+        }
+
+        StaticObject( StaticObject const & /*other*/ ) {}
+
+      public:
+        static T & getInstance()
+        {
+          return create();
+        }
+
+      private:
+        static T & instance;
+    };
+
+    template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
+  } // namespace detail
+} // namespace cereal
+
+#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_
\ No newline at end of file
diff --git a/include/cereal/details/traits.hpp b/include/cereal/details/traits.hpp
new file mode 100644
index 0000000..b268f9e
--- /dev/null
+++ b/include/cereal/details/traits.hpp
@@ -0,0 +1,1325 @@
+/*! \file traits.hpp
+    \brief Internal type trait support
+    \ingroup Internal */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_DETAILS_TRAITS_HPP_
+#define CEREAL_DETAILS_TRAITS_HPP_
+
+#ifndef __clang__
+#if (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
+#define CEREAL_OLDER_GCC
+#endif // gcc 4.7 or earlier
+#endif // __clang__
+
+#include <type_traits>
+#include <typeindex>
+
+#include <cereal/macros.hpp>
+#include <cereal/access.hpp>
+
+namespace cereal
+{
+  namespace traits
+  {
+    using yes = std::true_type;
+    using no  = std::false_type;
+
+    namespace detail
+    {
+      // ######################################################################
+      //! Used to delay a static_assert until template instantiation
+      template <class T>
+      struct delay_static_assert : std::false_type {};
+
+      // ######################################################################
+      // SFINAE Helpers
+      #ifdef CEREAL_OLDER_GCC // when VS supports better SFINAE, we can use this as the default
+      template<typename> struct Void { typedef void type; };
+      #endif // CEREAL_OLDER_GCC
+
+      //! Return type for SFINAE Enablers
+      enum class sfinae {};
+
+      // ######################################################################
+      // Helper functionality for boolean integral constants and Enable/DisableIf
+      template <bool H, bool ... T> struct meta_bool_and : std::integral_constant<bool, H && meta_bool_and<T...>::value> {};
+      template <bool B> struct meta_bool_and<B> : std::integral_constant<bool, B> {};
+
+      template <bool H, bool ... T> struct meta_bool_or : std::integral_constant<bool, H || meta_bool_or<T...>::value> {};
+      template <bool B> struct meta_bool_or<B> : std::integral_constant<bool, B> {};
+
+      // workaround needed due to bug in MSVC 2013, see
+      // http://connect.microsoft.com/VisualStudio/feedback/details/800231/c-11-alias-template-issue
+      template <bool ... Conditions>
+      struct EnableIfHelper : std::enable_if<meta_bool_and<Conditions...>::value, sfinae> {};
+
+      template <bool ... Conditions>
+      struct DisableIfHelper : std::enable_if<!meta_bool_or<Conditions...>::value, sfinae> {};
+    } // namespace detail
+
+    //! Used as the default value for EnableIf and DisableIf template parameters
+    /*! @relates EnableIf
+        @relates DisableIf */
+    static const detail::sfinae sfinae = {};
+
+    // ######################################################################
+    //! Provides a way to enable a function if conditions are met
+    /*! This is intended to be used in a near identical fashion to std::enable_if
+        while being significantly easier to read at the cost of not allowing for as
+        complicated of a condition.
+
+        This will compile (allow the function) if every condition evaluates to true.
+        at compile time.  This should be used with SFINAE to ensure that at least
+        one other candidate function works when one fails due to an EnableIf.
+
+        This should be used as the las template parameter to a function as
+        an unnamed parameter with a default value of cereal::traits::sfinae:
+
+        @code{cpp}
+        // using by making the last template argument variadic
+        template <class T, EnableIf<std::is_same<T, bool>::value> = sfinae>
+        void func(T t );
+        @endcode
+
+        Note that this performs a logical AND of all conditions, so you will need
+        to construct more complicated requirements with this fact in mind.
+
+        @relates DisableIf
+        @relates sfinae
+        @tparam Conditions The conditions which will be logically ANDed to enable the function. */
+    template <bool ... Conditions>
+    using EnableIf = typename detail::EnableIfHelper<Conditions...>::type;
+
+    // ######################################################################
+    //! Provides a way to disable a function if conditions are met
+    /*! This is intended to be used in a near identical fashion to std::enable_if
+        while being significantly easier to read at the cost of not allowing for as
+        complicated of a condition.
+
+        This will compile (allow the function) if every condition evaluates to false.
+        This should be used with SFINAE to ensure that at least one other candidate
+        function works when one fails due to a DisableIf.
+
+        This should be used as the las template parameter to a function as
+        an unnamed parameter with a default value of cereal::traits::sfinae:
+
+        @code{cpp}
+        // using by making the last template argument variadic
+        template <class T, DisableIf<std::is_same<T, bool>::value> = sfinae>
+        void func(T t );
+        @endcode
+
+        This is often used in conjunction with EnableIf to form an enable/disable pair of
+        overloads.
+
+        Note that this performs a logical AND of all conditions, so you will need
+        to construct more complicated requirements with this fact in mind.  If all conditions
+        hold, the function will be disabled.
+
+        @relates EnableIf
+        @relates sfinae
+        @tparam Conditions The conditions which will be logically ANDed to disable the function. */
+    template <bool ... Conditions>
+    using DisableIf = typename detail::DisableIfHelper<Conditions...>::type;
+
+    // ######################################################################
+    namespace detail
+    {
+      template <class InputArchive>
+      struct get_output_from_input : no
+      {
+        static_assert( detail::delay_static_assert<InputArchive>::value,
+            "Could not find an associated output archive for input archive." );
+      };
+
+      template <class OutputArchive>
+      struct get_input_from_output : no
+      {
+        static_assert( detail::delay_static_assert<OutputArchive>::value,
+            "Could not find an associated input archive for output archive." );
+      };
+    }
+
+    //! Sets up traits that relate an input archive to an output archive
+    #define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)  \
+    namespace cereal { namespace traits { namespace detail {          \
+      template <> struct get_output_from_input<InputArchive>          \
+      { using type = OutputArchive; };                                \
+      template <> struct get_input_from_output<OutputArchive>         \
+      { using type = InputArchive; }; } } } /* end namespaces */
+
+    // ######################################################################
+    //! Used to convert a MAKE_HAS_XXX macro into a versioned variant
+    #define CEREAL_MAKE_VERSIONED_TEST ,0
+
+    // ######################################################################
+    //! Creates a test for whether a non const member function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param name The name of the function to test for (e.g. serialize, load, save)
+        @param test_name The name to give the test for the function being tested for (e.g. serialize, versioned_serialize)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #ifdef CEREAL_OLDER_GCC
+    #define CEREAL_MAKE_HAS_MEMBER_TEST(name, test_name, versioned)                                                                         \
+    template <class T, class A, class SFINAE = void>                                                                                        \
+    struct has_member_##test_name : no {};                                                                                                  \
+    template <class T, class A>                                                                                                             \
+    struct has_member_##test_name<T, A,                                                                                                     \
+      typename detail::Void< decltype( cereal::access::member_##name( std::declval<A&>(), std::declval<T&>() versioned ) ) >::type> : yes {}
+    #else // NOT CEREAL_OLDER_GCC
+    #define CEREAL_MAKE_HAS_MEMBER_TEST(name, test_name, versioned)                                                                     \
+    namespace detail                                                                                                                    \
+    {                                                                                                                                   \
+      template <class T, class A>                                                                                                       \
+      struct has_member_##name##_##versioned##_impl                                                                                     \
+      {                                                                                                                                 \
+        template <class TT, class AA>                                                                                                   \
+        static auto test(int) -> decltype( cereal::access::member_##name( std::declval<AA&>(), std::declval<TT&>() versioned ), yes()); \
+        template <class, class>                                                                                                         \
+        static no test(...);                                                                                                            \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                                    \
+      };                                                                                                                                \
+    } /* end namespace detail */                                                                                                        \
+    template <class T, class A>                                                                                                         \
+    struct has_member_##test_name : std::integral_constant<bool, detail::has_member_##name##_##versioned##_impl<T, A>::value> {}
+    #endif // NOT CEREAL_OLDER_GCC
+
+    // ######################################################################
+    //! Creates a test for whether a non const non-member function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper non-member function for the given archive. */
+    #define CEREAL_MAKE_HAS_NON_MEMBER_TEST(test_name, func, versioned)                                                         \
+    namespace detail                                                                                                            \
+    {                                                                                                                           \
+      template <class T, class A>                                                                                               \
+      struct has_non_member_##test_name##_impl                                                                                  \
+      {                                                                                                                         \
+        template <class TT, class AA>                                                                                           \
+        static auto test(int) -> decltype( func( std::declval<AA&>(), std::declval<TT&>() versioned ), yes());                  \
+        template <class, class>                                                                                                 \
+        static no test( ... );                                                                                                  \
+        static const bool value = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                        \
+      };                                                                                                                        \
+    } /* end namespace detail */                                                                                                \
+    template <class T, class A>                                                                                                 \
+    struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> {}
+
+    // ######################################################################
+    // Member Serialize
+    CEREAL_MAKE_HAS_MEMBER_TEST(serialize, serialize,);
+
+    // ######################################################################
+    // Member Serialize (versioned)
+    CEREAL_MAKE_HAS_MEMBER_TEST(serialize, versioned_serialize, CEREAL_MAKE_VERSIONED_TEST);
+
+    // ######################################################################
+    // Non Member Serialize
+    CEREAL_MAKE_HAS_NON_MEMBER_TEST(serialize, CEREAL_SERIALIZE_FUNCTION_NAME,);
+
+    // ######################################################################
+    // Non Member Serialize (versioned)
+    CEREAL_MAKE_HAS_NON_MEMBER_TEST(versioned_serialize, CEREAL_SERIALIZE_FUNCTION_NAME, CEREAL_MAKE_VERSIONED_TEST);
+
+    // ######################################################################
+    // Member Load
+    CEREAL_MAKE_HAS_MEMBER_TEST(load, load,);
+
+    // ######################################################################
+    // Member Load (versioned)
+    CEREAL_MAKE_HAS_MEMBER_TEST(load, versioned_load, CEREAL_MAKE_VERSIONED_TEST);
+
+    // ######################################################################
+    // Non Member Load
+    CEREAL_MAKE_HAS_NON_MEMBER_TEST(load, CEREAL_LOAD_FUNCTION_NAME,);
+
+    // ######################################################################
+    // Non Member Load (versioned)
+    CEREAL_MAKE_HAS_NON_MEMBER_TEST(versioned_load, CEREAL_LOAD_FUNCTION_NAME, CEREAL_MAKE_VERSIONED_TEST);
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_NON_MEMBER_TEST
+    #undef CEREAL_MAKE_HAS_MEMBER_TEST
+
+    // ######################################################################
+    //! Creates a test for whether a member save function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param test_name The name to give the test (e.g. save or versioned_save)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #ifdef CEREAL_OLDER_GCC
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(test_name, versioned)                                                                  \
+    namespace detail                                                                                                                \
+    {                                                                                                                               \
+    template <class T, class A>                                                                                                     \
+    struct has_member_##test_name##_impl                                                                                            \
+      {                                                                                                                             \
+        template <class TT, class AA, class SFINAE = void> struct test : no {};                                                     \
+        template <class TT, class AA>                                                                                               \
+        struct test<TT, AA,                                                                                                         \
+          typename detail::Void< decltype( cereal::access::member_save( std::declval<AA&>(),                                        \
+                                                                        std::declval<TT const &>() versioned ) ) >::type> : yes {}; \
+        static const bool value = test<T, A>();                                                                                     \
+                                                                                                                                    \
+        template <class TT, class AA, class SFINAE = void> struct test2 : no {};                                                    \
+        template <class TT, class AA>                                                                                               \
+        struct test2<TT, AA,                                                                                                        \
+          typename detail::Void< decltype( cereal::access::member_save_non_const(                                                   \
+                                            std::declval<AA&>(),                                                                    \
+                                            std::declval<typename std::remove_const<TT>::type&>() versioned ) ) >::type> : yes {};  \
+        static const bool not_const_type = test2<T, A>();                                                                           \
+      };                                                                                                                            \
+    } /* end namespace detail */
+    #else /* NOT CEREAL_OLDER_GCC =================================== */
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(test_name, versioned)                                                                  \
+    namespace detail                                                                                                                \
+    {                                                                                                                               \
+    template <class T, class A>                                                                                                     \
+    struct has_member_##test_name##_impl                                                                                            \
+      {                                                                                                                             \
+        template <class TT, class AA>                                                                                               \
+        static auto test(int) -> decltype( cereal::access::member_save( std::declval<AA&>(),                                        \
+                                                                        std::declval<TT const &>() versioned ), yes());             \
+        template <class, class> static no test(...);                                                                                \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                                \
+                                                                                                                                    \
+        template <class TT, class AA>                                                                                               \
+        static auto test2(int) -> decltype( cereal::access::member_save_non_const(                                                  \
+                                              std::declval<AA &>(),                                                                 \
+                                              std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());            \
+        template <class, class> static no test2(...);                                                                               \
+        static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                                      \
+      };                                                                                                                            \
+    } /* end namespace detail */
+    #endif /* NOT CEREAL_OLDER_GCC */
+
+    // ######################################################################
+    // Member Save
+    CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(save, )
+
+    template <class T, class A>
+    struct has_member_save : std::integral_constant<bool, detail::has_member_save_impl<T, A>::value>
+    {
+      typedef typename detail::has_member_save_impl<T, A> check;
+      static_assert( check::value || !check::not_const_type,
+        "cereal detected a non-const save. \n "
+        "save member functions must always be const" );
+    };
+
+    // ######################################################################
+    // Member Save (versioned)
+    CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL(versioned_save, CEREAL_MAKE_VERSIONED_TEST)
+
+    template <class T, class A>
+    struct has_member_versioned_save : std::integral_constant<bool, detail::has_member_versioned_save_impl<T, A>::value>
+    {
+      typedef typename detail::has_member_versioned_save_impl<T, A> check;
+      static_assert( check::value || !check::not_const_type,
+        "cereal detected a versioned non-const save. \n "
+        "save member functions must always be const" );
+    };
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_MEMBER_SAVE_IMPL
+
+    // ######################################################################
+    //! Creates a test for whether a non-member save function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper non-member function for the given archive.
+
+        @param test_name The name to give the test (e.g. save or versioned_save)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(test_name, versioned)                                                       \
+    namespace detail                                                                                                         \
+    {                                                                                                                        \
+      template <class T, class A>                                                                                            \
+      struct has_non_member_##test_name##_impl                                                                               \
+      {                                                                                                                      \
+        template <class TT, class AA>                                                                                        \
+        static auto test(int) -> decltype( CEREAL_SAVE_FUNCTION_NAME(                                                        \
+                                              std::declval<AA&>(),                                                           \
+                                              std::declval<TT const &>() versioned ), yes());                                \
+        template <class, class> static no test(...);                                                                         \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                         \
+                                                                                                                             \
+        template <class TT, class AA>                                                                                        \
+        static auto test2(int) -> decltype( CEREAL_SAVE_FUNCTION_NAME(                                                       \
+                                              std::declval<AA &>(),                                                          \
+                                              std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());     \
+        template <class, class> static no test2(...);                                                                        \
+        static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                               \
+      };                                                                                                                     \
+    } /* end namespace detail */                                                                                             \
+                                                                                                                             \
+    template <class T, class A>                                                                                              \
+    struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> \
+    {                                                                                                                        \
+      using check = typename detail::has_non_member_##test_name##_impl<T, A>;                                                \
+      static_assert( check::value || !check::not_const_type,                                                                 \
+        "cereal detected a non-const type parameter in non-member " #test_name ". \n "                                       \
+        #test_name " non-member functions must always pass their types as const" );                                          \
+    };
+
+    // ######################################################################
+    // Non Member Save
+    CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(save, )
+
+    // ######################################################################
+    // Non Member Save (versioned)
+    CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST(versioned_save, CEREAL_MAKE_VERSIONED_TEST)
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_NON_MEMBER_SAVE_TEST
+
+    // ######################################################################
+    // Minimal Utilities
+    namespace detail
+    {
+      // Determines if the provided type is an std::string
+      template <class> struct is_string : std::false_type {};
+
+      template <class CharT, class Traits, class Alloc>
+      struct is_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};
+    }
+
+    // Determines if the type is valid for use with a minimal serialize function
+    template <class T>
+    struct is_minimal_type : std::integral_constant<bool,
+      detail::is_string<T>::value || std::is_arithmetic<T>::value> {};
+
+    // ######################################################################
+    //! Creates implementation details for whether a member save_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #ifdef CEREAL_OLDER_GCC
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(test_name, versioned)                                                                        \
+    namespace detail                                                                                                                              \
+    {                                                                                                                                             \
+      template <class T, class A>                                                                                                                 \
+      struct has_member_##test_name##_impl                                                                                                        \
+      {                                                                                                                                           \
+        template <class TT, class AA, class SFINAE = void> struct test : no {};                                                                   \
+        template <class TT, class AA>                                                                                                             \
+        struct test<TT, AA, typename detail::Void< decltype(                                                                                      \
+            cereal::access::member_save_minimal( std::declval<AA const &>(),                                                                      \
+                                                 std::declval<TT const &>() versioned ) ) >::type> : yes {};                                      \
+                                                                                                                                                  \
+        static const bool value = test<T, A>();                                                                                                   \
+                                                                                                                                                  \
+        template <class TT, class AA, class SFINAE = void> struct test2 : no {};                                                                  \
+        template <class TT, class AA>                                                                                                             \
+        struct test2<TT, AA, typename detail::Void< decltype(                                                                                     \
+            cereal::access::member_save_minimal_non_const( std::declval<AA const &>(),                                                            \
+                                                           std::declval<typename std::remove_const<TT>::type&>() versioned ) ) >::type> : yes {}; \
+        static const bool not_const_type = test2<T, A>();                                                                                         \
+                                                                                                                                                  \
+        static const bool valid = value || !not_const_type;                                                                                       \
+      };                                                                                                                                          \
+    } /* end namespace detail */
+    #else /* NOT CEREAL_OLDER_GCC =================================== */
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(test_name, versioned)                     \
+    namespace detail                                                                           \
+    {                                                                                          \
+      template <class T, class A>                                                              \
+      struct has_member_##test_name##_impl                                                     \
+      {                                                                                        \
+        template <class TT, class AA>                                                          \
+        static auto test(int) -> decltype( cereal::access::member_save_minimal(                \
+              std::declval<AA const &>(),                                                      \
+              std::declval<TT const &>() versioned ), yes());                                  \
+        template <class, class> static no test(...);                                           \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;           \
+                                                                                               \
+        template <class TT, class AA>                                                          \
+        static auto test2(int) -> decltype( cereal::access::member_save_minimal_non_const(     \
+              std::declval<AA const &>(),                                                      \
+              std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());       \
+        template <class, class> static no test2(...);                                          \
+        static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value; \
+                                                                                               \
+        static const bool valid = value || !not_const_type;                                    \
+      };                                                                                       \
+    } /* end namespace detail */
+    #endif // NOT CEREAL_OLDER_GCC
+
+    // ######################################################################
+    //! Creates helpers for minimal save functions
+    /*! The get_member_*_type structs allow access to the return type of a save_minimal,
+        assuming that the function actually exists.  If the function does not
+        exist, the type will be void.
+
+        @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(test_name, versioned)                           \
+    namespace detail                                                                                         \
+    {                                                                                                        \
+      template <class T, class A, bool Valid>                                                                \
+      struct get_member_##test_name##_type { using type = void; };                                           \
+                                                                                                             \
+      template <class T, class A>                                                                            \
+      struct get_member_##test_name##_type<T, A, true>                                                       \
+      {                                                                                                      \
+        using type = decltype( cereal::access::member_save_minimal( std::declval<A const &>(),               \
+                                                                    std::declval<T const &>() versioned ) ); \
+      };                                                                                                     \
+    } /* end namespace detail */
+
+    // ######################################################################
+    //! Creates a test for whether a member save_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal) */
+    #define CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(test_name)                                                      \
+    template <class T, class A>                                                                                      \
+    struct has_member_##test_name : std::integral_constant<bool, detail::has_member_##test_name##_impl<T, A>::value> \
+    {                                                                                                                \
+      using check = typename detail::has_member_##test_name##_impl<T, A>;                                            \
+      static_assert( check::valid,                                                                                   \
+        "cereal detected a non-const member " #test_name ". \n "                                                     \
+        #test_name " member functions must always be const" );                                                       \
+                                                                                                                     \
+      using type = typename detail::get_member_##test_name##_type<T, A, check::value>::type;                         \
+      static_assert( (check::value && is_minimal_type<type>::value) || !check::value,                                \
+        "cereal detected a member " #test_name " with an invalid return type. \n "                                   \
+        "return type must be arithmetic or string" );                                                                \
+    };
+
+    // ######################################################################
+    // Member Save Minimal
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(save_minimal, )
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(save_minimal, )
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(save_minimal)
+
+    // ######################################################################
+    // Member Save Minimal (versioned)
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
+    CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST(versioned_save_minimal)
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_IMPL
+    #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_HELPERS_IMPL
+    #undef CEREAL_MAKE_HAS_MEMBER_SAVE_MINIMAL_TEST
+
+    // ######################################################################
+    //! Creates a test for whether a non-member save_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param test_name The name to give the test (e.g. save_minimal or versioned_save_minimal)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #define CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(test_name, versioned)                                               \
+    namespace detail                                                                                                         \
+    {                                                                                                                        \
+      template <class T, class A>                                                                                            \
+      struct has_non_member_##test_name##_impl                                                                               \
+      {                                                                                                                      \
+        template <class TT, class AA>                                                                                        \
+        static auto test(int) -> decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(                                                \
+              std::declval<AA const &>(),                                                                                    \
+              std::declval<TT const &>() versioned ), yes());                                                                \
+        template <class, class> static no test(...);                                                                         \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;                                         \
+                                                                                                                             \
+        template <class TT, class AA>                                                                                        \
+        static auto test2(int) -> decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(                                               \
+              std::declval<AA const &>(),                                                                                    \
+              std::declval<typename std::remove_const<TT>::type&>() versioned ), yes());                                     \
+        template <class, class> static no test2(...);                                                                        \
+        static const bool not_const_type = std::is_same<decltype(test2<T, A>(0)), yes>::value;                               \
+                                                                                                                             \
+        static const bool valid = value || !not_const_type;                                                                  \
+      };                                                                                                                     \
+                                                                                                                             \
+      template <class T, class A, bool Valid>                                                                                \
+      struct get_non_member_##test_name##_type { using type = void; };                                                       \
+                                                                                                                             \
+      template <class T, class A>                                                                                            \
+      struct get_non_member_##test_name##_type <T, A, true>                                                                  \
+      {                                                                                                                      \
+        using type = decltype( CEREAL_SAVE_MINIMAL_FUNCTION_NAME( std::declval<A const &>(),                                 \
+                                                                  std::declval<T const &>() versioned ) );                   \
+      };                                                                                                                     \
+    } /* end namespace detail */                                                                                             \
+                                                                                                                             \
+    template <class T, class A>                                                                                              \
+    struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> \
+    {                                                                                                                        \
+      using check = typename detail::has_non_member_##test_name##_impl<T, A>;                                                \
+      static_assert( check::valid,                                                                                           \
+        "cereal detected a non-const type parameter in non-member " #test_name ". \n "                                       \
+        #test_name " non-member functions must always pass their types as const" );                                          \
+                                                                                                                             \
+      using type = typename detail::get_non_member_##test_name##_type<T, A, check::value>::type;                             \
+      static_assert( (check::value && is_minimal_type<type>::value) || !check::value,                                        \
+        "cereal detected a non-member " #test_name " with an invalid return type. \n "                                       \
+        "return type must be arithmetic or string" );                                                                        \
+    };
+
+    // ######################################################################
+    // Non-Member Save Minimal
+    CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(save_minimal, )
+
+    // ######################################################################
+    // Non-Member Save Minimal (versioned)
+    CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST(versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_NON_MEMBER_SAVE_MINIMAL_TEST
+
+    // ######################################################################
+    // Load Minimal Utilities
+    namespace detail
+    {
+      //! Used to help strip away conversion wrappers
+      /*! If someone writes a non-member load/save minimal function that accepts its
+          parameter as some generic template type and needs to perform trait checks
+          on that type, our NoConvert wrappers will interfere with this.  Using
+          the struct strip_minmal, users can strip away our wrappers to get to
+          the underlying type, allowing traits to work properly */
+      struct NoConvertBase {};
+
+      //! A struct that prevents implicit conversion
+      /*! Any type instantiated with this struct will be unable to implicitly convert
+          to another type.  Is designed to only allow conversion to Source const &.
+
+          @tparam Source the type of the original source */
+      template <class Source>
+      struct NoConvertConstRef : NoConvertBase
+      {
+        using type = Source; //!< Used to get underlying type easily
+
+        template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+        operator Dest () = delete;
+
+        //! only allow conversion if the types are the same and we are converting into a const reference
+        template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+        operator Dest const & ();
+      };
+
+      //! A struct that prevents implicit conversion
+      /*! Any type instantiated with this struct will be unable to implicitly convert
+          to another type.  Is designed to only allow conversion to Source &.
+
+          @tparam Source the type of the original source */
+      template <class Source>
+      struct NoConvertRef : NoConvertBase
+      {
+        using type = Source; //!< Used to get underlying type easily
+
+        template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+        operator Dest () = delete;
+
+        #ifdef __clang__
+        template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+        operator Dest const & () = delete;
+        #endif // __clang__
+
+        //! only allow conversion if the types are the same and we are converting into a const reference
+        template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
+        operator Dest & ();
+      };
+
+      //! A type that can implicitly convert to anything else
+      struct AnyConvert
+      {
+        template <class Dest>
+        operator Dest & ();
+
+        template <class Dest>
+        operator Dest const & () const;
+      };
+    } // namespace detail
+
+    // ######################################################################
+    //! Creates a test for whether a member load_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        Our strategy here is to first check if a function matching the signature more or less exists
+        (allow anything like load_minimal(xxx) using AnyConvert, and then secondly enforce
+        that it has the correct signature using NoConvertConstRef
+
+        @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #ifdef CEREAL_OLDER_GCC
+    #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(test_name, versioned)                                                    \
+    namespace detail                                                                                                          \
+    {                                                                                                                         \
+      template <class T, class A, class SFINAE = void> struct has_member_##test_name##_impl : no {};                          \
+      template <class T, class A>                                                                                             \
+      struct has_member_##test_name##_impl<T, A, typename detail::Void< decltype(                                             \
+          cereal::access::member_load_minimal( std::declval<A const &>(),                                                     \
+                                               std::declval<T &>(), AnyConvert() versioned ) ) >::type> : yes {};             \
+                                                                                                                              \
+        template <class T, class A, class U, class SFINAE = void> struct has_member_##test_name##_type_impl : no {};          \
+        template <class T, class A, class U>                                                                                  \
+        struct has_member_##test_name##_type_impl<T, A, U, typename detail::Void< decltype(                                   \
+            cereal::access::member_load_minimal( std::declval<A const &>(),                                                   \
+                                                 std::declval<T &>(), NoConvertConstRef<U>() versioned ) ) >::type> : yes {}; \
+    } /* end namespace detail */
+    #else /* NOT CEREAL_OLDER_GCC =================================== */
+    #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(test_name, versioned)              \
+    namespace detail                                                                    \
+    {                                                                                   \
+      template <class T, class A>                                                       \
+      struct has_member_##test_name##_impl                                              \
+      {                                                                                 \
+        template <class TT, class AA>                                                   \
+        static auto test(int) -> decltype( cereal::access::member_load_minimal(         \
+              std::declval<AA const &>(),                                               \
+              std::declval<TT &>(), AnyConvert() versioned ), yes());                   \
+        template <class, class> static no test(...);                                    \
+        static const bool value = std::is_same<decltype(test<T, A>(0)), yes>::value;    \
+      };                                                                                \
+      template <class T, class A, class U>                                              \
+      struct has_member_##test_name##_type_impl                                         \
+      {                                                                                 \
+        template <class TT, class AA, class UU>                                         \
+        static auto test(int) -> decltype( cereal::access::member_load_minimal(         \
+              std::declval<AA const &>(),                                               \
+              std::declval<TT &>(), NoConvertConstRef<UU>() versioned ), yes());        \
+        template <class, class, class> static no test(...);                             \
+        static const bool value = std::is_same<decltype(test<T, A, U>(0)), yes>::value; \
+                                                                                        \
+      };                                                                                \
+    } /* end namespace detail */
+    #endif // NOT CEREAL_OLDER_GCC
+
+    // ######################################################################
+    //! Creates helpers for minimal load functions
+    /*! The has_member_*_wrapper structs ensure that the load and save types for the
+        requested function type match appropriately.
+
+        @param load_test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
+        @param save_test_name The name to give the test (e.g. save_minimal or versioned_save_minimal,
+                              should match the load name.
+        @param save_test_prefix The name to give the test (e.g. save_minimal or versioned_save_minimal,
+                              should match the load name, without the trailing "_minimal" (e.g.
+                              save or versioned_save).  Needed because the preprocessor is an abomination.
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(load_test_name, save_test_name, save_test_prefix, versioned) \
+    namespace detail                                                                                                      \
+    {                                                                                                                     \
+      template <class T, class A, bool Valid>                                                                             \
+      struct has_member_##load_test_name##_wrapper : std::false_type {};                                                  \
+                                                                                                                          \
+      template <class T, class A>                                                                                         \
+      struct has_member_##load_test_name##_wrapper<T, A, true>                                                            \
+      {                                                                                                                   \
+        using AOut = typename detail::get_output_from_input<A>::type;                                                     \
+                                                                                                                          \
+        static_assert( has_member_##save_test_prefix##_minimal<T, AOut>::value,                                           \
+          "cereal detected member " #load_test_name " but no valid member " #save_test_name ". \n "                       \
+          "cannot evaluate correctness of " #load_test_name " without valid " #save_test_name "." );                      \
+                                                                                                                          \
+        using SaveType = typename detail::get_member_##save_test_prefix##_minimal_type<T, AOut, true>::type;              \
+        const static bool value = has_member_##load_test_name##_impl<T, A>::value;                                        \
+        const static bool valid = has_member_##load_test_name##_type_impl<T, A, SaveType>::value;                         \
+                                                                                                                          \
+        static_assert( valid || !value, "cereal detected different or invalid types in corresponding member "             \
+            #load_test_name " and " #save_test_name " functions. \n "                                                     \
+            "the paramater to " #load_test_name " must be a constant reference to the type that "                         \
+            #save_test_name " returns." );                                                                                \
+      };                                                                                                                  \
+    } /* end namespace detail */
+
+    // ######################################################################
+    //! Creates a test for whether a member load_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        @param load_test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
+        @param load_test_prefix The above parameter minus the trailing "_minimal" */
+    #define CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(load_test_name, load_test_prefix)                                         \
+    template <class T, class A>                                                                                                \
+    struct has_member_##load_test_prefix##_minimal : std::integral_constant<bool,                                              \
+      detail::has_member_##load_test_name##_wrapper<T, A, detail::has_member_##load_test_name##_impl<T, A>::value>::value> {};
+
+    // ######################################################################
+    // Member Load Minimal
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(load_minimal, )
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(load_minimal, save_minimal, save, )
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(load_minimal, load)
+
+    // ######################################################################
+    // Member Load Minimal (versioned)
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL(versioned_load_minimal, CEREAL_MAKE_VERSIONED_TEST)
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL(versioned_load_minimal, versioned_save_minimal, versioned_save, CEREAL_MAKE_VERSIONED_TEST)
+    CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_load)
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_IMPL
+    #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_HELPERS_IMPL
+    #undef CEREAL_MAKE_HAS_MEMBER_LOAD_MINIMAL_TEST
+
+    // ######################################################################
+    // Non-Member Load Minimal
+    namespace detail
+    {
+      #ifdef CEREAL_OLDER_GCC
+      void CEREAL_LOAD_MINIMAL_FUNCTION_NAME(); // prevents nonsense complaining about not finding this
+      void CEREAL_SAVE_MINIMAL_FUNCTION_NAME();
+      #endif // CEREAL_OLDER_GCC
+    } // namespace detail
+
+    // ######################################################################
+    //! Creates a test for whether a non-member load_minimal function exists
+    /*! This creates a class derived from std::integral_constant that will be true if
+        the type has the proper member function for the given archive.
+
+        See notes from member load_minimal implementation.
+
+        @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
+        @param save_name The corresponding name the save test would have (e.g. save_minimal or versioned_save_minimal)
+        @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
+    #define CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(test_name, save_name, versioned)                                    \
+    namespace detail                                                                                                         \
+    {                                                                                                                        \
+      template <class T, class A, class U = void>                                                                            \
+      struct has_non_member_##test_name##_impl                                                                               \
+      {                                                                                                                      \
+        template <class TT, class AA>                                                                                        \
+        static auto test(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                                \
+              std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() versioned ), yes() );                            \
+        template <class, class> static no test( ... );                                                                       \
+        static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;                                    \
+                                                                                                                             \
+        template <class TT, class AA, class UU>                                                                              \
+        static auto test2(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
+              std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() versioned ), yes() );                 \
+        template <class, class, class> static no test2( ... );                                                               \
+        static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;                                 \
+                                                                                                                             \
+        template <class TT, class AA>                                                                                        \
+        static auto test3(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME(                                               \
+              std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() versioned ), yes() );                             \
+        template <class, class> static no test3( ... );                                                                      \
+        static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;                              \
+      };                                                                                                                     \
+                                                                                                                             \
+      template <class T, class A, bool Valid>                                                                                \
+      struct has_non_member_##test_name##_wrapper : std::false_type {};                                                      \
+                                                                                                                             \
+      template <class T, class A>                                                                                            \
+      struct has_non_member_##test_name##_wrapper<T, A, true>                                                                \
+      {                                                                                                                      \
+        using AOut = typename detail::get_output_from_input<A>::type;                                                        \
+                                                                                                                             \
+        static_assert( detail::has_non_member_##save_name##_impl<T, AOut>::valid,                                            \
+          "cereal detected non-member " #test_name " but no valid non-member " #save_name ". \n "                            \
+          "cannot evaluate correctness of " #test_name " without valid " #save_name "." );                                   \
+                                                                                                                             \
+        using SaveType = typename detail::get_non_member_##save_name##_type<T, AOut, true>::type;                            \
+        using check = has_non_member_##test_name##_impl<T, A, SaveType>;                                                     \
+        static const bool value = check::exists;                                                                             \
+                                                                                                                             \
+        static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member "        \
+            #test_name " and " #save_name " functions. \n "                                                                  \
+            "the paramater to " #test_name " must be a constant reference to the type that " #save_name " returns." );       \
+        static_assert( check::const_valid || !check::exists,                                                                 \
+            "cereal detected an invalid serialization type parameter in non-member " #test_name ".  "                        \
+            #test_name " non-member functions must accept their serialization type by non-const reference" );                \
+      };                                                                                                                     \
+    } /* namespace detail */                                                                                                 \
+                                                                                                                             \
+    template <class T, class A>                                                                                              \
+    struct has_non_member_##test_name : std::integral_constant<bool,                                                         \
+      detail::has_non_member_##test_name##_wrapper<T, A, detail::has_non_member_##test_name##_impl<T, A>::exists>::value> {};
+
+    // ######################################################################
+    // Non-Member Load Minimal
+    CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(load_minimal, save_minimal, )
+
+    // ######################################################################
+    // Non-Member Load Minimal (versioned)
+    CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST(versioned_load_minimal, versioned_save_minimal, CEREAL_MAKE_VERSIONED_TEST)
+
+    // ######################################################################
+    #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
+
+    // ######################################################################
+    // End of serialization existence tests
+    #undef CEREAL_MAKE_VERSIONED_TEST
+
+    // ######################################################################
+    template <class T, class InputArchive, class OutputArchive>
+    struct has_member_split : std::integral_constant<bool,
+      (has_member_load<T, InputArchive>::value && has_member_save<T, OutputArchive>::value) ||
+      (has_member_versioned_load<T, InputArchive>::value && has_member_versioned_save<T, OutputArchive>::value)> {};
+
+    // ######################################################################
+    template <class T, class InputArchive, class OutputArchive>
+    struct has_non_member_split : std::integral_constant<bool,
+      (has_non_member_load<T, InputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
+      (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_versioned_save<T, OutputArchive>::value)> {};
+
+    // ######################################################################
+    template <class T, class OutputArchive>
+    struct has_invalid_output_versioning : std::integral_constant<bool,
+      (has_member_versioned_save<T, OutputArchive>::value && has_member_save<T, OutputArchive>::value) ||
+      (has_non_member_versioned_save<T, OutputArchive>::value && has_non_member_save<T, OutputArchive>::value) ||
+      (has_member_versioned_serialize<T, OutputArchive>::value && has_member_serialize<T, OutputArchive>::value) ||
+      (has_non_member_versioned_serialize<T, OutputArchive>::value && has_non_member_serialize<T, OutputArchive>::value) ||
+      (has_member_versioned_save_minimal<T, OutputArchive>::value && has_member_save_minimal<T, OutputArchive>::value) ||
+      (has_non_member_versioned_save_minimal<T, OutputArchive>::value &&  has_non_member_save_minimal<T, OutputArchive>::value)> {};
+
+    // ######################################################################
+    template <class T, class InputArchive>
+    struct has_invalid_input_versioning : std::integral_constant<bool,
+      (has_member_versioned_load<T, InputArchive>::value && has_member_load<T, InputArchive>::value) ||
+      (has_non_member_versioned_load<T, InputArchive>::value && has_non_member_load<T, InputArchive>::value) ||
+      (has_member_versioned_serialize<T, InputArchive>::value && has_member_serialize<T, InputArchive>::value) ||
+      (has_non_member_versioned_serialize<T, InputArchive>::value && has_non_member_serialize<T, InputArchive>::value) ||
+      (has_member_versioned_load_minimal<T, InputArchive>::value && has_member_load_minimal<T, InputArchive>::value) ||
+      (has_non_member_versioned_load_minimal<T, InputArchive>::value &&  has_non_member_load_minimal<T, InputArchive>::value)> {};
+
+    // ######################################################################
+    namespace detail
+    {
+      //! Create a test for a cereal::specialization entry
+      #define CEREAL_MAKE_IS_SPECIALIZED_IMPL(name)                                          \
+      template <class T, class A>                                                            \
+      struct is_specialized_##name : std::integral_constant<bool,                            \
+        !std::is_base_of<std::false_type, specialize<A, T, specialization::name>>::value> {}
+
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_serialize);
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save);
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(member_load_save_minimal);
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_serialize);
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save);
+      CEREAL_MAKE_IS_SPECIALIZED_IMPL(non_member_load_save_minimal);
+
+      #undef CEREAL_MAKE_IS_SPECIALIZED_IMPL
+
+      //! Number of specializations detected
+      template <class T, class A>
+      struct count_specializations : std::integral_constant<int,
+        is_specialized_member_serialize<T, A>::value +
+        is_specialized_member_load_save<T, A>::value +
+        is_specialized_member_load_save_minimal<T, A>::value +
+        is_specialized_non_member_serialize<T, A>::value +
+        is_specialized_non_member_load_save<T, A>::value +
+        is_specialized_non_member_load_save_minimal<T, A>::value> {};
+    } // namespace detail
+
+    //! Check if any specialization exists for a type
+    template <class T, class A>
+    struct is_specialized : std::integral_constant<bool,
+      detail::is_specialized_member_serialize<T, A>::value ||
+      detail::is_specialized_member_load_save<T, A>::value ||
+      detail::is_specialized_member_load_save_minimal<T, A>::value ||
+      detail::is_specialized_non_member_serialize<T, A>::value ||
+      detail::is_specialized_non_member_load_save<T, A>::value ||
+      detail::is_specialized_non_member_load_save_minimal<T, A>::value>
+    {
+      static_assert(detail::count_specializations<T, A>::value <= 1, "More than one explicit specialization detected for type.");
+    };
+
+    //! Create the static assertion for some specialization
+    /*! This assertion will fail if the type is indeed specialized and does not have the appropriate
+        type of serialization functions */
+    #define CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, print_name, spec_name)                      \
+    static_assert( (is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value &&           \
+                   (has_##name<T, A>::value || has_##versioned_name<T, A>::value))                              \
+                   || !(is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value),        \
+                   "cereal detected " #print_name " specialization but no " #print_name " serialize function" )
+
+    //! Generates a test for specialization for versioned and unversioned functions
+    /*! This creates checks that can be queried to see if a given type of serialization function
+        has been specialized for this type */
+    #define CEREAL_MAKE_IS_SPECIALIZED(name, versioned_name, spec_name)                     \
+    template <class T, class A>                                                             \
+    struct is_specialized_##name : std::integral_constant<bool,                             \
+      is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
+    { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, name, spec_name); };          \
+    template <class T, class A>                                                             \
+    struct is_specialized_##versioned_name : std::integral_constant<bool,                   \
+      is_specialized<T, A>::value && detail::is_specialized_##spec_name<T, A>::value>       \
+    { CEREAL_MAKE_IS_SPECIALIZED_ASSERT(name, versioned_name, versioned_name, spec_name); }
+
+    CEREAL_MAKE_IS_SPECIALIZED(member_serialize, member_versioned_serialize, member_serialize);
+    CEREAL_MAKE_IS_SPECIALIZED(non_member_serialize, non_member_versioned_serialize, non_member_serialize);
+
+    CEREAL_MAKE_IS_SPECIALIZED(member_save, member_versioned_save, member_load_save);
+    CEREAL_MAKE_IS_SPECIALIZED(non_member_save, non_member_versioned_save, non_member_load_save);
+    CEREAL_MAKE_IS_SPECIALIZED(member_load, member_versioned_load, member_load_save);
+    CEREAL_MAKE_IS_SPECIALIZED(non_member_load, non_member_versioned_load, non_member_load_save);
+
+    CEREAL_MAKE_IS_SPECIALIZED(member_save_minimal, member_versioned_save_minimal, member_load_save_minimal);
+    CEREAL_MAKE_IS_SPECIALIZED(non_member_save_minimal, non_member_versioned_save_minimal, non_member_load_save_minimal);
+    CEREAL_MAKE_IS_SPECIALIZED(member_load_minimal, member_versioned_load_minimal, member_load_save_minimal);
+    CEREAL_MAKE_IS_SPECIALIZED(non_member_load_minimal, non_member_versioned_load_minimal, non_member_load_save_minimal);
+
+    #undef CEREAL_MAKE_IS_SPECIALIZED_ASSERT
+    #undef CEREAL_MAKE_IS_SPECIALIZED
+
+    // ######################################################################
+    // detects if a type has any active minimal output serialization
+    template <class T, class OutputArchive>
+    struct has_minimal_output_serialization : std::integral_constant<bool,
+      is_specialized_member_save_minimal<T, OutputArchive>::value ||
+      ((has_member_save_minimal<T, OutputArchive>::value ||
+        has_non_member_save_minimal<T, OutputArchive>::value ||
+        has_member_versioned_save_minimal<T, OutputArchive>::value ||
+        has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
+       !(is_specialized_member_serialize<T, OutputArchive>::value ||
+         is_specialized_member_save<T, OutputArchive>::value))> {};
+
+    // ######################################################################
+    // detects if a type has any active minimal input serialization
+    template <class T, class InputArchive>
+    struct has_minimal_input_serialization : std::integral_constant<bool,
+      is_specialized_member_load_minimal<T, InputArchive>::value ||
+      ((has_member_load_minimal<T, InputArchive>::value ||
+        has_non_member_load_minimal<T, InputArchive>::value ||
+        has_member_versioned_load_minimal<T, InputArchive>::value ||
+        has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
+       !(is_specialized_member_serialize<T, InputArchive>::value ||
+         is_specialized_member_load<T, InputArchive>::value))> {};
+
+    // ######################################################################
+    namespace detail
+    {
+      //! The number of output serialization functions available
+      /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
+      template <class T, class OutputArchive>
+      struct count_output_serializers : std::integral_constant<int,
+        count_specializations<T, OutputArchive>::value ? count_specializations<T, OutputArchive>::value :
+        has_member_save<T, OutputArchive>::value +
+        has_non_member_save<T, OutputArchive>::value +
+        has_member_serialize<T, OutputArchive>::value +
+        has_non_member_serialize<T, OutputArchive>::value +
+        has_member_save_minimal<T, OutputArchive>::value +
+        has_non_member_save_minimal<T, OutputArchive>::value +
+        /*-versioned---------------------------------------------------------*/
+        has_member_versioned_save<T, OutputArchive>::value +
+        has_non_member_versioned_save<T, OutputArchive>::value +
+        has_member_versioned_serialize<T, OutputArchive>::value +
+        has_non_member_versioned_serialize<T, OutputArchive>::value +
+        has_member_versioned_save_minimal<T, OutputArchive>::value +
+        has_non_member_versioned_save_minimal<T, OutputArchive>::value> {};
+    }
+
+    template <class T, class OutputArchive>
+    struct is_output_serializable : std::integral_constant<bool,
+      detail::count_output_serializers<T, OutputArchive>::value == 1> {};
+
+    // ######################################################################
+    namespace detail
+    {
+      //! The number of input serialization functions available
+      /*! If specialization is being used, we'll count only those; otherwise we'll count everything */
+      template <class T, class InputArchive>
+      struct count_input_serializers : std::integral_constant<int,
+        count_specializations<T, InputArchive>::value ? count_specializations<T, InputArchive>::value :
+        has_member_load<T, InputArchive>::value +
+        has_non_member_load<T, InputArchive>::value +
+        has_member_serialize<T, InputArchive>::value +
+        has_non_member_serialize<T, InputArchive>::value +
+        has_member_load_minimal<T, InputArchive>::value +
+        has_non_member_load_minimal<T, InputArchive>::value +
+        /*-versioned---------------------------------------------------------*/
+        has_member_versioned_load<T, InputArchive>::value +
+        has_non_member_versioned_load<T, InputArchive>::value +
+        has_member_versioned_serialize<T, InputArchive>::value +
+        has_non_member_versioned_serialize<T, InputArchive>::value +
+        has_member_versioned_load_minimal<T, InputArchive>::value +
+        has_non_member_versioned_load_minimal<T, InputArchive>::value> {};
+    }
+
+    template <class T, class InputArchive>
+    struct is_input_serializable : std::integral_constant<bool,
+      detail::count_input_serializers<T, InputArchive>::value == 1> {};
+
+    // ######################################################################
+    // Base Class Support
+    namespace detail
+    {
+      struct base_class_id
+      {
+        template<class T>
+          base_class_id(T const * const t) :
+          type(typeid(T)),
+          ptr(t),
+          hash(std::hash<std::type_index>()(typeid(T)) ^ (std::hash<void const *>()(t) << 1))
+          { }
+
+          bool operator==(base_class_id const & other) const
+          { return (type == other.type) && (ptr == other.ptr); }
+
+          std::type_index type;
+          void const * ptr;
+          size_t hash;
+      };
+      struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; }  };
+    } // namespace detail
+
+    namespace detail
+    {
+      //! Common base type for base class casting
+      struct BaseCastBase {};
+
+      template <class>
+      struct get_base_class;
+
+      template <template<typename> class Cast, class Base>
+      struct get_base_class<Cast<Base>>
+      {
+        using type = Base;
+      };
+
+      //! Base class cast, behave as the test
+      template <class Cast, template<class, class> class Test, class Archive,
+                bool IsBaseCast = std::is_base_of<BaseCastBase, Cast>::value>
+      struct has_minimal_base_class_serialization_impl : Test<typename get_base_class<Cast>::type, Archive>
+      { };
+
+      //! Not a base class cast
+      template <class Cast, template<class, class> class Test, class Archive>
+      struct has_minimal_base_class_serialization_impl<Cast,Test, Archive, false> : std::false_type
+      { };
+    }
+
+    //! Checks to see if the base class used in a cast has a minimal serialization
+    /*! @tparam Cast Either base_class or virtual_base_class wrapped type
+        @tparam Test A has_minimal test (for either input or output)
+        @tparam Archive The archive to use with the test */
+    template <class Cast, template<class, class> class Test, class Archive>
+    struct has_minimal_base_class_serialization : detail::has_minimal_base_class_serialization_impl<Cast, Test, Archive>
+    { };
+
+
+    // ######################################################################
+    namespace detail
+    {
+      struct shared_from_this_wrapper
+      {
+        template <class U>
+        static auto check( U const & t ) -> decltype( ::cereal::access::shared_from_this(t), std::true_type() );
+
+        static auto check( ... ) -> decltype( std::false_type() );
+
+        template <class U>
+        static auto get( U const & t ) -> decltype( t.shared_from_this() );
+      };
+    }
+
+    //! Determine if T or any base class of T has inherited from std::enable_shared_from_this
+    template<class T>
+    struct has_shared_from_this : decltype(detail::shared_from_this_wrapper::check(std::declval<T>()))
+    { };
+
+    //! Get the type of the base class of T which inherited from std::enable_shared_from_this
+    template <class T>
+    struct get_shared_from_this_base
+    {
+      private:
+        using PtrType = decltype(detail::shared_from_this_wrapper::get(std::declval<T>()));
+      public:
+        //! The type of the base of T that inherited from std::enable_shared_from_this
+        using type = typename std::decay<typename PtrType::element_type>::type;
+    };
+
+    // ######################################################################
+    //! Extracts the true type from something possibly wrapped in a cereal NoConvert
+    /*! Internally cereal uses some wrapper classes to test the validity of non-member
+        minimal load and save functions.  This can interfere with user type traits on
+        templated load and save minimal functions.  To get to the correct underlying type,
+        users should use strip_minimal when performing any enable_if type type trait checks.
+
+        See the enum serialization in types/common.hpp for an example of using this */
+    template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
+    struct strip_minimal
+    {
+      using type = T;
+    };
+
+    //! Specialization for types wrapped in a NoConvert
+    template <class T>
+    struct strip_minimal<T, true>
+    {
+      using type = typename T::type;
+    };
+
+    // ######################################################################
+    //! Member load and construct check
+    template<typename T, typename A>
+    struct has_member_load_and_construct : std::integral_constant<bool,
+      std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
+    { };
+
+    // ######################################################################
+    //! Non member load and construct check
+    template<typename T, typename A>
+    struct has_non_member_load_and_construct : std::integral_constant<bool,
+      std::is_same<decltype( LoadAndConstruct<T>::load_and_construct( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
+    { };
+
+    // ######################################################################
+    //! Has either a member or non member allocate
+    template<typename T, typename A>
+    struct has_load_and_construct : std::integral_constant<bool,
+      has_member_load_and_construct<T, A>::value || has_non_member_load_and_construct<T, A>::value>
+    { };
+
+    // ######################################################################
+    //! Determines whether the class T can be default constructed by cereal::access
+    template <class T>
+    struct is_default_constructible
+    {
+      #ifdef CEREAL_OLDER_GCC
+      template <class TT, class SFINAE = void>
+      struct test : no {};
+      template <class TT>
+      struct test<TT, typename detail::Void< decltype( cereal::access::construct<TT>() ) >::type> : yes {};
+      static const bool value = test<T>();
+      #else // NOT CEREAL_OLDER_GCC =========================================
+      template <class TT>
+      static auto test(int) -> decltype( cereal::access::construct<TT>(), yes());
+      template <class>
+      static no test(...);
+      static const bool value = std::is_same<decltype(test<T>(0)), yes>::value;
+      #endif // NOT CEREAL_OLDER_GCC
+    };
+
+    // ######################################################################
+    namespace detail
+    {
+      //! Removes all qualifiers and minimal wrappers from an archive
+      template <class A>
+      using decay_archive = typename std::decay<typename strip_minimal<A>::type>::type;
+    }
+
+    //! Checks if the provided archive type is equal to some cereal archive type
+    /*! This automatically does things such as std::decay and removing any other wrappers that may be
+        on the Archive template parameter.
+
+        Example use:
+        @code{cpp}
+        // example use to disable a serialization function
+        template <class Archive, EnableIf<cereal::traits::is_same_archive<Archive, cereal::BinaryOutputArchive>::value> = sfinae>
+        void save( Archive & ar, MyType const & mt );
+        @endcode */
+    template <class ArchiveT, class CerealArchiveT>
+    struct is_same_archive : std::integral_constant<bool,
+      std::is_same<detail::decay_archive<ArchiveT>, CerealArchiveT>::value>
+    { };
+
+    // ######################################################################
+    //! A macro to use to restrict which types of archives your function will work for.
+    /*! This requires you to have a template class parameter named Archive and replaces the void return
+        type for your function.
+
+        INTYPE refers to the input archive type you wish to restrict on.
+        OUTTYPE refers to the output archive type you wish to restrict on.
+
+        For example, if we want to limit a serialize to only work with binary serialization:
+
+        @code{.cpp}
+        template <class Archive>
+        CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
+        serialize( Archive & ar, MyCoolType & m )
+        {
+          ar & m;
+        }
+        @endcode
+
+        If you need to do more restrictions in your enable_if, you will need to do this by hand.
+     */
+    #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \
+    typename std::enable_if<cereal::traits::is_same_archive<Archive, INTYPE>::value || cereal::traits::is_same_archive<Archive, OUTTYPE>::value, void>::type
+
+    //! Type traits only struct used to mark an archive as human readable (text based)
+    /*! Archives that wish to identify as text based/human readable should inherit from
+        this struct */
+    struct TextArchive {};
+
+    //! Checks if an archive is a text archive (human readable)
+    template <class A>
+    struct is_text_archive : std::integral_constant<bool,
+      std::is_base_of<TextArchive, detail::decay_archive<A>>::value>
+    { };
+  } // namespace traits
+
+  // ######################################################################
+  namespace detail
+  {
+    template <class T, class A, bool Member = traits::has_member_load_and_construct<T, A>::value, bool NonMember = traits::has_non_member_load_and_construct<T, A>::value>
+    struct Construct
+    {
+      static_assert( cereal::traits::detail::delay_static_assert<T>::value,
+        "Cereal detected both member and non member load_and_construct functions!" );
+      static T * load_andor_construct( A & /*ar*/, construct<T> & /*construct*/ )
+      { return nullptr; }
+    };
+
+    template <class T, class A>
+    struct Construct<T, A, false, false>
+    {
+      static_assert( ::cereal::traits::is_default_constructible<T>::value,
+                     "Trying to serialize a an object with no default constructor. \n\n "
+                     "Types must either be default constructible or define either a member or non member Construct function. \n "
+                     "Construct functions generally have the signature: \n\n "
+                     "template <class Archive> \n "
+                     "static void load_and_construct(Archive & ar, cereal::construct<T> & construct) \n "
+                     "{ \n "
+                     "  var a; \n "
+                     "  ar( a ) \n "
+                     "  construct( a ); \n "
+                     "} \n\n" );
+      static T * load_andor_construct()
+      { return ::cereal::access::construct<T>(); }
+    };
+
+    template <class T, class A>
+    struct Construct<T, A, true, false>
+    {
+      static void load_andor_construct( A & ar, construct<T> & construct )
+      {
+        access::load_and_construct<T>( ar, construct );
+      }
+    };
+
+    template <class T, class A>
+    struct Construct<T, A, false, true>
+    {
+      static void load_andor_construct( A & ar, construct<T> & construct )
+      {
+        LoadAndConstruct<T>::load_and_construct( ar, construct );
+      }
+    };
+  } // namespace detail
+} // namespace cereal
+
+#endif // CEREAL_DETAILS_TRAITS_HPP_
diff --git a/include/cereal/details/util.hpp b/include/cereal/details/util.hpp
new file mode 100644
index 0000000..ba24813
--- /dev/null
+++ b/include/cereal/details/util.hpp
@@ -0,0 +1,84 @@
+/*! \file util.hpp
+    \brief Internal misc utilities
+    \ingroup Internal */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_DETAILS_UTIL_HPP_
+#define CEREAL_DETAILS_UTIL_HPP_
+
+#include <typeinfo>
+#include <string>
+
+#ifdef _MSC_VER
+namespace cereal
+{
+  namespace util
+  {
+    //! Demangles the type encoded in a string
+    /*! @internal */
+    inline std::string demangle( std::string const & name )
+    { return name; }
+
+    //! Gets the demangled name of a type
+    /*! @internal */
+    template <class T> inline
+    std::string demangledName()
+    { return typeid( T ).name(); }
+  } // namespace util
+} // namespace cereal
+#else // clang or gcc
+#include <cxxabi.h>
+#include <cstdlib>
+namespace cereal
+{
+  namespace util
+  {
+    //! Demangles the type encoded in a string
+    /*! @internal */
+    inline std::string demangle(std::string mangledName)
+    {
+      int status = 0;
+      char *demangledName = nullptr;
+      std::size_t len;
+
+      demangledName = abi::__cxa_demangle(mangledName.c_str(), 0, &len, &status);
+
+      std::string retName(demangledName);
+      free(demangledName);
+
+      return retName;
+    }
+
+    //! Gets the demangled name of a type
+    /*! @internal */
+    template<class T> inline
+    std::string demangledName()
+    { return demangle(typeid(T).name()); }
+  }
+} // namespace cereal
+#endif // clang or gcc branch of _MSC_VER
+#endif // CEREAL_DETAILS_UTIL_HPP_
diff --git a/include/cereal/external/base64.hpp b/include/cereal/external/base64.hpp
new file mode 100644
index 0000000..66ff63d
--- /dev/null
+++ b/include/cereal/external/base64.hpp
@@ -0,0 +1,125 @@
+/*
+   Copyright (C) 2004-2008 René Nyffenegger
+
+   This source code is provided 'as-is', without any express or implied
+   warranty. In no event will the author be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code. If you use this source code
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original source code.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+   René Nyffenegger rene.nyffenegger at adp-gmbh.ch
+*/
+
+#ifndef CEREAL_EXTERNAL_BASE64_HPP_
+#define CEREAL_EXTERNAL_BASE64_HPP_
+
+#include <string>
+
+namespace base64
+{
+  static const std::string chars =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz"
+    "0123456789+/";
+
+  static inline bool is_base64(unsigned char c) {
+    return (isalnum(c) || (c == '+') || (c == '/'));
+  }
+
+  inline std::string encode(unsigned char const* bytes_to_encode, size_t in_len) {
+    std::string ret;
+    int i = 0;
+    int j = 0;
+    unsigned char char_array_3[3];
+    unsigned char char_array_4[4];
+
+    while (in_len--) {
+      char_array_3[i++] = *(bytes_to_encode++);
+      if (i == 3) {
+        char_array_4[0] = (unsigned char) ((char_array_3[0] & 0xfc) >> 2);
+        char_array_4[1] = (unsigned char) ( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) );
+        char_array_4[2] = (unsigned char) ( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) );
+        char_array_4[3] = (unsigned char) ( char_array_3[2] & 0x3f );
+
+        for(i = 0; (i <4) ; i++)
+          ret += chars[char_array_4[i]];
+        i = 0;
+      }
+    }
+
+    if (i)
+    {
+      for(j = i; j < 3; j++)
+        char_array_3[j] = '\0';
+
+      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+      char_array_4[3] = char_array_3[2] & 0x3f;
+
+      for (j = 0; (j < i + 1); j++)
+        ret += chars[char_array_4[j]];
+
+      while((i++ < 3))
+        ret += '=';
+
+    }
+
+    return ret;
+
+  }
+
+  inline std::string decode(std::string const& encoded_string) {
+    size_t in_len = encoded_string.size();
+    size_t i = 0;
+    size_t j = 0;
+    int in_ = 0;
+    unsigned char char_array_4[4], char_array_3[3];
+    std::string ret;
+
+    while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+      char_array_4[i++] = encoded_string[in_]; in_++;
+      if (i ==4) {
+        for (i = 0; i <4; i++)
+          char_array_4[i] = (unsigned char) chars.find( char_array_4[i] );
+
+        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+        for (i = 0; (i < 3); i++)
+          ret += char_array_3[i];
+        i = 0;
+      }
+    }
+
+    if (i) {
+      for (j = i; j <4; j++)
+        char_array_4[j] = 0;
+
+      for (j = 0; j <4; j++)
+        char_array_4[j] = (unsigned char) chars.find( char_array_4[j] );
+
+      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+      for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+    }
+
+    return ret;
+  }
+} // base64
+#endif // CEREAL_EXTERNAL_BASE64_HPP_
diff --git a/include/cereal/external/rapidjson/document.h b/include/cereal/external/rapidjson/document.h
new file mode 100644
index 0000000..d350191
--- /dev/null
+++ b/include/cereal/external/rapidjson/document.h
@@ -0,0 +1,821 @@
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+#include "reader.h"
+#include "internal/strfunc.h"
+#include <new>		// placement new
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+	A JSON value can be one of 7 types. This class is a variant type supporting
+	these types.
+
+	Use the Value if UTF8 and default allocator
+
+	\tparam Encoding	Encoding of the value. (Even non-string values need to have the same encoding in a document)
+	\tparam Allocator	Allocator type for allocating memory of object, array and string.
+*/
+#pragma pack (push, 4)
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+	//! Name-value pair in an object.
+	struct Member {
+		GenericValue<Encoding, Allocator> name;		//!< name of member (must be a string)
+		GenericValue<Encoding, Allocator> value;	//!< value of member.
+	};
+
+	typedef Encoding EncodingType;					//!< Encoding type from template parameter.
+	typedef Allocator AllocatorType;				//!< Allocator type from template parameter.
+	typedef typename Encoding::Ch Ch;				//!< Character type derived from Encoding.
+	typedef Member* MemberIterator;					//!< Member iterator for iterating in object.
+	typedef const Member* ConstMemberIterator;		//!< Constant member iterator for iterating in object.
+	typedef GenericValue* ValueIterator;			//!< Value iterator for iterating in array.
+	typedef const GenericValue* ConstValueIterator;	//!< Constant value iterator for iterating in array.
+
+	//!@name Constructors and destructor.
+	//@{
+
+	//! Default constructor creates a null value.
+	GenericValue() : flags_(kNull_Flag) {}
+
+	//! Copy constructor is not permitted.
+private:
+	GenericValue(const GenericValue& rhs);
+
+public:
+
+	//! Constructor with JSON value type.
+	/*! This creates a Value of specified type with default content.
+		\param type	Type of the value.
+		\note Default content for number is zero.
+	*/
+	GenericValue(Type type) {
+		static const unsigned defaultFlags[7] = {
+			kNull_Flag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
+			kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag
+		};
+		RAPIDJSON_ASSERT(type <= kNumberType);
+		flags_ = defaultFlags[type];
+		memset(&data_, 0, sizeof(data_));
+	}
+
+	//! Constructor for boolean value.
+	GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}
+
+	//! Constructor for int value.
+	GenericValue(int i) : flags_(kNumberIntFlag) {
+		data_.n.i64 = i;
+		if (i >= 0)
+			flags_ |= kUintFlag | kUint64Flag;
+	}
+
+	//! Constructor for unsigned value.
+	GenericValue(unsigned u) : flags_(kNumberUintFlag) {
+		data_.n.u64 = u;
+		if (!(u & 0x80000000))
+			flags_ |= kIntFlag | kInt64Flag;
+	}
+
+	//! Constructor for int64_t value.
+	GenericValue(int64_t i64) : flags_(kNumberInt64Flag) {
+		data_.n.i64 = i64;
+		if (i64 >= 0) {
+			flags_ |= kNumberUint64Flag;
+			if (!(i64 & 0xFFFFFFFF00000000LL))
+				flags_ |= kUintFlag;
+			if (!(i64 & 0xFFFFFFFF80000000LL))
+				flags_ |= kIntFlag;
+		}
+		else if (i64 >= -2147483648LL)
+			flags_ |= kIntFlag;
+	}
+
+	//! Constructor for uint64_t value.
+	GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
+		data_.n.u64 = u64;
+		if (!(u64 & 0x8000000000000000ULL))
+			flags_ |= kInt64Flag;
+		if (!(u64 & 0xFFFFFFFF00000000ULL))
+			flags_ |= kUintFlag;
+		if (!(u64 & 0xFFFFFFFF80000000ULL))
+			flags_ |= kIntFlag;
+	}
+
+	//! Constructor for double value.
+	GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+	//! Constructor for constant string (i.e. do not make a copy of string)
+	GenericValue(const Ch* s, SizeType length) {
+		RAPIDJSON_ASSERT(s != NULL);
+		flags_ = kConstStringFlag;
+		data_.s.str = s;
+		data_.s.length = length;
+	}
+
+	//! Constructor for constant string (i.e. do not make a copy of string)
+	GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }
+
+	//! Constructor for copy-string (i.e. do make a copy of string)
+	GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }
+
+	//! Constructor for copy-string (i.e. do make a copy of string)
+	GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }
+
+	//! Destructor.
+	/*! Need to destruct elements of array, members of object, or copy-string.
+	*/
+	~GenericValue() {
+		if (Allocator::kNeedFree) {	// Shortcut by Allocator's trait
+			switch(flags_) {
+			case kArrayFlag:
+				for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+					v->~GenericValue();
+				Allocator::Free(data_.a.elements);
+				break;
+
+			case kObjectFlag:
+				for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+					m->name.~GenericValue();
+					m->value.~GenericValue();
+				}
+				Allocator::Free(data_.o.members);
+				break;
+
+			case kCopyStringFlag:
+				Allocator::Free(const_cast<Ch*>(data_.s.str));
+				break;
+			}
+		}
+	}
+
+	//@}
+
+	//!@name Assignment operators
+	//@{
+
+	//! Assignment with move semantics.
+	/*! \param rhs Source of the assignment. It will become a null value after assignment.
+	*/
+	GenericValue& operator=(GenericValue& rhs) {
+		RAPIDJSON_ASSERT(this != &rhs);
+		this->~GenericValue();
+		memcpy(this, &rhs, sizeof(GenericValue));
+		rhs.flags_ = kNull_Flag;
+		return *this;
+	}
+
+	//! Assignment with primitive types.
+	/*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
+		\param value The value to be assigned.
+	*/
+	template <typename T>
+	GenericValue& operator=(T value) {
+		this->~GenericValue();
+		new (this) GenericValue(value);
+		return *this;
+	}
+	//@}
+
+	//!@name Type
+	//@{
+
+	Type GetType()	const { return static_cast<Type>(flags_ & kTypeMask); }
+	bool IsNull_()	const { return flags_ == kNull_Flag; }
+	bool IsFalse()	const { return flags_ == kFalseFlag; }
+	bool IsTrue()	const { return flags_ == kTrueFlag; }
+	bool IsBool_()	const { return (flags_ & kBool_Flag) != 0; }
+	bool IsObject()	const { return flags_ == kObjectFlag; }
+	bool IsArray()	const { return flags_ == kArrayFlag; }
+	bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+	bool IsInt()	const { return (flags_ & kIntFlag) != 0; }
+	bool IsUint()	const { return (flags_ & kUintFlag) != 0; }
+	bool IsInt64()	const { return (flags_ & kInt64Flag) != 0; }
+	bool IsUint64()	const { return (flags_ & kUint64Flag) != 0; }
+	bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+	bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+	//@}
+
+	//!@name Null_
+	//@{
+
+	GenericValue& SetNull_() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+	//@}
+
+	//!@name Bool_
+	//@{
+
+	bool GetBool_() const { RAPIDJSON_ASSERT(IsBool_()); return flags_ == kTrueFlag; }
+	GenericValue& SetBool_(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+	//@}
+
+	//!@name Object
+	//@{
+
+	//! Set this value as an empty object.
+	GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+	//! Get the value associated with the object's name.
+	GenericValue& operator[](const Ch* name) {
+		if (Member* member = FindMember(name))
+			return member->value;
+		else {
+			static GenericValue Null_Value;
+			return Null_Value;
+		}
+	}
+	const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+	//! Member iterators.
+	ConstMemberIterator MemberBegin() const	{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+	ConstMemberIterator MemberEnd()	const	{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+	MemberIterator MemberBegin()			{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+	MemberIterator MemberEnd()				{ RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+
+	//! Check whether a member exists in the object.
+	bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
+
+	//! Add a member (name-value pair) to the object.
+	/*! \param name A string value as name of member.
+		\param value Value of any type.
+	    \param allocator Allocator for reallocating memory.
+	    \return The value itself for fluent API.
+	    \note The ownership of name and value will be transfered to this object if success.
+	*/
+	GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+		RAPIDJSON_ASSERT(IsObject());
+		RAPIDJSON_ASSERT(name.IsString());
+		Object& o = data_.o;
+		if (o.size >= o.capacity) {
+			if (o.capacity == 0) {
+				o.capacity = kDefaultObjectCapacity;
+				o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));
+			}
+			else {
+				SizeType oldCapacity = o.capacity;
+				o.capacity *= 2;
+				o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));
+			}
+		}
+		o.members[o.size].name.RawAssign(name);
+		o.members[o.size].value.RawAssign(value);
+		o.size++;
+		return *this;
+	}
+
+	GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
+		GenericValue n(name, internal::StrLen(name), nameAllocator);
+		return AddMember(n, value, allocator);
+	}
+
+	GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {
+		GenericValue n(name, internal::StrLen(name));
+		return AddMember(n, value, allocator);
+	}
+
+	template <typename T>
+	GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {
+		GenericValue n(name, internal::StrLen(name));
+		GenericValue v(value);
+		return AddMember(n, v, allocator);
+	}
+
+	//! Remove a member in object by its name.
+	/*! \param name Name of member to be removed.
+	    \return Whether the member existed.
+	    \note Removing member is implemented by moving the last member. So the ordering of members is changed.
+	*/
+	bool RemoveMember(const Ch* name) {
+		RAPIDJSON_ASSERT(IsObject());
+		if (Member* m = FindMember(name)) {
+			RAPIDJSON_ASSERT(data_.o.size > 0);
+			RAPIDJSON_ASSERT(data_.o.members != 0);
+
+			Member* last = data_.o.members + (data_.o.size - 1);
+			if (data_.o.size > 1 && m != last) {
+				// Move the last one to this place
+				m->name = last->name;
+				m->value = last->value;
+			}
+			else {
+				// Only one left, just destroy
+				m->name.~GenericValue();
+				m->value.~GenericValue();
+			}
+			--data_.o.size;
+			return true;
+		}
+		return false;
+	}
+
+	//@}
+
+	//!@name Array
+	//@{
+
+	//! Set this value as an empty array.
+	GenericValue& SetArray() {	this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+	//! Get the number of elements in array.
+	SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+	//! Get the capacity of array.
+	SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+	//! Check whether the array is empty.
+	bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+	//! Remove all elements in the array.
+	/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+	*/
+	void Clear() {
+		RAPIDJSON_ASSERT(IsArray());
+		for (SizeType i = 0; i < data_.a.size; ++i)
+			data_.a.elements[i].~GenericValue();
+		data_.a.size = 0;
+	}
+
+	//! Get an element from array by index.
+	/*! \param index Zero-based index of element.
+		\note
+\code
+Value a(kArrayType);
+a.PushBack(123);
+int x = a[0].GetInt();				// Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
+int y = a[SizeType(0)].GetInt();	// Cast to SizeType will work.
+int z = a[0u].GetInt();				// This works too.
+\endcode
+	*/
+	GenericValue& operator[](SizeType index) {
+		RAPIDJSON_ASSERT(IsArray());
+		RAPIDJSON_ASSERT(index < data_.a.size);
+		return data_.a.elements[index];
+	}
+	const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+	//! Element iterator
+	ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+	ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+	ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+	ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+	//! Request the array to have enough capacity to store elements.
+	/*! \param newCapacity	The capacity that the array at least need to have.
+		\param allocator	The allocator for allocating memory. It must be the same one use previously.
+		\return The value itself for fluent API.
+	*/
+	GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+		RAPIDJSON_ASSERT(IsArray());
+		if (newCapacity > data_.a.capacity) {
+			data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
+			data_.a.capacity = newCapacity;
+		}
+		return *this;
+	}
+
+	//! Append a value at the end of the array.
+	/*! \param value		The value to be appended.
+	    \param allocator	The allocator for allocating memory. It must be the same one use previously.
+	    \return The value itself for fluent API.
+	    \note The ownership of the value will be transfered to this object if success.
+	    \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+	*/
+	GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+		RAPIDJSON_ASSERT(IsArray());
+		if (data_.a.size >= data_.a.capacity)
+			Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);
+		data_.a.elements[data_.a.size++].RawAssign(value);
+		return *this;
+	}
+
+	template <typename T>
+	GenericValue& PushBack(T value, Allocator& allocator) {
+		GenericValue v(value);
+		return PushBack(v, allocator);
+	}
+
+	//! Remove the last element in the array.
+	GenericValue& PopBack() {
+		RAPIDJSON_ASSERT(IsArray());
+		RAPIDJSON_ASSERT(!Empty());
+		data_.a.elements[--data_.a.size].~GenericValue();
+		return *this;
+	}
+	//@}
+
+	//!@name Number
+	//@{
+
+	int GetInt() const			{ RAPIDJSON_ASSERT(flags_ & kIntFlag);   return data_.n.i.i;   }
+	unsigned GetUint() const	{ RAPIDJSON_ASSERT(flags_ & kUintFlag);  return data_.n.u.u;   }
+	int64_t GetInt64() const	{ RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+	uint64_t GetUint64() const	{ RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+	double GetDouble() const {
+		RAPIDJSON_ASSERT(IsNumber());
+		if ((flags_ & kDoubleFlag) != 0)				return data_.n.d;	// exact type, no conversion.
+		if ((flags_ & kIntFlag) != 0)					return data_.n.i.i;	// int -> double
+		if ((flags_ & kUintFlag) != 0)					return data_.n.u.u;	// unsigned -> double
+		if ((flags_ & kInt64Flag) != 0)					return (double)data_.n.i64; // int64_t -> double (may lose precision)
+		RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0);	return (double)data_.n.u64;	// uint64_t -> double (may lose precision)
+	}
+
+	GenericValue& SetInt(int i)				{ this->~GenericValue(); new (this) GenericValue(i);	return *this; }
+	GenericValue& SetUint(unsigned u)		{ this->~GenericValue(); new (this) GenericValue(u);	return *this; }
+	GenericValue& SetInt64(int64_t i64)		{ this->~GenericValue(); new (this) GenericValue(i64);	return *this; }
+	GenericValue& SetUint64(uint64_t u64)	{ this->~GenericValue(); new (this) GenericValue(u64);	return *this; }
+	GenericValue& SetDouble(double d)		{ this->~GenericValue(); new (this) GenericValue(d);	return *this; }
+
+	//@}
+
+	//!@name String
+	//@{
+
+	const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
+
+	//! Get the length of string.
+	/*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+	*/
+	SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
+
+	//! Set this value as a string without copying source string.
+	/*! This version has better performance with supplied length, and also support string containing null character.
+		\param s source string pointer.
+		\param length The length of source string, excluding the trailing null terminator.
+		\return The value itself for fluent API.
+	*/
+	GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
+
+	//! Set this value as a string without copying source string.
+	/*! \param s source string pointer.
+		\return The value itself for fluent API.
+	*/
+	GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
+
+	//! Set this value as a string by copying from source string.
+	/*! This version has better performance with supplied length, and also support string containing null character.
+		\param s source string.
+		\param length The length of source string, excluding the trailing null terminator.
+		\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+		\return The value itself for fluent API.
+	*/
+	GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
+
+	//! Set this value as a string by copying from source string.
+	/*!	\param s source string.
+		\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+		\return The value itself for fluent API.
+	*/
+	GenericValue& SetString(const Ch* s, Allocator& allocator) {	SetString(s, internal::StrLen(s), allocator); return *this; }
+
+	//@}
+
+	//! Generate events of this value to a Handler.
+	/*! This function adopts the GoF visitor pattern.
+		Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+		It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+		\tparam Handler type of handler.
+		\param handler An object implementing concept Handler.
+	*/
+	template <typename Handler>
+	const GenericValue& Accept(Handler& handler) const {
+		switch(GetType()) {
+		case kNull_Type:		handler.Null_(); break;
+		case kFalseType:	handler.Bool_(false); break;
+		case kTrueType:		handler.Bool_(true); break;
+
+		case kObjectType:
+			handler.StartObject();
+			for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+				handler.String(m->name.data_.s.str, m->name.data_.s.length, false);
+				m->value.Accept(handler);
+			}
+			handler.EndObject(data_.o.size);
+			break;
+
+		case kArrayType:
+			handler.StartArray();
+			for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+				v->Accept(handler);
+			handler.EndArray(data_.a.size);
+			break;
+
+		case kStringType:
+			handler.String(data_.s.str, data_.s.length, false);
+			break;
+
+		case kNumberType:
+			if (IsInt())			handler.Int(data_.n.i.i);
+			else if (IsUint())		handler.Uint(data_.n.u.u);
+			else if (IsInt64())		handler.Int64(data_.n.i64);
+			else if (IsUint64())	handler.Uint64(data_.n.u64);
+			else					handler.Double(data_.n.d);
+			break;
+		}
+		return *this;
+	}
+
+private:
+	template <typename, typename>
+	friend class GenericDocument;
+
+	enum {
+		kBool_Flag = 0x100,
+		kNumberFlag = 0x200,
+		kIntFlag = 0x400,
+		kUintFlag = 0x800,
+		kInt64Flag = 0x1000,
+		kUint64Flag = 0x2000,
+		kDoubleFlag = 0x4000,
+		kStringFlag = 0x100000,
+		kCopyFlag = 0x200000,
+
+		// Initial flags of different types.
+		kNull_Flag = kNull_Type,
+		kTrueFlag = kTrueType | kBool_Flag,
+		kFalseFlag = kFalseType | kBool_Flag,
+		kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+		kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+		kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+		kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+		kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+		kConstStringFlag = kStringType | kStringFlag,
+		kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+		kObjectFlag = kObjectType,
+		kArrayFlag = kArrayType,
+
+		kTypeMask = 0xFF	// bitwise-and with mask of 0xFF can be optimized by compiler
+	};
+
+	static const SizeType kDefaultArrayCapacity = 16;
+	static const SizeType kDefaultObjectCapacity = 16;
+
+	struct String {
+		const Ch* str;
+		SizeType length;
+		unsigned hashcode;	//!< reserved
+	};	// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+	// By using proper binary layout, retrieval of different integer types do not need conversions.
+	union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+		struct I {
+			int i;
+			char padding[4];
+		}i;
+		struct U {
+			unsigned u;
+			char padding2[4];
+		}u;
+#else
+		struct I {
+			char padding[4];
+			int i;
+		}i;
+		struct U {
+			char padding2[4];
+			unsigned u;
+		}u;
+#endif
+		int64_t i64;
+		uint64_t u64;
+		double d;
+	};	// 8 bytes
+
+	struct Object {
+		Member* members;
+		SizeType size;
+		SizeType capacity;
+	};	// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+	struct Array {
+		GenericValue<Encoding, Allocator>* elements;
+		SizeType size;
+		SizeType capacity;
+	};	// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+	union Data {
+		String s;
+		Number n;
+		Object o;
+		Array a;
+	};	// 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+	//! Find member by name.
+	Member* FindMember(const Ch* name) {
+		RAPIDJSON_ASSERT(name);
+		RAPIDJSON_ASSERT(IsObject());
+
+		SizeType length = internal::StrLen(name);
+
+		Object& o = data_.o;
+		for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)
+			if (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0)
+				return member;
+
+		return 0;
+	}
+	const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+	// Initialize this value as array with initial data, without calling destructor.
+	void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
+		flags_ = kArrayFlag;
+		data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));
+		memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+		data_.a.size = data_.a.capacity = count;
+	}
+
+	//! Initialize this value as object with initial data, without calling destructor.
+	void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {
+		flags_ = kObjectFlag;
+		data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));
+		memcpy(data_.o.members, members, count * sizeof(Member));
+		data_.o.size = data_.o.capacity = count;
+	}
+
+	//! Initialize this value as constant string, without calling destructor.
+	void SetStringRaw(const Ch* s, SizeType length) {
+		RAPIDJSON_ASSERT(s != NULL);
+		flags_ = kConstStringFlag;
+		data_.s.str = s;
+		data_.s.length = length;
+	}
+
+	//! Initialize this value as copy string with initial data, without calling destructor.
+	void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
+		RAPIDJSON_ASSERT(s != NULL);
+		flags_ = kCopyStringFlag;
+		data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));
+		data_.s.length = length;
+		memcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));
+		const_cast<Ch*>(data_.s.str)[length] = '\0';
+	}
+
+	//! Assignment without calling destructor
+	void RawAssign(GenericValue& rhs) {
+		memcpy(this, &rhs, sizeof(GenericValue));
+		rhs.flags_ = kNull_Flag;
+	}
+
+	Data data_;
+	unsigned flags_;
+};
+#pragma pack (pop)
+
+//! Value with UTF8 encoding.
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+	\implements Handler
+	\tparam Encoding encoding for both parsing and string storage.
+	\tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+	typedef typename Encoding::Ch Ch;						//!< Character type derived from Encoding.
+	typedef GenericValue<Encoding, Allocator> ValueType;	//!< Value type of the document.
+	typedef Allocator AllocatorType;						//!< Allocator type from template parameter.
+
+	//! Constructor
+	/*! \param allocator		Optional allocator for allocating stack memory.
+		\param stackCapacity	Initial capacity of stack in bytes.
+	*/
+	GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+	//! Parse JSON text from an input stream.
+	/*! \tparam parseFlags Combination of ParseFlag.
+		\param stream Input stream to be parsed.
+		\return The document itself for fluent API.
+	*/
+	template <unsigned parseFlags, typename Stream>
+	GenericDocument& ParseStream(Stream& stream) {
+		ValueType::SetNull_(); // Remove existing root if exist
+		GenericReader<Encoding, Allocator> reader;
+		if (reader.template Parse<parseFlags>(stream, *this)) {
+			RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+			this->RawAssign(*stack_.template Pop<ValueType>(1));	// Add this-> to prevent issue 13.
+			parseError_ = 0;
+			errorOffset_ = 0;
+		}
+		else {
+			parseError_ = reader.GetParseError();
+			errorOffset_ = reader.GetErrorOffset();
+			ClearStack();
+		}
+		return *this;
+	}
+
+	//! Parse JSON text from a mutable string.
+	/*! \tparam parseFlags Combination of ParseFlag.
+		\param str Mutable zero-terminated string to be parsed.
+		\return The document itself for fluent API.
+	*/
+	template <unsigned parseFlags>
+	GenericDocument& ParseInsitu(Ch* str) {
+		GenericInsituStringStream<Encoding> s(str);
+		return ParseStream<parseFlags | kParseInsituFlag>(s);
+	}
+
+	//! Parse JSON text from a read-only string.
+	/*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
+		\param str Read-only zero-terminated string to be parsed.
+	*/
+	template <unsigned parseFlags>
+	GenericDocument& Parse(const Ch* str) {
+		RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+		GenericStringStream<Encoding> s(str);
+		return ParseStream<parseFlags>(s);
+	}
+
+	//! Whether a parse error was occured in the last parsing.
+	bool HasParseError() const { return parseError_ != 0; }
+
+	//! Get the message of parsing error.
+	const char* GetParseError() const { return parseError_; }
+
+	//! Get the offset in character of the parsing error.
+	size_t GetErrorOffset() const { return errorOffset_; }
+
+	//! Get the allocator of this document.
+	Allocator& GetAllocator() {	return stack_.GetAllocator(); }
+
+	//! Get the capacity of stack in bytes.
+	size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+	// Prohibit assignment
+	GenericDocument& operator=(const GenericDocument&);
+
+	friend class GenericReader<Encoding, Allocator>;	// for Reader to call the following private handler functions
+
+	// Implementation of Handler
+	void Null_()	{ new (stack_.template Push<ValueType>()) ValueType(); }
+	void Bool_(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }
+	void Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+	void Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+	void Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+	void Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+	void Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }
+
+	void String(const Ch* str, SizeType length, bool copy) {
+		if (copy)
+			new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+		else
+			new (stack_.template Push<ValueType>()) ValueType(str, length);
+	}
+
+	void StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }
+
+	void EndObject(SizeType memberCount) {
+		typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+		stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+	}
+
+	void StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }
+
+	void EndArray(SizeType elementCount) {
+		ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+		stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+	}
+
+	void ClearStack() {
+		if (Allocator::kNeedFree)
+			while (stack_.GetSize() > 0)	// Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+				(stack_.template Pop<ValueType>(1))->~ValueType();
+		else
+			stack_.Clear();
+	}
+
+	static const size_t kDefaultStackCapacity = 1024;
+	internal::Stack<Allocator> stack_;
+	const char* parseError_;
+	size_t errorOffset_;
+};
+
+typedef GenericDocument<UTF8<> > Document;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/include/cereal/external/rapidjson/filestream.h b/include/cereal/external/rapidjson/filestream.h
new file mode 100644
index 0000000..b11e2e9
--- /dev/null
+++ b/include/cereal/external/rapidjson/filestream.h
@@ -0,0 +1,47 @@
+#ifndef RAPIDJSON_FILESTREAM_H_
+#define RAPIDJSON_FILESTREAM_H_
+
+#include <cstdio>
+
+namespace rapidjson {
+
+//! Wrapper of C file stream for input or output.
+/*!
+	This simple wrapper does not check the validity of the stream.
+	\implements Stream
+*/
+class FileStream {
+public:
+	typedef char Ch;	//!< Character type. Only support char.
+
+	FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
+
+	char Peek() const   { return current_; }
+	char Take()         { char c = current_; Read(); return c; }
+	size_t Tell() const { return count_; }
+	void Put(char c)    { fputc(c, fp_); }
+
+	// Not implemented
+	char* PutBegin()     { return 0; }
+	size_t PutEnd(char*) { return 0; }
+
+private:
+	void Read() {
+		RAPIDJSON_ASSERT(fp_ != 0);
+		int c = fgetc(fp_);
+		if (c != EOF) {
+			current_ = (char)c;
+			count_++;
+		}
+		else
+			current_ = '\0';
+	}
+
+	FILE* fp_;
+	char current_;
+	size_t count_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/include/cereal/external/rapidjson/genericstream.h b/include/cereal/external/rapidjson/genericstream.h
new file mode 100644
index 0000000..2d6a705
--- /dev/null
+++ b/include/cereal/external/rapidjson/genericstream.h
@@ -0,0 +1,105 @@
+// Generic*Stream code from https://code.google.com/p/rapidjson/issues/detail?id=20
+#ifndef RAPIDJSON_GENERICSTREAM_H_
+#define RAPIDJSON_GENERICSTREAM_H_
+
+#include "rapidjson.h"
+#include <iostream>
+
+#ifdef _MSC_VER
+  #pragma warning(push)
+  #pragma warning(disable: 4127) // conditional expression is constant
+  #pragma warning(disable: 4512) // assignment operator could not be generated
+  #pragma warning(disable: 4100) // unreferenced formal parameter
+#endif
+
+namespace rapidjson {
+
+  //! Wrapper of std::istream for input.
+  class GenericReadStream {
+    public:
+      typedef char Ch;    //!< Character type (byte).
+
+      //! Constructor.
+      /*!
+        \param is Input stream.
+        */
+      GenericReadStream(std::istream & is) : is_(&is) {
+      }
+
+
+      Ch Peek() const {
+        if(is_->eof()) return '\0';
+        return static_cast<char>(is_->peek());
+      }
+
+      Ch Take() {
+        if(is_->eof()) return '\0';
+        return static_cast<char>(is_->get());
+      }
+
+      size_t Tell() const {
+        return (int)is_->tellg();
+      }
+
+      // Not implemented
+      void Put(Ch)       { RAPIDJSON_ASSERT(false); }
+      void Flush()       { RAPIDJSON_ASSERT(false); }
+      Ch* PutBegin()     { RAPIDJSON_ASSERT(false); return 0; }
+      size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+      std::istream * is_;
+  };
+
+
+  //! Wrapper of std::ostream for output.
+  class GenericWriteStream {
+    public:
+      typedef char Ch;    //!< Character type. Only support char.
+
+      //! Constructor
+      /*!
+        \param os Output stream.
+        */
+      GenericWriteStream(std::ostream& os) : os_(os) {
+      }
+
+      void Put(char c) {
+        os_.put(c);
+      }
+
+      void PutN(char c, size_t n) {
+        for (size_t i = 0; i < n; ++i) {
+          Put(c);
+        }
+      }
+
+      void Flush() {
+        os_.flush();
+      }
+
+      size_t Tell() const {
+        return (int)os_.tellp();
+      }
+
+      // Not implemented
+      char Peek() const    { RAPIDJSON_ASSERT(false); }
+      char Take()          { RAPIDJSON_ASSERT(false); }
+      char* PutBegin()     { RAPIDJSON_ASSERT(false); return 0; }
+      size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    private:
+      std::ostream& os_;
+  };
+
+  template<>
+    inline void PutN(GenericWriteStream& stream, char c, size_t n) {
+      stream.PutN(c, n);
+    }
+
+} // namespace rapidjson
+
+// On MSVC, restore warnings state
+#ifdef _MSC_VER
+    #pragma warning(pop)
+#endif
+#endif // RAPIDJSON_GENERICSTREAM_H_
diff --git a/include/cereal/external/rapidjson/internal/pow10.h b/include/cereal/external/rapidjson/internal/pow10.h
new file mode 100644
index 0000000..bf3a9af
--- /dev/null
+++ b/include/cereal/external/rapidjson/internal/pow10.h
@@ -0,0 +1,54 @@
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+namespace rapidjson {
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+	\param n positive/negative exponent. Must <= 308.
+	\return 10.0^n
+*/
+inline double Pow10(int n) {
+	static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
+		1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
+		1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
+		1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
+		1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
+		1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
+		1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
+		1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
+		1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
+		1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
+		1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
+		1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
+		1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80, 
+		1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 
+		1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 
+		1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, 
+		1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9,  1e-8,  1e-7,  1e-6,  1e-5,  1e-4,  1e-3,  1e-2,  1e-1,  1e+0,  
+		1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
+		1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+		1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+		1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+		1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+		1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+		1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+		1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+		1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+		1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+		1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+		1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+		1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+		1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+		1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+		1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+	};
+	RAPIDJSON_ASSERT(n <= 308);
+	return n < -308 ? 0.0 : e[n + 308];
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_POW10_
diff --git a/include/cereal/external/rapidjson/internal/stack.h b/include/cereal/external/rapidjson/internal/stack.h
new file mode 100644
index 0000000..3138b96
--- /dev/null
+++ b/include/cereal/external/rapidjson/internal/stack.h
@@ -0,0 +1,82 @@
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+namespace rapidjson {
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+	Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
+		RAPIDJSON_ASSERT(stack_capacity_ > 0);
+		if (!allocator_)
+			own_allocator_ = allocator_ = new Allocator();
+		stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
+		stack_end_ = stack_ + stack_capacity_;
+	}
+
+	~Stack() {
+		Allocator::Free(stack_);
+		delete own_allocator_; // Only delete if it is owned by the stack
+	}
+
+	void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
+
+	template<typename T>
+	T* Push(size_t count = 1) {
+		 // Expand the stack if needed
+		if (stack_top_ + sizeof(T) * count >= stack_end_) {
+			size_t new_capacity = stack_capacity_ * 2;
+			size_t size = GetSize();
+			size_t new_size = GetSize() + sizeof(T) * count;
+			if (new_capacity < new_size)
+				new_capacity = new_size;
+			stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
+			stack_capacity_ = new_capacity;
+			stack_top_ = stack_ + size;
+			stack_end_ = stack_ + stack_capacity_;
+		}
+		T* ret = (T*)stack_top_;
+		stack_top_ += sizeof(T) * count;
+		return ret;
+	}
+
+	template<typename T>
+	T* Pop(size_t count) {
+		RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+		stack_top_ -= count * sizeof(T);
+		return (T*)stack_top_;
+	}
+
+	template<typename T>
+	T* Top() { 
+		RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+		return (T*)(stack_top_ - sizeof(T));
+	}
+
+	template<typename T>
+	T* Bottom() { return (T*)stack_; }
+
+	Allocator& GetAllocator() { return *allocator_; }
+	size_t GetSize() const { return stack_top_ - stack_; }
+	size_t GetCapacity() const { return stack_capacity_; }
+
+private:
+	Allocator* allocator_;
+	Allocator* own_allocator_;
+	char *stack_;
+	char *stack_top_;
+	char *stack_end_;
+	size_t stack_capacity_;
+};
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/include/cereal/external/rapidjson/internal/strfunc.h b/include/cereal/external/rapidjson/internal/strfunc.h
new file mode 100644
index 0000000..47b8ac0
--- /dev/null
+++ b/include/cereal/external/rapidjson/internal/strfunc.h
@@ -0,0 +1,24 @@
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+namespace rapidjson {
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*!	\tparam Ch Character type (e.g. char, wchar_t, short)
+	\param s Null-terminated input string.
+	\return Number of characters in the string. 
+	\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+	const Ch* p = s;
+	while (*p != '\0')
+		++p;
+	return SizeType(p - s);
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/include/cereal/external/rapidjson/license.txt b/include/cereal/external/rapidjson/license.txt
new file mode 100644
index 0000000..fba5ec2
--- /dev/null
+++ b/include/cereal/external/rapidjson/license.txt
@@ -0,0 +1,19 @@
+Copyright (C) 2011 Milo Yip
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/include/cereal/external/rapidjson/prettywriter.h b/include/cereal/external/rapidjson/prettywriter.h
new file mode 100644
index 0000000..107a263
--- /dev/null
+++ b/include/cereal/external/rapidjson/prettywriter.h
@@ -0,0 +1,156 @@
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+namespace rapidjson {
+
+//! Writer with indentation and spacing.
+/*!
+	\tparam Stream Type of ouptut stream.
+	\tparam Encoding Encoding of both source strings and output.
+	\tparam Allocator Type of allocator for allocating memory of stack.
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
+public:
+	typedef Writer<Stream, Encoding, Allocator> Base;
+	typedef typename Base::Ch Ch;
+
+	//! Constructor
+	/*! \param stream Output stream.
+		\param allocator User supplied allocator. If it is null, it will create a private one.
+		\param levelDepth Initial capacity of
+	*/
+	PrettyWriter(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+		Base(stream, precision, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+	//! Set custom indentation.
+	/*! \param indentChar		Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
+		\param indentCharCount	Number of indent characters for each indentation level.
+		\note The default indentation is 4 spaces.
+	*/
+	PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+		RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+		indentChar_ = indentChar;
+		indentCharCount_ = indentCharCount;
+		return *this;
+	}
+
+	//@name Implementation of Handler.
+	//@{
+
+	PrettyWriter& Null_()				{ PrettyPrefix(kNull_Type);   Base::WriteNull_();			return *this; }
+	PrettyWriter& Bool_(bool b)			{ PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool_(b); return *this; }
+	PrettyWriter& Int(int i)			{ PrettyPrefix(kNumberType); Base::WriteInt(i);			return *this; }
+	PrettyWriter& Uint(unsigned u)		{ PrettyPrefix(kNumberType); Base::WriteUint(u);		return *this; }
+	PrettyWriter& Int64(int64_t i64)	{ PrettyPrefix(kNumberType); Base::WriteInt64(i64);		return *this; }
+	PrettyWriter& Uint64(uint64_t u64)	{ PrettyPrefix(kNumberType); Base::WriteUint64(u64);	return *this; }
+	PrettyWriter& Double(double d)		{ PrettyPrefix(kNumberType); Base::WriteDouble(d);		return *this; }
+
+	PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
+		(void)copy;
+		PrettyPrefix(kStringType);
+		Base::WriteString(str, length);
+		return *this;
+	}
+
+	PrettyWriter& StartObject() {
+		PrettyPrefix(kObjectType);
+		new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+		Base::WriteStartObject();
+		return *this;
+	}
+
+	PrettyWriter& EndObject(SizeType memberCount = 0) {
+		(void)memberCount;
+		RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+		RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+		bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+		if (!empty) {
+			Base::stream_.Put('\n');
+			WriteIndent();
+		}
+		Base::WriteEndObject();
+		return *this;
+	}
+
+	PrettyWriter& StartArray() {
+		PrettyPrefix(kArrayType);
+		new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+		Base::WriteStartArray();
+		return *this;
+	}
+
+	PrettyWriter& EndArray(SizeType memberCount = 0) {
+		(void)memberCount;
+		RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+		RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+		bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+		if (!empty) {
+			Base::stream_.Put('\n');
+			WriteIndent();
+		}
+		Base::WriteEndArray();
+		return *this;
+	}
+
+	//@}
+
+	//! Simpler but slower overload.
+	PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+	void PrettyPrefix(Type type) {
+		(void)type;
+		if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+			typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+			if (level->inArray) {
+				if (level->valueCount > 0) {
+					Base::stream_.Put(','); // add comma if it is not the first element in array
+					Base::stream_.Put('\n');
+				}
+				else
+					Base::stream_.Put('\n');
+				WriteIndent();
+			}
+			else {	// in object
+				if (level->valueCount > 0) {
+					if (level->valueCount % 2 == 0) {
+						Base::stream_.Put(',');
+						Base::stream_.Put('\n');
+					}
+					else {
+						Base::stream_.Put(':');
+						Base::stream_.Put(' ');
+					}
+				}
+				else
+					Base::stream_.Put('\n');
+
+				if (level->valueCount % 2 == 0)
+					WriteIndent();
+			}
+			if (!level->inArray && level->valueCount % 2 == 0)
+				RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+			level->valueCount++;
+		}
+		else
+			RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+	}
+
+	void WriteIndent()  {
+		size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+		PutN(Base::stream_, indentChar_, count);
+	}
+
+	Ch indentChar_;
+	unsigned indentCharCount_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/include/cereal/external/rapidjson/rapidjson.h b/include/cereal/external/rapidjson/rapidjson.h
new file mode 100644
index 0000000..20a73ae
--- /dev/null
+++ b/include/cereal/external/rapidjson/rapidjson.h
@@ -0,0 +1,525 @@
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+// Copyright (c) 2011-2012 Milo Yip (miloyip at gmail.com)
+// Version 0.11
+
+#include <cstdlib>	// malloc(), realloc(), free()
+#include <cstring>	// memcpy()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+// Here defines int64_t and uint64_t types in global namespace.
+// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
+#ifndef RAPIDJSON_NO_INT64DEFINE
+#ifdef _MSC_VER
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN	0	//!< Little endian machine
+#define RAPIDJSON_BIGENDIAN		1	//!< Big endian machine
+
+//! Endianness of the machine.
+/*!	GCC provided macro for detecting endianness of the target machine. But other
+	compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+	RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.
+*/
+#ifndef RAPIDJSON_ENDIAN
+#ifdef __BYTE_ORDER__
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#endif // __BYTE_ORDER__
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN	// Assumes little endian otherwise.
+#endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+// Enable SSE2 optimization.
+//#define RAPIDJSON_SSE2
+
+// Enable SSE4.2 optimization.
+//#define RAPIDJSON_SSE42
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+namespace rapidjson {
+//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
+/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+} // namespace rapidjson
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! By default, rapidjson uses C assert() for assertion.
+	User can override it by defining RAPIDJSON_ASSERT(x) macro.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+	\brief Concept for allocating, resizing and freeing memory block.
+	
+	Note that Malloc() and Realloc() are non-static but Free() is static.
+	
+	So if an allocator need to support Free(), it needs to put its pointer in 
+	the header of memory block.
+
+\code
+concept Allocator {
+	static const bool kNeedFree;	//!< Whether this allocator needs to call Free().
+
+	// Allocate a memory block.
+	// \param size of the memory block in bytes.
+	// \returns pointer to the memory block.
+	void* Malloc(size_t size);
+
+	// Resize a memory block.
+	// \param originalPtr The pointer to current memory block. Null_ pointer is permitted.
+	// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+	// \param newSize the new size in bytes.
+	void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+	// Free a memory block.
+	// \param pointer to the memory block. Null_ pointer is permitted.
+	static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+	\implements Allocator
+*/
+class CrtAllocator {
+public:
+	static const bool kNeedFree = true;
+	void* Malloc(size_t size) { return malloc(size); }
+	void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
+	static void Free(void *ptr) { free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
+
+    It does not free memory blocks. And Realloc() only allocate new memory.
+
+    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+    User may also supply a buffer as the first chunk.
+
+    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+    The user-buffer is not deallocated by this allocator.
+
+    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+	\implements Allocator
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+	static const bool kNeedFree = false;	//!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+	//! Constructor with chunkSize.
+	/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+		\param baseAllocator The allocator for allocating memory chunks.
+	*/
+	MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
+		chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+	{
+		if (!baseAllocator_)
+			ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
+		AddChunk(chunk_capacity_);
+	}
+
+	//! Constructor with user-supplied buffer.
+	/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+		The user buffer will not be deallocated when this allocator is destructed.
+
+		\param buffer User supplied buffer.
+		\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+		\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+		\param baseAllocator The allocator for allocating memory chunks.
+	*/
+	MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+		chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+	{
+		RAPIDJSON_ASSERT(buffer != 0);
+		RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+		chunkHead_ = (ChunkHeader*)buffer;
+		chunkHead_->capacity = size - sizeof(ChunkHeader);
+		chunkHead_->size = 0;
+		chunkHead_->next = 0;
+	}
+
+	//! Destructor.
+	/*! This deallocates all memory chunks, excluding the user-supplied buffer.
+	*/
+	~MemoryPoolAllocator() {
+		Clear();
+		delete ownBaseAllocator_;
+	}
+
+	//! Deallocates all memory chunks, excluding the user-supplied buffer.
+	void Clear() {
+		while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
+			ChunkHeader* next = chunkHead_->next;
+			baseAllocator_->Free(chunkHead_);
+			chunkHead_ = next;
+		}
+	}
+
+	//! Computes the total capacity of allocated memory chunks.
+	/*! \return total capacity in bytes.
+	*/
+	size_t Capacity() {
+		size_t capacity = 0;
+		for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+			capacity += c->capacity;
+		return capacity;
+	}
+
+	//! Computes the memory blocks allocated.
+	/*! \return total used bytes.
+	*/
+	size_t Size() {
+		size_t size = 0;
+		for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+			size += c->size;
+		return size;
+	}
+
+	//! Allocates a memory block. (concept Allocator)
+	void* Malloc(size_t size) {
+		size = (size + 3) & ~3;	// Force aligning size to 4
+
+		if (chunkHead_->size + size > chunkHead_->capacity)
+			AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+		char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
+		RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0);	// returned buffer is aligned to 4
+		chunkHead_->size += size;
+
+		return buffer;
+	}
+
+	//! Resizes a memory block (concept Allocator)
+	void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+		if (originalPtr == 0)
+			return Malloc(newSize);
+
+		// Do not shrink if new size is smaller than original
+		if (originalSize >= newSize)
+			return originalPtr;
+
+		// Simply expand it if it is the last allocation and there is sufficient space
+		if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
+			size_t increment = newSize - originalSize;
+			increment = (increment + 3) & ~3;	// Force aligning size to 4
+			if (chunkHead_->size + increment <= chunkHead_->capacity) {
+				chunkHead_->size += increment;
+				RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0);	// returned buffer is aligned to 4
+				return originalPtr;
+			}
+		}
+
+		// Realloc process: allocate and copy memory, do not free original buffer.
+		void* newBuffer = Malloc(newSize);
+		RAPIDJSON_ASSERT(newBuffer != 0);	// Do not handle out-of-memory explicitly.
+		return memcpy(newBuffer, originalPtr, originalSize);
+	}
+
+	//! Frees a memory block (concept Allocator)
+	static void Free(void *) {} // Do nothing
+
+private:
+	//! Creates a new chunk.
+	/*! \param capacity Capacity of the chunk in bytes.
+	*/
+	void AddChunk(size_t capacity) {
+		ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);
+		chunk->capacity = capacity;
+		chunk->size = 0;
+		chunk->next = chunkHead_;
+		chunkHead_ =  chunk;
+	}
+
+	static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+	//! Chunk header for perpending to each chunk.
+	/*! Chunks are stored as a singly linked list.
+	*/
+	struct ChunkHeader {
+		size_t capacity;	//!< Capacity of the chunk in bytes (excluding the header itself).
+		size_t size;		//!< Current size of allocated memory in bytes.
+		ChunkHeader *next;	//!< Next chunk in the linked list.
+	};
+
+	ChunkHeader *chunkHead_;	//!< Head of the chunk linked-list. Only the head chunk serves allocation.
+	size_t chunk_capacity_;		//!< The minimum capacity of chunk when they are allocated.
+	char *userBuffer_;			//!< User supplied buffer.
+	BaseAllocator* baseAllocator_;	//!< base allocator for allocating memory chunks.
+	BaseAllocator* ownBaseAllocator_;	//!< base allocator created by this object.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+	\brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+	typename Ch;	//! Type of character.
+
+	//! \brief Encode a Unicode codepoint to a buffer.
+	//! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.
+	//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+	//! \returns the pointer to the next character after the encoded data.
+	static Ch* Encode(Ch *buffer, unsigned codepoint);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+	\tparam CharType Type for storing 8-bit UTF-8 data. Default is char.
+	\implements Encoding
+*/
+template<typename CharType = char>
+struct UTF8 {
+	typedef CharType Ch;
+
+	static Ch* Encode(Ch *buffer, unsigned codepoint) {
+		if (codepoint <= 0x7F) 
+			*buffer++ = codepoint & 0xFF;
+		else if (codepoint <= 0x7FF) {
+			*buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);
+			*buffer++ = 0x80 | ((codepoint & 0x3F));
+		}
+		else if (codepoint <= 0xFFFF) {
+			*buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);
+			*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+			*buffer++ = 0x80 | (codepoint & 0x3F);
+		}
+		else {
+			RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+			*buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);
+			*buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);
+			*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+			*buffer++ = 0x80 | (codepoint & 0x3F);
+		}
+		return buffer;
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+	\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+	\implements Encoding
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+	typedef CharType Ch;
+
+	static Ch* Encode(Ch* buffer, unsigned codepoint) {
+		if (codepoint <= 0xFFFF) {
+			RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+			*buffer++ = static_cast<Ch>(codepoint);
+		}
+		else {
+			RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+			unsigned v = codepoint - 0x10000;
+			*buffer++ = static_cast<Ch>((v >> 10) + 0xD800);
+			*buffer++ = (v & 0x3FF) + 0xDC00;
+		}
+		return buffer;
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding. 
+/*! http://en.wikipedia.org/wiki/UTF-32
+	\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+	\implements Encoding
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+	typedef CharType Ch;
+
+	static Ch *Encode(Ch* buffer, unsigned codepoint) {
+		RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+		*buffer++ = codepoint;
+		return buffer;
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//  Stream
+
+/*! \class rapidjson::Stream
+	\brief Concept for reading and writing characters.
+
+	For read-only stream, no need to implement PutBegin(), Put() and PutEnd().
+
+	For write-only stream, only need to implement Put().
+
+\code
+concept Stream {
+	typename Ch;	//!< Character type of the stream.
+
+	//! Read the current character from stream without moving the read cursor.
+	Ch Peek() const;
+
+	//! Read the current character from stream and moving the read cursor to next character.
+	Ch Take();
+
+	//! Get the current read cursor.
+	//! \return Number of characters read from start.
+	size_t Tell();
+
+	//! Begin writing operation at the current read pointer.
+	//! \return The begin writer pointer.
+	Ch* PutBegin();
+
+	//! Write a character.
+	void Put(Ch c);
+
+	//! End the writing operation.
+	//! \param begin The begin write pointer returned by PutBegin().
+	//! \return Number of characters written.
+	size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+	for (size_t i = 0; i < n; i++)
+		stream.Put(c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \implements Stream
+*/
+template <typename Encoding>
+struct GenericStringStream {
+	typedef typename Encoding::Ch Ch;
+
+	GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+	Ch Peek() const { return *src_; }
+	Ch Take() { return *src_++; }
+	size_t Tell() const { return src_ - head_; }
+
+	Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+	void Put(Ch) { RAPIDJSON_ASSERT(false); }
+	size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+	const Ch* src_;		//!< Current read position.
+	const Ch* head_;	//!< Original head of the string.
+};
+
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+	\implements Stream
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+	typedef typename Encoding::Ch Ch;
+
+	GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+	// Read
+	Ch Peek() { return *src_; }
+	Ch Take() { return *src_++; }
+	size_t Tell() { return src_ - head_; }
+
+	// Write
+	Ch* PutBegin() { return dst_ = src_; }
+	void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+	size_t PutEnd(Ch* begin) { return dst_ - begin; }
+
+	Ch* src_;
+	Ch* dst_;
+	Ch* head_;
+};
+
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+//! Type of JSON value
+enum Type {
+	kNull_Type = 0,		//!< null
+	kFalseType = 1,		//!< false
+	kTrueType = 2,		//!< true
+	kObjectType = 3,	//!< object
+	kArrayType = 4,		//!< array 
+	kStringType = 5,	//!< string
+	kNumberType = 6,	//!< number
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/include/cereal/external/rapidjson/reader.h b/include/cereal/external/rapidjson/reader.h
new file mode 100644
index 0000000..a12149b
--- /dev/null
+++ b/include/cereal/external/rapidjson/reader.h
@@ -0,0 +1,749 @@
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+// Copyright (c) 2011 Milo Yip (miloyip at gmail.com)
+// Version 0.1
+
+#include "rapidjson.h"
+#include "internal/pow10.h"
+#include "internal/stack.h"
+#include <csetjmp>
+
+// All part of denormalized parsing
+#include <limits> // for numeric_limits
+#include <cmath> // for fpclassify
+#include <sstream>
+
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#pragma warning(disable : 4702) // uncreachable code
+#endif
+
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(msg, offset) \
+	RAPIDJSON_MULTILINEMACRO_BEGIN \
+	parseError_ = msg; \
+	errorOffset_ = offset; \
+	longjmp(jmpbuf_, 1); \
+	RAPIDJSON_MULTILINEMACRO_END
+#endif
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+//! Combination of parseFlags
+enum ParseFlag {
+	kParseDefaultFlags = 0,			//!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
+	kParseInsituFlag = 1			//!< In-situ(destructive) parsing.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*!	\class rapidjson::Handler
+	\brief Concept for receiving events from GenericReader upon parsing.
+\code
+concept Handler {
+	typename Ch;
+
+	void Null_();
+	void Bool_(bool b);
+	void Int(int i);
+	void Uint(unsigned i);
+	void Int64(int64_t i);
+	void Uint64(uint64_t i);
+	void Double(double d);
+	void String(const Ch* str, SizeType length, bool copy);
+	void StartObject();
+	void EndObject(SizeType memberCount);
+	void StartArray();
+	void EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+	\implements Handler
+*/
+template<typename Encoding = UTF8<> >
+struct BaseReaderHandler {
+	typedef typename Encoding::Ch Ch;
+
+	void Default() {}
+	void Null_() { Default(); }
+	void Bool_(bool) { Default(); }
+	void Int(int) { Default(); }
+	void Uint(unsigned) { Default(); }
+	void Int64(int64_t) { Default(); }
+	void Uint64(uint64_t) { Default(); }
+	void Double(double) { Default(); }
+	void String(const Ch*, SizeType, bool) { Default(); }
+	void StartObject() { Default(); }
+	void EndObject(SizeType) { Default(); }
+	void StartArray() { Default(); }
+	void EndArray(SizeType) { Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param stream A input stream for skipping white spaces.
+	\note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename Stream>
+void SkipWhitespace(Stream& stream) {
+	Stream s = stream;	// Use a local copy for optimization
+	while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+		s.Take();
+	stream = s;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+	static const char whitespace[16] = " \n\r\t";
+	__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
+
+	for (;;) {
+		__m128i s = _mm_loadu_si128((const __m128i *)p);
+		unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+		if (r == 0)	// all 16 characters are whitespace
+			p += 16;
+		else {		// some of characters may be non-whitespace
+#ifdef _MSC_VER		// Find the index of first non-whitespace
+			unsigned long offset;
+			if (_BitScanForward(&offset, r))
+				return p + offset;
+#else
+			if (r != 0)
+				return p + __builtin_ffs(r) - 1;
+#endif
+		}
+	}
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+	static const char whitespaces[4][17] = {
+		"                ",
+		"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
+		"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
+		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
+
+	__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
+	__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
+	__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
+	__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
+
+	for (;;) {
+		__m128i s = _mm_loadu_si128((const __m128i *)p);
+		__m128i x = _mm_cmpeq_epi8(s, w0);
+		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+		x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+		unsigned short r = ~_mm_movemask_epi8(x);
+		if (r == 0)	// all 16 characters are whitespace
+			p += 16;
+		else {		// some of characters may be non-whitespace
+#ifdef _MSC_VER		// Find the index of first non-whitespace
+			unsigned long offset;
+			if (_BitScanForward(&offset, r))
+				return p + offset;
+#else
+			if (r != 0)
+				return p + __builtin_ffs(r) - 1;
+#endif
+		}
+	}
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& stream) {
+	stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& stream) {
+	stream.src_ = SkipWhitespace_SIMD(stream.src_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+    object implementing Handler concept.
+
+    It needs to allocate a stack for storing a single decoded string during
+    non-destructive parsing.
+
+    For in-situ parsing, the decoded string is directly written to the source
+    text string, no temporary buffer is required.
+
+    A GenericReader object can be reused for parsing multiple JSON text.
+
+    \tparam Encoding Encoding of both the stream and the parse output.
+    \tparam Allocator Allocator type for stack.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericReader {
+public:
+	typedef typename Encoding::Ch Ch;
+
+	//! Constructor.
+	/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+		\param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)
+	*/
+	GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+	//! Parse JSON text.
+	/*! \tparam parseFlags Combination of ParseFlag.
+		 \tparam Stream Type of input stream.
+		 \tparam Handler Type of handler which must implement Handler concept.
+		 \param stream Input stream to be parsed.
+		 \param handler The handler to receive events.
+		 \return Whether the parsing is successful.
+	*/
+	template <unsigned parseFlags, typename Stream, typename Handler>
+	bool Parse(Stream& stream, Handler& handler) {
+		parseError_ = 0;
+		errorOffset_ = 0;
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+		if (setjmp(jmpbuf_)) {
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+			stack_.Clear();
+			return false;
+		}
+
+		SkipWhitespace(stream);
+
+		if (stream.Peek() == '\0')
+			RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
+		else {
+			switch (stream.Peek()) {
+				case '{': ParseObject<parseFlags>(stream, handler); break;
+				case '[': ParseArray<parseFlags>(stream, handler); break;
+				default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell());
+			}
+			SkipWhitespace(stream);
+
+			if (stream.Peek() != '\0' && stream.Peek() != static_cast<Ch>(std::char_traits<Ch>::eof()))
+				RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
+		}
+
+		return true;
+	}
+
+	bool HasParseError() const { return parseError_ != 0; }
+	const char* GetParseError() const { return parseError_; }
+	size_t GetErrorOffset() const { return errorOffset_; }
+
+private:
+	// Parse object: { string : value, ... }
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseObject(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == '{');
+		stream.Take();	// Skip '{'
+		handler.StartObject();
+		SkipWhitespace(stream);
+
+		if (stream.Peek() == '}') {
+			stream.Take();
+			handler.EndObject(0);	// empty object
+			return;
+		}
+
+		for (SizeType memberCount = 0;;) {
+			if (stream.Peek() != '"') {
+				RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
+				break;
+			}
+
+			ParseString<parseFlags>(stream, handler);
+			SkipWhitespace(stream);
+
+			if (stream.Take() != ':') {
+				RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
+				break;
+			}
+			SkipWhitespace(stream);
+
+			ParseValue<parseFlags>(stream, handler);
+			SkipWhitespace(stream);
+
+			++memberCount;
+
+			switch(stream.Take()) {
+				case ',': SkipWhitespace(stream); break;
+				case '}': handler.EndObject(memberCount); return;
+				default:  RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
+			}
+		}
+	}
+
+	// Parse array: [ value, ... ]
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseArray(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == '[');
+		stream.Take();	// Skip '['
+		handler.StartArray();
+		SkipWhitespace(stream);
+
+		if (stream.Peek() == ']') {
+			stream.Take();
+			handler.EndArray(0); // empty array
+			return;
+		}
+
+		for (SizeType elementCount = 0;;) {
+			ParseValue<parseFlags>(stream, handler);
+			++elementCount;
+			SkipWhitespace(stream);
+
+			switch (stream.Take()) {
+				case ',': SkipWhitespace(stream); break;
+				case ']': handler.EndArray(elementCount); return;
+				default:  RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
+			}
+		}
+	}
+
+  // Parses for null or NaN
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseNaNNull_(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == 'n');
+		stream.Take();
+
+    if( stream.Peek() == 'a' && stream.Take() == 'a' && stream.Take() == 'n' )
+      handler.Double( std::numeric_limits<double>::quiet_NaN() );
+    else if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
+			handler.Null_();
+    else
+			RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+	}
+
+  // Parses for infinity
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseInfinity(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == 'i');
+		stream.Take();
+
+    if (stream.Take() == 'n' && stream.Take() == 'f')
+      handler.Double( std::numeric_limits<double>::infinity() );
+    else
+			RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+	}
+
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseTrue(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == 't');
+		stream.Take();
+
+		if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
+			handler.Bool_(true);
+		else
+			RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
+	}
+
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseFalse(Stream& stream, Handler& handler) {
+		RAPIDJSON_ASSERT(stream.Peek() == 'f');
+		stream.Take();
+
+		if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
+			handler.Bool_(false);
+		else
+			RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+	}
+
+	// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+	template<typename Stream>
+	unsigned ParseHex4(Stream& stream) {
+		Stream s = stream;	// Use a local copy for optimization
+		unsigned codepoint = 0;
+		for (int i = 0; i < 4; i++) {
+			Ch c = s.Take();
+			codepoint <<= 4;
+			codepoint += c;
+			if (c >= '0' && c <= '9')
+				codepoint -= '0';
+			else if (c >= 'A' && c <= 'F')
+				codepoint -= 'A' - 10;
+			else if (c >= 'a' && c <= 'f')
+				codepoint -= 'a' - 10;
+			else
+				RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
+		}
+		stream = s; // Restore stream
+		return codepoint;
+	}
+
+  // cereal Temporary until constexpr support is added in RTM
+#ifdef _MSC_VER
+  template <class Ch>
+  bool characterOk( Ch c )
+  {
+    return c < 256;
+  }
+
+  template <>
+  bool characterOk<char>( char )
+  {
+    return true;
+  }
+
+#else
+  // As part of a fix for GCC 4.7
+  template <class T>
+  static constexpr int to_int( T t ){ return t; }
+
+  template<class Ch>
+  typename std::enable_if < to_int(std::numeric_limits<Ch>::max()) < to_int(256), bool>::type
+    characterOk( Ch )
+  {
+    return true;
+  }
+
+  template<class Ch>
+  typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
+    characterOk(Ch c)
+  { return c < 256; }
+#endif
+
+	// Parse string, handling the prefix and suffix double quotes and escaping.
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseString(Stream& stream, Handler& handler) {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+		static const Ch escape[256] = {
+			Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+			Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+			0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+			0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+			Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+		};
+#undef Z16
+
+		Stream s = stream;	// Use a local copy for optimization
+		RAPIDJSON_ASSERT(s.Peek() == '\"');
+		s.Take();	// Skip '\"'
+		Ch *head;
+		SizeType len;
+		if (parseFlags & kParseInsituFlag)
+			head = s.PutBegin();
+		else
+			len = 0;
+
+#define RAPIDJSON_PUT(x) \
+	do { \
+		if (parseFlags & kParseInsituFlag) \
+			s.Put(x); \
+		else { \
+			*stack_.template Push<Ch>() = x; \
+			++len; \
+		} \
+	} while(false)
+
+		for (;;) {
+			Ch c = s.Take();
+			if (c == '\\') {	// Escape
+				Ch e = s.Take();
+				if ((sizeof(Ch) == 1 || characterOk(e)) && escape[(unsigned char)e])
+					RAPIDJSON_PUT(escape[(unsigned char)e]);
+				else if (e == 'u') {	// Unicode
+					unsigned codepoint = ParseHex4(s);
+					if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
+						if (s.Take() != '\\' || s.Take() != 'u') {
+							RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
+							return;
+						}
+						unsigned codepoint2 = ParseHex4(s);
+						if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
+							RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
+							return;
+						}
+						codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+					}
+
+					Ch buffer[4];
+					SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
+
+					if (parseFlags & kParseInsituFlag)
+						for (SizeType i = 0; i < count; i++)
+							s.Put(buffer[i]);
+					else {
+						memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
+						len += count;
+					}
+				}
+				else {
+					RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
+					return;
+				}
+			}
+			else if (c == '"') {	// Closing double quote
+				if (parseFlags & kParseInsituFlag) {
+					size_t length = s.PutEnd(head);
+					RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+					RAPIDJSON_PUT('\0');	// null-terminate the string
+					handler.String(head, SizeType(length), false);
+				}
+				else {
+					RAPIDJSON_PUT('\0');
+					handler.String(stack_.template Pop<Ch>(len), len - 1, true);
+				}
+				stream = s;	// restore stream
+				return;
+			}
+			else if (c == '\0') {
+				RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
+				return;
+			}
+			else if ((unsigned)c < 0x20) {	// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+				RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
+				return;
+			}
+			else
+				RAPIDJSON_PUT(c);	// Normal character, just copy
+		}
+#undef RAPIDJSON_PUT
+	}
+
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseNumber(Stream& stream, Handler& handler) {
+		Stream s = stream; // Local copy for optimization
+
+		// Parse minus
+		bool minus = false;
+		if (s.Peek() == '-') {
+			minus = true;
+			s.Take();
+		}
+
+		// Parse int: zero / ( digit1-9 *DIGIT )
+		unsigned i;
+		bool try64bit = false;
+		if (s.Peek() == '0') {
+			i = 0;
+			s.Take();
+		}
+		else if (s.Peek() >= '1' && s.Peek() <= '9') {
+			i = s.Take() - '0';
+
+			if (minus)
+				while (s.Peek() >= '0' && s.Peek() <= '9') {
+					if (i >= 214748364) { // 2^31 = 2147483648
+						if (i != 214748364 || s.Peek() > '8') {
+							try64bit = true;
+							break;
+						}
+					}
+					i = i * 10 + (s.Take() - '0');
+				}
+			else
+				while (s.Peek() >= '0' && s.Peek() <= '9') {
+					if (i >= 429496729) { // 2^32 - 1 = 4294967295
+						if (i != 429496729 || s.Peek() > '5') {
+							try64bit = true;
+							break;
+						}
+					}
+					i = i * 10 + (s.Take() - '0');
+				}
+		}
+		else {
+			RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
+			return;
+		}
+
+		// Parse 64bit int
+		uint64_t i64 = 0;
+		bool useDouble = false;
+		if (try64bit) {
+			i64 = i;
+			if (minus)
+				while (s.Peek() >= '0' && s.Peek() <= '9') {
+					if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
+						if (i64 != 922337203685477580uLL || s.Peek() > '8') {
+							useDouble = true;
+							break;
+						}
+					i64 = i64 * 10 + (s.Take() - '0');
+				}
+			else
+				while (s.Peek() >= '0' && s.Peek() <= '9') {
+					if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
+						if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
+							useDouble = true;
+							break;
+						}
+					i64 = i64 * 10 + (s.Take() - '0');
+				}
+		}
+
+		// Force double for big integer
+		double d = 0.0;
+		if (useDouble) {
+			d = (double)i64;
+			while (s.Peek() >= '0' && s.Peek() <= '9') {
+				if (d >= 1E307) {
+					RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+					return;
+				}
+				d = d * 10 + (s.Take() - '0');
+			}
+		}
+
+		// Parse frac = decimal-point 1*DIGIT
+		int expFrac = 0;
+		if (s.Peek() == '.') {
+			if (!useDouble) {
+				d = try64bit ? (double)i64 : (double)i;
+				useDouble = true;
+			}
+			s.Take();
+
+			if (s.Peek() >= '0' && s.Peek() <= '9') {
+				d = d * 10 + (s.Take() - '0');
+				--expFrac;
+			}
+			else {
+				RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
+				return;
+			}
+
+			while (s.Peek() >= '0' && s.Peek() <= '9') {
+				if (expFrac > -20) {
+					d = d * 10 + (s.Peek() - '0');
+					--expFrac;
+				}
+				s.Take();
+			}
+		}
+
+		// Parse exp = e [ minus / plus ] 1*DIGIT
+		int exp = 0;
+		if (s.Peek() == 'e' || s.Peek() == 'E') {
+			if (!useDouble) {
+				d = try64bit ? (double)i64 : (double)i;
+				useDouble = true;
+			}
+			s.Take();
+
+			bool expMinus = false;
+			if (s.Peek() == '+')
+				s.Take();
+			else if (s.Peek() == '-') {
+				s.Take();
+				expMinus = true;
+			}
+
+			if (s.Peek() >= '0' && s.Peek() <= '9') {
+				exp = s.Take() - '0';
+				while (s.Peek() >= '0' && s.Peek() <= '9') {
+					exp = exp * 10 + (s.Take() - '0');
+					if (exp > 308) {
+            // Attempt denormalized construction
+            std::stringstream ss;
+            ss.precision( std::numeric_limits<double>::max_digits10 );
+            ss << d * internal::Pow10(expFrac) << 'e' << (expMinus ? '-' : '+') << exp;
+
+            double dd;
+            ss >> dd;
+
+            if( std::fpclassify( dd ) == FP_SUBNORMAL )
+              handler.Double( dd );
+            else
+						  RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+
+						return;
+					}
+				}
+			}
+			else {
+				RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
+				return;
+			}
+
+			if (expMinus)
+				exp = -exp;
+		}
+
+		// Finish parsing, call event according to the type of number.
+		if (useDouble) {
+			d *= internal::Pow10(exp + expFrac);
+			handler.Double(minus ? -d : d);
+		}
+		else {
+			if (try64bit) {
+				if (minus)
+					handler.Int64(-(int64_t)i64);
+				else
+					handler.Uint64(i64);
+			}
+			else {
+				if (minus)
+					handler.Int(-(int)i);
+				else
+					handler.Uint(i);
+			}
+		}
+
+		stream = s; // restore stream
+	}
+
+	// Parse any JSON value
+	template<unsigned parseFlags, typename Stream, typename Handler>
+	void ParseValue(Stream& stream, Handler& handler) {
+		switch (stream.Peek()) {
+			case 'n': ParseNaNNull_  <parseFlags>(stream, handler); break;
+			case 'i': ParseInfinity  <parseFlags>(stream, handler); break;
+			case 't': ParseTrue      <parseFlags>(stream, handler); break;
+			case 'f': ParseFalse     <parseFlags>(stream, handler); break;
+			case '"': ParseString    <parseFlags>(stream, handler); break;
+			case '{': ParseObject    <parseFlags>(stream, handler); break;
+			case '[': ParseArray     <parseFlags>(stream, handler); break;
+			default : ParseNumber    <parseFlags>(stream, handler);
+		}
+	}
+
+	static const size_t kDefaultStackCapacity = 256;	//!< Default stack capacity in bytes for storing a single decoded string.
+	internal::Stack<Allocator> stack_;	//!< A stack for storing decoded string temporarily during non-destructive parsing.
+	jmp_buf jmpbuf_;					//!< setjmp buffer for fast exit from nested parsing function calls.
+	const char* parseError_;
+	size_t errorOffset_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<> > Reader;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/include/cereal/external/rapidjson/stringbuffer.h b/include/cereal/external/rapidjson/stringbuffer.h
new file mode 100644
index 0000000..34cff58
--- /dev/null
+++ b/include/cereal/external/rapidjson/stringbuffer.h
@@ -0,0 +1,49 @@
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+
+namespace rapidjson {
+
+//! Represents an in-memory output stream.
+/*!
+	\tparam Encoding Encoding of the stream.
+	\tparam Allocator type for allocating memory buffer.
+	\implements Stream
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+struct GenericStringBuffer {
+	typedef typename Encoding::Ch Ch;
+
+	GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+	void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+
+	void Clear() { stack_.Clear(); }
+
+	const char* GetString() const {
+		// Push and pop a null terminator. This is safe.
+		*stack_.template Push<Ch>() = '\0';
+		stack_.template Pop<Ch>(1);
+
+		return stack_.template Bottom<Ch>();
+	}
+
+	size_t Size() const { return stack_.GetSize(); }
+
+	static const size_t kDefaultCapacity = 256;
+	mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+	memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/include/cereal/external/rapidjson/writer.h b/include/cereal/external/rapidjson/writer.h
new file mode 100644
index 0000000..ad9776a
--- /dev/null
+++ b/include/cereal/external/rapidjson/writer.h
@@ -0,0 +1,330 @@
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include <cstdio>	// snprintf() or _sprintf_s()
+#include <new>		// placement new
+#include <limits>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+	It generates JSON text by events to an output stream.
+
+	User may programmatically calls the functions of a writer to generate JSON text.
+
+	On the other side, a writer can also be passed to objects that generates events,
+
+	for example Reader::Parse() and Document::Accept().
+
+	\tparam Stream Type of ouptut stream.
+	\tparam Encoding Encoding of both source strings and output.
+	\implements Handler
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class Writer {
+public:
+	typedef typename Encoding::Ch Ch;
+
+	Writer(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+		stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level))
+  {
+#if _MSC_VER
+    (void) sprintf_s(double_format, sizeof(double_format), "%%0.%dg", precision);
+    (void) sprintf_s( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
+#else
+    (void) snprintf(double_format, sizeof(double_format), "%%0.%dg", precision);
+    (void) snprintf( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
+#endif
+
+  }
+
+protected:
+  char double_format[32];
+  char long_double_format[32];
+public:
+
+	//@name Implementation of Handler
+	//@{
+
+	Writer& Null_()                          { Prefix(kNull_Type);   WriteNull_();			return *this;             }
+	Writer& Bool_(bool b)                    { Prefix(b ? kTrueType : kFalseType); WriteBool_(b); return *this; }
+	Writer& Int(int i)                      { Prefix(kNumberType); WriteInt(i);			return *this;             }
+	Writer& Uint(unsigned u)                { Prefix(kNumberType); WriteUint(u);		return *this;             }
+	Writer& Int64(int64_t i64)              { Prefix(kNumberType); WriteInt64(i64);		return *this;           }
+	Writer& Uint64(uint64_t u64)            { Prefix(kNumberType); WriteUint64(u64);	return *this;           }
+	Writer& Double(double d)                { Prefix(kNumberType); WriteDouble(d);		return *this;           }
+	Writer& LongDouble(long double d)       { Prefix(kNumberType); WriteLongDouble(d);		return *this;       }
+	Writer& LongLong(long long d)           { Prefix(kNumberType); WriteLongLong(d);		return *this;         }
+	Writer& ULongLong(unsigned long long d) { Prefix(kNumberType); WriteULongLong(d);		return *this;         }
+
+	Writer& String(const Ch* str, SizeType length, bool copy = false) {
+		(void)copy;
+		Prefix(kStringType);
+		WriteString(str, length);
+		return *this;
+	}
+
+	Writer& StartObject() {
+		Prefix(kObjectType);
+		new (level_stack_.template Push<Level>()) Level(false);
+		WriteStartObject();
+		return *this;
+	}
+
+	Writer& EndObject(SizeType memberCount = 0) {
+		(void)memberCount;
+		RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+		RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+		level_stack_.template Pop<Level>(1);
+		WriteEndObject();
+		return *this;
+	}
+
+	Writer& StartArray() {
+		Prefix(kArrayType);
+		new (level_stack_.template Push<Level>()) Level(true);
+		WriteStartArray();
+		return *this;
+	}
+
+	Writer& EndArray(SizeType elementCount = 0) {
+		(void)elementCount;
+		RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+		RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+		level_stack_.template Pop<Level>(1);
+		WriteEndArray();
+		return *this;
+	}
+	//@}
+
+	//! Simpler but slower overload.
+	Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+	//! Information for each nested level
+	struct Level {
+		Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
+		bool inArray;		//!< true if in array, otherwise in object
+		size_t valueCount;	//!< number of values in this level
+	};
+
+	static const size_t kDefaultLevelDepth = 32;
+
+	void WriteNull_()  {
+		stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
+	}
+
+	void WriteBool_(bool b)  {
+		if (b) {
+			stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
+		}
+		else {
+			stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
+		}
+	}
+
+	void WriteInt(int i) {
+		if (i < 0) {
+			stream_.Put('-');
+			i = -i;
+		}
+		WriteUint((unsigned)i);
+	}
+
+	void WriteUint(unsigned u) {
+		char buffer[10];
+		char *p = buffer;
+		do {
+			*p++ = (u % 10) + '0';
+			u /= 10;
+		} while (u > 0);
+
+		do {
+			--p;
+			stream_.Put(*p);
+		} while (p != buffer);
+	}
+
+	void WriteInt64(int64_t i64) {
+		if (i64 < 0) {
+			stream_.Put('-');
+			i64 = -i64;
+		}
+		WriteUint64((uint64_t)i64);
+	}
+
+	void WriteUint64(uint64_t u64) {
+		char buffer[20];
+		char *p = buffer;
+		do {
+			*p++ = char(u64 % 10) + '0';
+			u64 /= 10;
+		} while (u64 > 0);
+
+		do {
+			--p;
+			stream_.Put(*p);
+		} while (p != buffer);
+	}
+
+  // cereal Temporary until constexpr support is added in RTM
+#ifdef _MSC_VER
+  template <class Ch>
+  bool characterOk( Ch c )
+  {
+    return c < 256;
+  }
+
+  template <>
+  bool characterOk<char>( char )
+  {
+    return true;
+  }
+
+#else
+  // As part of a fix for GCC 4.7
+  template <class T>
+  static constexpr int to_int( T t ){ return t; }
+
+  template<class Ch>
+  typename std::enable_if < to_int(std::numeric_limits<Ch>::max()) < to_int(256), bool>::type
+    characterOk( Ch )
+  {
+    return true;
+  }
+
+  template<class Ch>
+  typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
+    characterOk(Ch c)
+  { return c < 256; }
+#endif
+
+	//! \todo Optimization with custom double-to-string converter.
+	void WriteDouble(double d) {
+		char buffer[100];
+#if _MSC_VER
+		int ret = sprintf_s(buffer, sizeof(buffer), double_format, d);
+#else
+		int ret = snprintf(buffer, sizeof(buffer), double_format, d);
+#endif
+		RAPIDJSON_ASSERT(ret >= 1);
+		for (int i = 0; i < ret; i++)
+			stream_.Put(buffer[i]);
+	}
+
+	void WriteLongDouble(long double d) {
+		char buffer[256];
+#if _MSC_VER
+		int ret = sprintf_s(buffer, sizeof(buffer), long_double_format, d);
+#else
+		int ret = snprintf(buffer, sizeof(buffer), long_double_format, d);
+#endif
+		RAPIDJSON_ASSERT(ret >= 1);
+		for (int i = 0; i < ret; i++)
+			stream_.Put(buffer[i]);
+	}
+
+	void WriteLongLong(long long d) {
+		char buffer[256];
+#if _MSC_VER
+		int ret = sprintf_s(buffer, sizeof(buffer), "%lld", d);
+#else
+		int ret = snprintf(buffer, sizeof(buffer), "%lld", d);
+#endif
+		RAPIDJSON_ASSERT(ret >= 1);
+		for (int i = 0; i < ret; i++)
+			stream_.Put(buffer[i]);
+	}
+
+	void WriteULongLong(unsigned long long d) {
+		char buffer[256];
+#if _MSC_VER
+		int ret = sprintf_s(buffer, sizeof(buffer), "%llu", d);
+#else
+		int ret = snprintf(buffer, sizeof(buffer), "%llu", d);
+#endif
+		RAPIDJSON_ASSERT(ret >= 1);
+		for (int i = 0; i < ret; i++)
+			stream_.Put(buffer[i]);
+	}
+
+	void WriteString(const Ch* str, SizeType length)  {
+		static const char hexDigits[] = "0123456789ABCDEF";
+		static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+			//0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+			'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+			'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+			  0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
+			Z16, Z16,																		// 30~4F
+			  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
+			Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16								// 60~FF
+#undef Z16
+		};
+
+		stream_.Put('\"');
+		for (const Ch* p = str; p != str + length; ++p) {
+			if ((sizeof(Ch) == 1 || characterOk(*p)) && escape[(unsigned char)*p])  {
+			//if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p])  {
+				stream_.Put('\\');
+				stream_.Put(escape[(unsigned char)*p]);
+				if (escape[(unsigned char)*p] == 'u') {
+					stream_.Put('0');
+					stream_.Put('0');
+					stream_.Put(hexDigits[(*p) >> 4]);
+					stream_.Put(hexDigits[(*p) & 0xF]);
+				}
+			}
+			else
+				stream_.Put(*p);
+		}
+		stream_.Put('\"');
+	}
+
+	void WriteStartObject()	{ stream_.Put('{'); }
+	void WriteEndObject()	{ stream_.Put('}'); }
+	void WriteStartArray()	{ stream_.Put('['); }
+	void WriteEndArray()	{ stream_.Put(']'); }
+
+	void Prefix(Type type) {
+		(void)type;
+		if (level_stack_.GetSize() != 0) { // this value is not at root
+			Level* level = level_stack_.template Top<Level>();
+			if (level->valueCount > 0) {
+				if (level->inArray)
+					stream_.Put(','); // add comma if it is not the first element in array
+				else  // in object
+					stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
+			}
+			if (!level->inArray && level->valueCount % 2 == 0)
+				RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+			level->valueCount++;
+		}
+		else
+			RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+	}
+
+	Stream& stream_;
+	internal::Stack<Allocator> level_stack_;
+
+private:
+	// Prohibit assignment for VC C4512 warning
+	Writer& operator=(const Writer& w);
+};
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/include/cereal/external/rapidxml/license.txt b/include/cereal/external/rapidxml/license.txt
new file mode 100644
index 0000000..0095bc7
--- /dev/null
+++ b/include/cereal/external/rapidxml/license.txt
@@ -0,0 +1,52 @@
+Use of this software is granted under one of the following two licenses,
+to be chosen freely by the user.
+
+1. Boost Software License - Version 1.0 - August 17th, 2003
+===============================================================================
+
+Copyright (c) 2006, 2007 Marcin Kalicinski
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+2. The MIT License
+===============================================================================
+
+Copyright (c) 2006, 2007 Marcin Kalicinski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy 
+of this software and associated documentation files (the "Software"), to deal 
+in the Software without restriction, including without limitation the rights 
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
+of the Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
+IN THE SOFTWARE.
diff --git a/include/cereal/external/rapidxml/manual.html b/include/cereal/external/rapidxml/manual.html
new file mode 100644
index 0000000..4e6a5f1
--- /dev/null
+++ b/include/cereal/external/rapidxml/manual.html
@@ -0,0 +1,406 @@
+<html><head><style type="text/css">
+
+          body
+          {
+          font-family: sans-serif;
+          font-size: 90%;
+          margin: 8pt 8pt 8pt 8pt;
+          text-align: justify;
+          background-color: White;
+          }
+
+          h1 { font-weight: bold; text-align: left;  }
+          h2 { font: 140% sans-serif; font-weight: bold; text-align: left;  }
+          h3 { font: 120% sans-serif; font-weight: bold; text-align: left;  }
+          h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left;  }
+          h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left;  }
+          h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left;  }
+
+          code
+          {
+          font-family: "Courier New", Courier, mono;
+          }
+
+          pre
+          {
+          border-top: gray 0.5pt solid;
+          border-right: gray 0.5pt solid;
+          border-left: gray 0.5pt solid;
+          border-bottom: gray 0.5pt solid;
+          padding-top: 2pt;
+          padding-right: 2pt;
+          padding-left: 2pt;
+          padding-bottom: 2pt;
+          display: block;
+          font-family: "courier new", courier, mono;
+          background-color: #eeeeee;
+          }
+
+          a
+          {
+          color: #000080;
+          text-decoration: none;
+          }
+
+          a:hover
+          {
+          text-decoration: underline;
+          }
+
+          .reference-header
+          {
+          border-top: gray 0.5pt solid;
+          border-right: gray 0.5pt solid;
+          border-left: gray 0.5pt solid;
+          border-bottom: gray 0.5pt solid;
+          padding-top: 2pt;
+          padding-right: 2pt;
+          padding-left: 2pt;
+          padding-bottom: 2pt;
+          background-color: #dedede;
+          }
+
+          .parameter-name
+          {
+          font-style: italic;
+          }
+
+          .indented
+          {
+          margin-left: 0.5cm;
+          }
+
+          a.toc1
+          {
+          margin-left: 0.0cm;
+          }
+
+          a.toc2
+          {
+          margin-left: 0.75cm;
+          }
+
+          a.toc3
+          {
+          margin-left: 1.5cm;
+          }
+
+        </style></head><body><h1>RAPIDXML Manual</h1><h3>Version 1.13</h3><detaileddescription xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><para><i>Copyright (C) 2006, 2009 Marcin Kalicinski</i><br/><i>See accompanying file <a href="license.txt">license.txt</a> for license information.</i><hr/><h2 level="2">Table of Contents</h2></para><para><toc><toc-contents><a href="#namespacerapidxml_1what_is_rapidxml" class="toc1">1. What is RapidXml?</a><br/><a href="#namespacerapidxml_1d [...]
+ Entire parser is contained in a single header file, so no building or linking is neccesary. To use it you just need to copy <code>rapidxml.hpp</code> file to a convenient place (such as your project directory), and include it where needed. You may also want to use printing functions contained in header <code>rapidxml_print.hpp</code>.</para><sect2><h3 id="namespacerapidxml_1dependencies_and_compatibility">1.1 Dependencies And Compatibility</h3><para>RapidXml has <i>no dependencies</i> o [...]
+ Note that RapidXml performs no decoding - strings returned by name() and value() functions will contain text encoded using the same encoding as source file. Rapidxml understands and expands the following character references: <code>&apos; &amp; &quot; &lt; &gt; &#...;</code> Other character references are not expanded.</para></sect2><sect2><h3 id="namespacerapidxml_1error_handling">1.3 Error Handling</h3><para>By default, RapidXml uses C++ exceptions to report er [...]
+ Another unit test puts RapidXml head-to-head with another, well estabilished XML parser, and verifies that their outputs match across a wide variety of small and large documents. <br/><br/>
+ Yet another test feeds RapidXml with over 1000 test files from W3C compliance suite, and verifies that correct results are obtained. There are also additional tests that verify each API function separately, and test that various parsing modes work as expected.</para></sect2><sect2><h3 id="namespacerapidxml_1acknowledgements">1.8 Acknowledgements</h3><para>I would like to thank Arseny Kapoulkine for his work on <a href="http://code.google.com/p/pugixml">pugixml</a>, which was an inspirat [...]
+xml_document<> doc;    // character type defaults to char
+doc.parse<0>(text);    // 0 means default parse flags
+</pre><code>doc</code> object is now a root of DOM tree containing representation of the parsed XML. Because all RapidXml interface is contained inside namespace <code>rapidxml</code>, users must either bring contents of this namespace into scope, or fully qualify all the names. Class <a href="#classrapidxml_1_1xml__document" kindref="compound">xml_document</a> represents a root of the DOM hierarchy. By means of public inheritance, it is also an <a href="#classrapidxml_1_1xml__node" kind [...]
+xml_node<> *node = doc.first_node("foobar");
+cout << "Node foobar has value " << node->value() << "\n";
+for (xml_attribute<> *attr = node->first_attribute();
+     attr; attr = attr->next_attribute())
+{
+    cout << "Node foobar has attribute " << attr->name() << " ";
+    cout << "with value " << attr->value() << "\n";
+}
+</pre></para></sect2><sect2><h3 id="namespacerapidxml_1modifying_dom_tree">2.3 Modifying The DOM Tree</h3><para>DOM tree produced by the parser is fully modifiable. Nodes and attributes can be added/removed, and their contents changed. The below example creates a HTML document, whose sole contents is a link to google.com website: <pre>xml_document<> doc;
+xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
+doc.append_node(node);
+xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
+node->append_attribute(attr);
+</pre> One quirk is that nodes and attributes <i>do not own</i> the text of their names and values. This is because normally they only store pointers to the source text. So, when assigning a new name or value to the node, care must be taken to ensure proper lifetime of the string. The easiest way to achieve it is to allocate the string from the <a href="#classrapidxml_1_1xml__document" kindref="compound">xml_document</a> memory pool. In the above example this is not necessary, because we [...]
+char *node_name = doc.allocate_string(name);        // Allocate string and copy name into it
+xml_node<> *node = doc.allocate_node(node_element, node_name);  // Set node name to node_name
+</pre> Check <a href="#namespacerapidxml_1reference" kindref="member">Reference</a>  section for description of the entire interface.</para></sect2><sect2><h3 id="namespacerapidxml_1printing">2.4 Printing XML</h3><para>You can print <code><a href="#classrapidxml_1_1xml__document" kindref="compound">xml_document</a></code> and <code><a href="#classrapidxml_1_1xml__node" kindref="compound">xml_node</a></code> objects into an XML string. Use <a href="#namespacerapidxml_b94d570fc4c4ab2423813 [...]
+xml_document<> doc;    // character type defaults to char
+// ... some code to fill the document
+
+// Print to stream using operator <<
+std::cout << doc;   
+
+// Print to stream using print function, specifying printing flags
+print(std::cout, doc, 0);   // 0 means default printing flags
+
+// Print to string using output iterator
+std::string s;
+print(std::back_inserter(s), doc, 0);
+
+// Print to memory buffer using output iterator
+char buffer[4096];                      // You are responsible for making the buffer large enough!
+char *end = print(buffer, doc, 0);      // end contains pointer to character after last printed character
+*end = 0;                               // Add string terminator after XML
+</pre></para></sect2></sect1><sect1><h2 id="namespacerapidxml_1differences">3. Differences From Regular XML Parsers</h2><para>RapidXml is an <i>in-situ parser</i>, which allows it to achieve very high parsing speed. In-situ means that parser does not make copies of strings. Instead, it places pointers to the <i>source text</i> in the DOM hierarchy.</para><sect2><h3 id="namespacerapidxml_1lifetime_of_source_text">3.1 Lifetime Of Source Text</h3><para>In-situ parsing requires that source t [...]
+ In many cases however, these are not serious issues.</para></sect2><sect2><h3 id="namespacerapidxml_1ownership_of_strings">3.2 Ownership Of Strings</h3><para>Nodes and attributes produced by RapidXml do not own their name and value strings. They merely hold the pointers to them. This means you have to be careful when setting these values manually, by using <a href="#classrapidxml_1_1xml__base_e099c291e104a0d277307fe71f5e0f9e_1e099c291e104a0d277307fe71f5e0f9e" kindref="member">xml_base:: [...]
+ In some cases this behaviour may be undesirable, for example if source text resides in read only memory, or is mapped to memory directly from file. By using appropriate parser flags (parse_non_destructive), source text modifications can be disabled. However, because RapidXml does in-situ parsing, it obviously has the following side-effects:<ul><li><para>no whitespace normalization is done</para></li><li><para>no entity reference translation is done</para></li><li><para>names and values  [...]
+								  template
+							   <a href="#classrapidxml_1_1memory__pool">rapidxml::memory_pool</a></dt><dt class="indented">
+				constructor
+			 <a href="#classrapidxml_1_1memory__pool_f8fb3c8f1a564f8045c40bcd07a89866_1f8fb3c8f1a564f8045c40bcd07a89866">memory_pool()</a></dt><dt class="indented">
+				destructor
+			 <a href="#classrapidxml_1_1memory__pool_6f8c7990d9ec1ed2acf6558b238570eb_16f8c7990d9ec1ed2acf6558b238570eb">~memory_pool()</a></dt><dt class="indented">function <a href="#classrapidxml_1_1memory__pool_750ba3c610b129ac057d817509d08f41_1750ba3c610b129ac057d817509d08f41">allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)</a></dt><dt class="indented">function <a href="#classrapidxml_1_1memory__pool_462de142669e0ff649e8e61 [...]
+				constructor
+			 <a href="#classrapidxml_1_1parse__error_4dd8d1bdbd9221df4dcb90cafaee3332_14dd8d1bdbd9221df4dcb90cafaee3332">parse_error(const char *what, void *where)</a></dt><dt class="indented">function <a href="#classrapidxml_1_1parse__error_ff06f49065b54a8a86e02e9a2441a8ba_1ff06f49065b54a8a86e02e9a2441a8ba">what() const </a></dt><dt class="indented">function <a href="#classrapidxml_1_1parse__error_377be7d201d95221c318682c35377aca_1377be7d201d95221c318682c35377aca">where() const </a></dt><dt clas [...]
+								  template
+							   <a href="#classrapidxml_1_1xml__attribute">rapidxml::xml_attribute</a></dt><dt class="indented">
+				constructor
+			 <a href="#classrapidxml_1_1xml__attribute_d5464aadf08269a886b730993525db34_1d5464aadf08269a886b730993525db34">xml_attribute()</a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__attribute_77aea7d8d996ba4f6bd61cc478a4e72d_177aea7d8d996ba4f6bd61cc478a4e72d">document() const </a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__attribute_5c4a98d2b75f9b41b12c110108fd55ab_15c4a98d2b75f9b41b12c110108fd55ab">previous_attribute(const Ch *name=0, std::size_t [...]
+								  template
+							   <a href="#classrapidxml_1_1xml__base">rapidxml::xml_base</a></dt><dt class="indented">
+				constructor
+			 <a href="#classrapidxml_1_1xml__base_23630d2c130a9e0e3f3afa7584a9b218_123630d2c130a9e0e3f3afa7584a9b218">xml_base()</a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__base_622eade29fdf7806d3ef93ac4d90e707_1622eade29fdf7806d3ef93ac4d90e707">name() const </a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__base_0dae694c8f7e4d89f1003e2f3a15a43c_10dae694c8f7e4d89f1003e2f3a15a43c">name_size() const </a></dt><dt class="indented">function <a href="#class [...]
+								  template
+							   <a href="#classrapidxml_1_1xml__document">rapidxml::xml_document</a></dt><dt class="indented">
+				constructor
+			 <a href="#classrapidxml_1_1xml__document_6ce266cc52d549c42abe3a3d5e8af9ba_16ce266cc52d549c42abe3a3d5e8af9ba">xml_document()</a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c">parse(Ch *text)</a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__document_c8bb3912a3ce86b15842e79d0b421204_1c8bb3912a3ce86b15842e79d0b421204">clear()</a></dt><dt class="indented"/><dt class="inden [...]
+								  template
+							   <a href="#classrapidxml_1_1xml__node">rapidxml::xml_node</a></dt><dt class="indented">
+				constructor
+			 <a href="#classrapidxml_1_1xml__node_34c55af3504549a475e5b9dfcaa6adf5_134c55af3504549a475e5b9dfcaa6adf5">xml_node(node_type type)</a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__node_975e86937621ae4afe6a423219de30d0_1975e86937621ae4afe6a423219de30d0">type() const </a></dt><dt class="indented">function <a href="#classrapidxml_1_1xml__node_77aea7d8d996ba4f6bd61cc478a4e72d_177aea7d8d996ba4f6bd61cc478a4e72d">document() const </a></dt><dt class="indented">function <a [...]
+				constant
+			 <a href="#namespacerapidxml_87e8bbab53702cf3b438bd553c10b6b9_187e8bbab53702cf3b438bd553c10b6b9">parse_no_data_nodes</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_97e2c4fdc04fae17126f9971a4fc993e_197e2c4fdc04fae17126f9971a4fc993e">parse_no_element_values</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_9cae3801e70437cbc410c24bf6be691c_19cae3801e70437cbc410c24bf6be691c">parse_no_string_terminators</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_7223b7815c4fb8b42e6e4e77e1ea6b97_17223b7815c4fb8b42e6e4e77e1ea6b97">parse_no_entity_translation</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_ccde57f6054857ee4042a1b4d98c83b9_1ccde57f6054857ee4042a1b4d98c83b9">parse_no_utf8</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_52e2c934ad9c845a5f4cc49570470556_152e2c934ad9c845a5f4cc49570470556">parse_declaration_node</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_0f7479dacbc868456d07897a8c072784_10f7479dacbc868456d07897a8c072784">parse_comment_nodes</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_8e187746ba1ca04f107951ad32df962e_18e187746ba1ca04f107951ad32df962e">parse_doctype_node</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_1c20b2b2b75711cd76423e119c49f830_11c20b2b2b75711cd76423e119c49f830">parse_pi_nodes</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_a5daff9d61c7d4eaf98e4d42efe628ee_1a5daff9d61c7d4eaf98e4d42efe628ee">parse_validate_closing_tags</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_ac1f06b1afd47b812732fb521b146fd9_1ac1f06b1afd47b812732fb521b146fd9">parse_trim_whitespace</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_88f95d4e275ba01408fefde83078651b_188f95d4e275ba01408fefde83078651b">parse_normalize_whitespace</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_45751cf2f38fd6915f35b3122b46d5b6_145751cf2f38fd6915f35b3122b46d5b6">parse_default</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_a97ba1a0a79a6d66f4eef3612508d943_1a97ba1a0a79a6d66f4eef3612508d943">parse_non_destructive</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_398c5476e76102f8bd76c10bb0abbe10_1398c5476e76102f8bd76c10bb0abbe10">parse_fastest</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_b4f2515265facb42291570307924bd57_1b4f2515265facb42291570307924bd57">parse_full</a></dt><dt class="indented">
+				constant
+			 <a href="#namespacerapidxml_b08b8d4293c203b69ed6c5ae77ac1907_1b08b8d4293c203b69ed6c5ae77ac1907">print_no_indenting</a></dt><p/><p/><p/><p/></dl><hr/><h3 class="reference-header" id="classrapidxml_1_1memory__pool">class
+									  template
+								   rapidxml::memory_pool</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/>
+								  Base class for
+								  <a href="#classrapidxml_1_1xml__document">xml_document</a> <h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. In most cases, you will not need to use this class directly. However, if you need to create nodes manually or modify names/values of nodes, you are encouraged to use <a href="#classrapidxml_1_1memory__pool" kindref="compound"> [...]
+ Call <a href="#classrapidxml_1_1memory__pool_750ba3c610b129ac057d817509d08f41_1750ba3c610b129ac057d817509d08f41" kindref="member">allocate_node()</a> or <a href="#classrapidxml_1_1memory__pool_462de142669e0ff649e8e615b82bf457_1462de142669e0ff649e8e615b82bf457" kindref="member">allocate_attribute()</a> functions to obtain new nodes or attributes from the pool. You can also call <a href="#classrapidxml_1_1memory__pool_69729185bc59b0875192d667c47b8859_169729185bc59b0875192d667c47b8859" kin [...]
+ It is also possible to create a standalone <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a>, and use it to allocate nodes, whose lifetime will not be tied to any document. <br/><br/>
+ Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. Until static memory is exhausted, no dynamic memory allocations are done. When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each, by using global <code>new[]</code> and <code>delete[]</code> operators. This behaviour can be changed by setting custom allocation routines. Use <a href="#classrapidxml_1_1memory__pool_c0a55a6ef0 [...]
+ Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes. This value defaults to the size of pointer on target architecture. <br/><br/>
+ To obtain absolutely top performance from the parser, it is important that all nodes are allocated from a single, contiguous block of memory. Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code> to obtain best wasted memory to performance compromise. To do it, define their  [...]
+				constructor
+			 memory_pool::memory_pool</h3><h4>Synopsis</h4><code class="synopsis">memory_pool();
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Constructs empty pool with default allocator functions. </para><p/><h3 class="reference-header" id="classrapidxml_1_1memory__pool_6f8c7990d9ec1ed2acf6558b238570eb_16f8c7990d9ec1ed2acf6558b238570eb">
+				destructor
+			 memory_pool::~memory_pool</h3><h4>Synopsis</h4><code class="synopsis">~memory_pool();
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Destroys pool and frees all the memory. This causes memory occupied by nodes allocated by the pool to be freed. Nodes allocated from the pool are no longer valid. </para><p/><h3 class="reference-header" id="classrapidxml_1_1memory__pool_750ba3c610b129ac057d817509d08f41_1750ba3c610b129ac057d817509d08f41">function memory_pool::allocate_node</h3><h4>Synopsis</h4><code class="synopsis">xml_node& [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Allocates a new node from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call <a href="#namespacerapidxml_ff5d67f74437199d316d2b2660653ae1_1ff5d67f74437199d316d2b2660653ae1" kindref="member">rapidxml:: [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Allocates a new attribute from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call <a href="#namespacerapidxml_ff5d67f74437199d316d2b2660653ae1_1ff5d67f74437199d316d2b2660653ae1" kindref="member">rapid [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Allocates a char array of given size from the pool, and optionally copies a given string to it. If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call <a href="#namespacerapidxml_ff5d67f74437199d316d2b2660653ae1_1ff5d67f74437199d316d2b2660653ae1" kindref="mem [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Clones an <a href="#classrapidxml_1_1xml__node" kindref="compound">xml_node</a> and its hierarchy of child nodes and attributes. Nodes and attributes are allocated from this memory pool. Names and values are not cloned, they are shared between the clone and the source. Result node can be optionally specified as a second parameter, in which case its contents will be replaced with cloned sourc [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Clears the pool. This causes memory occupied by nodes allocated by the pool to be freed. Any nodes or strings allocated from the pool will no longer be valid. </para><p/><h3 class="reference-header" id="classrapidxml_1_1memory__pool_c0a55a6ef0837dca67572e357100d78a_1c0a55a6ef0837dca67572e357100d78a">function memory_pool::set_allocator</h3><h4>Synopsis</h4><code class="synopsis">void set_allo [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets or resets the user-defined memory allocation functions for the pool. This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. Allocation function must not return invalid pointer on failure. It should either throw, stop the program, or use <code>longjmp()</code> function to pass control to other place of program. If it returns invalid pointe [...]
+ User defined allocation functions must have the following forms: <br/><code><br/>
+void *allocate(std::size_t size); <br/>
+void free(void *pointer); </code><br/></para><h4>Parameters</h4><dl><dt class="parameter-name">af</dt><dd class="parameter-def">Allocation function, or 0 to restore default function </dd></dl><dl><dt class="parameter-name">ff</dt><dd class="parameter-def">Free function, or 0 to restore default function </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1parse__error">class rapidxml::parse_error</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse error exception. This exception is thrown by the parser when an error occurs. Use <a href="#classrapidxml_1_1parse__error_ff06f49065b54a8a86e02e9a2441a8ba_1ff06f49065b54a8a86e02e9a2441a8ba" kindref="member">what()</a> function to get human-readable error message. Use <a href="#classrapidxml_1_1parse__error_377be7d201d95221c318682c35377aca_1 [...]
+ If throwing exceptions by the parser is undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before <a href="#rapidxml_8hpp" kindref="compound">rapidxml.hpp</a> is included. This will cause the parser to call <a href="#namespacerapidxml_ff5d67f74437199d316d2b2660653ae1_1ff5d67f74437199d316d2b2660653ae1" kindref="member">rapidxml::parse_error_handler()</a> function instead of throwing an exception. This function must be defined by the user. <br/><br/>
+ This class derives from <code>std::exception</code> class. </para><p/><h3 class="reference-header" id="classrapidxml_1_1parse__error_4dd8d1bdbd9221df4dcb90cafaee3332_14dd8d1bdbd9221df4dcb90cafaee3332">
+				constructor
+			 parse_error::parse_error</h3><h4>Synopsis</h4><code class="synopsis">parse_error(const char *what, void *where);
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Constructs parse error. </para><p/><h3 class="reference-header" id="classrapidxml_1_1parse__error_ff06f49065b54a8a86e02e9a2441a8ba_1ff06f49065b54a8a86e02e9a2441a8ba">function parse_error::what</h3><h4>Synopsis</h4><code class="synopsis">virtual const char* what() const;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets human readable description of error. </para><h4>Returns</h4>Pointer to null terminated description of the error. <p/><h3 class="reference-header" id="classrapidxml_1_1parse__error_377be7d201d95221c318682c35377aca_1377be7d201d95221c318682c35377aca">function parse_error::where</h3><h4>Synopsis</h4><code class="synopsis">Ch* where() const;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets pointer to character data where error happened. Ch should be the same as char type of <a href="#classrapidxml_1_1xml__document" kindref="compound">xml_document</a> that produced the error. </para><h4>Returns</h4>Pointer to location within the parsed string where error occured. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__attribute">class
+									  template
+								   rapidxml::xml_attribute</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/>
+								  Inherits from
+								  <a href="#classrapidxml_1_1xml__base">xml_base</a> <br/><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Class representing attribute node of XML document. Each attribute has name and value strings, which are available through <a href="#classrapidxml_1_1xml__base_622eade29fdf7806d3ef93ac4d90e707_1622eade29fdf7806d3ef93ac4d90e707" kindref="member">name()</a> and <a href="#classrapidxml_1_1xml__base_c54fa4987fb503916a7b541eb15c9c7f_1c54fa4987fb50391 [...]
+				constructor
+			 xml_attribute::xml_attribute</h3><h4>Synopsis</h4><code class="synopsis">xml_attribute();
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Constructs an empty attribute with the specified type. Consider using <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a> of appropriate <a href="#classrapidxml_1_1xml__document" kindref="compound">xml_document</a> if allocating attributes manually. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__attribute_77aea7d8d996ba4f6bd61cc478a4e72d_177aea7d8d9 [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets document of which attribute is a child. </para><h4>Returns</h4>Pointer to document that contains this attribute, or 0 if there is no parent document. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__attribute_5c4a98d2b75f9b41b12c110108fd55ab_15c4a98d2b75f9b41b12c110108fd55ab">function xml_attribute::previous_attribute</h3><h4>Synopsis</h4><code class="synopsis">xml_attribute&l [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets previous attribute, optionally matching attribute name. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero </dd></dl><dl><dt class="parameter-name">name_size</dt><dd class="parameter-def [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets next attribute, optionally matching attribute name. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero </dd></dl><dl><dt class="parameter-name">name_size</dt><dd class="parameter-def">Size o [...]
+									  template
+								   rapidxml::xml_base</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/>
+								  Base class for
+								  <a href="#classrapidxml_1_1xml__attribute">xml_attribute</a> <a href="#classrapidxml_1_1xml__node">xml_node</a> <h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Base class for <a href="#classrapidxml_1_1xml__node" kindref="compound">xml_node</a> and <a href="#classrapidxml_1_1xml__attribute" kindref="compound">xml_attribute</a> implementing common functions: <a href="#classrapidxml_1_1xml__base_622eade29fdf7806d3ef93ac4d90e707_1622eade29fdf7806d3e [...]
+				constructor
+			 xml_base::xml_base</h3><h4>Synopsis</h4><code class="synopsis">xml_base();
+									  </code><p/><h3 class="reference-header" id="classrapidxml_1_1xml__base_622eade29fdf7806d3ef93ac4d90e707_1622eade29fdf7806d3ef93ac4d90e707">function xml_base::name</h3><h4>Synopsis</h4><code class="synopsis">Ch* name() const;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets name of the node. Interpretation of name depends on type of node. Note that name will not be zero-terminated if <a href="#namespacerapidxml_9cae3801e70437cbc410c24bf6be691c_19cae3801e70437cbc410c24bf6be691c" kindref="member">rapidxml::parse_no_string_terminators</a> option was selected during parse. <br/><br/>
+ Use <a href="#classrapidxml_1_1xml__base_0dae694c8f7e4d89f1003e2f3a15a43c_10dae694c8f7e4d89f1003e2f3a15a43c" kindref="member">name_size()</a> function to determine length of the name. </para><h4>Returns</h4>Name of node, or empty string if node has no name. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__base_0dae694c8f7e4d89f1003e2f3a15a43c_10dae694c8f7e4d89f1003e2f3a15a43c">function xml_base::name_size</h3><h4>Synopsis</h4><code class="synopsis">std::size_t name_size() const;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets size of node name, not including terminator character. This function works correctly irrespective of whether name is or is not zero terminated. </para><h4>Returns</h4>Size of node name, in characters. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__base_c54fa4987fb503916a7b541eb15c9c7f_1c54fa4987fb503916a7b541eb15c9c7f">function xml_base::value</h3><h4>Synopsis</h4><code clas [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if <a href="#namespacerapidxml_9cae3801e70437cbc410c24bf6be691c_19cae3801e70437cbc410c24bf6be691c" kindref="member">rapidxml::parse_no_string_terminators</a> option was selected during parse. <br/><br/>
+ Use <a href="#classrapidxml_1_1xml__base_aed5ae791b7164c1ee5e649198cbb3db_1aed5ae791b7164c1ee5e649198cbb3db" kindref="member">value_size()</a> function to determine length of the value. </para><h4>Returns</h4>Value of node, or empty string if node has no value. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__base_aed5ae791b7164c1ee5e649198cbb3db_1aed5ae791b7164c1ee5e649198cbb3db">function xml_base::value_size</h3><h4>Synopsis</h4><code class="synopsis">std::size_t value_size( [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets size of node value, not including terminator character. This function works correctly irrespective of whether value is or is not zero terminated. </para><h4>Returns</h4>Size of node value, in characters. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__base_4e7e23d06d48126c65b1f6266acfba5c_14e7e23d06d48126c65b1f6266acfba5c">function xml_base::name</h3><h4>Synopsis</h4><code cl [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets name of node to a non zero-terminated string. See <a href="#namespacerapidxml_1ownership_of_strings" kindref="member">Ownership Of Strings</a> . <br/><br/>
+ Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a> of the document to allocate the string - on destruction of the document the string will be automatically freed. <br/><br/>
+ Size of name must be specified separately, because name does not have to be zero terminated. Use <a href="#classrapidxml_1_1xml__base_e099c291e104a0d277307fe71f5e0f9e_1e099c291e104a0d277307fe71f5e0f9e" kindref="member">name(const Ch *)</a> function to have the length automatically calculated (string must be zero terminated). </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of node to set. Does not have to be zero terminated. </dd></dl><dl> [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets name of node to a zero-terminated string. See also <a href="#namespacerapidxml_1ownership_of_strings" kindref="member">Ownership Of Strings</a>  and <a href="#classrapidxml_1_1xml__base_4e7e23d06d48126c65b1f6266acfba5c_14e7e23d06d48126c65b1f6266acfba5c" kindref="member">xml_node::name(const Ch *, std::size_t)</a>. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd cla [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets value of node to a non zero-terminated string. See <a href="#namespacerapidxml_1ownership_of_strings" kindref="member">Ownership Of Strings</a> . <br/><br/>
+ Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a> of the document to allocate the string - on destruction of the document the string will be automatically freed. <br/><br/>
+ Size of value must be specified separately, because it does not have to be zero terminated. Use <a href="#classrapidxml_1_1xml__base_18c7469acdca771de9b4f3054053029c_118c7469acdca771de9b4f3054053029c" kindref="member">value(const Ch *)</a> function to have the length automatically calculated (string must be zero terminated). <br/><br/>
+ If an element has a child node of type node_data, it will take precedence over element value when printing. If you want to manipulate data of elements using values, use parser flag <a href="#namespacerapidxml_87e8bbab53702cf3b438bd553c10b6b9_187e8bbab53702cf3b438bd553c10b6b9" kindref="member">rapidxml::parse_no_data_nodes</a> to prevent creation of data nodes by the parser. </para><h4>Parameters</h4><dl><dt class="parameter-name">value</dt><dd class="parameter-def">value of node to set. [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets value of node to a zero-terminated string. See also <a href="#namespacerapidxml_1ownership_of_strings" kindref="member">Ownership Of Strings</a>  and <a href="#classrapidxml_1_1xml__base_d9640aa3f5374673cb72a5289b6c91eb_1d9640aa3f5374673cb72a5289b6c91eb" kindref="member">xml_node::value(const Ch *, std::size_t)</a>. </para><h4>Parameters</h4><dl><dt class="parameter-name">value</dt><dd  [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets node parent. </para><h4>Returns</h4>Pointer to parent node, or 0 if there is no parent. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__document">class
+									  template
+								   rapidxml::xml_document</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/>
+								  Inherits from
+								  <a href="#classrapidxml_1_1xml__node">xml_node</a> <a href="#classrapidxml_1_1memory__pool">memory_pool</a> <br/><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">This class represents root of the DOM hierarchy. It is also an <a href="#classrapidxml_1_1xml__node" kindref="compound">xml_node</a> and a <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a> through public inheritance. Use <a href="#classrapidxml_1_1xml__document_8 [...]
+				constructor
+			 xml_document::xml_document</h3><h4>Synopsis</h4><code class="synopsis">xml_document();
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Constructs empty XML document. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c">function xml_document::parse</h3><h4>Synopsis</h4><code class="synopsis">void parse(Ch *text);
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parses zero-terminated XML string according to given flags. Passed string will be modified by the parser, unless <a href="#namespacerapidxml_a97ba1a0a79a6d66f4eef3612508d943_1a97ba1a0a79a6d66f4eef3612508d943" kindref="member">rapidxml::parse_non_destructive</a> flag is used. The string must persist for the lifetime of the document. In case of error, <a href="#classrapidxml_1_1parse__error" k [...]
+ If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. Make sure that data is zero-terminated. <br/><br/>
+ Document can be parsed into multiple times. Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. </para><h4>Parameters</h4><dl><dt class="parameter-name">text</dt><dd class="parameter-def">XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__document_c8bb3912a3ce86b15842e79d0b421204_1c8bb3912a3ce86b15842e79d0b421204">funct [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Clears the document by deleting all nodes and clearing the memory pool. All nodes owned by document pool are destroyed. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node">class
+									  template
+								   rapidxml::xml_node</h3>
+
+							  Defined in <a href="rapidxml.hpp">rapidxml.hpp</a><br/>
+								  Inherits from
+								  <a href="#classrapidxml_1_1xml__base">xml_base</a> <br/>
+								  Base class for
+								  <a href="#classrapidxml_1_1xml__document">xml_document</a> <h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Class representing a node of XML document. Each node may have associated name and value strings, which are available through <a href="#classrapidxml_1_1xml__base_622eade29fdf7806d3ef93ac4d90e707_1622eade29fdf7806d3ef93ac4d90e707" kindref="member">name()</a> and <a href="#classrapidxml_1_1xml__base_c54fa4987fb503916a7b541eb15c9c7f_1c54fa4987f [...]
+ Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. Thus, this text must persist in the memory for the lifetime of node. </para><h4>Parameters</h4><dl><dt class="parameter-name">Ch</dt><dd>Character type to use. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_34c55af3504549a475e5b9dfcaa6adf5_134c55af3504549a475e5b9dfcaa6adf5">
+				constructor
+			 xml_node::xml_node</h3><h4>Synopsis</h4><code class="synopsis">xml_node(node_type type);
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Constructs an empty node with the specified type. Consider using <a href="#classrapidxml_1_1memory__pool" kindref="compound">memory_pool</a> of appropriate document to allocate nodes manually. </para><h4>Parameters</h4><dl><dt class="parameter-name">type</dt><dd class="parameter-def">Type of node to construct. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_975e8693 [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets type of node. </para><h4>Returns</h4>Type of node. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_77aea7d8d996ba4f6bd61cc478a4e72d_177aea7d8d996ba4f6bd61cc478a4e72d">function xml_node::document</h3><h4>Synopsis</h4><code class="synopsis">xml_document<Ch>* document() const;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets document of which node is a child. </para><h4>Returns</h4>Pointer to document that contains this node, or 0 if there is no parent document. <p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_7823e36687669e59c2afdf66334ef35a_17823e36687669e59c2afdf66334ef35a">function xml_node::first_node</h3><h4>Synopsis</h4><code class="synopsis">xml_node<Ch>* first_node(const Ch *na [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets first child node, optionally matching node name. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero </dd></dl><dl><dt class="parameter-name">name_size</dt><dd class="parameter-def">Size of name, in [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets last child node, optionally matching node name. Behaviour is undefined if node has no children. Use <a href="#classrapidxml_1_1xml__node_7823e36687669e59c2afdf66334ef35a_17823e36687669e59c2afdf66334ef35a" kindref="member">first_node()</a> to test if node has children. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of child to find, or 0  [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets previous sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use <a href="#classrapidxml_1_1xml__base_798e8df7ea53ade4d9f0701017dce80e_1798e8df7ea53ade4d9f0701017dce80e" kindref="member">parent()</a> to test if node has a parent. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of sibling to find, or  [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets next sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use <a href="#classrapidxml_1_1xml__base_798e8df7ea53ade4d9f0701017dce80e_1798e8df7ea53ade4d9f0701017dce80e" kindref="member">parent()</a> to test if node has a parent. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of sibling to find, or 0 to [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets first attribute of node, optionally matching attribute name. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero </dd></dl><dl><dt class="parameter-name">name_size</dt><dd class="parameter-d [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Gets last attribute of node, optionally matching attribute name. </para><h4>Parameters</h4><dl><dt class="parameter-name">name</dt><dd class="parameter-def">Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero </dd></dl><dl><dt class="parameter-name">name_size</dt><dd class="parameter-def [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sets type of node. </para><h4>Parameters</h4><dl><dt class="parameter-name">type</dt><dd class="parameter-def">Type of node to set. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_0c39df6617e709eb2fba11300dea63f2_10c39df6617e709eb2fba11300dea63f2">function xml_node::prepend_node</h3><h4>Synopsis</h4><code class="synopsis">void prepend_node(xml_node< Ch > *child);
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Prepends a new child node. The prepended child becomes the first child, and all existing children are moved one position back. </para><h4>Parameters</h4><dl><dt class="parameter-name">child</dt><dd class="parameter-def">Node to prepend. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_86de2e22276826089b7baed2599f8dee_186de2e22276826089b7baed2599f8dee">function xml_no [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Appends a new child node. The appended child becomes the last child. </para><h4>Parameters</h4><dl><dt class="parameter-name">child</dt><dd class="parameter-def">Node to append. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_780972a57fc447250ab47cc8f421b65e_1780972a57fc447250ab47cc8f421b65e">function xml_node::insert_node</h3><h4>Synopsis</h4><code class="synopsis" [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Inserts a new child node at specified place inside the node. All children after and including the specified node are moved one position back. </para><h4>Parameters</h4><dl><dt class="parameter-name">where</dt><dd class="parameter-def">Place where to insert the child, or 0 to insert at the back. </dd></dl><dl><dt class="parameter-name">child</dt><dd class="parameter-def">Node to insert. </dd> [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes first child node. If node has no children, behaviour is undefined. Use <a href="#classrapidxml_1_1xml__node_7823e36687669e59c2afdf66334ef35a_17823e36687669e59c2afdf66334ef35a" kindref="member">first_node()</a> to test if node has children. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_87addf2bc127ee31aa4b5295d3c9b530_187addf2bc127ee31aa4b5295d3c9b530">functio [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes last child of the node. If node has no children, behaviour is undefined. Use <a href="#classrapidxml_1_1xml__node_7823e36687669e59c2afdf66334ef35a_17823e36687669e59c2afdf66334ef35a" kindref="member">first_node()</a> to test if node has children. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_9316463a2201631e7e2062b17729f9cd_19316463a2201631e7e2062b17729f9cd">f [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes specified child from the node. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_0218147d13e41d5fa60ced4e7a7e9726_10218147d13e41d5fa60ced4e7a7e9726">function xml_node::remove_all_nodes</h3><h4>Synopsis</h4><code class="synopsis">void remove_all_nodes();
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes all child nodes (but not attributes). </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_f6dffa513da74cc0be71a7ba84f8265e_1f6dffa513da74cc0be71a7ba84f8265e">function xml_node::prepend_attribute</h3><h4>Synopsis</h4><code class="synopsis">void prepend_attribute(xml_attribute< Ch > *attribute);
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Prepends a new attribute to the node. </para><h4>Parameters</h4><dl><dt class="parameter-name">attribute</dt><dd class="parameter-def">Attribute to prepend. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_8fbd4f5ef7169d493da9f8d87ac04b77_18fbd4f5ef7169d493da9f8d87ac04b77">function xml_node::append_attribute</h3><h4>Synopsis</h4><code class="synopsis">void append_att [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Appends a new attribute to the node. </para><h4>Parameters</h4><dl><dt class="parameter-name">attribute</dt><dd class="parameter-def">Attribute to append. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_070d5888b0557fe06a5b24961de1b988_1070d5888b0557fe06a5b24961de1b988">function xml_node::insert_attribute</h3><h4>Synopsis</h4><code class="synopsis">void insert_attri [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Inserts a new attribute at specified place inside the node. All attributes after and including the specified attribute are moved one position back. </para><h4>Parameters</h4><dl><dt class="parameter-name">where</dt><dd class="parameter-def">Place where to insert the attribute, or 0 to insert at the back. </dd></dl><dl><dt class="parameter-name">attribute</dt><dd class="parameter-def">Attribu [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes first attribute of the node. If node has no attributes, behaviour is undefined. Use <a href="#classrapidxml_1_1xml__node_5810a09f82f8d53efbe9456286dcec83_15810a09f82f8d53efbe9456286dcec83" kindref="member">first_attribute()</a> to test if node has attributes. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_37d87c4d5d89fa0cf05b72ee8d4cba3b_137d87c4d5d89fa0cf05b7 [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes last attribute of the node. If node has no attributes, behaviour is undefined. Use <a href="#classrapidxml_1_1xml__node_5810a09f82f8d53efbe9456286dcec83_15810a09f82f8d53efbe9456286dcec83" kindref="member">first_attribute()</a> to test if node has attributes. </para><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_c75154db2e768c0e5b541fc8cd0775ab_1c75154db2e768c0e5b541f [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes specified attribute from node. </para><h4>Parameters</h4><dl><dt class="parameter-name">where</dt><dd class="parameter-def">Pointer to attribute to be removed. </dd></dl><p/><h3 class="reference-header" id="classrapidxml_1_1xml__node_59e6ad4cfd5e8096c052e71d79561eda_159e6ad4cfd5e8096c052e71d79561eda">function xml_node::remove_all_attributes</h3><h4>Synopsis</h4><code class="synopsis" [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Removes all attributes of node. </para><p/><h3 class="reference-header" id="namespacerapidxml_6a276b85e2da28c5f9c3dbce61c55682_16a276b85e2da28c5f9c3dbce61c55682">enum node_type</h3><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Enumeration listing all node types produced by the parser. Use <a href="#classrapidxml_1_1xml__node_975e86937621ae4afe6a423219de30d0_ [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function is called to notify user about the error. It must be defined by the user. <br/><br/>
+ This function cannot return. If it does, the results are undefined. <br/><br/>
+ A very simple definition might look like that: <preformatted>
+        void rapidxml::parse_error_handler(const char *what, void *where)
+        {
+            std::cout << "Parse error: " << what << "\n";
+            std::abort();
+        }
+        </preformatted></para><h4>Parameters</h4><dl><dt class="parameter-name">what</dt><dd class="parameter-def">Human readable description of the error. </dd></dl><dl><dt class="parameter-name">where</dt><dd class="parameter-def">Pointer to character data where error was detected. </dd></dl><p/><h3 class="reference-header" id="namespacerapidxml_b94d570fc4c4ab2423813cd0243326b1_1b94d570fc4c4ab2423813cd0243326b1">function print</h3><h4>Synopsis</h4><code class="synopsis">OutIt rapidxml: [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Prints XML to given output iterator. </para><h4>Parameters</h4><dl><dt class="parameter-name">out</dt><dd class="parameter-def">Output iterator to print to. </dd></dl><dl><dt class="parameter-name">node</dt><dd class="parameter-def">Node to be printed. Pass xml_document to print entire document. </dd></dl><dl><dt class="parameter-name">flags</dt><dd class="parameter-def">Flags controlling ho [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Prints XML to given output stream. </para><h4>Parameters</h4><dl><dt class="parameter-name">out</dt><dd class="parameter-def">Output stream to print to. </dd></dl><dl><dt class="parameter-name">node</dt><dd class="parameter-def">Node to be printed. Pass xml_document to print entire document. </dd></dl><dl><dt class="parameter-name">flags</dt><dd class="parameter-def">Flags controlling how XM [...]
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Prints formatted XML to given output stream. Uses default printing flags. Use <a href="#namespacerapidxml_b94d570fc4c4ab2423813cd0243326b1_1b94d570fc4c4ab2423813cd0243326b1" kindref="member">print()</a> function to customize printing process. </para><h4>Parameters</h4><dl><dt class="parameter-name">out</dt><dd class="parameter-def">Output stream to print to. </dd></dl><dl><dt class="paramete [...]
+				constant
+			 parse_no_data_nodes</h3><h4>Synopsis</h4><code class="synopsis">const int parse_no_data_nodes
+											  = 0x1;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to not create data nodes. Text of first data node will still be placed in value of parent element, unless <a href="#namespacerapidxml_97e2c4fdc04fae17126f9971a4fc993e_197e2c4fdc04fae17126f9971a4fc993e" kindref="member">rapidxml::parse_no_element_values</a> flag is also specified. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_97e2c4fdc04fae17126f9971a4fc993e_197e2c4fdc04fae17126f9971a4fc993e">
+				constant
+			 parse_no_element_values</h3><h4>Synopsis</h4><code class="synopsis">const int parse_no_element_values
+											  = 0x2;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to not use text of first data node as a value of parent element. Can be combined with other flags by use of | operator. Note that child data nodes of element node take precendence over its value when printing. That is, if element has one or more child data nodes <i>and</i> a value, the value will be ignored. Use <a href="#namespacerapidxml_87e8bbab53702cf3b4 [...]
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_9cae3801e70437cbc410c24bf6be691c_19cae3801e70437cbc410c24bf6be691c">
+				constant
+			 parse_no_string_terminators</h3><h4>Synopsis</h4><code class="synopsis">const int parse_no_string_terminators
+											  = 0x4;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to not place zero terminators after strings in the source text. By default zero terminators are placed, modifying source text. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_7223b7815c4fb8b42e6e4e77e1ea6b97_17223b7815c4fb8b42e6e4e77e1ea6b97">
+				constant
+			 parse_no_entity_translation</h3><h4>Synopsis</h4><code class="synopsis">const int parse_no_entity_translation
+											  = 0x8;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to not translate entities in the source text. By default entities are translated, modifying source text. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_ccde57f6054857ee4042a1b4d98c83b9_1ccde57f6054857ee4042a1b4d98c83b9">
+				constant
+			 parse_no_utf8</h3><h4>Synopsis</h4><code class="synopsis">const int parse_no_utf8
+											  = 0x10;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. By default, UTF-8 handling is enabled. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_52e2c934ad9c845a5f4cc49570470556_152e2c934ad9c845a5f4cc49570470556">
+				constant
+			 parse_declaration_node</h3><h4>Synopsis</h4><code class="synopsis">const int parse_declaration_node
+											  = 0x20;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to create XML declaration node. By default, declaration node is not created. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_0f7479dacbc868456d07897a8c072784_10f7479dacbc868456d07897a8c072784">
+				constant
+			 parse_comment_nodes</h3><h4>Synopsis</h4><code class="synopsis">const int parse_comment_nodes
+											  = 0x40;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to create comments nodes. By default, comment nodes are not created. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_8e187746ba1ca04f107951ad32df962e_18e187746ba1ca04f107951ad32df962e">
+				constant
+			 parse_doctype_node</h3><h4>Synopsis</h4><code class="synopsis">const int parse_doctype_node
+											  = 0x80;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to create DOCTYPE node. By default, doctype node is not created. Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_1c20b2b2b75711cd76423e119c49f830_11c20b2b2b75711cd76423e119c49f830">
+				constant
+			 parse_pi_nodes</h3><h4>Synopsis</h4><code class="synopsis">const int parse_pi_nodes
+											  = 0x100;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to create PI nodes. By default, PI nodes are not created. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_a5daff9d61c7d4eaf98e4d42efe628ee_1a5daff9d61c7d4eaf98e4d42efe628ee">
+				constant
+			 parse_validate_closing_tags</h3><h4>Synopsis</h4><code class="synopsis">const int parse_validate_closing_tags
+											  = 0x200;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to validate closing tag names. If not set, name inside closing tag is irrelevant to the parser. By default, closing tags are not validated. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_ac1f06b1afd47b812732fb521b146fd9_1ac1f06b1afd47b812732fb521b146fd9">
+				constant
+			 parse_trim_whitespace</h3><h4>Synopsis</h4><code class="synopsis">const int parse_trim_whitespace
+											  = 0x400;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. By default, whitespace is not trimmed. This flag does not cause the parser to modify source text. Can be combined with other flags by use of | operator. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_88f95d4e275ba01408fefde83078651b_188f95d4e275ba01408fefde83078651b">
+				constant
+			 parse_normalize_whitespace</h3><h4>Synopsis</h4><code class="synopsis">const int parse_normalize_whitespace
+											  = 0x800;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. Trimming of leading and trailing whitespace of data is controlled by <a href="#namespacerapidxml_ac1f06b1afd47b812732fb521b146fd9_1ac1f06b1afd47b812732fb521b146fd9" kindref="member">rapidxml::parse_trim_whitespace</a> flag. By default, whitespace is not normalized. If this flag is spe [...]
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_45751cf2f38fd6915f35b3122b46d5b6_145751cf2f38fd6915f35b3122b46d5b6">
+				constant
+			 parse_default</h3><h4>Synopsis</h4><code class="synopsis">const int parse_default
+											  = 0;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Parse flags which represent default behaviour of the parser. This is always equal to 0, so that all other flags can be simply ored together. Normally there is no need to inconveniently disable flags by anding with their negated (~) values. This also means that meaning of each flag is a <i>negation</i> of the default setting. For example, if flag name is <a href="#namespacerapidxml_ccde57f605 [...]
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_a97ba1a0a79a6d66f4eef3612508d943_1a97ba1a0a79a6d66f4eef3612508d943">
+				constant
+			 parse_non_destructive</h3><h4>Synopsis</h4><code class="synopsis">const int parse_non_destructive
+											  = parse_no_string_terminators | parse_no_entity_translation;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">A combination of parse flags that forbids any modifications of the source text. This also results in faster parsing. However, note that the following will occur: <ul><li><para>names and values of nodes will not be zero terminated, you have to use <a href="#classrapidxml_1_1xml__base_0dae694c8f7e4d89f1003e2f3a15a43c_10dae694c8f7e4d89f1003e2f3a15a43c" kindref="member">xml_base::name_size()</a> [...]
+See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_398c5476e76102f8bd76c10bb0abbe10_1398c5476e76102f8bd76c10bb0abbe10">
+				constant
+			 parse_fastest</h3><h4>Synopsis</h4><code class="synopsis">const int parse_fastest
+											  = parse_non_destructive | parse_no_data_nodes;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_b4f2515265facb42291570307924bd57_1b4f2515265facb42291570307924bd57">
+				constant
+			 parse_full</h3><h4>Synopsis</h4><code class="synopsis">const int parse_full
+											  = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">A combination of parse flags resulting in largest amount of data being extracted. This usually results in slowest parsing. <br/><br/>
+ See <a href="#classrapidxml_1_1xml__document_8338ce6042e7b04d5a42144fb446b69c_18338ce6042e7b04d5a42144fb446b69c" kindref="member">xml_document::parse()</a> function. </para><p/><h3 class="reference-header" id="namespacerapidxml_b08b8d4293c203b69ed6c5ae77ac1907_1b08b8d4293c203b69ed6c5ae77ac1907">
+				constant
+			 print_no_indenting</h3><h4>Synopsis</h4><code class="synopsis">const int print_no_indenting
+											  = 0x1;
+									  </code><h4>Description</h4><para xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Printer flag instructing the printer to suppress indenting of XML. See <a href="#namespacerapidxml_b94d570fc4c4ab2423813cd0243326b1_1b94d570fc4c4ab2423813cd0243326b1" kindref="member">print()</a> function. </para><p/></body></html>
\ No newline at end of file
diff --git a/include/cereal/external/rapidxml/rapidxml.hpp b/include/cereal/external/rapidxml/rapidxml.hpp
new file mode 100644
index 0000000..424ec65
--- /dev/null
+++ b/include/cereal/external/rapidxml/rapidxml.hpp
@@ -0,0 +1,2618 @@
+#ifndef RAPIDXML_HPP_INCLUDED
+#define RAPIDXML_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+
+// If standard library is disabled, user must provide implementations of required functions and typedefs
+#if !defined(RAPIDXML_NO_STDLIB)
+    #include <cstdlib>      // For std::size_t
+    #include <cassert>      // For assert
+    #include <new>          // For placement new
+#endif
+
+// On MSVC, disable "conditional expression is constant" warning (level 4).
+// This warning is almost impossible to avoid with certain types of templated code
+#ifdef _MSC_VER
+    #pragma warning(push)
+    #pragma warning(disable:4127)   // Conditional expression is constant
+    #pragma warning(disable:4100)   // unreferenced formal parameter
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// RAPIDXML_PARSE_ERROR
+
+#if defined(RAPIDXML_NO_EXCEPTIONS)
+
+#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
+
+namespace rapidxml
+{
+    //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS,
+    //! this function is called to notify user about the error.
+    //! It must be defined by the user.
+    //! <br><br>
+    //! This function cannot return. If it does, the results are undefined.
+    //! <br><br>
+    //! A very simple definition might look like that:
+    //! <pre>
+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! </pre>
+    //! \param what Human readable description of the error.
+    //! \param where Pointer to character data where error was detected.
+    void parse_error_handler(const char *what, void *where);
+}
+
+#else
+
+#include <exception>    // For std::exception
+
+#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
+
+namespace rapidxml
+{
+
+    //! Parse error exception.
+    //! This exception is thrown by the parser when an error occurs.
+    //! Use what() function to get human-readable error message.
+    //! Use where() function to get a pointer to position within source text where error was detected.
+    //! <br><br>
+    //! If throwing exceptions by the parser is undesirable,
+    //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
+    //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
+    //! This function must be defined by the user.
+    //! <br><br>
+    //! This class derives from <code>std::exception</code> class.
+    class parse_error: public std::exception
+    {
+
+    public:
+
+        //! Constructs parse error
+        parse_error(const char *what_, void *where_)
+            : m_what(what_)
+            , m_where(where_)
+        {
+        }
+
+        //! Gets human readable description of error.
+        //! \return Pointer to null terminated description of the error.
+        virtual const char *what() const throw()
+        {
+            return m_what;
+        }
+
+        //! Gets pointer to character data where error happened.
+        //! Ch should be the same as char type of xml_document that produced the error.
+        //! \return Pointer to location within the parsed string where error occured.
+        template<class Ch>
+        Ch *where() const
+        {
+            return reinterpret_cast<Ch *>(m_where);
+        }
+
+    private:
+
+        const char *m_what;
+        void *m_where;
+
+    };
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// Pool sizes
+
+#ifndef RAPIDXML_STATIC_POOL_SIZE
+    // Size of static memory block of memory_pool.
+    // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+    // No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
+    #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
+    // Size of dynamic memory block of memory_pool.
+    // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+    // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
+    #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_ALIGNMENT
+    // Memory allocation alignment.
+    // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
+    // All memory allocations for nodes, attributes and strings will be aligned to this value.
+    // This must be a power of 2 and at least 1, otherwise memory_pool will not work.
+    #define RAPIDXML_ALIGNMENT sizeof(void *)
+#endif
+
+namespace rapidxml
+{
+    // Forward declarations
+    template<class Ch> class xml_node;
+    template<class Ch> class xml_attribute;
+    template<class Ch> class xml_document;
+
+    //! Enumeration listing all node types produced by the parser.
+    //! Use xml_node::type() function to query node type.
+    enum node_type
+    {
+        node_document,      //!< A document node. Name and value are empty.
+        node_element,       //!< An element node. Name contains element name. Value contains text of first data node.
+        node_data,          //!< A data node. Name is empty. Value contains data text.
+        node_cdata,         //!< A CDATA node. Name is empty. Value contains data text.
+        node_comment,       //!< A comment node. Name is empty. Value contains comment text.
+        node_declaration,   //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
+        node_doctype,       //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
+        node_pi             //!< A PI node. Name contains target. Value contains instructions.
+    };
+
+    ///////////////////////////////////////////////////////////////////////
+    // Parsing flags
+
+    //! Parse flag instructing the parser to not create data nodes.
+    //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_data_nodes = 0x1;
+
+    //! Parse flag instructing the parser to not use text of first data node as a value of parent element.
+    //! Can be combined with other flags by use of | operator.
+    //! Note that child data nodes of element node take precendence over its value when printing.
+    //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored.
+    //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_element_values = 0x2;
+
+    //! Parse flag instructing the parser to not place zero terminators after strings in the source text.
+    //! By default zero terminators are placed, modifying source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_string_terminators = 0x4;
+
+    //! Parse flag instructing the parser to not translate entities in the source text.
+    //! By default entities are translated, modifying source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_entity_translation = 0x8;
+
+    //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters.
+    //! By default, UTF-8 handling is enabled.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_utf8 = 0x10;
+
+    //! Parse flag instructing the parser to create XML declaration node.
+    //! By default, declaration node is not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_declaration_node = 0x20;
+
+    //! Parse flag instructing the parser to create comments nodes.
+    //! By default, comment nodes are not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_comment_nodes = 0x40;
+
+    //! Parse flag instructing the parser to create DOCTYPE node.
+    //! By default, doctype node is not created.
+    //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_doctype_node = 0x80;
+
+    //! Parse flag instructing the parser to create PI nodes.
+    //! By default, PI nodes are not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_pi_nodes = 0x100;
+
+    //! Parse flag instructing the parser to validate closing tag names.
+    //! If not set, name inside closing tag is irrelevant to the parser.
+    //! By default, closing tags are not validated.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_validate_closing_tags = 0x200;
+
+    //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes.
+    //! By default, whitespace is not trimmed.
+    //! This flag does not cause the parser to modify source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_trim_whitespace = 0x400;
+
+    //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character.
+    //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag.
+    //! By default, whitespace is not normalized.
+    //! If this flag is specified, source text will be modified.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_normalize_whitespace = 0x800;
+
+    // Compound flags
+
+    //! Parse flags which represent default behaviour of the parser.
+    //! This is always equal to 0, so that all other flags can be simply ored together.
+    //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values.
+    //! This also means that meaning of each flag is a <i>negation</i> of the default setting.
+    //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default,
+    //! and using the flag will disable it.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_default = 0;
+
+    //! A combination of parse flags that forbids any modifications of the source text.
+    //! This also results in faster parsing. However, note that the following will occur:
+    //! <ul>
+    //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li>
+    //! <li>entities will not be translated</li>
+    //! <li>whitespace will not be normalized</li>
+    //! </ul>
+    //! See xml_document::parse() function.
+    const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation;
+
+    //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_fastest = parse_non_destructive | parse_no_data_nodes;
+
+    //! A combination of parse flags resulting in largest amount of data being extracted.
+    //! This usually results in slowest parsing.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
+
+    ///////////////////////////////////////////////////////////////////////
+    // Internals
+
+    //! \cond internal
+    namespace internal
+    {
+
+        // Struct that contains lookup tables for the parser
+        // It must be a template to allow correct linking (because it has static data members, which are defined in a header file).
+        template<int Dummy>
+        struct lookup_tables
+        {
+            static const unsigned char lookup_whitespace[256];              // Whitespace table
+            static const unsigned char lookup_node_name[256];               // Node name table
+            static const unsigned char lookup_text[256];                    // Text table
+            static const unsigned char lookup_text_pure_no_ws[256];         // Text table
+            static const unsigned char lookup_text_pure_with_ws[256];       // Text table
+            static const unsigned char lookup_attribute_name[256];          // Attribute name table
+            static const unsigned char lookup_attribute_data_1[256];        // Attribute data table with single quote
+            static const unsigned char lookup_attribute_data_1_pure[256];   // Attribute data table with single quote
+            static const unsigned char lookup_attribute_data_2[256];        // Attribute data table with double quotes
+            static const unsigned char lookup_attribute_data_2_pure[256];   // Attribute data table with double quotes
+            static const unsigned char lookup_digits[256];                  // Digits
+            static const unsigned char lookup_upcase[256];                  // To uppercase conversion table for ASCII characters
+        };
+
+        // Find length of the string
+        template<class Ch>
+        inline std::size_t measure(const Ch *p)
+        {
+            const Ch *tmp = p;
+            while (*tmp)
+                ++tmp;
+            return tmp - p;
+        }
+
+        // Compare strings for equality
+        template<class Ch>
+        inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive)
+        {
+            if (size1 != size2)
+                return false;
+            if (case_sensitive)
+            {
+                for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+                    if (*p1 != *p2)
+                        return false;
+            }
+            else
+            {
+                for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+                    if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
+                        return false;
+            }
+            return true;
+        }
+
+        template<class Ch>
+        inline bool preserve_space(xml_node<Ch>* node)
+        {
+            const Ch preserve_value[] = { Ch('p'), Ch('r'), Ch('e'), Ch('s'), Ch('e'), Ch('r'), Ch('v'), Ch('e') };
+            const xml_attribute<Ch>* space = node->first_attribute("xml:space");
+            return space && internal::compare(space->value(), space->value_size(), preserve_value, sizeof(preserve_value) / sizeof(Ch), true);
+        }
+    }
+    //! \endcond
+
+    ///////////////////////////////////////////////////////////////////////
+    // Memory pool
+
+    //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation.
+    //! In most cases, you will not need to use this class directly.
+    //! However, if you need to create nodes manually or modify names/values of nodes,
+    //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory.
+    //! Not only is this faster than allocating them by using <code>new</code> operator,
+    //! but also their lifetime will be tied to the lifetime of document,
+    //! possibly simplyfing memory management.
+    //! <br><br>
+    //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool.
+    //! You can also call allocate_string() function to allocate strings.
+    //! Such strings can then be used as names or values of nodes without worrying about their lifetime.
+    //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called,
+    //! or when the pool is destroyed.
+    //! <br><br>
+    //! It is also possible to create a standalone memory_pool, and use it
+    //! to allocate nodes, whose lifetime will not be tied to any document.
+    //! <br><br>
+    //! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory.
+    //! Until static memory is exhausted, no dynamic memory allocations are done.
+    //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
+    //! by using global <code>new[]</code> and <code>delete[]</code> operators.
+    //! This behaviour can be changed by setting custom allocation routines.
+    //! Use set_allocator() function to set them.
+    //! <br><br>
+    //! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes.
+    //! This value defaults to the size of pointer on target architecture.
+    //! <br><br>
+    //! To obtain absolutely top performance from the parser,
+    //! it is important that all nodes are allocated from a single, contiguous block of memory.
+    //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
+    //! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code>
+    //! to obtain best wasted memory to performance compromise.
+    //! To do it, define their values before rapidxml.hpp file is included.
+    //! \param Ch Character type of created nodes.
+    template<class Ch = char>
+    class memory_pool
+    {
+
+    public:
+
+        //! \cond internal
+        typedef void *(alloc_func)(std::size_t);       // Type of user-defined function used to allocate memory
+        typedef void (free_func)(void *);              // Type of user-defined function used to free memory
+        //! \endcond
+
+        //! Constructs empty pool with default allocator functions.
+        memory_pool()
+            : m_alloc_func(0)
+            , m_free_func(0)
+        {
+            init();
+        }
+
+        //! Destroys pool and frees all the memory.
+        //! This causes memory occupied by nodes allocated by the pool to be freed.
+        //! Nodes allocated from the pool are no longer valid.
+        ~memory_pool()
+        {
+            clear();
+        }
+
+        //! Allocates a new node from the pool, and optionally assigns name and value to it.
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param type Type of node to create.
+        //! \param name Name to assign to the node, or 0 to assign no name.
+        //! \param value Value to assign to the node, or 0 to assign no value.
+        //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+        //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+        //! \return Pointer to allocated node. This pointer will never be NULL.
+        xml_node<Ch> *allocate_node(node_type type,
+                                    const Ch *name = 0, const Ch *value = 0,
+                                    std::size_t name_size = 0, std::size_t value_size = 0)
+        {
+            void *memory = allocate_aligned(sizeof(xml_node<Ch>));
+            xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
+            if (name)
+            {
+                if (name_size > 0)
+                    node->name(name, name_size);
+                else
+                    node->name(name);
+            }
+            if (value)
+            {
+                if (value_size > 0)
+                    node->value(value, value_size);
+                else
+                    node->value(value);
+            }
+            return node;
+        }
+
+        //! Allocates a new attribute from the pool, and optionally assigns name and value to it.
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param name Name to assign to the attribute, or 0 to assign no name.
+        //! \param value Value to assign to the attribute, or 0 to assign no value.
+        //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+        //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+        //! \return Pointer to allocated attribute. This pointer will never be NULL.
+        xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0,
+                                              std::size_t name_size = 0, std::size_t value_size = 0)
+        {
+            void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
+            xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
+            if (name)
+            {
+                if (name_size > 0)
+                    attribute->name(name, name_size);
+                else
+                    attribute->name(name);
+            }
+            if (value)
+            {
+                if (value_size > 0)
+                    attribute->value(value, value_size);
+                else
+                    attribute->value(value);
+            }
+            return attribute;
+        }
+
+        //! Allocates a char array of given size from the pool, and optionally copies a given string to it.
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param source String to initialize the allocated memory with, or 0 to not initialize it.
+        //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.
+        //! \return Pointer to allocated char array. This pointer will never be NULL.
+        Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
+        {
+            assert(source || size);     // Either source or size (or both) must be specified
+            if (size == 0)
+                size = internal::measure(source) + 1;
+            Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
+            if (source)
+                for (std::size_t i = 0; i < size; ++i)
+                    result[i] = source[i];
+            return result;
+        }
+
+        //! Clones an xml_node and its hierarchy of child nodes and attributes.
+        //! Nodes and attributes are allocated from this memory pool.
+        //! Names and values are not cloned, they are shared between the clone and the source.
+        //! Result node can be optionally specified as a second parameter,
+        //! in which case its contents will be replaced with cloned source node.
+        //! This is useful when you want to clone entire document.
+        //! \param source Node to clone.
+        //! \param result Node to put results in, or 0 to automatically allocate result node
+        //! \return Pointer to cloned node. This pointer will never be NULL.
+        xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0)
+        {
+            // Prepare result node
+            if (result)
+            {
+                result->remove_all_attributes();
+                result->remove_all_nodes();
+                result->type(source->type());
+            }
+            else
+                result = allocate_node(source->type());
+
+            // Clone name and value
+            result->name(source->name(), source->name_size());
+            result->value(source->value(), source->value_size());
+
+            // Clone child nodes and attributes
+            for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling())
+                result->append_node(clone_node(child));
+            for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute())
+                result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
+
+            return result;
+        }
+
+        //! Clears the pool.
+        //! This causes memory occupied by nodes allocated by the pool to be freed.
+        //! Any nodes or strings allocated from the pool will no longer be valid.
+        void clear()
+        {
+            while (m_begin != m_static_memory)
+            {
+                char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
+                if (m_free_func)
+                    m_free_func(m_begin);
+                else
+                    delete[] m_begin;
+                m_begin = previous_begin;
+            }
+            init();
+        }
+
+        //! Sets or resets the user-defined memory allocation functions for the pool.
+        //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined.
+        //! Allocation function must not return invalid pointer on failure. It should either throw,
+        //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program.
+        //! If it returns invalid pointer, results are undefined.
+        //! <br><br>
+        //! User defined allocation functions must have the following forms:
+        //! <br><code>
+        //! <br>void *allocate(std::size_t size);
+        //! <br>void free(void *pointer);
+        //! </code><br>
+        //! \param af Allocation function, or 0 to restore default function
+        //! \param ff Free function, or 0 to restore default function
+        void set_allocator(alloc_func *af, free_func *ff)
+        {
+            assert(m_begin == m_static_memory && m_ptr == align(m_begin));    // Verify that no memory is allocated yet
+            m_alloc_func = af;
+            m_free_func = ff;
+        }
+
+    private:
+
+        struct header
+        {
+            char *previous_begin;
+        };
+
+        void init()
+        {
+            m_begin = m_static_memory;
+            m_ptr = align(m_begin);
+            m_end = m_static_memory + sizeof(m_static_memory);
+        }
+
+        char *align(char *ptr)
+        {
+            std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1));
+            return ptr + alignment;
+        }
+
+        char *allocate_raw(std::size_t size)
+        {
+            // Allocate
+            void *memory;
+            if (m_alloc_func)   // Allocate memory using either user-specified allocation function or global operator new[]
+            {
+                memory = m_alloc_func(size);
+                assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
+            }
+            else
+            {
+                memory = new char[size];
+#ifdef RAPIDXML_NO_EXCEPTIONS
+                if (!memory)            // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
+                    RAPIDXML_PARSE_ERROR("out of memory", 0);
+#endif
+            }
+            return static_cast<char *>(memory);
+        }
+
+        void *allocate_aligned(std::size_t size)
+        {
+            // Calculate aligned pointer
+            char *result = align(m_ptr);
+
+            // If not enough memory left in current pool, allocate a new pool
+            if (result + size > m_end)
+            {
+                // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE)
+                std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
+                if (pool_size < size)
+                    pool_size = size;
+
+                // Allocate
+                std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size;     // 2 alignments required in worst case: one for header, one for actual allocation
+                char *raw_memory = allocate_raw(alloc_size);
+
+                // Setup new pool in allocated memory
+                char *pool = align(raw_memory);
+                header *new_header = reinterpret_cast<header *>(pool);
+                new_header->previous_begin = m_begin;
+                m_begin = raw_memory;
+                m_ptr = pool + sizeof(header);
+                m_end = raw_memory + alloc_size;
+
+                // Calculate aligned pointer again using new pool
+                result = align(m_ptr);
+            }
+
+            // Update pool and return aligned pointer
+            m_ptr = result + size;
+            return result;
+        }
+
+        char *m_begin;                                      // Start of raw memory making up current pool
+        char *m_ptr;                                        // First free byte in current pool
+        char *m_end;                                        // One past last available byte in current pool
+        char m_static_memory[RAPIDXML_STATIC_POOL_SIZE];    // Static raw memory
+        alloc_func *m_alloc_func;                           // Allocator function, or 0 if default is to be used
+        free_func *m_free_func;                             // Free function, or 0 if default is to be used
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML base
+
+    //! Base class for xml_node and xml_attribute implementing common functions:
+    //! name(), name_size(), value(), value_size() and parent().
+    //! \param Ch Character type to use
+    template<class Ch = char>
+    class xml_base
+    {
+
+    public:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+
+        // Construct a base with empty name, value and parent
+        xml_base()
+            : m_name(0)
+            , m_value(0)
+            , m_parent(0)
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node data access
+
+        //! Gets name of the node.
+        //! Interpretation of name depends on type of node.
+        //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+        //! <br><br>
+        //! Use name_size() function to determine length of the name.
+        //! \return Name of node, or empty string if node has no name.
+        Ch *name() const
+        {
+            return m_name ? m_name : nullstr();
+        }
+
+        //! Gets size of node name, not including terminator character.
+        //! This function works correctly irrespective of whether name is or is not zero terminated.
+        //! \return Size of node name, in characters.
+        std::size_t name_size() const
+        {
+            return m_name ? m_name_size : 0;
+        }
+
+        //! Gets value of node.
+        //! Interpretation of value depends on type of node.
+        //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+        //! <br><br>
+        //! Use value_size() function to determine length of the value.
+        //! \return Value of node, or empty string if node has no value.
+        Ch *value() const
+        {
+            return m_value ? m_value : nullstr();
+        }
+
+        //! Gets size of node value, not including terminator character.
+        //! This function works correctly irrespective of whether value is or is not zero terminated.
+        //! \return Size of node value, in characters.
+        std::size_t value_size() const
+        {
+            return m_value ? m_value_size : 0;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node modification
+
+        //! Sets name of node to a non zero-terminated string.
+        //! See \ref ownership_of_strings.
+        //! <br><br>
+        //! Note that node does not own its name or value, it only stores a pointer to it.
+        //! It will not delete or otherwise free the pointer on destruction.
+        //! It is reponsibility of the user to properly manage lifetime of the string.
+        //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+        //! on destruction of the document the string will be automatically freed.
+        //! <br><br>
+        //! Size of name must be specified separately, because name does not have to be zero terminated.
+        //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+        //! \param name Name of node to set. Does not have to be zero terminated.
+        //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
+        void name(const Ch *name_, std::size_t size)
+        {
+            m_name = const_cast<Ch *>(name_);
+            m_name_size = size;
+        }
+
+        //! Sets name of node to a zero-terminated string.
+        //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
+        //! \param name Name of node to set. Must be zero terminated.
+        void name(const Ch *name_)
+        {
+            this->name(name_, internal::measure(name_));
+        }
+
+        //! Sets value of node to a non zero-terminated string.
+        //! See \ref ownership_of_strings.
+        //! <br><br>
+        //! Note that node does not own its name or value, it only stores a pointer to it.
+        //! It will not delete or otherwise free the pointer on destruction.
+        //! It is reponsibility of the user to properly manage lifetime of the string.
+        //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+        //! on destruction of the document the string will be automatically freed.
+        //! <br><br>
+        //! Size of value must be specified separately, because it does not have to be zero terminated.
+        //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+        //! <br><br>
+        //! If an element has a child node of type node_data, it will take precedence over element value when printing.
+        //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
+        //! \param value value of node to set. Does not have to be zero terminated.
+        //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
+        void value(const Ch *value_, std::size_t size)
+        {
+            m_value = const_cast<Ch *>(value_);
+            m_value_size = size;
+        }
+
+        //! Sets value of node to a zero-terminated string.
+        //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
+        //! \param value Vame of node to set. Must be zero terminated.
+        void value(const Ch *value_)
+        {
+            this->value(value_, internal::measure(value_));
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+
+        //! Gets node parent.
+        //! \return Pointer to parent node, or 0 if there is no parent.
+        xml_node<Ch> *parent() const
+        {
+            return m_parent;
+        }
+
+    protected:
+
+        // Return empty string
+        static Ch *nullstr()
+        {
+            static Ch zero = Ch('\0');
+            return &zero;
+        }
+
+        Ch *m_name;                         // Name of node, or 0 if no name
+        Ch *m_value;                        // Value of node, or 0 if no value
+        std::size_t m_name_size;            // Length of node name, or undefined of no name
+        std::size_t m_value_size;           // Length of node value, or undefined if no value
+        xml_node<Ch> *m_parent;             // Pointer to parent node, or 0 if none
+
+    };
+
+    //! Class representing attribute node of XML document.
+    //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
+    //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing.
+    //! Thus, this text must persist in memory for the lifetime of attribute.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_attribute: public xml_base<Ch>
+    {
+
+        friend class xml_node<Ch>;
+
+    public:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+
+        //! Constructs an empty attribute with the specified type.
+        //! Consider using memory_pool of appropriate xml_document if allocating attributes manually.
+        xml_attribute()
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+
+        //! Gets document of which attribute is a child.
+        //! \return Pointer to document that contains this attribute, or 0 if there is no parent document.
+        xml_document<Ch> *document() const
+        {
+            if (xml_node<Ch> *node = this->parent())
+            {
+                while (node->parent())
+                    node = node->parent();
+                return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+            }
+            else
+                return 0;
+        }
+
+        //! Gets previous attribute, optionally matching attribute name.
+        //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+        {
+            if (name)
+            {
+                if (name_size == 0)
+                    name_size = internal::measure(name);
+                for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return this->m_parent ? m_prev_attribute : 0;
+        }
+
+        //! Gets next attribute, optionally matching attribute name.
+        //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *next_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
+        {
+            if (name_)
+            {
+                if (name_size_ == 0)
+                    name_size_ = internal::measure(name_);
+                for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return this->m_parent ? m_next_attribute : 0;
+        }
+
+    private:
+
+        xml_attribute<Ch> *m_prev_attribute;        // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero
+        xml_attribute<Ch> *m_next_attribute;        // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
+
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML node
+
+    //! Class representing a node of XML document.
+    //! Each node may have associated name and value strings, which are available through name() and value() functions.
+    //! Interpretation of name and value depends on type of the node.
+    //! Type of node can be determined by using type() function.
+    //! <br><br>
+    //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing.
+    //! Thus, this text must persist in the memory for the lifetime of node.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_node: public xml_base<Ch>
+    {
+
+    public:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+
+        //! Constructs an empty node with the specified type.
+        //! Consider using memory_pool of appropriate document to allocate nodes manually.
+        //! \param type Type of node to construct.
+        xml_node(node_type type_)
+            : m_type(type_)
+            , m_first_node(0)
+            , m_first_attribute(0)
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node data access
+
+        //! Gets type of node.
+        //! \return Type of node.
+        node_type type() const
+        {
+            return m_type;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+
+        //! Gets document of which node is a child.
+        //! \return Pointer to document that contains this node, or 0 if there is no parent document.
+        xml_document<Ch> *document() const
+        {
+            xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
+            while (node->parent())
+                node = node->parent();
+            return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+        }
+
+        //! Gets first child node, optionally matching node name.
+        //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found child, or 0 if not found.
+        xml_node<Ch> *first_node(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
+        {
+            if (name_)
+            {
+                if (name_size_ == 0)
+                    name_size_ = internal::measure(name_);
+                for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
+                    if (internal::compare(child->name(), child->name_size(), name_, name_size_, case_sensitive))
+                        return child;
+                return 0;
+            }
+            else
+                return m_first_node;
+        }
+
+        //! Gets last child node, optionally matching node name.
+        //! Behaviour is undefined if node has no children.
+        //! Use first_node() to test if node has children.
+        //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found child, or 0 if not found.
+        xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+        {
+            assert(m_first_node);  // Cannot query for last child if node has no children
+            if (name)
+            {
+                if (name_size == 0)
+                    name_size = internal::measure(name);
+                for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
+                    if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
+                        return child;
+                return 0;
+            }
+            else
+                return m_last_node;
+        }
+
+        //! Gets previous sibling node, optionally matching node name.
+        //! Behaviour is undefined if node has no parent.
+        //! Use parent() to test if node has a parent.
+        //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found sibling, or 0 if not found.
+        xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+        {
+            assert(this->m_parent);     // Cannot query for siblings if node has no parent
+            if (name)
+            {
+                if (name_size == 0)
+                    name_size = internal::measure(name);
+                for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
+                    if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
+                        return sibling;
+                return 0;
+            }
+            else
+                return m_prev_sibling;
+        }
+
+        //! Gets next sibling node, optionally matching node name.
+        //! Behaviour is undefined if node has no parent.
+        //! Use parent() to test if node has a parent.
+        //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found sibling, or 0 if not found.
+        xml_node<Ch> *next_sibling(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
+        {
+            assert(this->m_parent);     // Cannot query for siblings if node has no parent
+            if (name_)
+            {
+                if (name_size_ == 0)
+                    name_size_ = internal::measure(name_);
+                for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
+                    if (internal::compare(sibling->name(), sibling->name_size(), name_, name_size_, case_sensitive))
+                        return sibling;
+                return 0;
+            }
+            else
+                return m_next_sibling;
+        }
+
+        //! Gets first attribute of node, optionally matching attribute name.
+        //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *first_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
+        {
+            if (name_)
+            {
+                if (name_size_ == 0)
+                    name_size_ = internal::measure(name_);
+                for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return m_first_attribute;
+        }
+
+        //! Gets last attribute of node, optionally matching attribute name.
+        //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+        //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+        {
+            if (name)
+            {
+                if (name_size == 0)
+                    name_size = internal::measure(name);
+                for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return m_first_attribute ? m_last_attribute : 0;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node modification
+
+        //! Sets type of node.
+        //! \param type Type of node to set.
+        void type(node_type type_)
+        {
+            m_type = type_;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node manipulation
+
+        //! Prepends a new child node.
+        //! The prepended child becomes the first child, and all existing children are moved one position back.
+        //! \param child Node to prepend.
+        void prepend_node(xml_node<Ch> *child)
+        {
+            assert(child && !child->parent() && child->type() != node_document);
+            if (first_node())
+            {
+                child->m_next_sibling = m_first_node;
+                m_first_node->m_prev_sibling = child;
+            }
+            else
+            {
+                child->m_next_sibling = 0;
+                m_last_node = child;
+            }
+            m_first_node = child;
+            child->m_parent = this;
+            child->m_prev_sibling = 0;
+        }
+
+        //! Appends a new child node.
+        //! The appended child becomes the last child.
+        //! \param child Node to append.
+        void append_node(xml_node<Ch> *child)
+        {
+            assert(child && !child->parent() && child->type() != node_document);
+            if (first_node())
+            {
+                child->m_prev_sibling = m_last_node;
+                m_last_node->m_next_sibling = child;
+            }
+            else
+            {
+                child->m_prev_sibling = 0;
+                m_first_node = child;
+            }
+            m_last_node = child;
+            child->m_parent = this;
+            child->m_next_sibling = 0;
+        }
+
+        //! Inserts a new child node at specified place inside the node.
+        //! All children after and including the specified node are moved one position back.
+        //! \param where Place where to insert the child, or 0 to insert at the back.
+        //! \param child Node to insert.
+        void insert_node(xml_node<Ch> *where, xml_node<Ch> *child)
+        {
+            assert(!where || where->parent() == this);
+            assert(child && !child->parent() && child->type() != node_document);
+            if (where == m_first_node)
+                prepend_node(child);
+            else if (where == 0)
+                append_node(child);
+            else
+            {
+                child->m_prev_sibling = where->m_prev_sibling;
+                child->m_next_sibling = where;
+                where->m_prev_sibling->m_next_sibling = child;
+                where->m_prev_sibling = child;
+                child->m_parent = this;
+            }
+        }
+
+        //! Removes first child node.
+        //! If node has no children, behaviour is undefined.
+        //! Use first_node() to test if node has children.
+        void remove_first_node()
+        {
+            assert(first_node());
+            xml_node<Ch> *child = m_first_node;
+            m_first_node = child->m_next_sibling;
+            if (child->m_next_sibling)
+                child->m_next_sibling->m_prev_sibling = 0;
+            else
+                m_last_node = 0;
+            child->m_parent = 0;
+        }
+
+        //! Removes last child of the node.
+        //! If node has no children, behaviour is undefined.
+        //! Use first_node() to test if node has children.
+        void remove_last_node()
+        {
+            assert(first_node());
+            xml_node<Ch> *child = m_last_node;
+            if (child->m_prev_sibling)
+            {
+                m_last_node = child->m_prev_sibling;
+                child->m_prev_sibling->m_next_sibling = 0;
+            }
+            else
+                m_first_node = 0;
+            child->m_parent = 0;
+        }
+
+        //! Removes specified child from the node
+        // \param where Pointer to child to be removed.
+        void remove_node(xml_node<Ch> *where)
+        {
+            assert(where && where->parent() == this);
+            assert(first_node());
+            if (where == m_first_node)
+                remove_first_node();
+            else if (where == m_last_node)
+                remove_last_node();
+            else
+            {
+                where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
+                where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
+                where->m_parent = 0;
+            }
+        }
+
+        //! Removes all child nodes (but not attributes).
+        void remove_all_nodes()
+        {
+            for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
+                node->m_parent = 0;
+            m_first_node = 0;
+        }
+
+        //! Prepends a new attribute to the node.
+        //! \param attribute Attribute to prepend.
+        void prepend_attribute(xml_attribute<Ch> *attribute)
+        {
+            assert(attribute && !attribute->parent());
+            if (first_attribute())
+            {
+                attribute->m_next_attribute = m_first_attribute;
+                m_first_attribute->m_prev_attribute = attribute;
+            }
+            else
+            {
+                attribute->m_next_attribute = 0;
+                m_last_attribute = attribute;
+            }
+            m_first_attribute = attribute;
+            attribute->m_parent = this;
+            attribute->m_prev_attribute = 0;
+        }
+
+        //! Appends a new attribute to the node.
+        //! \param attribute Attribute to append.
+        void append_attribute(xml_attribute<Ch> *attribute)
+        {
+            assert(attribute && !attribute->parent());
+            if (first_attribute())
+            {
+                attribute->m_prev_attribute = m_last_attribute;
+                m_last_attribute->m_next_attribute = attribute;
+            }
+            else
+            {
+                attribute->m_prev_attribute = 0;
+                m_first_attribute = attribute;
+            }
+            m_last_attribute = attribute;
+            attribute->m_parent = this;
+            attribute->m_next_attribute = 0;
+        }
+
+        //! Inserts a new attribute at specified place inside the node.
+        //! All attributes after and including the specified attribute are moved one position back.
+        //! \param where Place where to insert the attribute, or 0 to insert at the back.
+        //! \param attribute Attribute to insert.
+        void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute)
+        {
+            assert(!where || where->parent() == this);
+            assert(attribute && !attribute->parent());
+            if (where == m_first_attribute)
+                prepend_attribute(attribute);
+            else if (where == 0)
+                append_attribute(attribute);
+            else
+            {
+                attribute->m_prev_attribute = where->m_prev_attribute;
+                attribute->m_next_attribute = where;
+                where->m_prev_attribute->m_next_attribute = attribute;
+                where->m_prev_attribute = attribute;
+                attribute->m_parent = this;
+            }
+        }
+
+        //! Removes first attribute of the node.
+        //! If node has no attributes, behaviour is undefined.
+        //! Use first_attribute() to test if node has attributes.
+        void remove_first_attribute()
+        {
+            assert(first_attribute());
+            xml_attribute<Ch> *attribute = m_first_attribute;
+            if (attribute->m_next_attribute)
+            {
+                attribute->m_next_attribute->m_prev_attribute = 0;
+            }
+            else
+                m_last_attribute = 0;
+            attribute->m_parent = 0;
+            m_first_attribute = attribute->m_next_attribute;
+        }
+
+        //! Removes last attribute of the node.
+        //! If node has no attributes, behaviour is undefined.
+        //! Use first_attribute() to test if node has attributes.
+        void remove_last_attribute()
+        {
+            assert(first_attribute());
+            xml_attribute<Ch> *attribute = m_last_attribute;
+            if (attribute->m_prev_attribute)
+            {
+                attribute->m_prev_attribute->m_next_attribute = 0;
+                m_last_attribute = attribute->m_prev_attribute;
+            }
+            else
+                m_first_attribute = 0;
+            attribute->m_parent = 0;
+        }
+
+        //! Removes specified attribute from node.
+        //! \param where Pointer to attribute to be removed.
+        void remove_attribute(xml_attribute<Ch> *where)
+        {
+            assert(first_attribute() && where->parent() == this);
+            if (where == m_first_attribute)
+                remove_first_attribute();
+            else if (where == m_last_attribute)
+                remove_last_attribute();
+            else
+            {
+                where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
+                where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
+                where->m_parent = 0;
+            }
+        }
+
+        //! Removes all attributes of node.
+        void remove_all_attributes()
+        {
+            for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
+                attribute->m_parent = 0;
+            m_first_attribute = 0;
+        }
+
+    private:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Restrictions
+
+        // No copying
+        xml_node(const xml_node &);
+        void operator =(const xml_node &);
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Data members
+
+        // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
+        // This is required for maximum performance, as it allows the parser to omit initialization of
+        // unneded/redundant values.
+        //
+        // The rules are as follows:
+        // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively
+        // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage
+        // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
+
+        node_type m_type;                       // Type of node; always valid
+        xml_node<Ch> *m_first_node;             // Pointer to first child node, or 0 if none; always valid
+        xml_node<Ch> *m_last_node;              // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero
+        xml_attribute<Ch> *m_first_attribute;   // Pointer to first attribute of node, or 0 if none; always valid
+        xml_attribute<Ch> *m_last_attribute;    // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero
+        xml_node<Ch> *m_prev_sibling;           // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+        xml_node<Ch> *m_next_sibling;           // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML document
+
+    //! This class represents root of the DOM hierarchy.
+    //! It is also an xml_node and a memory_pool through public inheritance.
+    //! Use parse() function to build a DOM tree from a zero-terminated XML text string.
+    //! parse() function allocates memory for nodes and attributes by using functions of xml_document,
+    //! which are inherited from memory_pool.
+    //! To access root node of the document, use the document itself, as if it was an xml_node.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_document: public xml_node<Ch>, public memory_pool<Ch>
+    {
+
+    public:
+
+        //! Constructs empty XML document
+        xml_document()
+            : xml_node<Ch>(node_document)
+        {
+        }
+
+        //! Parses zero-terminated XML string according to given flags.
+        //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used.
+        //! The string must persist for the lifetime of the document.
+        //! In case of error, rapidxml::parse_error exception will be thrown.
+        //! <br><br>
+        //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning.
+        //! Make sure that data is zero-terminated.
+        //! <br><br>
+        //! Document can be parsed into multiple times.
+        //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.
+        //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.
+        template<int Flags>
+        void parse(Ch *text)
+        {
+            assert(text);
+
+            // Remove current contents
+            this->remove_all_nodes();
+            this->remove_all_attributes();
+
+            // Parse BOM, if any
+            parse_bom<Flags>(text);
+
+            // Parse children
+            while (1)
+            {
+                // Skip whitespace before node
+                skip<whitespace_pred, Flags>(text);
+                if (*text == 0)
+                    break;
+
+                // Parse and append new child
+                if (*text == Ch('<'))
+                {
+                    ++text;     // Skip '<'
+                    if (xml_node<Ch> *node = parse_node<Flags>(text))
+                        this->append_node(node);
+                }
+                else
+                    RAPIDXML_PARSE_ERROR("expected <", text);
+            }
+
+        }
+
+        //! Clears the document by deleting all nodes and clearing the memory pool.
+        //! All nodes owned by document pool are destroyed.
+        void clear()
+        {
+            this->remove_all_nodes();
+            this->remove_all_attributes();
+            memory_pool<Ch>::clear();
+        }
+
+    private:
+
+        ///////////////////////////////////////////////////////////////////////
+        // Internal character utility functions
+
+        // Detect whitespace character
+        struct whitespace_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect node name character
+        struct node_name_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect attribute name character
+        struct attribute_name_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA)
+        struct text_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA) that does not require processing
+        struct text_pure_no_ws_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA) that does not require processing
+        struct text_pure_with_ws_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)];
+            }
+        };
+
+        // Detect attribute value character
+        template<Ch Quote>
+        struct attribute_value_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                if (Quote == Ch('\''))
+                    return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
+                if (Quote == Ch('\"'))
+                    return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
+                return 0;       // Should never be executed, to avoid warnings on Comeau
+            }
+        };
+
+        // Detect attribute value character
+        template<Ch Quote>
+        struct attribute_value_pure_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                if (Quote == Ch('\''))
+                    return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
+                if (Quote == Ch('\"'))
+                    return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
+                return 0;       // Should never be executed, to avoid warnings on Comeau
+            }
+        };
+
+        // Insert coded character, using UTF8 or 8-bit ASCII
+        template<int Flags>
+        static void insert_coded_character(Ch *&text, unsigned long code)
+        {
+            if (Flags & parse_no_utf8)
+            {
+                // Insert 8-bit ASCII character
+                // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
+                text[0] = static_cast<unsigned char>(code);
+                text += 1;
+            }
+            else
+            {
+                // Insert UTF8 sequence
+                if (code < 0x80)    // 1 byte sequence
+                {
+	                text[0] = static_cast<unsigned char>(code);
+                    text += 1;
+                }
+                else if (code < 0x800)  // 2 byte sequence
+                {
+	                text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[0] = static_cast<unsigned char>(code | 0xC0);
+                    text += 2;
+                }
+	            else if (code < 0x10000)    // 3 byte sequence
+                {
+	                text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[0] = static_cast<unsigned char>(code | 0xE0);
+                    text += 3;
+                }
+	            else if (code < 0x110000)   // 4 byte sequence
+                {
+	                text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+	                text[0] = static_cast<unsigned char>(code | 0xF0);
+                    text += 4;
+                }
+                else    // Invalid, only codes up to 0x10FFFF are allowed in Unicode
+                {
+                    RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
+                }
+            }
+        }
+
+        // Skip characters until predicate evaluates to true
+        template<class StopPred, int Flags>
+        static void skip(Ch *&text)
+        {
+            Ch *tmp = text;
+            while (StopPred::test(*tmp))
+                ++tmp;
+            text = tmp;
+        }
+
+        // Skip characters until predicate evaluates to true while doing the following:
+        // - replacing XML character entity references with proper characters (' & " < > &#...;)
+        // - condensing whitespace sequences to single space character
+        template<class StopPred, class StopPredPure, int Flags>
+        static Ch *skip_and_expand_character_refs(Ch *&text, bool preserve_space)
+        {
+            // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
+            if (Flags & parse_no_entity_translation &&
+                !(Flags & parse_normalize_whitespace) &&
+                !(Flags & parse_trim_whitespace))
+            {
+                skip<StopPred, Flags>(text);
+                return text;
+            }
+
+            // Use simple skip until first modification is detected
+            skip<StopPredPure, Flags>(text);
+
+            // Use translation skip
+            Ch *src = text;
+            Ch *dest = src;
+            while (StopPred::test(*src))
+            {
+                // If entity translation is enabled
+                if (!(Flags & parse_no_entity_translation))
+                {
+                    // Test if replacement is needed
+                    if (src[0] == Ch('&'))
+                    {
+                        switch (src[1])
+                        {
+
+                        // & '
+                        case Ch('a'):
+                            if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
+                            {
+                                *dest = Ch('&');
+                                ++dest;
+                                src += 5;
+                                continue;
+                            }
+                            if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
+                            {
+                                *dest = Ch('\'');
+                                ++dest;
+                                src += 6;
+                                continue;
+                            }
+                            break;
+
+                        // "
+                        case Ch('q'):
+                            if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
+                            {
+                                *dest = Ch('"');
+                                ++dest;
+                                src += 6;
+                                continue;
+                            }
+                            break;
+
+                        // >
+                        case Ch('g'):
+                            if (src[2] == Ch('t') && src[3] == Ch(';'))
+                            {
+                                *dest = Ch('>');
+                                ++dest;
+                                src += 4;
+                                continue;
+                            }
+                            break;
+
+                        // <
+                        case Ch('l'):
+                            if (src[2] == Ch('t') && src[3] == Ch(';'))
+                            {
+                                *dest = Ch('<');
+                                ++dest;
+                                src += 4;
+                                continue;
+                            }
+                            break;
+
+                        // &#...; - assumes ASCII
+                        case Ch('#'):
+                            if (src[2] == Ch('x'))
+                            {
+                                unsigned long code = 0;
+                                src += 3;   // Skip &#x
+                                while (1)
+                                {
+                                    unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+                                    if (digit == 0xFF)
+                                        break;
+                                    code = code * 16 + digit;
+                                    ++src;
+                                }
+                                insert_coded_character<Flags>(dest, code);    // Put character in output
+                            }
+                            else
+                            {
+                                unsigned long code = 0;
+                                src += 2;   // Skip &#
+                                while (1)
+                                {
+                                    unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+                                    if (digit == 0xFF)
+                                        break;
+                                    code = code * 10 + digit;
+                                    ++src;
+                                }
+                                insert_coded_character<Flags>(dest, code);    // Put character in output
+                            }
+                            if (*src == Ch(';'))
+                                ++src;
+                            else
+                                RAPIDXML_PARSE_ERROR("expected ;", src);
+                            continue;
+
+                        // Something else
+                        default:
+                            // Ignore, just copy '&' verbatim
+                            break;
+
+                        }
+                    }
+                }
+
+                // If whitespace condensing is enabled
+                if ((Flags & parse_normalize_whitespace) && !preserve_space)
+                {
+                    // Test if condensing is needed
+                    if (whitespace_pred::test(*src))
+                    {
+                        *dest = Ch(' '); ++dest;    // Put single space in dest
+                        ++src;                      // Skip first whitespace char
+                        // Skip remaining whitespace chars
+                        while (whitespace_pred::test(*src))
+                            ++src;
+                        continue;
+                    }
+                }
+
+                // No replacement, only copy character
+                *dest++ = *src++;
+
+            }
+
+            // Return new end
+            text = src;
+            return dest;
+
+        }
+
+        ///////////////////////////////////////////////////////////////////////
+        // Internal parsing functions
+
+        // Parse BOM, if any
+        template<int Flags>
+        void parse_bom(Ch *&text)
+        {
+            // UTF-8?
+            if (static_cast<unsigned char>(text[0]) == 0xEF &&
+                static_cast<unsigned char>(text[1]) == 0xBB &&
+                static_cast<unsigned char>(text[2]) == 0xBF)
+            {
+                text += 3;      // Skup utf-8 bom
+            }
+        }
+
+        // Parse XML declaration (<?xml...)
+        template<int Flags>
+        xml_node<Ch> *parse_xml_declaration(Ch *&text)
+        {
+            // If parsing of declaration is disabled
+            if (!(Flags & parse_declaration_node))
+            {
+                // Skip until end of declaration
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (!text[0])
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 2;    // Skip '?>'
+                return 0;
+            }
+
+            // Create declaration
+            xml_node<Ch> *declaration = this->allocate_node(node_declaration);
+
+            // Skip whitespace before attributes or ?>
+            skip<whitespace_pred, Flags>(text);
+
+            // Parse declaration attributes
+            parse_node_attributes<Flags>(text, declaration);
+
+            // Skip ?>
+            if (text[0] != Ch('?') || text[1] != Ch('>'))
+                RAPIDXML_PARSE_ERROR("expected ?>", text);
+            text += 2;
+
+            return declaration;
+        }
+
+        // Parse XML comment (<!--...)
+        template<int Flags>
+        xml_node<Ch> *parse_comment(Ch *&text)
+        {
+            // If parsing of comments is disabled
+            if (!(Flags & parse_comment_nodes))
+            {
+                // Skip until end of comment
+                while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+                {
+                    if (!text[0])
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 3;     // Skip '-->'
+                return 0;      // Do not produce comment node
+            }
+
+            // Remember value start
+            Ch *value_ = text;
+
+            // Skip until end of comment
+            while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+            {
+                if (!text[0])
+                    RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                ++text;
+            }
+
+            // Create comment node
+            xml_node<Ch> *comment = this->allocate_node(node_comment);
+            comment->value(value_, text - value_);
+
+            // Place zero terminator after comment value
+            if (!(Flags & parse_no_string_terminators))
+                *text = Ch('\0');
+
+            text += 3;     // Skip '-->'
+            return comment;
+        }
+
+        // Parse DOCTYPE
+        template<int Flags>
+        xml_node<Ch> *parse_doctype(Ch *&text)
+        {
+            // Remember value start
+            Ch *value_ = text;
+
+            // Skip to >
+            while (*text != Ch('>'))
+            {
+                // Determine character type
+                switch (*text)
+                {
+
+                // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
+                // This works for all W3C test files except for 2 most wicked
+                case Ch('['):
+                {
+                    ++text;     // Skip '['
+                    int depth = 1;
+                    while (depth > 0)
+                    {
+                        switch (*text)
+                        {
+                            case Ch('['): ++depth; break;
+                            case Ch(']'): --depth; break;
+                            case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                        }
+                        ++text;
+                    }
+                    break;
+                }
+
+                // Error on end of text
+                case Ch('\0'):
+                    RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+
+                // Other character, skip it
+                default:
+                    ++text;
+
+                }
+            }
+
+            // If DOCTYPE nodes enabled
+            if (Flags & parse_doctype_node)
+            {
+                // Create a new doctype node
+                xml_node<Ch> *doctype = this->allocate_node(node_doctype);
+                doctype->value(value_, text - value_);
+
+                // Place zero terminator after value
+                if (!(Flags & parse_no_string_terminators))
+                    *text = Ch('\0');
+
+                text += 1;      // skip '>'
+                return doctype;
+            }
+            else
+            {
+                text += 1;      // skip '>'
+                return 0;
+            }
+
+        }
+
+        // Parse PI
+        template<int Flags>
+        xml_node<Ch> *parse_pi(Ch *&text)
+        {
+            // If creation of PI nodes is enabled
+            if (Flags & parse_pi_nodes)
+            {
+                // Create pi node
+                xml_node<Ch> *pi = this->allocate_node(node_pi);
+
+                // Extract PI target name
+                Ch *name_ = text;
+                skip<node_name_pred, Flags>(text);
+                if (text == name_)
+                    RAPIDXML_PARSE_ERROR("expected PI target", text);
+                pi->name(name_, text - name_);
+
+                // Skip whitespace between pi target and pi
+                skip<whitespace_pred, Flags>(text);
+
+                // Remember start of pi
+                Ch *value_ = text;
+
+                // Skip to '?>'
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (*text == Ch('\0'))
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+
+                // Set pi value (verbatim, no entity expansion or whitespace normalization)
+                pi->value(value_, text - value_);
+
+                // Place zero terminator after name and value
+                if (!(Flags & parse_no_string_terminators))
+                {
+                    pi->name()[pi->name_size()] = Ch('\0');
+                    pi->value()[pi->value_size()] = Ch('\0');
+                }
+
+                text += 2;                          // Skip '?>'
+                return pi;
+            }
+            else
+            {
+                // Skip to '?>'
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (*text == Ch('\0'))
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 2;    // Skip '?>'
+                return 0;
+            }
+        }
+
+        // Parse and append data
+        // Return character that ends data.
+        // This is necessary because this character might have been overwritten by a terminating 0
+        template<int Flags>
+        Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
+        {
+            // Backup to contents start if whitespace trimming is disabled
+            if (!(Flags & parse_trim_whitespace))
+                text = contents_start;
+
+            const bool preserve_space =  internal::preserve_space(node);
+
+            // Skip until end of data
+            Ch *value_ = text, *end;
+            if ((Flags & parse_normalize_whitespace) && !preserve_space)
+                end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text, false);
+            else
+                end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text, preserve_space);
+
+            // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
+            if ((Flags & parse_trim_whitespace) && !preserve_space)
+            {
+                if (Flags & parse_normalize_whitespace)
+                {
+                    // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end
+                    if (*(end - 1) == Ch(' '))
+                        --end;
+                }
+                else
+                {
+                    // Backup until non-whitespace character is found
+                    while (whitespace_pred::test(*(end - 1)))
+                        --end;
+                }
+            }
+
+            // If characters are still left between end and value (this test is only necessary if normalization is enabled)
+            // Create new data node
+            if (!(Flags & parse_no_data_nodes))
+            {
+                xml_node<Ch> *data = this->allocate_node(node_data);
+                data->value(value_, end - value_);
+                node->append_node(data);
+            }
+
+            // Add data to parent node if no data exists yet
+            if (!(Flags & parse_no_element_values))
+                if (*node->value() == Ch('\0'))
+                    node->value(value_, end - value_);
+
+            // Place zero terminator after value
+            if (!(Flags & parse_no_string_terminators))
+            {
+                Ch ch = *text;
+                *end = Ch('\0');
+                return ch;      // Return character that ends data; this is required because zero terminator overwritten it
+            }
+
+            // Return character that ends data
+            return *text;
+        }
+
+        // Parse CDATA
+        template<int Flags>
+        xml_node<Ch> *parse_cdata(Ch *&text)
+        {
+            // If CDATA is disabled
+            if (Flags & parse_no_data_nodes)
+            {
+                // Skip until end of cdata
+                while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+                {
+                    if (!text[0])
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 3;      // Skip ]]>
+                return 0;       // Do not produce CDATA node
+            }
+
+            // Skip until end of cdata
+            Ch *value_ = text;
+            while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+            {
+                if (!text[0])
+                    RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                ++text;
+            }
+
+            // Create new cdata node
+            xml_node<Ch> *cdata = this->allocate_node(node_cdata);
+            cdata->value(value_, text - value_);
+
+            // Place zero terminator after value
+            if (!(Flags & parse_no_string_terminators))
+                *text = Ch('\0');
+
+            text += 3;      // Skip ]]>
+            return cdata;
+        }
+
+        // Parse element node
+        template<int Flags>
+        xml_node<Ch> *parse_element(Ch *&text)
+        {
+            // Create element node
+            xml_node<Ch> *element = this->allocate_node(node_element);
+
+            // Extract element name
+            Ch *name_ = text;
+            skip<node_name_pred, Flags>(text);
+            if (text == name_)
+                RAPIDXML_PARSE_ERROR("expected element name", text);
+            element->name(name_, text - name_);
+
+            // Skip whitespace between element name and attributes or >
+            skip<whitespace_pred, Flags>(text);
+
+            // Parse attributes, if any
+            parse_node_attributes<Flags>(text, element);
+
+            // Determine ending type
+            if (*text == Ch('>'))
+            {
+                ++text;
+                parse_node_contents<Flags>(text, element);
+            }
+            else if (*text == Ch('/'))
+            {
+                ++text;
+                if (*text != Ch('>'))
+                    RAPIDXML_PARSE_ERROR("expected >", text);
+                ++text;
+            }
+            else
+                RAPIDXML_PARSE_ERROR("expected >", text);
+
+            // Place zero terminator after name
+            if (!(Flags & parse_no_string_terminators))
+                element->name()[element->name_size()] = Ch('\0');
+
+            // Return parsed element
+            return element;
+        }
+
+        // Determine node type, and parse it
+        template<int Flags>
+        xml_node<Ch> *parse_node(Ch *&text)
+        {
+            // Parse proper node type
+            switch (text[0])
+            {
+
+            // <...
+            default:
+                // Parse and append element node
+                return parse_element<Flags>(text);
+
+            // <?...
+            case Ch('?'):
+                ++text;     // Skip ?
+                if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
+                    (text[1] == Ch('m') || text[1] == Ch('M')) &&
+                    (text[2] == Ch('l') || text[2] == Ch('L')) &&
+                    whitespace_pred::test(text[3]))
+                {
+                    // '<?xml ' - xml declaration
+                    text += 4;      // Skip 'xml '
+                    return parse_xml_declaration<Flags>(text);
+                }
+                else
+                {
+                    // Parse PI
+                    return parse_pi<Flags>(text);
+                }
+
+            // <!...
+            case Ch('!'):
+
+                // Parse proper subset of <! node
+                switch (text[1])
+                {
+
+                // <!-
+                case Ch('-'):
+                    if (text[2] == Ch('-'))
+                    {
+                        // '<!--' - xml comment
+                        text += 3;     // Skip '!--'
+                        return parse_comment<Flags>(text);
+                    }
+                    break;
+
+                // <![
+                case Ch('['):
+                    if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') &&
+                        text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('['))
+                    {
+                        // '<![CDATA[' - cdata
+                        text += 8;     // Skip '![CDATA['
+                        return parse_cdata<Flags>(text);
+                    }
+                    break;
+
+                // <!D
+                case Ch('D'):
+                    if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') &&
+                        text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') &&
+                        whitespace_pred::test(text[8]))
+                    {
+                        // '<!DOCTYPE ' - doctype
+                        text += 9;      // skip '!DOCTYPE '
+                        return parse_doctype<Flags>(text);
+                    }
+
+                }   // switch
+
+                // Attempt to skip other, unrecognized node types starting with <!
+                ++text;     // Skip !
+                while (*text != Ch('>'))
+                {
+                    if (*text == 0)
+                        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                ++text;     // Skip '>'
+                return 0;   // No node recognized
+
+            }
+        }
+
+        // Parse contents of the node - children, data etc.
+        template<int Flags>
+        void parse_node_contents(Ch *&text, xml_node<Ch> *node)
+        {
+            // For all children and text
+            while (1)
+            {
+                // Skip whitespace between > and node contents
+                Ch *contents_start = text;      // Store start of node contents before whitespace is skipped
+                skip<whitespace_pred, Flags>(text);
+                Ch next_char = *text;
+
+            // After data nodes, instead of continuing the loop, control jumps here.
+            // This is because zero termination inside parse_and_append_data() function
+            // would wreak havoc with the above code.
+            // Also, skipping whitespace after data nodes is unnecessary.
+            after_data_node:
+
+                // Determine what comes next: node closing, child node, data node, or 0?
+                switch (next_char)
+                {
+
+                // Node closing or child node
+                case Ch('<'):
+                    if (text[1] == Ch('/'))
+                    {
+                        Ch *contents_end = 0;
+                        if (internal::preserve_space(node))
+                        {
+                            contents_end = text;
+                        }
+
+                        // Node closing
+                        text += 2;      // Skip '</'
+                        if (Flags & parse_validate_closing_tags)
+                        {
+                            // Skip and validate closing tag name
+                            Ch *closing_name = text;
+                            skip<node_name_pred, Flags>(text);
+                            if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
+                                RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
+                        }
+                        else
+                        {
+                            // No validation, just skip name
+                            skip<node_name_pred, Flags>(text);
+                        }
+                        // Skip remaining whitespace after node name
+                        skip<whitespace_pred, Flags>(text);
+                        if (*text != Ch('>'))
+                            RAPIDXML_PARSE_ERROR("expected >", text);
+                        ++text;     // Skip '>'
+
+                        if (contents_end && contents_end != contents_start)
+                        {
+                            node->value(contents_start, contents_end - contents_start);
+                            node->value()[node->value_size()] = Ch('\0');
+                        }
+                        return;     // Node closed, finished parsing contents
+                    }
+                    else
+                    {
+                        // Child node
+                        ++text;     // Skip '<'
+                        if (xml_node<Ch> *child = parse_node<Flags>(text))
+                            node->append_node(child);
+                    }
+                    break;
+
+                // End of data - error
+                case Ch('\0'):
+                    RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+
+                // Data node
+                default:
+                    next_char = parse_and_append_data<Flags>(node, text, contents_start);
+                    goto after_data_node;   // Bypass regular processing after data nodes
+
+                }
+            }
+        }
+
+        // Parse XML attributes of the node
+        template<int Flags>
+        void parse_node_attributes(Ch *&text, xml_node<Ch> *node)
+        {
+            // For all attributes
+            while (attribute_name_pred::test(*text))
+            {
+                // Extract attribute name
+                Ch *name_ = text;
+                ++text;     // Skip first character of attribute name
+                skip<attribute_name_pred, Flags>(text);
+                if (text == name_)
+                    RAPIDXML_PARSE_ERROR("expected attribute name", name_);
+
+                // Create new attribute
+                xml_attribute<Ch> *attribute = this->allocate_attribute();
+                attribute->name(name_, text - name_);
+                node->append_attribute(attribute);
+
+                // Skip whitespace after attribute name
+                skip<whitespace_pred, Flags>(text);
+
+                // Skip =
+                if (*text != Ch('='))
+                    RAPIDXML_PARSE_ERROR("expected =", text);
+                ++text;
+
+                // Add terminating zero after name
+                if (!(Flags & parse_no_string_terminators))
+                    attribute->name()[attribute->name_size()] = 0;
+
+                // Skip whitespace after =
+                skip<whitespace_pred, Flags>(text);
+
+                // Skip quote and remember if it was ' or "
+                Ch quote = *text;
+                if (quote != Ch('\'') && quote != Ch('"'))
+                    RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+                ++text;
+
+                // Extract attribute value and expand char refs in it
+                Ch *value_ = text, *end;
+                const int AttFlags = Flags & ~parse_normalize_whitespace;   // No whitespace normalization in attributes
+                if (quote == Ch('\''))
+                    end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text, false);
+                else
+                    end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, false);
+
+                // Set attribute value
+                attribute->value(value_, end - value_);
+
+                // Make sure that end quote is present
+                if (*text != quote)
+                    RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+                ++text;     // Skip quote
+
+                // Add terminating zero after value
+                if (!(Flags & parse_no_string_terminators))
+                    attribute->value()[attribute->value_size()] = 0;
+
+                // Skip whitespace after attribute value
+                skip<whitespace_pred, Flags>(text);
+            }
+        }
+
+    };
+
+    //! \cond internal
+    namespace internal
+    {
+
+        // Whitespace (space \n \r \t)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,  // 0
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
+             1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 2
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 3
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 4
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 5
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 6
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 7
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 8
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 9
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // A
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // B
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // C
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // D
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // E
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0   // F
+        };
+
+        // Node name (anything but space \n \r \t / > ? \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_node_name[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) (anything but < \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled
+        // (anything but < \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled
+        // (anything but < \0 & space \n \r \t)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute name (anything but space \n \r \t / < > = ? ! \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with single quote (anything but ' \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with single quote that does not require processing (anything but ' \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with double quote (anything but " \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with double quote that does not require processing (anything but " \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  0,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Digits (dec and hex, 255 denotes end of numeric character reference)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_digits[256] =
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 0
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 1
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 2
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,  // 3
+           255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 4
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 5
+           255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 6
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 7
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 8
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 9
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // A
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // B
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // C
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // D
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // E
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255   // F
+        };
+
+        // Upper case conversion
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_upcase[256] =
+        {
+          // 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  A   B   C   D   E   F
+           0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,   // 0
+           16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,   // 1
+           32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,   // 2
+           48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,   // 3
+           64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 4
+           80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,   // 5
+           96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 6
+           80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127,  // 7
+           128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  // 8
+           144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  // 9
+           160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  // A
+           176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,  // B
+           192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,  // C
+           208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,  // D
+           224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,  // E
+           240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255   // F
+        };
+    }
+    //! \endcond
+
+}
+
+// Undefine internal macros
+#undef RAPIDXML_PARSE_ERROR
+
+// On MSVC, restore warnings state
+#ifdef _MSC_VER
+    #pragma warning(pop)
+#endif
+
+#endif
diff --git a/include/cereal/external/rapidxml/rapidxml_iterators.hpp b/include/cereal/external/rapidxml/rapidxml_iterators.hpp
new file mode 100644
index 0000000..5a301c4
--- /dev/null
+++ b/include/cereal/external/rapidxml/rapidxml_iterators.hpp
@@ -0,0 +1,173 @@
+#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
+#define RAPIDXML_ITERATORS_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+
+#include "rapidxml.hpp"
+
+namespace rapidxml
+{
+
+    //! Iterator of child nodes of xml_node
+    template<class Ch>
+    class node_iterator
+    {
+
+    public:
+
+        typedef typename xml_node<Ch> value_type;
+        typedef typename xml_node<Ch> &reference;
+        typedef typename xml_node<Ch> *pointer;
+        typedef std::ptrdiff_t difference_type;
+        typedef std::bidirectional_iterator_tag iterator_category;
+
+        node_iterator()
+            : m_node(0)
+        {
+        }
+
+        node_iterator(xml_node<Ch> *node)
+            : m_node(node->first_node())
+        {
+        }
+
+        reference operator *() const
+        {
+            assert(m_node);
+            return *m_node;
+        }
+
+        pointer operator->() const
+        {
+            assert(m_node);
+            return m_node;
+        }
+
+        node_iterator& operator++()
+        {
+            assert(m_node);
+            m_node = m_node->next_sibling();
+            return *this;
+        }
+
+        node_iterator operator++(int)
+        {
+            node_iterator tmp = *this;
+            ++this;
+            return tmp;
+        }
+
+        node_iterator& operator--()
+        {
+            assert(m_node && m_node->previous_sibling());
+            m_node = m_node->previous_sibling();
+            return *this;
+        }
+
+        node_iterator operator--(int)
+        {
+            node_iterator tmp = *this;
+            ++this;
+            return tmp;
+        }
+
+        bool operator ==(const node_iterator<Ch> &rhs)
+        {
+            return m_node == rhs.m_node;
+        }
+
+        bool operator !=(const node_iterator<Ch> &rhs)
+        {
+            return m_node != rhs.m_node;
+        }
+
+    private:
+
+        xml_node<Ch> *m_node;
+
+    };
+
+    //! Iterator of child attributes of xml_node
+    template<class Ch>
+    class attribute_iterator
+    {
+
+    public:
+
+        typedef typename xml_attribute<Ch> value_type;
+        typedef typename xml_attribute<Ch> &reference;
+        typedef typename xml_attribute<Ch> *pointer;
+        typedef std::ptrdiff_t difference_type;
+        typedef std::bidirectional_iterator_tag iterator_category;
+
+        attribute_iterator()
+            : m_attribute(0)
+        {
+        }
+
+        attribute_iterator(xml_node<Ch> *node)
+            : m_attribute(node->first_attribute())
+        {
+        }
+
+        reference operator *() const
+        {
+            assert(m_attribute);
+            return *m_attribute;
+        }
+
+        pointer operator->() const
+        {
+            assert(m_attribute);
+            return m_attribute;
+        }
+
+        attribute_iterator& operator++()
+        {
+            assert(m_attribute);
+            m_attribute = m_attribute->next_attribute();
+            return *this;
+        }
+
+        attribute_iterator operator++(int)
+        {
+            attribute_iterator tmp = *this;
+            ++this;
+            return tmp;
+        }
+
+        attribute_iterator& operator--()
+        {
+            assert(m_attribute && m_attribute->previous_attribute());
+            m_attribute = m_attribute->previous_attribute();
+            return *this;
+        }
+
+        attribute_iterator operator--(int)
+        {
+            attribute_iterator tmp = *this;
+            ++this;
+            return tmp;
+        }
+
+        bool operator ==(const attribute_iterator<Ch> &rhs)
+        {
+            return m_attribute == rhs.m_attribute;
+        }
+
+        bool operator !=(const attribute_iterator<Ch> &rhs)
+        {
+            return m_attribute != rhs.m_attribute;
+        }
+
+    private:
+
+        xml_attribute<Ch> *m_attribute;
+
+    };
+
+}
+
+#endif
diff --git a/include/cereal/external/rapidxml/rapidxml_print.hpp b/include/cereal/external/rapidxml/rapidxml_print.hpp
new file mode 100644
index 0000000..f890d41
--- /dev/null
+++ b/include/cereal/external/rapidxml/rapidxml_print.hpp
@@ -0,0 +1,424 @@
+#ifndef RAPIDXML_PRINT_HPP_INCLUDED
+#define RAPIDXML_PRINT_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+
+#include "rapidxml.hpp"
+
+// Only include streams if not disabled
+#ifndef RAPIDXML_NO_STREAMS
+    #include <ostream>
+    #include <iterator>
+#endif
+
+namespace rapidxml
+{
+
+    ///////////////////////////////////////////////////////////////////////
+    // Printing flags
+
+    const int print_no_indenting = 0x1;   //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
+
+    ///////////////////////////////////////////////////////////////////////
+    // Internal
+
+    //! \cond internal
+    namespace internal
+    {
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Internal character operations
+
+        // Copy characters from given range to given output iterator
+        template<class OutIt, class Ch>
+        inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
+        {
+            while (begin != end)
+                *out++ = *begin++;
+            return out;
+        }
+
+        // Copy characters from given range to given output iterator and expand
+        // characters into references (< > ' " &)
+        template<class OutIt, class Ch>
+        inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
+        {
+            while (begin != end)
+            {
+                if (*begin == noexpand)
+                {
+                    *out++ = *begin;    // No expansion, copy character
+                }
+                else
+                {
+                    switch (*begin)
+                    {
+                    case Ch('<'):
+                        *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
+                        break;
+                    case Ch('>'):
+                        *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
+                        break;
+                    case Ch('\''):
+                        *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
+                        break;
+                    case Ch('"'):
+                        *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
+                        break;
+                    case Ch('&'):
+                        *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
+                        break;
+                    default:
+                        *out++ = *begin;    // No expansion, copy character
+                    }
+                }
+                ++begin;    // Step to next character
+            }
+            return out;
+        }
+
+        // Fill given output iterator with repetitions of the same character
+        template<class OutIt, class Ch>
+        inline OutIt fill_chars(OutIt out, int n, Ch ch)
+        {
+            for (int i = 0; i < n; ++i)
+                *out++ = ch;
+            return out;
+        }
+
+        // Find character
+        template<class Ch, Ch ch>
+        inline bool find_char(const Ch *begin, const Ch *end)
+        {
+            while (begin != end)
+                if (*begin++ == ch)
+                    return true;
+            return false;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Internal printing operations
+
+        // Print node
+        template<class OutIt, class Ch>
+        inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
+
+        // Print children of the node
+        template<class OutIt, class Ch>
+        inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
+                out = print_node(out, child, flags, indent);
+            return out;
+        }
+
+        // Print attributes of the node
+        template<class OutIt, class Ch>
+        inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int /*flags*/)
+        {
+            for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
+            {
+                if (attribute->name() && attribute->value())
+                {
+                    // Print attribute name
+                    *out = Ch(' '), ++out;
+                    out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
+                    *out = Ch('='), ++out;
+                    // Print attribute value using appropriate quote type
+                    if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
+                    {
+                        *out = Ch('\''), ++out;
+                        out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
+                        *out = Ch('\''), ++out;
+                    }
+                    else
+                    {
+                        *out = Ch('"'), ++out;
+                        out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
+                        *out = Ch('"'), ++out;
+                    }
+                }
+            }
+            return out;
+        }
+
+        // Print data node
+        template<class OutIt, class Ch>
+        inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_data);
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
+            return out;
+        }
+
+        // Print data node
+        template<class OutIt, class Ch>
+        inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_cdata);
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'); ++out;
+            *out = Ch('!'); ++out;
+            *out = Ch('['); ++out;
+            *out = Ch('C'); ++out;
+            *out = Ch('D'); ++out;
+            *out = Ch('A'); ++out;
+            *out = Ch('T'); ++out;
+            *out = Ch('A'); ++out;
+            *out = Ch('['); ++out;
+            out = copy_chars(node->value(), node->value() + node->value_size(), out);
+            *out = Ch(']'); ++out;
+            *out = Ch(']'); ++out;
+            *out = Ch('>'); ++out;
+            return out;
+        }
+
+        // Print element node
+        template<class OutIt, class Ch>
+        inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_element);
+
+            // Print element name and attributes, if any
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'), ++out;
+            out = copy_chars(node->name(), node->name() + node->name_size(), out);
+            out = print_attributes(out, node, flags);
+
+            // If node is childless
+            if (node->value_size() == 0 && !node->first_node())
+            {
+                // Print childless node tag ending
+                *out = Ch('/'), ++out;
+                *out = Ch('>'), ++out;
+            }
+            else
+            {
+                // Print normal node tag ending
+                *out = Ch('>'), ++out;
+
+                // Test if node contains a single data node only (and no other nodes)
+                xml_node<Ch> *child = node->first_node();
+                if (!child)
+                {
+                    // If node has no children, only print its value without indenting
+                    out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
+                }
+                else if (child->next_sibling() == 0 && child->type() == node_data)
+                {
+                    // If node has a sole data child, only print its value without indenting
+                    out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
+                }
+                else
+                {
+                    // Print all children with full indenting
+                    if (!(flags & print_no_indenting))
+                        *out = Ch('\n'), ++out;
+                    out = print_children(out, node, flags, indent + 1);
+                    if (!(flags & print_no_indenting))
+                        out = fill_chars(out, indent, Ch('\t'));
+                }
+
+                // Print node end
+                *out = Ch('<'), ++out;
+                *out = Ch('/'), ++out;
+                out = copy_chars(node->name(), node->name() + node->name_size(), out);
+                *out = Ch('>'), ++out;
+            }
+            return out;
+        }
+
+        // Print declaration node
+        template<class OutIt, class Ch>
+        inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            // Print declaration start
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'), ++out;
+            *out = Ch('?'), ++out;
+            *out = Ch('x'), ++out;
+            *out = Ch('m'), ++out;
+            *out = Ch('l'), ++out;
+
+            // Print attributes
+            out = print_attributes(out, node, flags);
+
+            // Print declaration end
+            *out = Ch('?'), ++out;
+            *out = Ch('>'), ++out;
+
+            return out;
+        }
+
+        // Print comment node
+        template<class OutIt, class Ch>
+        inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_comment);
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'), ++out;
+            *out = Ch('!'), ++out;
+            *out = Ch('-'), ++out;
+            *out = Ch('-'), ++out;
+            out = copy_chars(node->value(), node->value() + node->value_size(), out);
+            *out = Ch('-'), ++out;
+            *out = Ch('-'), ++out;
+            *out = Ch('>'), ++out;
+            return out;
+        }
+
+        // Print doctype node
+        template<class OutIt, class Ch>
+        inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_doctype);
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'), ++out;
+            *out = Ch('!'), ++out;
+            *out = Ch('D'), ++out;
+            *out = Ch('O'), ++out;
+            *out = Ch('C'), ++out;
+            *out = Ch('T'), ++out;
+            *out = Ch('Y'), ++out;
+            *out = Ch('P'), ++out;
+            *out = Ch('E'), ++out;
+            *out = Ch(' '), ++out;
+            out = copy_chars(node->value(), node->value() + node->value_size(), out);
+            *out = Ch('>'), ++out;
+            return out;
+        }
+
+        // Print pi node
+        template<class OutIt, class Ch>
+        inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            assert(node->type() == node_pi);
+            if (!(flags & print_no_indenting))
+                out = fill_chars(out, indent, Ch('\t'));
+            *out = Ch('<'), ++out;
+            *out = Ch('?'), ++out;
+            out = copy_chars(node->name(), node->name() + node->name_size(), out);
+            *out = Ch(' '), ++out;
+            out = copy_chars(node->value(), node->value() + node->value_size(), out);
+            *out = Ch('?'), ++out;
+            *out = Ch('>'), ++out;
+            return out;
+        }
+
+        // Print node
+        template<class OutIt, class Ch>
+        inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+        {
+            // Print proper node type
+            switch (node->type())
+            {
+
+            // Document
+            case node_document:
+                out = print_children(out, node, flags, indent);
+                break;
+
+            // Element
+            case node_element:
+                out = print_element_node(out, node, flags, indent);
+                break;
+
+            // Data
+            case node_data:
+                out = print_data_node(out, node, flags, indent);
+                break;
+
+            // CDATA
+            case node_cdata:
+                out = print_cdata_node(out, node, flags, indent);
+                break;
+
+            // Declaration
+            case node_declaration:
+                out = print_declaration_node(out, node, flags, indent);
+                break;
+
+            // Comment
+            case node_comment:
+                out = print_comment_node(out, node, flags, indent);
+                break;
+
+            // Doctype
+            case node_doctype:
+                out = print_doctype_node(out, node, flags, indent);
+                break;
+
+            // Pi
+            case node_pi:
+                out = print_pi_node(out, node, flags, indent);
+                break;
+
+                // Unknown
+            default:
+                assert(0);
+                break;
+            }
+
+            // If indenting not disabled, add line break after node
+            if (!(flags & print_no_indenting))
+                *out = Ch('\n'), ++out;
+
+            // Return modified iterator
+            return out;
+        }
+
+    }
+    //! \endcond
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Printing
+
+    //! Prints XML to given output iterator.
+    //! \param out Output iterator to print to.
+    //! \param node Node to be printed. Pass xml_document to print entire document.
+    //! \param flags Flags controlling how XML is printed.
+    //! \return Output iterator pointing to position immediately after last character of printed text.
+    template<class OutIt, class Ch>
+    inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
+    {
+        return internal::print_node(out, &node, flags, 0);
+    }
+
+#ifndef RAPIDXML_NO_STREAMS
+
+    //! Prints XML to given output stream.
+    //! \param out Output stream to print to.
+    //! \param node Node to be printed. Pass xml_document to print entire document.
+    //! \param flags Flags controlling how XML is printed.
+    //! \return Output stream.
+    template<class Ch>
+    inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
+    {
+        print(std::ostream_iterator<Ch>(out), node, flags);
+        return out;
+    }
+
+    //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
+    //! \param out Output stream to print to.
+    //! \param node Node to be printed.
+    //! \return Output stream.
+    template<class Ch>
+    inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
+    {
+        return print(out, node);
+    }
+
+#endif
+
+}
+
+#endif
diff --git a/include/cereal/external/rapidxml/rapidxml_utils.hpp b/include/cereal/external/rapidxml/rapidxml_utils.hpp
new file mode 100644
index 0000000..290cc53
--- /dev/null
+++ b/include/cereal/external/rapidxml/rapidxml_utils.hpp
@@ -0,0 +1,121 @@
+#ifndef RAPIDXML_UTILS_HPP_INCLUDED
+#define RAPIDXML_UTILS_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
+
+#include "rapidxml.hpp"
+#include <vector>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+
+namespace rapidxml
+{
+
+    //! Represents data loaded from a file
+    template<class Ch = char>
+    class file
+    {
+
+    public:
+
+        //! Loads file into the memory. Data will be automatically destroyed by the destructor.
+        //! \param filename Filename to load.
+        file(const char *filename)
+        {
+            using namespace std;
+
+            // Open stream
+            basic_ifstream<Ch> stream(filename, ios::binary);
+            if (!stream)
+                throw runtime_error(string("cannot open file ") + filename);
+            stream.unsetf(ios::skipws);
+
+            // Determine stream size
+            stream.seekg(0, ios::end);
+            size_t size = stream.tellg();
+            stream.seekg(0);
+
+            // Load data and add terminating 0
+            m_data.resize(size + 1);
+            stream.read(&m_data.front(), static_cast<streamsize>(size));
+            m_data[size] = 0;
+        }
+
+        //! Loads file into the memory. Data will be automatically destroyed by the destructor
+        //! \param stream Stream to load from
+        file(std::basic_istream<Ch> &stream)
+        {
+            using namespace std;
+
+            // Load data and add terminating 0
+            stream.unsetf(ios::skipws);
+            m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
+            if (stream.fail() || stream.bad())
+                throw runtime_error("error reading stream");
+            m_data.push_back(0);
+        }
+
+        //! Gets file data.
+        //! \return Pointer to data of file.
+        Ch *data()
+        {
+            return &m_data.front();
+        }
+
+        //! Gets file data.
+        //! \return Pointer to data of file.
+        const Ch *data() const
+        {
+            return &m_data.front();
+        }
+
+        //! Gets file data size.
+        //! \return Size of file data, in characters.
+        std::size_t size() const
+        {
+            return m_data.size();
+        }
+
+    private:
+
+        std::vector<Ch> m_data;   // File data
+
+    };
+
+    //! Counts children of node. Time complexity is O(n).
+    //! \return Number of children of node
+    template<class Ch>
+    inline std::size_t count_children(xml_node<Ch> *node)
+    {
+        xml_node<Ch> *child = node->first_node();
+        std::size_t count = 0;
+        while (child)
+        {
+            ++count;
+            child = child->next_sibling();
+        }
+        return count;
+    }
+
+    //! Counts attributes of node. Time complexity is O(n).
+    //! \return Number of attributes of node
+    template<class Ch>
+    inline std::size_t count_attributes(xml_node<Ch> *node)
+    {
+        xml_attribute<Ch> *attr = node->first_attribute();
+        std::size_t count = 0;
+        while (attr)
+        {
+            ++count;
+            attr = attr->next_attribute();
+        }
+        return count;
+    }
+
+}
+
+#endif
diff --git a/include/cereal/macros.hpp b/include/cereal/macros.hpp
new file mode 100644
index 0000000..a670be6
--- /dev/null
+++ b/include/cereal/macros.hpp
@@ -0,0 +1,82 @@
+/*! \file macros.hpp
+    \brief Preprocessor macros that can customise the cereal library
+
+    By default, cereal looks for serialization functions with very
+    specific names, that is: serialize, load, save, load_minimal,
+    or save_minimal.
+
+    This file allows an advanced user to change these names to conform
+    to some other style or preference.  This is implemented using
+    preprocessor macros.
+
+    As a result of this, in internal cereal code you will see macros
+    used for these function names.  In user code, you should name
+    the functions like you normally would and not use the macros
+    to improve readability.
+    \ingroup utility */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CEREAL_MACROS_HPP_
+#define CEREAL_MACROS_HPP_
+
+#ifndef CEREAL_SERIALIZE_FUNCTION_NAME
+//! The serialization/deserialization function name to search for.
+/*! You can define @c CEREAL_SERIALIZE_FUNCTION_NAME to be different assuming
+    you do so before this file is included. */
+#define CEREAL_SERIALIZE_FUNCTION_NAME serialize
+#endif // CEREAL_SERIALIZE_FUNCTION_NAME
+
+#ifndef CEREAL_LOAD_FUNCTION_NAME
+//! The deserialization (load) function name to search for.
+/*! You can define @c CEREAL_LOAD_FUNCTION_NAME to be different assuming you do so
+    before this file is included. */
+#define CEREAL_LOAD_FUNCTION_NAME load
+#endif // CEREAL_LOAD_FUNCTION_NAME
+
+#ifndef CEREAL_SAVE_FUNCTION_NAME
+//! The serialization (save) function name to search for.
+/*! You can define @c CEREAL_SAVE_FUNCTION_NAME to be different assuming you do so
+    before this file is included. */
+#define CEREAL_SAVE_FUNCTION_NAME save
+#endif // CEREAL_SAVE_FUNCTION_NAME
+
+#ifndef CEREAL_LOAD_MINIMAL_FUNCTION_NAME
+//! The deserialization (load_minimal) function name to search for.
+/*! You can define @c CEREAL_LOAD_MINIMAL_FUNCTION_NAME to be different assuming you do so
+    before this file is included. */
+#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME load_minimal
+#endif // CEREAL_LOAD_MINIMAL_FUNCTION_NAME
+
+#ifndef CEREAL_SAVE_MINIMAL_FUNCTION_NAME
+//! The serialization (save_minimal) function name to search for.
+/*! You can define @c CEREAL_SAVE_MINIMAL_FUNCTION_NAME to be different assuming you do so
+    before this file is included. */
+#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME save_minimal
+#endif // CEREAL_SAVE_MINIMAL_FUNCTION_NAME
+
+#endif // CEREAL_MACROS_HPP_
diff --git a/include/cereal/types/array.hpp b/include/cereal/types/array.hpp
new file mode 100644
index 0000000..34766e9
--- /dev/null
+++ b/include/cereal/types/array.hpp
@@ -0,0 +1,79 @@
+/*! \file array.hpp
+    \brief Support for types found in \<array\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_ARRAY_HPP_
+#define CEREAL_TYPES_ARRAY_HPP_
+
+#include <cereal/cereal.hpp>
+#include <array>
+
+namespace cereal
+{
+  //! Saving for std::array primitive types
+  //! using binary serialization, if supported
+  template <class Archive, class T, size_t N> inline
+  typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
+  {
+    ar( binary_data( array.data(), sizeof(array) ) );
+  }
+
+  //! Loading for std::array primitive types
+  //! using binary serialization, if supported
+  template <class Archive, class T, size_t N> inline
+  typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
+  {
+    ar( binary_data( array.data(), sizeof(array) ) );
+  }
+
+  //! Saving for std::array all other types
+  template <class Archive, class T, size_t N> inline
+  typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
+  {
+    for( auto const & i : array )
+      ar( i );
+  }
+
+  //! Loading for std::array all other types
+  template <class Archive, class T, size_t N> inline
+  typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
+  {
+    for( auto & i : array )
+      ar( i );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_ARRAY_HPP_
diff --git a/include/cereal/types/base_class.hpp b/include/cereal/types/base_class.hpp
new file mode 100644
index 0000000..6611876
--- /dev/null
+++ b/include/cereal/types/base_class.hpp
@@ -0,0 +1,164 @@
+/*! \file base_class.hpp
+    \brief Support for base classes (virtual and non-virtual)
+    \ingroup OtherTypes */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_BASE_CLASS_HPP_
+#define CEREAL_TYPES_BASE_CLASS_HPP_
+
+#include <cereal/details/traits.hpp>
+
+namespace cereal
+{
+  //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
+  /*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
+      using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
+
+      \sa virtual_base_class
+
+      @code{.cpp}
+      struct MyBase
+      {
+        int x;
+
+        virtual void foo() = 0;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( x );
+        }
+      };
+
+      struct MyDerived : public MyBase //<-- Note non-virtual inheritance
+      {
+        int y;
+
+        virtual void foo() {};
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( cereal::base_class<MyBase>(this) );
+          ar( y );
+        }
+      };
+      @endcode */
+  template<class Base>
+    struct base_class : private traits::detail::BaseCastBase
+    {
+      template<class Derived>
+        base_class(Derived const * derived) :
+          base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
+      { static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
+
+        Base * base_ptr;
+    };
+
+  //! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
+  /*! This should be used in cases when a derived type features virtual inheritance from some
+      base type.  This allows cereal to track the inheritance and to avoid making duplicate copies
+      during serialization.
+
+      It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
+      where virtual inheritance does not take place, though it may be slightly faster to utilize
+      cereal::base_class<> if you do not need to worry about virtual inheritance.
+
+      \sa base_class
+
+      @code{.cpp}
+      struct MyBase
+      {
+        int x;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( x );
+        }
+      };
+
+      struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
+      {
+        int y;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( cereal::virtual_base_class<MyBase>( this ) );
+          ar( y );
+        }
+      };
+
+      struct MyRight : virtual MyBase
+      {
+        int z;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( cereal::virtual_base_clas<MyBase>( this ) );
+          ar( z );
+        }
+      };
+
+      // diamond virtual inheritance; contains one copy of each base class
+      struct MyDerived : virtual MyLeft, virtual MyRight
+      {
+        int a;
+
+        template <class Archive>
+        void serialize( Archive & ar )
+        {
+          ar( cereal::virtual_base_class<MyLeft>( this ) );  // safely serialize data members in MyLeft
+          ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight
+          ar( a );
+
+          // Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
+          // serialized as we traverse the inheritance heirarchy. This means that there will be one copy
+          // each of the variables x, y, z, and a
+
+          // If we had chosen to use static_cast<> instead, cereal would perform no tracking and
+          // assume that every base class should be serialized (in this case leading to a duplicate
+          // serialization of MyBase due to diamond inheritance
+      };
+     }
+     @endcode */
+  template<class Base>
+    struct virtual_base_class : private traits::detail::BaseCastBase
+    {
+      template<class Derived>
+        virtual_base_class(Derived const * derived) :
+          base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
+      { static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
+
+        Base * base_ptr;
+    };
+
+} // namespace cereal
+
+#endif // CEREAL_TYPES_BASE_CLASS_HPP_
diff --git a/include/cereal/types/bitset.hpp b/include/cereal/types/bitset.hpp
new file mode 100644
index 0000000..d421e10
--- /dev/null
+++ b/include/cereal/types/bitset.hpp
@@ -0,0 +1,112 @@
+/*! \file bitset.hpp
+    \brief Support for types found in \<bitset\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_BITSET_HPP_
+#define CEREAL_TYPES_BITSET_HPP_
+
+#include <cereal/cereal.hpp>
+#include <bitset>
+
+namespace cereal
+{
+  namespace bitset_detail
+  {
+    //! The type the bitset is encoded with
+    /*! @internal */
+    enum class type : uint8_t
+    {
+      ulong,
+      ullong,
+      string
+    };
+  }
+
+  //! Serializing (save) for std::bitset
+  template <class Archive, size_t N> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
+  {
+    try
+    {
+      auto const b = bits.to_ulong();
+      ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
+      ar( CEREAL_NVP_("data", b) );
+    }
+    catch( std::overflow_error const & )
+    {
+      try
+      {
+        auto const b = bits.to_ullong();
+        ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
+        ar( CEREAL_NVP_("data", b) );
+      }
+      catch( std::overflow_error const & )
+      {
+        ar( CEREAL_NVP_("type", bitset_detail::type::string) );
+        ar( CEREAL_NVP_("data", bits.to_string()) );
+      }
+    }
+  }
+
+  //! Serializing (load) for std::bitset
+  template <class Archive, size_t N> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
+  {
+    bitset_detail::type t;
+    ar( CEREAL_NVP_("type", t) );
+
+    switch( t )
+    {
+      case bitset_detail::type::ulong:
+      {
+        unsigned long b;
+        ar( CEREAL_NVP_("data", b) );
+        bits = std::bitset<N>( b );
+        break;
+      }
+      case bitset_detail::type::ullong:
+      {
+        unsigned long long b;
+        ar( CEREAL_NVP_("data", b) );
+        bits = std::bitset<N>( b );
+        break;
+      }
+      case bitset_detail::type::string:
+      {
+        std::string b;
+        ar( CEREAL_NVP_("data", b) );
+        bits = std::bitset<N>( b );
+        break;
+      }
+      default:
+        throw Exception("Invalid bitset data representation");
+    }
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_BITSET_HPP_
diff --git a/include/cereal/types/boost_variant.hpp b/include/cereal/types/boost_variant.hpp
new file mode 100644
index 0000000..0f38589
--- /dev/null
+++ b/include/cereal/types/boost_variant.hpp
@@ -0,0 +1,106 @@
+/*! \file boost_variant.hpp
+    \brief Support for boost::variant
+    \ingroup OtherTypes */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_
+#define CEREAL_TYPES_BOOST_VARIANT_HPP_
+
+#include <cereal/cereal.hpp>
+#include <boost/variant.hpp>
+#include <boost/mpl/size.hpp>
+
+namespace cereal
+{
+  namespace variant_detail
+  {
+    //! @internal
+    template <class Archive>
+    struct variant_save_visitor : boost::static_visitor<>
+    {
+      variant_save_visitor(Archive & ar_) : ar(ar_) {}
+
+      template<class T>
+        void operator()(T const & value) const
+        {
+          ar( CEREAL_NVP_("data", value) );
+        }
+
+      Archive & ar;
+    };
+
+    //! @internal
+    template<int N, class Variant, class ... Args, class Archive>
+    typename std::enable_if<N == boost::mpl::size<typename Variant::types>::value, void>::type
+    load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
+    {
+      throw ::cereal::Exception("Error traversing variant during load");
+    }
+
+    //! @internal
+    template<int N, class Variant, class H, class ... T, class Archive>
+    typename std::enable_if<N < boost::mpl::size<typename Variant::types>::value, void>::type
+    load_variant(Archive & ar, int target, Variant & variant)
+    {
+      if(N == target)
+      {
+        H value;
+        ar( CEREAL_NVP_("data", value) );
+        variant = value;
+      }
+      else
+        load_variant<N+1, Variant, T...>(ar, target, variant);
+    }
+
+  } // namespace variant_detail
+
+  //! Saving for boost::variant
+  template <class Archive, typename... VariantTypes> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
+  {
+    int32_t which = variant.which();
+    ar( CEREAL_NVP_("which", which) );
+    variant_detail::variant_save_visitor<Archive> visitor(ar);
+    variant.apply_visitor(visitor);
+  }
+
+  //! Loading for boost::variant
+  template <class Archive, typename... VariantTypes> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
+  {
+    typedef typename boost::variant<VariantTypes...>::types types;
+
+    int32_t which;
+    ar( CEREAL_NVP_("which", which) );
+    if(which >= boost::mpl::size<types>::value)
+      throw Exception("Invalid 'which' selector when deserializing boost::variant");
+
+    variant_detail::load_variant<0, boost::variant<VariantTypes...>, VariantTypes...>(ar, which, variant);
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
diff --git a/include/cereal/types/chrono.hpp b/include/cereal/types/chrono.hpp
new file mode 100644
index 0000000..12ee4cb
--- /dev/null
+++ b/include/cereal/types/chrono.hpp
@@ -0,0 +1,72 @@
+/*! \file chrono.hpp
+    \brief Support for types found in \<chrono\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_CHRONO_HPP_
+#define CEREAL_TYPES_CHRONO_HPP_
+
+#include <chrono>
+
+namespace cereal
+{
+  //! Saving std::chrono::duration
+  template <class Archive, class R, class P> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> const & dur )
+  {
+    ar( CEREAL_NVP_("count", dur.count()) );
+  }
+
+  //! Loading std::chrono::duration
+  template <class Archive, class R, class P> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> & dur )
+  {
+    R count;
+    ar( CEREAL_NVP_("count", count) );
+
+    dur = std::chrono::duration<R, P>{count};
+  }
+
+  //! Saving std::chrono::time_point
+  template <class Archive, class C, class D> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> const & dur )
+  {
+    ar( CEREAL_NVP_("time_since_epoch", dur.time_since_epoch()) );
+  }
+
+  //! Loading std::chrono::time_point
+  template <class Archive, class C, class D> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> & dur )
+  {
+    D elapsed;
+    ar( CEREAL_NVP_("time_since_epoch", elapsed) );
+
+    dur = std::chrono::time_point<C, D>{elapsed};
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_CHRONO_HPP_
diff --git a/include/cereal/types/common.hpp b/include/cereal/types/common.hpp
new file mode 100644
index 0000000..57ab204
--- /dev/null
+++ b/include/cereal/types/common.hpp
@@ -0,0 +1,129 @@
+/*! \file common.hpp
+    \brief Support common types - always included automatically
+    \ingroup OtherTypes */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_COMMON_HPP_
+#define CEREAL_TYPES_COMMON_HPP_
+
+#include <cereal/cereal.hpp>
+
+namespace cereal
+{
+  namespace common_detail
+  {
+    //! Serialization for arrays if BinaryData is supported and we are arithmetic
+    /*! @internal */
+    template <class Archive, class T> inline
+    void serializeArray( Archive & ar, T & array, std::true_type /* binary_supported */ )
+    {
+      ar( binary_data( array, sizeof(array) ) );
+    }
+
+    //! Serialization for arrays if BinaryData is not supported or we are not arithmetic
+    /*! @internal */
+    template <class Archive, class T> inline
+    void serializeArray( Archive & ar, T & array, std::false_type /* binary_supported */ )
+    {
+      for( auto & i : array )
+        ar( i );
+    }
+
+    namespace
+    {
+      //! Gets the underlying type of an enum
+      /*! @internal */
+      template <class T, bool IsEnum>
+      struct enum_underlying_type : std::false_type {};
+
+      //! Gets the underlying type of an enum
+      /*! Specialization for when we actually have an enum
+          @internal */
+      template <class T>
+      struct enum_underlying_type<T, true> { using type = typename std::underlying_type<T>::type; };
+    } // anon namespace
+
+    //! Checks if a type is an enum
+    /*! This is needed over simply calling std::is_enum because the type
+        traits checking at compile time will attempt to call something like
+        load_minimal with a special NoConvertRef struct that wraps up the true type.
+
+        This will strip away any of that and also expose the true underlying type.
+        @internal */
+    template <class T>
+    class is_enum
+    {
+      private:
+        using DecayedT  = typename std::decay<T>::type;
+        using StrippedT = typename ::cereal::traits::strip_minimal<DecayedT>::type;
+
+      public:
+        static const bool value = std::is_enum<StrippedT>::value;
+        using type = StrippedT;
+        using base_type = typename enum_underlying_type<StrippedT, value>::type;
+    };
+  }
+
+  //! Saving for enum types
+  template <class Archive, class T> inline
+  typename std::enable_if<common_detail::is_enum<T>::value,
+                          typename common_detail::is_enum<T>::base_type>::type
+  CEREAL_SAVE_MINIMAL_FUNCTION_NAME( Archive const &, T const & t )
+  {
+    return static_cast<typename common_detail::is_enum<T>::base_type>(t);
+  }
+
+  //! Loading for enum types
+  template <class Archive, class T> inline
+  typename std::enable_if<common_detail::is_enum<T>::value, void>::type
+  CEREAL_LOAD_MINIMAL_FUNCTION_NAME( Archive const &, T && t,
+                                     typename common_detail::is_enum<T>::base_type const & value )
+  {
+    t = reinterpret_cast<typename common_detail::is_enum<T>::type const &>( value );
+  }
+
+  //! Serialization for raw pointers
+  /*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
+  template <class Archive, class T> inline
+  void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, T * & )
+  {
+    static_assert(cereal::traits::detail::delay_static_assert<T>::value,
+      "Cereal does not support serializing raw pointers - please use a smart pointer");
+  }
+
+  //! Serialization for C style arrays
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_array<T>::value, void>::type
+  CEREAL_SERIALIZE_FUNCTION_NAME(Archive & ar, T & array)
+  {
+    common_detail::serializeArray( ar, array,
+        std::integral_constant<bool, traits::is_output_serializable<BinaryData<T>, Archive>::value &&
+                                     std::is_arithmetic<typename std::remove_all_extents<T>::type>::value>() );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_COMMON_HPP_
diff --git a/include/cereal/types/complex.hpp b/include/cereal/types/complex.hpp
new file mode 100644
index 0000000..7e6ff54
--- /dev/null
+++ b/include/cereal/types/complex.hpp
@@ -0,0 +1,56 @@
+/*! \file complex.hpp
+    \brief Support for types found in \<complex\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_COMPLEX_HPP_
+#define CEREAL_TYPES_COMPLEX_HPP_
+
+#include <complex>
+
+namespace cereal
+{
+  //! Serializing (save) for std::complex
+  template <class Archive, class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::complex<T> const & comp )
+  {
+    ar( CEREAL_NVP_("real", comp.real()),
+        CEREAL_NVP_("imag", comp.imag()) );
+  }
+
+  //! Serializing (load) for std::complex
+  template <class Archive, class T> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::complex<T> & bits )
+  {
+    T real, imag;
+    ar( CEREAL_NVP_("real", real),
+        CEREAL_NVP_("imag", imag) );
+    bits = {real, imag};
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_COMPLEX_HPP_
diff --git a/include/cereal/types/deque.hpp b/include/cereal/types/deque.hpp
new file mode 100644
index 0000000..df93e64
--- /dev/null
+++ b/include/cereal/types/deque.hpp
@@ -0,0 +1,62 @@
+/*! \file deque.hpp
+    \brief Support for types found in \<deque\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_DEQUE_HPP_
+#define CEREAL_TYPES_DEQUE_HPP_
+
+#include <cereal/cereal.hpp>
+#include <deque>
+
+namespace cereal
+{
+  //! Saving for std::deque
+  template <class Archive, class T, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::deque<T, A> const & deque )
+  {
+    ar( make_size_tag( static_cast<size_type>(deque.size()) ) );
+
+    for( auto const & i : deque )
+      ar( i );
+  }
+
+  //! Loading for std::deque
+  template <class Archive, class T, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::deque<T, A> & deque )
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+
+    deque.resize( static_cast<size_t>( size ) );
+
+    for( auto & i : deque )
+      ar( i );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_DEQUE_HPP_
diff --git a/include/cereal/types/forward_list.hpp b/include/cereal/types/forward_list.hpp
new file mode 100644
index 0000000..72a8b88
--- /dev/null
+++ b/include/cereal/types/forward_list.hpp
@@ -0,0 +1,68 @@
+/*! \file forward_list.hpp
+    \brief Support for types found in \<forward_list\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_FORWARD_LIST_HPP_
+#define CEREAL_TYPES_FORWARD_LIST_HPP_
+
+#include <cereal/cereal.hpp>
+#include <forward_list>
+
+namespace cereal
+{
+  //! Saving for std::forward_list all other types
+  template <class Archive, class T, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> const & forward_list )
+  {
+    // write the size - note that this is slow because we need to traverse
+    // the entire list. there are ways we could avoid this but this was chosen
+    // since it works in the most general fashion with any archive type
+    size_type const size = std::distance( forward_list.begin(), forward_list.end() );
+
+    ar( make_size_tag( size ) );
+
+    // write the list
+    for( const auto & i : forward_list )
+      ar( i );
+  }
+
+  //! Loading for std::forward_list all other types from
+  template <class Archive, class T, class A>
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> & forward_list )
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+
+    forward_list.resize( static_cast<size_t>( size ) );
+
+    for( auto & i : forward_list )
+      ar( i );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_FORWARD_LIST_HPP_
diff --git a/include/cereal/types/list.hpp b/include/cereal/types/list.hpp
new file mode 100644
index 0000000..d071e72
--- /dev/null
+++ b/include/cereal/types/list.hpp
@@ -0,0 +1,62 @@
+/*! \file list.hpp
+    \brief Support for types found in \<list\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_LIST_HPP_
+#define CEREAL_TYPES_LIST_HPP_
+
+#include <cereal/cereal.hpp>
+#include <list>
+
+namespace cereal
+{
+  //! Saving for std::list
+  template <class Archive, class T, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::list<T, A> const & list )
+  {
+    ar( make_size_tag( static_cast<size_type>(list.size()) ) );
+
+    for( auto const & i : list )
+      ar( i );
+  }
+
+  //! Loading for std::list
+  template <class Archive, class T, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::list<T, A> & list )
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+
+    list.resize( static_cast<size_t>( size ) );
+
+    for( auto & i : list )
+      ar( i );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_LIST_HPP_
diff --git a/include/cereal/types/map.hpp b/include/cereal/types/map.hpp
new file mode 100644
index 0000000..c5d3f4e
--- /dev/null
+++ b/include/cereal/types/map.hpp
@@ -0,0 +1,108 @@
+/*! \file map.hpp
+    \brief Support for types found in \<map\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_MAP_HPP_
+#define CEREAL_TYPES_MAP_HPP_
+
+#include <cereal/cereal.hpp>
+#include <map>
+
+namespace cereal
+{
+  namespace map_detail
+  {
+    //! @internal
+    template <class Archive, class MapT> inline
+    void save( Archive & ar, MapT const & map )
+    {
+      ar( make_size_tag( static_cast<size_type>(map.size()) ) );
+
+      for( const auto & i : map )
+      {
+        ar( make_map_item(i.first, i.second) );
+      }
+    }
+
+    //! @internal
+    template <class Archive, class MapT> inline
+    void load( Archive & ar, MapT & map )
+    {
+      size_type size;
+      ar( make_size_tag( size ) );
+
+      map.clear();
+
+      auto hint = map.begin();
+      for( size_t i = 0; i < size; ++i )
+      {
+        typename MapT::key_type key;
+        typename MapT::mapped_type value;
+
+        ar( make_map_item(key, value) );
+        #ifdef CEREAL_OLDER_GCC
+        hint = map.insert( hint, std::make_pair(std::move(key), std::move(value)) );
+        #else // NOT CEREAL_OLDER_GCC
+        hint = map.emplace_hint( hint, std::move( key ), std::move( value ) );
+        #endif // NOT CEREAL_OLDER_GCC
+      }
+    }
+  }
+
+  //! Saving for std::map
+  template <class Archive, class K, class T, class C, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> const & map )
+  {
+    map_detail::save( ar, map );
+  }
+
+  //! Loading for std::map
+  template <class Archive, class K, class T, class C, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> & map )
+  {
+    map_detail::load( ar, map );
+  }
+
+  //! Saving for std::multimap
+  /*! @note serialization for this type is not guaranteed to preserve ordering */
+  template <class Archive, class K, class T, class C, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> const & multimap )
+  {
+    map_detail::save( ar, multimap );
+  }
+
+  //! Loading for std::multimap
+  /*! @note serialization for this type is not guaranteed to preserve ordering */
+  template <class Archive, class K, class T, class C, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> & multimap )
+  {
+    map_detail::load( ar, multimap );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_MAP_HPP_
diff --git a/include/cereal/types/memory.hpp b/include/cereal/types/memory.hpp
new file mode 100644
index 0000000..040093a
--- /dev/null
+++ b/include/cereal/types/memory.hpp
@@ -0,0 +1,392 @@
+/*! \file memory.hpp
+    \brief Support for types found in \<memory\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_SHARED_PTR_HPP_
+#define CEREAL_TYPES_SHARED_PTR_HPP_
+
+#include <cereal/cereal.hpp>
+#include <memory>
+#include <cstring>
+
+namespace cereal
+{
+  namespace memory_detail
+  {
+    //! A wrapper class to notify cereal that it is ok to serialize the contained pointer
+    /*! This mechanism allows us to intercept and properly handle polymorphic pointers
+        @internal */
+    template<class T>
+    struct PtrWrapper
+    {
+      PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
+      T & ptr;
+
+      PtrWrapper & operator=( PtrWrapper const & ) = delete;
+    };
+
+    //! Make a PtrWrapper
+    /*! @internal */
+    template<class T> inline
+    PtrWrapper<T> make_ptr_wrapper(T && t)
+    {
+      return {std::forward<T>(t)};
+    }
+
+    //! A struct that acts as a wrapper around calling load_andor_construct
+    /*! The purpose of this is to allow a load_and_construct call to properly enter into the
+        'data' NVP of the ptr_wrapper
+        @internal */
+    template <class Archive, class T>
+    struct LoadAndConstructLoadWrapper
+    {
+      LoadAndConstructLoadWrapper( T * ptr ) :
+        construct( ptr )
+      { }
+
+      inline void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
+      {
+        ::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
+      }
+
+      ::cereal::construct<T> construct;
+    };
+
+    //! A helper struct for saving and restoring the state of types that derive from
+    //! std::enable_shared_from_this
+    /*! This special struct is necessary because when a user uses load_and_construct,
+        the weak_ptr (or whatever implementation defined variant) that allows
+        enable_shared_from_this to function correctly will not be initialized properly.
+
+        This internal weak_ptr can also be modified by the shared_ptr that is created
+        during the serialization of a polymorphic pointer, where cereal creates a
+        wrapper shared_ptr out of a void pointer to the real data.
+
+        In the case of load_and_construct, this happens because it is the allocation
+        of shared_ptr that perform this initialization, which we let happen on a buffer
+        of memory (aligned_storage).  This buffer is then used for placement new
+        later on, effectively overwriting any initialized weak_ptr with a default
+        initialized one, eventually leading to issues when the user calls shared_from_this.
+
+        To get around these issues, we will store the memory for the enable_shared_from_this
+        portion of the class and replace it after whatever happens to modify it (e.g. the
+        user performing construction or the wrapper shared_ptr in saving).
+
+        Example usage:
+
+        @code{.cpp}
+        T * myActualPointer;
+        {
+          EnableSharedStateHelper<T> helper( myActualPointer ); // save the state
+          std::shared_ptr<T> myPtr( myActualPointer ); // modifies the internal weak_ptr
+          // helper restores state when it goes out of scope
+        }
+        @endcode
+
+        This is designed to be used in an RAII fashion - it will save state on construction
+        and restore it on destruction.
+
+        @tparam T Type pointed to by shared_ptr
+        @internal */
+    template <class T>
+    class EnableSharedStateHelper
+    {
+      // typedefs for parent type and storage type
+      using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
+      using ParentType = std::enable_shared_from_this<BaseType>;
+      using StorageType = typename std::aligned_storage<sizeof(ParentType)>::type;
+
+      public:
+        //! Saves the state of some type inheriting from enable_shared_from_this
+        /*! @param ptr The raw pointer held by the shared_ptr */
+        inline EnableSharedStateHelper( T * ptr ) :
+          itsPtr( static_cast<ParentType *>( ptr ) ),
+          itsState()
+        {
+          std::memcpy( &itsState, itsPtr, sizeof(ParentType) );
+        }
+
+        //! Restores the state of the held pointer
+        inline ~EnableSharedStateHelper()
+        {
+          std::memcpy( itsPtr, &itsState, sizeof(ParentType) );
+        }
+
+      private:
+        ParentType * itsPtr;
+        StorageType itsState;
+    }; // end EnableSharedStateHelper
+
+    //! Performs loading and construction for a shared pointer that is derived from
+    //! std::enable_shared_from_this
+    /*! @param ar The archive
+        @param ptr Raw pointer held by the shared_ptr
+        @internal */
+    template <class Archive, class T> inline
+    void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
+    {
+      memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
+      memory_detail::EnableSharedStateHelper<T> state( ptr );
+
+      // let the user perform their initialization
+      ar( CEREAL_NVP_("data", loadWrapper) );
+    }
+
+    //! Performs loading and construction for a shared pointer that is NOT derived from
+    //! std::enable_shared_from_this
+    /*! This is the typical case, where we simply pass the load wrapper to the
+        archive.
+
+        @param ar The archive
+        @param ptr Raw pointer held by the shared_ptr
+        @internal */
+    template <class Archive, class T> inline
+    void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
+    {
+      memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
+      ar( CEREAL_NVP_("data", loadWrapper) );
+    }
+  } // end namespace memory_detail
+
+  //! Saving std::shared_ptr for non polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
+  {
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
+  }
+
+  //! Loading std::shared_ptr, case when no user load and construct for non polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
+  {
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
+  }
+
+  //! Saving std::weak_ptr for non polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
+  {
+    auto const sptr = ptr.lock();
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
+  }
+
+  //! Loading std::weak_ptr for non polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
+  {
+    std::shared_ptr<T> sptr;
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
+    ptr = sptr;
+  }
+
+  //! Saving std::unique_ptr for non polymorphic types
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
+  {
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
+  }
+
+  //! Loading std::unique_ptr, case when user provides load_and_construct for non polymorphic types
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
+  {
+    ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
+  }
+
+  // ######################################################################
+  // Pointer wrapper implementations follow below
+
+  //! Saving std::shared_ptr (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
+  {
+    auto & ptr = wrapper.ptr;
+
+    uint32_t id = ar.registerSharedPointer( ptr.get() );
+    ar( CEREAL_NVP_("id", id) );
+
+    if( id & detail::msb_32bit )
+    {
+      ar( CEREAL_NVP_("data", *ptr) );
+    }
+  }
+
+  //! Loading std::shared_ptr, case when user load and construct (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T> inline
+  typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
+  {
+    auto & ptr = wrapper.ptr;
+
+    uint32_t id;
+
+    ar( CEREAL_NVP_("id", id) );
+
+    if( id & detail::msb_32bit )
+    {
+      // Storage type for the pointer - since we can't default construct this type,
+      // we'll allocate it using std::aligned_storage and use a custom deleter
+      using ST = typename std::aligned_storage<sizeof(T)>::type;
+
+      // Valid flag - set to true once construction finishes
+      //  This prevents us from calling the destructor on
+      //  uninitialized data.
+      auto valid = std::make_shared<bool>( false );
+
+      // Allocate our storage, which we will treat as
+      //  uninitialized until initialized with placement new
+      ptr.reset( reinterpret_cast<T *>( new ST() ),
+          [=]( T * t )
+          {
+            if( valid )
+              t->~T();
+
+            delete reinterpret_cast<ST *>( t );
+          } );
+
+      // Register the pointer
+      ar.registerSharedPointer( id, ptr );
+
+      // Perform the actual loading and allocation
+      memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<T>::type() );
+
+      // Mark pointer as valid (initialized)
+      *valid = true;
+    }
+    else
+      ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
+  }
+
+  //! Loading std::shared_ptr, case when no user load and construct (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T> inline
+  typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
+  {
+    auto & ptr = wrapper.ptr;
+
+    uint32_t id;
+
+    ar( CEREAL_NVP_("id", id) );
+
+    if( id & detail::msb_32bit )
+    {
+      ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
+      ar.registerSharedPointer( id, ptr );
+      ar( CEREAL_NVP_("data", *ptr) );
+    }
+    else
+      ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
+  }
+
+  //! Saving std::unique_ptr (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T, class D> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
+  {
+    auto & ptr = wrapper.ptr;
+
+    // unique_ptr get one byte of metadata which signifies whether they were a nullptr
+    // 0 == nullptr
+    // 1 == not null
+
+    if( !ptr )
+      ar( CEREAL_NVP_("valid", uint8_t(0)) );
+    else
+    {
+      ar( CEREAL_NVP_("valid", uint8_t(1)) );
+      ar( CEREAL_NVP_("data", *ptr) );
+    }
+  }
+
+  //! Loading std::unique_ptr, case when user provides load_and_construct (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
+  {
+    uint8_t isValid;
+    ar( CEREAL_NVP_("valid", isValid) );
+
+    auto & ptr = wrapper.ptr;
+
+    if( isValid )
+    {
+      // Storage type for the pointer - since we can't default construct this type,
+      // we'll allocate it using std::aligned_storage
+      using ST = typename std::aligned_storage<sizeof(T)>::type;
+
+      // Allocate storage - note the ST type so that deleter is correct if
+      //                    an exception is thrown before we are initialized
+      std::unique_ptr<ST> stPtr( new ST() );
+
+      // Use wrapper to enter into "data" nvp of ptr_wrapper
+      memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
+
+      // Initialize storage
+      ar( CEREAL_NVP_("data", loadWrapper) );
+
+      // Transfer ownership to correct unique_ptr type
+      ptr.reset( reinterpret_cast<T *>( stPtr.release() ) );
+    }
+    else
+      ptr.reset( nullptr );
+  }
+
+  //! Loading std::unique_ptr, case when no load_and_construct (wrapper implementation)
+  /*! @internal */
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
+  {
+    uint8_t isValid;
+    ar( CEREAL_NVP_("valid", isValid) );
+
+    auto & ptr = wrapper.ptr;
+
+    if( isValid )
+    {
+      ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
+      ar( CEREAL_NVP_( "data", *ptr ) );
+    }
+    else
+    {
+      ptr.reset( nullptr );
+    }
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_SHARED_PTR_HPP_
diff --git a/include/cereal/types/polymorphic.hpp b/include/cereal/types/polymorphic.hpp
new file mode 100644
index 0000000..6cd85f6
--- /dev/null
+++ b/include/cereal/types/polymorphic.hpp
@@ -0,0 +1,462 @@
+/*! \file polymorphic.hpp
+    \brief Support for pointers to polymorphic base classes
+    \ingroup OtherTypes */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_POLYMORPHIC_HPP_
+#define CEREAL_TYPES_POLYMORPHIC_HPP_
+
+#include <cereal/cereal.hpp>
+#include <cereal/types/memory.hpp>
+
+#include <cereal/details/util.hpp>
+#include <cereal/details/helpers.hpp>
+#include <cereal/details/traits.hpp>
+#include <cereal/details/polymorphic_impl.hpp>
+
+#ifdef _MSC_VER
+#define STATIC_CONSTEXPR static
+#else
+#define STATIC_CONSTEXPR static constexpr
+#endif
+
+//! Registers a derived polymorphic type with cereal
+/*! Polymorphic types must be registered before smart
+    pointers to them can be serialized.  Note that base
+    classes do not need to be registered.
+
+    Registering a type lets cereal know how to properly
+    serialize it when a smart pointer to a base object is
+    used in conjunction with a derived class.
+
+    This assumes that all relevant archives have also
+    previously been registered.  Registration for archives
+    is usually done in the header file in which they are
+    defined.  This means that type registration needs to
+    happen after specific archives to be used are included.
+
+    It is recommended that type registration be done in
+    the header file in which the type is declared.
+
+    Registration can also be placed in a source file,
+    but this may require the use of the
+    CEREAL_REGISTER_DYNAMIC_INIT macro (see below).
+
+    Registration may be called repeatedly for the same
+    type in different translation units to add support
+    for additional archives if they are not initially
+    available (included and registered).
+
+    When building serialization support as a DLL on
+    Windows, registration must happen in the header file.
+    On Linux and Mac things should still work properly
+    if placed in a source file, but see the above comments
+    on registering in source files.
+
+    Polymorphic support in cereal requires RTTI to be
+    enabled */
+#define CEREAL_REGISTER_TYPE(T)                         \
+  namespace cereal {                                    \
+  namespace detail {                                    \
+  template <>                                           \
+  struct binding_name<T>                                \
+  {                                                     \
+    STATIC_CONSTEXPR char const * name() { return #T; } \
+  };                                                    \
+  } } /* end namespaces */                              \
+  CEREAL_BIND_TO_ARCHIVES(T)
+
+//! Registers a polymorphic type with cereal, giving it a
+//! user defined name
+/*! In some cases the default name used with
+    CEREAL_REGISTER_TYPE (the name of the type) may not be
+    suitable.  This macro allows any name to be associated
+    with the type.  The name should be unique */
+#define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name)              \
+  namespace cereal {                                         \
+  namespace detail {                                         \
+  template <>                                                \
+  struct binding_name<T>                                     \
+  { STATIC_CONSTEXPR char const * name() { return Name; } }; \
+  } } /* end namespaces */                                   \
+  CEREAL_BIND_TO_ARCHIVES(T)
+
+//! Adds a way to force initialization of a translation unit containing
+//! calls to CEREAL_REGISTER_TYPE
+/*! In C++, dynamic initialization of non-local variables of a translation
+    unit may be deferred until "the first odr-use of any function or variable
+    defined in the same translation unit as the variable to be initialized."
+
+    Informally, odr-use means that your program takes the address of or binds
+    a reference directly to an object, which must have a definition.
+
+    Since polymorphic type support in cereal relies on the dynamic
+    initialization of certain global objects happening before
+    serialization is performed, it is important to ensure that something
+    from files that call CEREAL_REGISTER_TYPE is odr-used before serialization
+    occurs, otherwise the registration will never take place.  This may often
+    be the case when serialization is built as a shared library external from
+    your main program.
+
+    This macro, with any name of your choosing, should be placed into the
+    source file that contains calls to CEREAL_REGISTER_TYPE.
+
+    Its counterpart, CEREAL_FORCE_DYNAMIC_INIT, should be placed in its
+    associated header file such that it is included in the translation units
+    (source files) in which you want the registration to appear.
+
+    @relates CEREAL_FORCE_DYNAMIC_INIT
+    */
+#define CEREAL_REGISTER_DYNAMIC_INIT(LibName)                \
+  namespace cereal {                                         \
+  namespace detail {                                         \
+    void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName() {} \
+  } } /* end namespaces */
+
+//! Forces dynamic initialization of polymorphic support in a
+//! previously registered source file
+/*! @sa CEREAL_REGISTER_DYNAMIC_INIT
+
+    See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
+    of how this macro should be used.  The name used should
+    match that for CEREAL_REGISTER_DYNAMIC_INIT. */
+#define CEREAL_FORCE_DYNAMIC_INIT(LibName)              \
+  namespace cereal {                                    \
+  namespace detail {                                    \
+    void dynamic_init_dummy_##LibName();                \
+  } /* end detail */                                    \
+  namespace {                                           \
+    void dynamic_init_##LibName()                       \
+    {                                                   \
+      ::cereal::detail::dynamic_init_dummy_##LibName(); \
+    }                                                   \
+  } } /* end namespaces */
+
+#ifdef _MSC_VER
+#undef CONSTEXPR
+#endif
+
+namespace cereal
+{
+  namespace polymorphic_detail
+  {
+    //! Error message used for unregistered polymorphic types
+    /*! @internal */
+    #define UNREGISTERED_POLYMORPHIC_EXCEPTION(LoadSave, Name)                                                                                      \
+      throw cereal::Exception("Trying to " #LoadSave " an unregistered polymorphic type (" + Name + ").\n"                                          \
+                              "Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive "                                   \
+                              "you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.\n"   \
+                              "If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.");
+
+    //! Get an input binding from the given archive by deserializing the type meta data
+    /*! @internal */
+    template<class Archive> inline
+    typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t const nameid)
+    {
+      // If the nameid is zero, we serialized a null pointer
+      if(nameid == 0)
+      {
+        typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
+        emptySerializers.shared_ptr = [](void*, std::shared_ptr<void> & ptr) { ptr.reset(); };
+        emptySerializers.unique_ptr = [](void*, std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> & ptr) { ptr.reset( nullptr ); };
+        return emptySerializers;
+      }
+
+      std::string name;
+      if(nameid & detail::msb_32bit)
+      {
+        ar( CEREAL_NVP_("polymorphic_name", name) );
+        ar.registerPolymorphicName(nameid, name);
+      }
+      else
+        name = ar.getPolymorphicName(nameid);
+
+      auto & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
+
+      auto binding = bindingMap.find(name);
+      if(binding == bindingMap.end())
+        UNREGISTERED_POLYMORPHIC_EXCEPTION(load, name)
+      return binding->second;
+    }
+
+    //! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
+    /*! This check lets us try and skip doing polymorphic machinery if we can get away with
+        using the derived class serialize function
+
+        Note that on MSVC 2013 preview, is_default_constructible<T> returns true for abstract classes with
+        default constructors, but on clang/gcc this will return false.  So we also need to check for that here.
+        @internal */
+    template<class Archive, class T> inline
+    typename std::enable_if<(traits::is_default_constructible<T>::value
+                             || traits::has_load_and_construct<T, Archive>::value)
+                             && !std::is_abstract<T>::value, bool>::type
+    serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
+    {
+      if(nameid & detail::msb2_32bit)
+      {
+        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
+        return true;
+      }
+      return false;
+    }
+
+    //! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
+    /*! This check lets us try and skip doing polymorphic machinery if we can get away with
+        using the derived class serialize function
+        @internal */
+    template<class Archive, class T, class D> inline
+    typename std::enable_if<(traits::is_default_constructible<T>::value
+                             || traits::has_load_and_construct<T, Archive>::value)
+                             && !std::is_abstract<T>::value, bool>::type
+    serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
+    {
+      if(nameid & detail::msb2_32bit)
+      {
+        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
+        return true;
+      }
+      return false;
+    }
+
+    //! Serialize a shared_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
+    /*! This case is for when we can't actually construct the shared pointer.  Normally this would be caught
+        as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
+        the pointer we'd end up back here recursively.  So we have to catch the error here as well, if
+        this was a polymorphic type serialized by its proper pointer type
+        @internal */
+    template<class Archive, class T> inline
+    typename std::enable_if<(!traits::is_default_constructible<T>::value
+                             && !traits::has_load_and_construct<T, Archive>::value)
+                             || std::is_abstract<T>::value, bool>::type
+    serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
+    {
+      if(nameid & detail::msb2_32bit)
+        throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
+      return false;
+    }
+
+    //! Serialize a unique_ptr if the 2nd msb in the nameid is set, and if we can actually construct the pointee
+    /*! This case is for when we can't actually construct the unique pointer.  Normally this would be caught
+        as the pointer itself is serialized, but since this is a polymorphic pointer, if we tried to serialize
+        the pointer we'd end up back here recursively.  So we have to catch the error here as well, if
+        this was a polymorphic type serialized by its proper pointer type
+        @internal */
+    template<class Archive, class T, class D> inline
+     typename std::enable_if<(!traits::is_default_constructible<T>::value
+                               && !traits::has_load_and_construct<T, Archive>::value)
+                               || std::is_abstract<T>::value, bool>::type
+    serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
+    {
+      if(nameid & detail::msb2_32bit)
+        throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_construct function");
+      return false;
+    }
+  } // polymorphic_detail
+
+  // ######################################################################
+  // Pointer serialization for polymorphic types
+
+  //! Saving std::shared_ptr for polymorphic types, abstract
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
+  {
+    if(!ptr)
+    {
+      // same behavior as nullptr in memory implementation
+      ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
+      return;
+    }
+
+    std::type_info const & ptrinfo = typeid(*ptr.get());
+    // ptrinfo can never be equal to T info since we can't have an instance
+    // of an abstract object
+    //  this implies we need to do the lookup
+
+    auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
+
+    auto binding = bindingMap.find(std::type_index(ptrinfo));
+    if(binding == bindingMap.end())
+      UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
+
+    binding->second.shared_ptr(&ar, ptr.get());
+  }
+
+  //! Saving std::shared_ptr for polymorphic types, not abstract
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
+  {
+    if(!ptr)
+    {
+      // same behavior as nullptr in memory implementation
+      ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
+      return;
+    }
+
+    std::type_info const & ptrinfo = typeid(*ptr.get());
+    static std::type_info const & tinfo = typeid(T);
+
+    if(ptrinfo == tinfo)
+    {
+      // The 2nd msb signals that the following pointer does not need to be
+      // cast with our polymorphic machinery
+      ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
+
+      ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
+
+      return;
+    }
+
+    auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
+
+    auto binding = bindingMap.find(std::type_index(ptrinfo));
+    if(binding == bindingMap.end())
+      UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
+
+    binding->second.shared_ptr(&ar, ptr.get());
+  }
+
+  //! Loading std::shared_ptr for polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
+  {
+    std::uint32_t nameid;
+    ar( CEREAL_NVP_("polymorphic_id", nameid) );
+
+    // Check to see if we can skip all of this polymorphism business
+    if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
+      return;
+
+    auto binding = polymorphic_detail::getInputBinding(ar, nameid);
+    std::shared_ptr<void> result;
+    binding.shared_ptr(&ar, result);
+    ptr = std::static_pointer_cast<T>(result);
+  }
+
+  //! Saving std::weak_ptr for polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_polymorphic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
+  {
+    auto const sptr = ptr.lock();
+    ar( CEREAL_NVP_("locked_ptr", sptr) );
+  }
+
+  //! Loading std::weak_ptr for polymorphic types
+  template <class Archive, class T> inline
+  typename std::enable_if<std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
+  {
+    std::shared_ptr<T> sptr;
+    ar( CEREAL_NVP_("locked_ptr", sptr) );
+    ptr = sptr;
+  }
+
+  //! Saving std::unique_ptr for polymorphic types that are abstract
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
+  {
+    if(!ptr)
+    {
+      // same behavior as nullptr in memory implementation
+      ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
+      return;
+    }
+
+    std::type_info const & ptrinfo = typeid(*ptr.get());
+    // ptrinfo can never be equal to T info since we can't have an instance
+    // of an abstract object
+    //  this implies we need to do the lookup
+
+    auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
+
+    auto binding = bindingMap.find(std::type_index(ptrinfo));
+    if(binding == bindingMap.end())
+      UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
+
+    binding->second.unique_ptr(&ar, ptr.get());
+  }
+
+  //! Saving std::unique_ptr for polymorphic types, not abstract
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
+  {
+    if(!ptr)
+    {
+      // same behavior as nullptr in memory implementation
+      ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
+      return;
+    }
+
+    std::type_info const & ptrinfo = typeid(*ptr.get());
+    static std::type_info const & tinfo = typeid(T);
+
+    if(ptrinfo == tinfo)
+    {
+      // The 2nd msb signals that the following pointer does not need to be
+      // cast with our polymorphic machinery
+      ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
+
+      ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
+
+      return;
+    }
+
+    auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
+
+    auto binding = bindingMap.find(std::type_index(ptrinfo));
+    if(binding == bindingMap.end())
+      UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
+
+    binding->second.unique_ptr(&ar, ptr.get());
+  }
+
+  //! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
+  template <class Archive, class T, class D> inline
+  typename std::enable_if<std::is_polymorphic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
+  {
+    std::uint32_t nameid;
+    ar( CEREAL_NVP_("polymorphic_id", nameid) );
+
+    // Check to see if we can skip all of this polymorphism business
+    if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
+      return;
+
+    auto binding = polymorphic_detail::getInputBinding(ar, nameid);
+    std::unique_ptr<void, ::cereal::detail::EmptyDeleter<void>> result;
+    binding.unique_ptr(&ar, result);
+    ptr.reset(static_cast<T*>(result.release()));
+  }
+
+  #undef UNREGISTERED_POLYMORPHIC_EXCEPTION
+} // namespace cereal
+#endif // CEREAL_TYPES_POLYMORPHIC_HPP_
diff --git a/include/cereal/types/queue.hpp b/include/cereal/types/queue.hpp
new file mode 100644
index 0000000..6030350
--- /dev/null
+++ b/include/cereal/types/queue.hpp
@@ -0,0 +1,130 @@
+/*! \file queue.hpp
+    \brief Support for types found in \<queue\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_QUEUE_HPP_
+#define CEREAL_TYPES_QUEUE_HPP_
+
+#include <cereal/details/helpers.hpp>
+#include <queue>
+
+// The default container for queue is deque, so let's include that too
+#include <cereal/types/deque.hpp>
+
+namespace cereal
+{
+  namespace queue_detail
+  {
+    //! Allows access to the protected container in queue
+    /*! @internal */
+    template <class T, class C> inline
+    C const & container( std::queue<T, C> const & queue )
+    {
+      struct H : public std::queue<T, C>
+      {
+        static C const & get( std::queue<T, C> const & q )
+        {
+          return q.*(&H::c);
+        }
+      };
+
+      return H::get( queue );
+    }
+
+    //! Allows access to the protected container in priority queue
+    /*! @internal */
+    template <class T, class C, class Comp> inline
+    C const & container( std::priority_queue<T, C, Comp> const & priority_queue )
+    {
+      struct H : public std::priority_queue<T, C, Comp>
+      {
+        static C const & get( std::priority_queue<T, C, Comp> const & pq )
+        {
+          return pq.*(&H::c);
+        }
+      };
+
+      return H::get( priority_queue );
+    }
+
+    //! Allows access to the protected comparator in priority queue
+    /*! @internal */
+    template <class T, class C, class Comp> inline
+    Comp const & comparator( std::priority_queue<T, C, Comp> const & priority_queue )
+    {
+      struct H : public std::priority_queue<T, C, Comp>
+      {
+        static Comp const & get( std::priority_queue<T, C, Comp> const & pq )
+        {
+          return pq.*(&H::comp);
+        }
+      };
+
+      return H::get( priority_queue );
+    }
+  }
+
+  //! Saving for std::queue
+  template <class Archive, class T, class C> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::queue<T, C> const & queue )
+  {
+    ar( CEREAL_NVP_("container", queue_detail::container( queue )) );
+  }
+
+  //! Loading for std::queue
+  template <class Archive, class T, class C> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::queue<T, C> & queue )
+  {
+    C container;
+    ar( CEREAL_NVP_("container", container) );
+    queue = std::queue<T, C>( std::move( container ) );
+  }
+
+  //! Saving for std::priority_queue
+  template <class Archive, class T, class C, class Comp> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
+  {
+    ar( CEREAL_NVP_("comparator", queue_detail::comparator( priority_queue )) );
+    ar( CEREAL_NVP_("container", queue_detail::container( priority_queue )) );
+  }
+
+  //! Loading for std::priority_queue
+  template <class Archive, class T, class C, class Comp> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
+  {
+    Comp comparator;
+    ar( CEREAL_NVP_("comparator", comparator) );
+
+    C container;
+    ar( CEREAL_NVP_("container", container) );
+
+    priority_queue = std::priority_queue<T, C, Comp>( comparator, std::move( container ) );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_QUEUE_HPP_
diff --git a/include/cereal/types/set.hpp b/include/cereal/types/set.hpp
new file mode 100644
index 0000000..a5b3bc6
--- /dev/null
+++ b/include/cereal/types/set.hpp
@@ -0,0 +1,103 @@
+/*! \file set.hpp
+    \brief Support for types found in \<set\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_SET_HPP_
+#define CEREAL_TYPES_SET_HPP_
+
+#include <cereal/cereal.hpp>
+#include <set>
+
+namespace cereal
+{
+  namespace set_detail
+  {
+    //! @internal
+    template <class Archive, class SetT> inline
+    void save( Archive & ar, SetT const & set )
+    {
+      ar( make_size_tag( static_cast<size_type>(set.size()) ) );
+
+      for( const auto & i : set )
+        ar( i );
+    }
+
+    //! @internal
+    template <class Archive, class SetT> inline
+    void load( Archive & ar, SetT & set )
+    {
+      size_type size;
+      ar( make_size_tag( size ) );
+
+      set.clear();
+
+      auto hint = set.begin();
+      for( size_type i = 0; i < size; ++i )
+      {
+        typename SetT::key_type key;
+
+        ar( key );
+        #ifdef CEREAL_OLDER_GCC
+        hint = set.insert( hint, std::move( key ) );
+        #else // NOT CEREAL_OLDER_GCC
+        hint = set.emplace_hint( hint, std::move( key ) );
+        #endif // NOT CEREAL_OLDER_GCC
+      }
+    }
+  }
+
+  //! Saving for std::set
+  template <class Archive, class K, class C, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::set<K, C, A> const & set )
+  {
+    set_detail::save( ar, set );
+  }
+
+  //! Loading for std::set
+  template <class Archive, class K, class C, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::set<K, C, A> & set )
+  {
+    set_detail::load( ar, set );
+  }
+
+  //! Saving for std::multiset
+  template <class Archive, class K, class C, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> const & multiset )
+  {
+    set_detail::save( ar, multiset );
+  }
+
+  //! Loading for std::multiset
+  template <class Archive, class K, class C, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> & multiset )
+  {
+    set_detail::load( ar, multiset );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_SET_HPP_
diff --git a/include/cereal/types/stack.hpp b/include/cereal/types/stack.hpp
new file mode 100644
index 0000000..d2a6667
--- /dev/null
+++ b/include/cereal/types/stack.hpp
@@ -0,0 +1,76 @@
+/*! \file stack.hpp
+    \brief Support for types found in \<stack\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_STACK_HPP_
+#define CEREAL_TYPES_STACK_HPP_
+
+#include <cereal/cereal.hpp>
+#include <stack>
+
+// The default container for stack is deque, so let's include that too
+#include <cereal/types/deque.hpp>
+
+namespace cereal
+{
+  namespace stack_detail
+  {
+    //! Allows access to the protected container in stack
+    template <class T, class C> inline
+    C const & container( std::stack<T, C> const & stack )
+    {
+      struct H : public std::stack<T, C>
+      {
+        static C const & get( std::stack<T, C> const & s )
+        {
+          return s.*(&H::c);
+        }
+      };
+
+      return H::get( stack );
+    }
+  }
+
+  //! Saving for std::stack
+  template <class Archive, class T, class C> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::stack<T, C> const & stack )
+  {
+    ar( CEREAL_NVP_("container", stack_detail::container( stack )) );
+  }
+
+  //! Loading for std::stack
+  template <class Archive, class T, class C> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::stack<T, C> & stack )
+  {
+    C container;
+    ar( CEREAL_NVP_("container", container) );
+    stack = std::stack<T, C>( std::move( container ) );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_STACK_HPP_
diff --git a/include/cereal/types/string.hpp b/include/cereal/types/string.hpp
new file mode 100644
index 0000000..55ebe72
--- /dev/null
+++ b/include/cereal/types/string.hpp
@@ -0,0 +1,61 @@
+/*! \file string.hpp
+    \brief Support for types found in \<string\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_STRING_HPP_
+#define CEREAL_TYPES_STRING_HPP_
+
+#include <cereal/cereal.hpp>
+#include <string>
+
+namespace cereal
+{
+  //! Serialization for basic_string types, if binary data is supported
+  template<class Archive, class CharT, class Traits, class Alloc> inline
+  typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
+  {
+    // Save number of chars + the data
+    ar( make_size_tag( static_cast<size_type>(str.size()) ) );
+    ar( binary_data( str.data(), str.size() * sizeof(CharT) ) );
+  }
+
+  //! Serialization for basic_string types, if binary data is supported
+  template<class Archive, class CharT, class Traits, class Alloc> inline
+  typename std::enable_if<traits::is_input_serializable<BinaryData<CharT>, Archive>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+    str.resize(static_cast<std::size_t>(size));
+    ar( binary_data( const_cast<CharT *>( str.data() ), static_cast<std::size_t>(size) * sizeof(CharT) ) );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_STRING_HPP_
+
diff --git a/include/cereal/types/tuple.hpp b/include/cereal/types/tuple.hpp
new file mode 100644
index 0000000..2831728
--- /dev/null
+++ b/include/cereal/types/tuple.hpp
@@ -0,0 +1,123 @@
+/*! \file tuple.hpp
+    \brief Support for types found in \<tuple\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_TUPLE_HPP_
+#define CEREAL_TYPES_TUPLE_HPP_
+
+#include <cereal/cereal.hpp>
+#include <tuple>
+
+namespace cereal
+{
+  namespace tuple_detail
+  {
+    //! Creates a c string from a sequence of characters
+    /*! The c string created will alwas be prefixed by "tuple_element"
+        Based on code from: http://stackoverflow/a/20973438/710791
+        @internal */
+    template<char...Cs>
+    struct char_seq_to_c_str
+    {
+      static const int size = 14;// Size of array for the word: tuple_element
+      typedef const char (&arr_type)[sizeof...(Cs) + size];
+      static const char str[sizeof...(Cs) + size];
+    };
+
+    // the word tuple_element plus a number
+    //! @internal
+    template<char...Cs>
+    const char char_seq_to_c_str<Cs...>::str[sizeof...(Cs) + size] =
+      {'t','u','p','l','e','_','e','l','e','m','e','n','t', Cs..., '\0'};
+
+    //! Converts a number into a sequence of characters
+    /*! @tparam Q The quotient of dividing the original number by 10
+        @tparam R The remainder of dividing the original number by 10
+        @tparam C The sequence built so far
+        @internal */
+    template <size_t Q, size_t R, char ... C>
+    struct to_string_impl
+    {
+      using type = typename to_string_impl<Q/10, Q%10, R+'0', C...>::type;
+    };
+
+    //! Base case with no quotient
+    /*! @internal */
+    template <size_t R, char ... C>
+    struct to_string_impl<0, R, C...>
+    {
+      using type = char_seq_to_c_str<R+'0', C...>;
+    };
+
+    //! Generates a c string for a given index of a tuple
+    /*! Example use:
+        @code{cpp}
+        tuple_element_name<3>::c_str();// returns "tuple_element3"
+        @endcode
+        @internal */
+    template<size_t T>
+    struct tuple_element_name
+    {
+      using type = typename to_string_impl<T/10, T%10>::type;
+      static const typename type::arr_type c_str(){ return type::str; };
+    };
+
+    // unwinds a tuple to save it
+    //! @internal
+    template <size_t Height>
+    struct serialize
+    {
+      template <class Archive, class ... Types> inline
+      static void apply( Archive & ar, std::tuple<Types...> & tuple )
+      {
+        serialize<Height - 1>::template apply( ar, tuple );
+        ar( CEREAL_NVP_(tuple_element_name<Height - 1>::c_str(),
+            std::get<Height - 1>( tuple )) );
+      }
+    };
+
+    // Zero height specialization - nothing to do here
+    //! @internal
+    template <>
+    struct serialize<0>
+    {
+      template <class Archive, class ... Types> inline
+      static void apply( Archive &, std::tuple<Types...> & )
+      { }
+    };
+  }
+
+  //! Serializing for std::tuple
+  template <class Archive, class ... Types> inline
+  void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::tuple<Types...> & tuple )
+  {
+    tuple_detail::serialize<std::tuple_size<std::tuple<Types...>>::value>::template apply( ar, tuple );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_TUPLE_HPP_
diff --git a/include/cereal/types/unordered_map.hpp b/include/cereal/types/unordered_map.hpp
new file mode 100644
index 0000000..8ee828d
--- /dev/null
+++ b/include/cereal/types/unordered_map.hpp
@@ -0,0 +1,100 @@
+/*! \file unordered_map.hpp
+    \brief Support for types found in \<unordered_map\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_UNORDERED_MAP_HPP_
+#define CEREAL_TYPES_UNORDERED_MAP_HPP_
+
+#include <cereal/cereal.hpp>
+#include <unordered_map>
+
+namespace cereal
+{
+  namespace unordered_map_detail
+  {
+    //! @internal
+    template <class Archive, class MapT> inline
+    void save( Archive & ar, MapT const & map )
+    {
+      ar( make_size_tag( static_cast<size_type>(map.size()) ) );
+
+      for( const auto & i : map )
+        ar( make_map_item(i.first, i.second) );
+    }
+
+    //! @internal
+    template <class Archive, class MapT> inline
+    void load( Archive & ar, MapT & map )
+    {
+      size_type size;
+      ar( make_size_tag( size ) );
+
+      map.clear();
+      map.reserve( static_cast<std::size_t>( size ) );
+
+      for( size_type i = 0; i < size; ++i )
+      {
+        typename MapT::key_type key;
+        typename MapT::mapped_type value;
+
+        ar( make_map_item(key, value) );
+        map.emplace( std::move( key ), std::move( value ) );
+      }
+    }
+  }
+
+  //! Saving for std::unordered_map
+  template <class Archive, class K, class T, class H, class KE, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> const & unordered_map )
+  {
+    unordered_map_detail::save( ar, unordered_map );
+  }
+
+  //! Loading for std::unordered_map
+  template <class Archive, class K, class T, class H, class KE, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> & unordered_map )
+  {
+    unordered_map_detail::load( ar, unordered_map );
+  }
+
+  //! Saving for std::unordered_multimap
+  template <class Archive, class K, class T, class H, class KE, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> const & unordered_multimap )
+  {
+    unordered_map_detail::save( ar, unordered_multimap );
+  }
+
+  //! Loading for std::unordered_multimap
+  template <class Archive, class K, class T, class H, class KE, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> & unordered_multimap )
+  {
+    unordered_map_detail::load( ar, unordered_multimap );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_UNORDERED_MAP_HPP_
diff --git a/include/cereal/types/unordered_set.hpp b/include/cereal/types/unordered_set.hpp
new file mode 100644
index 0000000..f3cdebd
--- /dev/null
+++ b/include/cereal/types/unordered_set.hpp
@@ -0,0 +1,99 @@
+/*! \file unordered_set.hpp
+    \brief Support for types found in \<unordered_set\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_UNORDERED_SET_HPP_
+#define CEREAL_TYPES_UNORDERED_SET_HPP_
+
+#include <cereal/cereal.hpp>
+#include <unordered_set>
+
+namespace cereal
+{
+  namespace unordered_set_detail
+  {
+    //! @internal
+    template <class Archive, class SetT> inline
+    void save( Archive & ar, SetT const & set )
+    {
+      ar( make_size_tag( static_cast<size_type>(set.size()) ) );
+
+      for( const auto & i : set )
+        ar( i );
+    }
+
+    //! @internal
+    template <class Archive, class SetT> inline
+    void load( Archive & ar, SetT & set )
+    {
+      size_type size;
+      ar( make_size_tag( size ) );
+
+      set.clear();
+      set.reserve( static_cast<std::size_t>( size ) );
+
+      for( size_type i = 0; i < size; ++i )
+      {
+        typename SetT::key_type key;
+
+        ar( key );
+        set.emplace( std::move( key ) );
+      }
+    }
+  }
+
+  //! Saving for std::unordered_set
+  template <class Archive, class K, class H, class KE, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
+  {
+    unordered_set_detail::save( ar, unordered_set );
+  }
+
+  //! Loading for std::unordered_set
+  template <class Archive, class K, class H, class KE, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
+  {
+    unordered_set_detail::load( ar, unordered_set );
+  }
+
+  //! Saving for std::unordered_multiset
+  template <class Archive, class K, class H, class KE, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
+  {
+    unordered_set_detail::save( ar, unordered_multiset );
+  }
+
+  //! Loading for std::unordered_multiset
+  template <class Archive, class K, class H, class KE, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
+  {
+    unordered_set_detail::load( ar, unordered_multiset );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_UNORDERED_SET_HPP_
diff --git a/include/cereal/types/utility.hpp b/include/cereal/types/utility.hpp
new file mode 100644
index 0000000..1dc382d
--- /dev/null
+++ b/include/cereal/types/utility.hpp
@@ -0,0 +1,47 @@
+/*! \file utility.hpp
+    \brief Support for types found in \<utility\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_UTILITY_HPP_
+#define CEREAL_TYPES_UTILITY_HPP_
+
+#include <cereal/cereal.hpp>
+#include <utility>
+
+namespace cereal
+{
+  //! Serializing for std::pair
+  template <class Archive, class T1, class T2> inline
+  void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::pair<T1, T2> & pair )
+  {
+    ar( CEREAL_NVP_("first",  pair.first),
+        CEREAL_NVP_("second", pair.second) );
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_UTILITY_HPP_
diff --git a/include/cereal/types/valarray.hpp b/include/cereal/types/valarray.hpp
new file mode 100644
index 0000000..eade2fe
--- /dev/null
+++ b/include/cereal/types/valarray.hpp
@@ -0,0 +1,89 @@
+/*! \file valarray.hpp
+\brief Support for types found in \<valarray\>
+\ingroup STLSupport */
+
+/*
+Copyright (c) 2014, Randolph Voorhies, Shane Grant
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of cereal nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CEREAL_TYPES_VALARRAY_HPP_
+#define CEREAL_TYPES_VALARRAY_HPP_
+
+#include <cereal/cereal.hpp>
+#include <valarray>
+
+namespace cereal
+{
+  //! Saving for std::valarray arithmetic types, using binary serialization, if supported
+  template <class Archive, class T> inline
+  typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
+  {
+    ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
+    ar( binary_data( &valarray[0], valarray.size() * sizeof(T) ) ); // &valarray[0] ok since guaranteed contiguous
+  }
+
+  //! Loading for std::valarray arithmetic types, using binary serialization, if supported
+  template <class Archive, class T> inline
+  typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
+  {
+    size_type valarraySize;
+    ar( make_size_tag( valarraySize ) );
+
+    valarray.resize( static_cast<std::size_t>( valarraySize ) );
+    ar( binary_data( &valarray[0], static_cast<std::size_t>( valarraySize ) * sizeof(T) ) );
+  }
+
+  //! Saving for std::valarray all other types
+  template <class Archive, class T> inline
+  typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::valarray<T> const & valarray )
+  {
+    ar( make_size_tag( static_cast<size_type>(valarray.size()) ) ); // number of elements
+    for(auto && v : valarray)
+      ar(v);
+  }
+
+  //! Loading for std::valarray all other types
+  template <class Archive, class T> inline
+  typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::valarray<T> & valarray )
+  {
+    size_type valarraySize;
+    ar( make_size_tag( valarraySize ) );
+
+    valarray.resize( static_cast<size_t>( valarraySize ) );
+    for(auto && v : valarray)
+      ar(v);
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_VALARRAY_HPP_
diff --git a/include/cereal/types/vector.hpp b/include/cereal/types/vector.hpp
new file mode 100644
index 0000000..36a2a4c
--- /dev/null
+++ b/include/cereal/types/vector.hpp
@@ -0,0 +1,112 @@
+/*! \file vector.hpp
+    \brief Support for types found in \<vector\>
+    \ingroup STLSupport */
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TYPES_VECTOR_HPP_
+#define CEREAL_TYPES_VECTOR_HPP_
+
+#include <cereal/cereal.hpp>
+#include <vector>
+
+namespace cereal
+{
+  //! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
+  template <class Archive, class T, class A> inline
+  typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
+  {
+    ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
+    ar( binary_data( vector.data(), vector.size() * sizeof(T) ) );
+  }
+
+  //! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported
+  template <class Archive, class T, class A> inline
+  typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          && std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
+  {
+    size_type vectorSize;
+    ar( make_size_tag( vectorSize ) );
+
+    vector.resize( static_cast<std::size_t>( vectorSize ) );
+    ar( binary_data( vector.data(), static_cast<std::size_t>( vectorSize ) * sizeof(T) ) );
+  }
+
+  //! Serialization for non-arithmetic vector types
+  template <class Archive, class T, class A> inline
+  typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
+  {
+    ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
+    for(auto && v : vector)
+      ar( v );
+  }
+
+  //! Serialization for non-arithmetic vector types
+  template <class Archive, class T, class A> inline
+  typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
+                          || !std::is_arithmetic<T>::value, void>::type
+  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+
+    vector.resize( static_cast<std::size_t>( size ) );
+    for(auto && v : vector)
+      ar( v );
+  }
+
+  //! Serialization for bool vector types
+  template <class Archive, class A> inline
+  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<bool, A> const & vector )
+  {
+    ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
+    for(auto && v : vector)
+      ar( static_cast<bool>(v) );
+  }
+
+  //! Serialization for bool vector types
+  template <class Archive, class A> inline
+  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<bool, A> & vector )
+  {
+    size_type size;
+    ar( make_size_tag( size ) );
+
+    vector.resize( static_cast<std::size_t>( size ) );
+    for(auto && v : vector)
+    {
+      bool b;
+      ar( b );
+      v = b;
+    }
+  }
+} // namespace cereal
+
+#endif // CEREAL_TYPES_VECTOR_HPP_
diff --git a/sandbox/CMakeLists.txt b/sandbox/CMakeLists.txt
new file mode 100644
index 0000000..5008e42
--- /dev/null
+++ b/sandbox/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_subdirectory(sandbox_shared_lib)
+
+add_executable(sandbox sandbox.cpp)
+add_executable(sandbox_json sandbox_json.cpp)
+add_executable(sandbox_rtti sandbox_rtti.cpp)
+
+add_executable(sandbox_vs sandbox_vs.cpp)
+target_link_libraries(sandbox_vs sandbox_vs_dll)
+include_directories(sandbox_shared_lib)
+
+if(Boost_FOUND)
+  add_executable(performance performance.cpp)
+  target_link_libraries(performance ${Boost_LIBRARIES})
+endif(Boost_FOUND)
diff --git a/sandbox/performance.cpp b/sandbox/performance.cpp
new file mode 100644
index 0000000..e5d61f0
--- /dev/null
+++ b/sandbox/performance.cpp
@@ -0,0 +1,469 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifdef _MSC_VER
+#  pragma warning(push)
+#  pragma warning(disable : 4244 4267)
+#endif
+
+#include <sstream>
+#include <iostream>
+#include <chrono>
+#include <random>
+
+#include <boost/format.hpp>
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/base_object.hpp>
+
+#include <cereal/archives/binary.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/string.hpp>
+#include <cereal/types/map.hpp>
+
+//! Runs serialization to save data to an ostringstream
+/*! Used to time how long it takes to save data to an ostringstream.
+    Everything that happens within the save function will be timed, including
+    any set-up necessary to perform the serialization.
+
+    @param data The data to save
+    @param saveFunction A function taking in an ostringstream and the data and returning void
+    @return The ostringstream and the time it took to save the data */
+template <class T>
+std::chrono::nanoseconds
+saveData( T const & data, std::function<void(std::ostringstream &, T const&)> saveFunction, std::ostringstream & os )
+{
+  auto start = std::chrono::high_resolution_clock::now();
+  saveFunction( os, data );
+  return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now() - start );
+}
+
+//! Runs serialization to load data to from an istringstream
+/*! Used to time how long it takes to load data from an istringstream.
+    Everything that happens within the load function will be timed, including
+    any set-up necessary to perform the serialization.
+
+    @param dataStream The saved data stream
+    @param loadFunction A function taking in an istringstream and a data reference and returning void
+    @return The loaded data and the time it took to save the data */
+template <class T>
+std::pair<T, std::chrono::nanoseconds>
+loadData( std::ostringstream const & dataStream, std::function<void(std::istringstream &, T &)> loadFunction )
+{
+  T data;
+  std::istringstream os( dataStream.str() );
+
+  auto start = std::chrono::high_resolution_clock::now();
+  loadFunction( os, data );
+
+  return {data, std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now() - start )};
+}
+
+struct cerealBinary
+{
+  //! Saves data to a cereal binary archive
+  template <class T>
+  static void save( std::ostringstream & os, T const & data )
+  {
+    cereal::BinaryOutputArchive oar(os);
+    oar(data);
+  }
+
+  //! Loads data to a cereal binary archive
+  template <class T>
+  static void load( std::istringstream & is, T & data )
+  {
+    cereal::BinaryInputArchive iar(is);
+    iar(data);
+  }
+};
+
+struct boostBinary
+{
+  //! Saves data to a boost binary archive
+  template <class T>
+  static void save( std::ostringstream & os, T const & data )
+  {
+    boost::archive::binary_oarchive oar(os);
+    oar & data;
+  }
+
+  //! Loads data to a boost binary archive
+  template <class T>
+  static void load( std::istringstream & is, T & data )
+  {
+    boost::archive::binary_iarchive iar(is);
+    iar & data;
+  }
+};
+
+struct binary
+{
+  typedef boostBinary  boost;
+  typedef cerealBinary cereal;
+};
+
+//! Times how long it takes to serialize (load and store) some data
+/*! Times how long and the size of the serialization object used to serialize
+    some data.  Result is output to standard out.
+
+    @tparam SerializationT The serialization struct that has all save and load functions
+    @tparam DataTCereal The type of data to test for cereal
+    @tparam DataTBoost The type of data to test for boost
+    @param name The name for this test
+    @param data The data to serialize for cereal
+    @param data The data to serialize for boost
+    @param numAverages The number of times to average
+    @param validateData Whether data should be validated (input == output) */
+template <class SerializationT, class DataTCereal, class DataTBoost>
+void test( std::string const & name,
+            DataTCereal const & dataC,
+            DataTBoost const & dataB,
+            size_t numAverages = 100,
+            bool validateData = false );
+
+template <class SerializationT, class DataTCereal, class DataTBoost>
+void test( std::string const & name,
+            DataTCereal const & dataC,
+            DataTBoost const & dataB,
+            size_t numAverages,
+            bool /*validateData*/ )
+{
+  std::cout << "-----------------------------------" << std::endl;
+  std::cout << "Running test: " << name << std::endl;
+
+  std::chrono::nanoseconds totalBoostSave{0};
+  std::chrono::nanoseconds totalBoostLoad{0};
+
+  std::chrono::nanoseconds totalCerealSave{0};
+  std::chrono::nanoseconds totalCerealLoad{0};
+
+  size_t boostSize = 0;
+  size_t cerealSize = 0;
+
+  for(size_t i = 0; i < numAverages; ++i)
+  {
+    // Boost
+    {
+      std::ostringstream os;
+      auto saveResult = saveData<DataTBoost>( dataB, {SerializationT::boost::template save<DataTBoost>}, os );
+      totalBoostSave += saveResult;
+      if(!boostSize)
+        boostSize = os.tellp();
+
+      auto loadResult = loadData<DataTBoost>( os, {SerializationT::boost::template load<DataTBoost>} );
+      totalBoostLoad += loadResult.second;
+    }
+
+    // Cereal
+    {
+      std::ostringstream os;
+      auto saveResult = saveData<DataTCereal>( dataC, {SerializationT::cereal::template save<DataTCereal>}, os );
+      totalCerealSave += saveResult;
+      if(!cerealSize)
+        cerealSize = os.tellp();
+
+      auto loadResult = loadData<DataTCereal>( os, {SerializationT::cereal::template load<DataTCereal>} );
+      totalCerealLoad += loadResult.second;
+    }
+  }
+
+  // Averages
+  double averageBoostSave = std::chrono::duration_cast<std::chrono::milliseconds>(totalBoostSave).count() / static_cast<double>( numAverages );
+  double averageBoostLoad = std::chrono::duration_cast<std::chrono::milliseconds>(totalBoostLoad).count() / static_cast<double>( numAverages );
+
+  double averageCerealSave = std::chrono::duration_cast<std::chrono::milliseconds>(totalCerealSave).count() / static_cast<double>( numAverages );
+  double averageCerealLoad = std::chrono::duration_cast<std::chrono::milliseconds>(totalCerealLoad).count() / static_cast<double>( numAverages );
+
+  // Percentages relative to boost
+  double cerealSaveP = averageCerealSave / averageBoostSave;
+  double cerealLoadP = averageCerealLoad / averageBoostLoad;
+  double cerealSizeP = cerealSize / static_cast<double>( boostSize );
+
+  std::cout << "  Boost results:" << std::endl;
+  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
+    % averageBoostSave % 1.0 % (boostSize / 1024.0) % 1.0 % static_cast<double>( std::chrono::duration_cast<std::chrono::milliseconds>(totalBoostSave).count() );
+  std::cout << std::endl;
+  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
+    % averageBoostLoad % 1.0 % static_cast<double>( std::chrono::duration_cast<std::chrono::milliseconds>(totalBoostLoad).count() );
+  std::cout << std::endl;
+
+  std::cout << "  Cereal results:" << std::endl;
+  std::cout << boost::format("\tsave | time: %06.4fms (%1.2f) size: %20.8fkb (%1.8f) total: %6.1fms")
+    % averageCerealSave % cerealSaveP % (cerealSize / 1024.0) % cerealSizeP % static_cast<double>( std::chrono::duration_cast<std::chrono::milliseconds>(totalCerealSave).count() );
+  std::cout << std::endl;
+  std::cout << boost::format("\tload | time: %06.4fms (%1.2f) total: %6.1fms")
+    % averageCerealLoad % cerealLoadP % static_cast<double>( std::chrono::duration_cast<std::chrono::milliseconds>(totalCerealLoad).count() );
+  std::cout << std::endl;
+}
+
+template <class SerializationT, class DataT>
+void test( std::string const & name,
+            DataT const & data,
+            size_t numAverages = 100,
+            bool validateData = false )
+{
+  return test<SerializationT, DataT, DataT>( name, data, data, numAverages, validateData );
+}
+
+template<class T>
+typename std::enable_if<std::is_floating_point<T>::value, T>::type
+random_value(std::mt19937 & gen)
+{ return std::uniform_real_distribution<T>(-10000.0, 10000.0)(gen); }
+
+template<class T>
+typename std::enable_if<std::is_integral<T>::value && sizeof(T) != sizeof(char), T>::type
+random_value(std::mt19937 & gen)
+{ return std::uniform_int_distribution<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen); }
+
+template<class T>
+typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(char), T>::type
+random_value(std::mt19937 & gen)
+{ return static_cast<T>( std::uniform_int_distribution<int64_t>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen) ); }
+
+template<class T>
+typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
+random_value(std::mt19937 & gen)
+{
+  std::string s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
+  for(char & c : s)
+    c = std::uniform_int_distribution<char>(' ', '~')(gen);
+  return s;
+}
+
+template<class C>
+std::basic_string<C> random_basic_string(std::mt19937 & gen, size_t maxSize = 30)
+{
+  std::basic_string<C> s(std::uniform_int_distribution<int>(3, maxSize)(gen), ' ');
+  for(C & c : s)
+    c = static_cast<C>( std::uniform_int_distribution<int>( '~', '~' )(gen) );
+  return s;
+  return s;
+}
+
+template <size_t N>
+std::string random_binary_string(std::mt19937 & gen)
+{
+  std::string s(N, ' ');
+  for(auto & c : s )
+    c = std::uniform_int_distribution<char>('0', '1')(gen);
+  return s;
+}
+
+struct PoDStructCereal
+{
+  int32_t a;
+  int64_t b;
+  float c;
+  double d;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar(a, b, c, d);
+  }
+};
+
+struct PoDStructBoost
+{
+  int32_t a;
+  int64_t b;
+  float c;
+  double d;
+
+  template <class Archive>
+  void serialize( Archive & ar, const unsigned int /*version*/ )
+  {
+    ar & a & b & c & d;
+  }
+};
+
+struct PoDChildCereal : virtual PoDStructCereal
+{
+  PoDChildCereal() : v(1024)
+  { }
+
+  std::vector<float> v;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( cereal::virtual_base_class<PoDStructCereal>(this), v );
+  }
+};
+
+struct PoDChildBoost : virtual PoDStructBoost
+{
+  PoDChildBoost() : v(1024)
+  { }
+
+  std::vector<float> v;
+
+  template <class Archive>
+  void serialize( Archive & ar, const unsigned int /*version*/ )
+  {
+    ar & boost::serialization::base_object<PoDStructBoost>(*this);
+    ar & v;
+  }
+};
+
+int main()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+  auto rngC = [&](){ return random_value<uint8_t>(gen); };
+  auto rngD = [&](){ return random_value<double>(gen); };
+  const bool randomize = false;
+
+  //########################################
+  auto vectorDoubleTest = [&](size_t s, bool randomize_)
+  {
+    std::ostringstream name;
+    name << "Vector(double) size " << s;
+
+    std::vector<double> data(s);
+    if(randomize_)
+      for( auto & d : data )
+        d = rngD();
+
+    test<binary>( name.str(), data );
+  };
+
+  vectorDoubleTest(1, randomize); // 8B
+  vectorDoubleTest(16, randomize); // 128B
+  vectorDoubleTest(1024, randomize); // 8KB
+  vectorDoubleTest(1024*1024, randomize); // 8MB
+
+  //########################################
+  auto vectorCharTest = [&](size_t s, bool randomize_)
+  {
+    std::ostringstream name;
+    name << "Vector(uint8_t) size " << s;
+
+    std::vector<uint8_t> data(s);
+    if(randomize_)
+      for( auto & d : data )
+        d = rngC();
+
+    test<binary>( name.str(), data );
+  };
+
+  vectorCharTest(1024*1024*64, randomize);
+
+  //########################################
+  auto vectorPoDStructTest = [&](size_t s)
+  {
+    std::ostringstream name;
+    name << "Vector(PoDStruct) size " << s;
+
+    std::vector<PoDStructCereal> dataC(s);
+    std::vector<PoDStructBoost> dataB(s);
+    test<binary>( name.str(), dataC, dataB );
+  };
+
+  vectorPoDStructTest(1);
+  vectorPoDStructTest(64);
+  vectorPoDStructTest(1024);
+  vectorPoDStructTest(1024*1024);
+  vectorPoDStructTest(1024*1024*2);
+
+  //########################################
+  auto vectorPoDChildTest = [&](size_t s)
+  {
+    std::ostringstream name;
+    name << "Vector(PoDChild) size " << s;
+
+    std::vector<PoDChildCereal> dataC(s);
+    std::vector<PoDChildBoost> dataB(s);
+    test<binary>( name.str(), dataC, dataB );
+  };
+
+  vectorPoDChildTest(1024);
+  vectorPoDChildTest(1024*32);
+
+  //########################################
+  auto stringTest = [&](size_t s)
+  {
+    std::ostringstream name;
+    name << "String size " << s;
+
+    std::string data = random_basic_string<char>(gen, s);
+    std::cout << "data.size " << data.size() << std::endl;
+    test<binary>( name.str(), data );
+  };
+
+  stringTest(200000);
+  stringTest(2000000);
+  stringTest(20000000);
+
+  //########################################
+  auto vectorStringTest = [&](size_t s)
+  {
+    std::ostringstream name;
+    name << "Vector(String) size " << s;
+
+    std::vector<std::string> data(s);
+    for(size_t i=0; i<data.size(); ++i)
+      data[i] = random_basic_string<char>(gen);
+
+    test<binary>( name.str(), data );
+  };
+
+  vectorStringTest(512);
+  vectorStringTest(1024);
+  vectorStringTest(1024*64);
+  vectorStringTest(1024*128);
+
+  //########################################
+  auto mapPoDStructTest = [&](size_t s)
+  {
+    std::ostringstream name;
+    name << "Map(PoDStruct) size " <<s;
+
+    std::map<std::string, PoDStructCereal> mC;
+    std::map<std::string, PoDStructBoost> mB;
+    for(size_t i=0; i<s; ++i)
+    {
+      mC[std::to_string( i )] = PoDStructCereal();
+      mB[std::to_string( i )] = PoDStructBoost();
+    }
+    test<binary>(name.str(), mC, mB);
+  };
+
+  mapPoDStructTest(1024);
+  mapPoDStructTest(1024*64);
+
+  return 0;
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/sandbox/sandbox.cpp b/sandbox/sandbox.cpp
new file mode 100644
index 0000000..b1ca284
--- /dev/null
+++ b/sandbox/sandbox.cpp
@@ -0,0 +1,820 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <cereal/cereal.hpp>
+#include <cereal/archives/binary.hpp>
+#include <cereal/archives/portable_binary.hpp>
+#include <cereal/archives/xml.hpp>
+
+#include <cereal/types/string.hpp>
+#include <cereal/types/utility.hpp>
+#include <cereal/types/memory.hpp>
+#include <cereal/types/complex.hpp>
+#include <cereal/types/base_class.hpp>
+#include <cereal/types/array.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/utility.hpp>
+#include <cereal/types/bitset.hpp>
+#include <cereal/types/polymorphic.hpp>
+
+//#include <cxxabi.h>
+#include <sstream>
+#include <fstream>
+#include <cassert>
+#include <complex>
+#include <iostream>
+#include <random>
+
+class Base
+{
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void serialize( Archive & ar )
+    {
+      std::cout << "Base serialize" << std::endl;
+      ar( x );
+    }
+
+    virtual void foo() = 0;
+
+  public:
+    int x;
+};
+
+class Derived : public Base
+{
+  public:
+    using Base::x;
+    Derived() : Base(), y() {}
+    Derived( int d, int b )
+    {
+      y = d;
+      x = b;
+    }
+
+    template <class Archive>
+    void save( Archive & ar ) const
+    {
+      ar( cereal::virtual_base_class<Base>(this) );
+      std::cout << "Derived save" << std::endl;
+      ar( y );
+    }
+
+    template <class Archive>
+    void load( Archive & ar )
+    {
+      ar( cereal::virtual_base_class<Base>(this) );
+      std::cout << "Derived load" << std::endl;
+      ar( y );
+    }
+
+    void foo() {}
+
+    int y;
+};
+
+namespace cereal
+{
+  template <class Archive> struct specialize<Archive, Derived, cereal::specialization::member_load_save> {};
+}
+
+CEREAL_REGISTER_TYPE(Derived)
+
+// ###################################
+struct Test1
+{
+  int a;
+
+  private:
+    friend class cereal::access;
+    template<class Archive>
+    void serialize(Archive & ar)
+    {
+      ar(CEREAL_NVP(a));
+    }
+};
+
+// ###################################
+class Test2
+{
+  public:
+    Test2() {}
+    Test2( int x ) : a( x ) {}
+    int a;
+
+  private:
+    friend class cereal::access;
+
+    template<class Archive>
+      void save(Archive & ar) const
+      {
+        ar(a);
+      }
+
+    template<class Archive>
+      void load(Archive & ar)
+      {
+        ar(a);
+      }
+};
+
+// ###################################
+struct Test3
+{
+  int a;
+};
+
+template<class Archive>
+void serialize(Archive & ar, Test3 & t)
+{
+  ar(CEREAL_NVP(t.a));
+}
+
+namespace test4
+{
+  // ###################################
+  struct Test4
+  {
+    int a;
+  };
+
+  template<class Archive>
+  void save(Archive & ar, Test4 const & t)
+  {
+    ar(CEREAL_NVP(t.a));
+  }
+
+  template<class Archive>
+  void load(Archive & ar, Test4 & t)
+  {
+    ar(CEREAL_NVP(t.a));
+  }
+}
+
+class Private
+{
+  public:
+    Private() : a('z') {}
+
+  private:
+    char a;
+
+    friend class cereal::access;
+
+    template<class Archive>
+      void serialize(Archive & ar)
+      {
+        ar(a);
+      }
+};
+
+struct Everything
+{
+  int x;
+  int y;
+  Test1 t1;
+  Test2 t2;
+  Test3 t3;
+  test4::Test4 t4;
+  std::string s;
+
+  template<class Archive>
+  void serialize(Archive & ar)
+  {
+    ar(CEREAL_NVP(x));
+    ar(CEREAL_NVP(y));
+    ar(CEREAL_NVP(t1));
+    ar(CEREAL_NVP(t2));
+    ar(CEREAL_NVP(t3));
+    ar(CEREAL_NVP(t4));
+    ar(CEREAL_NVP(s));
+  }
+
+  bool operator==(Everything const & o)
+  {
+    return
+      x == o.x &&
+      y == o.y &&
+      t1.a == o.t1.a &&
+      t2.a == o.t2.a &&
+      t3.a == o.t3.a &&
+      t4.a == o.t4.a &&
+      s == o.s;
+  }
+};
+
+struct EmptyStruct
+{
+  template<class Archive>
+  void serialize(Archive &)
+  {
+    std::cout << "Side effects!" << std::endl;
+  }
+};
+
+struct NonEmptyStruct
+{
+  int x, y, z;
+};
+
+struct NoDefaultCtor
+{
+private:
+  NoDefaultCtor() {};
+  int z;
+  NoDefaultCtor( int x, bool ) :y(x) {}
+public:
+  NoDefaultCtor(int x) : y(x)
+  { }
+
+  friend class cereal::access;
+
+  int y;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( y );
+  }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
+  {
+    int yy;
+    ar( yy );
+    construct( yy, true );
+    construct->z = 33;
+    construct.ptr()->z = 33;
+  }
+};
+
+//namespace cereal
+//{
+//  template <>
+//  struct LoadAndConstruct<NoDefaultCtor>
+//  {
+//    template <class Archive>
+//    static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
+//    {
+//      int y;
+//      ar( y );
+//      construct( y );
+//    }
+//  };
+//}
+
+struct unordered_naming
+{
+  int x;
+  int y;
+  int z;
+
+  template <class Archive>
+  void save( Archive & ar ) const
+  {
+    ar( CEREAL_NVP(x),
+        CEREAL_NVP(z),
+        CEREAL_NVP(y) );
+  }
+
+  template <class Archive>
+  void load( Archive & ar )
+  {
+    ar( x,
+        CEREAL_NVP(y),
+        CEREAL_NVP(z) );
+  }
+
+  bool operator==( unordered_naming const & other ) const
+  {
+    return x == other.x && y == other.y && z == other.z;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, unordered_naming const & s)
+{
+  os << "[x: " << s.x << " y: " << s.y << " z: " << s.z << "]";
+  return os;
+}
+
+template <class IArchive, class OArchive>
+void test_unordered_loads()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rngI = [](){ return 1; };
+  auto rngF = [](){ return 2.0f; };
+  auto rngD = [](){ return 3.2; };
+
+  for(int i=0; i<100; ++i)
+  {
+    auto const name1 = "1";
+    auto const name2 = "2";
+    auto const name3 = "3";
+    auto const name4 = "4";
+    auto const name5 = "5";
+    auto const name6 = "6";
+    auto const name7 = "7";
+
+    int o_int1 = rngI();
+    double o_double2 = rngD();
+    std::vector<bool> o_vecbool3 = { true, false, true, false, true };
+    int o_int4 = rngI();
+    int o_int5 = rngI();
+    int o_int6 = rngI();
+    std::pair<float, unordered_naming> o_un7;
+    o_un7.first = rngF();
+    o_un7.second.x = rngI();
+    o_un7.second.y = rngI();
+    o_un7.second.z = rngI();
+
+    {
+      std::ofstream os("test.xml");
+      OArchive oar(os);
+
+      oar( cereal::make_nvp( name1, o_int1 ),
+           cereal::make_nvp( name2, o_double2 ),
+           cereal::make_nvp( name3, o_vecbool3 ),
+           cereal::make_nvp( name4, o_int4 ),
+           cereal::make_nvp( name5, o_int5 ),
+           cereal::make_nvp( name6, o_int6 ),
+           cereal::make_nvp( name7, o_un7 ) );
+    }
+
+    decltype(o_int1) i_int1;
+    decltype(o_double2) i_double2;
+    decltype(o_vecbool3) i_vecbool3;
+    decltype(o_int4) i_int4;
+    decltype(o_int5) i_int5;
+    decltype(o_int6) i_int6;
+    decltype(o_un7) i_un7;
+
+    std::ifstream is("test.xml");
+    {
+      IArchive iar(is);
+
+      iar( cereal::make_nvp( name7, o_un7 ),
+           cereal::make_nvp( name2, i_double2 ),
+           cereal::make_nvp( name4, i_int4 ),
+           cereal::make_nvp( name3, i_vecbool3 ),
+           cereal::make_nvp( name1, i_int1 ),
+           cereal::make_nvp( name5, i_int5 ),
+           i_int6 );
+    }
+  }
+}
+
+class BoostTransitionMS
+{
+  public:
+    BoostTransitionMS() {}
+    BoostTransitionMS( int xx ) : x(xx) {}
+
+    int getX(){ return x; }
+    void setX( int xx ){ x = xx; }
+
+  private:
+    friend class cereal::access;
+    int x;
+
+    template <class Archive>
+    void serialize( Archive & ar, const std::uint32_t /*version*/ )
+    { ar( x ); }
+};
+
+class BoostTransitionSplit
+{
+  public:
+    BoostTransitionSplit() {}
+    BoostTransitionSplit( int xx ) : x(xx) {}
+
+    int getX(){ return x; }
+    void setX( int xx ){ x = xx; }
+
+  private:
+    friend class cereal::access;
+    int x;
+
+    template <class Archive>
+    void save( Archive & ar, const std::uint32_t /*version*/ ) const
+    { ar( x ); }
+
+    template <class Archive>
+    void load( Archive & ar, const std::uint32_t /*version*/ )
+    { ar( x ); }
+};
+
+class BoostTransitionNMS
+{
+  public:
+    BoostTransitionNMS() {}
+    BoostTransitionNMS( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void serialize( Archive & ar, BoostTransitionNMS & bnms, const std::uint32_t version )
+{ ar( bnms.x ); std::cout << "NMS version: " << version << std::endl; }
+
+struct BoostTransitionNMSplit
+{
+  public:
+    BoostTransitionNMSplit() {}
+    BoostTransitionNMSplit( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void save( Archive & ar, BoostTransitionNMSplit const & bnsplit, const std::uint32_t version )
+{ ar( bnsplit.x ); std::cout << "NMsave version: " << version << std::endl; }
+
+template <class Archive>
+void load( Archive & ar, BoostTransitionNMSplit & bnsplit, const std::uint32_t version )
+{ ar( bnsplit.x ); std::cout << "NMload version: " << version << std::endl; }
+
+// ######################################################################
+int main()
+{
+  std::cout << std::boolalpha << std::endl;
+
+  Everything e_out;
+  e_out.x = 99;
+  e_out.y = 100;
+  e_out.t1 = {1};
+  e_out.t2 = {2};
+  e_out.t3 = {3};
+  e_out.t4 = {4};
+  e_out.s = "Hello, World!";
+  std::unique_ptr<NoDefaultCtor> nodefault( new NoDefaultCtor( 3 ) );
+
+  Test2 t2 = {22};
+
+  {
+    std::ofstream os("out.txt", std::ios::binary);
+    cereal::BinaryOutputArchive archive(os);
+    archive(CEREAL_NVP(e_out));
+    archive(t2);
+    archive(nodefault);
+  }
+
+  Everything e_in;
+
+  std::unique_ptr<NoDefaultCtor> nodefaultin( new NoDefaultCtor( 1 ) );
+
+  {
+    std::ifstream is("out.txt", std::ios::binary);
+    cereal::BinaryInputArchive archive(is);
+    archive(CEREAL_NVP(e_in));
+    archive(t2);
+    archive(nodefaultin);
+    std::remove("out.txt");
+  }
+
+  assert(e_in == e_out);
+  assert(nodefault->y == nodefaultin->y);
+
+  {
+    cereal::BinaryOutputArchive archive(std::cout);
+    int xxx[] = {-1, 95, 3};
+    archive( xxx );
+
+    cereal::XMLOutputArchive archive2(std::cout, cereal::XMLOutputArchive::Options(std::numeric_limits<double>::max_digits10, true, true));
+    archive2( xxx );
+
+    std::vector<int> yyy = {1, 2, 3};
+    archive2( yyy );
+
+    archive2.saveBinaryValue( xxx, sizeof(int)*3 );
+  }
+
+  {
+    std::ofstream os("out.xml");
+    cereal::XMLOutputArchive oar( os );
+    //cereal::XMLOutputArchive oar( std::cout );
+
+    oar( cereal::make_nvp("hello", 5 ) );
+
+    std::string bla("bla");
+    oar( bla );
+
+    auto intptr = std::make_shared<int>(99);
+    oar( CEREAL_NVP(intptr) );
+
+    std::map<std::string, int> map1 =
+    {
+      {"one",   1},
+      {"two",   2},
+      {"three", 3}
+    };
+
+    oar( CEREAL_NVP(map1) );
+
+    int x = 3;
+    oar( CEREAL_NVP(x) );
+    oar( 5 );
+    oar( 3.3 );
+    oar( 3.2f );
+    oar( true );
+
+    std::array<int,5> arr = {{1, 2, 3, 4, 5}};
+    oar( arr );
+
+    std::vector<std::string> vec = {"hey",
+                                    "there",
+                                    "buddy"};
+
+    std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
+
+    oar( cereal::make_nvp("EVERYTHING", e_out) );
+    oar( vec );
+    oar( vec2 );
+
+    int xxx[] = {-1, 95, 3};
+    oar.saveBinaryValue( xxx, sizeof(int)*3, "xxxbinary" );
+    //oar.saveBinaryValue( xxx, sizeof(int)*3 );
+
+    std::unique_ptr<Derived> d1( new Derived(3, 4) );
+    std::unique_ptr<Base> d2( new Derived(4, 5) );
+    std::shared_ptr<Base> d3( new Derived(5, 6) );
+    oar( d1 );
+    oar( d2 );
+    oar( d3 );
+  }
+
+  {
+    std::ifstream is("out.xml");
+    cereal::XMLInputArchive iar( is );
+
+    int hello;
+    iar( cereal::make_nvp("hello", hello) );
+    assert( hello == 5 );
+
+    std::string bla;
+    iar( bla );
+    assert( bla == "bla" );
+
+    std::shared_ptr<int> intptr;
+    iar( CEREAL_NVP(intptr) );
+    assert( *intptr == 99 );
+
+    std::map<std::string, int> map1;
+
+    iar( CEREAL_NVP(map1) );
+    assert( map1["one"]   == 1 );
+    assert( map1["two"]   == 2 );
+    assert( map1["three"] == 3 );
+
+
+    int x;
+    iar( CEREAL_NVP(x) );
+    assert( x == 3 );
+
+    int x5;
+    iar( x5 );
+    assert( x5 == 5 );
+
+    double x33;
+    iar( x33 );
+    assert( x33 == 3.3 );
+
+    float x32;
+    iar( x32 );
+    assert( x32 == 3.2f );
+
+    bool xtrue;
+    iar( xtrue );
+    assert( xtrue == true );
+
+    std::array<int,5> arr;
+    iar( arr );
+    for( int i = 0; i < 5; ++i )
+      assert( arr[i] == (i+1) );
+
+    Everything e;
+    iar( cereal::make_nvp("EVERYTHING", e) );
+    assert( e == e_out );
+
+    std::vector<std::string> vec;
+    iar( vec );
+    assert( vec[0] == "hey" );
+    assert( vec[1] == "there" );
+    assert( vec[2] == "buddy" );
+
+    std::vector<std::vector<std::string>> vec2;
+    iar( vec2 );
+    for( auto & v : vec2 )
+    {
+      assert( v[0] == "hey" );
+      assert( v[1] == "there" );
+      assert( v[2] == "buddy" );
+    }
+
+    int xxx[3];
+    iar.loadBinaryValue( xxx, sizeof(int)*3 );
+    assert( xxx[0] == -1 );
+    assert( xxx[1] == 95 );
+    assert( xxx[2] == 3 );
+
+    std::unique_ptr<Derived> d1;
+    std::unique_ptr<Base> d2;
+    std::shared_ptr<Base> d3;
+
+    iar( d1 );
+    assert( d1->x == 4 && d1->y == 3 );
+    iar( d2 );
+    assert( ((Derived*)d2.get())->x == 5 && ((Derived*)d2.get())->y == 4 );
+    iar( d3 );
+    assert( ((Derived*)d3.get())->x == 6 && ((Derived*)d3.get())->y == 5 );
+  }
+
+  {
+    std::ofstream b("endian.out", std::ios::binary);
+    cereal::PortableBinaryOutputArchive oar(b);
+
+    bool bb = true;
+    char a = 'a';
+    int x = 1234;
+    float y = 1.324f;
+    double z = 3.1452;
+    long double d = 1.123451234512345;
+    long long j = 2394873298472343;
+
+    oar( bb, a, x, y, z, d, j );
+    std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
+    // valgrind will complain about uninitialized bytes here - seems to be the padding caused by the long double and
+    // long long allocations (this padding just exists on the stack and is never used anywhere)
+    // see https://bugs.kde.org/show_bug.cgi?id=197915
+  }
+  {
+    std::ifstream b("endian.out", std::ios::binary);
+    cereal::PortableBinaryInputArchive iar(b);
+
+    bool bb;
+    char a;
+    int x;
+    float y;
+    double z;
+    long double d;
+    long long j;
+
+    iar( bb, a, x, y, z, d, j );
+
+    std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
+
+    std::remove("endian.out");
+  }
+
+  {
+    std::ofstream ss("xml_ordering.out");
+    cereal::XMLOutputArchive ar(ss);
+
+    double one = 1;
+    double two = 2;
+    double three = 3;
+    std::vector<int> four = {1, 2, 3, 4};
+
+    // Output is ordered 3 2 1 4
+    ar( three, CEREAL_NVP(two), one, cereal::make_nvp("five", four) );
+  }
+
+  {
+    std::ifstream ss("xml_ordering.out");
+    cereal::XMLInputArchive ar(ss);
+
+    // Output prodered out of order, try to load in order 1 2 3 4
+    double one;
+    double two;
+    double three;
+    std::vector<int> four;
+
+    ar( one ); // cereal can only give warnings if you used an NVP!
+    ar( CEREAL_NVP( two ) );
+    ar( three );
+
+    try
+    {
+      ar( CEREAL_NVP( three ) );
+    }
+    catch( cereal::Exception const & e )
+    {
+      std::cout << e.what() << std::endl;
+      std::cout << "Looked for three but we didn't use an NVP when saving" << std::endl;
+    }
+    ar( cereal::make_nvp("five", four) );
+    ar( cereal::make_nvp("five", four) ); // do it a second time since it shouldn't matter as we provide the name
+
+    std::cout << one << std::endl;
+    std::cout << two << std::endl;
+    std::cout << three << std::endl;
+    for( auto i : four ) std::cout << i << " ";
+    std::cout << std::endl;
+  }
+
+  {
+    // Boost transition layer stuff
+    std::ofstream ss("cereal_version.out");
+    cereal::XMLOutputArchive ar(ss);
+
+    BoostTransitionMS b(3);
+    ar( b, b );
+
+    BoostTransitionSplit c(4);
+    ar( c, c );
+
+    BoostTransitionNMS d(5);
+    ar( d, d );
+
+    BoostTransitionNMSplit e(32);
+    ar( e, e );
+  }
+
+  {
+    // Boost transition layer stuff
+    std::ifstream ss("cereal_version.out");
+    cereal::XMLInputArchive ar(ss);
+
+    BoostTransitionMS b;
+    ar( b );
+    assert( b.getX() == 3 );
+    b.setX( 0 );
+    ar( b );
+    assert( b.getX() == 3 );
+
+    BoostTransitionSplit c;
+    ar( c );
+    assert( c.getX() == 4 );
+    c.setX( 0 );
+    ar( c );
+    assert( c.getX() == 4 );
+
+    BoostTransitionNMS d;
+    ar( d );
+    assert( d.x == 5 );
+    d.x = 0;
+    ar( d );
+    assert( d.x == 5 );
+
+    BoostTransitionNMSplit e;
+    ar( e );
+    assert( e.x == 32 );
+    e.x = 0;
+    ar( e );
+    assert( e.x == 32 );
+  }
+
+#ifdef CEREAL_FUTURE_EXPERIMENTAL
+  {
+    // Any testing
+    int x = 32;
+    int * xx = &x;
+    std::string y("hello");
+    cereal::detail::Any a(xx);
+    auto b = a;
+
+    std::cout << *((int *)a) << std::endl;
+    *((int*)a) = 44;
+    std::cout << *((int *)b) << std::endl;
+    std::cout << *((int *)a) << std::endl;
+
+    a = cereal::detail::Any(y);
+    std::string a_out = a;
+    std::cout << a_out << std::endl;
+  }
+#endif // CEREAL_FUTURE_EXPERIMENTAL
+
+  return 0;
+}
+
+CEREAL_CLASS_VERSION(BoostTransitionMS, 1)
+CEREAL_CLASS_VERSION(BoostTransitionSplit, 2)
+CEREAL_CLASS_VERSION(BoostTransitionNMS, 3)
+// keep the other at default version (0)
diff --git a/sandbox/sandbox_json.cpp b/sandbox/sandbox_json.cpp
new file mode 100644
index 0000000..8f054c5
--- /dev/null
+++ b/sandbox/sandbox_json.cpp
@@ -0,0 +1,475 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <cereal/cereal.hpp>
+#include <cereal/archives/binary.hpp>
+#include <cereal/archives/json.hpp>
+
+#include <cereal/types/string.hpp>
+#include <cereal/types/utility.hpp>
+#include <cereal/types/memory.hpp>
+#include <cereal/types/complex.hpp>
+#include <cereal/types/base_class.hpp>
+#include <cereal/types/array.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/map.hpp>
+
+#include <cereal/external/rapidjson/filestream.h>
+
+#include <sstream>
+#include <fstream>
+#include <cassert>
+#include <complex>
+#include <iostream>
+#include <iomanip>
+#include <string>
+
+// ###################################
+struct Test1
+{
+  int a;
+
+  private:
+    friend class cereal::access;
+    template<class Archive>
+    void serialize(Archive & ar)
+    {
+      ar(CEREAL_NVP(a));
+    }
+};
+
+// ###################################
+class Test2
+{
+  public:
+    Test2() {}
+    Test2( int x ) : a( x ) {}
+    int a;
+
+  private:
+    friend class cereal::access;
+
+    template<class Archive>
+      void save(Archive & ar) const
+      {
+        ar(a);
+      }
+
+    template<class Archive>
+      void load(Archive & ar)
+      {
+        ar(a);
+      }
+};
+
+// ###################################
+struct Test3
+{
+  int a;
+};
+
+template<class Archive>
+void serialize(Archive & ar, Test3 & t)
+{
+  ar(CEREAL_NVP(t.a));
+}
+
+namespace test4
+{
+  // ###################################
+  struct Test4
+  {
+    int a;
+  };
+
+  template<class Archive>
+  void save(Archive & ar, Test4 const & t)
+  {
+    ar(CEREAL_NVP(t.a));
+  }
+
+  template<class Archive>
+  void load(Archive & ar, Test4 & t)
+  {
+    ar(CEREAL_NVP(t.a));
+  }
+}
+
+class Private
+{
+  public:
+    Private() : a('z') {}
+
+  private:
+    char a;
+
+    friend class cereal::access;
+
+    template<class Archive>
+      void serialize(Archive & ar)
+      {
+        ar(a);
+      }
+};
+
+struct Everything
+{
+  int x;
+  int y;
+  Test1 t1;
+  Test2 t2;
+  Test3 t3;
+  test4::Test4 t4;
+  std::string s;
+
+  template<class Archive>
+  void serialize(Archive & ar)
+  {
+    ar(CEREAL_NVP(x));
+    ar(CEREAL_NVP(y));
+    ar(CEREAL_NVP(t1));
+    ar(CEREAL_NVP(t2));
+    ar(CEREAL_NVP(t3));
+    ar(CEREAL_NVP(t4));
+    ar(CEREAL_NVP(s));
+  }
+
+  bool operator==(Everything const & o)
+  {
+    return
+      x == o.x &&
+      y == o.y &&
+      t1.a == o.t1.a &&
+      t2.a == o.t2.a &&
+      t3.a == o.t3.a &&
+      t4.a == o.t4.a &&
+      s == o.s;
+  }
+};
+
+
+struct SubFixture
+{
+  SubFixture() : a( 3 ),
+    b( 9999 ),
+    c( 100.1f ),
+    d( 2000.9 ),
+    s( "hello, world!" )
+  {}
+
+  int a;
+  uint64_t b;
+  float c;
+  double d;
+  std::string s;
+
+    template<class Archive>
+      void serialize(Archive & ar)
+      {
+        ar( CEREAL_NVP(a),
+            b,
+            c,
+            CEREAL_NVP(d),
+            CEREAL_NVP(s) );
+      }
+    void change()
+    {
+      a = 4;
+      b = 4;
+      c = 4;
+      d = 4;
+      s = "4";
+    }
+};
+
+struct Fixture
+{
+  SubFixture f1, f2, f3;
+  int array[4];
+
+  Fixture()
+  {
+    array[0] = 1;
+    array[1] = 2;
+    array[2] = 3;
+    array[3] = 4;
+  }
+
+  template<class Archive>
+  void save(Archive & ar) const
+  {
+    ar( f1,
+        CEREAL_NVP(f2),
+        f3 );
+    ar.saveBinaryValue( array, sizeof(int)*4, "cool array man" );
+  }
+
+  template<class Archive>
+  void load(Archive & ar)
+  {
+    ar( f1,
+        CEREAL_NVP(f2),
+        f3 );
+    ar.loadBinaryValue( array, sizeof(int)*4 );
+  }
+
+    void change()
+    {
+      f1.change();
+      f2.change();
+      f3.change();
+    }
+};
+
+struct AAA
+{
+  AAA() : one( 1 ), two( 2 ), three( { {1, 2, 3}, { 4, 5, 6 }, {} } ) {}
+  int one, two;
+
+  std::vector<std::vector<int>> three;
+
+  template<class Archive>
+    void serialize(Archive & ar)
+    {
+      ar( CEREAL_NVP(one), CEREAL_NVP(two) );
+      //ar( CEREAL_NVP(three) );
+    }
+};
+
+class Stuff
+{
+  public:
+    Stuff() {}
+
+    void fillData()
+    {
+      std::vector<std::complex<float>> t1{ {0, -1.0f},
+                          { 0, -2.9932f },
+                          { 0, -3.5f } };
+      std::vector<std::complex<float>> t2{ {1.0f, 0},
+                     { 2.2f, 0 },
+                     { 3.3f, 0 } };
+      data["imaginary"] = t1;
+      data["real"] = t2;
+    }
+
+  private:
+    std::map<std::string, std::vector<std::complex<float>>> data;
+
+    friend class cereal::access;
+
+    template <class Archive>
+    void serialize( Archive & ar )
+    {
+      ar( CEREAL_NVP(data) );
+    }
+};
+
+struct OOJson
+{
+  OOJson() = default;
+  OOJson( int aa, int bb, bool cc, double dd ) :
+    a( aa ), b( bb ), c{ cc, dd }
+  {
+    d[0] = 0; d[1] = 1; d[2] = 2;
+  }
+
+  int a;
+  int b;
+  std::pair<bool, double> c;
+  float d[3];
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( CEREAL_NVP(c) );
+    ar( CEREAL_NVP(a) );
+    ar( b );
+    ar( CEREAL_NVP(d) );
+  }
+};
+
+enum Bla
+{
+  x,
+  y
+};
+
+template <class Archive>
+void save( Archive & ar, Bla const & b )
+{
+  ar( (const int &)b );
+}
+
+template <class Archive>
+void load( Archive & ar, Bla & b )
+{
+  ar( (int&)b );
+}
+
+CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Bla, cereal::specialization::non_member_load_save )
+
+//namespace cereal
+//{
+//  //template <class Archive> struct specialize<Archive, Bla, cereal::specialization::non_member_load_save> {};
+//}
+
+// ######################################################################
+int main()
+{
+  std::cout << std::boolalpha << std::endl;
+
+  {
+    std::ofstream os("file.json");
+    cereal::JSONOutputArchive oar( os );
+
+    //auto f = std::make_shared<Fixture>();
+    //auto f2 = f;
+    //oar( f );
+    //oar( f2 );
+    Stuff s; s.fillData();
+    oar( cereal::make_nvp("best data ever", s) );
+  }
+
+  {
+    std::ifstream is("file.json");
+    std::string str((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
+    std::cout << "---------------------" << std::endl << str << std::endl << "---------------------" << std::endl;
+  }
+
+  // playground
+  {
+    cereal::JSONOutputArchive archive( std::cout );
+    bool arr[] = {true, false};
+    std::vector<int> vec = {1, 2, 3, 4, 5};
+    archive( CEREAL_NVP(vec),
+        arr );
+    auto f = std::make_shared<Fixture>();
+    auto f2 = f;
+    archive( f );
+    archive( f2 );
+
+    archive( Bla::x );
+  }
+
+  // test out of order
+  std::stringstream oos;
+  {
+    cereal::JSONOutputArchive ar(oos);
+    cereal::JSONOutputArchive ar2(std::cout,
+        cereal::JSONOutputArchive::Options(2, cereal::JSONOutputArchive::Options::IndentChar::space, 2) );
+
+    ar( cereal::make_nvp( "1", 1 ),
+        cereal::make_nvp( "2", 2 ),
+        3,
+        0, // unused
+        cereal::make_nvp( "4", 4 ),
+        cereal::make_nvp( "5", 5 ) );
+
+    int x = 33;
+    ar.saveBinaryValue( &x, sizeof(int), "bla" );
+
+    ar2( cereal::make_nvp( "1", 1 ),
+         cereal::make_nvp( "2", 2 ),
+         3,
+         0, // unused
+         cereal::make_nvp( "4", 4 ),
+         cereal::make_nvp( "5", 5 ) );
+    ar2.saveBinaryValue( &x, sizeof(int), "bla" );
+
+    OOJson oo( 1, 2, true, 4.2 );
+    ar( CEREAL_NVP(oo) );
+    ar2( CEREAL_NVP(oo) );
+
+    // boost stuff
+    ar & cereal::make_nvp("usingop&", oo ) & 6;
+    ar << 5 << 4 << 3;
+
+    ar2 & cereal::make_nvp("usingop&", oo ) & 6;
+    ar2 << 5 << 4 << 3;
+
+    long double ld = std::numeric_limits<long double>::max();
+    long long ll = std::numeric_limits<long long>::max();
+    unsigned long long ull = std::numeric_limits<unsigned long long>::max();
+
+    ar( CEREAL_NVP(ld),
+        CEREAL_NVP(ll),
+        CEREAL_NVP(ull) );
+
+    ar2( CEREAL_NVP(ld),
+         CEREAL_NVP(ll),
+         CEREAL_NVP(ull) );
+  }
+
+  {
+    cereal::JSONInputArchive ar(oos);
+    int i1, i2, i3, i4, i5, x;
+
+    ar( i1 );
+    ar( cereal::make_nvp( "2", i2 ), i3 );
+
+    ar( cereal::make_nvp( "4", i4 ),
+        i5 );
+
+    ar.loadBinaryValue( &x, sizeof(int) );
+
+    OOJson ii;
+    ar( cereal::make_nvp("oo", ii) );
+    ar( cereal::make_nvp( "2", i2 ) );
+
+    std::cout << i1 << " " << i2 << " " << i3 << " " << i4 << " " << i5 << std::endl;
+    std::cout << x << std::endl;
+    std::cout << ii.a << " " << ii.b << " " << ii.c.first << " " << ii.c.second << " ";
+    for( auto z : ii.d )
+      std::cout << z << " ";
+    std::cout << std::endl;
+
+    OOJson oo;
+    ar >> cereal::make_nvp("usingop&", oo );
+    std::cout << oo.a << " " << oo.b << " " << oo.c.first << " " << oo.c.second << " ";
+    for( auto z : oo.d )
+      std::cout << z << " ";
+
+    int aa, a, b, c;
+    ar & aa & a & b & c;
+    std::cout << aa << " " << a << " " << b << " " << c << std::endl;
+
+    long double ld;
+    long long ll;
+    unsigned long long ull;
+
+    ar( CEREAL_NVP(ld),
+        CEREAL_NVP(ll),
+        CEREAL_NVP(ull) );
+
+    std::cout << (ld  == std::numeric_limits<long double>::max()) << std::endl;
+    std::cout << (ll  == std::numeric_limits<long long>::max()) << std::endl;
+    std::cout << (ull == std::numeric_limits<unsigned long long>::max()) << std::endl;
+  }
+
+  return 0;
+}
diff --git a/sandbox/sandbox_rtti.cpp b/sandbox/sandbox_rtti.cpp
new file mode 100644
index 0000000..dd3f595
--- /dev/null
+++ b/sandbox/sandbox_rtti.cpp
@@ -0,0 +1,229 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <type_traits>
+#include <cereal/archives/binary.hpp>
+#include <cereal/archives/xml.hpp>
+#include <cereal/types/polymorphic.hpp>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+
+struct Base
+{
+  int y;
+  virtual void foo() = 0;
+
+  template<class Archive>
+    void save(Archive & ar) const
+    {
+      std::cout << "Saving Base" << std::endl;
+      ar( y );
+    }
+
+  template<class Archive>
+    void load(Archive & ar)
+    {
+      std::cout << "Loading Base" << std::endl;
+      ar( y );
+    }
+};
+
+struct MyType : public Base
+{
+  int x;
+
+  void foo() {}
+
+  template<class Archive>
+    void save(Archive & ar) const
+    {
+      std::cout << "Saving MyType" << std::endl;
+      ar( cereal::virtual_base_class<Base>( this ) );
+    }
+
+  template<class Archive>
+    void load(Archive & ar)
+    {
+      std::cout << "Loading MyType" << std::endl;
+      ar( cereal::base_class<Base>( this ) );
+    }
+};
+CEREAL_REGISTER_TYPE(MyType)
+
+struct YourType : public Base
+{
+  YourType(int xx) : x(xx) {}
+  YourType() : x(-1) {}
+  int x;
+
+  void foo() {}
+
+  template<class Archive>
+    void save(Archive & ar) const
+    {
+      std::cout << "Saving YourType" << std::endl;
+      ar( x );
+    }
+
+  template<class Archive>
+    void load(Archive & ar)
+    {
+      std::cout << "Loading YourType" << std::endl;
+      ar( x );
+    }
+};
+CEREAL_REGISTER_TYPE(YourType)
+
+struct OurBase
+{
+  virtual void foo() {}
+
+  template<class Archive>
+    void serialize(Archive &)
+    { }
+};
+
+struct OurType : public OurBase
+{
+  OurType() : OurBase(), x() {}
+  OurType(int x_) : x(x_) {}
+  void foo() {}
+
+  int x;
+
+  template<class Archive>
+    void serialize(Archive & ar)
+    {
+      ar( x );
+    }
+};
+
+struct BaseVirtual
+{
+  int x;
+  template <class Archive>
+  void serialize( Archive & ar )
+  { ar( x ); }
+  virtual void foo() = 0;
+};
+
+struct DerivedVirtual : public virtual BaseVirtual
+{
+  int y;
+  virtual void foo() {}
+
+  template <class Archive>
+  void save( Archive & ar ) const
+  {
+    ar( cereal::virtual_base_class<BaseVirtual>( this ) );
+    ar( y );
+  }
+
+  template <class Archive>
+  void load( Archive & ar )
+  {
+    ar( cereal::virtual_base_class<BaseVirtual>( this ) );
+    ar( y );
+  }
+};
+
+struct TestType
+{
+  int x;
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x );
+  }
+};
+
+namespace cereal
+{
+  template <class Archive> struct specialize<Archive, DerivedVirtual, cereal::specialization::member_load_save> {};
+  template <class Archive> struct specialize<Archive, TestType, cereal::specialization::member_serialize> {};
+}
+
+struct AAA
+{
+  virtual void foo() = 0;
+};
+
+struct BBB : AAA
+{
+  void foo() {}
+  template <class Archive>
+  void serialize( Archive & ) {}
+};
+
+CEREAL_REGISTER_TYPE(BBB)
+
+template <class T> void nop(T&&) {}
+
+int main()
+{
+  {
+    std::ofstream ostream("rtti.txt");
+    //cereal::BinaryOutputArchive oarchive(ostream);
+    cereal::XMLOutputArchive oarchive(ostream);
+
+    std::shared_ptr<Base> ptr1 = std::make_shared<MyType>();
+    std::shared_ptr<Base> ptr2 = std::make_shared<YourType>(33);
+    std::unique_ptr<Base> ptr3(new MyType());
+    std::weak_ptr<Base>   ptr4 = ptr2;
+
+    std::shared_ptr<OurType> ptr5 = std::make_shared<OurType>(99);
+
+    oarchive(ptr1);
+    oarchive(ptr2);
+    oarchive(ptr3);
+    oarchive(ptr4);
+    oarchive(ptr5);
+
+    //std::shared_ptr<AAA> a = std::make_shared<BBB>();
+    //oarchive(a);
+  }
+
+  {
+    std::ifstream istream("rtti.txt");
+    //cereal::BinaryInputArchive iarchive(istream);
+    cereal::XMLInputArchive iarchive(istream);
+
+    std::shared_ptr<Base> ptr1;
+    std::shared_ptr<Base> ptr2;
+    std::unique_ptr<Base> ptr3;
+    std::weak_ptr<Base>   ptr4;
+
+    std::shared_ptr<OurType> ptr5;
+
+    iarchive(ptr1);
+    iarchive(ptr2);
+    iarchive(ptr3);
+    iarchive(ptr4);
+    iarchive(ptr5);
+  }
+}
diff --git a/sandbox/sandbox_shared_lib/CMakeLists.txt b/sandbox/sandbox_shared_lib/CMakeLists.txt
new file mode 100644
index 0000000..5d8ea08
--- /dev/null
+++ b/sandbox/sandbox_shared_lib/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(sandbox_vs_dll SHARED base.cpp derived.cpp)
diff --git a/sandbox/sandbox_shared_lib/base.cpp b/sandbox/sandbox_shared_lib/base.cpp
new file mode 100755
index 0000000..9d8e360
--- /dev/null
+++ b/sandbox/sandbox_shared_lib/base.cpp
@@ -0,0 +1,9 @@
+#ifndef CEREAL_DLL_USE
+#define CEREAL_DLL_MAKE
+#endif
+#include "base.hpp"
+
+template void Base::serialize<cereal::XMLOutputArchive>
+    ( cereal::XMLOutputArchive & ar, std::uint32_t const version );
+template void Base::serialize<cereal::XMLInputArchive>
+    ( cereal::XMLInputArchive & ar, std::uint32_t const version );
diff --git a/sandbox/sandbox_shared_lib/base.hpp b/sandbox/sandbox_shared_lib/base.hpp
new file mode 100755
index 0000000..388a015
--- /dev/null
+++ b/sandbox/sandbox_shared_lib/base.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <memory>
+#include <cereal/cereal.hpp>
+#include <cereal/archives/xml.hpp>
+#include <cereal/types/polymorphic.hpp>
+
+#if defined (_WINDLL)
+#define DECLSPECIFIER __declspec(dllexport)
+#elif defined(MSC_VER)
+#define DECLSPECIFIER __declspec(dllimport)
+#else
+#define DECLSPECIFIER
+#endif
+
+int doit();
+
+class VersionTest
+{
+  public:
+    int x;
+    template <class Archive>
+    void serialize( Archive & ar, const std::uint32_t /* version */ )
+    { ar( x ); }
+};
+
+class Base
+{
+  public:
+    friend class cereal::access;
+
+    template < class Archive >
+    void serialize(Archive &, std::uint32_t const) {}
+    virtual ~Base() {}
+};
+
+extern template DECLSPECIFIER void Base::serialize<cereal::XMLInputArchive>
+( cereal::XMLInputArchive & ar, std::uint32_t const version );
+
+extern template DECLSPECIFIER void Base::serialize<cereal::XMLOutputArchive>
+( cereal::XMLOutputArchive & ar, std::uint32_t const version );
+
+CEREAL_CLASS_VERSION(VersionTest, 1)
diff --git a/sandbox/sandbox_shared_lib/derived.cpp b/sandbox/sandbox_shared_lib/derived.cpp
new file mode 100755
index 0000000..52043e2
--- /dev/null
+++ b/sandbox/sandbox_shared_lib/derived.cpp
@@ -0,0 +1,10 @@
+#ifndef CEREAL_DLL_USE
+#define CEREAL_DLL_MAKE
+#endif
+#include "derived.hpp"
+
+template void Derived::serialize<cereal::XMLOutputArchive>
+    ( cereal::XMLOutputArchive & ar, std::uint32_t const version );
+
+template void Derived::serialize<cereal::XMLInputArchive>
+    ( cereal::XMLInputArchive & ar, std::uint32_t const version );
diff --git a/sandbox/sandbox_shared_lib/derived.hpp b/sandbox/sandbox_shared_lib/derived.hpp
new file mode 100755
index 0000000..6f6cfb6
--- /dev/null
+++ b/sandbox/sandbox_shared_lib/derived.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include "base.hpp"
+class Derived : public Base
+{
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void serialize(Archive & ar, std::uint32_t const)
+    {
+      ar(cereal::base_class<Base>(this));
+    }
+};
+
+extern template DECLSPECIFIER void Derived::serialize<cereal::XMLOutputArchive>
+    ( cereal::XMLOutputArchive & ar, std::uint32_t const version );
+extern template DECLSPECIFIER void Derived::serialize<cereal::XMLInputArchive>
+    ( cereal::XMLInputArchive & ar, std::uint32_t const version );
+
+CEREAL_REGISTER_TYPE(Derived)
diff --git a/sandbox/sandbox_vs.cpp b/sandbox/sandbox_vs.cpp
new file mode 100644
index 0000000..2ec989f
--- /dev/null
+++ b/sandbox/sandbox_vs.cpp
@@ -0,0 +1,277 @@
+#include <base.hpp>
+#include <derived.hpp>
+
+#include <cereal/access.hpp>
+#include <cereal/details/traits.hpp>
+#include <cereal/details/helpers.hpp>
+#include <cereal/types/base_class.hpp>
+#include <cereal/cereal.hpp>
+
+#include <cereal/types/array.hpp>
+#include <cereal/types/bitset.hpp>
+#include <cereal/types/chrono.hpp>
+#include <cereal/types/common.hpp>
+#include <cereal/types/complex.hpp>
+#include <cereal/types/deque.hpp>
+#include <cereal/types/forward_list.hpp>
+#include <cereal/types/list.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/memory.hpp>
+
+#include <cereal/details/util.hpp>
+
+#include <cereal/details/polymorphic_impl.hpp>
+#include <cereal/types/polymorphic.hpp>
+
+#include <cereal/types/queue.hpp>
+#include <cereal/types/set.hpp>
+#include <cereal/types/stack.hpp>
+#include <cereal/types/string.hpp>
+#include <cereal/types/tuple.hpp>
+#include <cereal/types/unordered_map.hpp>
+#include <cereal/types/unordered_set.hpp>
+#include <cereal/types/utility.hpp>
+#include <cereal/types/vector.hpp>
+
+#include <cereal/archives/binary.hpp>
+#include <cereal/archives/portable_binary.hpp>
+#include <cereal/archives/xml.hpp>
+#include <cereal/archives/json.hpp>
+
+#include <iostream>
+#include <type_traits>
+#include <functional>
+
+//CEREAL_FORCE_LINK_SHARED_LIBRARY(Sandbox)
+
+struct Archive {};
+CEREAL_SETUP_ARCHIVE_TRAITS(Archive, Archive)
+
+struct Test
+{
+  template <class Archive>
+  void serialzize( Archive & )
+  {
+    std::cout << "hey there" << std::endl;
+  }
+
+  template <class Archive>
+  void save( Archive & ) const
+  {
+    std::cout << "saved by the bell" << std::endl;
+  }
+
+  template <class Archive>
+  void load( Archive & )
+  {
+    std::cout << "locked and loaded" << std::endl;
+  }
+
+  template <class Archive>
+  static void load_and_construct( Archive &, cereal::construct<Test> & )
+  {
+  }
+
+  template <class Archive>
+  int save_minimal() const
+  {
+    return 0;
+  }
+
+  template <class Archive>
+  int save_minimal(const std::uint32_t) const
+  {
+    return 1;
+  }
+
+  template <class Archive>
+  void load_minimal( int & )
+  { }
+};
+
+template <class Archive>
+void serialize( Archive &, Test & )
+{ }
+
+template <class Archive>
+void load( Archive &, Test & )
+{ }
+
+template <class Archive>
+void save( Archive &, Test const & )
+{ }
+
+template <class Archive>
+int save_minimal( Test const & )
+{ return 0; }
+
+template <class Archive>
+int save_minimal( Test const &, const std::uint32_t )
+{ return 0; }
+
+namespace cereal
+{
+  template <>
+  struct LoadAndConstruct<Test>
+  {
+    template <class Archive>
+    static void load_and_construct( Archive &, cereal::construct<Test> & construct )
+    {
+      construct();
+    }
+  };
+}
+
+struct A
+{
+  virtual void foo() = 0;
+};
+
+struct B : A
+{
+  void foo() {}
+
+  template <class Archive>
+  void serialize( Archive & )
+  {
+    std::cout << "i'm in your b" << std::endl;
+  }
+};
+
+struct C
+{
+  char a;
+};
+
+CEREAL_REGISTER_TYPE(B)
+
+class MemberMinimal
+{
+  public:
+    MemberMinimal() = default;
+    template <class Archive>
+    int save_minimal( Archive const & ) const
+    {
+      return x;
+    }
+
+    template <class Archive>
+    void load_minimal( Archive const &, int const & str )
+    {
+      x = str;
+    }
+
+  public:
+    int x;
+};
+
+int main()
+{
+  typedef Test T;
+  std::cout << std::boolalpha;
+
+  // Test Load and Construct internal/external
+  std::cout << "\tload_and_construct" << std::endl;
+  std::cout << cereal::traits::has_member_load_and_construct<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_load_and_construct<T, Archive>::value << std::endl;
+
+  // serialize
+  std::cout << "\tserialize" << std::endl;
+  std::cout << cereal::traits::has_member_serialize<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_serialize<T, Archive>::value << std::endl;
+
+  // load
+  std::cout << "\tload" << std::endl;
+  std::cout << cereal::traits::has_member_load<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_load<T, Archive>::value << std::endl;
+
+  // load minimal
+  std::cout << "\tload minimal" << std::endl;
+  std::cout << cereal::traits::has_member_load<T, Archive>::value << std::endl;
+
+  // save
+  std::cout << "\tsave" << std::endl;
+  std::cout << cereal::traits::has_member_save<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_save<T, Archive>::value << std::endl;
+
+  // save_minimal
+  std::cout << "\tsave_minimal" << std::endl;
+  std::cout << cereal::traits::has_member_save_minimal<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_save_minimal<T, Archive>::value << std::endl;
+
+  // save_minimal_versioned
+  std::cout << "\tsave_minimal versioned" << std::endl;
+  std::cout << cereal::traits::has_member_versioned_save_minimal<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_versioned_save_minimal<T, Archive>::value << std::endl;
+
+  // splittable
+  std::cout << "\t splittable" << std::endl;
+  std::cout << cereal::traits::has_member_split<T, Archive, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_non_member_split<T, Archive, Archive>::value << std::endl;
+
+  // serialiable
+  std::cout << "\toutput serializable" << std::endl;
+  std::cout << cereal::traits::is_output_serializable<T, Archive>::value << std::endl;
+
+#if !defined(__INTEL_COMPILER)
+  //! TODO: This causes icc to crash
+  std::cout << cereal::traits::is_input_serializable<T, Archive>::value << std::endl;
+#endif
+
+  // specialized
+  std::cout << "\tspecialized" << std::endl;
+  std::cout << cereal::traits::detail::is_specialized_member_serialize<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::detail::is_specialized_member_load_save<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::detail::is_specialized_non_member_serialize<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::detail::is_specialized_non_member_load_save<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::detail::count_specializations<T, Archive>::value << std::endl;
+  std::cout << cereal::traits::is_specialized<T, Archive>::value << std::endl;
+
+  // array size
+  std::cout << typeid(A).name() << std::endl;
+  std::cout << typeid(cereal::traits::has_load_and_construct<int, bool>).name() << std::endl;
+
+  // extra testing
+  std::cout << "\textra" << std::endl;
+  std::cout << cereal::traits::has_member_save_minimal<MemberMinimal, Archive>::value << std::endl;
+  std::cout << cereal::traits::has_member_load_minimal<MemberMinimal, Archive>::value << std::endl;
+
+  // DLL testing
+  std::cout << "------DLL TESTING------" << std::endl;
+  std::stringstream dllSS1;
+  std::stringstream dllSS2;
+  {
+    cereal::XMLOutputArchive out(dllSS1);
+    VersionTest x{1};
+    std::shared_ptr<Base> p = std::make_shared<Derived>();
+    out(x);
+    out( p );
+
+    std::shared_ptr<A> ay = std::make_shared<B>();
+    out(ay);
+  }
+
+  std::cout << dllSS1.str() << std::endl;
+
+  {
+    VersionTest x;
+    std::shared_ptr<Base> p;
+    std::shared_ptr<A> ay;
+    {
+      cereal::XMLInputArchive in(dllSS1);
+      in(x);
+      in( p );
+      in( ay );
+    }
+    {
+      cereal::XMLOutputArchive out(dllSS2);
+      out( x );
+      out( p );
+      out( ay );
+    }
+  }
+
+  std::cout << dllSS2.str() << std::endl;
+
+  return 0;
+}
diff --git a/scripts/renameincludes.sh b/scripts/renameincludes.sh
new file mode 100755
index 0000000..acc2fa2
--- /dev/null
+++ b/scripts/renameincludes.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+destdir="include_renamed"
+
+echo -n "New prefix: "
+read newprefix
+
+cp -r include ${destdir}
+
+newprefix=$(echo ${newprefix} | sed -e 's/\//\\\//')
+
+find ${destdir} -name '*.hpp' -exec sed -i "s/#include <cereal/#include <${newprefix}\/cereal/" {} \;
diff --git a/scripts/updatecoverage.sh b/scripts/updatecoverage.sh
new file mode 100755
index 0000000..a3ec4ad
--- /dev/null
+++ b/scripts/updatecoverage.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Updates the coverage documentation, and copies it into the appropriate place
+# in the gh-pages-develop branch.
+#   $1 from CMAKE will contain the root directory of cereal
+
+# this requires lcov 1.10 or newer
+
+set -e
+
+COVERAGE_TESTS=./coverage_*
+
+# run tests
+for f in $COVERAGE_TESTS
+  do
+    echo $f
+    $f
+  done
+
+# build coverage output
+tempdir=`mktemp -d`
+
+lcov --capture --directory $1 --output-file coverage.info --no-external
+lcov --remove coverage.info '*/external/*' 'cereal/details/util.hpp' 'sandbox/*' 'unittests/*' -o coverage.info
+genhtml --demangle-cpp coverage.info --output-directory ${tempdir}
+
+# copy over to gh pages
+git checkout gh-pages-develop
+
+rm -rf $1/assets/coverage
+mkdir $1/assets/coverage
+cp -r ${tempdir}/* $1/assets/coverage/
+rm -rf ${tempdir}
diff --git a/scripts/updatedoc.in b/scripts/updatedoc.in
new file mode 100755
index 0000000..5e7a714
--- /dev/null
+++ b/scripts/updatedoc.in
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# Updates the doxygen documentation, and copies it into the appropriate place
+# in the gh-pages branch.
+
+set -e
+
+tempdir=`mktemp -d`
+branch=`git rev-parse --abbrev-ref HEAD`
+
+cp -r @CMAKE_CURRENT_BINARY_DIR@/doc/html/ ${tempdir}
+
+git stash
+git checkout gh-pages-develop
+
+rm -rf @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen
+mkdir @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen
+cp -r ${tempdir}/html/* @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen/
+
+rm -rf ${tempdir}
+
+git commit @CMAKE_CURRENT_SOURCE_DIR@/assets/doxygen
+
+git checkout ${branch}
+git stash apply
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
new file mode 100644
index 0000000..622d49e
--- /dev/null
+++ b/unittests/CMakeLists.txt
@@ -0,0 +1,77 @@
+file(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
+
+# A semi-colon separated list of test sources that should not be automatically built with boost unit test
+set(SPECIAL_TESTS "portability_test.cpp")
+
+# Build the portability test only if we are on a 64-bit machine (void* is 8 bytes)
+if((${CMAKE_SIZEOF_VOID_P} EQUAL 8) AND (NOT SKIP_PORTABILITY_TEST))
+  add_executable(portability_test32 portability_test.cpp)
+  set_target_properties(portability_test32 PROPERTIES COMPILE_FLAGS "-m32")
+  set_target_properties(portability_test32 PROPERTIES LINK_FLAGS "-m32")
+
+  add_executable(portability_test64 portability_test.cpp)
+
+  add_test(NAME portability_test COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/run_portability_test.sh")
+
+endif()
+
+# Build all of the non-special tests and link against the boost unit test framework
+foreach(TEST_SOURCE ${TESTS})
+
+  string(REPLACE ".cpp" "" TEST_TARGET "${TEST_SOURCE}")
+  set(TEST_TARGET "test_${TEST_TARGET}")
+
+  # Check to see if our target is listed in "SPECIAL_TESTS"
+  list(FIND SPECIAL_TESTS "${TEST_SOURCE}" IS_SPECIAL_TEST)
+
+  if(IS_SPECIAL_TEST EQUAL -1)
+
+    add_executable(${TEST_TARGET} ${TEST_SOURCE})
+    set_target_properties(${TEST_TARGET} PROPERTIES COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${TEST_TARGET}")
+    target_link_libraries(${TEST_TARGET} ${Boost_LIBRARIES})
+    add_test("${TEST_TARGET}" "${TEST_TARGET}")
+
+    # TODO: This won't work right now, because we would need a 32-bit boost
+    ## If we are on a 64-bit machine, create an extra 32-bit version of the test
+    #if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+    #  add_executable(${TEST_TARGET}_32 ${TEST_SOURCE})
+    #  set_target_properties(${TEST_TARGET}_32 PROPERTIES 
+    #    COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${TEST_TARGET}"
+    #    COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
+    #  target_link_libraries(${TEST_TARGET}_32 ${Boost_LIBRARIES})
+    #  add_test("${TEST_TARGET}_32" "${TEST_TARGET}_32")
+    #endif()
+
+  endif()
+
+endforeach()
+
+# Add the valgrind target
+add_custom_target(valgrind
+  COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/run_valgrind.sh")
+
+# Add the coverage target
+add_custom_target(coverage)
+add_custom_command(TARGET coverage
+  COMMAND "${CMAKE_SOURCE_DIR}/scripts/updatecoverage.sh" ${CMAKE_SOURCE_DIR}
+  WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/coverage")
+
+# add tests to coverage
+foreach(TEST_SOURCE ${TESTS})
+  string(REPLACE ".cpp" "" COVERAGE_TARGET "${TEST_SOURCE}")
+  set(COVERAGE_TARGET "coverage_${COVERAGE_TARGET}")
+
+  # Check to see if our target is listed in "SPECIAL_TESTS"
+  list(FIND SPECIAL_TESTS "${TEST_SOURCE}" IS_SPECIAL_TEST)
+
+  if(IS_SPECIAL_TEST EQUAL -1)
+    add_dependencies(coverage ${COVERAGE_TARGET})
+    
+    add_executable(${COVERAGE_TARGET} EXCLUDE_FROM_ALL ${TEST_SOURCE})
+    set_target_properties(${COVERAGE_TARGET} PROPERTIES COMPILE_DEFINITIONS "BOOST_TEST_DYN_LINK;BOOST_TEST_MODULE=${COVERAGE_TARGET}")
+    set_target_properties(${COVERAGE_TARGET} PROPERTIES COMPILE_FLAGS "-coverage")
+    set_target_properties(${COVERAGE_TARGET} PROPERTIES LINK_FLAGS "-coverage")
+    set_target_properties(${COVERAGE_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/coverage")
+    target_link_libraries(${COVERAGE_TARGET} ${Boost_LIBRARIES})
+  endif()
+endforeach()
diff --git a/unittests/array.cpp b/unittests/array.cpp
new file mode 100644
index 0000000..2ae3fcc
--- /dev/null
+++ b/unittests/array.cpp
@@ -0,0 +1,113 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_array()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::array<int, 100> o_podarray;
+    for(auto & elem : o_podarray)
+      elem = random_value<int>(gen);
+
+    std::array<StructInternalSerialize, 100> o_iserarray;
+    for(auto & elem : o_iserarray)
+      elem = StructInternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::array<StructInternalSplit, 100> o_isplarray;
+    for(auto & elem : o_isplarray)
+      elem = StructInternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::array<StructExternalSerialize, 100> o_eserarray;
+    for(auto & elem : o_eserarray)
+      elem = StructExternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::array<StructExternalSplit, 100> o_esplarray;
+    for(auto & elem : o_esplarray)
+      elem = StructExternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podarray);
+      oar(o_iserarray);
+      oar(o_isplarray);
+      oar(o_eserarray);
+      oar(o_esplarray);
+    }
+
+    std::array<int, 100> i_podarray;
+    std::array<StructInternalSerialize, 100> i_iserarray;
+    std::array<StructInternalSplit, 100>     i_isplarray;
+    std::array<StructExternalSerialize, 100> i_eserarray;
+    std::array<StructExternalSplit, 100>     i_esplarray;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podarray);
+      iar(i_iserarray);
+      iar(i_isplarray);
+      iar(i_eserarray);
+      iar(i_esplarray);
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podarray.begin(),    i_podarray.end(),    o_podarray.begin(),  o_podarray.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserarray.begin(),   i_iserarray.end(),   o_iserarray.begin(), o_iserarray.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplarray.begin(),   i_isplarray.end(),   o_isplarray.begin(), o_isplarray.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserarray.begin(),   i_eserarray.end(),   o_eserarray.begin(), o_eserarray.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplarray.begin(),   i_esplarray.end(),   o_esplarray.begin(), o_esplarray.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_array )
+{
+  test_array<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_array )
+{
+  test_array<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_array )
+{
+  test_array<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_array )
+{
+  test_array<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/basic_string.cpp b/unittests/basic_string.cpp
new file mode 100644
index 0000000..ede1852
--- /dev/null
+++ b/unittests/basic_string.cpp
@@ -0,0 +1,227 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/string_ref.hpp>
+
+template <class IArchive, class OArchive>
+void test_string_basic()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(size_t i=0; i<100; ++i)
+  {
+    std::basic_string<char> o_string  = random_basic_string<char>(gen);
+    std::basic_string<char> o_string2 = "";
+    std::basic_string<char> o_string3;
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar(o_string);
+      oar(o_string2);
+      oar(o_string3);
+    }
+
+    std::basic_string<char> i_string;
+    std::basic_string<char> i_string2;
+    std::basic_string<char> i_string3;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_string);
+      iar(i_string2);
+      iar(i_string3);
+    }
+
+    BOOST_CHECK_EQUAL(i_string, o_string);
+    BOOST_CHECK_EQUAL(i_string2, o_string2);
+    BOOST_CHECK_EQUAL(i_string3, o_string3);
+  }
+}
+
+template <class IArchive, class OArchive>
+void test_string_all()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(size_t i=0; i<100; ++i)
+  {
+    std::basic_string<char> o_string        = random_basic_string<char>(gen);
+    std::basic_string<wchar_t> o_wstring    = random_basic_string<wchar_t>(gen);
+    std::basic_string<char16_t> o_u16string = random_basic_string<char16_t>(gen);
+    std::basic_string<char32_t> o_u32string = random_basic_string<char32_t>(gen);
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar(o_string);
+      oar(o_wstring);
+      oar(o_u16string);
+      oar(o_u32string);
+    }
+
+    std::basic_string<char> i_string;
+    std::basic_string<wchar_t> i_wstring;
+    std::basic_string<char16_t> i_u16string;
+    std::basic_string<char32_t> i_u32string;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_string);
+      iar(i_wstring);
+      iar(i_u16string);
+      iar(i_u32string);
+    }
+
+    BOOST_CHECK_EQUAL(i_string, o_string);
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_wstring.begin(),     i_wstring.end(),   o_wstring.begin(),   o_wstring.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_u16string.begin(),  i_u16string.end(),  o_u16string.begin(), o_u16string.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_u32string.begin(),  i_u32string.end(),  o_u32string.begin(), o_u32string.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_string )
+{
+  test_string_all<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_string )
+{
+  test_string_all<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_string_basic )
+{
+  test_string_basic<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_string_basic )
+{
+  test_string_basic<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+template <class IArchive, class OArchive, class Out, class In = Out>
+void test_ws_in_out(Out const & o_value_with_ws)
+{
+  std::ostringstream os;
+  {
+    OArchive oar(os);
+    oar(o_value_with_ws);
+  }
+
+  In i_value_with_ws;
+
+  std::istringstream is(os.str());
+  {
+    IArchive iar(is);
+    iar(i_value_with_ws);
+  }
+
+  BOOST_CHECK_EQUAL(i_value_with_ws, o_value_with_ws);
+}
+
+namespace boost
+{
+  void save( cereal::XMLOutputArchive & ar, boost::string_ref const & str )
+  {
+    ar.saveValue( str );
+  }
+
+  bool operator==( std::string const & s1, boost::string_ref const & s2 )
+  {
+    return s1 == std::string(s2.data(), s2.length());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( xml_string_issue109 )
+{
+  char strings[][20] = {
+    "some text",
+    "some text ",
+    " some text",
+    " some text ",
+    "  ",
+    "    text    ",
+    " ]]> ",
+    " > > ]]> ",
+    " < <]>] < ",
+    " & &   "
+  };
+
+  for( size_t i=0; i<( sizeof( strings ) / sizeof( strings[0] ) ); ++i )
+  {
+    std::basic_string<char> o_string = strings[i];
+
+    test_ws_in_out<cereal::XMLInputArchive, cereal::XMLOutputArchive>( o_string );
+  }
+
+  for( size_t i=0; i<( sizeof( strings ) / sizeof( strings[0] ) ); ++i )
+  {
+    boost::string_ref o_string = strings[i];
+
+    test_ws_in_out<cereal::XMLInputArchive, cereal::XMLOutputArchive, boost::string_ref, std::string>( o_string );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( xml_char_issue109 )
+{
+  uint8_t chars[] = {
+    ' ',
+    '\t',
+    '\n',
+    '\r',
+    '&',
+    '>',
+    '<',
+    '\'',
+    '"',
+    '!',
+    '|'
+  };
+
+  for( size_t i=0; i<( sizeof( chars ) / sizeof( chars[0] ) ); ++i )
+  {
+    test_ws_in_out<cereal::XMLInputArchive, cereal::XMLOutputArchive>( chars[i] );
+  }
+
+  for( size_t i=0; i<( sizeof( chars ) / sizeof( chars[0] ) ); ++i )
+  {
+    test_ws_in_out<cereal::XMLInputArchive, cereal::XMLOutputArchive>( int8_t( chars[i] ) );
+  }
+
+  for( size_t i=0; i<( sizeof( chars ) / sizeof( chars[0] ) ); ++i )
+  {
+    test_ws_in_out<cereal::XMLInputArchive, cereal::XMLOutputArchive>( char( chars[i] ) );
+  }
+}
diff --git a/unittests/bitset.cpp b/unittests/bitset.cpp
new file mode 100644
index 0000000..5176531
--- /dev/null
+++ b/unittests/bitset.cpp
@@ -0,0 +1,94 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_bitset()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rng32  = [&](){ return random_binary_string<32>( gen ); };
+  auto rng65  = [&](){ return random_binary_string<65>( gen ); };
+  auto rng256 = [&](){ return random_binary_string<256>( gen ); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::bitset<32> o_bit32( rng32() );
+    std::bitset<65> o_bit65( rng65() );
+    std::bitset<256> o_bit256( rng256() );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_bit32);
+      oar(o_bit65);
+      oar(o_bit256);
+    }
+
+    std::bitset<32>  i_bit32;
+    std::bitset<65>  i_bit65;
+    std::bitset<256> i_bit256;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_bit32);
+      iar(i_bit65);
+      iar(i_bit256);
+    }
+
+    BOOST_CHECK_EQUAL( o_bit32, i_bit32 );
+    BOOST_CHECK_EQUAL( o_bit65, i_bit65 );
+    BOOST_CHECK_EQUAL( o_bit256, i_bit256 );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_bitset )
+{
+  test_bitset<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_bitset )
+{
+  test_bitset<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_bitset )
+{
+  test_bitset<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_bitset )
+{
+  test_bitset<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/chrono.cpp b/unittests/chrono.cpp
new file mode 100644
index 0000000..c71238a
--- /dev/null
+++ b/unittests/chrono.cpp
@@ -0,0 +1,123 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_chrono()
+{
+  for(int ii=0; ii<100; ++ii)
+  {
+    auto o_timePoint1 = std::chrono::system_clock::now();
+    #ifndef CEREAL_OLDER_GCC
+    auto o_timePoint2 = std::chrono::steady_clock::now();
+    #endif // CEREAL_OLDER_GCC
+    auto o_timePoint3 = std::chrono::high_resolution_clock::now();
+
+    auto o_duration1 = std::chrono::system_clock::now() - o_timePoint1;
+    #ifndef CEREAL_OLDER_GCC
+    auto o_duration2 = std::chrono::steady_clock::now() - o_timePoint2;
+    #endif // CEREAL_OLDER_GCC
+    auto o_duration3 = std::chrono::high_resolution_clock::now() - o_timePoint3;
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_timePoint1);
+      #ifndef CEREAL_OLDER_GCC
+      oar(o_timePoint2);
+      #endif // CEREAL_OLDER_GCC
+      oar(o_timePoint3);
+      oar(o_duration1);
+      #ifndef CEREAL_OLDER_GCC
+      oar(o_duration2);
+      #endif // CEREAL_OLDER_GCC
+      oar(o_duration3);
+    }
+
+    decltype(o_timePoint1) i_timePoint1;
+    #ifndef CEREAL_OLDER_GCC
+    decltype(o_timePoint2) i_timePoint2;
+    #endif // CEREAL_OLDER_GCC
+    decltype(o_timePoint3) i_timePoint3;
+    decltype(o_duration1) i_duration1;
+    #ifndef CEREAL_OLDER_GCC
+    decltype(o_duration2) i_duration2;
+    #endif // CEREAL_OLDER_GCC
+    decltype(o_duration3) i_duration3;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_timePoint1);
+      #ifndef CEREAL_OLDER_GCC
+      iar(i_timePoint2);
+      #endif // CEREAL_OLDER_GCC
+      iar(i_timePoint3);
+      iar(i_duration1);
+      #ifndef CEREAL_OLDER_GCC
+      iar(i_duration2);
+      #endif // CEREAL_OLDER_GCC
+      iar(i_duration3);
+    }
+
+    BOOST_CHECK( o_timePoint1 == i_timePoint1 );
+    #ifndef CEREAL_OLDER_GCC
+    BOOST_CHECK( o_timePoint2 == i_timePoint2 );
+    #endif // CEREAL_OLDER_GCC
+    BOOST_CHECK( o_timePoint3 == i_timePoint3 );
+    BOOST_CHECK( o_duration1 == i_duration1 );
+    #ifndef CEREAL_OLDER_GCC
+    BOOST_CHECK( o_duration2 == i_duration2 );
+    #endif // CEREAL_OLDER_GCC
+    BOOST_CHECK( o_duration3 == i_duration3 );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_chrono )
+{
+  test_chrono<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_chrono )
+{
+  test_chrono<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_chrono )
+{
+  test_chrono<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_chrono )
+{
+  test_chrono<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/common.hpp b/unittests/common.hpp
new file mode 100644
index 0000000..d3e58c9
--- /dev/null
+++ b/unittests/common.hpp
@@ -0,0 +1,212 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CEREAL_TEST_COMMON_H_
+#define CEREAL_TEST_COMMON_H_
+
+#include <cereal/types/memory.hpp>
+#include <cereal/types/array.hpp>
+#include <cereal/types/valarray.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/deque.hpp>
+#include <cereal/types/forward_list.hpp>
+#include <cereal/types/list.hpp>
+#include <cereal/types/string.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/queue.hpp>
+#include <cereal/types/set.hpp>
+#include <cereal/types/stack.hpp>
+#include <cereal/types/unordered_map.hpp>
+#include <cereal/types/unordered_set.hpp>
+#include <cereal/types/utility.hpp>
+#include <cereal/types/tuple.hpp>
+#include <cereal/types/bitset.hpp>
+#include <cereal/types/complex.hpp>
+#include <cereal/types/chrono.hpp>
+#include <cereal/types/polymorphic.hpp>
+
+#include <cereal/archives/binary.hpp>
+#include <cereal/archives/portable_binary.hpp>
+#include <cereal/archives/xml.hpp>
+#include <cereal/archives/json.hpp>
+#include <limits>
+#include <random>
+
+namespace boost
+{
+  template<class F, class S> inline
+  ::std::ostream & operator<<(::std::ostream & os, ::std::pair<F, S> const & p)
+  {
+    os << "([" << p.first << "], [" << p.second << "])";
+    return os;
+  }
+}
+
+
+namespace cereal
+{
+  template <class Archive, class T> inline
+    void serialize( Archive &, std::less<T> & )
+    { }
+}
+
+template<class T> inline
+typename std::enable_if<std::is_floating_point<T>::value, T>::type
+random_value(std::mt19937 & gen)
+{ return std::uniform_real_distribution<T>(-10000.0, 10000.0)(gen); }
+
+template<class T> inline
+typename std::enable_if<std::is_integral<T>::value && sizeof(T) != sizeof(char), T>::type
+random_value(std::mt19937 & gen)
+{ return std::uniform_int_distribution<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen); }
+
+template<class T> inline
+typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(char), T>::type
+random_value(std::mt19937 & gen)
+{ return static_cast<T>( std::uniform_int_distribution<int64_t>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max())(gen) ); }
+
+template<class T> inline
+typename std::enable_if<std::is_same<T, std::string>::value, std::string>::type
+random_value(std::mt19937 & gen)
+{
+  std::string s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
+  for(char & c : s)
+    c = static_cast<char>( std::uniform_int_distribution<int>( 'A', 'Z' )(gen) );
+  return s;
+}
+
+template<class C> inline
+std::basic_string<C> random_basic_string(std::mt19937 & gen)
+{
+  std::basic_string<C> s(std::uniform_int_distribution<int>(3, 30)(gen), ' ');
+  for(C & c : s)
+    c = static_cast<C>( std::uniform_int_distribution<int>( 'A', 'Z' )(gen) );
+  return s;
+}
+
+template <size_t N> inline
+std::string random_binary_string(std::mt19937 & gen)
+{
+  std::string s(N, ' ');
+  for(auto & c : s )
+     c = static_cast<char>( std::uniform_int_distribution<int>( '0', '1' )(gen) );
+  return s;
+}
+
+struct StructBase
+{
+  StructBase() {}
+  StructBase( int xx, int yy ) : x( xx ), y( yy ) {}
+  int x, y;
+  bool operator==(StructBase const & other) const
+  { return x == other.x && y == other.y; }
+  bool operator!=(StructBase const & other) const
+  { return x != other.x || y != other.y; }
+  bool operator<(StructBase const & other) const
+  {
+    if (x < other.x) return true;
+    else if(other.x < x) return false;
+    else return (y < other.y);
+  }
+};
+
+inline std::ostream& operator<<(std::ostream& os, StructBase const & s)
+{
+    os << "[x: " << s.x << " y: " << s.y << "]";
+    return os;
+}
+
+struct StructInternalSerialize : StructBase
+{
+  StructInternalSerialize() : StructBase{0,0} {}
+  StructInternalSerialize(int x_, int y_) : StructBase{x_,y_} {}
+  template<class Archive>
+    void serialize(Archive & ar)
+    {
+      ar(x, y);
+    }
+};
+
+struct StructInternalSplit : StructBase
+{
+  StructInternalSplit() : StructBase{0,0} {}
+  StructInternalSplit(int x_, int y_) : StructBase{x_,y_} {}
+  template<class Archive>
+    void save(Archive & ar) const
+    {
+      ar(x, y);
+    }
+
+  template<class Archive>
+    void load(Archive & ar)
+    {
+      ar(x, y);
+    }
+};
+
+struct StructExternalSerialize : StructBase
+{
+  StructExternalSerialize() : StructBase{0,0} {}
+  StructExternalSerialize(int x_, int y_) : StructBase{x_,y_} {}
+};
+
+  template<class Archive>
+void serialize(Archive & ar, StructExternalSerialize & s)
+{
+  ar(s.x, s.y);
+}
+
+struct StructExternalSplit : StructBase
+{
+  StructExternalSplit() : StructBase{0,0} {}
+  StructExternalSplit(int x_, int y_) : StructBase{x_,y_} {}
+};
+
+  template<class Archive> inline
+void save(Archive & ar, StructExternalSplit const & s)
+{
+  ar(s.x, s.y);
+}
+
+  template<class Archive> inline
+void load(Archive & ar, StructExternalSplit & s)
+{
+  ar(s.x, s.y);
+}
+
+
+template<class T>
+struct StructHash {
+  public:
+    size_t operator()(const T & s) const
+    {
+      size_t h1 = std::hash<int>()(s.x);
+      size_t h2 = std::hash<int>()(s.y);
+      return h1 ^ ( h2 << 1 );
+    }
+};
+
+#endif // CEREAL_TEST_COMMON_H_
diff --git a/unittests/complex.cpp b/unittests/complex.cpp
new file mode 100644
index 0000000..786e0da
--- /dev/null
+++ b/unittests/complex.cpp
@@ -0,0 +1,96 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_complex()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rngF = [&](){ return random_value<float>(gen); };
+  auto rngD = [&](){ return random_value<double>(gen); };
+  auto rngLD = [&](){ return random_value<long double>(gen); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::complex<float> o_float( rngF(), rngF() );
+    std::complex<double> o_double( rngD(), rngD() );
+    std::complex<long double> o_ldouble( rngLD(), rngLD() );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_float);
+      oar(o_double);
+      oar(o_ldouble);
+    }
+
+    std::complex<float> i_float;
+    std::complex<double> i_double;
+    std::complex<long double> i_ldouble;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_float);
+      iar(i_double);
+      iar(i_ldouble);
+    }
+
+    BOOST_CHECK_EQUAL( o_float, i_float );
+    BOOST_CHECK_CLOSE( o_double.real(), i_double.real(), 1e-5);
+    BOOST_CHECK_CLOSE( o_double.imag(), i_double.imag(), 1e-5);
+    BOOST_CHECK_CLOSE( o_ldouble.real(), i_ldouble.real(), 1e-5);
+    BOOST_CHECK_CLOSE( o_ldouble.imag(), i_ldouble.imag(), 1e-5);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_complex )
+{
+  test_complex<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_complex )
+{
+  test_complex<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_complex )
+{
+  test_complex<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_complex )
+{
+  test_complex<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/deque.cpp b/unittests/deque.cpp
new file mode 100644
index 0000000..9bf694d
--- /dev/null
+++ b/unittests/deque.cpp
@@ -0,0 +1,118 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_deque()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::deque<int> o_poddeque(100);
+    for(auto & elem : o_poddeque)
+      elem = random_value<int>(gen);
+
+    std::deque<StructInternalSerialize> o_iserdeque(100);
+    for(auto & elem : o_iserdeque)
+      elem = StructInternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::deque<StructInternalSplit> o_ispldeque(100);
+    for(auto & elem : o_ispldeque)
+      elem = StructInternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::deque<StructExternalSerialize> o_eserdeque(100);
+    for(auto & elem : o_eserdeque)
+      elem = StructExternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::deque<StructExternalSplit> o_espldeque(100);
+    for(auto & elem : o_espldeque)
+      elem = StructExternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_poddeque);
+      oar(o_iserdeque);
+      oar(o_ispldeque);
+      oar(o_eserdeque);
+      oar(o_espldeque);
+    }
+
+    std::deque<int> i_poddeque;
+    std::deque<StructInternalSerialize> i_iserdeque;
+    std::deque<StructInternalSplit>     i_ispldeque;
+    std::deque<StructExternalSerialize> i_eserdeque;
+    std::deque<StructExternalSplit>     i_espldeque;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_poddeque);
+      iar(i_iserdeque);
+      iar(i_ispldeque);
+      iar(i_eserdeque);
+      iar(i_espldeque);
+    }
+
+    BOOST_CHECK_EQUAL(i_poddeque.size(),  o_poddeque.size());
+    BOOST_CHECK_EQUAL(i_iserdeque.size(), o_iserdeque.size());
+    BOOST_CHECK_EQUAL(i_ispldeque.size(), o_ispldeque.size());
+    BOOST_CHECK_EQUAL(i_eserdeque.size(), o_eserdeque.size());
+    BOOST_CHECK_EQUAL(i_espldeque.size(), o_espldeque.size());
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_poddeque.begin(),    i_poddeque.end(),    o_poddeque.begin(),  o_poddeque.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserdeque.begin(),   i_iserdeque.end(),   o_iserdeque.begin(), o_iserdeque.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_ispldeque.begin(),   i_ispldeque.end(),   o_ispldeque.begin(), o_ispldeque.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserdeque.begin(),   i_eserdeque.end(),   o_eserdeque.begin(), o_eserdeque.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_espldeque.begin(),   i_espldeque.end(),   o_espldeque.begin(), o_espldeque.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_dequeue )
+{
+  test_deque<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_dequeue )
+{
+  test_deque<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_dequeue )
+{
+  test_deque<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_dequeue )
+{
+  test_deque<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/forward_list.cpp b/unittests/forward_list.cpp
new file mode 100644
index 0000000..cf87d62
--- /dev/null
+++ b/unittests/forward_list.cpp
@@ -0,0 +1,112 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_forward_list()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::forward_list<int> o_podforward_list(100);
+    for(auto & elem : o_podforward_list)
+      elem = random_value<int>(gen);
+
+    std::forward_list<StructInternalSerialize> o_iserforward_list(100);
+    for(auto & elem : o_iserforward_list)
+      elem = StructInternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::forward_list<StructInternalSplit> o_isplforward_list(100);
+    for(auto & elem : o_isplforward_list)
+      elem = StructInternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::forward_list<StructExternalSerialize> o_eserforward_list(100);
+    for(auto & elem : o_eserforward_list)
+      elem = StructExternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::forward_list<StructExternalSplit> o_esplforward_list(100);
+    for(auto & elem : o_esplforward_list)
+      elem = StructExternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podforward_list);
+      oar(o_iserforward_list);
+      oar(o_isplforward_list);
+      oar(o_eserforward_list);
+      oar(o_esplforward_list);
+    }
+
+    std::forward_list<int> i_podforward_list;
+    std::forward_list<StructInternalSerialize> i_iserforward_list;
+    std::forward_list<StructInternalSplit>     i_isplforward_list;
+    std::forward_list<StructExternalSerialize> i_eserforward_list;
+    std::forward_list<StructExternalSplit>     i_esplforward_list;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podforward_list);
+      iar(i_iserforward_list);
+      iar(i_isplforward_list);
+      iar(i_eserforward_list);
+      iar(i_esplforward_list);
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podforward_list.begin(),    i_podforward_list.end(),    o_podforward_list.begin(),  o_podforward_list.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserforward_list.begin(),   i_iserforward_list.end(),   o_iserforward_list.begin(), o_iserforward_list.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplforward_list.begin(),   i_isplforward_list.end(),   o_isplforward_list.begin(), o_isplforward_list.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserforward_list.begin(),   i_eserforward_list.end(),   o_eserforward_list.begin(), o_eserforward_list.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplforward_list.begin(),   i_esplforward_list.end(),   o_esplforward_list.begin(), o_esplforward_list.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_forward_list )
+{
+  test_forward_list<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_forward_list )
+{
+  test_forward_list<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_forward_list )
+{
+  test_forward_list<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_forward_list )
+{
+  test_forward_list<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/list.cpp b/unittests/list.cpp
new file mode 100644
index 0000000..8f14fe9
--- /dev/null
+++ b/unittests/list.cpp
@@ -0,0 +1,113 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_list()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::list<int> o_podlist(100);
+    for(auto & elem : o_podlist)
+      elem = random_value<int>(gen);
+
+    std::list<StructInternalSerialize> o_iserlist(100);
+    for(auto & elem : o_iserlist)
+      elem = StructInternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::list<StructInternalSplit> o_ispllist(100);
+    for(auto & elem : o_ispllist)
+      elem = StructInternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::list<StructExternalSerialize> o_eserlist(100);
+    for(auto & elem : o_eserlist)
+      elem = StructExternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::list<StructExternalSplit> o_espllist(100);
+    for(auto & elem : o_espllist)
+      elem = StructExternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podlist);
+      oar(o_iserlist);
+      oar(o_ispllist);
+      oar(o_eserlist);
+      oar(o_espllist);
+    }
+
+    std::list<int> i_podlist;
+    std::list<StructInternalSerialize> i_iserlist;
+    std::list<StructInternalSplit>     i_ispllist;
+    std::list<StructExternalSerialize> i_eserlist;
+    std::list<StructExternalSplit>     i_espllist;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podlist);
+      iar(i_iserlist);
+      iar(i_ispllist);
+      iar(i_eserlist);
+      iar(i_espllist);
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podlist.begin(),    i_podlist.end(),    o_podlist.begin(),  o_podlist.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserlist.begin(),   i_iserlist.end(),   o_iserlist.begin(), o_iserlist.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_ispllist.begin(),   i_ispllist.end(),   o_ispllist.begin(), o_ispllist.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserlist.begin(),   i_eserlist.end(),   o_eserlist.begin(), o_eserlist.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_espllist.begin(),   i_espllist.end(),   o_espllist.begin(), o_espllist.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_list )
+{
+  test_list<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_list )
+{
+  test_list<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_list )
+{
+  test_list<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_list )
+{
+  test_list<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/load_construct.cpp b/unittests/load_construct.cpp
new file mode 100644
index 0000000..62158f1
--- /dev/null
+++ b/unittests/load_construct.cpp
@@ -0,0 +1,195 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+struct OneLA
+{
+  OneLA( int xx ) : x( xx ) {}
+
+  int x;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  { ar( x ); }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<OneLA> & construct )
+  {
+    int xx;
+    ar( xx );
+    construct( xx );
+  }
+
+  bool operator==( OneLA const & other ) const
+  { return x == other.x; }
+};
+
+std::ostream& operator<<(std::ostream& os, OneLA const & s)
+{
+  os << "[" << s.x << "]";
+  return os;
+}
+
+struct TwoLA
+{
+  TwoLA( int xx ) : x( xx ) {}
+
+  int x;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  { ar( x ); }
+
+  bool operator==( TwoLA const & other ) const
+  { return x == other.x; }
+};
+
+std::ostream& operator<<(std::ostream& os, TwoLA const & s)
+{
+  os << "[" << s.x << "]";
+  return os;
+}
+
+namespace cereal
+{
+  template <>
+  struct LoadAndConstruct<TwoLA>
+  {
+    template <class Archive>
+    static void load_and_construct( Archive & ar, cereal::construct<TwoLA> & construct )
+    {
+      int xx;
+      ar( xx );
+      construct( xx );
+    }
+  };
+}
+
+struct ThreeLA : std::enable_shared_from_this<ThreeLA>
+{
+  ThreeLA( int xx ) : x( xx ) {}
+
+  int x;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  { ar( x ); }
+
+  bool operator==( ThreeLA const & other ) const
+  { return x == other.x; }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<ThreeLA> & construct )
+  {
+    int xx;
+    ar( xx );
+    construct( xx );
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, ThreeLA const & s)
+{
+  os << "[" << s.x << "]";
+  return os;
+}
+
+template <class IArchive, class OArchive>
+void test_memory_load_construct()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    auto o_shared1 = std::make_shared<OneLA>( random_value<int>(gen) );
+    auto o_shared2 = std::make_shared<TwoLA>( random_value<int>(gen) );
+    std::unique_ptr<OneLA> o_unique1( new OneLA( random_value<int>(gen) ) );
+    std::unique_ptr<TwoLA> o_unique2( new TwoLA( random_value<int>(gen) ) );
+    auto o_shared3 = std::make_shared<ThreeLA>( random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_shared1 );
+      oar( o_shared2 );
+      oar( o_unique1 );
+      oar( o_unique2 );
+      oar( o_shared3 );
+    }
+
+    o_shared3->shared_from_this(); // tests github issue #68
+
+    decltype(o_shared1) i_shared1;
+    decltype(o_shared2) i_shared2;
+    decltype(o_unique1) i_unique1;
+    decltype(o_unique2) i_unique2;
+    decltype(o_shared3) i_shared3;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_shared1 );
+      iar( i_shared2 );
+      iar( i_unique1 );
+      iar( i_unique2 );
+      iar( i_shared3 );
+    }
+
+    BOOST_CHECK_EQUAL( *o_shared1, *i_shared1 );
+    BOOST_CHECK_EQUAL( *o_shared2, *i_shared2 );
+    BOOST_CHECK_EQUAL( *o_unique1, *i_unique1 );
+    BOOST_CHECK_EQUAL( *o_unique2, *i_unique2 );
+    BOOST_CHECK_EQUAL( *o_shared3, *i_shared3 );
+
+    auto i_shared3_2 = i_shared3->shared_from_this();
+    BOOST_CHECK_EQUAL( *o_shared3, *i_shared3_2 );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_memory_load_construct )
+{
+  test_memory_load_construct<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_memory_load_construct )
+{
+  test_memory_load_construct<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_memory_load_construct )
+{
+  test_memory_load_construct<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_memory_load_construct )
+{
+  test_memory_load_construct<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/map.cpp b/unittests/map.cpp
new file mode 100644
index 0000000..90dc283
--- /dev/null
+++ b/unittests/map.cpp
@@ -0,0 +1,206 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_map()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::map<size_t, std::vector<StructInternalSerialize>> o_vectormap;
+    for(int j=0; j<10; ++j)
+    {
+      size_t id = random_value<size_t>(gen);
+      for(int k=0; k<100; ++k)
+        o_vectormap[id].emplace_back(random_value<int>(gen), random_value<int>(gen));
+    }
+
+    std::map<std::string, int> o_podmap;
+    for(int j=0; j<100; ++j)
+      o_podmap.insert({random_value<std::string>(gen), random_value<int>(gen)});
+
+    std::map<int, StructInternalSerialize> o_isermap;
+    for(int j=0; j<100; ++j)
+      o_isermap.insert({random_value<int>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::map<int, StructInternalSplit> o_isplmap;
+    for(int j=0; j<100; ++j)
+      o_isplmap.insert({random_value<int>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::map<uint32_t, StructExternalSerialize> o_esermap;
+    for(int j=0; j<100; ++j)
+      o_esermap.insert({random_value<uint32_t>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::map<int8_t, StructExternalSplit> o_esplmap;
+    for(int j=0; j<100; ++j)
+      o_esplmap.insert({random_value<char>(gen),  { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_vectormap);
+      oar(o_podmap);
+      oar(o_isermap);
+      oar(o_isplmap);
+      oar(o_esermap);
+      oar(o_esplmap);
+    }
+
+    std::map<size_t, std::vector<StructInternalSerialize>> i_vectormap;
+    std::map<std::string, int> i_podmap;
+    std::map<int, StructInternalSerialize>   i_isermap;
+    std::map<int, StructInternalSplit>        i_isplmap;
+    std::map<uint32_t, StructExternalSerialize> i_esermap;
+    std::map<int8_t, StructExternalSplit>       i_esplmap;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_vectormap);
+      iar(i_podmap);
+      iar(i_isermap);
+      iar(i_isplmap);
+      iar(i_esermap);
+      iar(i_esplmap);
+    }
+
+    BOOST_CHECK_EQUAL(i_vectormap.size(), o_vectormap.size());
+    auto o_v_it = o_vectormap.begin();
+    auto i_v_it = i_vectormap.begin();
+    for(;o_v_it != o_vectormap.end(); ++o_v_it, ++i_v_it)
+    {
+      BOOST_CHECK_EQUAL(i_v_it->second.size(), o_v_it->second.size());
+      BOOST_CHECK_EQUAL_COLLECTIONS(i_v_it->second.begin(), i_v_it->second.end(), o_v_it->second.begin(), o_v_it->second.end());
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podmap.begin(),    i_podmap.end(),    o_podmap.begin(),  o_podmap.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isermap.begin(),   i_isermap.end(),   o_isermap.begin(), o_isermap.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplmap.begin(),   i_isplmap.end(),   o_isplmap.begin(), o_isplmap.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esermap.begin(),   i_esermap.end(),   o_esermap.begin(), o_esermap.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplmap.begin(),   i_esplmap.end(),   o_esplmap.begin(), o_esplmap.end());
+  }
+}
+
+template <class IArchive, class OArchive>
+void test_map_memory()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::map<int, std::unique_ptr<int>> o_uniqueptrMap;
+    std::map<int, std::shared_ptr<int>> o_sharedptrMap;
+
+    for(int j=0; j<100; ++j)
+    {
+      #ifdef CEREAL_OLDER_GCC
+      o_uniqueptrMap.insert( std::make_pair(random_value<int>(gen), std::unique_ptr<int>( new int( random_value<int>(gen) ) )) );
+      o_sharedptrMap.insert( std::make_pair(random_value<int>(gen), std::make_shared<int>( random_value<int>(gen) )) );
+      #else // NOT CEREAL_OLDER_GCC
+      o_uniqueptrMap.emplace( random_value<int>(gen), std::unique_ptr<int>( new int( random_value<int>(gen) ) ) );
+      o_sharedptrMap.emplace( random_value<int>(gen), std::make_shared<int>( random_value<int>(gen) ) );
+      #endif // NOT CEREAL_OLDER_GCC
+    }
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_uniqueptrMap );
+      oar( o_sharedptrMap );
+    }
+
+    decltype( o_uniqueptrMap ) i_uniqueptrMap;
+    decltype( o_sharedptrMap ) i_sharedptrMap;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_uniqueptrMap );
+      iar( i_sharedptrMap );
+    }
+
+    BOOST_CHECK_EQUAL(o_sharedptrMap.size(), i_sharedptrMap.size());
+    BOOST_CHECK_EQUAL(o_uniqueptrMap.size(), i_uniqueptrMap.size());
+
+    auto o_v_it = o_uniqueptrMap.begin();
+    auto i_v_it = i_uniqueptrMap.begin();
+    for(;o_v_it != o_uniqueptrMap.end(); ++o_v_it, ++i_v_it)
+    {
+      BOOST_CHECK_EQUAL(i_v_it->first, o_v_it->first);
+      BOOST_CHECK_EQUAL(*i_v_it->second, *o_v_it->second);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_map )
+{
+  test_map<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_map )
+{
+  test_map<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_map )
+{
+  test_map<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_map )
+{
+  test_map<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( binary_map_memory )
+{
+  test_map_memory<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_map_memory )
+{
+  test_map_memory<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_map_memory )
+{
+  test_map_memory<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_map_memory )
+{
+  test_map_memory<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/memory.cpp b/unittests/memory.cpp
new file mode 100644
index 0000000..8a86410
--- /dev/null
+++ b/unittests/memory.cpp
@@ -0,0 +1,154 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_memory()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::shared_ptr<int> o_xptr1 = std::make_shared<int>(random_value<int>(gen));
+    std::shared_ptr<int> o_xptr2 = o_xptr1;
+    std::shared_ptr<int> o_yptr1 = std::make_shared<int>(random_value<int>(gen));
+    std::shared_ptr<int> o_yptr2 = o_yptr1;
+    std::shared_ptr<int> o_nullptr1;
+    std::shared_ptr<int> o_nullptr2;
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_xptr1, o_xptr2 );
+      oar( o_yptr1, o_yptr2 );
+      oar( o_nullptr1, o_nullptr2 );
+    }
+
+    std::shared_ptr<int> i_xptr1;
+    std::shared_ptr<int> i_xptr2;
+    std::shared_ptr<int> i_yptr1;
+    std::shared_ptr<int> i_yptr2;
+    std::shared_ptr<int> i_nullptr1;
+    std::shared_ptr<int> i_nullptr2;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_xptr1, i_xptr2);
+      iar( i_yptr1, i_yptr2);
+      iar( i_nullptr1, i_nullptr2 );
+    }
+
+    BOOST_CHECK_EQUAL(o_xptr1.get(), o_xptr2.get());
+    BOOST_CHECK_EQUAL(i_xptr1.get(), i_xptr2.get());
+    BOOST_CHECK_EQUAL(*i_xptr1,      *i_xptr2);
+
+    BOOST_CHECK_EQUAL(o_yptr1.get(), o_yptr2.get());
+    BOOST_CHECK_EQUAL(i_yptr1.get(), i_yptr2.get());
+    BOOST_CHECK_EQUAL(*i_yptr1,      *i_yptr2);
+    BOOST_CHECK(!i_nullptr1);
+    BOOST_CHECK(!i_nullptr2);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_memory )
+{
+  test_memory<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_memory )
+{
+  test_memory<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_memory )
+{
+  test_memory<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_memory )
+{
+  test_memory<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+class TestClass
+{
+  public:
+    TestClass(int v) : x(v) { }
+    int x;
+
+  private:
+    friend class cereal::access;
+    TestClass() { };
+
+    template<class Archive>
+      void serialize(Archive & ar) { ar(x); }
+};
+
+
+template <class IArchive, class OArchive>
+void test_default_construction()
+{
+  auto o_ptr = std::make_shared<TestClass>(1);
+  std::shared_ptr<TestClass> i_ptr;
+
+  std::ostringstream os;
+  {
+    OArchive oar(os);
+    oar(o_ptr);
+  }
+  {
+    std::istringstream is(os.str());
+    IArchive iar(is);
+    iar(i_ptr);
+  }
+  BOOST_CHECK_EQUAL(o_ptr->x, i_ptr->x);
+}
+
+BOOST_AUTO_TEST_CASE( binary_default_construction )
+{
+  test_default_construction<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_default_construction )
+{
+  test_default_construction<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_default_construction )
+{
+  test_default_construction<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_default_construction )
+{
+  test_default_construction<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/memory_cycles.cpp b/unittests/memory_cycles.cpp
new file mode 100644
index 0000000..a98dd86
--- /dev/null
+++ b/unittests/memory_cycles.cpp
@@ -0,0 +1,161 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+struct MemoryCycle
+{
+  MemoryCycle() = default;
+
+  MemoryCycle( int v ) :
+    value( v )
+  { }
+
+  int value;
+  std::weak_ptr<MemoryCycle> ptr;
+
+  bool operator==( MemoryCycle const & other ) const
+  {
+    return value == other.value && ptr.lock() == other.ptr.lock();
+  }
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( value, ptr );
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, MemoryCycle const & s)
+{
+  os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]";
+  return os;
+}
+
+class MemoryCycleLoadAndConstruct
+{
+  public:
+    MemoryCycleLoadAndConstruct( int v ) :
+      value( v )
+    { }
+
+    MemoryCycleLoadAndConstruct( int v,
+        std::weak_ptr<MemoryCycleLoadAndConstruct> p ) :
+      value( v ),
+      ptr( p )
+    { }
+
+    bool operator==( MemoryCycleLoadAndConstruct const & other ) const
+    {
+      return value == other.value && ptr.lock() == other.ptr.lock();
+    }
+
+    template <class Archive>
+    void serialize( Archive & ar )
+    {
+      ar( value, ptr );
+    }
+
+    template <class Archive>
+    static void load_and_construct( Archive & ar, cereal::construct<MemoryCycleLoadAndConstruct> & construct )
+    {
+      int val;
+      std::weak_ptr<MemoryCycleLoadAndConstruct> p;
+
+      ar( val, p );
+      construct( val, p );
+    }
+
+    int value;
+    std::weak_ptr<MemoryCycleLoadAndConstruct> ptr;
+};
+
+std::ostream& operator<<(std::ostream& os, MemoryCycleLoadAndConstruct const & s)
+{
+  os << "[value: " << s.value << " ptr: " << s.ptr.lock() << "]";
+  return os;
+}
+
+template <class IArchive, class OArchive>
+void test_memory_cycles()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    auto o_ptr1 = std::make_shared<MemoryCycle>( random_value<int>(gen) );
+    o_ptr1->ptr = o_ptr1;
+    auto o_ptr2 = std::make_shared<MemoryCycleLoadAndConstruct>( random_value<int>(gen) );
+    o_ptr2->ptr = o_ptr2;
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_ptr1 );
+      oar( o_ptr2 );
+    }
+
+    decltype(o_ptr1) i_ptr1;
+    decltype(o_ptr2) i_ptr2;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_ptr1 );
+      iar( i_ptr2 );
+    }
+
+    BOOST_CHECK_EQUAL( o_ptr1->value, i_ptr1->value );
+    BOOST_CHECK_EQUAL( i_ptr1.get(), i_ptr1->ptr.lock().get() );
+    BOOST_CHECK_EQUAL( o_ptr2->value, i_ptr2->value );
+    BOOST_CHECK_EQUAL( i_ptr2.get(), i_ptr2->ptr.lock().get() );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_memory_cycles )
+{
+  test_memory_cycles<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_memory_cycles )
+{
+  test_memory_cycles<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_memory_cycles )
+{
+  test_memory_cycles<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_memory_cycles )
+{
+  test_memory_cycles<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/multimap.cpp b/unittests/multimap.cpp
new file mode 100644
index 0000000..af8492d
--- /dev/null
+++ b/unittests/multimap.cpp
@@ -0,0 +1,147 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_multimap()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::multimap<std::string, int> o_podmultimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<std::string>(gen);
+      o_podmultimap.insert({key, random_value<int>(gen)});
+      o_podmultimap.insert({key, random_value<int>(gen)});
+    }
+
+    std::multimap<uint8_t, StructInternalSerialize> o_isermultimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<uint8_t>(gen);
+      o_isermultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_isermultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::multimap<int16_t, StructInternalSplit> o_isplmultimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<int16_t>(gen);
+      o_isplmultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_isplmultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::multimap<uint32_t, StructExternalSerialize> o_esermultimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<uint32_t>(gen);
+      o_esermultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_esermultimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::multimap<int8_t, StructExternalSplit> o_esplmultimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<char>(gen);
+      o_esplmultimap.insert({key,  { random_value<int>(gen), random_value<int>(gen) }});
+      o_esplmultimap.insert({key,  { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podmultimap);
+      oar(o_isermultimap);
+      oar(o_isplmultimap);
+      oar(o_esermultimap);
+      oar(o_esplmultimap);
+    }
+
+    std::multimap<std::string, int> i_podmultimap;
+    std::multimap<uint8_t, StructInternalSerialize>   i_isermultimap;
+    std::multimap<int16_t, StructInternalSplit>        i_isplmultimap;
+    std::multimap<uint32_t, StructExternalSerialize> i_esermultimap;
+    std::multimap<int8_t, StructExternalSplit>       i_esplmultimap;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podmultimap);
+      iar(i_isermultimap);
+      iar(i_isplmultimap);
+      iar(i_esermultimap);
+      iar(i_esplmultimap);
+    }
+
+#define MULTIMAP_CHECK(InMap, OutMap) \
+    for( auto & pair : OutMap ) \
+    { \
+      auto const count = InMap.count( pair.first ); \
+      BOOST_CHECK_EQUAL( count, OutMap.count( pair.first ) ); \
+      auto find = InMap.find( pair.first ); \
+      bool found = false; \
+      for( size_t i = 0; i < count; ++i, ++find ) \
+        found |= find->second == pair.second; \
+      BOOST_CHECK( found ); \
+    }
+
+    MULTIMAP_CHECK( i_podmultimap, o_podmultimap );
+    MULTIMAP_CHECK( i_isermultimap, o_isermultimap );
+    MULTIMAP_CHECK( i_isplmultimap, o_isplmultimap );
+    MULTIMAP_CHECK( i_esermultimap, o_esermultimap );
+    MULTIMAP_CHECK( i_esplmultimap, o_esplmultimap );
+
+#undef MULTIMAP_CHECK
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_multimap )
+{
+  test_multimap<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_multimap )
+{
+  test_multimap<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_multimap )
+{
+  test_multimap<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_multimap )
+{
+  test_multimap<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/multiset.cpp b/unittests/multiset.cpp
new file mode 100644
index 0000000..206c69f
--- /dev/null
+++ b/unittests/multiset.cpp
@@ -0,0 +1,153 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_multiset()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::multiset<int> o_podmultiset;
+    for(int j=0; j<100; ++j)
+    {
+      int value = random_value<int>(gen);
+      o_podmultiset.insert(value);
+      o_podmultiset.insert(value);
+    }
+
+    std::multiset<StructInternalSerialize> o_isermultiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructInternalSerialize value = { random_value<int>(gen), random_value<int>(gen) };
+      o_isermultiset.insert(value);
+      o_isermultiset.insert(value);
+    }
+
+    std::multiset<StructInternalSplit> o_isplmultiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructInternalSplit value = { random_value<int>(gen), random_value<int>(gen) };
+      o_isplmultiset.insert(value);
+      o_isplmultiset.insert(value);
+    }
+
+    std::multiset<StructExternalSerialize> o_esermultiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructExternalSerialize value = { random_value<int>(gen), random_value<int>(gen) };
+      o_esermultiset.insert(value);
+      o_esermultiset.insert(value);
+    }
+
+    std::multiset<StructExternalSplit> o_esplmultiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructExternalSplit value = { random_value<int>(gen), random_value<int>(gen) };
+      o_esplmultiset.insert(value);
+      o_esplmultiset.insert(value);
+    }
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podmultiset);
+      oar(o_isermultiset);
+      oar(o_isplmultiset);
+      oar(o_esermultiset);
+      oar(o_esplmultiset);
+    }
+
+    std::multiset<int> i_podmultiset;
+    std::multiset<StructInternalSerialize> i_isermultiset;
+    std::multiset<StructInternalSplit>     i_isplmultiset;
+    std::multiset<StructExternalSerialize> i_esermultiset;
+    std::multiset<StructExternalSplit>     i_esplmultiset;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podmultiset);
+      iar(i_isermultiset);
+      iar(i_isplmultiset);
+      iar(i_esermultiset);
+      iar(i_esplmultiset);
+    }
+
+    for(auto const & p : i_podmultiset)
+    {
+      BOOST_CHECK_EQUAL(o_podmultiset.count(p), i_podmultiset.count(p));
+    }
+
+    for(auto const & p : i_isermultiset)
+    {
+      BOOST_CHECK_EQUAL(o_isermultiset.count(p), i_isermultiset.count(p));
+    }
+
+    for(auto const & p : i_isplmultiset)
+    {
+      BOOST_CHECK_EQUAL(o_isplmultiset.count(p), i_isplmultiset.count(p));
+    }
+
+    for(auto const & p : i_esermultiset)
+    {
+      BOOST_CHECK_EQUAL(o_esermultiset.count(p), i_esermultiset.count(p));
+    }
+
+    for(auto const & p : i_esplmultiset)
+    {
+      BOOST_CHECK_EQUAL(o_esplmultiset.count(p), i_esplmultiset.count(p));
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_multiset )
+{
+  test_multiset<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_multiset )
+{
+  test_multiset<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_multiset )
+{
+  test_multiset<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_multiset )
+{
+  test_multiset<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/pair.cpp b/unittests/pair.cpp
new file mode 100644
index 0000000..4e1e61a
--- /dev/null
+++ b/unittests/pair.cpp
@@ -0,0 +1,109 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_pair()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rng = [&](){ return random_value<int>(gen); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::pair<int, int> o_podpair = {rng(), rng()};
+    std::pair<StructInternalSerialize, StructInternalSerialize> o_iserpair = {{rng(), rng()}, {rng(), rng()}};
+    std::pair<StructInternalSplit, StructInternalSplit> o_isplpair = {{rng(), rng()}, {rng(), rng()}};
+    std::pair<StructExternalSerialize, StructExternalSerialize> o_eserpair = {{rng(), rng()}, {rng(), rng()}};
+    std::pair<StructExternalSplit, StructExternalSplit> o_esplpair = {{rng(), rng()}, {rng(), rng()}};
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podpair);
+      oar(o_iserpair);
+      oar(o_isplpair);
+      oar(o_eserpair);
+      oar(o_esplpair);
+    }
+
+    std::pair<int, int> i_podpair;
+    std::pair<StructInternalSerialize, StructInternalSerialize> i_iserpair;
+    std::pair<StructInternalSplit, StructInternalSplit> i_isplpair;
+    std::pair<StructExternalSerialize, StructExternalSerialize> i_eserpair;
+    std::pair<StructExternalSplit, StructExternalSplit> i_esplpair;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podpair);
+      iar(i_iserpair);
+      iar(i_isplpair);
+      iar(i_eserpair);
+      iar(i_esplpair);
+    }
+
+    BOOST_CHECK_EQUAL( i_podpair.first, o_podpair.first );
+    BOOST_CHECK_EQUAL( i_podpair.second, o_podpair.second );
+
+    BOOST_CHECK_EQUAL( i_iserpair.first, o_iserpair.first );
+    BOOST_CHECK_EQUAL( i_iserpair.second, o_iserpair.second );
+
+    BOOST_CHECK_EQUAL( i_isplpair.first, o_isplpair.first );
+    BOOST_CHECK_EQUAL( i_isplpair.second, o_isplpair.second );
+
+    BOOST_CHECK_EQUAL( i_eserpair.first, o_eserpair.first );
+    BOOST_CHECK_EQUAL( i_eserpair.second, o_eserpair.second );
+
+    BOOST_CHECK_EQUAL( i_esplpair.first, o_esplpair.first );
+    BOOST_CHECK_EQUAL( i_esplpair.second, o_esplpair.second );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_pair )
+{
+  test_pair<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_pair )
+{
+  test_pair<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_pair )
+{
+  test_pair<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+BOOST_AUTO_TEST_CASE( json_pair )
+{
+  test_pair<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/pod.cpp b/unittests/pod.cpp
new file mode 100644
index 0000000..4fe5ac8
--- /dev/null
+++ b/unittests/pod.cpp
@@ -0,0 +1,164 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_pod()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(size_t i=0; i<100; ++i)
+  {
+    bool          const o_bool   = random_value<uint8_t>(gen) % 2 ? true : false;
+    char          const o_char   = random_value<char>(gen);
+    unsigned char const o_uchar  = random_value<unsigned char>(gen);
+    uint8_t       const o_uint8  = random_value<uint8_t>(gen);
+    int8_t        const o_int8   = random_value<int8_t>(gen);
+    uint16_t      const o_uint16 = random_value<uint16_t>(gen);
+    int16_t       const o_int16  = random_value<int16_t>(gen);
+    uint32_t      const o_uint32 = random_value<uint32_t>(gen);
+    int32_t       const o_int32  = random_value<int32_t>(gen);
+    uint64_t      const o_uint64 = random_value<uint64_t>(gen);
+    int64_t       const o_int64  = random_value<int64_t>(gen);
+    float         const o_float  = random_value<float>(gen);
+    double        const o_double = random_value<double>(gen);
+
+    long double const o_long_double = random_value<long double>(gen);
+    long const o_long = random_value<long>(gen);
+    unsigned long const o_ulong = random_value<unsigned long>(gen);
+    long long const o_long_long = random_value<long long>(gen);
+    unsigned long long const o_ulong_long = random_value<unsigned long long>(gen);
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar(o_bool);
+      oar(o_char);
+      oar(o_uchar);
+      oar(o_uint8);
+      oar(o_int8);
+      oar(o_uint16);
+      oar(o_int16);
+      oar(o_uint32);
+      oar(o_int32);
+      oar(o_uint64);
+      oar(o_int64);
+      oar(o_float);
+      oar(o_double);
+      oar(o_long_double);
+      oar(o_long);
+      oar(o_ulong);
+      oar(o_long_long);
+      oar(o_ulong_long);
+    }
+
+    bool          i_bool                       = false;
+    char          i_char                       = 0;
+    unsigned char i_uchar                      = 0;
+    uint8_t       i_uint8                      = 0;
+    int8_t        i_int8                       = 0;
+    uint16_t      i_uint16                     = 0;
+    int16_t       i_int16                      = 0;
+    uint32_t      i_uint32                     = 0;
+    int32_t       i_int32                      = 0;
+    uint64_t      i_uint64                     = 0;
+    int64_t       i_int64                      = 0;
+    float         i_float                      = 0;
+    double        i_double                     = 0;
+
+    long double i_long_double       = 0;
+    long i_long                     = 0;
+    unsigned long i_ulong           = 0;
+    long long i_long_long           = 0;
+    unsigned long long i_ulong_long = 0;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+      iar(i_bool);
+      iar(i_char);
+      iar(i_uchar);
+      iar(i_uint8);
+      iar(i_int8);
+      iar(i_uint16);
+      iar(i_int16);
+      iar(i_uint32);
+      iar(i_int32);
+      iar(i_uint64);
+      iar(i_int64);
+      iar(i_float);
+      iar(i_double);
+      iar(i_long_double);
+      iar(i_long);
+      iar(i_ulong);
+      iar(i_long_long);
+      iar(i_ulong_long);
+    }
+
+    BOOST_CHECK_EQUAL(i_bool   , o_bool);
+    BOOST_CHECK_EQUAL(i_char   , o_char);
+    BOOST_CHECK_EQUAL(i_uchar  , o_uchar);
+    BOOST_CHECK_EQUAL(i_uint8  , o_uint8);
+    BOOST_CHECK_EQUAL(i_int8   , o_int8);
+    BOOST_CHECK_EQUAL(i_uint16 , o_uint16);
+    BOOST_CHECK_EQUAL(i_int16  , o_int16);
+    BOOST_CHECK_EQUAL(i_uint32 , o_uint32);
+    BOOST_CHECK_EQUAL(i_int32  , o_int32);
+    BOOST_CHECK_EQUAL(i_uint64 , o_uint64);
+    BOOST_CHECK_EQUAL(i_int64  , o_int64);
+    BOOST_CHECK_CLOSE(i_float  , o_float,  (float)1e-5);
+    BOOST_CHECK_CLOSE(i_double , o_double, 1e-5);
+
+    BOOST_CHECK_CLOSE(i_long_double, o_long_double, 1e-5);
+    BOOST_CHECK_EQUAL(i_long,        o_long);
+    BOOST_CHECK_EQUAL(i_ulong,       o_ulong);
+    BOOST_CHECK_EQUAL(i_long_long,   o_long_long);
+    BOOST_CHECK_EQUAL(i_ulong_long,  o_ulong_long);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_pod )
+{
+  test_pod<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_pod )
+{
+  test_pod<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_pod )
+{
+  test_pod<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_pod )
+{
+  test_pod<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/polymorphic.cpp b/unittests/polymorphic.cpp
new file mode 100644
index 0000000..835983d
--- /dev/null
+++ b/unittests/polymorphic.cpp
@@ -0,0 +1,212 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+struct PolyBase
+{
+  PolyBase() {}
+  PolyBase( int xx, float yy ) : x(xx), y(yy) {}
+  int x;
+  float y;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x, y );
+  }
+
+  virtual void foo() = 0;
+
+  bool operator==( PolyBase const & other ) const
+  {
+    return x == other.x && std::abs(y - other.y) < 1e-5;
+  }
+};
+
+struct PolyDerived : PolyBase
+{
+  PolyDerived() {}
+  PolyDerived( int xx, float yy, bool aa, double bb ) :
+    PolyBase( xx, yy ), a(aa), b(bb) {}
+
+  bool a;
+  double b;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( cereal::base_class<PolyBase>( this ),
+        a, b );
+  }
+
+  bool operator==( PolyDerived const & other ) const
+  {
+    return PolyBase::operator==( other ) && a == other.a && std::abs(b - other.b) < 1e-5;
+  }
+
+  void foo() {}
+};
+
+struct PolyLA : std::enable_shared_from_this<PolyLA>
+{
+  virtual void foo() = 0;
+};
+
+struct PolyDerivedLA : public PolyLA
+{
+  PolyDerivedLA( int xx ) : x( xx ) { }
+
+  int x;
+  std::vector<std::shared_ptr<PolyLA>> vec;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x );
+    ar( vec );
+  }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<PolyDerivedLA> & construct )
+  {
+    int xx;
+    ar( xx );
+    construct( xx );
+    ar( construct->vec );
+  }
+
+  void foo() {}
+
+  bool operator==( PolyDerivedLA const & other ) const
+  {
+    if( x != other.x )
+      return false;
+    if( vec.size() != other.vec.size() )
+      return false;
+    for( size_t i = 0; i < vec.size(); ++i )
+      if( !(*std::dynamic_pointer_cast<PolyDerivedLA>(vec[i]) == *std::dynamic_pointer_cast<PolyDerivedLA>(other.vec[i])) )
+        return false;
+
+    return true;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, PolyDerivedLA const & s)
+{
+    os << "[x: " << s.x << "] ";
+    for( auto const & v : s.vec )
+      os << " child: " << (*std::dynamic_pointer_cast<PolyDerivedLA>(v));
+    return os;
+}
+
+std::ostream& operator<<(std::ostream& os, PolyDerived const & s)
+{
+    os << "[x: " << s.x << " y: " << s.y << " a: " << s.a << " b: " << s.b << "]";
+    return os;
+}
+
+CEREAL_REGISTER_TYPE(PolyDerived)
+CEREAL_REGISTER_TYPE(PolyDerivedLA)
+
+template <class IArchive, class OArchive>
+void test_polymorphic()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rngB = [&](){ return random_value<int>( gen ) % 2 == 0; };
+  auto rngI = [&](){ return random_value<int>( gen ); };
+  auto rngF = [&](){ return random_value<float>( gen ); };
+  auto rngD = [&](){ return random_value<double>( gen ); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::shared_ptr<PolyBase> o_shared = std::make_shared<PolyDerived>( rngI(), rngF(), rngB(), rngD() );
+    std::weak_ptr<PolyBase>   o_weak = o_shared;
+    std::unique_ptr<PolyBase> o_unique( new PolyDerived( rngI(), rngF(), rngB(), rngD() ) );
+
+    auto pda = std::make_shared<PolyDerivedLA>( rngI() );
+    pda->vec.emplace_back( std::make_shared<PolyDerivedLA>( rngI() ) );
+    std::shared_ptr<PolyLA>   o_sharedLA = pda;
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_shared, o_weak, o_unique );
+      oar( o_sharedLA );
+    }
+
+    decltype(o_shared) i_shared;
+    decltype(o_weak) i_weak;
+    decltype(o_unique) i_unique;
+    decltype(o_sharedLA) i_sharedLA;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_shared, i_weak, i_unique );
+      iar( i_sharedLA );
+    }
+
+    auto i_locked = i_weak.lock();
+    auto o_locked = o_weak.lock();
+
+    auto i_sharedLA2 = i_sharedLA->shared_from_this();
+
+    BOOST_CHECK_EQUAL(i_shared.get(), i_locked.get());
+    BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)o_shared.get()));
+    BOOST_CHECK_EQUAL(*((PolyDerived*)i_shared.get()), *((PolyDerived*)i_locked.get()));
+    BOOST_CHECK_EQUAL(*((PolyDerived*)i_locked.get()), *((PolyDerived*)o_locked.get()));
+    BOOST_CHECK_EQUAL(*((PolyDerived*)i_unique.get()), *((PolyDerived*)o_unique.get()));
+    BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA.get()), *((PolyDerivedLA*)o_sharedLA.get()));
+    BOOST_CHECK_EQUAL(*((PolyDerivedLA*)i_sharedLA2.get()), *((PolyDerivedLA*)o_sharedLA.get()));
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_polymorphic )
+{
+  test_polymorphic<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_polymorphic )
+{
+  test_polymorphic<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_polymorphic )
+{
+  test_polymorphic<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_polymorphic )
+{
+  test_polymorphic<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/portability_test.cpp b/unittests/portability_test.cpp
new file mode 100644
index 0000000..f3a7edb
--- /dev/null
+++ b/unittests/portability_test.cpp
@@ -0,0 +1,202 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <cereal/archives/portable_binary.hpp>
+
+#include <cereal/types/memory.hpp>
+#include <cereal/types/map.hpp>
+#include <cereal/types/vector.hpp>
+
+#include <fstream>
+#include <iostream>
+
+struct Data : std::enable_shared_from_this<Data>
+{
+  int32_t x;
+  int64_t y;
+
+  Data( int32_t xx, int64_t yy ) : x(xx), y(yy) {}
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x, y );
+  }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<Data> & construct )
+  {
+    int32_t xx;
+    int64_t yy;
+    ar( xx, yy );
+    construct( xx, yy );
+  }
+
+  bool operator==( Data const & other ) const
+  {
+    if( x != other.x )
+    {
+      std::cerr << "x=" << x << ", other.x=" << other.x << std::endl;
+      return false;
+    }
+    if( y != other.y )
+    {
+      std::cerr << "y=" << y << ", other.y=" << other.y << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+};
+
+struct Data2
+{
+  int32_t x;
+  int64_t y;
+
+  Data2() = default;
+  Data2( int32_t xx, int64_t yy ) : x(xx), y(yy) {}
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( x, y );
+  }
+
+  bool operator==( Data2 const & other ) const
+  {
+    if( x != other.x )
+    {
+      std::cerr << "x=" << x << ", other.x=" << other.x << std::endl;
+      return false;
+    }
+    if( y != other.y )
+    {
+      std::cerr << "y=" << y << ", other.y=" << other.y << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+};
+
+const uint32_t AnotherCount = 32;
+
+struct Another
+{
+  Another() = default;
+
+  Another( bool )
+  {
+    for( uint32_t i = 0; i < AnotherCount; ++i )
+      data[i] = Data2( i, i+1 );
+  }
+
+  std::map<std::uint32_t, Data2> data;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( data );
+  }
+
+  bool operator==( Another const & other ) const
+  {
+    auto iter  = data.begin();
+    auto oiter = other.data.begin();
+    for( ; iter != data.end(); ++iter, ++oiter )
+    {
+      if( !(iter->second == oiter->second) )
+      {
+        std::cerr << "Data mismatch at i=" << iter->first << std::endl;
+        return false;
+      }
+    }
+
+    return true;
+  }
+};
+
+int main( int, char ** argv )
+{
+  std::vector<Another> vec_o;
+  for( int i = 0; i < 5; ++i )
+    vec_o.emplace_back( true );
+
+  auto data_o = std::make_shared<Data>( 33, 64 );
+  int32_t int_o = 7;
+
+  std::cerr << "Portability test: " << argv[2] << "bit" << std::endl;
+
+  if( std::string(argv[1]) == "load" )
+  {
+    std::ifstream is("portable.cereal", std::ios::binary);
+    cereal::PortableBinaryInputArchive ar( is );
+
+    std::vector<Another> vec_i;
+    std::shared_ptr<Data> data_i;
+    int32_t int_i;
+
+    ar( int_i );
+
+    if( int_i != int_o )
+    {
+      std::cerr << "in " << int_i << ", out: " << int_o << std::endl;
+      return -1;
+    }
+
+    ar( vec_i );
+    ar( data_i );
+
+    if( vec_i != vec_o )
+    {
+      std::cerr << "Input vector did not equal output vector" << std::endl;
+      return -1;
+    }
+
+    if( !(*data_i == *data_o) )
+    {
+      std::cerr << "Data did not match" << std::endl;
+      return -1;
+    }
+  }
+  else if( std::string(argv[1]) == "save" )
+  {
+    std::ofstream os("portable.cereal", std::ios::binary);
+    cereal::PortableBinaryOutputArchive ar( os );
+
+    ar( int_o );
+    ar( vec_o );
+    ar( data_o );
+  }
+  else // clean
+  {
+    std::remove( "portable.cereal" );
+  }
+
+  return 0;
+}
diff --git a/unittests/portable_binary_archive.cpp b/unittests/portable_binary_archive.cpp
new file mode 100644
index 0000000..68b78cb
--- /dev/null
+++ b/unittests/portable_binary_archive.cpp
@@ -0,0 +1,155 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace mynamespace { struct MyCustomClass {}; }
+
+#ifdef _MSC_VER
+BOOST_AUTO_TEST_CASE( util )
+{
+  BOOST_CHECK_EQUAL( cereal::util::demangledName<mynamespace::MyCustomClass>(), "struct mynamespace::MyCustomClass" );
+}
+#else
+BOOST_AUTO_TEST_CASE( util )
+{
+  BOOST_CHECK_EQUAL( cereal::util::demangledName<mynamespace::MyCustomClass>(), "mynamespace::MyCustomClass" );
+}
+#endif
+
+template <class T>
+inline void swapBytes( T & t )
+{
+  cereal::portable_binary_detail::swap_bytes<sizeof(T)>( reinterpret_cast<std::uint8_t*>(&t) );
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_archive )
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(size_t i=0; i<100; ++i)
+  {
+    bool     o_bool   = random_value<uint8_t>(gen) % 2 ? true : false;
+    uint8_t  o_uint8  = random_value<uint8_t>(gen);
+    int8_t   o_int8   = random_value<int8_t>(gen);
+    uint16_t o_uint16 = random_value<uint16_t>(gen);
+    int16_t  o_int16  = random_value<int16_t>(gen);
+    uint32_t o_uint32 = random_value<uint32_t>(gen);
+    int32_t  o_int32  = random_value<int32_t>(gen);
+    uint64_t o_uint64 = random_value<uint64_t>(gen);
+    int64_t  o_int64  = random_value<int64_t>(gen);
+    float    o_float  = random_value<float>(gen);
+    double   o_double = random_value<double>(gen);
+
+    // swap the bytes on all of the data
+    swapBytes(o_bool);
+    swapBytes(o_uint8);
+    swapBytes(o_int8);
+    swapBytes(o_uint16);
+    swapBytes(o_int16);
+    swapBytes(o_uint32);
+    swapBytes(o_int32);
+    swapBytes(o_uint64);
+    swapBytes(o_int64);
+    swapBytes(o_float);
+    swapBytes(o_double);
+
+    std::ostringstream os;
+    {
+      cereal::BinaryOutputArchive oar(os);
+      // manually insert incorrect endian encoding
+      oar(!cereal::portable_binary_detail::is_little_endian());
+
+      oar(o_bool);
+      oar(o_uint8);
+      oar(o_int8);
+      oar(o_uint16);
+      oar(o_int16);
+      oar(o_uint32);
+      oar(o_int32);
+      oar(o_uint64);
+      oar(o_int64);
+      oar(o_float);
+      oar(o_double);
+    }
+
+    // swap back to original values
+    swapBytes(o_bool);
+    swapBytes(o_uint8);
+    swapBytes(o_int8);
+    swapBytes(o_uint16);
+    swapBytes(o_int16);
+    swapBytes(o_uint32);
+    swapBytes(o_int32);
+    swapBytes(o_uint64);
+    swapBytes(o_int64);
+    swapBytes(o_float);
+    swapBytes(o_double);
+
+    bool     i_bool   = false;
+    uint8_t  i_uint8  = 0;
+    int8_t   i_int8   = 0;
+    uint16_t i_uint16 = 0;
+    int16_t  i_int16  = 0;
+    uint32_t i_uint32 = 0;
+    int32_t  i_int32  = 0;
+    uint64_t i_uint64 = 0;
+    int64_t  i_int64  = 0;
+    float    i_float  = 0;
+    double   i_double = 0;
+
+    std::istringstream is(os.str());
+    {
+      cereal::PortableBinaryInputArchive iar(is);
+      iar(i_bool);
+      iar(i_uint8);
+      iar(i_int8);
+      iar(i_uint16);
+      iar(i_int16);
+      iar(i_uint32);
+      iar(i_int32);
+      iar(i_uint64);
+      iar(i_int64);
+      iar(i_float);
+      iar(i_double);
+    }
+
+    BOOST_CHECK_EQUAL(i_bool   , o_bool);
+    BOOST_CHECK_EQUAL(i_uint8  , o_uint8);
+    BOOST_CHECK_EQUAL(i_int8   , o_int8);
+    BOOST_CHECK_EQUAL(i_uint16 , o_uint16);
+    BOOST_CHECK_EQUAL(i_int16  , o_int16);
+    BOOST_CHECK_EQUAL(i_uint32 , o_uint32);
+    BOOST_CHECK_EQUAL(i_int32  , o_int32);
+    BOOST_CHECK_EQUAL(i_uint64 , o_uint64);
+    BOOST_CHECK_EQUAL(i_int64  , o_int64);
+    BOOST_CHECK_CLOSE(i_float  , o_float,  (float)1e-5);
+    BOOST_CHECK_CLOSE(i_double , o_double, 1e-5);
+  }
+}
+
diff --git a/unittests/priority_queue.cpp b/unittests/priority_queue.cpp
new file mode 100644
index 0000000..8e0b32f
--- /dev/null
+++ b/unittests/priority_queue.cpp
@@ -0,0 +1,125 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_priority_queue()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::priority_queue<int> o_podpriority_queue;
+    for(int j=0; j<100; ++j)
+      o_podpriority_queue.push(random_value<int>(gen));
+
+    std::priority_queue<StructInternalSerialize> o_iserpriority_queue;
+    for(int j=0; j<100; ++j)
+      o_iserpriority_queue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::priority_queue<StructInternalSplit> o_isplpriority_queue;
+    for(int j=0; j<100; ++j)
+      o_isplpriority_queue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::priority_queue<StructExternalSerialize> o_eserpriority_queue;
+    for(int j=0; j<100; ++j)
+      o_eserpriority_queue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::priority_queue<StructExternalSplit> o_esplpriority_queue;
+    for(int j=0; j<100; ++j)
+      o_esplpriority_queue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podpriority_queue);
+      oar(o_iserpriority_queue);
+      oar(o_isplpriority_queue);
+      oar(o_eserpriority_queue);
+      oar(o_esplpriority_queue);
+    }
+
+    std::priority_queue<int> i_podpriority_queue;
+    std::priority_queue<StructInternalSerialize> i_iserpriority_queue;
+    std::priority_queue<StructInternalSplit>     i_isplpriority_queue;
+    std::priority_queue<StructExternalSerialize> i_eserpriority_queue;
+    std::priority_queue<StructExternalSplit>     i_esplpriority_queue;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podpriority_queue);
+      iar(i_iserpriority_queue);
+      iar(i_isplpriority_queue);
+      iar(i_eserpriority_queue);
+      iar(i_esplpriority_queue);
+    }
+
+    auto & i_podpriority_queue_c  = cereal::queue_detail::container(i_podpriority_queue);
+    auto & i_iserpriority_queue_c = cereal::queue_detail::container(i_iserpriority_queue);
+    auto & i_isplpriority_queue_c = cereal::queue_detail::container(i_isplpriority_queue);
+    auto & i_eserpriority_queue_c = cereal::queue_detail::container(i_eserpriority_queue);
+    auto & i_esplpriority_queue_c = cereal::queue_detail::container(i_esplpriority_queue);
+
+    auto & o_podpriority_queue_c  = cereal::queue_detail::container(o_podpriority_queue);
+    auto & o_iserpriority_queue_c = cereal::queue_detail::container(o_iserpriority_queue);
+    auto & o_isplpriority_queue_c = cereal::queue_detail::container(o_isplpriority_queue);
+    auto & o_eserpriority_queue_c = cereal::queue_detail::container(o_eserpriority_queue);
+    auto & o_esplpriority_queue_c = cereal::queue_detail::container(o_esplpriority_queue);
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podpriority_queue_c.begin(),    i_podpriority_queue_c.end(),    o_podpriority_queue_c.begin(),  o_podpriority_queue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserpriority_queue_c.begin(),   i_iserpriority_queue_c.end(),   o_iserpriority_queue_c.begin(), o_iserpriority_queue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplpriority_queue_c.begin(),   i_isplpriority_queue_c.end(),   o_isplpriority_queue_c.begin(), o_isplpriority_queue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserpriority_queue_c.begin(),   i_eserpriority_queue_c.end(),   o_eserpriority_queue_c.begin(), o_eserpriority_queue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplpriority_queue_c.begin(),   i_esplpriority_queue_c.end(),   o_esplpriority_queue_c.begin(), o_esplpriority_queue_c.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_priority_queue )
+{
+  test_priority_queue<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_priority_queue )
+{
+  test_priority_queue<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_priority_queue )
+{
+  test_priority_queue<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_priority_queue )
+{
+  test_priority_queue<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/queue.cpp b/unittests/queue.cpp
new file mode 100644
index 0000000..175456e
--- /dev/null
+++ b/unittests/queue.cpp
@@ -0,0 +1,125 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_queue()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::queue<int> o_podqueue;
+    for(int j=0; j<100; ++j)
+      o_podqueue.push(random_value<int>(gen));
+
+    std::queue<StructInternalSerialize> o_iserqueue;
+    for(int j=0; j<100; ++j)
+      o_iserqueue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::queue<StructInternalSplit> o_isplqueue;
+    for(int j=0; j<100; ++j)
+      o_isplqueue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::queue<StructExternalSerialize> o_eserqueue;
+    for(int j=0; j<100; ++j)
+      o_eserqueue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::queue<StructExternalSplit> o_esplqueue;
+    for(int j=0; j<100; ++j)
+      o_esplqueue.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podqueue);
+      oar(o_iserqueue);
+      oar(o_isplqueue);
+      oar(o_eserqueue);
+      oar(o_esplqueue);
+    }
+
+    std::queue<int> i_podqueue;
+    std::queue<StructInternalSerialize> i_iserqueue;
+    std::queue<StructInternalSplit>     i_isplqueue;
+    std::queue<StructExternalSerialize> i_eserqueue;
+    std::queue<StructExternalSplit>     i_esplqueue;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podqueue);
+      iar(i_iserqueue);
+      iar(i_isplqueue);
+      iar(i_eserqueue);
+      iar(i_esplqueue);
+    }
+
+    auto & i_podqueue_c  = cereal::queue_detail::container(i_podqueue);
+    auto & i_iserqueue_c = cereal::queue_detail::container(i_iserqueue);
+    auto & i_isplqueue_c = cereal::queue_detail::container(i_isplqueue);
+    auto & i_eserqueue_c = cereal::queue_detail::container(i_eserqueue);
+    auto & i_esplqueue_c = cereal::queue_detail::container(i_esplqueue);
+
+    auto & o_podqueue_c  = cereal::queue_detail::container(o_podqueue);
+    auto & o_iserqueue_c = cereal::queue_detail::container(o_iserqueue);
+    auto & o_isplqueue_c = cereal::queue_detail::container(o_isplqueue);
+    auto & o_eserqueue_c = cereal::queue_detail::container(o_eserqueue);
+    auto & o_esplqueue_c = cereal::queue_detail::container(o_esplqueue);
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podqueue_c.begin(),    i_podqueue_c.end(),    o_podqueue_c.begin(),  o_podqueue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserqueue_c.begin(),   i_iserqueue_c.end(),   o_iserqueue_c.begin(), o_iserqueue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplqueue_c.begin(),   i_isplqueue_c.end(),   o_isplqueue_c.begin(), o_isplqueue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserqueue_c.begin(),   i_eserqueue_c.end(),   o_eserqueue_c.begin(), o_eserqueue_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplqueue_c.begin(),   i_esplqueue_c.end(),   o_esplqueue_c.begin(), o_esplqueue_c.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_queue )
+{
+  test_queue<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_queue )
+{
+  test_queue<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_queue )
+{
+  test_queue<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_queue )
+{
+  test_queue<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/run_portability_test.sh b/unittests/run_portability_test.sh
new file mode 100755
index 0000000..7184402
--- /dev/null
+++ b/unittests/run_portability_test.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+set -e
+
+./portability_test64 save 64
+./portability_test32 load 32
+./portability_test32 save 32
+./portability_test64 load 64
+./portability_test64 remove 64
diff --git a/unittests/run_valgrind.sh b/unittests/run_valgrind.sh
new file mode 100755
index 0000000..022b1b0
--- /dev/null
+++ b/unittests/run_valgrind.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -e
+
+TESTS=./test_*
+
+for f in $TESTS
+  do
+    valgrind --tool=memcheck --leak-check=full $f
+  done
diff --git a/unittests/set.cpp b/unittests/set.cpp
new file mode 100644
index 0000000..e9bb3bb
--- /dev/null
+++ b/unittests/set.cpp
@@ -0,0 +1,113 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_set()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::set<int> o_podset;
+    for(int j=0; j<100; ++j)
+      o_podset.insert(random_value<int>(gen));
+
+    std::set<StructInternalSerialize> o_iserset;
+    for(int j=0; j<100; ++j)
+      o_iserset.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::set<StructInternalSplit> o_isplset;
+    for(int j=0; j<100; ++j)
+      o_isplset.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::set<StructExternalSerialize> o_eserset;
+    for(int j=0; j<100; ++j)
+      o_eserset.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::set<StructExternalSplit> o_esplset;
+    for(int j=0; j<100; ++j)
+      o_esplset.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podset);
+      oar(o_iserset);
+      oar(o_isplset);
+      oar(o_eserset);
+      oar(o_esplset);
+    }
+
+    std::set<int> i_podset;
+    std::set<StructInternalSerialize>   i_iserset;
+    std::set<StructInternalSplit>        i_isplset;
+    std::set<StructExternalSerialize> i_eserset;
+    std::set<StructExternalSplit>       i_esplset;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podset);
+      iar(i_iserset);
+      iar(i_isplset);
+      iar(i_eserset);
+      iar(i_esplset);
+    }
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podset.begin(),    i_podset.end(),    o_podset.begin(),  o_podset.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserset.begin(),   i_iserset.end(),   o_iserset.begin(), o_iserset.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplset.begin(),   i_isplset.end(),   o_isplset.begin(), o_isplset.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserset.begin(),   i_eserset.end(),   o_eserset.begin(), o_eserset.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplset.begin(),   i_esplset.end(),   o_esplset.begin(), o_esplset.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_set )
+{
+  test_set<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_set )
+{
+  test_set<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_set )
+{
+  test_set<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_set )
+{
+  test_set<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/stack.cpp b/unittests/stack.cpp
new file mode 100644
index 0000000..edc0920
--- /dev/null
+++ b/unittests/stack.cpp
@@ -0,0 +1,125 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_stack()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::stack<int> o_podstack;
+    for(int j=0; j<100; ++j)
+      o_podstack.push(random_value<int>(gen));
+
+    std::stack<StructInternalSerialize> o_iserstack;
+    for(int j=0; j<100; ++j)
+      o_iserstack.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::stack<StructInternalSplit> o_isplstack;
+    for(int j=0; j<100; ++j)
+      o_isplstack.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::stack<StructExternalSerialize> o_eserstack;
+    for(int j=0; j<100; ++j)
+      o_eserstack.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::stack<StructExternalSplit> o_esplstack;
+    for(int j=0; j<100; ++j)
+      o_esplstack.push({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podstack);
+      oar(o_iserstack);
+      oar(o_isplstack);
+      oar(o_eserstack);
+      oar(o_esplstack);
+    }
+
+    std::stack<int> i_podstack;
+    std::stack<StructInternalSerialize> i_iserstack;
+    std::stack<StructInternalSplit>     i_isplstack;
+    std::stack<StructExternalSerialize> i_eserstack;
+    std::stack<StructExternalSplit>     i_esplstack;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podstack);
+      iar(i_iserstack);
+      iar(i_isplstack);
+      iar(i_eserstack);
+      iar(i_esplstack);
+    }
+
+    auto & i_podstack_c  = cereal::stack_detail::container(i_podstack);
+    auto & i_iserstack_c = cereal::stack_detail::container(i_iserstack);
+    auto & i_isplstack_c = cereal::stack_detail::container(i_isplstack);
+    auto & i_eserstack_c = cereal::stack_detail::container(i_eserstack);
+    auto & i_esplstack_c = cereal::stack_detail::container(i_esplstack);
+
+    auto & o_podstack_c  = cereal::stack_detail::container(o_podstack);
+    auto & o_iserstack_c = cereal::stack_detail::container(o_iserstack);
+    auto & o_isplstack_c = cereal::stack_detail::container(o_isplstack);
+    auto & o_eserstack_c = cereal::stack_detail::container(o_eserstack);
+    auto & o_esplstack_c = cereal::stack_detail::container(o_esplstack);
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podstack_c.begin(),    i_podstack_c.end(),    o_podstack_c.begin(),  o_podstack_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iserstack_c.begin(),   i_iserstack_c.end(),   o_iserstack_c.begin(), o_iserstack_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplstack_c.begin(),   i_isplstack_c.end(),   o_isplstack_c.begin(), o_isplstack_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eserstack_c.begin(),   i_eserstack_c.end(),   o_eserstack_c.begin(), o_eserstack_c.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplstack_c.begin(),   i_esplstack_c.end(),   o_esplstack_c.begin(), o_esplstack_c.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_stack )
+{
+  test_stack<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_stack )
+{
+  test_stack<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_stack )
+{
+  test_stack<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_stack )
+{
+  test_stack<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/structs.cpp b/unittests/structs.cpp
new file mode 100644
index 0000000..245e15d
--- /dev/null
+++ b/unittests/structs.cpp
@@ -0,0 +1,85 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_structs()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    StructInternalSerialize o_iser = { random_value<int>(gen), random_value<int>(gen) };
+    StructInternalSplit     o_ispl = { random_value<int>(gen), random_value<int>(gen) };
+    StructExternalSerialize o_eser = { random_value<int>(gen), random_value<int>(gen) };
+    StructExternalSplit     o_espl = { random_value<int>(gen), random_value<int>(gen) };
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar( o_iser, o_ispl, o_eser, o_espl);
+    }
+
+    StructInternalSerialize i_iser;
+    StructInternalSplit     i_ispl;
+    StructExternalSerialize i_eser;
+    StructExternalSplit     i_espl;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+      iar( i_iser, i_ispl, i_eser, i_espl);
+    }
+
+    BOOST_CHECK(i_iser == o_iser);
+    BOOST_CHECK(i_ispl == o_ispl);
+    BOOST_CHECK(i_eser == o_eser);
+    BOOST_CHECK(i_espl == o_espl);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_structs )
+{
+  test_structs<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_structs )
+{
+  test_structs<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_structs )
+{
+  test_structs<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_structs )
+{
+  test_structs<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/structs_minimal.cpp b/unittests/structs_minimal.cpp
new file mode 100644
index 0000000..877c65f
--- /dev/null
+++ b/unittests/structs_minimal.cpp
@@ -0,0 +1,271 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+class MemberMinimal
+{
+  public:
+    MemberMinimal() = default;
+    MemberMinimal( std::string const & str ) : x( str ) {}
+
+  protected:
+    friend class cereal::access;
+
+    template <class Archive>
+    std::string save_minimal( Archive const & ) const
+    {
+      return x;
+    }
+
+    template <class Archive>
+    void load_minimal( Archive const &, std::string const & str )
+    {
+      x = str;
+    }
+
+  public:
+    std::string x;
+};
+
+class MemberMinimalVersioned
+{
+  public:
+    MemberMinimalVersioned() = default;
+    MemberMinimalVersioned( double d ) : x( d ) {}
+
+  protected:
+    friend class cereal::access;
+
+    template <class Archive>
+    double save_minimal( Archive const &, const std::uint32_t ) const
+    {
+      return x;
+    }
+
+    template <class Archive>
+    void load_minimal( Archive const &, double const & d, const std::uint32_t )
+    {
+      x = d;
+    }
+
+  public:
+    double x;
+};
+
+struct NonMemberMinimal
+{
+  NonMemberMinimal() = default;
+  NonMemberMinimal( std::uint32_t xx ) : x(xx) {}
+  std::uint32_t x;
+};
+
+template <class Archive>
+std::uint32_t save_minimal( Archive const &, NonMemberMinimal const & nmm )
+{
+  return nmm.x;
+}
+
+template <class Archive>
+void load_minimal( Archive const &, NonMemberMinimal & nmm, std::uint32_t const & data )
+{
+  nmm.x = data;
+}
+
+struct NonMemberMinimalVersioned
+{
+  NonMemberMinimalVersioned() = default;
+  NonMemberMinimalVersioned( bool xx ) : x(xx) {}
+  bool x;
+};
+
+template <class Archive>
+bool save_minimal( Archive const &, NonMemberMinimalVersioned const & nmm, std::uint32_t const )
+{
+  return nmm.x;
+}
+
+template <class Archive>
+void load_minimal( Archive const &, NonMemberMinimalVersioned & nmm, bool const & data, std::uint32_t const )
+{
+  nmm.x = data;
+}
+
+struct TestStruct
+{
+  TestStruct() = default;
+  TestStruct( std::string const & s, double d, std::uint32_t u, bool b ) :
+    mm(s), mmv(d), nmm(u), nmmv(b) {}
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( mm, mmv );
+    ar( nmm, nmmv );
+  }
+
+  MemberMinimal mm;
+  MemberMinimalVersioned mmv;
+  NonMemberMinimal nmm;
+  NonMemberMinimalVersioned nmmv;
+};
+
+struct Issue79Struct
+{
+  Issue79Struct() = default;
+  Issue79Struct( std::int32_t xx ) : x(xx) {}
+  std::int32_t x;
+};
+
+template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
+                                                   std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
+std::string save_minimal( Archive const &, Issue79Struct const & val )
+{
+  return std::to_string( val.x );
+}
+
+template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
+                                                   std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
+void load_minimal( Archive const &, Issue79Struct & val, std::string const & str )
+{
+  val.x = std::stoi( str );
+}
+
+template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
+                                                  std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
+std::int32_t save_minimal( Archive const &, Issue79Struct const & val )
+{
+  return val.x;
+}
+
+template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
+                                                  std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
+void load_minimal( Archive const &, Issue79Struct & val, std::int32_t const & xx )
+{
+  val.x = xx;
+}
+
+struct Issue79StructInternal
+{
+  Issue79StructInternal() = default;
+  Issue79StructInternal( std::int32_t xx ) : x(xx) {}
+  std::int32_t x;
+
+  template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
+                                                     std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
+  std::string save_minimal( Archive const & ) const
+  {
+    return std::to_string( x );
+  }
+
+  template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
+                                                     std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
+  void load_minimal( Archive const &, std::string const & str )
+  {
+    x = std::stoi( str );
+  }
+
+  template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
+                                                    std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
+  std::int32_t save_minimal( Archive const & ) const
+  {
+    return x;
+  }
+
+  template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
+                                                    std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
+  void load_minimal( Archive const &, std::int32_t const & xx )
+  {
+    x = xx;
+  }
+};
+
+template <class IArchive, class OArchive>
+void test_structs_minimal()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    TestStruct o_struct = { random_basic_string<char>(gen), random_value<double>(gen),
+                            random_value<std::uint32_t>(gen), random_value<uint8_t>(gen) % 2 ? true : false };
+
+    Issue79Struct o_struct2 = { random_value<std::int32_t>(gen) };
+    Issue79StructInternal o_struct3 = { random_value<std::int32_t>(gen) };
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar( o_struct );
+      oar( o_struct2 );
+      oar( o_struct3 );
+    }
+
+    decltype(o_struct) i_struct;
+    decltype(o_struct2) i_struct2;
+    decltype(o_struct3) i_struct3;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+      iar( i_struct );
+      iar( i_struct2 );
+      iar( i_struct3 );
+    }
+
+    BOOST_CHECK(o_struct.mm.x == i_struct.mm.x);
+    BOOST_CHECK_CLOSE(o_struct.mmv.x, i_struct.mmv.x, 1e-5);
+
+    BOOST_CHECK(o_struct.nmm.x == i_struct.nmm.x);
+    BOOST_CHECK(o_struct.nmmv.x == i_struct.nmmv.x);
+
+    BOOST_CHECK(o_struct2.x == i_struct2.x);
+
+    BOOST_CHECK(o_struct3.x == i_struct3.x);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_structs_minimal )
+{
+  test_structs_minimal<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_structs_minimal )
+{
+  test_structs_minimal<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_structs_minimal )
+{
+  test_structs_minimal<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_structs_minimal )
+{
+  test_structs_minimal<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/structs_specialized.cpp b/unittests/structs_specialized.cpp
new file mode 100644
index 0000000..bb26e67
--- /dev/null
+++ b/unittests/structs_specialized.cpp
@@ -0,0 +1,478 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+struct BogusBase
+{
+  template <class Archive>
+  void serialize( Archive & ) {}
+
+  template <class Archive>
+  void save( Archive & ) const {}
+
+  template <class Archive>
+  void load( Archive & ) {}
+
+  template <class Archive>
+  int save_minimal( Archive const & ) const { return 0; }
+
+  template <class Archive>
+  void load_minimal( Archive const &, int const & ) {}
+};
+
+struct BogusBaseVersioned
+{
+  template <class Archive>
+  void serialize( Archive &, const std::uint32_t ) {}
+
+  template <class Archive>
+  void save( Archive &, const std::uint32_t ) const {}
+
+  template <class Archive>
+  void load( Archive &, const std::uint32_t ) {}
+
+  template <class Archive>
+  int save_minimal( Archive const &, const std::uint32_t ) const { return 0; }
+
+  template <class Archive>
+  void load_minimal( Archive const &, int const &, const std::uint32_t ) {}
+};
+
+struct BogusBasePolymorphic
+{
+  template <class Archive>
+  void serialize( Archive & ) {}
+
+  virtual void doesNothing() {}
+};
+
+class SpecializedMSerialize : public BogusBase
+{
+  public:
+    SpecializedMSerialize() = default;
+    SpecializedMSerialize( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void serialize( Archive & ar )
+    {
+      ar( x );
+    }
+};
+
+class SpecializedMSerializeVersioned : public BogusBaseVersioned
+{
+  public:
+    SpecializedMSerializeVersioned() = default;
+    SpecializedMSerializeVersioned( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void serialize( Archive & ar, const std::uint32_t )
+    {
+      ar( x );
+    }
+};
+
+class SpecializedMSplit : public BogusBase
+{
+  public:
+    SpecializedMSplit() = default;
+    SpecializedMSplit( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void save( Archive & ar ) const
+    {
+      ar( x );
+    }
+
+    template <class Archive>
+    void load( Archive & ar )
+    {
+      ar( x );
+    }
+};
+
+class SpecializedMSplitVersioned : public BogusBaseVersioned
+{
+  public:
+    SpecializedMSplitVersioned() = default;
+    SpecializedMSplitVersioned( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void save( Archive & ar, const std::uint32_t ) const
+    {
+      ar( x );
+    }
+
+    template <class Archive>
+    void load( Archive & ar, const std::uint32_t )
+    {
+      ar( x );
+    }
+};
+
+class SpecializedMSplitPolymorphic : public BogusBasePolymorphic
+{
+  public:
+    SpecializedMSplitPolymorphic() = default;
+    SpecializedMSplitPolymorphic( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void save( Archive & ar ) const
+    {
+      ar( x );
+    }
+
+    template <class Archive>
+    void load( Archive & ar )
+    {
+      ar( x );
+    }
+};
+
+class SpecializedMSplitMinimal : public BogusBase
+{
+  public:
+    SpecializedMSplitMinimal() = default;
+    SpecializedMSplitMinimal( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    int save_minimal( Archive const & ) const
+    {
+      return x;
+    }
+
+    template <class Archive>
+    void load_minimal( Archive const &, int const & value )
+    {
+      x = value;
+    }
+};
+
+class SpecializedMSplitVersionedMinimal : public BogusBaseVersioned
+{
+  public:
+    SpecializedMSplitVersionedMinimal() = default;
+    SpecializedMSplitVersionedMinimal( int xx ) : x(xx) {}
+
+    int x;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    int save_minimal( Archive const &, const std::uint32_t ) const
+    {
+      return x;
+    }
+
+    template <class Archive>
+    void load_minimal( Archive const &, int const & value, const std::uint32_t )
+    {
+      x = value;
+    }
+};
+
+class SpecializedNMSerialize : public BogusBase
+{
+  public:
+    SpecializedNMSerialize() = default;
+    SpecializedNMSerialize( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void serialize( Archive & ar, SpecializedNMSerialize & s )
+{
+  ar( s.x );
+}
+
+class SpecializedNMSerializeVersioned : public BogusBaseVersioned
+{
+  public:
+    SpecializedNMSerializeVersioned() = default;
+    SpecializedNMSerializeVersioned( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void serialize( Archive & ar, SpecializedNMSerializeVersioned & s )
+{
+  ar( s.x );
+}
+
+class SpecializedNMSplit : public BogusBase
+{
+  public:
+    SpecializedNMSplit() = default;
+    SpecializedNMSplit( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void load( Archive & ar, SpecializedNMSplit & s )
+{
+  ar( s.x );
+}
+
+template <class Archive>
+void save( Archive & ar, SpecializedNMSplit const & s )
+{
+  ar( s.x );
+}
+
+class SpecializedNMSplitVersioned : public BogusBaseVersioned
+{
+  public:
+    SpecializedNMSplitVersioned() = default;
+    SpecializedNMSplitVersioned( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void load( Archive & ar, SpecializedNMSplitVersioned & s, const std::uint32_t )
+{
+  ar( s.x );
+}
+
+template <class Archive>
+void save( Archive & ar, SpecializedNMSplitVersioned const & s, const std::uint32_t )
+{
+  ar( s.x );
+}
+
+class SpecializedNMSplitMinimal : public BogusBase
+{
+  public:
+    SpecializedNMSplitMinimal() = default;
+    SpecializedNMSplitMinimal( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void load_minimal( Archive const &, SpecializedNMSplitMinimal & s, int const & value )
+{
+  s.x = value;
+}
+
+template <class Archive>
+int save_minimal( Archive const &, SpecializedNMSplitMinimal const & s )
+{
+  return s.x;
+}
+
+class SpecializedNMSplitVersionedMinimal : public BogusBaseVersioned
+{
+  public:
+    SpecializedNMSplitVersionedMinimal() = default;
+    SpecializedNMSplitVersionedMinimal( int xx ) : x(xx) {}
+
+    int x;
+};
+
+template <class Archive>
+void load_minimal( Archive const &, SpecializedNMSplitVersionedMinimal & s, int const & value, const std::uint32_t )
+{
+  s.x = value;
+}
+
+template <class Archive>
+int save_minimal( Archive const &, SpecializedNMSplitVersionedMinimal const & s, const std::uint32_t )
+{
+  return s.x;
+}
+
+namespace cereal
+{
+  template <class Archive> struct specialize<Archive, SpecializedMSerialize, cereal::specialization::member_serialize> {};
+  template <class Archive> struct specialize<Archive, SpecializedMSerializeVersioned, cereal::specialization::member_serialize> {};
+
+  template <class Archive> struct specialize<Archive, SpecializedMSplit, cereal::specialization::member_load_save> {};
+  template <class Archive> struct specialize<Archive, SpecializedMSplitVersioned, cereal::specialization::member_load_save> {};
+  template <class Archive> struct specialize<Archive, SpecializedMSplitPolymorphic, cereal::specialization::member_load_save> {};
+
+  template <class Archive> struct specialize<Archive, SpecializedMSplitMinimal, cereal::specialization::member_load_save_minimal> {};
+  template <class Archive> struct specialize<Archive, SpecializedMSplitVersionedMinimal, cereal::specialization::member_load_save_minimal> {};
+
+  template <class Archive> struct specialize<Archive, SpecializedNMSerialize, cereal::specialization::non_member_serialize> {};
+  template <class Archive> struct specialize<Archive, SpecializedNMSerializeVersioned, cereal::specialization::non_member_serialize> {};
+
+  template <class Archive> struct specialize<Archive, SpecializedNMSplit, cereal::specialization::non_member_load_save> {};
+  template <class Archive> struct specialize<Archive, SpecializedNMSplitVersioned, cereal::specialization::non_member_load_save> {};
+
+  template <class Archive> struct specialize<Archive, SpecializedNMSplitMinimal,
+           cereal::specialization::non_member_load_save_minimal> {};
+  template <class Archive> struct specialize<Archive, SpecializedNMSplitVersionedMinimal,
+           cereal::specialization::non_member_load_save_minimal> {};
+}
+
+CEREAL_REGISTER_TYPE(SpecializedMSplitPolymorphic)
+
+template <class IArchive, class OArchive>
+void test_structs_specialized()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    SpecializedMSerialize               o_iser          = { random_value<int>(gen) };
+    SpecializedMSerializeVersioned      o_iserv         = { random_value<int>(gen) };
+
+    SpecializedMSplit                   o_ispl          = { random_value<int>(gen) };
+    SpecializedMSplitVersioned          o_isplv         = { random_value<int>(gen) };
+
+    // added re: issue #180
+    std::shared_ptr<BogusBasePolymorphic> o_shared_ispl = std::make_shared<SpecializedMSplitPolymorphic>( random_value<int>(gen) );
+
+    SpecializedMSplitMinimal            o_isplm         = { random_value<int>(gen) };
+    SpecializedMSplitVersionedMinimal   o_isplvm        = { random_value<int>(gen) };
+
+    SpecializedNMSerialize              o_eser          = { random_value<int>(gen) };
+    SpecializedNMSerializeVersioned     o_eserv         = { random_value<int>(gen) };
+
+    SpecializedNMSplit                  o_espl          = { random_value<int>(gen) };
+    SpecializedNMSplitVersioned         o_esplv         = { random_value<int>(gen) };
+
+    SpecializedNMSplitMinimal           o_esplm         = { random_value<int>(gen) };
+    SpecializedNMSplitVersionedMinimal  o_esplvm        = { random_value<int>(gen) };
+
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( o_iser, o_iserv,
+           o_ispl, o_isplv, o_shared_ispl,
+           o_isplm, o_isplvm,
+           o_eser, o_eserv,
+           o_espl, o_esplv,
+           o_esplm, o_esplvm );
+    }
+
+    decltype(o_iser) i_iser;
+    decltype(o_iserv) i_iserv;
+
+    decltype(o_ispl) i_ispl;
+    decltype(o_isplv) i_isplv;
+
+    decltype(o_shared_ispl) i_shared_ispl;
+
+    decltype(o_isplm) i_isplm;
+    decltype(o_isplvm) i_isplvm;
+
+    decltype(o_eser) i_eser;
+    decltype(o_eserv) i_eserv;
+
+    decltype(o_espl) i_espl;
+    decltype(o_esplv) i_esplv;
+
+    decltype(o_esplm) i_esplm;
+    decltype(o_esplvm) i_esplvm;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( i_iser, i_iserv,
+           i_ispl, i_isplv, i_shared_ispl,
+           i_isplm, i_isplvm,
+           i_eser, i_eserv,
+           i_espl, i_esplv,
+           i_esplm, i_esplvm );
+    }
+
+    BOOST_CHECK(i_iser.x == o_iser.x);
+    BOOST_CHECK(i_iserv.x == o_iserv.x);
+
+    BOOST_CHECK(i_ispl.x == o_ispl.x);
+    BOOST_CHECK(i_isplv.x == o_isplv.x);
+
+    BOOST_CHECK_EQUAL(((SpecializedMSplitPolymorphic*)i_shared_ispl.get())->x, ((SpecializedMSplitPolymorphic*)o_shared_ispl.get())->x);
+
+    BOOST_CHECK(i_isplm.x == o_isplm.x);
+    BOOST_CHECK(i_isplvm.x == o_isplvm.x);
+
+    BOOST_CHECK(i_eser.x == o_eser.x);
+    BOOST_CHECK(i_eserv.x == o_eserv.x);
+
+    BOOST_CHECK(i_espl.x == o_espl.x);
+    BOOST_CHECK(i_esplv.x == o_esplv.x);
+
+    BOOST_CHECK(i_esplm.x == o_esplm.x);
+    BOOST_CHECK(i_esplvm.x == o_esplvm.x);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_structs_specialized )
+{
+  test_structs_specialized<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_structs_specialized )
+{
+  test_structs_specialized<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_structs_specialized )
+{
+  test_structs_specialized<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_structs_specialized )
+{
+  test_structs_specialized<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/tuple.cpp b/unittests/tuple.cpp
new file mode 100644
index 0000000..973b1a1
--- /dev/null
+++ b/unittests/tuple.cpp
@@ -0,0 +1,119 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_tuple()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rng = [&](){ return random_value<int>(gen); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    auto o_podtuple = std::make_tuple( rng(), rng(), rng(), rng() );
+    auto o_podtuple11 = std::make_tuple( rng(), rng(), rng(), rng(), rng(), rng(),
+                                         rng(), rng(), rng(), rng(), rng() );
+    auto o_isertuple = std::make_tuple( StructInternalSerialize( rng(), rng() ),
+        StructInternalSerialize( rng(), rng() ),
+        StructInternalSerialize( rng(), rng() ),
+        StructInternalSerialize( rng(), rng() ) );
+    auto o_ispltuple = std::make_tuple( StructInternalSplit( rng(), rng() ),
+        StructInternalSplit( rng(), rng() ),
+        StructInternalSplit( rng(), rng() ),
+        StructInternalSplit( rng(), rng() ) );
+    auto o_esertuple = std::make_tuple( StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ) );
+    auto o_espltuple = std::make_tuple( StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ),
+        StructExternalSerialize( rng(), rng() ) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podtuple);
+      oar(o_podtuple11);
+      oar(o_isertuple);
+      oar(o_ispltuple);
+      oar(o_esertuple);
+      oar(o_espltuple);
+    }
+
+    decltype( o_podtuple   ) i_podtuple;
+    decltype( o_podtuple11 ) i_podtuple11;
+    decltype( o_isertuple  ) i_isertuple;
+    decltype( o_ispltuple  ) i_ispltuple;
+    decltype( o_esertuple  ) i_esertuple;
+    decltype( o_espltuple  ) i_espltuple;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podtuple);
+      iar(i_podtuple11);
+      iar(i_isertuple);
+      iar(i_ispltuple);
+      iar(i_esertuple);
+      iar(i_espltuple);
+    }
+
+    BOOST_CHECK_EQUAL( i_podtuple   == o_podtuple,   true );
+    BOOST_CHECK_EQUAL( i_podtuple11 == o_podtuple11, true );
+    BOOST_CHECK_EQUAL( i_isertuple  == o_isertuple,  true );
+    BOOST_CHECK_EQUAL( i_ispltuple  == o_ispltuple,  true );
+    BOOST_CHECK_EQUAL( i_esertuple  == o_esertuple,  true );
+    BOOST_CHECK_EQUAL( i_espltuple  == o_espltuple,  true );
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_tuple )
+{
+  test_tuple<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_tuple )
+{
+  test_tuple<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_tuple )
+{
+  test_tuple<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_tuple )
+{
+  test_tuple<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/unordered_loads.cpp b/unittests/unordered_loads.cpp
new file mode 100644
index 0000000..4357b67
--- /dev/null
+++ b/unittests/unordered_loads.cpp
@@ -0,0 +1,157 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+struct unordered_naming
+{
+  int x;
+  int xx;
+  int y;
+  int z;
+
+  template <class Archive>
+  void save( Archive & ar ) const
+  {
+    ar( CEREAL_NVP(x),
+        CEREAL_NVP(z),
+        CEREAL_NVP(y),
+        CEREAL_NVP(xx) );
+  }
+
+  template <class Archive>
+  void load( Archive & ar )
+  {
+    ar( x,
+        CEREAL_NVP(y),
+        CEREAL_NVP(z),
+        CEREAL_NVP(xx) );
+  }
+
+  bool operator==( unordered_naming const & other ) const
+  {
+    return x == other.x && xx == other.xx && y == other.y && z == other.z;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, unordered_naming const & s)
+{
+  os << "[x: " << s.x << " xx: " << s.xx << " y: " << s.y << " z: " << s.z << "]";
+  return os;
+}
+
+template <class IArchive, class OArchive>
+void test_unordered_loads()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rngB = [&](){ return random_value<int>( gen ) % 2 == 0; };
+  auto rngI = [&](){ return random_value<int>( gen ); };
+  auto rngF = [&](){ return random_value<float>( gen ); };
+  auto rngD = [&](){ return random_value<double>( gen ); };
+  auto rngS = [&](){ return random_basic_string<char>( gen ); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    auto const name1 = rngS();
+    auto const name2 = rngS();
+    auto const name3 = rngS();
+    auto const name4 = rngS();
+    auto const name5 = rngS();
+    auto const name6 = rngS();
+    auto const name7 = rngS();
+
+    int o_int1 = rngI();
+    double o_double2 = rngD();
+    std::vector<bool> o_vecbool3 = { rngB(), rngB(), rngB(), rngB(), rngB() };
+    int o_int4 = rngI();
+    int o_int5 = rngI();
+    int o_int6 = rngI();
+    std::pair<float, unordered_naming> o_un7;
+    o_un7.first = rngF();
+    o_un7.second.x = rngI();
+    o_un7.second.xx = rngI();
+    o_un7.second.y = rngI();
+    o_un7.second.z = rngI();
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar( cereal::make_nvp( name1, o_int1 ),
+           cereal::make_nvp( name2, o_double2 ),
+           cereal::make_nvp( name3, o_vecbool3 ),
+           cereal::make_nvp( name4, o_int4 ),
+           cereal::make_nvp( name5, o_int5 ),
+           cereal::make_nvp( name6, o_int6 ),
+           cereal::make_nvp( name7, o_un7 ) );
+    }
+
+    decltype(o_int1) i_int1;
+    decltype(o_double2) i_double2;
+    decltype(o_vecbool3) i_vecbool3;
+    decltype(o_int4) i_int4;
+    decltype(o_int5) i_int5;
+    decltype(o_int6) i_int6;
+    decltype(o_un7) i_un7;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar( cereal::make_nvp( name7, i_un7 ),
+           cereal::make_nvp( name2, i_double2 ),
+           cereal::make_nvp( name4, i_int4 ),
+           cereal::make_nvp( name3, i_vecbool3 ),
+           cereal::make_nvp( name1, i_int1 ),
+           cereal::make_nvp( name5, i_int5 ),
+           i_int6 );
+    }
+
+    BOOST_CHECK_EQUAL(o_int1, i_int1);
+    BOOST_CHECK_CLOSE(o_double2 , o_double2, 1e-5);
+    BOOST_CHECK_EQUAL(o_vecbool3.size(), i_vecbool3.size());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_vecbool3.begin(),    i_vecbool3.end(),    o_vecbool3.begin(),  o_vecbool3.end());
+    BOOST_CHECK_EQUAL(o_int4, i_int4);
+    BOOST_CHECK_EQUAL(o_int5, i_int5);
+    BOOST_CHECK_EQUAL(o_int6, i_int6);
+    BOOST_CHECK_EQUAL(o_un7.first, i_un7.first);
+    BOOST_CHECK_EQUAL(o_un7.second, i_un7.second);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( xml_unordered_loads )
+{
+  test_unordered_loads<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_unordered_loads )
+{
+  test_unordered_loads<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/unordered_map.cpp b/unittests/unordered_map.cpp
new file mode 100644
index 0000000..df81833
--- /dev/null
+++ b/unittests/unordered_map.cpp
@@ -0,0 +1,142 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_unordered_map()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::unordered_map<std::string, int> o_podunordered_map;
+    for(int j=0; j<100; ++j)
+      o_podunordered_map.insert({random_value<std::string>(gen), random_value<int>(gen)});
+
+    std::unordered_map<uint16_t, StructInternalSerialize> o_iserunordered_map;
+    for(int j=0; j<100; ++j)
+      o_iserunordered_map.insert({random_value<uint16_t>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::unordered_map<uint16_t, StructInternalSplit> o_isplunordered_map;
+    for(int j=0; j<100; ++j)
+      o_isplunordered_map.insert({random_value<uint16_t>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::unordered_map<uint32_t, StructExternalSerialize> o_eserunordered_map;
+    for(int j=0; j<100; ++j)
+      o_eserunordered_map.insert({random_value<uint32_t>(gen), { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::unordered_map<int8_t, StructExternalSplit> o_esplunordered_map;
+    for(int j=0; j<100; ++j)
+      o_esplunordered_map.insert({random_value<char>(gen),  { random_value<int>(gen), random_value<int>(gen) }});
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podunordered_map);
+      oar(o_iserunordered_map);
+      oar(o_isplunordered_map);
+      oar(o_eserunordered_map);
+      oar(o_esplunordered_map);
+    }
+
+    std::unordered_map<std::string, int> i_podunordered_map;
+    std::unordered_map<uint16_t, StructInternalSerialize>   i_iserunordered_map;
+    std::unordered_map<uint16_t, StructInternalSplit>        i_isplunordered_map;
+    std::unordered_map<uint32_t, StructExternalSerialize> i_eserunordered_map;
+    std::unordered_map<int8_t, StructExternalSplit>       i_esplunordered_map;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podunordered_map);
+      iar(i_iserunordered_map);
+      iar(i_isplunordered_map);
+      iar(i_eserunordered_map);
+      iar(i_esplunordered_map);
+    }
+
+    for(auto const & p : i_podunordered_map)
+    {
+      auto v = o_podunordered_map.find(p.first);
+      BOOST_CHECK(v != o_podunordered_map.end());
+      BOOST_CHECK_EQUAL(p.second, v->second);
+    }
+
+    for(auto const & p : i_iserunordered_map)
+    {
+      auto v = o_iserunordered_map.find(p.first);
+      BOOST_CHECK(v != o_iserunordered_map.end());
+      BOOST_CHECK_EQUAL(p.second, v->second);
+    }
+
+    for(auto const & p : i_isplunordered_map)
+    {
+      auto v = o_isplunordered_map.find(p.first);
+      BOOST_CHECK(v != o_isplunordered_map.end());
+      BOOST_CHECK_EQUAL(p.second, v->second);
+    }
+
+    for(auto const & p : i_eserunordered_map)
+    {
+      auto v = o_eserunordered_map.find(p.first);
+      BOOST_CHECK(v != o_eserunordered_map.end());
+      BOOST_CHECK_EQUAL(p.second, v->second);
+    }
+
+    for(auto const & p : i_esplunordered_map)
+    {
+      auto v = o_esplunordered_map.find(p.first);
+      BOOST_CHECK(v != o_esplunordered_map.end());
+      BOOST_CHECK_EQUAL(p.second, v->second);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_unordered_map )
+{
+  test_unordered_map<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_unordered_map )
+{
+  test_unordered_map<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_unordered_map )
+{
+  test_unordered_map<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_unordered_map )
+{
+  test_unordered_map<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/unordered_multimap.cpp b/unittests/unordered_multimap.cpp
new file mode 100644
index 0000000..ad0913d
--- /dev/null
+++ b/unittests/unordered_multimap.cpp
@@ -0,0 +1,172 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_unordered_multimap()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::unordered_multimap<std::string, int> o_podunordered_multimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<std::string>(gen);
+      o_podunordered_multimap.insert({key, random_value<int>(gen)});
+      o_podunordered_multimap.insert({key, random_value<int>(gen)});
+    }
+
+    std::unordered_multimap<int, StructInternalSerialize> o_iserunordered_multimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<int>(gen);
+      o_iserunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_iserunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::unordered_multimap<int, StructInternalSplit> o_isplunordered_multimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<int>(gen);
+      o_isplunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_isplunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::unordered_multimap<uint32_t, StructExternalSerialize> o_eserunordered_multimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<uint32_t>(gen);
+      o_eserunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+      o_eserunordered_multimap.insert({key, { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::unordered_multimap<int8_t, StructExternalSplit> o_esplunordered_multimap;
+    for(int j=0; j<100; ++j)
+    {
+      auto key = random_value<char>(gen);
+      o_esplunordered_multimap.insert({key,  { random_value<int>(gen), random_value<int>(gen) }});
+      o_esplunordered_multimap.insert({key,  { random_value<int>(gen), random_value<int>(gen) }});
+    }
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podunordered_multimap);
+      oar(o_iserunordered_multimap);
+      oar(o_isplunordered_multimap);
+      oar(o_eserunordered_multimap);
+      oar(o_esplunordered_multimap);
+    }
+
+    std::unordered_multimap<std::string, int> i_podunordered_multimap;
+    std::unordered_multimap<int, StructInternalSerialize>   i_iserunordered_multimap;
+    std::unordered_multimap<int, StructInternalSplit>        i_isplunordered_multimap;
+    std::unordered_multimap<uint32_t, StructExternalSerialize> i_eserunordered_multimap;
+    std::unordered_multimap<int8_t, StructExternalSplit>       i_esplunordered_multimap;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podunordered_multimap);
+      iar(i_iserunordered_multimap);
+      iar(i_isplunordered_multimap);
+      iar(i_eserunordered_multimap);
+      iar(i_esplunordered_multimap);
+    }
+
+    BOOST_CHECK_EQUAL(i_podunordered_multimap.size(),  o_podunordered_multimap.size());
+    BOOST_CHECK_EQUAL(i_iserunordered_multimap.size(), o_iserunordered_multimap.size());
+    BOOST_CHECK_EQUAL(i_isplunordered_multimap.size(), o_isplunordered_multimap.size());
+    BOOST_CHECK_EQUAL(i_eserunordered_multimap.size(), o_eserunordered_multimap.size());
+    BOOST_CHECK_EQUAL(i_esplunordered_multimap.size(), o_esplunordered_multimap.size());
+
+    for(auto const & p : i_podunordered_multimap)
+    {
+      size_t const bucket = o_podunordered_multimap.bucket(p.first);
+      auto bucket_begin   = o_podunordered_multimap.begin(bucket);
+      auto bucket_end     = o_podunordered_multimap.end(bucket);
+      BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end);
+    }
+
+    for(auto const & p : i_iserunordered_multimap)
+    {
+      size_t const bucket = o_iserunordered_multimap.bucket(p.first);
+      auto bucket_begin   = o_iserunordered_multimap.begin(bucket);
+      auto bucket_end     = o_iserunordered_multimap.end(bucket);
+      BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end);
+    }
+
+    for(auto const & p : i_isplunordered_multimap)
+    {
+      size_t const bucket = o_isplunordered_multimap.bucket(p.first);
+      auto bucket_begin   = o_isplunordered_multimap.begin(bucket);
+      auto bucket_end     = o_isplunordered_multimap.end(bucket);
+      BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end);
+    }
+
+    for(auto const & p : i_eserunordered_multimap)
+    {
+      size_t const bucket = o_eserunordered_multimap.bucket(p.first);
+      auto bucket_begin   = o_eserunordered_multimap.begin(bucket);
+      auto bucket_end     = o_eserunordered_multimap.end(bucket);
+      BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end);
+    }
+
+    for(auto const & p : i_esplunordered_multimap)
+    {
+      size_t const bucket = o_esplunordered_multimap.bucket(p.first);
+      auto bucket_begin   = o_esplunordered_multimap.begin(bucket);
+      auto bucket_end     = o_esplunordered_multimap.end(bucket);
+      BOOST_CHECK(std::find(bucket_begin, bucket_end, p) != bucket_end);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_unordered_multimap )
+{
+  test_unordered_multimap<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_unordered_multimap )
+{
+  test_unordered_multimap<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_unordered_multimap )
+{
+  test_unordered_multimap<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_unordered_multimap )
+{
+  test_unordered_multimap<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/unordered_multiset.cpp b/unittests/unordered_multiset.cpp
new file mode 100644
index 0000000..9e7a56d
--- /dev/null
+++ b/unittests/unordered_multiset.cpp
@@ -0,0 +1,152 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_unordered_multiset()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::unordered_multiset<int> o_podunordered_multiset;
+    for(int j=0; j<100; ++j)
+    {
+      int value = random_value<int>(gen);
+      o_podunordered_multiset.insert(value);
+      o_podunordered_multiset.insert(value);
+    }
+
+    std::unordered_multiset<StructInternalSerialize, StructHash<StructInternalSerialize>> o_iserunordered_multiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructInternalSerialize value = { random_value<int>(gen), random_value<int>(gen) };
+      o_iserunordered_multiset.insert(value);
+      o_iserunordered_multiset.insert(value);
+    }
+
+    std::unordered_multiset<StructInternalSplit, StructHash<StructInternalSplit>> o_isplunordered_multiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructInternalSplit value = { random_value<int>(gen), random_value<int>(gen) };
+      o_isplunordered_multiset.insert(value);
+      o_isplunordered_multiset.insert(value);
+    }
+
+    std::unordered_multiset<StructExternalSerialize, StructHash<StructExternalSerialize>> o_eserunordered_multiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructExternalSerialize value = { random_value<int>(gen), random_value<int>(gen) };
+      o_eserunordered_multiset.insert(value);
+      o_eserunordered_multiset.insert(value);
+    }
+
+    std::unordered_multiset<StructExternalSplit, StructHash<StructExternalSplit>> o_esplunordered_multiset;
+    for(int j=0; j<100; ++j)
+    {
+      StructExternalSplit value = { random_value<int>(gen), random_value<int>(gen) };
+      o_esplunordered_multiset.insert(value);
+      o_esplunordered_multiset.insert(value);
+    }
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podunordered_multiset);
+      oar(o_iserunordered_multiset);
+      oar(o_isplunordered_multiset);
+      oar(o_eserunordered_multiset);
+      oar(o_esplunordered_multiset);
+    }
+
+    std::unordered_multiset<int> i_podunordered_multiset;
+    std::unordered_multiset<StructInternalSerialize, StructHash<StructInternalSerialize>> i_iserunordered_multiset;
+    std::unordered_multiset<StructInternalSplit, StructHash<StructInternalSplit>>         i_isplunordered_multiset;
+    std::unordered_multiset<StructExternalSerialize, StructHash<StructExternalSerialize>> i_eserunordered_multiset;
+    std::unordered_multiset<StructExternalSplit, StructHash<StructExternalSplit>>         i_esplunordered_multiset;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podunordered_multiset);
+      iar(i_iserunordered_multiset);
+      iar(i_isplunordered_multiset);
+      iar(i_eserunordered_multiset);
+      iar(i_esplunordered_multiset);
+    }
+
+    for(auto const & p : i_podunordered_multiset)
+    {
+      BOOST_CHECK_EQUAL(o_podunordered_multiset.count(p), i_podunordered_multiset.count(p));
+    }
+
+    for(auto const & p : i_iserunordered_multiset)
+    {
+      BOOST_CHECK_EQUAL(o_iserunordered_multiset.count(p), i_iserunordered_multiset.count(p));
+    }
+
+    for(auto const & p : i_isplunordered_multiset)
+    {
+      BOOST_CHECK_EQUAL(o_isplunordered_multiset.count(p), i_isplunordered_multiset.count(p));
+    }
+
+    for(auto const & p : i_eserunordered_multiset)
+    {
+      BOOST_CHECK_EQUAL(o_eserunordered_multiset.count(p), i_eserunordered_multiset.count(p));
+    }
+
+    for(auto const & p : i_esplunordered_multiset)
+    {
+      BOOST_CHECK_EQUAL(o_esplunordered_multiset.count(p), i_esplunordered_multiset.count(p));
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_unordered_multiset )
+{
+  test_unordered_multiset<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_unordered_multiset )
+{
+  test_unordered_multiset<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_unordered_multiset )
+{
+  test_unordered_multiset<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_unordered_multiset )
+{
+  test_unordered_multiset<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/unordered_set.cpp b/unittests/unordered_set.cpp
new file mode 100644
index 0000000..64f9618
--- /dev/null
+++ b/unittests/unordered_set.cpp
@@ -0,0 +1,133 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_unordered_set()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::unordered_set<int> o_podunordered_set;
+    for(int j=0; j<100; ++j)
+      o_podunordered_set.insert(random_value<int>(gen));
+
+    std::unordered_set<StructInternalSerialize, StructHash<StructInternalSerialize>> o_iserunordered_set;
+    for(int j=0; j<100; ++j)
+      o_iserunordered_set.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::unordered_set<StructInternalSplit, StructHash<StructInternalSplit>> o_isplunordered_set;
+    for(int j=0; j<100; ++j)
+      o_isplunordered_set.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::unordered_set<StructExternalSerialize, StructHash<StructExternalSerialize>> o_eserunordered_set;
+    for(int j=0; j<100; ++j)
+      o_eserunordered_set.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::unordered_set<StructExternalSplit, StructHash<StructExternalSplit>> o_esplunordered_set;
+    for(int j=0; j<100; ++j)
+      o_esplunordered_set.insert({ random_value<int>(gen), random_value<int>(gen) });
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podunordered_set);
+      oar(o_iserunordered_set);
+      oar(o_isplunordered_set);
+      oar(o_eserunordered_set);
+      oar(o_esplunordered_set);
+    }
+
+    std::unordered_set<int> i_podunordered_set;
+    std::unordered_set<StructInternalSerialize, StructHash<StructInternalSerialize>>   i_iserunordered_set;
+    std::unordered_set<StructInternalSplit, StructHash<StructInternalSplit>>           i_isplunordered_set;
+    std::unordered_set<StructExternalSerialize, StructHash<StructExternalSerialize>>   i_eserunordered_set;
+    std::unordered_set<StructExternalSplit, StructHash<StructExternalSplit>>           i_esplunordered_set;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podunordered_set);
+      iar(i_iserunordered_set);
+      iar(i_isplunordered_set);
+      iar(i_eserunordered_set);
+      iar(i_esplunordered_set);
+    }
+
+    for(auto const & p : i_podunordered_set)
+    {
+      BOOST_CHECK_EQUAL(o_podunordered_set.count(p), 1);
+    }
+
+    for(auto const & p : i_iserunordered_set)
+    {
+      BOOST_CHECK_EQUAL(o_iserunordered_set.count(p), 1);
+    }
+
+    for(auto const & p : i_isplunordered_set)
+    {
+      BOOST_CHECK_EQUAL(o_isplunordered_set.count(p), 1);
+    }
+
+    for(auto const & p : i_eserunordered_set)
+    {
+      BOOST_CHECK_EQUAL(o_eserunordered_set.count(p), 1);
+    }
+
+    for(auto const & p : i_esplunordered_set)
+    {
+      BOOST_CHECK_EQUAL(o_esplunordered_set.count(p), 1);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_unordered_set )
+{
+  test_unordered_set<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_unordered_set )
+{
+  test_unordered_set<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_unordered_set )
+{
+  test_unordered_set<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_unordered_set )
+{
+  test_unordered_set<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/user_data_adapters.cpp b/unittests/user_data_adapters.cpp
new file mode 100644
index 0000000..429d605
--- /dev/null
+++ b/unittests/user_data_adapters.cpp
@@ -0,0 +1,137 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#define CEREAL_FUTURE_EXPERIMENTAL
+#include <cereal/archives/adapters.hpp>
+#include <boost/test/unit_test.hpp>
+
+struct SomeStruct {};
+
+struct UserData
+{
+  UserData( SomeStruct * pp, SomeStruct & r ) :
+    p(pp), ref(r) {}
+
+  SomeStruct * p;
+  std::reference_wrapper<SomeStruct> ref;
+};
+
+struct UserStruct
+{
+  UserStruct( std::int32_t i,
+              SomeStruct * pointer,
+              SomeStruct & reference ) :
+    i32( i ),
+    p( pointer ),
+    ref( reference )
+  { }
+
+  UserStruct & operator=( UserStruct const & ) = delete;
+
+  std::int32_t i32;
+  SomeStruct const * p;
+  SomeStruct & ref;
+
+  template <class Archive>
+  void serialize( Archive & ar )
+  {
+    ar( i32 );
+  }
+
+  template <class Archive>
+  static void load_and_construct( Archive & ar, cereal::construct<UserStruct> & construct )
+  {
+    std::int32_t ii;
+    ar( ii );
+    auto & data = cereal::get_user_data<UserData>( ar );
+    construct( ii, data.p, data.ref.get() );
+  }
+};
+
+template <class IArchive, class OArchive>
+void test_user_data_adapters()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  auto rng = [&](){ return random_value<int>(gen); };
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    SomeStruct ss;
+    std::unique_ptr<UserStruct> o_ptr( new UserStruct( rng(), &ss, ss ) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_ptr);
+    }
+
+    decltype( o_ptr  ) i_ptr;
+
+    std::istringstream is(os.str());
+    {
+      UserData ud(&ss, ss);
+      cereal::UserDataAdapter<UserData, IArchive> iar(ud, is);
+
+      iar(i_ptr);
+    }
+
+    BOOST_CHECK_EQUAL( i_ptr->p == o_ptr->p, true );
+    BOOST_CHECK_EQUAL( std::addressof(i_ptr->ref) == std::addressof(o_ptr->ref), true );
+    BOOST_CHECK_EQUAL( i_ptr->i32, o_ptr->i32 );
+
+    std::istringstream bad_is(os.str());
+    {
+      IArchive iar(bad_is);
+
+      BOOST_CHECK_THROW( iar(i_ptr), ::cereal::Exception );
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_user_data_adapters )
+{
+  test_user_data_adapters<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_user_data_adapters )
+{
+  test_user_data_adapters<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_user_data_adapters )
+{
+  test_user_data_adapters<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_user_data_adapters )
+{
+  test_user_data_adapters<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/unittests/valarray.cpp b/unittests/valarray.cpp
new file mode 100644
index 0000000..7a1fbd1
--- /dev/null
+++ b/unittests/valarray.cpp
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2014, Randolph Voorhies, Shane Grant
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of cereal nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_valarray()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for (int ii = 0; ii<100; ++ii)
+  {
+    std::valarray<int> o_podvalarray(100);
+    for (auto & elem : o_podvalarray)
+      elem = random_value<int>(gen);
+
+    std::valarray<StructInternalSerialize> o_iservalarray(100);
+    for (auto & elem : o_iservalarray)
+      elem = StructInternalSerialize(random_value<int>(gen), random_value<int>(gen));
+
+    std::valarray<StructInternalSplit> o_isplvalarray(100);
+    for (auto & elem : o_isplvalarray)
+      elem = StructInternalSplit(random_value<int>(gen), random_value<int>(gen));
+
+    std::valarray<StructExternalSerialize> o_eservalarray(100);
+    for (auto & elem : o_eservalarray)
+      elem = StructExternalSerialize(random_value<int>(gen), random_value<int>(gen));
+
+    std::valarray<StructExternalSplit> o_esplvalarray(100);
+    for (auto & elem : o_esplvalarray)
+      elem = StructExternalSplit(random_value<int>(gen), random_value<int>(gen));
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podvalarray);
+      oar(o_iservalarray);
+      oar(o_isplvalarray);
+      oar(o_eservalarray);
+      oar(o_esplvalarray);
+    }
+
+    std::valarray<int> i_podvalarray;
+    std::valarray<StructInternalSerialize> i_iservalarray;
+    std::valarray<StructInternalSplit>     i_isplvalarray;
+    std::valarray<StructExternalSerialize> i_eservalarray;
+    std::valarray<StructExternalSplit>     i_esplvalarray;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podvalarray);
+      iar(i_iservalarray);
+      iar(i_isplvalarray);
+      iar(i_eservalarray);
+      iar(i_esplvalarray);
+    }
+
+    BOOST_CHECK_EQUAL(i_podvalarray.size(), o_podvalarray.size());
+    BOOST_CHECK_EQUAL(i_iservalarray.size(), o_iservalarray.size());
+    BOOST_CHECK_EQUAL(i_isplvalarray.size(), o_isplvalarray.size());
+    BOOST_CHECK_EQUAL(i_eservalarray.size(), o_eservalarray.size());
+    BOOST_CHECK_EQUAL(i_esplvalarray.size(), o_esplvalarray.size());
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_podvalarray), std::end(i_podvalarray), std::begin(o_podvalarray), std::end(o_podvalarray));
+    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_iservalarray), std::end(i_iservalarray), std::begin(o_iservalarray), std::end(o_iservalarray));
+    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_isplvalarray), std::end(i_isplvalarray), std::begin(o_isplvalarray), std::end(o_isplvalarray));
+    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_eservalarray), std::end(i_eservalarray), std::begin(o_eservalarray), std::end(o_eservalarray));
+    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(i_esplvalarray), std::end(i_esplvalarray), std::begin(o_esplvalarray), std::end(o_esplvalarray));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(binary_valarray)
+{
+  test_valarray<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE(portable_binary_valarray)
+{
+  test_valarray<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE(xml_valarray)
+{
+  test_valarray<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE(json_valarray)
+{
+  test_valarray<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
diff --git a/unittests/vector.cpp b/unittests/vector.cpp
new file mode 100644
index 0000000..fdb6869
--- /dev/null
+++ b/unittests/vector.cpp
@@ -0,0 +1,129 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+template <class IArchive, class OArchive>
+void test_vector()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(int ii=0; ii<100; ++ii)
+  {
+    std::vector<int> o_podvector(100);
+    for(auto & elem : o_podvector)
+      elem = random_value<int>(gen);
+
+    std::vector<bool> o_boolvector; o_boolvector.resize(100);
+    for( size_t i = 0; i < 100; ++i )
+      o_boolvector[i] = (random_value<int>(gen) % 2) == 0;
+
+    std::vector<StructInternalSerialize> o_iservector(100);
+    for(auto & elem : o_iservector)
+      elem = StructInternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::vector<StructInternalSplit> o_isplvector(100);
+    for(auto & elem : o_isplvector)
+      elem = StructInternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::vector<StructExternalSerialize> o_eservector(100);
+    for(auto & elem : o_eservector)
+      elem = StructExternalSerialize( random_value<int>(gen), random_value<int>(gen) );
+
+    std::vector<StructExternalSplit> o_esplvector(100);
+    for(auto & elem : o_esplvector)
+      elem = StructExternalSplit( random_value<int>(gen), random_value<int>(gen) );
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+
+      oar(o_podvector);
+      oar(o_boolvector);
+      oar(o_iservector);
+      oar(o_isplvector);
+      oar(o_eservector);
+      oar(o_esplvector);
+    }
+
+    std::vector<int> i_podvector;
+    std::vector<bool> i_boolvector;
+    std::vector<StructInternalSerialize> i_iservector;
+    std::vector<StructInternalSplit>     i_isplvector;
+    std::vector<StructExternalSerialize> i_eservector;
+    std::vector<StructExternalSplit>     i_esplvector;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+
+      iar(i_podvector);
+      iar(i_boolvector);
+      iar(i_iservector);
+      iar(i_isplvector);
+      iar(i_eservector);
+      iar(i_esplvector);
+    }
+
+    BOOST_CHECK_EQUAL(i_podvector.size(),  o_podvector.size());
+    BOOST_CHECK_EQUAL(i_boolvector.size(),  o_boolvector.size());
+    BOOST_CHECK_EQUAL(i_iservector.size(), o_iservector.size());
+    BOOST_CHECK_EQUAL(i_isplvector.size(), o_isplvector.size());
+    BOOST_CHECK_EQUAL(i_eservector.size(), o_eservector.size());
+    BOOST_CHECK_EQUAL(i_esplvector.size(), o_esplvector.size());
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_podvector.begin(),    i_podvector.end(),    o_podvector.begin(),  o_podvector.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_boolvector.begin(),    i_boolvector.end(),    o_boolvector.begin(),  o_boolvector.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_iservector.begin(),   i_iservector.end(),   o_iservector.begin(), o_iservector.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_isplvector.begin(),   i_isplvector.end(),   o_isplvector.begin(), o_isplvector.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_eservector.begin(),   i_eservector.end(),   o_eservector.begin(), o_eservector.end());
+    BOOST_CHECK_EQUAL_COLLECTIONS(i_esplvector.begin(),   i_esplvector.end(),   o_esplvector.begin(), o_esplvector.end());
+  }
+}
+
+BOOST_AUTO_TEST_CASE( binary_vector )
+{
+  test_vector<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_vector )
+{
+  test_vector<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_vector )
+{
+  test_vector<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_vector )
+{
+  test_vector<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
+
diff --git a/unittests/versioning.cpp b/unittests/versioning.cpp
new file mode 100644
index 0000000..86fb4e5
--- /dev/null
+++ b/unittests/versioning.cpp
@@ -0,0 +1,205 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "common.hpp"
+#include <boost/test/unit_test.hpp>
+
+namespace Nested
+{
+  struct NestedClass
+  {
+    int x;
+
+    template <class Archive>
+    void serialize( Archive & ar )
+    { ar( x ); }
+  };
+}
+
+CEREAL_CLASS_VERSION( Nested::NestedClass, 1 )
+
+class VersionStructMS
+{
+  public:
+    bool x;
+    std::uint32_t v;
+
+  private:
+    friend class cereal::access;
+    template <class Archive>
+    void serialize( Archive & ar, std::uint32_t const version )
+    {
+      ar( x );
+      v = version;
+    }
+};
+
+struct VersionStructMSP
+{
+  uint8_t x;
+  std::uint32_t v;
+  template <class Archive>
+  void save( Archive & ar, std::uint32_t const /*version*/ ) const
+  {
+    ar( x );
+  }
+
+  template <class Archive>
+  void load( Archive & ar, std::uint32_t const version )
+  {
+    ar( x );
+    v = version;
+  }
+};
+
+struct VersionStructNMS
+{
+  std::int32_t x;
+  std::uint32_t v;
+};
+
+template <class Archive>
+void serialize( Archive & ar, VersionStructNMS & vnms, const std::uint32_t version )
+{
+  ar( vnms.x );
+  vnms.v = version;
+}
+
+struct VersionStructNMSP
+{
+  double x;
+  std::uint32_t v;
+};
+
+template <class Archive>
+void save( Archive & ar, VersionStructNMSP const & vnms, const std::uint32_t /*version*/ )
+{
+  ar( vnms.x );
+}
+
+template <class Archive>
+void load( Archive & ar, VersionStructNMSP & vnms, const std::uint32_t version )
+{
+  ar( vnms.x );
+  vnms.v = version;
+}
+
+CEREAL_CLASS_VERSION( VersionStructMSP, 33 )
+CEREAL_CLASS_VERSION( VersionStructNMS, 66 )
+CEREAL_CLASS_VERSION( VersionStructNMSP, 99 )
+
+template <class IArchive, class OArchive>
+void test_versioning()
+{
+  std::random_device rd;
+  std::mt19937 gen(rd());
+
+  for(size_t i=0; i<100; ++i)
+  {
+    VersionStructMS o_MS      = {random_value<uint8_t>(gen) % 2 ? true : false, 1};
+    VersionStructMSP o_MSP    = {random_value<uint8_t>(gen), 1};
+    VersionStructNMS o_NMS    = {random_value<int32_t>(gen), 1};
+    VersionStructNMSP o_NMSP  = {random_value<double>(gen), 1};
+    VersionStructMS o_MS2     = {random_value<uint8_t>(gen) % 2 ? true : false, 1};
+    VersionStructMSP o_MSP2   = {random_value<uint8_t>(gen), 1};
+    VersionStructNMS o_NMS2   = {random_value<int32_t>(gen), 1};
+    VersionStructNMSP o_NMSP2 = {random_value<double>(gen), 1};
+
+    std::ostringstream os;
+    {
+      OArchive oar(os);
+      oar( o_MS );
+      oar( o_MSP );
+      oar( o_NMS );
+      oar( o_NMSP );
+      oar( o_MS2 );
+      oar( o_MSP2 );
+      oar( o_NMS2 );
+      oar( o_NMSP2 );
+    }
+
+    decltype(o_MS) i_MS;
+    decltype(o_MSP) i_MSP;
+    decltype(o_NMS) i_NMS;
+    decltype(o_NMSP) i_NMSP;
+    decltype(o_MS2) i_MS2;
+    decltype(o_MSP2) i_MSP2;
+    decltype(o_NMS2) i_NMS2;
+    decltype(o_NMSP2) i_NMSP2;
+
+    std::istringstream is(os.str());
+    {
+      IArchive iar(is);
+      iar( i_MS );
+      iar( i_MSP );
+      iar( i_NMS );
+      iar( i_NMSP );
+      iar( i_MS2 );
+      iar( i_MSP2 );
+      iar( i_NMS2 );
+      iar( i_NMSP2 );
+    }
+
+    BOOST_CHECK_EQUAL(o_MS.x, i_MS.x);
+    BOOST_CHECK_EQUAL(i_MS.v, 0);
+    BOOST_CHECK_EQUAL(o_MSP.x, i_MSP.x);
+    BOOST_CHECK_EQUAL(i_MSP.v, 33);
+    BOOST_CHECK_EQUAL(o_NMS.x, i_NMS.x);
+    BOOST_CHECK_EQUAL(i_NMS.v, 66);
+    BOOST_CHECK_CLOSE(o_NMSP.x, i_NMSP.x, 1e-5);
+    BOOST_CHECK_EQUAL(i_NMSP.v, 99);
+
+    BOOST_CHECK_EQUAL(o_MS2.x, i_MS2.x);
+    BOOST_CHECK_EQUAL(i_MS2.v, 0);
+    BOOST_CHECK_EQUAL(o_MSP2.x, i_MSP2.x);
+    BOOST_CHECK_EQUAL(i_MSP2.v, 33);
+    BOOST_CHECK_EQUAL(o_NMS2.x, i_NMS2.x);
+    BOOST_CHECK_EQUAL(i_NMS2.v, 66);
+    BOOST_CHECK_CLOSE(o_NMSP2.x, i_NMSP2.x, 1e-5);
+    BOOST_CHECK_EQUAL(i_NMSP2.v, 99);
+    }
+}
+
+BOOST_AUTO_TEST_CASE( binary_versioning )
+{
+  test_versioning<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( portable_binary_versioning )
+{
+  test_versioning<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( xml_versioning )
+{
+  test_versioning<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
+}
+
+BOOST_AUTO_TEST_CASE( json_versioning )
+{
+  test_versioning<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
+}
+
diff --git a/vs2013/.gitignore b/vs2013/.gitignore
new file mode 100644
index 0000000..c6eec7a
--- /dev/null
+++ b/vs2013/.gitignore
@@ -0,0 +1,3 @@
+*/Debug
+*/Release
+*/x64
diff --git a/vs2013/performance/performance.vcxproj b/vs2013/performance/performance.vcxproj
new file mode 100644
index 0000000..439907d
--- /dev/null
+++ b/vs2013/performance/performance.vcxproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\performance.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{2F374733-FCA8-4CBB-91A0-2B0B34393D86}</ProjectGuid>
+    <RootNamespace>performance</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib\x64;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib\x64;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/performance/performance.vcxproj.filters b/vs2013/performance/performance.vcxproj.filters
new file mode 100644
index 0000000..e25e75e
--- /dev/null
+++ b/vs2013/performance/performance.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\performance.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox/sandbox.vcxproj b/vs2013/sandbox/sandbox.vcxproj
new file mode 100644
index 0000000..f651f80
--- /dev/null
+++ b/vs2013/sandbox/sandbox.vcxproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{DAC23DBB-630B-46B9-B115-F1449697898A}</ProjectGuid>
+    <RootNamespace>sandbox</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+    <LibraryPath>C:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+    <LibraryPath>C:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>false</RunCodeAnalysis>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <EnablePREfast>false</EnablePREfast>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox/sandbox.vcxproj.filters b/vs2013/sandbox/sandbox.vcxproj.filters
new file mode 100644
index 0000000..90e0f7d
--- /dev/null
+++ b/vs2013/sandbox/sandbox.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_json/sandbox_json.vcxproj b/vs2013/sandbox_json/sandbox_json.vcxproj
new file mode 100644
index 0000000..9672c3a
--- /dev/null
+++ b/vs2013/sandbox_json/sandbox_json.vcxproj
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_json.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{52E96EC3-125A-4525-BC72-F3C524F24640}</ProjectGuid>
+    <RootNamespace>sandbox_json</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_json/sandbox_json.vcxproj.filters b/vs2013/sandbox_json/sandbox_json.vcxproj.filters
new file mode 100644
index 0000000..3edef0a
--- /dev/null
+++ b/vs2013/sandbox_json/sandbox_json.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_json.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_rtti/sandbox_rtti.vcxproj b/vs2013/sandbox_rtti/sandbox_rtti.vcxproj
new file mode 100644
index 0000000..d5fbd0e
--- /dev/null
+++ b/vs2013/sandbox_rtti/sandbox_rtti.vcxproj
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_rtti.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C81EF3F9-7849-4506-898C-85D0D564CD6A}</ProjectGuid>
+    <RootNamespace>sandbox_rtti</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+    <LibraryPath>C:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_54;$(IncludePath)</IncludePath>
+    <LibraryPath>C:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;C:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_rtti/sandbox_rtti.vcxproj.filters b/vs2013/sandbox_rtti/sandbox_rtti.vcxproj.filters
new file mode 100644
index 0000000..813de5f
--- /dev/null
+++ b/vs2013/sandbox_rtti/sandbox_rtti.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_rtti.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_vs/sandbox_vs.vcxproj b/vs2013/sandbox_vs/sandbox_vs.vcxproj
new file mode 100644
index 0000000..869e945
--- /dev/null
+++ b/vs2013/sandbox_vs/sandbox_vs.vcxproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}</ProjectGuid>
+    <RootNamespace>sandbox_vs</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\sandbox_vs_dll;$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(SolutionDir)\..\sandbox\sandbox_shared_lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(SolutionDir)\Debug;E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\sandbox_vs_dll;$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(SolutionDir)\..\sandbox\sandbox_shared_lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(SolutionDir)\x64\Debug;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\sandbox_vs_dll;$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(SolutionDir)\..\sandbox\sandbox_shared_lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(SolutionDir)\Release;E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\sandbox_vs_dll;$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(SolutionDir)\..\sandbox\sandbox_shared_lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(SolutionDir)\x64\Release;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <TreatWarningAsError>false</TreatWarningAsError>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>sandbox_vs_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>sandbox_vs_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>sandbox_vs_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>sandbox_vs_dll.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_vs.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_vs/sandbox_vs.vcxproj.filters b/vs2013/sandbox_vs/sandbox_vs.vcxproj.filters
new file mode 100644
index 0000000..70ecf39
--- /dev/null
+++ b/vs2013/sandbox_vs/sandbox_vs.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_vs.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj b/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj
new file mode 100755
index 0000000..cfeb78f
--- /dev/null
+++ b/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_shared_lib\base.cpp" />
+    <ClCompile Include="..\..\sandbox\sandbox_shared_lib\derived.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\sandbox\sandbox_shared_lib\base.hpp" />
+    <ClInclude Include="..\..\sandbox\sandbox_shared_lib\derived.hpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{95D6662F-4166-40D2-87D7-CABFB60C199A}</ProjectGuid>
+    <RootNamespace>sandbox_vs_dll</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj.filters b/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj.filters
new file mode 100755
index 0000000..d61909d
--- /dev/null
+++ b/vs2013/sandbox_vs_dll/sandbox_vs_dll.vcxproj.filters
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\sandbox\sandbox_shared_lib\base.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\sandbox\sandbox_shared_lib\derived.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\sandbox\sandbox_shared_lib\base.hpp">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\sandbox\sandbox_shared_lib\derived.hpp">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/unittests/main.cpp b/vs2013/unittests/main.cpp
new file mode 100755
index 0000000..c78f94a
--- /dev/null
+++ b/vs2013/unittests/main.cpp
@@ -0,0 +1,32 @@
+/*
+  Copyright (c) 2014, Randolph Voorhies, Shane Grant
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+      * Neither the name of cereal nor the
+        names of its contributors may be used to endorse or promote products
+        derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <common.hpp>
+
+#define BOOST_TEST_MODULE Cereal
+#include <boost/test/unit_test.hpp>
+#include <boost/test/included/unit_test.hpp>
\ No newline at end of file
diff --git a/vs2013/unittests/unittests.vcxproj b/vs2013/unittests/unittests.vcxproj
new file mode 100644
index 0000000..2a84192
--- /dev/null
+++ b/vs2013/unittests/unittests.vcxproj
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\unittests\array.cpp" />
+    <ClCompile Include="..\..\unittests\basic_string.cpp" />
+    <ClCompile Include="..\..\unittests\bitset.cpp" />
+    <ClCompile Include="..\..\unittests\chrono.cpp" />
+    <ClCompile Include="..\..\unittests\complex.cpp" />
+    <ClCompile Include="..\..\unittests\deque.cpp" />
+    <ClCompile Include="..\..\unittests\forward_list.cpp" />
+    <ClCompile Include="..\..\unittests\list.cpp" />
+    <ClCompile Include="..\..\unittests\load_construct.cpp" />
+    <ClCompile Include="..\..\unittests\map.cpp" />
+    <ClCompile Include="..\..\unittests\memory.cpp" />
+    <ClCompile Include="..\..\unittests\memory_cycles.cpp" />
+    <ClCompile Include="..\..\unittests\multimap.cpp" />
+    <ClCompile Include="..\..\unittests\multiset.cpp" />
+    <ClCompile Include="..\..\unittests\pair.cpp" />
+    <ClCompile Include="..\..\unittests\pod.cpp" />
+    <ClCompile Include="..\..\unittests\polymorphic.cpp" />
+    <ClCompile Include="..\..\unittests\portable_binary_archive.cpp" />
+    <ClCompile Include="..\..\unittests\priority_queue.cpp" />
+    <ClCompile Include="..\..\unittests\queue.cpp" />
+    <ClCompile Include="..\..\unittests\set.cpp" />
+    <ClCompile Include="..\..\unittests\stack.cpp" />
+    <ClCompile Include="..\..\unittests\structs.cpp" />
+    <ClCompile Include="..\..\unittests\structs_minimal.cpp" />
+    <ClCompile Include="..\..\unittests\structs_specialized.cpp" />
+    <ClCompile Include="..\..\unittests\tuple.cpp" />
+    <ClCompile Include="..\..\unittests\unordered_loads.cpp" />
+    <ClCompile Include="..\..\unittests\unordered_map.cpp" />
+    <ClCompile Include="..\..\unittests\unordered_multimap.cpp" />
+    <ClCompile Include="..\..\unittests\unordered_multiset.cpp" />
+    <ClCompile Include="..\..\unittests\unordered_set.cpp" />
+    <ClCompile Include="..\..\unittests\user_data_adapters.cpp" />
+    <ClCompile Include="..\..\unittests\vector.cpp" />
+    <ClCompile Include="..\..\unittests\valarray.cpp" />
+    <ClCompile Include="..\..\unittests\versioning.cpp" />
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}</ProjectGuid>
+    <RootNamespace>unittests</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;$(SolutionDir)\..\unittests;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>$(SolutionDir)\..\include;$(SolutionDir)\..\unittests;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib\x64;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IncludePath>$(SolutionDir)\..\include;$(SolutionDir)\..\unittests;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IncludePath>$(SolutionDir)\..\include;$(SolutionDir)\..\unittests;E:\Boost\include\boost-1_55;$(IncludePath)</IncludePath>
+    <LibraryPath>E:\Boost\lib\x64;$(LibraryPath)</LibraryPath>
+    <RunCodeAnalysis>false</RunCodeAnalysis>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <ShowProgress>NotSet</ShowProgress>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+      <EnablePREfast>false</EnablePREfast>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/unittests/unittests.vcxproj.filters b/vs2013/unittests/unittests.vcxproj.filters
new file mode 100644
index 0000000..902b535
--- /dev/null
+++ b/vs2013/unittests/unittests.vcxproj.filters
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\unittests\array.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\basic_string.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\bitset.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\chrono.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\complex.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\deque.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\forward_list.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\list.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\load_construct.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\map.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\memory.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\memory_cycles.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\multimap.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\multiset.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\pair.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\pod.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\polymorphic.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\portable_binary_archive.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\priority_queue.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\queue.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\set.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\stack.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\structs.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\structs_specialized.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\tuple.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\unordered_loads.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\unordered_map.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\unordered_multimap.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\unordered_multiset.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\unordered_set.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\vector.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+     <ClCompile Include="..\..\unittests\valarray.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\versioning.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\structs_minimal.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\unittests\user_data_adapters.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2013/vs2013.sln b/vs2013/vs2013.sln
new file mode 100644
index 0000000..350d412
--- /dev/null
+++ b/vs2013/vs2013.sln
@@ -0,0 +1,90 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30324.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_vs", "sandbox_vs\sandbox_vs.vcxproj", "{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}"
+	ProjectSection(ProjectDependencies) = postProject
+		{95D6662F-4166-40D2-87D7-CABFB60C199A} = {95D6662F-4166-40D2-87D7-CABFB60C199A}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_json", "sandbox_json\sandbox_json.vcxproj", "{52E96EC3-125A-4525-BC72-F3C524F24640}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox", "sandbox\sandbox.vcxproj", "{DAC23DBB-630B-46B9-B115-F1449697898A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_rtti", "sandbox_rtti\sandbox_rtti.vcxproj", "{C81EF3F9-7849-4506-898C-85D0D564CD6A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittests", "unittests\unittests.vcxproj", "{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "performance", "performance\performance.vcxproj", "{2F374733-FCA8-4CBB-91A0-2B0B34393D86}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_vs_dll", "sandbox_vs_dll\sandbox_vs_dll.vcxproj", "{95D6662F-4166-40D2-87D7-CABFB60C199A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Debug|Win32.ActiveCfg = Debug|Win32
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Debug|Win32.Build.0 = Debug|Win32
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Debug|x64.ActiveCfg = Debug|x64
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Debug|x64.Build.0 = Debug|x64
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Release|Win32.ActiveCfg = Release|Win32
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Release|Win32.Build.0 = Release|Win32
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Release|x64.ActiveCfg = Release|x64
+		{A67E36D2-32BE-4D4D-BA2E-8FD59378E734}.Release|x64.Build.0 = Release|x64
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Debug|Win32.ActiveCfg = Debug|Win32
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Debug|Win32.Build.0 = Debug|Win32
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Debug|x64.ActiveCfg = Debug|x64
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Debug|x64.Build.0 = Debug|x64
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Release|Win32.ActiveCfg = Release|Win32
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Release|Win32.Build.0 = Release|Win32
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Release|x64.ActiveCfg = Release|x64
+		{52E96EC3-125A-4525-BC72-F3C524F24640}.Release|x64.Build.0 = Release|x64
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Debug|Win32.Build.0 = Debug|Win32
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Debug|x64.ActiveCfg = Debug|x64
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Debug|x64.Build.0 = Debug|x64
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Release|Win32.ActiveCfg = Release|Win32
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Release|Win32.Build.0 = Release|Win32
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Release|x64.ActiveCfg = Release|x64
+		{DAC23DBB-630B-46B9-B115-F1449697898A}.Release|x64.Build.0 = Release|x64
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Debug|Win32.Build.0 = Debug|Win32
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Debug|x64.ActiveCfg = Debug|x64
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Debug|x64.Build.0 = Debug|x64
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Release|Win32.ActiveCfg = Release|Win32
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Release|Win32.Build.0 = Release|Win32
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Release|x64.ActiveCfg = Release|x64
+		{C81EF3F9-7849-4506-898C-85D0D564CD6A}.Release|x64.Build.0 = Release|x64
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Debug|Win32.Build.0 = Debug|Win32
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Debug|x64.ActiveCfg = Debug|x64
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Debug|x64.Build.0 = Debug|x64
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Release|Win32.ActiveCfg = Release|Win32
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Release|Win32.Build.0 = Release|Win32
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Release|x64.ActiveCfg = Release|x64
+		{D447E13A-97A4-4907-9F61-A9BCCDB91EF7}.Release|x64.Build.0 = Release|x64
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Debug|Win32.Build.0 = Debug|Win32
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Debug|x64.ActiveCfg = Debug|x64
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Release|Win32.ActiveCfg = Release|Win32
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Release|Win32.Build.0 = Release|Win32
+		{2F374733-FCA8-4CBB-91A0-2B0B34393D86}.Release|x64.ActiveCfg = Release|x64
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Debug|Win32.ActiveCfg = Debug|Win32
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Debug|Win32.Build.0 = Debug|Win32
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Debug|x64.ActiveCfg = Debug|x64
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Release|Win32.ActiveCfg = Release|Win32
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Release|Win32.Build.0 = Release|Win32
+		{95D6662F-4166-40D2-87D7-CABFB60C199A}.Release|x64.ActiveCfg = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
+EndGlobal

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/cereal.git



More information about the debian-med-commit mailing list