Repository: bacpop/PopPUNK (language: python)

Issue:
pip installable poppunk, almost
Currently uses the path docker2 because there is historical docker image material there that I now think is redundant/unused?

Pulls in the fix-json-serialisation branch which is unmerged
Add rapidnj to docker image
Rapidnj installation was added to Dockerfile


Discussion / hints:

Fix patch:
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..86741df0
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,6 @@
+build
+dist
+*.egg-info
+.git
+test
+docs
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6f82f992..57344c9a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.18)
+cmake_minimum_required(VERSION 3.16)
 project(poppunk_refine)
 set(CMAKE_CXX_STANDARD 14)
 
@@ -25,9 +25,12 @@ if(DEFINED ENV{CONDA_PREFIX})
 endif()
 
 # Add libraries
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+execute_process(COMMAND pybind11-config --cmakedir OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE pybind11_DIR)
 find_package(pybind11 REQUIRED)
-find_package (Eigen3 3.3 REQUIRED NO_MODULE)
+find_package(Eigen3 3.3 REQUIRED NO_MODULE)
 #find_package(OpenMP) # This links system openmp if present - conda sorts out rpath but take care
 
 # Define python library target
diff --git a/MANIFEST.in b/MANIFEST.in
index ad9e8edf..4e5b847c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,5 @@
 recursive-include scripts *.py
-recursive-include PopPUNK/data *.gz
\ No newline at end of file
+recursive-include PopPUNK/data *.gz
+recursive-include vendor *
+recursive-include src *
+include CMakeLists.txt
diff --git a/PopPUNK/web.py b/PopPUNK/web.py
index cd24eb07..6621085b 100644
--- a/PopPUNK/web.py
+++ b/PopPUNK/web.py
@@ -1,7 +1,6 @@
-from types import SimpleNamespace
+from re import I
 import h5py
 import os
-import re
 import sys
 import numpy as np
 import pandas as pd
@@ -10,165 +9,7 @@
 import networkx as nx
 from networkx.readwrite import json_graph
 
-import subprocess
-import uuid
-import glob
-import atexit
-from flask import Flask, request, jsonify
-from flask_cors import CORS, cross_origin
 import json
-from flask_apscheduler import APScheduler
-
-from PopPUNK.assign import assign_query
-from PopPUNK.utils import setupDBFuncs
-from PopPUNK.visualise import generate_visualisations
-
-# data locations
-db_prefix = 'WebOutput'
-db_location = '/home/poppunk-usr/' + os.getenv('POPPUNK_DBS_LOC', 'poppunk_dbs')
-
-app = Flask(__name__, instance_relative_config=True)
-app.config.update(
-    TESTING=True,
-    SCHEDULER_API_ENABLED=True,
-    SECRET_KEY=os.environ.get('FLASK_SECRET_KEY')
-)
-CORS(app, expose_headers='Authorization')
-scheduler = APScheduler()
-
-@app.route('/')
-def api_up():
-    return 'PopPUNK.web running\n'
-
-@app.route('/upload', methods=['POST'])
-@cross_origin()
-def sketchAssign():
-    """Recieve sketch and respond with clustering information"""
-    if not request.json:
-        return "not a json post"
-    if request.json:
-        sketch_dict = request.json
-        # determine database to use
-        if sketch_dict["species"] == "S.pneumoniae":
-            species = 'Streptococcus pneumoniae'
-            species_db = db_location + "/GPS_v3_references"
-        args = default_options(species_db)
-
-        outdir = "/tmp/" + db_prefix + "_" + str(uuid.uuid4())
-        if not os.path.exists(outdir):
-            os.mkdir(outdir)
-
-        qc_dict = {'run_qc': False }
-        dbFuncs = setupDBFuncs(args.assign, qc_dict)
-
-        # assign query to strain
-        ClusterResult = assign_query(dbFuncs,
-                                    args.assign.ref_db,
-                                    args.assign.q_files,
-                                    outdir,
-                                    qc_dict,
-                                    args.assign.update_db,
-                                    args.assign.write_references,
-                                    args.assign.distances,
-                                    args.assign.threads,
-                                    args.assign.overwrite,
-                                    args.assign.plot_fit,
-                                    args.assign.graph_weights,
-                                    args.assign.max_a_dist,
-                                    args.assign.max_pi_dist,
-                                    args.assign.type_isolate,
-                                    args.assign.model_dir,
-                                    args.assign.strand_preserved,
-                                    args.assign.previous_clustering,
-                                    args.assign.external_clustering,
-                                    args.assign.core_only,
-                                    args.assign.accessory_only,
-                                    args.assign.gpu_sketch,
-                                    args.assign.gpu_dist,
-                                    args.assign.gpu_graph,
-                                    args.assign.deviceid,
-                                    args.assign.web,
-                                    sketch_dict["sketch"],
-                                    args.assign.save_partial_query_graph)
-        query, query_prevalence, clusters, prevalences, alias_dict, to_include = \
-            summarise_clusters(outdir, species, species_db)
-        colours = get_colours(query, clusters)
-        url = api(query, args.assign.ref_db)
-
-        # generate visualisations from assign output
-        if len(to_include) < 3:
-            args.visualise.microreact = False
-        generate_visualisations(outdir,
-                                species_db,
-                                None,
-                                args.visualise.threads,
-                                outdir,
-                                args.visualise.gpu_dist,
-                                args.visualise.deviceid,
-                                args.visualise.external_clustering,
-                                args.visualise.microreact,
-                                args.visualise.phandango,
-                                args.visualise.grapetree,
-                                args.visualise.cytoscape,
-                                args.visualise.perplexity,
-                                args.visualise.strand_preserved,
-                                outdir + "/include.txt",
-                                species_db,
-                                species_db + "/" + os.path.basename(species_db) + "_clusters.csv",
-                                args.visualise.previous_query_clustering,
-                                outdir + "/" + os.path.basename(outdir) + "_graph.gt",                                args.visualise.gpu_graph,
-                                args.visualise.info_csv,
-                                args.visualise.rapidnj,
-                                args.visualise.tree,
-                                args.visualise.mst_distances,
-                                args.visualise.overwrite,
-                                args.visualise.core_only,
-                                args.visualise.accessory_only,
-                                args.visualise.display_cluster,
-                                web=True)
-        networkJson = graphml_to_json(outdir)
-        if len(to_include) >= 3:
-            with open(os.path.join(outdir, os.path.basename(outdir) + "_core_NJ.nwk"), "r") as p:
-                phylogeny = p.read()
-        else:
-            phylogeny = "A tree cannot be built with fewer than 3 samples."
-
-        # Convert outputs to JSON for post to site
-        response = {"species":species,
-                    "prev":str(query_prevalence) + '%',
-                    "query":query,
-                    "clusters":clusters,
-                    "prevalences":prevalences,
-                    "colours":colours,
-                    "microreactUrl":url,
-                    "aliases":alias_dict,
-                    "network": networkJson,
-                    "phylogeny": phylogeny}
-        response = json.dumps(response)
-        subprocess.run(["rm", "-rf", outdir]) # shutil issues on azure
-        return jsonify(response)
-
-def default_options(species_db):
-    """Default options for WebAPI"""
-    with open(os.path.join(species_db, "args.txt")) as a:
-        args_json = a.read()
-    args = json.loads(args_json, object_hook=lambda d: SimpleNamespace(**d))
-    args.assign.ref_db = species_db
-    args.assign.previous_clustering = species_db
-    args.assign.model_dir = species_db
-    args.assign.distances = os.path.join(species_db, os.path.basename(species_db) + ".dists")
-    args.assign.q_files = os.path.join(args.assign.output, "queries.txt")
-    return (args)
-
-def get_colours(query, clusters):
-    """Colour array for Plotly.js"""
-    colours = []
-    for clus in clusters:
-        if str(clus) == str(query):
-            colours.append('rgb(255,128,128)')
-        else:
-            colours.append('blue')
-    return colours
 
 def sketch_to_hdf5(sketches_dict, output):
     """Convert dict of JSON sketches to query hdf5 database"""
@@ -180,7 +21,10 @@ def sketch_to_hdf5(sketches_dict, output):
         qNames.append(top_key)
         kmers = []
         dists = []
-        sketch_dict = json.loads(top_value)
+        if type(top_value) == str:
+            sketch_dict = json.loads(top_value)
+        else:
+            sketch_dict = top_value
         sketch_props = sketches.create_group(top_key)
 
         for key, value in sketch_dict.items():
@@ -255,6 +99,7 @@ def highlight_cluster(query, cluster):
         colour = "blue"
     return colour
 
+# TODO: update to new microreact API
 def api(query, ref_db):
     """Post cluster and tree information to microreact"""
     url = "https://microreact.org/api/project/"
@@ -322,19 +167,6 @@ def summarise_clusters(output, species, species_db, qNames):
     if os.path.isfile(os.path.join(species_db, "aliases.csv")):
         aliasDF = pd.read_csv(os.path.join(species_db, "aliases.csv"))
         alias_dict = get_aliases(aliasDF, list(clusterDF['Taxon']), species)
-    else: 
+    else:
         alias_dict = {"Aliases": "NA"}
     return queries_names, queries_clusters, queries_prevalence, clusters, prevalences, alias_dict, to_include
-
-@scheduler.task('interval', id='clean_tmp', hours=1, misfire_grace_time=900)
-def clean_tmp():
-    print("Cleaning up unused databases")
-    for name in glob.glob("/tmp/" + db_prefix + "_*"):
-        shutil.rmtree(name)
-
-def main():
-    # data cleanup
-    scheduler.init_app(app)
-    scheduler.start()
-    atexit.register(lambda: scheduler.shutdown())
-    app.run(debug=False,use_reloader=False)
diff --git a/README.md b/README.md
index fa240387..9d9808d4 100644
--- a/README.md
+++ b/README.md
@@ -68,3 +68,11 @@ conda config --add channels conda-forge
 
 See the [quickstart](https://poppunk.readthedocs.io/en/latest/quickstart.html) guide
 for a brief tutorial.
+
+## Docker image
+
+A docker image is available
+
+```
+docker pull mrcide/poppunk:bacpop-20
+```
diff --git a/boost/Dockerfile b/boost/Dockerfile
new file mode 100644
index 00000000..42272b09
--- /dev/null
+++ b/boost/Dockerfile
@@ -0,0 +1,5 @@
+FROM ubuntu:20.04
+
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \
+    libboost-all-dev
diff --git a/boost/extract b/boost/extract
new file mode 100755
index 00000000..912e6b3d
--- /dev/null
+++ b/boost/extract
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+set -eux
+HERE=$(dirname $0)
+ROOT=$(realpath $HERE/..)
+IMAGE=mrcide/poppunk:boost
+DEST=$ROOT/vendor
+REQUIRE=boost/sort/parallel_stable_sort/parallel_stable_sort.hpp
+docker build -t $IMAGE "$ROOT/boost"
+rm -rf $DEST/boost
+mkdir -p $DEST
+docker run \
+       --user "$(id -u):$(id -g)" \
+       -v $DEST:/dest \
+       $IMAGE \
+       bcp --boost=/usr/include $REQUIRE /dest
diff --git a/buildkite/pipeline.yml b/buildkite/pipeline.yml
new file mode 100644
index 00000000..5c4894a3
--- /dev/null
+++ b/buildkite/pipeline.yml
@@ -0,0 +1,13 @@
+steps:
+  - label: ":whale::python: Build"
+    command: docker2/build
+
+  - wait
+
+  - label: ":hammer: Test image"
+    command: docker2/test
+
+  - wait
+
+  - label: ":shipit: Push images"
+    command: docker2/push
diff --git a/docker2/Dockerfile b/docker2/Dockerfile
new file mode 100644
index 00000000..9f895932
--- /dev/null
+++ b/docker2/Dockerfile
@@ -0,0 +1,43 @@
+FROM python:3.10
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+                          cmake \
+                          gfortran \
+                          libarmadillo-dev \
+                          libeigen3-dev \
+                          libopenblas-dev \
+                          software-properties-common
+
+RUN git clone https://github.com/somme89/rapidNJ.git && \
+    cd rapidNJ && \
+    make && \
+    mv ./bin/rapidnj /usr/bin &&\
+    cd .. && rm -r rapidNJ
+
+# Special snowflake treatment for graph_tool because the maintainer
+# refuses to make the package pip-installable, meaning we can't depend
+# on it in a sane way. Least pain seems to be to install via apt, even
+# though that might result in slightly incorrect versions (built
+# around system python).
+#
+# The alternative would be to build it from source
+# https://git.skewed.de/count0/graph-tool/-/wikis/installation-instructions#manual-compilation
+# but it takes over an hour to compile apparently, so that sounds not
+# ideal.
+RUN add-apt-repository https://downloads.skewed.de/apt && \
+    apt-key adv --keyserver keyserver.ubuntu.com \
+            --recv-key 612DEFB798507F25 && \
+    apt-get update && \
+    apt-get install -y --no-install-recommends python3-graph-tool && \
+    ln -s /usr/lib/python3/dist-packages/graph_tool \
+      /usr/local/lib/python3.10/site-packages
+
+COPY requirements.txt /tmp/requirements.txt
+RUN pip install pybind11 && \
+  pip install -r /tmp/requirements.txt && \
+  rm -f /tmp/requirements.txt
+
+COPY . /src
+WORKDIR /src
+RUN python setup.py install
diff --git a/docker2/build b/docker2/build
new file mode 100755
index 00000000..68784d80
--- /dev/null
+++ b/docker2/build
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+set -ex
+
+HERE=$(dirname $0)
+. $HERE/common
+
+docker build --pull \
+       --tag $TAG_SHA \
+       -f docker2/Dockerfile \
+       $PACKAGE_ROOT
+
+# We always push the SHA tagged versions, for debugging if the tests
+# after this step fail
+docker push $TAG_SHA
diff --git a/docker2/common b/docker2/common
new file mode 100755
index 00000000..a0448139
--- /dev/null
+++ b/docker2/common
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+set -e
+
+PACKAGE_ROOT=$(realpath $HERE/..)
+PACKAGE_NAME=poppunk
+PACKAGE_ORG=mrcide
+
+# Buildkite doesn't check out a full history from the remote (just the
+# single commit) so you end up with a detached head and git rev-parse
+# doesn't work
+if [ "$BUILDKITE" = "true" ]; then
+    GIT_SHA=${BUILDKITE_COMMIT:0:7}
+else
+    GIT_SHA=$(git -C "$PACKAGE_ROOT" rev-parse --short=7 HEAD)
+fi
+
+if [ "$BUILDKITE" = "true" ]; then
+    GIT_BRANCH=$BUILDKITE_BRANCH
+else
+    GIT_BRANCH=$(git -C "$PACKAGE_ROOT" symbolic-ref --short HEAD)
+fi
+
+TAG_SHA="${PACKAGE_ORG}/${PACKAGE_NAME}:${GIT_SHA}"
+TAG_BRANCH="${PACKAGE_ORG}/${PACKAGE_NAME}:${GIT_BRANCH}"
+TAG_LATEST="${PACKAGE_ORG}/${PACKAGE_NAME}:latest"
diff --git a/docker2/push b/docker2/push
new file mode 100755
index 00000000..103533a1
--- /dev/null
+++ b/docker2/push
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -e
+
+HERE=$(dirname $0)
+. $HERE/common
+
+# In case we switch agents between steps
+[ ! -z $(docker images -q $TAG_SHA) ] || docker pull $TAG_SHA
+
+docker tag $TAG_SHA $TAG_BRANCH
+docker push $TAG_BRANCH
+
+if [ $GIT_BRANCH == "master" ]; then
+   docker tag $TAG_SHA $TAG_LATEST
+   docker push $TAG_LATEST
+fi
diff --git a/environment.yml b/environment.yml
index 6b5b4e27..545b84d3 100644
--- a/environment.yml
+++ b/environment.yml
@@ -6,7 +6,7 @@ channels:
   - r
 dependencies:
   - pip
-  - numpy
+  - numpy <=1.22.4
   - scipy
   - python-dateutil
   - pandas
@@ -18,12 +18,8 @@ dependencies:
   - hdbscan
   - rapidnj
   - h5py
-  - pp-sketchlib >=1.7.0
+  - pp-sketchlib >=2.0.0
   - graph-tool >=2.35
-  - requests
-  - flask
-  - flask-cors
-  - gunicorn
   - networkx
   - xorg-libxi
   - xorg-libxcursor
@@ -42,5 +38,3 @@ dependencies:
   - boost-cpp
   - libgomp
   - tqdm
-  - tzlocal <3.0
-  - flask-apscheduler
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..20bf631f
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools>=42", "wheel", "pybind11~=2.6.1"]
+build-backend = "setuptools.build_meta"
diff --git a/requirements.txt b/requirements.txt
index 4bfc4281..65392a9f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,1 +1,19 @@
-Cython>=0.26.1
\ No newline at end of file
+Cython>=0.26.1
+pybind11
+dendropy>=4.4.0
+flask
+flask-cors
+gunicorn
+h5py
+hdbscan
+matplotlib
+networkx
+numpy
+pandas
+pp-sketchlib>=1.7.0
+requests
+scikit-learn>=0.24
+scipy
+tqdm
+treeswift
+tzlocal<3.0
diff --git a/setup.py b/setup.py
old mode 100644
new mode 100755
diff --git a/src/boundary.hpp b/src/boundary.hpp
index 6aff8162..f188920d 100644
--- a/src/boundary.hpp
+++ b/src/boundary.hpp
@@ -16,7 +16,7 @@
 #include <Eigen/Dense>
 
 // Parallel sort
-#include <boost/sort/sort.hpp>
+#include <boost/sort/parallel_stable_sort/parallel_stable_sort.hpp>
 typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
     NumpyMatrix;
 typedef std::tuple<std::vector<long>, std::vector<long>, std::vector<long>>
diff --git a/vendor/boost/sort/common/indirect.hpp b/vendor/boost/sort/common/indirect.hpp
new file mode 100644
index 00000000..a55ef820
--- /dev/null
+++ b/vendor/boost/sort/common/indirect.hpp
@@ -0,0 +1,153 @@
+//----------------------------------------------------------------------------
+/// @file indirect.hpp
+/// @brief Indirect algorithm
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_COMMON_INDIRECT_HPP
+#define __BOOST_SORT_PARALLEL_COMMON_INDIRECT_HPP
+
+//#include <boost/sort/common/atomic.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <functional>
+#include <iterator>
+#include <type_traits>
+#include <vector>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+
+//
+//---------------------------------------------------------------------------
+/// @struct less_ptr_no_null
+///
+/// @remarks this is the comparison object for pointers. Compare the objects
+///          pointed by the iterators
+//---------------------------------------------------------------------------
+template<class Iter_t, class Compare = util::compare_iter<Iter_t> >
+struct less_ptr_no_null
+{
+    //----------------------------- Variables -----------------------
+    Compare comp; // comparison object of the elements pointed by Iter_t
+
+    //------------------------------------------------------------------------
+    //  function : less_ptr_no_null
+    /// @brief constructor from a Compare object
+    /// @param C1 : comparison object
+    //-----------------------------------------------------------------------
+    less_ptr_no_null(Compare C1 = Compare()): comp(C1) { };
+
+    //------------------------------------------------------------------------
+    //  function : operator ( )
+    /// @brief Make the comparison of the objects pointed by T1 and T2, using
+    //         the internal comp
+    //
+    /// @param  T1 : first iterator
+    /// @param  T2 : second iterator
+    /// @return bool result of the comparison
+    //-----------------------------------------------------------------------
+    bool operator( )(Iter_t T1, Iter_t T2) const
+    {
+        return comp(*T1, *T2);
+    };
+};
+//
+//-----------------------------------------------------------------------------
+//  function : create_index
+/// @brief From a vector of objects, create a vector of iterators to
+///        the objects
+///
+/// @param first : iterator to the first element of the range
+/// @param last : iterator to the element after the last of the range
+/// @param index : vector where store the iterators
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+static void create_index(Iter_t first, Iter_t last, std::vector<Iter_t> &index)
+{
+    auto nelem = last - first;
+    assert(nelem >= 0);
+    index.clear();
+    index.reserve(nelem);
+    for (; first != last; ++first) index.push_back(first);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : sort_index
+/// @brief This function transform a logical sort of the elements in the index
+///        in a physical sort
+//
+/// @param global_first : iterator to the first element of the data
+/// @param [in] index : vector of the iterators
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+static void sort_index(Iter_t global_first, std::vector<Iter_t> &index)
+{
+    typedef util::value_iter<Iter_t> value_t;
+
+    size_t pos_dest = 0;
+    size_t pos_src = 0;
+    size_t pos_in_vector = 0;
+    size_t nelem = index.size();
+    Iter_t it_dest, it_src;
+
+    while (pos_in_vector < nelem)
+    {
+        while (pos_in_vector < nelem and
+               (size_t(index[pos_in_vector] - global_first)) == pos_in_vector)
+        {
+            ++pos_in_vector;
+        };
+
+        if (pos_in_vector == nelem) return;
+        pos_dest = pos_src = pos_in_vector;
+        it_dest = global_first + pos_dest;
+        value_t Aux = std::move(*it_dest);
+
+        while ((pos_src = (size_t(index[pos_dest] - global_first)))
+               != pos_in_vector)
+        {
+            index[pos_dest] = it_dest;
+            it_src = global_first + pos_src;
+            *it_dest = std::move(*it_src);
+            it_dest = it_src;
+            pos_dest = pos_src;
+        };
+
+        *it_dest = std::move(Aux);
+        index[pos_dest] = it_dest;
+        ++pos_in_vector;
+    };
+};
+
+template<class func, class Iter_t, class Compare = compare_iter<Iter_t> >
+static void indirect_sort(func method, Iter_t first, Iter_t last, Compare comp)
+{
+    auto nelem = (last - first);
+    assert(nelem >= 0);
+    if (nelem < 2) return;
+    std::vector<Iter_t> index;
+    index.reserve((size_t) nelem);
+    create_index(first, last, index);
+    less_ptr_no_null<Iter_t, Compare> index_comp(comp);
+    method(index.begin(), index.end(), index_comp);
+    sort_index(first, index);
+};
+
+//
+//****************************************************************************
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/merge_four.hpp b/vendor/boost/sort/common/merge_four.hpp
new file mode 100644
index 00000000..edfb2ffc
--- /dev/null
+++ b/vendor/boost/sort/common/merge_four.hpp
@@ -0,0 +1,327 @@
+//----------------------------------------------------------------------------
+/// @file merge_four.hpp
+/// @brief This file have the functions for to merge 4 buffers
+///
+/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_MERGE_FOUR_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_UTIL_MERGE_FOUR_HPP
+
+#include <boost/sort/common/util/traits.hpp>
+#include <boost/sort/common/range.hpp>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+
+//
+//############################################################################
+//                                                                          ##
+//                       F U S I O N     O F                                ##
+//                                                                          ##
+//              F O U R     E L E M E N T S    R A N G E                    ##
+//                                                                          ##
+//############################################################################
+//
+
+//-----------------------------------------------------------------------------
+//  function : less_range
+/// @brief Compare the elements pointed by it1 and it2, and if they
+///        are equals, compare their position, doing a stable comparison
+///
+/// @param it1 : iterator to the first element
+/// @param pos1 : position of the object pointed by it1
+/// @param it2 : iterator to the second element
+/// @param pos2 : position of the element pointed by it2
+/// @param comp : comparison object
+/// @return result of the comparison
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Compare = typename util::compare_iter<Iter_t> >
+inline bool less_range(Iter_t it1, uint32_t pos1, Iter_t it2, uint32_t pos2,
+                       Compare comp = Compare())
+{
+    return (comp(*it1, *it2)) ? true :
+           (pos2 < pos1) ? false : not (comp(*it2, *it1));
+};
+
+//-----------------------------------------------------------------------------
+//  function : full_merge4
+/// @brief Merge four ranges
+///
+/// @param dest: range where move the elements merged. Their size must be
+///              greater or equal than the sum of the sizes of the ranges
+///              in vrange_input
+/// @param vrange_input : array of ranges to merge
+/// @param nrange_input : number of ranges in vrange_input
+/// @param comp : comparison object
+/// @return range with all the elements moved with the size adjusted
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+range<Iter1_t> full_merge4(const range<Iter1_t> &rdest,
+                           range<Iter2_t> vrange_input[4],
+                           uint32_t nrange_input, Compare comp)
+{
+    typedef range<Iter1_t> range1_t;
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+
+    size_t ndest = 0;
+    uint32_t i = 0;
+    while (i < nrange_input)
+    {
+        if (vrange_input[i].size() != 0)
+        {
+            ndest += vrange_input[i++].size();
+        }
+        else
+        {
+            for (uint32_t k = i + 1; k < nrange_input; ++k)
+            {
+                vrange_input[k - 1] = vrange_input[k];
+            };
+            --nrange_input;
+        };
+    };
+
+    if (nrange_input == 0) return range1_t(rdest.first, rdest.first);
+    if (nrange_input == 1) return move_forward(rdest, vrange_input[0]);
+    if (nrange_input == 2)
+    {
+        return merge(rdest, vrange_input[0], vrange_input[1], comp);
+    };
+
+    //------------------------------------------------------------------------
+    // Initial sort
+    //------------------------------------------------------------------------
+    uint32_t pos[4] =
+    { 0, 1, 2, 3 }, npos = nrange_input;
+
+    //-----------------------------------------------------------------------
+    // thanks to Steven Ross by their suggestion about the optimal
+    // sorting networks
+    //-----------------------------------------------------------------------
+    if (less_range(vrange_input[pos[1]].first, pos[1],
+                    vrange_input[pos[0]].first, pos[0], comp))
+    {
+        std::swap(pos[0], pos[1]);
+    };
+    if (npos == 4 and less_range(vrange_input[pos[3]].first, pos[3],
+                                 vrange_input[pos[2]].first, pos[2], comp))
+    {
+        std::swap(pos[3], pos[2]);
+    };
+    if (less_range (vrange_input[pos[2]].first, pos[2],
+                    vrange_input[pos[0]].first, pos[0], comp))
+    {
+        std::swap(pos[0], pos[2]);
+    };
+    if (npos == 4
+                    and less_range (vrange_input[pos[3]].first, pos[3],
+                                    vrange_input[pos[1]].first, pos[1], comp))
+    {
+        std::swap(pos[1], pos[3]);
+    };
+    if (less_range (vrange_input[pos[2]].first, pos[2],
+                    vrange_input[pos[1]].first, pos[1], comp))
+    {
+        std::swap(pos[1], pos[2]);
+    };
+
+    Iter1_t it_dest = rdest.first;
+    while (npos > 2)
+    {
+        *(it_dest++) = std::move(*(vrange_input[pos[0]].first++));
+        if (vrange_input[pos[0]].size() == 0)
+        {
+            pos[0] = pos[1];
+            pos[1] = pos[2];
+            pos[2] = pos[3];
+            --npos;
+        }
+        else
+        {
+            if (less_range(vrange_input[pos[1]].first, pos[1],
+                            vrange_input[pos[0]].first, pos[0], comp))
+            {
+                std::swap(pos[0], pos[1]);
+                if (less_range(vrange_input[pos[2]].first, pos[2],
+                                vrange_input[pos[1]].first, pos[1], comp))
+                {
+                    std::swap(pos[1], pos[2]);
+                    if (npos == 4
+                                    and less_range(vrange_input[pos[3]].first,
+                                                    pos[3],
+                                                    vrange_input[pos[2]].first,
+                                                    pos[2], comp))
+                    {
+                        std::swap(pos[2], pos[3]);
+                    };
+                };
+            };
+        };
+    };
+
+    range1_t raux1(rdest.first, it_dest), raux2(it_dest, rdest.last);
+    if (pos[0] < pos[1])
+    {
+        return concat(raux1,merge(raux2, vrange_input[pos[0]], 
+                                  vrange_input[pos[1]], comp));
+    }
+    else
+    {
+        return concat(raux1, merge (raux2, vrange_input[pos[1]], 
+                                    vrange_input[pos[0]], comp));
+    };
+};
+
+//-----------------------------------------------------------------------------
+//  function : uninit_full_merge4
+/// @brief Merge four ranges and put the result in uninitialized memory
+///
+/// @param dest: range where create and move the elements merged. Their
+///              size must be greater or equal than the sum of the sizes
+///              of the ranges in the array R
+/// @param vrange_input : array of ranges to merge
+/// @param nrange_input : number of ranges in vrange_input
+/// @param comp : comparison object
+/// @return range with all the elements move with the size adjusted
+//-----------------------------------------------------------------------------
+template<class Value_t, class Iter_t, class Compare>
+range<Value_t *> uninit_full_merge4(const range<Value_t *> &dest,
+                                    range<Iter_t> vrange_input[4],
+                                    uint32_t nrange_input, Compare comp)
+{
+    typedef util::value_iter<Iter_t> type1;
+    static_assert (std::is_same< type1, Value_t >::value,
+                    "Incompatible iterators\n");
+
+    size_t ndest = 0;
+    uint32_t i = 0;
+    while (i < nrange_input)
+    {
+        if (vrange_input[i].size() != 0)
+        {
+            ndest += vrange_input[i++].size();
+        }
+        else
+        {
+            for (uint32_t k = i + 1; k < nrange_input; ++k)
+            {
+                vrange_input[k - 1] = vrange_input[k];
+            };
+            --nrange_input;
+        };
+    };
+    if (nrange_input == 0) return range<Value_t *>(dest.first, dest.first);
+    if (nrange_input == 1) return move_construct(dest, vrange_input[0]);
+    if (nrange_input == 2)
+    {
+        return merge_construct(dest, vrange_input[0], vrange_input[1], comp);
+    };
+
+    //------------------------------------------------------------------------
+    // Initial sort
+    //------------------------------------------------------------------------
+    uint32_t pos[4] = { 0, 1, 2, 3 }, npos = nrange_input;
+
+    //-----------------------------------------------------------------------
+    // thanks to Steven Ross by their suggestion about the optimal
+    // sorting networks
+    //-----------------------------------------------------------------------
+    if (less_range(vrange_input[pos[1]].first, pos[1],
+                    vrange_input[pos[0]].first, pos[0], comp))
+    {
+        std::swap(pos[0], pos[1]);
+    };
+    if (npos == 4  and less_range(vrange_input[pos[3]].first, pos[3],
+                                  vrange_input[pos[2]].first, pos[2], comp))
+    {
+        std::swap(pos[3], pos[2]);
+    };
+    if (less_range(vrange_input[pos[2]].first, pos[2],
+                    vrange_input[pos[0]].first, pos[0], comp))
+    {
+        std::swap(pos[0], pos[2]);
+    };
+    if (npos == 4 and less_range(vrange_input[pos[3]].first, pos[3],
+                                 vrange_input[pos[1]].first, pos[1], comp))
+    {
+        std::swap(pos[1], pos[3]);
+    };
+    if (less_range(vrange_input[pos[2]].first, pos[2],
+                    vrange_input[pos[1]].first, pos[1], comp))
+    {
+        std::swap(pos[1], pos[2]);
+    };
+
+    Value_t *it_dest = dest.first;
+    while (npos > 2)
+    {
+        util::construct_object(&(*(it_dest++)),
+                        std::move(*(vrange_input[pos[0]].first++)));
+        if (vrange_input[pos[0]].size() == 0)
+        {
+            pos[0] = pos[1];
+            pos[1] = pos[2];
+            pos[2] = pos[3];
+            --npos;
+        }
+        else
+        {
+            if (less_range (vrange_input[pos[1]].first, pos[1],
+                            vrange_input[pos[0]].first, pos[0], comp))
+            {
+                std::swap(pos[0], pos[1]);
+                if (less_range (vrange_input[pos[2]].first, pos[2],
+                                vrange_input[pos[1]].first, pos[1], comp))
+                {
+                    std::swap(pos[1], pos[2]);
+                    if (npos == 4 and less_range(vrange_input[pos[3]].first,
+                                                 pos[3],
+                                                 vrange_input[pos[2]].first,
+                                                 pos[2], comp))
+                    {
+                        std::swap(pos[2], pos[3]);
+                    };
+                };
+            };
+        };
+    }; // end while (npos > 2)
+
+    range<Value_t *> raux1(dest.first, it_dest), raux2(it_dest, dest.last);
+    if (pos[0] < pos[1])
+    {
+        return concat(raux1,
+                      merge_construct(raux2, vrange_input[pos[0]],
+                                      vrange_input[pos[1]], comp));
+    }
+    else
+    {
+        return concat(raux1,
+                      merge_construct(raux2, vrange_input[pos[1]],
+                                      vrange_input[pos[0]], comp));
+    };
+};
+
+//****************************************************************************
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/merge_vector.hpp b/vendor/boost/sort/common/merge_vector.hpp
new file mode 100644
index 00000000..84afea5a
--- /dev/null
+++ b/vendor/boost/sort/common/merge_vector.hpp
@@ -0,0 +1,196 @@
+//----------------------------------------------------------------------------
+/// @file merge_vector.hpp
+/// @brief In this file have the functions for to do a stable merge of
+//         ranges, in a vector
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_MERGE_VECTOR_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_UTIL_MERGE_VECTOR_HPP
+
+#include <boost/sort/common/merge_four.hpp>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+
+//############################################################################
+//                                                                          ##
+//                       F U S I O N     O F                                ##
+//                                                                          ##
+//              A  V E C T O R   O F    R A N G E S                         ##
+//                                                                          ##
+//############################################################################
+
+//
+//-----------------------------------------------------------------------------
+//  function : merge_level4
+/// @brief merge the ranges in the vector v_input with the full_merge4 function.
+///        The v_output vector is used as auxiliary memory in the internal
+///        process. The final results is in the dest range.
+///        All the ranges of v_output are inside the range dest
+/// @param dest : range where move the elements merged
+/// @param v_input : vector of ranges to merge
+/// @param v_output : vector of ranges obtained
+/// @param comp : comparison object
+/// @return range with all the elements moved
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+void merge_level4(range<Iter1_t> dest, std::vector<range<Iter2_t> > &v_input,
+                  std::vector<range<Iter1_t> > &v_output, Compare comp)
+{
+    typedef range<Iter1_t> range1_t;
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+
+    v_output.clear();
+    if (v_input.size() == 0) return;
+    if (v_input.size() == 1)
+    {
+        v_output.emplace_back(move_forward(dest, v_input[0]));
+        return;
+    };
+
+    uint32_t nrange = v_input.size();
+    uint32_t pos_ini = 0;
+    while (pos_ini < v_input.size())
+    {
+        uint32_t nmerge = (nrange + 3) >> 2;
+        uint32_t nelem = (nrange + nmerge - 1) / nmerge;
+        range1_t rz = full_merge4(dest, &v_input[pos_ini], nelem, comp);
+        v_output.emplace_back(rz);
+        dest.first = rz.last;
+        pos_ini += nelem;
+        nrange -= nelem;
+    };
+    return;
+};
+//
+//-----------------------------------------------------------------------------
+//  function : uninit_merge_level4
+/// @brief merge the ranges moving the objects and constructing them in
+///        uninitialized memory, in the vector v_input
+///        using full_merge4. The v_output vector is used as auxiliary memory
+///        in the internal process. The final results is in the dest range.
+///        All the ranges of v_output are inside the range dest
+///
+/// @param dest : range where move the elements merged
+/// @param v_input : vector of ranges to merge
+/// @param v_output : vector of ranges obtained
+/// @param comp : comparison object
+/// @return range with all the elements moved and constructed
+//-----------------------------------------------------------------------------
+template<class Value_t, class Iter_t, class Compare>
+void uninit_merge_level4(range<Value_t *> dest,
+                         std::vector<range<Iter_t> > &v_input,
+                         std::vector<range<Value_t *> > &v_output, Compare comp)
+{
+    typedef range<Value_t *> range1_t;
+    typedef util::value_iter<Iter_t> type1;
+    static_assert (std::is_same< type1, Value_t >::value,
+                    "Incompatible iterators\n");
+
+    v_output.clear();
+    if (v_input.size() == 0) return;
+    if (v_input.size() == 1)
+    {
+        v_output.emplace_back(move_construct(dest, v_input[0]));
+        return;
+    };
+
+    uint32_t nrange = v_input.size();
+    uint32_t pos_ini = 0;
+    while (pos_ini < v_input.size())
+    {
+        uint32_t nmerge = (nrange + 3) >> 2;
+        uint32_t nelem = (nrange + nmerge - 1) / nmerge;
+        range1_t rz = uninit_full_merge4(dest, &v_input[pos_ini], nelem, comp);
+        v_output.emplace_back(rz);
+        dest.first = rz.last;
+        pos_ini += nelem;
+        nrange -= nelem;
+    };
+    return;
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge_vector4
+/// @brief merge the ranges in the vector v_input using the merge_level4
+///        function. The v_output vector is used as auxiliary memory in the
+///        internal process
+///        The final results is in the range_output range.
+///        All the ranges of v_output are inside the range range_output
+///        All the ranges of v_input are inside the range range_input
+/// @param range_input : range including all the ranges of v_input
+/// @param ange_output : range including all the elements of v_output
+/// @param v_input : vector of ranges to merge
+/// @param v_output : vector of ranges obtained
+/// @param comp : comparison object
+/// @return range with all the elements moved
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+range<Iter2_t> merge_vector4(range<Iter1_t> range_input,
+                             range<Iter2_t> range_output,
+                             std::vector<range<Iter1_t> > &v_input,
+                             std::vector<range<Iter2_t> > &v_output,
+                             Compare comp)
+{
+    typedef range<Iter2_t> range2_t;
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+
+    v_output.clear();
+    if (v_input.size() == 0)
+    {
+        return range2_t(range_output.first, range_output.first);
+    };
+    if (v_input.size() == 1)
+    {
+        return move_forward(range_output, v_input[0]);
+    };
+    bool sw = false;
+    uint32_t nrange = v_input.size();
+
+    while (nrange > 1)
+    {
+        if (sw)
+        {
+            merge_level4(range_input, v_output, v_input, comp);
+            sw = false;
+            nrange = v_input.size();
+        }
+        else
+        {
+            merge_level4(range_output, v_input, v_output, comp);
+            sw = true;
+            nrange = v_output.size();
+        };
+    };
+    return (sw) ? v_output[0] : move_forward(range_output, v_input[0]);
+};
+
+//****************************************************************************
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/range.hpp b/vendor/boost/sort/common/range.hpp
new file mode 100644
index 00000000..072d98a9
--- /dev/null
+++ b/vendor/boost/sort/common/range.hpp
@@ -0,0 +1,399 @@
+//----------------------------------------------------------------------------
+/// @file range.hpp
+/// @brief Define a range [first, last), and the associated operations
+///
+/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanyingfile LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
+
+#include <boost/sort/common/util/algorithm.hpp>
+#include <boost/sort/common/util/merge.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <cassert>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+
+///---------------------------------------------------------------------------
+/// @struct range
+/// @brief this represent a range between two iterators
+/// @remarks
+//----------------------------------------------------------------------------
+template <class Iter_t>
+struct range
+{
+    Iter_t first, last;
+    //
+    //------------------------------------------------------------------------
+    //  function : range
+    /// @brief  empty constructor
+    //------------------------------------------------------------------------
+    range(void) { };
+    //
+    //------------------------------------------------------------------------
+    //  function : range
+    /// @brief  constructor with two parameters
+    /// @param frs : iterator to the first element
+    /// @param lst : iterator to the last element
+    //-----------------------------------------------------------------------
+    range(const Iter_t &frs, const Iter_t &lst): first(frs), last(lst) { };
+    //
+    //-----------------------------------------------------------------------
+    //  function : empty
+    /// @brief indicate if the range is empty
+    /// @return  true : empty false : not empty
+    //-----------------------------------------------------------------------
+    bool empty(void) const { return (first == last); };
+    //
+    //-----------------------------------------------------------------------
+    //  function : not_empty
+    /// @brief indicate if the range is not empty
+    /// @return  true : not empty false : empty
+    //-----------------------------------------------------------------------
+    bool not_empty(void) const {return (first != last); };
+    //
+    //-----------------------------------------------------------------------
+    //  function : valid
+    /// @brief  Indicate if the range is well constructed, and valid
+    /// @return true : valid,  false : not valid
+    //-----------------------------------------------------------------------
+    bool valid(void) const { return ((last - first) >= 0); };
+    //
+    //-----------------------------------------------------------------------
+    //  function : size
+    /// @brief  return the size of the range
+    /// @return size
+    //-----------------------------------------------------------------------
+    size_t size(void) const { return (last - first); };
+    //
+    //------------------------------------------------------------------------
+    //  function : front
+    /// @brief return an iterator to the first element of the range
+    /// @return iterator
+    //-----------------------------------------------------------------------
+    Iter_t front(void) const { return first; };
+    //
+    //-------------------------------------------------------------------------
+    //  function : back
+    /// @brief return an iterator to the last element of the range
+    /// @return iterator
+    //-------------------------------------------------------------------------
+    Iter_t back(void) const {return (last - 1); };
+};
+
+//
+//-----------------------------------------------------------------------------
+//  function : concat
+/// @brief concatenate two contiguous ranges
+/// @param it1 : first range
+/// @param it2 : second range
+/// @return  range resulting of the concatenation
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+inline range<Iter_t> concat(const range<Iter_t> &it1, const range<Iter_t> &it2)
+{
+    return range<Iter_t>(it1.first, it2.last);
+}
+;
+//
+//-----------------------------------------------------------------------------
+//  function : move_forward
+/// @brief Move initialized objets from the range src to dest
+/// @param dest : range where move the objects
+/// @param src : range from where move the objects
+/// @return range with the objects moved and the size adjusted
+//-----------------------------------------------------------------------------
+template <class Iter1_t, class Iter2_t>
+inline range<Iter2_t> move_forward(const range<Iter2_t> &dest,
+                                   const range<Iter1_t> &src)
+{
+    assert(dest.size() >= src.size());
+    Iter2_t it_aux = util::move_forward(dest.first, src.first, src.last);
+    return range<Iter2_t>(dest.first, it_aux);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : move_backward
+/// @brief Move initialized objets from the range src to dest
+/// @param dest : range where move the objects
+/// @param src : range from where move the objects
+/// @return range with the objects moved and the size adjusted
+//-----------------------------------------------------------------------------
+template <class Iter1_t, class Iter2_t>
+inline range<Iter2_t> move_backward(const range<Iter2_t> &dest,
+                                    const range<Iter1_t> &src)
+{
+    assert(dest.size() >= src.size());
+    Iter2_t it_aux = util::move_backward(dest.first + src.size(), src.first,
+                    src.last);
+    return range<Iter2_t>(dest.first, dest.src.size());
+};
+
+//-----------------------------------------------------------------------------
+//  function : uninit_move
+/// @brief Move uninitialized objets from the range src creating them in  dest
+///
+/// @param dest : range where move and create the objects
+/// @param src : range from where move the objects
+/// @return range with the objects moved and the size adjusted
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
+inline range<Value_t*> move_construct(const range<Value_t*> &dest,
+                                      const range<Iter_t> &src)
+{
+    Value_t *ptr_aux = util::move_construct(dest.first, src.first, src.last);
+    return range<Value_t*>(dest.first, ptr_aux);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : destroy
+/// @brief destroy a range of objects
+/// @param rng : range to destroy
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+inline void destroy(range<Iter_t> rng)
+{
+    util::destroy(rng.first, rng.last);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : initialize
+/// @brief initialize a range of objects with the object val moving across them
+/// @param rng : range of elements not initialized
+/// @param val : object used for the initialization
+/// @return range initialized
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
+inline range<Iter_t> initialize(const range<Iter_t> &rng, Value_t &val)
+{
+    util::initialize(rng.first, rng.last, val);
+    return rng;
+};
+//
+//-----------------------------------------------------------------------------
+//  function : is_mergeable
+/// @brief : indicate if two ranges have a possible merge
+/// @param src1 : first range
+/// @param src2 : second range
+/// @param comp : object for to compare elements
+/// @return true : they can be merged
+///         false : they can't be merged
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+inline bool is_mergeable(const range<Iter1_t> &src1, const range<Iter2_t> &src2,
+                         Compare comp)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+    //------------------------------------------------------------------------
+    //                 Code
+    //------------------------------------------------------------------------
+    return comp(*(src2.front()), *(src1.back()));
+};
+//
+//-----------------------------------------------------------------------------
+//  function : is_mergeable_stable
+/// @brief : indicate if two ranges have a possible merge
+/// @param src1 : first range
+/// @param src2 : second range
+/// @param comp : object for to compare elements
+/// @return true : they can be merged
+///         false : they can't be merged
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+inline bool is_mergeable_stable(const range<Iter1_t> &src1,
+                                const range<Iter2_t> &src2, Compare comp)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+    //------------------------------------------------------------------------
+    //                 Code
+    //------------------------------------------------------------------------
+    return not comp(*(src1.back()), *(src2.front()));
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge
+/// @brief Merge two contiguous ranges src1 and src2, and put the result in
+///        the range dest, returning the range merged
+///
+/// @param dest : range where locate the lements merged. the size of dest
+///               must be  greater or equal than the sum of the sizes of
+///               src1 and src2
+/// @param src1 : first range to merge
+/// @param src2 : second range to merge
+/// @param comp : comparison object
+/// @return range with the elements merged and the size adjusted
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
+inline range<Iter3_t> merge(const range<Iter3_t> &dest,
+                            const range<Iter1_t> &src1,
+                            const range<Iter2_t> &src2, Compare comp)
+{
+    Iter3_t it_aux = util::merge(src1.first, src1.last, src2.first, src2.last,
+                    dest.first, comp);
+    return range<Iter3_t>(dest.first, it_aux);
+};
+
+//-----------------------------------------------------------------------------
+//  function : merge_construct
+/// @brief Merge two contiguous uninitialized ranges src1 and src2, and create
+///        and move the result in the uninitialized range dest, returning the
+///        range merged
+//
+/// @param dest : range where locate the elements merged. the size of dest
+///               must be  greater or equal than the sum of the sizes of
+///               src1 and src2. Initially is uninitialize memory
+/// @param src1 : first range to merge
+/// @param src2 : second range to merge
+/// @param comp : comparison object
+/// @return range with the elements merged and the size adjusted
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Value_t, class Compare>
+inline range<Value_t *> merge_construct(const range<Value_t *> &dest,
+                                        const range<Iter1_t> &src1,
+                                        const range<Iter2_t> &src2,
+                                        Compare comp)
+{
+    Value_t * ptr_aux = util::merge_construct(src1.first, src1.last, src2.first,
+                    src2.last, dest.first, comp);
+    return range<Value_t*>(dest.first, ptr_aux);
+};
+//
+//---------------------------------------------------------------------------
+//  function : half_merge
+/// @brief : Merge two initialized buffers. The first buffer is in a separate
+///          memory
+//
+/// @param dest : range where finish the two buffers merged
+/// @param src1 : first range to merge in a separate memory
+/// @param src2 : second range to merge, in the final part of the
+///               range where deposit the final results
+/// @param comp : object for compare two elements of the type pointed
+///               by the Iter1_t and Iter2_t
+/// @return : range with the two buffers merged
+//---------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+inline range<Iter2_t> merge_half(const range<Iter2_t> &dest,
+                                 const range<Iter1_t> &src1,
+                                 const range<Iter2_t> &src2, Compare comp)
+{
+    Iter2_t it_aux = util::merge_half(src1.first, src1.last, src2.first,
+                    src2.last, dest.first, comp);
+    return range<Iter2_t>(dest.first, it_aux);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge_uncontiguous
+/// @brief : merge two non contiguous ranges src1, src2, using the range
+///          aux as auxiliary memory. The results are in the original ranges
+//
+/// @param src1 : first range to merge
+/// @param src2 : second range to merge
+/// @param aux : auxiliary range used in the merge
+/// @param comp : object for to compare elements
+/// @return true : not changes done, false : changes in the buffers
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
+inline bool merge_uncontiguous(const range<Iter1_t> &src1,
+                               const range<Iter2_t> &src2,
+                               const range<Iter3_t> &aux, Compare comp)
+{
+    return util::merge_uncontiguous(src1.first, src1.last, src2.first,
+                    src2.last, aux.first, comp);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge_contiguous
+/// @brief : merge two contiguous ranges ( src1, src2) using buf as
+///          auxiliary memory. The results are in the same ranges
+/// @param src1 : first range to merge
+/// @param src1 : second range to merge
+/// @param buf : auxiliary memory used in the merge
+/// @param comp : object for to compare elements
+/// @return true : not changes done,   false : changes in the buffers
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+inline range<Iter1_t> merge_contiguous(const range<Iter1_t> &src1,
+                                       const range<Iter1_t> &src2,
+                                       const range<Iter2_t> &buf, Compare comp)
+{
+    util::merge_contiguous(src1.first, src1.last, src2.last, buf.first, comp);
+    return concat(src1, src2);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge_flow
+/// @brief : merge two ranges, as part of a merge the ranges in a list. This
+///         function reduce the number of movements compared with inplace_merge
+///         when you need to merge a sequence of ranges.
+///         This function merge the ranges rbuf and rng2, and the results
+///          are in rng1 and rbuf
+//
+/// @param rng1 : range where locate the first elements of the merge
+/// @param rbuf : range which provide the first elements, and where store
+///               the last results of the merge
+/// @param rng2 : range which provide the last elements to merge
+/// @param comp : object for to compare elements
+/// @return true : not changes done,  false : changes in the buffers
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static void merge_flow(range<Iter1_t> rng1, range<Iter2_t> rbuf,
+                       range<Iter1_t> rng2, Compare cmp)
+{
+    //-------------------------------------------------------------------------
+    //                       Metaprogramming
+    //-------------------------------------------------------------------------
+    typedef util::value_iter<Iter1_t> type1;
+    typedef util::value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                       Code
+    //-------------------------------------------------------------------------
+    range<Iter2_t> rbx(rbuf);
+    range<Iter1_t> rx1(rng1), rx2(rng2);
+    assert(rbx.size() == rx1.size() and rx1.size() == rx2.size());
+    while (rx1.first != rx1.last)
+    {
+        *(rx1.first++) = (cmp(*rbx.first, *rx2.first)) ?
+                                                    std::move(*(rbx.first++)):
+                                                    std::move(*(rx2.first++));
+    };
+    if (rx2.first == rx2.last) return;
+    if (rbx.first == rbx.last) move_forward(rbuf, rng2);
+    else                       merge_half(rbuf, rx2, rbx, cmp);
+};
+
+//****************************************************************************
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/util/algorithm.hpp b/vendor/boost/sort/common/util/algorithm.hpp
new file mode 100644
index 00000000..db7607aa
--- /dev/null
+++ b/vendor/boost/sort/common/util/algorithm.hpp
@@ -0,0 +1,309 @@
+//----------------------------------------------------------------------------
+/// @file algorithm.hpp
+/// @brief low level functions of create, destroy, move and merge functions
+///
+/// @author Copyright (c) 2017 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_COMMON_UTIL_ALGORITHM_HPP
+#define __BOOST_SORT_COMMON_UTIL_ALGORITHM_HPP
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+#include <boost/sort/common/util/traits.hpp>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+//
+//###########################################################################
+//
+//                       I M P O R T A N T
+//
+// The functions of this file are for internal use only
+// All the operations are done with move operations, because the copy
+// operations are unnecesary
+//
+//###########################################################################
+//
+//----------------------------------------------------------------------------
+//
+//         F U N C T I O N S   I N   T H E   F I L E
+//
+//----------------------------------------------------------------------------
+//
+// static inline uint32_t nbits32 (uint32_t num) noexcept
+//
+// static inline uint32_t nbits64 (uint64_t num)
+//
+// template < class Value_t, class... Args >
+// inline void construct_object (Value_t *ptr, Args &&... args)
+//
+// template < class Value_t >
+// inline void destroy_object (Value_t *ptr)
+//
+// template < class Iter_t, class Value_t = value_iter<Iter_t> >
+// void initialize (Iter_t first, Iter_t last, Value_t && val)
+//
+// template < class Iter1_t, class Iter2_t >
+// Iter2_t move_forward (Iter2_t it_dest, Iter1_t first, Iter1_t last)
+//
+// template < class Iter1_t, class Iter2_t >
+// Iter2_t move_backward (Iter2_t it_dest, Iter1_t first, Iter1_t last)
+//
+// template < class Iter_t, class Value_t = value_iter< Iter_t > >
+// Value_t * move_construct (Value_t *ptr, Iter_t first, Iter_t last)
+//
+// template < class Iter_t >
+// void destroy (Iter_t first, const Iter_t last)
+//
+// template < class Iter_t >
+// void reverse (Iter_t first, const Iter_t last)
+//
+//----------------------------------------------------------------------------
+//
+//--------------------------------------------------------------------------
+//
+//                    G L O B A L     V A R I B L E S
+//
+//--------------------------------------------------------------------------
+//
+// this array represent the number of bits needed for to represent the
+// first 256 numbers
+static constexpr const uint32_t tmsb[256] =
+{ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+                5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+                6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7,
+                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+                8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 };
+//
+//---------------------------------------------------------------------------
+//
+//                           F U N C T I O N S
+//
+//---------------------------------------------------------------------------
+//
+//---------------------------------------------------------------------------
+//  function : nbits32
+/// @brief Obtain the number of bits of a number equal or greater than num
+/// @param num : Number to examine
+/// @return Number of bits
+//---------------------------------------------------------------------------
+static inline uint32_t nbits32 (uint32_t num) noexcept
+{
+    int Pos = (num & 0xffff0000U) ? 16 : 0;
+    if ((num >> Pos) & 0xff00U) Pos += 8;
+    return (tmsb[num >> Pos] + Pos);
+}
+//
+//---------------------------------------------------------------------------
+//  function : nbits64
+/// @brief Obtain the number of bits of a number equal or greater than num
+/// @param num : Number to examine
+/// @exception none
+/// @return Number of bits
+//---------------------------------------------------------------------------
+static inline uint32_t nbits64(uint64_t num)noexcept
+{
+    uint32_t Pos = (num & 0xffffffff00000000ULL) ? 32 : 0;
+    if ((num >> Pos) & 0xffff0000ULL) Pos += 16;
+    if ((num >> Pos) & 0xff00ULL) Pos += 8;
+    return (tmsb[num >> Pos] + Pos);
+}
+//
+//-----------------------------------------------------------------------------
+//  function : construct_object
+/// @brief create an object in the memory specified by ptr
+///
+/// @param ptr : pointer to the memory where to create the object
+/// @param args : arguments to the constructor
+//-----------------------------------------------------------------------------
+template <class Value_t, class ... Args>
+inline void construct_object (Value_t *ptr, Args &&... args)
+{
+    (::new (static_cast<void *>(ptr)) Value_t(std::forward< Args > (args)...));
+};
+//
+//-----------------------------------------------------------------------------
+//  function : destroy_object
+/// @brief destroy an object in the memory specified by ptr
+/// @param ptr : pointer to the object to destroy
+//-----------------------------------------------------------------------------
+template<class Value_t>
+inline void destroy_object(Value_t *ptr)
+{
+    ptr->~Value_t();
+};
+//
+//-----------------------------------------------------------------------------
+//  function : initialize
+/// @brief initialize a range of objects with the object val moving across them
+///
+/// @param first : itertor to the first element to initialize
+/// @param last : iterator to the last element to initialize
+/// @param val : object used for the initialization
+//-----------------------------------------------------------------------------
+template <class Iter_t, class Value_t = value_iter<Iter_t> >
+inline void initialize (Iter_t first, Iter_t last, Value_t & val)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter_t> value_t;
+    static_assert (std::is_same< Value_t, value_t >::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                 Code
+    //------------------------------------------------------------------------
+    if (first == last) return;
+    construct_object(&(*first), std::move(val));
+
+    Iter_t it1 = first, it2 = first + 1;
+    while (it2 != last)
+    {
+        construct_object(&(*(it2++)), std::move(*(it1++)));
+    };
+    val = std::move(*(last - 1));
+};
+//
+//-----------------------------------------------------------------------------
+//  function : move_forward
+/// @brief Move initialized objets
+/// @param it_dest : iterator to the final place of the objects
+/// @param first : iterator to the first element to move
+/// @param last : iterator to the last element to move
+/// @return Output iterator to the element past the last element
+///         moved (it_dest + (last - first))
+//-----------------------------------------------------------------------------
+template <class Iter1_t, class Iter2_t>
+inline Iter2_t move_forward (Iter2_t it_dest, Iter1_t first, Iter1_t last)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value1_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value1_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                 Code
+    //------------------------------------------------------------------------
+    while (first != last)
+    {   *it_dest++ = std::move(*first++);
+    }
+    return it_dest;
+
+};
+//
+//-----------------------------------------------------------------------------
+//  function : move_backard
+/// @brief Move initialized objets in reverse order
+/// @param it_dest : last iterator to the final place of the objects
+/// @param first : iterator to the first element to move
+/// @param last : iterator to the last element to move
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t>
+inline Iter2_t move_backward(Iter2_t it_dest, Iter1_t  first, Iter1_t last)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value1_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value1_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                 Code
+    //------------------------------------------------------------------------
+    while (first != last)
+    {   *(--it_dest) = std::move (*(--last));
+    }
+    return it_dest;
+};
+
+//
+//-----------------------------------------------------------------------------
+//  function : move_construct
+/// @brief Move objets to uninitialized memory
+///
+/// @param ptr : pointer to the memory where to create the objects
+/// @param first : iterator to the first element to move
+/// @param last : iterator to the last element to move
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Value_t = value_iter<Iter_t> >
+inline Value_t * move_construct(Value_t *ptr, Iter_t first, Iter_t last)
+{
+    //------------------------------------------------------------------------
+    //                  Metaprogramming
+    //------------------------------------------------------------------------
+    typedef typename iterator_traits<Iter_t>::value_type value2_t;
+    static_assert (std::is_same< Value_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                    Code
+    //------------------------------------------------------------------------
+    while (first != last)
+    {
+        ::new (static_cast<void *>(ptr++)) Value_t(std::move(*(first++)));
+    };
+    return ptr;
+};
+//
+//-----------------------------------------------------------------------------
+//  function : destroy
+/// @brief destroy the elements between first and last
+/// @param first : iterator to the first element to destroy
+/// @param last : iterator to the last element to destroy
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+inline void destroy(Iter_t first, const Iter_t last)
+{
+    while (first != last)
+        destroy_object(&(*(first++)));
+};
+//
+//-----------------------------------------------------------------------------
+//  function : reverse
+/// @brief destroy the elements between first and last
+/// @param first : iterator to the first element to destroy
+/// @param last : iterator to the last element to destroy
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+inline void reverse(Iter_t first, Iter_t last)
+{
+    std::reverse ( first, last);
+};
+//
+//****************************************************************************
+};//    End namespace util
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/util/atomic.hpp b/vendor/boost/sort/common/util/atomic.hpp
new file mode 100644
index 00000000..15906fe5
--- /dev/null
+++ b/vendor/boost/sort/common/util/atomic.hpp
@@ -0,0 +1,98 @@
+//----------------------------------------------------------------------------
+/// @file atomic.hpp
+/// @brief Basic layer for to simplify the use of atomic functions
+/// @author Copyright(c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_ATOMIC_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_UTIL_ATOMIC_HPP
+
+#include <atomic>
+#include <cassert>
+#include <type_traits>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+//-----------------------------------------------------------------------------
+//  function : atomic_read
+/// @brief make the atomic read of an atomic variable, using a memory model
+/// @param at_var : atomic variable to read
+/// @return value obtained
+//-----------------------------------------------------------------------------
+template<typename T>
+inline T atomic_read(std::atomic<T> &at_var)
+{
+    return std::atomic_load_explicit < T > (&at_var, std::memory_order_acquire);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : atomic_add
+/// @brief Add a number to an atomic variable, using a memory model
+/// @param at_var : variable to add
+/// @param num : value to add to at_var
+/// @return result of the operation
+//-----------------------------------------------------------------------------
+template<typename T, typename T2>
+inline T atomic_add(std::atomic<T> &at_var, T2 num)
+{
+    static_assert (std::is_integral< T2 >::value, "Bad parameter");
+    return std::atomic_fetch_add_explicit <T> 
+                               (&at_var, (T) num, std::memory_order_acq_rel);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : atomic_sub
+/// @brief Atomic subtract of an atomic variable using memory model
+/// @param at_var : Varibale to subtract
+/// @param num : value to sub to at_var
+/// @return result of the operation
+//-----------------------------------------------------------------------------
+template<typename T, typename T2>
+inline T atomic_sub(std::atomic<T> &at_var, T2 num)
+{
+    static_assert (std::is_integral< T2 >::value, "Bad parameter");
+    return std::atomic_fetch_sub_explicit <T> 
+                                (&at_var, (T) num, std::memory_order_acq_rel);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : atomic_write
+/// @brief Write a value in an atomic variable using memory model
+/// @param at_var : varible to write
+/// @param num : value to write in at_var
+//-----------------------------------------------------------------------------
+template<typename T, typename T2>
+inline void atomic_write(std::atomic<T> &at_var, T2 num)
+{
+    static_assert (std::is_integral< T2 >::value, "Bad parameter");
+    std::atomic_store_explicit <T> 
+                                (&at_var, (T) num, std::memory_order_release);
+};
+template<typename T>
+struct counter_guard
+{
+    typedef std::atomic<T> atomic_t;
+    atomic_t &count;
+
+    counter_guard(atomic_t & counter): count(counter) { };
+    ~counter_guard() {atomic_sub(count, 1); };
+};
+//
+//****************************************************************************
+};// End namespace util
+};// End namespace common
+};// End namespace sort
+};// End namespace boost
+//****************************************************************************
+#endif
diff --git a/vendor/boost/sort/common/util/circular_buffer.hpp b/vendor/boost/sort/common/util/circular_buffer.hpp
new file mode 100644
index 00000000..2fc7e973
--- /dev/null
+++ b/vendor/boost/sort/common/util/circular_buffer.hpp
@@ -0,0 +1,572 @@
+//----------------------------------------------------------------------------
+/// @file   circular_buffer.hpp
+/// @brief  This file contains the implementation of the circular buffer
+///
+/// @author Copyright (c) 2010 2015 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanyingfile LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP
+#define __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP
+
+#include <memory>
+#include <cassert>
+#include <exception>
+#include <boost/sort/common/util/algorithm.hpp>
+#include <boost/sort/common/util/traits.hpp>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+
+//---------------------------------------------------------------------------
+/// @class  circular_buffer
+/// @brief  This class implement a circular buffer
+/// @remarks
+//---------------------------------------------------------------------------
+template <class Value_t, uint32_t Power2 = 11>
+struct circular_buffer
+{
+    //------------------------------------------------------------------------
+    //                          STATIC CHECK
+    //------------------------------------------------------------------------
+    static_assert ( Power2 != 0, "Wrong Power2");
+
+    //------------------------------------------------------------------------
+    //                          DEFINITIONS
+    //------------------------------------------------------------------------
+    typedef Value_t value_t;
+
+    //------------------------------------------------------------------------
+    //                          VARIABLES
+    //------------------------------------------------------------------------
+    const size_t NMAX = (size_t) 1 << Power2;
+    const size_t MASK = (NMAX - 1);
+    const size_t BLOCK_SIZE = NMAX >> 1;
+    const size_t LOG_BLOCK = Power2 - 1;
+    Value_t * ptr = nullptr;
+
+    //------------------------------------------------------------------------
+    // first and last are  the position of the first and last elements
+    // always are in the range [0, NMAX - 1]
+    //------------------------------------------------------------------------
+    size_t nelem, first_pos;
+    bool initialized;
+
+    //
+    //------------------------------------------------------------------------
+    //  function : circular_buffer
+    /// @brief  constructor of the class
+    //-----------------------------------------------------------------------
+    circular_buffer(void)
+    : ptr(nullptr), nelem(0), first_pos(0), initialized(false)
+    {
+        ptr = std::get_temporary_buffer < Value_t > (NMAX).first;
+        if (ptr == nullptr) throw std::bad_alloc();
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : ~circular_buffer
+    /// @brief destructor of the class
+    //-----------------------------------------------------------------------
+    ~circular_buffer()
+    {
+        if (initialized)
+        {   for (size_t i = 0; i < NMAX; ++i) (ptr + i)->~Value_t();
+            initialized = false;
+        };
+        std::return_temporary_buffer(ptr);
+    }
+    ;
+    //
+    //------------------------------------------------------------------------
+    //  function : initialize
+    /// @brief : initialize the memory of the buffer from the uninitialize
+    //           memory obtained from the temporary buffer
+    /// @param val : value used to initialize the memory
+    //-----------------------------------------------------------------------
+    void initialize(Value_t & val)
+    {
+        assert (initialized == false);
+        ::new (static_cast<void*>(ptr)) Value_t(std::move(val));
+        for (size_t i = 1; i < NMAX; ++i)
+            ::new (static_cast<void*>(ptr + i)) Value_t(std::move(ptr[i - 1]));
+        val = std::move(ptr[NMAX - 1]);
+        initialized = true;
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : destroy_all
+    /// @brief : destroy all the objects in the internal memory
+    //-----------------------------------------------------------------------
+    void destroy_all(void) { destroy(ptr, ptr + NMAX); };
+    //
+    //------------------------------------------------------------------------
+    //  function : get_buffer
+    /// @brief return the internal memory of the circular buffer
+    /// @return pointer to the internal memory of the buffer
+    //-----------------------------------------------------------------------
+    Value_t * get_buffer(void) { return ptr; };
+    //
+    //------------------------------------------------------------------------
+    //  function : empty
+    /// @brief return if the buffer is empty
+    /// @return true : empty
+    //-----------------------------------------------------------------------
+    bool empty(void) const {return (nelem == 0); };
+    //
+    //------------------------------------------------------------------------
+    //  function : full
+    /// @brief return if the buffer is full
+    /// @return true : full
+    //-----------------------------------------------------------------------
+    bool full(void) const { return (nelem == NMAX); };
+    //
+    //------------------------------------------------------------------------
+    //  function : size
+    /// @brief return the number of elements stored in the buffer
+    /// @return number of elements stored
+    //-----------------------------------------------------------------------
+    size_t size(void) const { return nelem;};
+    //
+    //------------------------------------------------------------------------
+    //  function : capacity
+    /// @brief : return the maximun capacity of the buffer
+    /// @return number of elements
+    //-----------------------------------------------------------------------
+    size_t capacity(void) const { return NMAX;};
+    //
+    //------------------------------------------------------------------------
+    //  function : free_size
+    /// @brief return the free positions in the buffer
+    /// @return number of elements
+    //-----------------------------------------------------------------------
+    size_t free_size(void) const  { return (NMAX - nelem); };
+    //
+    //------------------------------------------------------------------------
+    //  function : clear
+    /// @brief clear the buffer
+    //-----------------------------------------------------------------------
+    void clear(void)  { nelem = first_pos = 0; };
+    //
+    //------------------------------------------------------------------------
+    //  function : front
+    /// @brief return the first element of the buffer
+    /// @return reference to the first value
+    //-----------------------------------------------------------------------
+    Value_t & front(void)
+    {
+#ifdef __BS_DEBUG
+        assert (nelem > 0);
+#endif
+        return (ptr[first_pos]);
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function :front
+    /// @brief return the first element of the buffer
+    /// @return const reference to the first value
+    //-----------------------------------------------------------------------
+    const Value_t & front(void) const
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        return (ptr[first_pos]);
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : back
+    /// @brief reference to the last value of the buffer
+    /// @return reference to the last value
+    //-----------------------------------------------------------------------
+    Value_t & back(void)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        return (ptr[(first_pos + nelem - 1) & MASK]);
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : back
+    /// @brief reference to the last value of the buffer
+    /// @return const reference to the last value
+    //-----------------------------------------------------------------------
+    const Value_t & back(void) const
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        return (ptr[(first_pos + nelem - 1) & MASK]);
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : operator []
+    /// @brief positional access to the elements
+    /// @param pos rquested
+    /// @return reference to the element
+    //-----------------------------------------------------------------------
+    Value_t & operator[](uint32_t pos)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        return ptr[(first_pos + pos) & MASK];
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : operator []
+    /// @brief positional access to the elements
+    /// @param pos rquested
+    /// @return const reference to the element
+    //-----------------------------------------------------------------------
+    const Value_t & operator[](uint32_t pos) const
+    {
+
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        return ptr[(first_pos + pos) & MASK];
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : push_front
+    /// @brief insert an element in the first position of the buffer
+    /// @param val : const value to insert
+    //-----------------------------------------------------------------------
+    void push_front(const Value_t & val)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem != NMAX);
+#endif
+        ++nelem;
+        first_pos = ((first_pos + MASK) & MASK);
+        ptr[first_pos] = val;
+
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : push_front
+    /// @brief insert an element in the first position of the buffer
+    /// @param val : rvalue to insert
+    //-----------------------------------------------------------------------
+    void push_front(Value_t && val)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem != NMAX);
+#endif
+        ++nelem;
+        first_pos = ((first_pos + MASK) & MASK);
+        ptr[first_pos] = val;
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : push_back
+    /// @brief insert an element in the last position of the buffer
+    /// @param val : value to insert
+    //-----------------------------------------------------------------------
+    void push_back(const Value_t & val)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem != NMAX);
+#endif
+        ptr[(first_pos + (nelem++)) & MASK] = val;
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : push_back
+    /// @brief insert an element in the last position of the buffer
+    /// @param val : value to insert
+    //-----------------------------------------------------------------------
+    void push_back(Value_t && val)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem != NMAX);
+#endif
+        ptr[(first_pos + (nelem++)) & MASK] = std::move(val);
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : pop_front
+    /// @brief remove the first element of the buffer
+    //-----------------------------------------------------------------------
+    void pop_front(void)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        --nelem;
+        (++first_pos) &= MASK;
+    };
+    //
+    //------------------------------------------------------------------------
+    //  function : pop_back
+    /// @brief remove the last element of the buffer
+    //-----------------------------------------------------------------------
+    void pop_back(void)
+    {
+#ifdef __BS_DEBUG
+        assert ( nelem > 0 );
+#endif
+        --nelem;
+    };
+
+    template<class iter_t>
+    void pop_copy_front(iter_t it_dest, size_t num);
+
+    template<class iter_t>
+    void pop_move_front(iter_t it_dest, size_t num);
+
+    template<class iter_t>
+    void pop_copy_back(iter_t it_dest, size_t num);
+
+    template<class iter_t>
+    void pop_move_back(iter_t it_dest, size_t num);
+
+    template<class iter_t>
+    void push_copy_front(iter_t it_src, size_t num);
+
+    template<class iter_t>
+    void push_move_front(iter_t it_src, size_t num);
+
+    template<class iter_t>
+    void push_copy_back(iter_t it_src, size_t num);
+
+    template<class iter_t>
+    void push_move_back(iter_t it_src, size_t num);
+
+//---------------------------------------------------------------------------
+};//               End of class circular_buffer
+//---------------------------------------------------------------------------
+//
+//
+//############################################################################
+//                                                                          ##
+//             N O N    I N L I N E    F U N C T I O N S                    ##
+//                                                                          ##
+//############################################################################
+//
+//------------------------------------------------------------------------
+//  function : pop_copy_front
+/// @brief copy and delete num elements from the front of the buffer
+/// @param it_dest : iterator to the first position where copy the elements
+/// @param num : number of elements to copy
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::pop_copy_front(iter_t it_dest, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( num <= nelem);
+#endif
+    nelem -= num;
+    size_t pos = first_pos;
+    first_pos = (first_pos + num) & MASK;
+    for (size_t i = 0; i < num; ++i)
+    {
+        *(it_dest++) = ptr[pos++ & MASK];
+    };
+    first_pos &= MASK;
+};
+//
+//------------------------------------------------------------------------
+//  function : pop_move_front
+/// @brief move num elements from the front of the buffer to the place
+//         pointed by it_dest
+/// @param it_dest : iterator to the first position where move the elements
+/// @param num : number of elements to move
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+:: pop_move_front(iter_t it_dest, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( num <= nelem);
+#endif
+    nelem -= num;
+    size_t pos = first_pos;
+    first_pos = (first_pos + num) & MASK;
+    for (size_t i = 0; i < num; ++i)
+    {
+        *(it_dest++) = std::move(ptr[pos++ & MASK]);
+    };
+    first_pos &= MASK;
+};
+//
+//------------------------------------------------------------------------
+//  function : pop_copy_back
+/// @brief copy and delete num elements from the back of the buffer
+/// @param p1 : iterator where begin to copy the elements
+/// @param num : number of elements to copy
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::pop_copy_back(iter_t it_dest, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( num <= nelem);
+#endif
+    nelem -= num;
+    size_t pos = (first_pos + nelem) & MASK;
+    for (size_t i = 0; i < num; ++i)
+    {
+        *(it_dest++) = ptr[pos++ & MASK];
+    };
+};
+//
+//------------------------------------------------------------------------
+//  function : pop_move_back
+/// @brief move and delete num elements from the back of the buffer
+/// @param p1 : iterator where begin to move the elements
+/// @param num : number of elements to move
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::pop_move_back(iter_t it_dest, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( num <= nelem);
+#endif
+    nelem -= num;
+    size_t pos = (first_pos + nelem) & MASK;
+    for (size_t i = 0; i < num; ++i)
+    {
+        *(it_dest++) = std::move(ptr[pos++ & MASK]);
+    };
+};
+//
+//------------------------------------------------------------------------
+//  function : push_copy_front
+/// @brief copy num elements in the front of the buffer
+/// @param it_src : iterator from where begin to copy the elements
+/// @param mun : number of element to copy
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::push_copy_front(iter_t it_src, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( free_size() >= num);
+#endif
+    nelem += num;
+
+    first_pos = (first_pos + NMAX - num) & MASK;
+    size_t pos = first_pos;
+    for (size_t i = 0; i < num; ++i)
+    {
+        ptr[(pos++) & MASK] = *(it_src++);
+    };
+};
+//
+//------------------------------------------------------------------------
+//  function : push_move_front
+/// @brief move num elements in the front of the buffer
+/// @param p1 : iterator from where begin to move the elements
+/// @param mun : number of element to move
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::push_move_front(iter_t it_src, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( free_size() >= num);
+#endif
+    nelem += num;
+    size_t pos = first_pos;
+    for (size_t i = 0; i < num; ++i)
+    {
+        ptr[(pos++) & MASK] = std::move(*(it_src++));
+    };
+};
+//
+//------------------------------------------------------------------------
+//  function : push_copy_back
+/// @brief copy num elements in the back of the buffer
+/// @param p1 : iterator from where begin to copy the elements
+/// @param mun : number of element to copy
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::push_copy_back(iter_t it_src, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( free_size() >= num);
+#endif
+    size_t pos = first_pos + nelem;
+    nelem += num;
+    for (size_t i = 0; i < num; ++i)
+    {
+        ptr[(pos++) & MASK] = *(it_src++);
+    };
+};
+//
+//------------------------------------------------------------------------
+//  function : push_move_back
+/// @brief move num elements in the back of the buffer
+/// @param p1 : iterator from where begin to move the elements
+/// @param mun : number of element to move
+//-----------------------------------------------------------------------
+template <class Value_t, uint32_t Power2>
+template<class iter_t>
+void circular_buffer<Value_t, Power2>
+::push_move_back(iter_t it_src, size_t num)
+{
+    static_assert ( std::is_same <value_iter<iter_t>, Value_t>::value,
+                    "Incompatible iterator");
+    if (num == 0) return;
+#ifdef __BS_DEBUG
+    assert ( free_size() >= num);
+#endif
+    size_t pos = first_pos + nelem;
+    nelem += num;
+    for (size_t i = 0; i < num; ++i)
+    {
+        ptr[(pos++) & MASK] = std::move(*(it_src++));
+    };
+};
+
+//****************************************************************************
+};// End namespace util
+};// End namespace common
+};// End namespace sort
+};// End namespace boost
+//****************************************************************************
+#endif
diff --git a/vendor/boost/sort/common/util/insert.hpp b/vendor/boost/sort/common/util/insert.hpp
new file mode 100644
index 00000000..219fa8a3
--- /dev/null
+++ b/vendor/boost/sort/common/util/insert.hpp
@@ -0,0 +1,142 @@
+//----------------------------------------------------------------------------
+/// @file insert.hpp
+/// @brief
+///
+/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_COMMON_UTIL_INSERT_HPP
+#define __BOOST_SORT_COMMON_UTIL_INSERT_HPP
+
+//#include <boost/sort/spinsort/util/indirect.hpp>
+#include <boost/sort/common/util/insert.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <boost/sort/common/util/algorithm.hpp>
+#include <cstdlib>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+#include <cstddef>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+namespace here = boost::sort::common::util;
+//
+//############################################################################
+//
+//          D E F I N I T I O N S    O F    F U N C T I O N S
+//    
+// template < class Iter1_t, class Iter2_t, typename Compare>
+// void insert_sorted (Iter1_t first, Iter1_t mid, Iter1_t last,
+//                     Compare comp, Iter2_t  it_aux)
+//
+//############################################################################
+//
+//-----------------------------------------------------------------------------
+//  function : insert_sorted
+/// @brief : Insertion sort of elements sorted
+/// @param first: iterator to the first element of the range
+/// @param mid : last pointer of the sorted data, and first pointer to the
+///               elements to insert
+/// @param last : iterator to the next element of the last in the range
+/// @param comp :
+/// @comments : the two ranges are sorted and in it_aux there is spave for 
+///             to store temporally the elements to insert
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, typename Compare>
+static void insert_sorted(Iter1_t first, Iter1_t mid, Iter1_t last,
+                          Compare comp, Iter2_t it_aux)
+{
+    //------------------------------------------------------------------------
+    //                 metaprogram
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //--------------------------------------------------------------------
+    //                   program
+    //--------------------------------------------------------------------
+    if (mid == last) return;
+    if (first == mid) return;
+
+    //------------------------------------------------------------------------
+    // creation of the vector of elements to insert and their position in the
+    // sorted part
+    // the data are inserted in it_aux
+    //-----------------------------------------------------------------------
+    move_forward(it_aux, mid, last);
+
+    // search of the iterators where insert the new elements
+    size_t ndata = last - mid;
+    Iter1_t mv_first = mid, mv_last = mid;
+
+    for (size_t i = ndata; i > 0; --i)
+    {
+        mv_last = mv_first;
+        mv_first = std::upper_bound(first, mv_last, it_aux[i - 1], comp);
+        Iter1_t it1 = here::move_backward(mv_last + i, mv_first, mv_last);
+        *(it1 - 1) = std::move(it_aux[i - 1]);
+    };
+};
+
+template<class Iter1_t, class Iter2_t, typename Compare>
+static void insert_sorted_backward(Iter1_t first, Iter1_t mid, Iter1_t last,
+                                   Compare comp, Iter2_t it_aux)
+{
+    //------------------------------------------------------------------------
+    //                 metaprogram
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //--------------------------------------------------------------------
+    //                   program
+    //--------------------------------------------------------------------
+    if (mid == last) return;
+    if (first == mid) return;
+    //------------------------------------------------------------------------
+    // creation of the vector of elements to insert and their position in the
+    // sorted part
+    // the data are inserted in it_aux
+    //-----------------------------------------------------------------------
+    move_forward(it_aux, first, mid);
+
+    // search of the iterators where insert the new elements
+    size_t ndata = mid - first;
+    Iter1_t mv_first = mid, mv_last = mid;
+
+    for (size_t i = 0; i < ndata; ++i)
+    {
+        mv_first = mv_last;
+        mv_last = std::lower_bound(mv_first, last, it_aux[i], comp);
+        Iter1_t it1 = move_forward(mv_first - (ndata - i), mv_first, mv_last);
+        *(it1) = std::move(it_aux[i]);
+    };
+
+};
+//
+//****************************************************************************
+};//    End namespace util
+};//    End namepspace common
+};//    End namespace sort
+};//    End namepspace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/util/merge.hpp b/vendor/boost/sort/common/util/merge.hpp
new file mode 100644
index 00000000..5fc90c0f
--- /dev/null
+++ b/vendor/boost/sort/common/util/merge.hpp
@@ -0,0 +1,494 @@
+//----------------------------------------------------------------------------
+/// @file merge.hpp
+/// @brief low level merge functions
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_COMMON_UTIL_MERGE_HPP
+#define __BOOST_SORT_COMMON_UTIL_MERGE_HPP
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+
+#include <boost/sort/common/util/algorithm.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <boost/sort/common/util/circular_buffer.hpp>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+namespace here = boost::sort::common::util;
+//----------------------------------------------------------------------------
+//
+//           F U N C T I O N S    I N    T H E     F I L E
+//----------------------------------------------------------------------------
+//
+// template < class Iter1_t, class Iter2_t, class Compare >
+// Iter2_t merge (Iter1_t buf1, const Iter1_t end_buf1, Iter1_t buf2,
+//                const Iter1_t end_buf2, Iter2_t buf_out, Compare comp)
+//
+// template < class Iter_t, class Value_t, class Compare >
+// Value_t *merge_construct (Iter_t first1, const Iter_t last1, Iter_t first2,
+//                           const Iter_t last2, Value_t *it_out, Compare comp)
+//
+// template < class Iter1_t, class Iter2_t, class Compare >
+// Iter2_t merge_half (Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
+//                     const Iter2_t end_buf2, Iter2_t buf_out, Compare comp)
+//
+// template < class Iter1_t, class Iter2_t, class Compare >
+// Iter2_t merge_half_backward (Iter1_t buf1,  Iter1_t end_buf1,
+//                              Iter2_t buf2, Iter2_t end_buf2,
+//                              Iter1_t end_buf_out, Compare comp)
+//
+// template < class Iter1_t, class Iter2_t, class Iter3_t, class Compare >
+// bool merge_uncontiguous (Iter1_t src1, const Iter1_t end_src1,
+//                          Iter2_t src2, const Iter2_t end_src2,
+//                          Iter3_t aux, Compare comp)
+//
+// template < class Iter1_t, class Iter2_t, class Compare >
+// bool merge_contiguous (Iter1_t src1, Iter1_t src2, Iter1_t end_src2,
+//                        Iter2_t buf, Compare comp)
+//
+// template < class Iter_t, class Circular ,class Compare >
+// bool merge_circular  (Iter_t buf1, Iter_t end_buf1,
+//                       Iter_t buf2, Iter_t end_buf2,
+//                       Circular &circ, Compare comp, Iter_t &it_aux)
+//
+//----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+//  function : merge
+/// @brief Merge two contiguous buffers pointed by buf1 and buf2, and put
+///        in the buffer pointed by buf_out
+///
+/// @param buf1 : iterator to the first element in the first buffer
+/// @param end_buf1 : final iterator of first buffer
+/// @param buf2 : iterator to the first iterator to the second buffer
+/// @param end_buf2 : final iterator of the second buffer
+/// @param buf_out : buffer where move the elements merged
+/// @param comp : comparison object
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
+static Iter3_t merge(Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
+                     const Iter2_t end_buf2, Iter3_t buf_out, Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                       Metaprogramming
+    //------------------------------------------------------------------------- 
+    typedef value_iter<Iter1_t> value1_t;
+    typedef value_iter<Iter2_t> value2_t;
+    typedef value_iter<Iter3_t> value3_t;
+    static_assert (std::is_same< value1_t, value2_t >::value,
+                    "Incompatible iterators\n");
+    static_assert (std::is_same< value3_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                       Code
+    //-------------------------------------------------------------------------
+    const size_t MIN_CHECK = 1024;
+
+    if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
+    {
+        if (buf1 == end_buf1) return move_forward(buf_out, buf2, end_buf2);
+        if (buf2 == end_buf2) return move_forward(buf_out, buf1, end_buf1);
+
+        if (not comp(*buf2, *(end_buf1 - 1)))
+        {
+            Iter3_t mid = move_forward(buf_out, buf1, end_buf1);
+            return move_forward(mid, buf2, end_buf2);
+        };
+
+        if (comp(*(end_buf2 - 1), *buf1))
+        {
+            Iter3_t mid = move_forward(buf_out, buf2, end_buf2);
+            return move_forward(mid, buf1, end_buf1);
+        };
+    };
+    while ((buf1 != end_buf1) and (buf2 != end_buf2))
+    {
+        *(buf_out++) = (not comp(*buf2, *buf1)) ?
+                        std::move(*(buf1++)) : std::move(*(buf2++));
+    };
+
+    return (buf1 == end_buf1) ?
+                    move_forward(buf_out, buf2, end_buf2) :
+                    move_forward(buf_out, buf1, end_buf1);
+}
+;
+//
+//-----------------------------------------------------------------------------
+//  function : merge_construct
+/// @brief Merge two contiguous buffers pointed by first1 and first2, and put
+///        in the uninitialized buffer pointed by it_out
+///
+/// @param first1 : iterator to the first element in the first buffer
+/// @param last1 : last iterator of the first buffer
+/// @param first2 : iterator to the first element to the second buffer
+/// @param last2 : final iterator of the second buffer
+/// @param it_out : uninitialized buffer where move the elements merged
+/// @param comp : comparison object
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Value_t, class Compare>
+static Value_t *merge_construct(Iter1_t first1, const Iter1_t last1,
+                                Iter2_t first2, const Iter2_t last2,
+                                Value_t *it_out, Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                       Metaprogramming
+    //------------------------------------------------------------------------- 
+    typedef value_iter<Iter1_t> type1;
+    typedef value_iter<Iter2_t> type2;
+    static_assert (std::is_same< Value_t, type1 >::value,
+                    "Incompatible iterators\n");
+    static_assert (std::is_same< Value_t, type2 >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                       Code
+    //-------------------------------------------------------------------------
+    const size_t MIN_CHECK = 1024;
+
+    if (size_t((last1 - first1) + (last2 - first2)) >= MIN_CHECK)
+    {
+        if (first1 == last1) return move_construct(it_out, first2, last2);
+        if (first2 == last2) return move_construct(it_out, first1, last1);
+
+        if (not comp(*first2, *(last1 - 1)))
+        {
+            Value_t* mid = move_construct(it_out, first1, last1);
+            return move_construct(mid, first2, last2);
+        };
+
+        if (comp(*(last2 - 1), *first1))
+        {
+            Value_t* mid = move_construct(it_out, first2, last2);
+            return move_construct(mid, first1, last1);
+        };
+    };
+    while (first1 != last1 and first2 != last2)
+    {
+        construct_object((it_out++),
+                        (not comp(*first2, *first1)) ?
+                                        std::move(*(first1++)) :
+                                        std::move(*(first2++)));
+    };
+    return (first1 == last1) ?
+                    move_construct(it_out, first2, last2) :
+                    move_construct(it_out, first1, last1);
+};
+//
+//---------------------------------------------------------------------------
+//  function : merge_half
+/// @brief : Merge two buffers. The first buffer is in a separate memory.
+///          The second buffer have a empty space before buf2 of the same size
+///          than the (end_buf1 - buf1)
+///
+/// @param buf1 : iterator to the first element of the first buffer
+/// @param end_buf1 : iterator to the last element of the first buffer
+/// @param buf2 : iterator to the first element of the second buffer
+/// @param end_buf2 : iterator to the last element of the second buffer
+/// @param buf_out : iterator to the first element to the buffer where put
+///                  the result
+/// @param comp : object for Compare two elements of the type pointed
+///                by the Iter1_t and Iter2_t
+//---------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static Iter2_t merge_half(Iter1_t buf1, const Iter1_t end_buf1, Iter2_t buf2,
+                          const Iter2_t end_buf2, Iter2_t buf_out, Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                         Metaprogramming
+    //------------------------------------------------------------------------- 
+    typedef value_iter<Iter1_t> value1_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value1_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                         Code
+    //-------------------------------------------------------------------------
+#ifdef __BS_DEBUG
+    assert ( (buf2 - buf_out) == ( end_buf1 - buf1));
+#endif
+    const size_t MIN_CHECK = 1024;
+
+    if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
+    {
+        if (buf1 == end_buf1) return end_buf2;
+        if (buf2 == end_buf2) return move_forward(buf_out, buf1, end_buf1);
+
+        if (not comp(*buf2, *(end_buf1 - 1)))
+        {
+            move_forward(buf_out, buf1, end_buf1);
+            return end_buf2;
+        };
+
+        if (comp(*(end_buf2 - 1), *buf1))
+        {
+            Iter2_t mid = move_forward(buf_out, buf2, end_buf2);
+            return move_forward(mid, buf1, end_buf1);
+        };
+    };
+    while ((buf1 != end_buf1) and (buf2 != end_buf2))
+    {
+        *(buf_out++) = (not comp(*buf2, *buf1)) ?
+                        std::move(*(buf1++)) : std::move(*(buf2++));
+    };
+    return (buf2 == end_buf2)? move_forward(buf_out, buf1, end_buf1) : end_buf2;
+};
+
+//
+//---------------------------------------------------------------------------
+//  function : merge_half_backward
+/// @brief : Merge two buffers. The first buffer is in a separate memory.
+///          The second buffer have a empty space before buf2 of the same size
+///          than the (end_buf1 - buf1)
+///
+/// @param buf1 : iterator to the first element of the first buffer
+/// @param end_buf1 : iterator to the last element of the first buffer
+/// @param buf2 : iterator to the first element of the second buffer
+/// @param end_buf2 : iterator to the last element of the second buffer
+/// @param buf_out : iterator to the first element to the buffer where put
+///                  the result
+/// @param comp : object for Compare two elements of the type pointed
+///                by the Iter1_t and Iter2_t
+//---------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static Iter2_t merge_half_backward(Iter1_t buf1, Iter1_t end_buf1, Iter2_t buf2,
+                                   Iter2_t end_buf2, Iter1_t end_buf_out,
+                                   Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                         Metaprogramming
+    //-------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value1_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same< value1_t, value2_t >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                         Code
+    //-------------------------------------------------------------------------
+#ifdef __BS_DEBUG
+    assert ((end_buf_out - end_buf1) == (end_buf2 - buf2) );
+#endif
+    const size_t MIN_CHECK = 1024;
+
+    if (size_t((end_buf1 - buf1) + (end_buf2 - buf2)) >= MIN_CHECK)
+    {
+        if (buf2 == end_buf2) return buf1;
+        if (buf1 == end_buf1)
+            return here::move_backward(end_buf_out, buf2, end_buf2);
+
+        if (not comp(*buf2, *(end_buf1 - 1)))
+        {
+            here::move_backward(end_buf_out, buf2, end_buf2);
+            return buf1;
+        };
+
+        if (comp(*(end_buf2 - 1), *buf1))
+        {
+            Iter1_t mid = here::move_backward(end_buf_out, buf1, end_buf1);
+            return here::move_backward(mid, buf2, end_buf2);
+        };
+    };
+    while ((buf1 != end_buf1) and (buf2 != end_buf2))
+    {
+        *(--end_buf_out) =
+                        (not comp(*(end_buf2 - 1), *(end_buf1 - 1))) ?
+                                        std::move(*(--end_buf2)):
+                                        std::move(*(--end_buf1));
+    };
+    return (buf1 == end_buf1) ?
+                    here::move_backward(end_buf_out, buf2, end_buf2) : buf1;
+};
+
+//
+//-----------------------------------------------------------------------------
+//  function : merge_uncontiguous
+/// @brief : merge two uncontiguous buffers, placing the results in the buffers
+///          Use an auxiliary buffer pointed by aux
+///
+/// @param src1 : iterator to the first element of the first buffer
+/// @param end_src1 : last iterator  of the first buffer
+/// @param src2 : iterator to the first element of the second buffer
+/// @param end_src2 : last iterator  of the second buffer
+/// @param aux  : iterator to the first element of the auxiliary buffer
+/// @param comp : object for to Compare elements
+/// @return true : not changes done,  false : changes in the buffers
+/// @remarks
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
+static bool merge_uncontiguous(Iter1_t src1, const Iter1_t end_src1,
+                               Iter2_t src2, const Iter2_t end_src2,
+                               Iter3_t aux, Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                    Metaprogramming
+    //------------------------------------------------------------------------- 
+    typedef value_iter<Iter1_t> type1;
+    typedef value_iter<Iter2_t> type2;
+    typedef value_iter<Iter3_t> type3;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+    static_assert (std::is_same< type3, type2 >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                    Code
+    //-------------------------------------------------------------------------
+    if (src1 == end_src1 or src2 == end_src2
+                    or not comp(*src2, *(end_src1 - 1))) return true;
+
+    while (src1 != end_src1 and not comp(*src2, *src1))
+        ++src1;
+
+    Iter3_t const end_aux = aux + (end_src1 - src1);
+    Iter2_t src2_first = src2;
+    move_forward(aux, src1, end_src1);
+
+    while ((src1 != end_src1) and (src2 != end_src2))
+    {
+        *(src1++) = std::move((not comp(*src2, *aux)) ? *(aux++) : *(src2++));
+    }
+
+    if (src2 == end_src2)
+    {
+        while (src1 != end_src1)
+            *(src1++) = std::move(*(aux++));
+        move_forward(src2_first, aux, end_aux);
+    }
+    else
+    {
+        merge_half(aux, end_aux, src2, end_src2, src2_first, comp);
+    };
+    return false;
+};
+
+//
+//-----------------------------------------------------------------------------
+//  function : merge_contiguous
+/// @brief : merge two contiguous buffers,using an auxiliary buffer pointed
+///          by buf. The results are in src1 and src2
+///
+/// @param src1: iterator to the first position of the first buffer
+/// @param src2: final iterator of the first buffer and first iterator
+///              of the second buffer
+/// @param end_src2 : final iterator of the second buffer
+/// @param buf  : iterator to buffer used as auxiliary memory
+/// @param comp : object for to Compare elements
+/// @return true : not changes done,  false : changes in the buffers
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static bool merge_contiguous(Iter1_t src1, Iter1_t src2, Iter1_t end_src2,
+                             Iter2_t buf, Compare comp)
+{
+    //-------------------------------------------------------------------------
+    //                      Metaprogramming
+    //------------------------------------------------------------------------- 
+    typedef value_iter<Iter1_t> type1;
+    typedef value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                         Code
+    //-------------------------------------------------------------------------
+    if (src1 == src2 or src2 == end_src2 or not comp(*src2, *(src2 - 1)))
+        return true;
+
+    Iter1_t end_src1 = src2;
+    while (src1 != end_src1 and not comp(*src2, *src1))
+        ++src1;
+
+    if (src1 == end_src1) return false;
+
+    size_t nx = end_src1 - src1;
+    move_forward(buf, src1, end_src1);
+    merge_half(buf, buf + nx, src2, end_src2, src1, comp);
+    return false;
+};
+//
+//-----------------------------------------------------------------------------
+//  function : merge_circular
+/// @brief : merge two buffers,using a circular buffer
+///          This function don't check the parameters
+/// @param buf1: iterator to the first position of the first buffer
+/// @param end_buf1: iterator after the last element of the first buffer
+/// @param buf2: iterator to the first element of the secind buffer
+/// @param end_buf2: iterator to the first element of the secind buffer
+/// @param circ : circular buffer
+/// @param comp : comparison object
+/// @return true : finished buf1,  false : finished buf2
+/// @comments : be carefully because the iterators buf1 and buf2 are modified
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Circular, class Compare>
+static bool merge_circular(Iter1_t buf1, Iter1_t end_buf1, Iter2_t buf2,
+                           Iter2_t end_buf2, Circular &circ, Compare comp,
+                           Iter1_t &it1_out, Iter2_t &it2_out)
+{
+    //-------------------------------------------------------------------------
+    //                      Metaprogramming
+    //-------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> type1;
+    typedef value_iter<Iter2_t> type2;
+    static_assert (std::is_same< type1, type2 >::value,
+                    "Incompatible iterators\n");
+    typedef typename Circular::value_t type3;
+    static_assert (std::is_same<type1, type3>::value,
+                    "Incompatible iterators\n");
+
+    //-------------------------------------------------------------------------
+    //                      Code
+    //-------------------------------------------------------------------------
+#ifdef __BS_DEBUG
+    assert ( circ.free_size() >= size_t ((end_buf1-buf1) + (end_buf2-buf2)));
+#endif
+
+    if (not comp(*buf2, *(end_buf1 - 1)))
+    {
+        circ.push_move_back(buf1, (end_buf1 - buf1));
+        it1_out = end_buf1;
+        it2_out = buf2;
+        return true;
+    };
+    if (comp(*(end_buf2 - 1), *buf1))
+    {
+        circ.push_move_back(buf2, (end_buf2 - buf2));
+        it1_out = buf1;
+        it2_out = end_buf2;
+        return false;
+    }
+    while (buf1 != end_buf1 and buf2 != end_buf2)
+    {
+        circ.push_back(comp(*buf2, *buf1) ? std::move(*(buf2++))
+                                          : std::move(*(buf1++)));
+    };
+    it2_out = buf2;
+    it1_out = buf1;
+    bool ret = (buf1 == end_buf1);
+    return ret;
+};
+//
+//****************************************************************************
+};//    End namespace util
+};//    End namespace common
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/common/util/traits.hpp b/vendor/boost/sort/common/util/traits.hpp
new file mode 100644
index 00000000..68e5cf03
--- /dev/null
+++ b/vendor/boost/sort/common/util/traits.hpp
@@ -0,0 +1,123 @@
+//----------------------------------------------------------------------------
+/// @file traits.hpp
+/// @brief this file contains the metaprogramming classes  compare_iter and
+///         enable_if_not_integral
+/// @author Copyright(c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_COMMON_UTIL_TRAITS_HPP
+#define __BOOST_SORT_COMMON_UTIL_TRAITS_HPP
+
+#include <functional>
+#include <iterator>
+#include <type_traits>
+
+namespace boost
+{
+namespace sort
+{
+namespace common
+{
+namespace util
+{
+//----------------------------------------------------------------------------
+//                  USING SENTENCES
+//----------------------------------------------------------------------------
+using std::iterator_traits;
+
+//
+//---------------------------------------------------------------------------
+/// @class value_iter
+/// @brief From the iterator, obtain the type pointed by it
+/// @remarks The main utility of this, is simplify the default template
+///          parameter of comparison
+//---------------------------------------------------------------------------
+template<class iter_t>
+using value_iter = typename iterator_traits< iter_t >::value_type;
+//
+//---------------------------------------------------------------------------
+/// @class compare_iter
+/// @brief From the iterator, received as template parameter, obtain the type
+///        of the object pointed by the iterator, and with this define the
+///        std::less with this type obtained
+/// @remarks The main utility of this, is simplify the default template
+///          parameter of comparison
+//---------------------------------------------------------------------------
+template<class iter_t>
+using compare_iter =  std::less< value_iter< iter_t > >;
+
+//
+//---------------------------------------------------------------------------
+/// @class enable_if_not_integral
+/// @brief This is a SFINAE class for to detect if the third parameter in the
+///        invocation of the parallel sorting algorithms is an integer
+///        representing the number of threads to use or is a comparison object
+/// @remarks
+//---------------------------------------------------------------------------
+template<class T>
+using enable_if_not_integral =
+      typename std::enable_if< !std::is_integral< T >::value >::type;
+//
+//---------------------------------------------------------------------------
+/// @class enable_if_integral
+/// @brief This is a SFINAE class for to detect if the third parameter in the
+///        invocation of the parallel sorting algorithms is an integer
+///        representing the number of threads to use or is a comparison object
+/// @remarks
+//---------------------------------------------------------------------------
+template<class T>
+using enable_if_integral =
+      typename std::enable_if< std::is_integral< T >::value >::type;
+
+//
+//---------------------------------------------------------------------------
+/// @class enable_if_string
+/// @brief This is a SFINAE class for to detect if the parameter is a
+///        std::string for to apply specialized parameters in the invocation
+///        of the block_indirect_sort algorithm
+/// @remarks
+//---------------------------------------------------------------------------
+template<class T>
+using enable_if_string =
+      typename std::enable_if< std::is_same< T, std::string >::value >::type;
+
+//
+//---------------------------------------------------------------------------
+/// @class enable_if_not_string
+/// @brief This is a SFINAE class for to detect if the parameter is a
+///        std::string for to apply specialized parameters in the invocation
+///        of the block_indirect_sort algorithm
+/// @remarks
+//---------------------------------------------------------------------------
+template<class T>
+using enable_if_not_string =
+      typename std::enable_if<! std::is_same< T, std::string >::value >::type;
+
+//
+//---------------------------------------------------------------------------
+/// @class constructor
+/// @brief create a functor with the constructor of a class for to be invoked
+///        from a bind or a lambda
+/// @remarks
+//---------------------------------------------------------------------------
+template<class T>
+struct constructor
+{
+    template<class ... Args>
+    void operator()(Args && ... args)
+    {
+        T(std::forward<Args> (args) ...);
+    };
+};
+//
+//****************************************************************************
+};// End namespace util
+};// End namespace common
+};// End namespace sort
+};// End namespace boost
+//****************************************************************************
+#endif
diff --git a/vendor/boost/sort/insert_sort/insert_sort.hpp b/vendor/boost/sort/insert_sort/insert_sort.hpp
new file mode 100644
index 00000000..d40302ad
--- /dev/null
+++ b/vendor/boost/sort/insert_sort/insert_sort.hpp
@@ -0,0 +1,119 @@
+//----------------------------------------------------------------------------
+/// @file insert_sort.hpp
+/// @brief Insertion Sort algorithm
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_INTROSORT_DETAIL_INSERT_SORT_HPP
+#define __BOOST_SORT_INTROSORT_DETAIL_INSERT_SORT_HPP
+
+#include <functional>
+#include <iterator>
+#include <algorithm>
+#include <utility> // std::swap
+#include <boost/sort/common/util/traits.hpp>
+#include <boost/sort/common/util/insert.hpp>
+
+namespace boost
+{
+namespace sort
+{
+using common::util::compare_iter;
+using common::util::value_iter;
+//
+//-----------------------------------------------------------------------------
+//  function : insert_sort
+/// @brief : Insertion sort algorithm
+/// @param first: iterator to the first element of the range
+/// @param last : iterator to the next element of the last in the range
+/// @param comp : object for to do the comparison between the elements
+/// @remarks This algorithm is O(N^2)
+//-----------------------------------------------------------------------------
+template < class Iter_t, typename Compare = compare_iter < Iter_t > >
+static void insert_sort (Iter_t first, Iter_t last,
+                         Compare comp = Compare())
+{
+    //--------------------------------------------------------------------
+    //                   DEFINITIONS
+    //--------------------------------------------------------------------
+    typedef value_iter< Iter_t > value_t;
+
+    if ((last - first) < 2) return;
+
+    for (Iter_t it_examine = first + 1; it_examine != last; ++it_examine)
+    {
+        value_t Aux = std::move (*it_examine);
+        Iter_t it_insertion = it_examine;
+
+        while (it_insertion != first and comp (Aux, *(it_insertion - 1)))
+        {
+            *it_insertion = std::move (*(it_insertion - 1));
+            --it_insertion;
+        };
+        *it_insertion = std::move (Aux);
+    };
+};
+
+/*
+//
+//-----------------------------------------------------------------------------
+//  function : insert_partial_sort
+/// @brief : Insertion sort of elements sorted
+/// @param first: iterator to the first element of the range
+/// @param mid : last pointer of the sorted data, and first pointer to the
+///               elements to insert
+/// @param last : iterator to the next element of the last in the range
+/// @param comp : object for to do the comparison between the elements
+/// @remarks This algorithm is O(N^2)
+//-----------------------------------------------------------------------------
+template < class Iter_t, typename Compare = compare_iter < Iter_t > >
+void insert_partial_sort (Iter_t first, Iter_t mid, Iter_t last,
+                          Compare comp = Compare())
+{
+    //--------------------------------------------------------------------
+    //                   DEFINITIONS
+    //--------------------------------------------------------------------
+    typedef value_iter< Iter_t > value_t;
+
+    if ( mid == last ) return ;
+    insert_sort ( mid, last, comp);
+    if (first == mid) return ;
+
+    // creation of the vector of elements to insert and their position in the
+    // sorted part
+    std::vector<Iter_t> viter ;
+    std::vector<value_t> vdata ;
+
+    for ( Iter_t alpha = mid ; alpha != last ; ++alpha)
+        vdata.push_back ( std::move ( *alpha));
+
+    Iter_t linf = first , lsup = mid ;
+    for ( uint32_t i= 0 ; i < vdata.size() ; ++i)
+    {   Iter_t it1 = std::upper_bound ( linf, lsup , vdata[i], comp);
+        viter.push_back ( it1 );
+        linf = it1 ;
+    };
+
+    // moving the elements
+    viter.push_back ( mid) ;
+    for ( uint32_t i = viter.size() -1 ; i!= 0 ; --i)
+    {   Iter_t src = viter[i], limit = viter[i-1];
+        Iter_t dest = src + ( i);
+        while ( src != limit) * (--dest) = std::move ( *(--src));
+        *(viter[i-1] + (i -1)) = std::move (vdata[i-1]);
+    };
+}
+*/
+//
+//****************************************************************************
+}; //    End namespace sort
+}; //    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/parallel_stable_sort/parallel_stable_sort.hpp b/vendor/boost/sort/parallel_stable_sort/parallel_stable_sort.hpp
new file mode 100644
index 00000000..3dc92f21
--- /dev/null
+++ b/vendor/boost/sort/parallel_stable_sort/parallel_stable_sort.hpp
@@ -0,0 +1,292 @@
+//----------------------------------------------------------------------------
+/// @file parallel_stable_sort.hpp
+/// @brief This file contains the class parallel_stable_sort
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_STABLE_SORT_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_PARALLEL_STABLE_SORT_HPP
+
+#include <boost/sort/sample_sort/sample_sort.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <functional>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+namespace boost
+{
+namespace sort
+{
+namespace stable_detail
+{
+
+//---------------------------------------------------------------------------
+//                    USING SENTENCES
+//---------------------------------------------------------------------------
+namespace bsc = boost::sort::common;
+namespace bss = boost::sort::spin_detail;
+using bsc::range;
+using bsc::merge_half;
+using boost::sort::sample_detail::sample_sort;
+//
+///---------------------------------------------------------------------------
+/// @struct parallel_stable_sort
+/// @brief This a structure for to implement a parallel stable sort, exception
+///        safe
+//----------------------------------------------------------------------------
+template <class Iter_t, class Compare = compare_iter <Iter_t> >
+struct parallel_stable_sort
+{
+    //-------------------------------------------------------------------------
+    //                      DEFINITIONS
+    //-------------------------------------------------------------------------
+    typedef value_iter<Iter_t> value_t;
+
+    //-------------------------------------------------------------------------
+    //                     VARIABLES
+    //-------------------------------------------------------------------------
+    // Number of elements to sort
+    size_t nelem;
+    // Pointer to the auxiliary memory needed for the algorithm
+    value_t *ptr;
+    // Minimal number of elements for to be sorted in parallel mode
+    const size_t nelem_min = 1 << 16;
+
+    //------------------------------------------------------------------------
+    //                F U N C T I O N S
+    //------------------------------------------------------------------------
+    parallel_stable_sort (Iter_t first, Iter_t last)
+    : parallel_stable_sort (first, last, Compare(),
+                            std::thread::hardware_concurrency()) { };
+
+    parallel_stable_sort (Iter_t first, Iter_t last, Compare cmp)
+    : parallel_stable_sort (first, last, cmp,
+                            std::thread::hardware_concurrency()) { };
+
+    parallel_stable_sort (Iter_t first, Iter_t last, uint32_t num_thread)
+    : parallel_stable_sort (first, last, Compare(), num_thread) { };
+
+    parallel_stable_sort (Iter_t first, Iter_t last, Compare cmp,
+                          uint32_t num_thread);
+
+    //
+    //-----------------------------------------------------------------------------
+    //  function : destroy_all
+    /// @brief The utility is to destroy the temporary buffer used in the
+    ///        sorting process
+    //-----------------------------------------------------------------------------
+    void destroy_all()
+    {
+        if (ptr != nullptr) std::return_temporary_buffer(ptr);
+    };
+    //
+    //-----------------------------------------------------------------------------
+    //  function :~parallel_stable_sort
+    /// @brief destructor of the class. The utility is to destroy the temporary
+    ///        buffer used in the sorting process
+    //-----------------------------------------------------------------------------
+    ~parallel_stable_sort() {destroy_all(); } ;
+};
+// end struct parallel_stable_sort
+
+//
+//############################################################################
+//                                                                          ##
+//                                                                          ##
+//            N O N     I N L I N E      F U N C T I O N S                  ##
+//                                                                          ##
+//                                                                          ##
+//############################################################################
+//
+//-----------------------------------------------------------------------------
+//  function : parallel_stable_sort
+/// @brief constructor of the class
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///                    iterators
+/// @param nthread : Number of threads to use in the process. When this value
+///                  is lower than 2, the sorting is done with 1 thread
+//-----------------------------------------------------------------------------
+template <class Iter_t, class Compare>
+parallel_stable_sort <Iter_t, Compare>
+::parallel_stable_sort (Iter_t first, Iter_t last, Compare comp,
+                        uint32_t nthread) : nelem(0), ptr(nullptr)
+{
+    range<Iter_t> range_initial(first, last);
+    assert(range_initial.valid());
+
+    nelem = range_initial.size();
+    size_t nptr = (nelem + 1) >> 1;
+
+    if (nelem < nelem_min or nthread < 2)
+    {
+        bss::spinsort<Iter_t, Compare>
+            (range_initial.first, range_initial.last, comp);
+        return;
+    };
+
+    //------------------- check if sort --------------------------------------
+    bool sw = true;
+    for (Iter_t it1 = first, it2 = first + 1;
+         it2 != last and (sw = not comp(*it2, *it1)); it1 = it2++);
+    if (sw) return;
+
+    //------------------- check if reverse sort ---------------------------
+    sw = true;
+    for (Iter_t it1 = first, it2 = first + 1;
+         it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
+    if (sw)
+    {
+        size_t nelem2 = nelem >> 1;
+        Iter_t it1 = first, it2 = last - 1;
+        for (size_t i = 0; i < nelem2; ++i)
+            std::swap(*(it1++), *(it2--));
+        return;
+    };
+
+    ptr = std::get_temporary_buffer<value_t>(nptr).first;
+    if (ptr == nullptr) throw std::bad_alloc();
+
+    //---------------------------------------------------------------------
+    //     Parallel Process
+    //---------------------------------------------------------------------
+    range<Iter_t> range_first(range_initial.first, range_initial.first + nptr);
+
+    range<Iter_t> range_second(range_initial.first + nptr, range_initial.last);
+
+    range<value_t *> range_buffer(ptr, ptr + nptr);
+
+    try
+    {
+        sample_sort<Iter_t, Compare>
+            (range_initial.first, range_initial.first + nptr,
+             comp, nthread, range_buffer);
+    } catch (std::bad_alloc &)
+    {
+        destroy_all();
+        throw std::bad_alloc();
+    };
+
+    try
+    {
+        sample_sort<Iter_t, Compare>
+            (range_initial.first + nptr,
+             range_initial.last, comp, nthread, range_buffer);
+    } catch (std::bad_alloc &)
+    {
+        destroy_all();
+        throw std::bad_alloc();
+    };
+
+    range_buffer = move_forward(range_buffer, range_first);
+    range_initial = merge_half(range_initial, range_buffer, range_second, comp);
+}; // end of constructor
+
+//
+//****************************************************************************
+};//    End namespace stable_detail
+//****************************************************************************
+//
+
+//---------------------------------------------------------------------------
+//                    USING SENTENCES
+//---------------------------------------------------------------------------
+namespace bsc = boost::sort::common;
+namespace bscu = bsc::util;
+namespace bss = boost::sort::spin_detail;
+using bsc::range;
+using bsc::merge_half;
+//
+//############################################################################
+//                                                                          ##
+//                                                                          ##
+//            P A R A L L E L _ S T A B L E _ S O R T                       ##
+//                                                                          ##
+//                                                                          ##
+//############################################################################
+//
+//-----------------------------------------------------------------------------
+//  function : parallel_stable_sort
+/// @brief : parallel stable sort with 2 parameters
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+void parallel_stable_sort(Iter_t first, Iter_t last)
+{
+    typedef bscu::compare_iter<Iter_t> Compare;
+    stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : parallel_stable_sort
+/// @brief parallel stable sort with 3 parameters. The third is the number 
+///        of threads
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param nthread : Number of threads to use in the process. When this value
+///                  is lower than 2, the sorting is done with 1 thread
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+void parallel_stable_sort(Iter_t first, Iter_t last, uint32_t nthread)
+{
+    typedef bscu::compare_iter<Iter_t> Compare;
+    stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last, nthread);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : parallel_stable_sort
+/// @brief : parallel stable sort with 3 parameters. The thisrd is the 
+///          comparison object
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+//-----------------------------------------------------------------------------
+template <class Iter_t, class Compare,
+          bscu::enable_if_not_integral<Compare> * = nullptr>
+void parallel_stable_sort(Iter_t first, Iter_t last, Compare comp)
+{
+    stable_detail::parallel_stable_sort<Iter_t, Compare>(first, last, comp);
+};
+
+//
+//-----------------------------------------------------------------------------
+//  function : parallel_stable_sort
+/// @brief : parallel stable sort with 3 parameters. 
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+/// @param nthread : Number of threads to use in the process. When this value
+///                  is lower than 2, the sorting is done with 1 thread
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Compare>
+void parallel_stable_sort (Iter_t first, Iter_t last, Compare comp,
+                          uint32_t nthread)
+{
+    stable_detail::parallel_stable_sort<Iter_t, Compare>
+                                                (first, last, comp, nthread);
+}
+//
+//****************************************************************************
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/sample_sort/sample_sort.hpp b/vendor/boost/sort/sample_sort/sample_sort.hpp
new file mode 100644
index 00000000..ded1781c
--- /dev/null
+++ b/vendor/boost/sort/sample_sort/sample_sort.hpp
@@ -0,0 +1,560 @@
+//----------------------------------------------------------------------------
+/// @file sample_sort.hpp
+/// @brief contains the class sample_sort
+///
+/// @author Copyright (c) 2016 Francisco Jose Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_DETAIL_SAMPLE_SORT_HPP
+#define __BOOST_SORT_PARALLEL_DETAIL_SAMPLE_SORT_HPP
+
+#include <functional>
+#include <future>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include <algorithm>
+#include <boost/sort/spinsort/spinsort.hpp>
+#include <boost/sort/common/indirect.hpp>
+#include <boost/sort/common/util/atomic.hpp>
+#include <boost/sort/common/merge_four.hpp>
+#include <boost/sort/common/merge_vector.hpp>
+#include <boost/sort/common/range.hpp>
+
+namespace boost
+{
+namespace sort
+{
+namespace sample_detail
+{
+//---------------------------------------------------------------------------
+//                    USING SENTENCES
+//---------------------------------------------------------------------------
+namespace bsc = boost::sort::common;
+namespace bss = boost::sort::spin_detail;
+namespace bscu = boost::sort::common::util;
+using bsc::range;
+using bscu::atomic_add;
+using bsc::merge_vector4;
+using bsc::uninit_merge_level4;
+using bsc::less_ptr_no_null;
+
+//
+///---------------------------------------------------------------------------
+/// @struct sample_sort
+/// @brief This a structure for to implement a sample sort, exception
+///        safe
+/// @tparam
+/// @remarks
+//----------------------------------------------------------------------------
+template<class Iter_t, class Compare>
+struct sample_sort
+{
+    //------------------------------------------------------------------------
+    //                     DEFINITIONS
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter_t> value_t;
+    typedef range<Iter_t> range_it;
+    typedef range<value_t *> range_buf;
+    typedef sample_sort<Iter_t, Compare> this_t;
+
+    //------------------------------------------------------------------------
+    //                VARIABLES AND CONSTANTS
+    //------------------------------------------------------------------------
+    // minimun numbers of elements for to be sortd in parallel mode
+    static const uint32_t thread_min = (1 << 16);
+
+    // Number of threads to use in the algorithm
+    // Number of intervals for to do the internal division of the data
+    uint32_t nthread, ninterval;
+
+    // Bool variables indicating if the auxiliary memory is constructed
+    // and indicating in the auxiliary memory had been obtained inside the
+    /// algorithm or had been received as a parameter
+    bool construct = false, owner = false;
+
+    // Comparison object for to compare two elements
+    Compare comp;
+
+    // Range with all the elements to sort
+    range_it global_range;
+
+    // range with the auxiliary memory
+    range_buf global_buf;
+
+    // vector of futures
+    std::vector<std::future<void>> vfuture;
+
+    // vector of vectors which contains the ranges to merge obtained in the
+    // subdivision
+    std::vector<std::vector<range_it>> vv_range_it;
+
+    // each vector of ranges of the vv_range_it, need their corresponding buffer
+    // for to do the merge
+    std::vector<std::vector<range_buf>> vv_range_buf;
+
+    // Initial vector of ranges
+    std::vector<range_it> vrange_it_ini;
+
+    // Initial vector of buffers
+    std::vector<range_buf> vrange_buf_ini;
+
+    // atomic counter for to know when are finished the function_t created
+    // inside a function
+    std::atomic<uint32_t> njob;
+
+    // Indicate if an error in the algorithm for to undo all
+    bool error;
+
+    //------------------------------------------------------------------------
+    //                       FUNCTIONS OF THE STRUCT
+    //------------------------------------------------------------------------
+    void initial_configuration(void);
+
+    sample_sort (Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
+                 value_t *paux, size_t naux);
+
+    sample_sort(Iter_t first, Iter_t last)
+    : sample_sort (first, last, Compare(), std::thread::hardware_concurrency(),
+                   nullptr, 0) { };
+
+    sample_sort(Iter_t first, Iter_t last, Compare cmp)
+    : sample_sort(first, last, cmp, std::thread::hardware_concurrency(),
+                  nullptr, 0) { };
+
+    sample_sort(Iter_t first, Iter_t last, uint32_t num_thread)
+    : sample_sort(first, last, Compare(), num_thread, nullptr, 0) { };
+
+    sample_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread)
+    : sample_sort(first, last, cmp, num_thread, nullptr, 0) { };
+
+    sample_sort(Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
+                range_buf range_buf_initial)
+    : sample_sort(first, last, cmp, num_thread,
+                  range_buf_initial.first, range_buf_initial.size()) { };
+
+    void destroy_all(void);
+    //
+    //-----------------------------------------------------------------------------
+    //  function :~sample_sort
+    /// @brief destructor of the class. The utility is to destroy the temporary
+    ///        buffer used in the sorting process
+    //-----------------------------------------------------------------------------
+    ~sample_sort(void) { destroy_all(); };
+    //
+    //-----------------------------------------------------------------------
+    //  function : execute first
+    /// @brief this a function to assign to each thread in the first merge
+    //-----------------------------------------------------------------------
+    void execute_first(void)
+    {
+        uint32_t job = 0;
+        while ((job = atomic_add(njob, 1)) < ninterval)
+        {
+            uninit_merge_level4(vrange_buf_ini[job], vv_range_it[job],
+                            vv_range_buf[job], comp);
+        };
+    };
+    //
+    //-----------------------------------------------------------------------
+    //  function : execute
+    /// @brief this is a function to assignt each thread the final merge
+    //-----------------------------------------------------------------------
+    void execute(void)
+    {
+        uint32_t job = 0;
+        while ((job = atomic_add(njob, 1)) < ninterval)
+        {
+            merge_vector4(vrange_buf_ini[job], vrange_it_ini[job],
+                            vv_range_buf[job], vv_range_it[job], comp);
+        };
+    };
+    //
+    //-----------------------------------------------------------------------
+    //  function : first merge
+    /// @brief Implement the merge of the initially sparse ranges
+    //-----------------------------------------------------------------------
+    void first_merge(void)
+    { //---------------------------------- begin --------------------------
+        njob = 0;
+
+        for (uint32_t i = 0; i < nthread; ++i)
+        {
+            vfuture[i] = std::async(std::launch::async, &this_t::execute_first,
+                            this);
+        };
+        for (uint32_t i = 0; i < nthread; ++i)
+            vfuture[i].get();
+    };
+    //
+    //-----------------------------------------------------------------------
+    //  function : final merge
+    /// @brief Implement the final merge of the ranges
+    //-----------------------------------------------------------------------
+    void final_merge(void)
+    { //---------------------------------- begin --------------------------
+        njob = 0;
+
+        for (uint32_t i = 0; i < nthread; ++i)
+        {
+            vfuture[i] = std::async(std::launch::async, &this_t::execute, this);
+        };
+        for (uint32_t i = 0; i < nthread; ++i)
+            vfuture[i].get();
+    };
+    //----------------------------------------------------------------------------
+};
+//                    End class sample_sort
+//----------------------------------------------------------------------------
+//
+//############################################################################
+//                                                                          ##
+//              N O N    I N L I N E      F U N C T I O N S                 ##
+//                                                                          ##
+//                                                                          ##
+//############################################################################
+//
+//-----------------------------------------------------------------------------
+//  function : sample_sort
+/// @brief constructor of the class
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param cmp : object for to compare two elements pointed by Iter_t iterators
+/// @param num_thread : Number of threads to use in the process. When this value
+///                     is lower than 2, the sorting is done with 1 thread
+/// @param paux : pointer to the auxiliary memory. If nullptr, the memory is
+///               created inside the class
+/// @param naux : number of elements of the memory pointed by paux
+//-----------------------------------------------------------------------------
+template<class Iter_t, typename Compare>
+sample_sort<Iter_t, Compare>
+::sample_sort (Iter_t first, Iter_t last, Compare cmp, uint32_t num_thread,
+               value_t *paux, size_t naux)
+: nthread(num_thread), owner(false), comp(cmp), global_range(first, last),
+  global_buf(nullptr, nullptr), error(false)
+{
+    assert((last - first) >= 0);
+    size_t nelem = size_t(last - first);
+    construct = false;
+    njob = 0;
+    vfuture.resize(nthread);
+
+    // Adjust when have many threads and only a few elements
+    while (nelem > thread_min and (nthread * nthread) > (nelem >> 3))
+    {
+        nthread /= 2;
+    };
+    ninterval = (nthread << 3);
+
+    if (nthread < 2 or nelem <= (thread_min))
+    {
+        bss::spinsort<Iter_t, Compare>(first, last, comp);
+        return;
+    };
+
+    //------------------- check if sort --------------------------------------
+    bool sw = true;
+    for (Iter_t it1 = first, it2 = first + 1;
+                    it2 != last and (sw = not comp(*it2, *it1)); it1 = it2++);
+    if (sw) return;
+
+    //------------------- check if reverse sort ---------------------------
+    sw = true;
+    for (Iter_t it1 = first, it2 = first + 1;
+                    it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
+    if (sw)
+    {
+        size_t nelem2 = nelem >> 1;
+        Iter_t it1 = first, it2 = last - 1;
+        for (size_t i = 0; i < nelem2; ++i)
+            std::swap(*(it1++), *(it2--));
+        return;
+    };
+
+    if (paux != nullptr)
+    {
+        assert(naux != 0);
+        global_buf.first = paux;
+        global_buf.last = paux + naux;
+        owner = false;
+    }
+    else
+    {
+        value_t *ptr = std::get_temporary_buffer<value_t>(nelem).first;
+        if (ptr == nullptr) throw std::bad_alloc();
+        owner = true;
+        global_buf = range_buf(ptr, ptr + nelem);
+    };
+    //------------------------------------------------------------------------
+    //                    PROCESS
+    //------------------------------------------------------------------------
+    try
+    {
+        initial_configuration();
+    } catch (std::bad_alloc &)
+    {
+        error = true;
+    };
+    if (not error)
+    {
+        first_merge();
+        construct = true;
+        final_merge();
+    };
+    if (error)
+    {
+        destroy_all();
+        throw std::bad_alloc();
+    };
+}
+;
+//
+//-----------------------------------------------------------------------------
+//  function : destroy_all
+/// @brief destructor of the class. The utility is to destroy the temporary
+///        buffer used in the sorting process
+//-----------------------------------------------------------------------------
+template<class Iter_t, typename Compare>
+void sample_sort<Iter_t, Compare>::destroy_all(void)
+{
+    if (construct)
+    {
+        destroy(global_buf);
+        construct = false;
+    }
+    if (global_buf.first != nullptr and owner)
+        std::return_temporary_buffer(global_buf.first);
+}
+//
+//-----------------------------------------------------------------------------
+//  function : initial_configuration
+/// @brief Create the internal data structures, and obtain the inital set of
+///        ranges to merge
+//-----------------------------------------------------------------------------
+template<class Iter_t, typename Compare>
+void sample_sort<Iter_t, Compare>::initial_configuration(void)
+{
+    std::vector<range_it> vmem_thread;
+    std::vector<range_buf> vbuf_thread;
+    size_t nelem = global_range.size();
+
+    //------------------------------------------------------------------------
+    size_t cupo = nelem / nthread;
+    Iter_t it_first = global_range.first;
+    value_t *buf_first = global_buf.first;
+    vmem_thread.reserve(nthread + 1);
+    vbuf_thread.reserve(nthread + 1);
+
+    for (uint32_t i = 0; i < (nthread - 1); ++i, it_first += cupo, buf_first +=
+                    cupo)
+    {
+        vmem_thread.emplace_back(it_first, it_first + cupo);
+        vbuf_thread.emplace_back(buf_first, buf_first + cupo);
+    };
+
+    vmem_thread.emplace_back(it_first, global_range.last);
+    vbuf_thread.emplace_back(buf_first, global_buf.last);
+
+    //------------------------------------------------------------------------
+    // Sorting of the ranges
+    //------------------------------------------------------------------------
+    std::vector<std::future<void>> vfuture(nthread);
+
+    for (uint32_t i = 0; i < nthread; ++i)
+    {
+        auto func = [=]()
+        {
+            bss::spinsort<Iter_t, Compare> (vmem_thread[i].first,
+                            vmem_thread[i].last, comp,
+                            vbuf_thread[i]);
+        };
+        vfuture[i] = std::async(std::launch::async, func);
+    };
+
+    for (uint32_t i = 0; i < nthread; ++i)
+        vfuture[i].get();
+
+    //------------------------------------------------------------------------
+    // Obtain the vector of milestones
+    //------------------------------------------------------------------------
+    std::vector<Iter_t> vsample;
+    vsample.reserve(nthread * (ninterval - 1));
+
+    for (uint32_t i = 0; i < nthread; ++i)
+    {
+        size_t distance = vmem_thread[i].size() / ninterval;
+        for (size_t j = 1, pos = distance; j < ninterval; ++j, pos += distance)
+        {
+            vsample.push_back(vmem_thread[i].first + pos);
+        };
+    };
+    typedef less_ptr_no_null<Iter_t, Compare> compare_ptr;
+    typedef typename std::vector<Iter_t>::iterator it_to_it;
+
+    bss::spinsort<it_to_it, compare_ptr>(vsample.begin(), vsample.end(),
+                    compare_ptr(comp));
+
+    //------------------------------------------------------------------------
+    // Create the final milestone vector
+    //------------------------------------------------------------------------
+    std::vector<Iter_t> vmilestone;
+    vmilestone.reserve(ninterval);
+
+    for (uint32_t pos = nthread >> 1; pos < vsample.size(); pos += nthread)
+    {
+        vmilestone.push_back(vsample[pos]);
+    };
+
+    //------------------------------------------------------------------------
+    // Creation of the first vector of ranges
+    //------------------------------------------------------------------------
+    std::vector<std::vector<range<Iter_t>>>vv_range_first (nthread);
+
+    for (uint32_t i = 0; i < nthread; ++i)
+    {
+        Iter_t itaux = vmem_thread[i].first;
+
+        for (uint32_t k = 0; k < (ninterval - 1); ++k)
+        {
+            Iter_t it2 = std::upper_bound(itaux, vmem_thread[i].last,
+                            *vmilestone[k], comp);
+
+            vv_range_first[i].emplace_back(itaux, it2);
+            itaux = it2;
+        };
+        vv_range_first[i].emplace_back(itaux, vmem_thread[i].last);
+    };
+
+    //------------------------------------------------------------------------
+    // Copy in buffer and  creation of the final matrix of ranges
+    //------------------------------------------------------------------------
+    vv_range_it.resize(ninterval);
+    vv_range_buf.resize(ninterval);
+    vrange_it_ini.reserve(ninterval);
+    vrange_buf_ini.reserve(ninterval);
+
+    for (uint32_t i = 0; i < ninterval; ++i)
+    {
+        vv_range_it[i].reserve(nthread);
+        vv_range_buf[i].reserve(nthread);
+    };
+
+    Iter_t it = global_range.first;
+    value_t *it_buf = global_buf.first;
+
+    for (uint32_t k = 0; k < ninterval; ++k)
+    {
+        size_t nelem_interval = 0;
+
+        for (uint32_t i = 0; i < nthread; ++i)
+        {
+            size_t nelem_range = vv_range_first[i][k].size();
+            if (nelem_range != 0)
+            {
+                vv_range_it[k].push_back(vv_range_first[i][k]);
+            };
+            nelem_interval += nelem_range;
+        };
+
+        vrange_it_ini.emplace_back(it, it + nelem_interval);
+        vrange_buf_ini.emplace_back(it_buf, it_buf + nelem_interval);
+
+        it += nelem_interval;
+        it_buf += nelem_interval;
+    };
+}
+;
+//
+//****************************************************************************
+}
+;
+//    End namespace sample_detail
+//****************************************************************************
+//
+namespace bscu = boost::sort::common::util;
+//
+//############################################################################
+//                                                                          ##
+//                                                                          ##
+//                       S A M P L E _ S O R T                              ##
+//                                                                          ##
+//                                                                          ##
+//############################################################################
+//
+//-----------------------------------------------------------------------------
+//  function : sample_sort
+/// @brief parallel sample sort  algorithm (stable sort)
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+void sample_sort(Iter_t first, Iter_t last)
+{
+    typedef compare_iter<Iter_t> Compare;
+    sample_detail::sample_sort<Iter_t, Compare>(first, last);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : sample_sort
+/// @brief parallel sample sort  algorithm (stable sort)
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param nthread : Number of threads to use in the process. When this value
+///                  is lower than 2, the sorting is done with 1 thread
+//-----------------------------------------------------------------------------
+template<class Iter_t>
+void sample_sort(Iter_t first, Iter_t last, uint32_t nthread)
+{
+    typedef compare_iter<Iter_t> Compare;
+    sample_detail::sample_sort<Iter_t, Compare>(first, last, nthread);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : sample_sort
+/// @brief parallel sample sort  algorithm (stable sort)
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Compare, bscu::enable_if_not_integral<Compare> * =
+                nullptr>
+void sample_sort(Iter_t first, Iter_t last, Compare comp)
+{
+    sample_detail::sample_sort<Iter_t, Compare>(first, last, comp);
+};
+//
+//-----------------------------------------------------------------------------
+//  function : sample_sort
+/// @brief parallel sample sort  algorithm (stable sort)
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+/// @param nthread : Number of threads to use in the process. When this value
+///                  is lower than 2, the sorting is done with 1 thread
+//-----------------------------------------------------------------------------
+template<class Iter_t, class Compare>
+void sample_sort(Iter_t first, Iter_t last, Compare comp, uint32_t nthread)
+{
+    sample_detail::sample_sort<Iter_t, Compare>(first, last, comp, nthread);
+};
+//
+//****************************************************************************
+};//    End namespace sort
+};//    End namespace boost
+//****************************************************************************
+//
+#endif
diff --git a/vendor/boost/sort/spinsort/spinsort.hpp b/vendor/boost/sort/spinsort/spinsort.hpp
new file mode 100644
index 00000000..0e9f2d55
--- /dev/null
+++ b/vendor/boost/sort/spinsort/spinsort.hpp
@@ -0,0 +1,564 @@
+//----------------------------------------------------------------------------
+/// @file spinsort.hpp
+/// @brief Spin Sort algorithm
+///
+/// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
+///         Distributed under the Boost Software License, Version 1.0.\n
+///         ( See accompanying file LICENSE_1_0.txt or copy at
+///           http://www.boost.org/LICENSE_1_0.txt  )
+/// @version 0.1
+///
+/// @remarks
+//-----------------------------------------------------------------------------
+#ifndef __BOOST_SORT_PARALLEL_ALGORITHM_SPIN_SORT_HPP
+#define __BOOST_SORT_PARALLEL_ALGORITHM_SPIN_SORT_HPP
+
+//#include <boost/sort/spinsort/util/indirect.hpp>
+#include <boost/sort/insert_sort/insert_sort.hpp>
+#include <boost/sort/common/util/traits.hpp>
+#include <boost/sort/common/util/algorithm.hpp>
+#include <boost/sort/common/range.hpp>
+#include <boost/sort/common/indirect.hpp>
+#include <cstdlib>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+#include <cstddef>
+
+namespace boost
+{
+namespace sort
+{
+namespace spin_detail
+{
+
+//----------------------------------------------------------------------------
+//                USING SENTENCES
+//----------------------------------------------------------------------------
+namespace bsc = boost::sort::common;
+using bsc::range;
+using bsc::util::nbits64;
+using bsc::util::compare_iter;
+using bsc::util::value_iter;
+using boost::sort::insert_sort;
+
+//
+//############################################################################
+//                                                                          ##
+//          D E F I N I T I O N S    O F    F U N C T I O N S               ##
+//                                                                          ##
+//############################################################################
+//
+template <class Iter1_t, class Iter2_t, typename Compare>
+static void insert_partial_sort (Iter1_t first, Iter1_t mid,
+                                 Iter1_t last, Compare comp,
+                                 const range<Iter2_t> &rng_aux);
+
+template<class Iter1_t, class Iter2_t, class Compare>
+static bool check_stable_sort (const range<Iter1_t> &rng_data,
+                               const range<Iter2_t> &rng_aux, Compare comp);
+
+template<class Iter1_t, class Iter2_t, class Compare>
+static void range_sort (const range<Iter1_t> &range1,
+                        const range<Iter2_t> &range2, Compare comp,
+                        uint32_t level);
+
+template<class Iter1_t, class Iter2_t, class Compare>
+static void sort_range_sort (const range<Iter1_t> &rng_data,
+                             const range<Iter2_t> &rng_aux, Compare comp);
+
+//
+//-----------------------------------------------------------------------------
+//  function : insert_partial_sort
+/// @brief : Insertion sort of elements sorted
+/// @param first: iterator to the first element of the range
+/// @param mid : last pointer of the sorted data, and first pointer to the
+///               elements to insert
+/// @param last : iterator to the next element of the last in the range
+/// @param comp :
+/// @comments : the two ranges are sorted
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, typename Compare>
+static void insert_partial_sort (Iter1_t first, Iter1_t mid, Iter1_t last,
+                                 Compare comp, const range<Iter2_t> &rng_aux)
+{
+    //------------------------------------------------------------------------
+    //                 metaprogram
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same<value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //--------------------------------------------------------------------
+    //                   program
+    //--------------------------------------------------------------------
+    assert(size_t(last - mid) <= rng_aux.size());
+
+    if (mid == last) return;
+    //insertionsort ( mid, last, comp);
+    if (first == mid) return;
+
+    //------------------------------------------------------------------------
+    // creation of the vector of elements to insert and their position in the
+    // sorted part
+    // the data are inserted in rng_aux
+    //-----------------------------------------------------------------------
+    std::vector<Iter1_t> viter;
+    Iter2_t beta = rng_aux.first, data = rng_aux.first;
+
+    for (Iter1_t alpha = mid; alpha != last; ++alpha)
+        *(beta++) = std::move(*alpha);
+
+    size_t ndata = last - mid;
+
+    Iter1_t linf = first, lsup = mid;
+    for (uint32_t i = 0; i < ndata; ++i)
+    {
+        Iter1_t it1 = std::upper_bound(linf, lsup, *(data + i), comp);
+        viter.push_back(it1);
+        linf = it1;
+    };
+
+    // moving the elements
+    viter.push_back(mid);
+    for (uint32_t i = viter.size() - 1; i != 0; --i)
+    {
+        Iter1_t src = viter[i], limit = viter[i - 1];
+        Iter1_t dest = src + (i);
+        while (src != limit) *(--dest) = std::move(*(--src));
+        *(viter[i - 1] + (i - 1)) = std::move(*(data + (i - 1)));
+    };
+}
+;
+//-----------------------------------------------------------------------------
+//  function : check_stable_sort
+/// @brief check if the elements between first and last are osted or reverse
+///        sorted. If the number of elements not sorted is small, insert in
+///        the sorted part
+/// @param range_input : range with the elements to sort
+/// @param range_buffer : range with the elements sorted
+/// @param comp : object for to compare two elements
+/// @param level : when is 1, sort with the insertionsort algorithm
+///                if not make a recursive call splitting the ranges
+//
+/// @comments : if the number of levels is odd, the data are in the first
+/// parameter of range_sort, and the results appear in the second parameter
+/// If the number of levels is even, the data are in the second
+/// parameter of range_sort, and the results are in the same parameter
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static bool check_stable_sort(const range<Iter1_t> &rng_data,
+                              const range<Iter2_t> &rng_aux, Compare comp)
+{
+    //------------------------------------------------------------------------
+    //              metaprogramming
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same<value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                    program
+    //------------------------------------------------------------------------
+    // the maximun number of elements not ordered, for to be inserted in the
+    // sorted part
+    //const ptrdiff_t  min_insert_partial_sort = 32 ;
+    const size_t ndata = rng_data.size();
+    if (ndata < 32)
+    {
+        insert_sort(rng_data.first, rng_data.last, comp);
+        return true;
+    };
+    const size_t min_insert_partial_sort =
+                    ((ndata >> 3) < 33) ? 32 : (ndata >> 3);
+    if (ndata < 2) return true;
+
+    // check if sorted
+    bool sw = true;
+    Iter1_t it2 = rng_data.first + 1;
+    for (Iter1_t it1 = rng_data.first;
+                    it2 != rng_data.last and (sw = not comp(*it2, *it1)); it1 =
+                                    it2++)
+        ;
+    if (sw) return true;
+
+    // insert the elements between it1 and last
+    if (size_t(rng_data.last - it2) < min_insert_partial_sort)
+    {
+        sort_range_sort(range<Iter1_t>(it2, rng_data.last), rng_aux, comp);
+        insert_partial_sort(rng_data.first, it2, rng_data.last, comp, rng_aux);
+        return true;
+    };
+
+    // check if reverse sorted
+    if ((it2 != (rng_data.first + 1))) return false;
+    sw = true;
+    for (Iter1_t it1 = rng_data.first;
+                    it2 != rng_data.last and (sw = comp(*it2, *it1)); it1 =
+                                    it2++)
+        ;
+    if (size_t(rng_data.last - it2) >= min_insert_partial_sort) return false;
+
+    // reverse the elements between first and it1
+    size_t nreverse = it2 - rng_data.first;
+    Iter1_t alpha(rng_data.first), beta(it2 - 1), mid(
+                    rng_data.first + (nreverse >> 1));
+    while (alpha != mid)
+        std::swap(*(alpha++), *(beta--));
+
+    // insert the elements between it1 and last
+    if (it2 != rng_data.last)
+    {
+        sort_range_sort(range<Iter1_t>(it2, rng_data.last), rng_aux, comp);
+        insert_partial_sort(rng_data.first, it2, rng_data.last, comp, rng_aux);
+    };
+    return true;
+}
+;
+//-----------------------------------------------------------------------------
+//  function : range_sort
+/// @brief this function divide r_input in two parts, sort it,and merge moving
+///        the elements to range_buf
+/// @param range_input : range with the elements to sort
+/// @param range_buffer : range with the elements sorted
+/// @param comp : object for to compare two elements
+/// @param level : when is 1, sort with the insertionsort algorithm
+///                if not make a recursive call splitting the ranges
+//
+/// @comments : if the number of levels is odd, the data are in the first
+/// parameter of range_sort, and the results appear in the second parameter
+/// If the number of levels is even, the data are in the second
+/// parameter of range_sort, and the results are in the same parameter
+/// The two ranges must have the same size
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static void range_sort(const range<Iter1_t> &range1,
+                       const range<Iter2_t> &range2, Compare comp,
+                       uint32_t level)
+{
+    //-----------------------------------------------------------------------
+    //                  metaprogram
+    //-----------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same<value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //-----------------------------------------------------------------------
+    //                  program
+    //-----------------------------------------------------------------------
+    typedef range<Iter1_t> range_it1;
+    typedef range<Iter2_t> range_it2;
+    assert(range1.size() == range2.size() and level != 0);
+
+    //------------------- check if sort --------------------------------------
+    if (range1.size() > 1024)
+    {
+        if ((level & 1) == 0)
+        {
+            if (check_stable_sort(range2, range1, comp)) return;
+        }
+        else
+        {
+            if (check_stable_sort(range1, range2, comp))
+            {
+                move_forward(range2, range1);
+                return;
+            };
+        };
+    };
+
+    //------------------- normal process -----------------------------------
+    size_t nelem1 = (range1.size() + 1) >> 1;
+    range_it1 range_input1(range1.first, range1.first + nelem1),
+                           range_input2(range1.first + nelem1, range1.last);
+
+    if (level < 2)
+    {
+        insert_sort(range_input1.first, range_input1.last, comp);
+        insert_sort(range_input2.first, range_input2.last, comp);
+    }
+    else
+    {
+        range_sort (range_it2(range2.first, range2.first + nelem1),
+                    range_input1, comp, level - 1);
+
+        range_sort (range_it2(range2.first + nelem1, range2.last),
+                    range_input2, comp, level - 1);
+    };
+
+    merge(range2, range_input1, range_input2, comp);
+}
+;
+//-----------------------------------------------------------------------------
+//  function : sort_range_sort
+/// @brief this sort elements using the range_sort function and receiving a
+///        buffer of initialized memory
+/// @param rng_data : range with the elements to sort
+/// @param rng_aux : range of at least the same memory than rng_data used as
+///                  auxiliary memory in the sorting
+/// @param comp : object for to compare two elements
+//-----------------------------------------------------------------------------
+template<class Iter1_t, class Iter2_t, class Compare>
+static void sort_range_sort(const range<Iter1_t> &rng_data,
+                            const range<Iter2_t> &rng_aux, Compare comp)
+{
+    //-----------------------------------------------------------------------
+    //                  metaprogram
+    //-----------------------------------------------------------------------
+    typedef value_iter<Iter1_t> value_t;
+    typedef value_iter<Iter2_t> value2_t;
+    static_assert (std::is_same<value_t, value2_t>::value,
+                    "Incompatible iterators\n");
+
+    //------------------------------------------------------------------------
+    //                    program
+    //------------------------------------------------------------------------
+    // minimal number of element before to jump to insertionsort
+    static const uint32_t sort_min = 32;
+    if (rng_data.size() <= sort_min)
+    {
+        insert_sort(rng_data.first, rng_data.last, comp);
+        return;
+    };
+
+#ifdef __BS_DEBUG
+    assert (rng_aux.size () >= rng_data.size ());
+#endif
+
+    range<Iter2_t> rng_buffer(rng_aux.first, rng_aux.first + rng_data.size());
+    uint32_t nlevel =
+                    nbits64(((rng_data.size() + sort_min - 1) / sort_min) - 1);
+    //assert (nlevel != 0);
+
+    if ((nlevel & 1) == 0)
+    {
+        range_sort(rng_buffer, rng_data, comp, nlevel);
+    }
+    else
+    {
+        range_sort(rng_data, rng_buffer, comp, nlevel);
+        move_forward(rng_data, rng_buffer);
+    };
+}
+;
+//
+//############################################################################
+//                                                                          ##
+//                              S T R U C T                                 ##
+//                                                                          ##
+//                           S P I N _ S O R T                              ##
+//                                                                          ##
+//############################################################################
+//---------------------------------------------------------------------------
+/// @struct spin_sort
+/// @brief  This class implement s stable sort algorithm with 1 thread, with
+///         an auxiliary memory of N/2 elements
+//----------------------------------------------------------------------------
+template<class Iter_t, typename Compare = compare_iter<Iter_t>>
+class spinsort
+{
+    //------------------------------------------------------------------------
+    //               DEFINITIONS AND CONSTANTS
+    //------------------------------------------------------------------------
+    typedef value_iter<Iter_t> value_t;
+    typedef range<Iter_t> range_it;
+    typedef range<value_t *> range_buf;
+    // When the number of elements to sort is smaller than Sort_min, are sorted
+    // by the insertion sort algorithm
+    static const uint32_t Sort_min = 36;
+
+    //------------------------------------------------------------------------
+    //                      VARIABLES
+    //------------------------------------------------------------------------
+    // Pointer to the auxiliary memory
+    value_t *ptr;
+
+    // Number of elements in the auxiliary memory
+    size_t nptr;
+
+    // construct indicate if the auxiliary memory in initialized, and owner
+    // indicate if the auxiliary memory had been created inside the object or
+    // had
+    // been received as a parameter
+    bool construct = false, owner = false;
+
+    //------------------------------------------------------------------------
+    //                   PRIVATE FUNCTIONS
+    //-------------------------------------------------------------------------
+    spinsort (Iter_t first, Iter_t last, Compare comp, value_t *paux,
+               size_t naux);
+
+public:
+    //------------------------------------------------------------------------
+    //                   PUBLIC FUNCTIONS
+    //-------------------------------------------------------------------------
+    spinsort(Iter_t first, Iter_t last, Compare comp = Compare())
+    : spinsort(first, last, comp, nullptr, 0) { };
+
+    spinsort(Iter_t first, Iter_t last, Compare comp, range_buf range_aux)
+    : spinsort(first, last, comp, range_aux.first, range_aux.size()) { };
+    //
+    //-----------------------------------------------------------------------
+    //  function :~spinsort
+    /// @brief destructor of the struct. Destroy the elements if construct is
+    /// true,
+    ///        and return the memory if owner is true
+    //-----------------------------------------------------------------------
+    ~spinsort(void)
+    {
+        if (construct)
+        {
+            destroy(range<value_t *>(ptr, ptr + nptr));
+            construct = false;
+        };
+        if (owner and ptr != nullptr) std::return_temporary_buffer(ptr);
+    };
+};
+//----------------------------------------------------------------------------
+//        End of class spinsort
+//----------------------------------------------------------------------------
+//
+//-------------------------------------------------------------------------
+//  function : spinsort
+/// @brief constructor of the struct
+//
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+/// @param paux : pointer to the auxiliary memory provided. If nullptr, the
+///               memory is created inside the class
+/// @param naux : number of elements pointed by paux
+//------------------------------------------------------------------------
+template <class Iter_t, typename Compare>
+spinsort <Iter_t, Compare>
+::spinsort (Iter_t first, Iter_t last, Compare comp, value_t *paux, size_t naux)
+: ptr(paux), nptr(naux), construct(false), owner(false)
+{
+    range<Iter_t> range_input(first, last);
+    assert(range_input.valid());
+
+    size_t nelem = range_input.size();
+    owner = construct = false;
+
+    nptr = (nelem + 1) >> 1;
+    size_t nelem_1 = nptr;
+    size_t nelem_2 = nelem - nelem_1;
+
+    if (nelem <= (Sort_min << 1))
+    {
+        insert_sort(range_input.first, range_input.last, comp);
+        return;
+    };
+
+    //------------------- check if sort ---------------------------------
+    bool sw = true;
+    for (Iter_t it1 = first, it2 = first + 1; it2 != last
+         and (sw = not comp(*it2, *it1)); it1 = it2++) ;
+    if (sw) return;
+
+    //------------------- check if reverse sort -------------------------
+    sw = true;
+    for (Iter_t it1 = first, it2 = first + 1;
+         it2 != last and (sw = comp(*it2, *it1)); it1 = it2++);
+    if (sw)
+    {
+        size_t nelem2 = nelem >> 1;
+        Iter_t it1 = first, it2 = last - 1;
+        for (size_t i = 0; i < nelem2; ++i)
+            std::swap(*(it1++), *(it2--));
+        return;
+    };
+
+    if (ptr == nullptr)
+    {
+        ptr = std::get_temporary_buffer<value_t>(nptr).first;
+        if (ptr == nullptr) throw std::bad_alloc();
+        owner = true;
+    };
+    range_buf range_aux(ptr, (ptr + nptr));
+
+    //---------------------------------------------------------------------
+    //                  Process
+    //---------------------------------------------------------------------
+    uint32_t nlevel = nbits64(((nelem + Sort_min - 1) / Sort_min) - 1) - 1;
+    assert(nlevel != 0);
+
+    if ((nlevel & 1) == 1)
+    {
+        //----------------------------------------------------------------
+        // if the number of levels is odd, the data are in the first
+        // parameter of range_sort, and the results appear in the second
+        // parameter
+        //----------------------------------------------------------------
+        range_it range_1(first, first + nelem_2), range_2(first + nelem_2,
+                        last);
+        range_aux = move_construct(range_aux, range_2);
+        construct = true;
+
+        range_sort(range_aux, range_2, comp, nlevel);
+        range_buf rng_bx(range_aux.first, range_aux.first + nelem_2);
+
+        range_sort(range_1, rng_bx, comp, nlevel);
+        merge_half(range_input, rng_bx, range_2, comp);
+    }
+    else
+    {
+        //----------------------------------------------------------------
+        // If the number of levels is even, the data are in the second
+        // parameter of range_sort, and the results are in the same
+        //  parameter
+        //----------------------------------------------------------------
+        range_it range_1(first, first + nelem_1), range_2(first + nelem_1,
+                        last);
+        range_aux = move_construct(range_aux, range_1);
+        construct = true;
+
+        range_sort(range_1, range_aux, comp, nlevel);
+
+        range_1.last = range_1.first + range_2.size();
+        range_sort(range_1, range_2, comp, nlevel);
+        merge_half(range_input, range_aux, range_2, comp);
+    };
+};
+
+//****************************************************************************
+};//    End namepspace spin_detail
+//****************************************************************************
+//
+namespace bsc = boost::sort::common;
+//-----------------------------------------------------------------------------
+//  function : spinsort
+/// @brief this function implement a single thread stable sort
+///
+/// @param first : iterator to the first element of the range to sort
+/// @param last : iterator after the last element to the range to sort
+/// @param comp : object for to compare two elements pointed by Iter_t
+///               iterators
+//-----------------------------------------------------------------------------
+template <class Iter_t, class Compare = compare_iter<Iter_t>>
+inline void spinsort (Iter_t first, Iter_t last, Compare comp = Compare())
+{
+    spin_detail::spinsort <Iter_t, Compare> (first, last, comp);
+};
+
+template <class Iter_t, class Compare = compare_iter<Iter_t>>
+inline void indirect_spinsort (Iter_t first, Iter_t last,
+                               Compare comp = Compare())
+{
+    typedef typename std::vector<Iter_t>::iterator itx_iter;
+    typedef common::less_ptr_no_null <Iter_t, Compare> itx_comp;
+    common::indirect_sort (spinsort<itx_iter, itx_comp>, first, last, comp);
+};
+
+//****************************************************************************
+};//    End namespace sort
+};//    End namepspace boost
+//****************************************************************************
+//
+#endif


Test patch:
diff --git a/docker2/test b/docker2/test
new file mode 100755
index 00000000..e70d5c2b
--- /dev/null
+++ b/docker2/test
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+set -ex
+
+HERE=$(dirname $0)
+. $HERE/common
+
+# In case we switch agents between steps
+[ ! -z $(docker images -q $TAG_SHA) ] || docker pull $TAG_SHA
+
+## Just check that we can bring up the container and run something
+docker run -it -w /src --rm $TAG_SHA poppunk --version
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 00000000..98c06456
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,1 @@
+*.fa