--- /dev/null
+From ee63b2717de7261c95733bc1742d8dfc3317429e Mon Sep 17 00:00:00 2001
+From: "Damien Buhl (alias daminetreg)" <damien.buhl@lecbna.org>
+Date: Thu, 6 Sep 2018 05:07:03 +0200
+Subject: [PATCH] :wrench: fix build in c++17 on GCC libstdc++ and on
+ clang+libc++.
+
+---
+ CMakeLists.txt | 3 +--
+ include/mstch/mstch.hpp | 4 ++--
+ src/render_context.cpp | 4 ++--
+ src/state/in_section.cpp | 6 +++---
+ src/state/outside_section.cpp | 4 ++--
+ src/visitor/render_node.hpp | 2 +-
+ src/visitor/render_section.hpp | 4 ++--
+ 7 files changed, 13 insertions(+), 14 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 8d8e0c7..7ee9f01 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -6,12 +6,11 @@ option(WITH_BENCHMARK "enable building benchmark executable" OFF)
+
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+-set(CMAKE_BUILD_TYPE Release)
+
+ set(mstch_VERSION 1.0.1)
+
+ if(NOT MSVC)
+- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -O3")
++ add_compile_options(-Wall -Wextra)
+ endif()
+
+ add_subdirectory(src)
+diff --git a/include/mstch/mstch.hpp b/include/mstch/mstch.hpp
+index 58d3330..0af9e4d 100644
+--- a/include/mstch/mstch.hpp
++++ b/include/mstch/mstch.hpp
+@@ -97,11 +97,11 @@ using node = boost::make_recursive_variant<
+ std::nullptr_t, std::string, int, double, bool,
+ internal::lambda_t<boost::recursive_variant_>,
+ std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
+- std::map<const std::string, boost::recursive_variant_>,
++ std::map<std::string, boost::recursive_variant_>,
+ std::vector<boost::recursive_variant_>>::type;
+ using object = internal::object_t<node>;
+ using lambda = internal::lambda_t<node>;
+-using map = std::map<const std::string, node>;
++using map = std::map<std::string, node>;
+ using array = std::vector<node>;
+
+ std::string render(
+diff --git a/src/render_context.cpp b/src/render_context.cpp
+index 90b2ffc..756114d 100644
+--- a/src/render_context.cpp
++++ b/src/render_context.cpp
+@@ -41,8 +41,8 @@ const mstch::node& render_context::find_node(
+ {&find_node(token.substr(0, token.rfind('.')), current_nodes)});
+ else
+ for (auto& node: current_nodes)
+- if (visit(has_token(token), *node))
+- return visit(get_token(token, *node), *node);
++ if (mstch::visit(has_token(token), *node))
++ return mstch::visit(get_token(token, *node), *node);
+ return null_node;
+ }
+
+diff --git a/src/state/in_section.cpp b/src/state/in_section.cpp
+index a139913..0062493 100644
+--- a/src/state/in_section.cpp
++++ b/src/state/in_section.cpp
+@@ -16,9 +16,9 @@ std::string in_section::render(render_context& ctx, const token& token) {
+ auto& node = ctx.get_node(m_start_token.name());
+ std::string out;
+
+- if (m_type == type::normal && !visit(is_node_empty(), node))
+- out = visit(render_section(ctx, m_section, m_start_token.delims()), node);
+- else if (m_type == type::inverted && visit(is_node_empty(), node))
++ if (m_type == type::normal && !mstch::visit(is_node_empty(), node))
++ out = mstch::visit(render_section(ctx, m_section, m_start_token.delims()), node);
++ else if (m_type == type::inverted && mstch::visit(is_node_empty(), node))
+ out = render_context::push(ctx).render(m_section);
+
+ ctx.set_state<outside_section>();
+diff --git a/src/state/outside_section.cpp b/src/state/outside_section.cpp
+index c9817b1..46e204b 100644
+--- a/src/state/outside_section.cpp
++++ b/src/state/outside_section.cpp
+@@ -18,9 +18,9 @@ std::string outside_section::render(
+ ctx.set_state<in_section>(in_section::type::inverted, token);
+ break;
+ case token::type::variable:
+- return visit(render_node(ctx, flag::escape_html), ctx.get_node(token.name()));
++ return mstch::visit(render_node(ctx, flag::escape_html), ctx.get_node(token.name()));
+ case token::type::unescaped_variable:
+- return visit(render_node(ctx, flag::none), ctx.get_node(token.name()));
++ return mstch::visit(render_node(ctx, flag::none), ctx.get_node(token.name()));
+ case token::type::text:
+ return token.raw();
+ case token::type::partial:
+diff --git a/src/visitor/render_node.hpp b/src/visitor/render_node.hpp
+index 633dd4d..d5d5b40 100644
+--- a/src/visitor/render_node.hpp
++++ b/src/visitor/render_node.hpp
+@@ -38,7 +38,7 @@ class render_node: public boost::static_visitor<std::string> {
+
+ std::string operator()(const lambda& value) const {
+ template_type interpreted{value([this](const mstch::node& n) {
+- return visit(render_node(m_ctx), n);
++ return mstch::visit(render_node(m_ctx), n);
+ })};
+ auto rendered = render_context::push(m_ctx).render(interpreted);
+ return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
+diff --git a/src/visitor/render_section.hpp b/src/visitor/render_section.hpp
+index f2d5259..ac753e3 100644
+--- a/src/visitor/render_section.hpp
++++ b/src/visitor/render_section.hpp
+@@ -31,7 +31,7 @@ class render_section: public boost::static_visitor<std::string> {
+ for (auto& token: m_section)
+ section_str += token.raw();
+ template_type interpreted{fun([this](const mstch::node& n) {
+- return visit(render_node(m_ctx), n);
++ return mstch::visit(render_node(m_ctx), n);
+ }, section_str), m_delims};
+ return render_context::push(m_ctx).render(interpreted);
+ }
+@@ -42,7 +42,7 @@ class render_section: public boost::static_visitor<std::string> {
+ return render_context::push(m_ctx, array).render(m_section);
+ else
+ for (auto& item: array)
+- out += visit(render_section(
++ out += mstch::visit(render_section(
+ m_ctx, m_section, m_delims, flag::keep_array), item);
+ return out;
+ }
+--
+2.17.1
+
--- /dev/null
+From 8e9679af05f0132e2934f8d7e1bfbaf36dc57cd7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Torbj=C3=B6rn=20Klatt?= <t.klatt.oss@mailbox.org>
+Date: Tue, 27 Nov 2018 20:56:02 +0100
+Subject: [PATCH] switch boost::variant to std::variant and to C++17
+
+This is based on work by @mbits-libs as published on Github:
+mbits-libs/libmstch@747c5eed3ddbff94a0354f1b1d217f547867ef27
+
+The `is_node_empty` type had to be extended to detect the std::variant's
+default type `std::monostate` as an empty value. This change made all
+the unit tests pass.
+---
+ CMakeLists.txt | 6 ++-
+ include/mstch/mstch.hpp | 41 ++++++++++++++++----
+ src/CMakeLists.txt | 6 +--
+ src/utils.hpp | 13 ++++---
+ src/visitor/get_token.hpp | 4 +-
+ src/visitor/has_token.hpp | 4 +-
+ src/visitor/is_node_empty.hpp | 16 +++++---
+ src/visitor/render_node.hpp | 69 +++++++++++++++-------------------
+ src/visitor/render_section.hpp | 48 ++++++++++++-----------
+ test/CMakeLists.txt | 3 --
+ test/test_main.cpp | 2 +-
+ 11 files changed, 115 insertions(+), 97 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 7ee9f01..9df666f 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -7,10 +7,12 @@ option(WITH_BENCHMARK "enable building benchmark executable" OFF)
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+
+-set(mstch_VERSION 1.0.1)
++set(mstch_VERSION 1.0.2)
+
+ if(NOT MSVC)
+- add_compile_options(-Wall -Wextra)
++ add_compile_options(-std=c++17 -Wall -Wextra -O3)
++else()
++ add_compile_options(/std:c++latest)
+ endif()
+
+ add_subdirectory(src)
+diff --git a/include/mstch/mstch.hpp b/include/mstch/mstch.hpp
+index 0af9e4d..2ea9855 100644
+--- a/include/mstch/mstch.hpp
++++ b/include/mstch/mstch.hpp
+@@ -5,8 +5,7 @@
+ #include <string>
+ #include <memory>
+ #include <functional>
+-
+-#include <boost/variant.hpp>
++#include <variant>
+
+ namespace mstch {
+
+@@ -93,12 +92,38 @@ class lambda_t {
+
+ }
+
+-using node = boost::make_recursive_variant<
+- std::nullptr_t, std::string, int, double, bool,
+- internal::lambda_t<boost::recursive_variant_>,
+- std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
+- std::map<std::string, boost::recursive_variant_>,
+- std::vector<boost::recursive_variant_>>::type;
++struct node : std::variant<
++ std::monostate, std::nullptr_t, std::string, int, unsigned int, double, bool,
++ internal::lambda_t<node>,
++ std::shared_ptr<internal::object_t<node>>,
++ std::map<const std::string, node>,
++ std::vector<node>
++> {
++ using empty_type = std::monostate;
++ using lambda_type = internal::lambda_t<node>;
++ using shared_ptr_type = std::shared_ptr<internal::object_t<node>>;
++ using map_type = std::map<const std::string, node>;
++ using vector_type = std::vector<node>;
++
++ using base_type = std::variant<
++ std::monostate, std::nullptr_t, std::string, int, unsigned int, double, bool,
++ internal::lambda_t<node>,
++ std::shared_ptr<internal::object_t<node>>,
++ std::map<const std::string, node>,
++ std::vector<node>
++ >;
++
++ using base_type::base_type;
++
++ node() : base_type(std::in_place_type<std::monostate>) {}
++
++ explicit node(const char* value) : base_type(std::in_place_type<std::string>, value) {}
++
++ base_type& base() { return *this; }
++ base_type const& base() const { return *this; }
++};
++
++using empty = std::monostate;
+ using object = internal::object_t<node>;
+ using lambda = internal::lambda_t<node>;
+ using map = std::map<std::string, node>;
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index 6517fc4..22d4f41 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -1,11 +1,8 @@
+-find_package(Boost 1.54 REQUIRED)
+-
+ set(mstch_INCLUDE_DIR
+ ${PROJECT_SOURCE_DIR}/include CACHE STRING "mstch include directory")
+
+ include_directories(
+- ${mstch_INCLUDE_DIR}
+- ${Boost_INCLUDE_DIR})
++ ${mstch_INCLUDE_DIR})
+
+ set(SRC
+ state/in_section.cpp
+@@ -62,3 +59,4 @@ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/mstch/mstch-config-version.cmake"
+ DESTINATION lib/cmake/mstch
+ COMPONENT Devel)
++
+diff --git a/src/utils.hpp b/src/utils.hpp
+index 9041a3e..ea19029 100644
+--- a/src/utils.hpp
++++ b/src/utils.hpp
+@@ -1,7 +1,8 @@
+ #pragma once
+
+ #include <string>
+-#include <boost/variant/apply_visitor.hpp>
++#include <vector>
++#include <variant>
+
+ namespace mstch {
+
+@@ -13,11 +14,13 @@ citer first_not_ws(criter begin, criter end);
+ std::string html_escape(const std::string& str);
+ criter reverse(citer it);
+
+-template<class... Args>
+-auto visit(Args&&... args) -> decltype(boost::apply_visitor(
+- std::forward<Args>(args)...))
++template<class Visitor, class... Visited>
++decltype(auto) visit(Visitor&& visitor, Visited&&... nodes)
+ {
+- return boost::apply_visitor(std::forward<Args>(args)...);
++ return std::visit(std::forward<Visitor>(visitor), nodes.base()...);
+ }
+
++template <typename T, typename U>
++constexpr bool is_v = std::is_same_v<T, U>;
++
+ }
+diff --git a/src/visitor/get_token.hpp b/src/visitor/get_token.hpp
+index d41ab6e..f7b1714 100644
+--- a/src/visitor/get_token.hpp
++++ b/src/visitor/get_token.hpp
+@@ -1,13 +1,11 @@
+ #pragma once
+
+-#include <boost/variant/static_visitor.hpp>
+-
+ #include "mstch/mstch.hpp"
+ #include "has_token.hpp"
+
+ namespace mstch {
+
+-class get_token: public boost::static_visitor<const mstch::node&> {
++class get_token {
+ public:
+ get_token(const std::string& token, const mstch::node& node):
+ m_token(token), m_node(node)
+diff --git a/src/visitor/has_token.hpp b/src/visitor/has_token.hpp
+index 5ab30d4..0076f97 100644
+--- a/src/visitor/has_token.hpp
++++ b/src/visitor/has_token.hpp
+@@ -1,12 +1,10 @@
+ #pragma once
+
+-#include <boost/variant/static_visitor.hpp>
+-
+ #include "mstch/mstch.hpp"
+
+ namespace mstch {
+
+-class has_token: public boost::static_visitor<bool> {
++class has_token {
+ public:
+ has_token(const std::string& token): m_token(token) {
+ }
+diff --git a/src/visitor/is_node_empty.hpp b/src/visitor/is_node_empty.hpp
+index a0ae432..d7434e7 100644
+--- a/src/visitor/is_node_empty.hpp
++++ b/src/visitor/is_node_empty.hpp
+@@ -1,18 +1,20 @@
+ #pragma once
+
+-#include <boost/variant/static_visitor.hpp>
+-
+ #include "mstch/mstch.hpp"
+
+ namespace mstch {
+
+-class is_node_empty: public boost::static_visitor<bool> {
++class is_node_empty {
+ public:
+ template<class T>
+ bool operator()(const T&) const {
+ return false;
+ }
+
++ bool operator()(const empty&) const {
++ return true;
++ }
++
+ bool operator()(const std::nullptr_t&) const {
+ return true;
+ }
+@@ -21,6 +23,10 @@ class is_node_empty: public boost::static_visitor<bool> {
+ return value == 0;
+ }
+
++ bool operator()(const unsigned int& value) const {
++ return value == 0;
++ }
++
+ bool operator()(const double& value) const {
+ return value == 0;
+ }
+@@ -30,11 +36,11 @@ class is_node_empty: public boost::static_visitor<bool> {
+ }
+
+ bool operator()(const std::string& value) const {
+- return value == "";
++ return value.empty();
+ }
+
+ bool operator()(const array& array) const {
+- return array.size() == 0;
++ return array.empty();
+ }
+ };
+
+diff --git a/src/visitor/render_node.hpp b/src/visitor/render_node.hpp
+index d5d5b40..d8f5315 100644
+--- a/src/visitor/render_node.hpp
++++ b/src/visitor/render_node.hpp
+@@ -1,7 +1,6 @@
+ #pragma once
+
+ #include <sstream>
+-#include <boost/variant/static_visitor.hpp>
+
+ #include "render_context.hpp"
+ #include "mstch/mstch.hpp"
+@@ -9,47 +8,41 @@
+
+ namespace mstch {
+
+-class render_node: public boost::static_visitor<std::string> {
+- public:
++class render_node {
++public:
+ enum class flag { none, escape_html };
+- render_node(render_context& ctx, flag p_flag = flag::none):
+- m_ctx(ctx), m_flag(p_flag)
++ render_node(render_context& ctx, flag p_flag = flag::none) :
++ m_ctx(ctx), m_flag(p_flag)
+ {
+ }
+
+- template<class T>
+- std::string operator()(const T&) const {
+- return "";
+- }
+-
+- std::string operator()(const int& value) const {
+- return std::to_string(value);
+- }
+-
+- std::string operator()(const double& value) const {
+- std::stringstream ss;
+- ss << value;
+- return ss.str();
+- }
+-
+- std::string operator()(const bool& value) const {
+- return value ? "true" : "false";
+- }
+-
+- std::string operator()(const lambda& value) const {
+- template_type interpreted{value([this](const mstch::node& n) {
+- return mstch::visit(render_node(m_ctx), n);
+- })};
+- auto rendered = render_context::push(m_ctx).render(interpreted);
+- return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
+- }
+-
+- std::string operator()(const std::string& value) const {
+- return (m_flag == flag::escape_html) ? html_escape(value) : value;
+- }
+-
+- private:
+- render_context& m_ctx;
++ template <typename T>
++ std::string operator()(const T& value) const {
++ if constexpr(is_v<T, int>) {
++ return std::to_string(value);
++ } else if constexpr(is_v<T, unsigned int>) {
++ return std::to_string(value);
++ } else if constexpr(is_v<T, double>) {
++ std::stringstream ss;
++ ss << value;
++ return ss.str();
++ } else if constexpr(is_v<T, bool>) {
++ return value ? "true" : "false";
++ } else if constexpr(is_v<T, lambda>) {
++ template_type interpreted{ value([this](const mstch::node& n) {
++ return mstch::visit(render_node(m_ctx), n);
++ }) };
++ auto rendered = render_context::push(m_ctx).render(interpreted);
++ return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
++ } else if constexpr(is_v<T, std::string>) {
++ return (m_flag == flag::escape_html) ? html_escape(value) : value;
++ }
++
++ return {};
++ };
++
++private:
++ render_context & m_ctx;
+ flag m_flag;
+ };
+
+diff --git a/src/visitor/render_section.hpp b/src/visitor/render_section.hpp
+index ac753e3..0c08c17 100644
+--- a/src/visitor/render_section.hpp
++++ b/src/visitor/render_section.hpp
+@@ -1,7 +1,5 @@
+ #pragma once
+
+-#include <boost/variant/static_visitor.hpp>
+-
+ #include "render_context.hpp"
+ #include "mstch/mstch.hpp"
+ #include "utils.hpp"
+@@ -9,7 +7,7 @@
+
+ namespace mstch {
+
+-class render_section: public boost::static_visitor<std::string> {
++class render_section {
+ public:
+ enum class flag { none, keep_array };
+ render_section(
+@@ -22,29 +20,29 @@ class render_section: public boost::static_visitor<std::string> {
+ }
+
+ template<class T>
+- std::string operator()(const T& t) const {
+- return render_context::push(m_ctx, t).render(m_section);
+- }
+-
+- std::string operator()(const lambda& fun) const {
+- std::string section_str;
+- for (auto& token: m_section)
+- section_str += token.raw();
+- template_type interpreted{fun([this](const mstch::node& n) {
+- return mstch::visit(render_node(m_ctx), n);
+- }, section_str), m_delims};
+- return render_context::push(m_ctx).render(interpreted);
+- }
+-
+- std::string operator()(const array& array) const {
+- std::string out;
+- if (m_flag == flag::keep_array)
+- return render_context::push(m_ctx, array).render(m_section);
+- else
+- for (auto& item: array)
+- out += mstch::visit(render_section(
++ std::string operator()(const T& value) const {
++ if constexpr(is_v<T, lambda>) {
++ std::string section_str;
++ for (auto& token : m_section) {
++ section_str += token.raw();
++ }
++ template_type interpreted{ value([this](const mstch::node& n) {
++ return mstch::visit(render_node(m_ctx), n);
++ }, section_str), m_delims };
++ return render_context::push(m_ctx).render(interpreted);
++ } else if constexpr(is_v<T, array>) {
++ std::string out;
++ if (m_flag == flag::keep_array) {
++ return render_context::push(m_ctx, value).render(m_section);
++ } else {
++ for (auto& item: value) {
++ out += mstch::visit(render_section(
+ m_ctx, m_section, m_delims, flag::keep_array), item);
+- return out;
++ }
++ }
++ return out;
++ }
++ return render_context::push(m_ctx, value).render(m_section);
+ }
+
+ private:
+diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
+index 061bc2e..b290b65 100644
+--- a/test/CMakeLists.txt
++++ b/test/CMakeLists.txt
+@@ -1,10 +1,7 @@
+-find_package(Boost 1.54 REQUIRED)
+-
+ include_directories(
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/vendor/Catch/single_include
+ ${CMAKE_SOURCE_DIR}/vendor/rapidjson/include
+- ${Boost_INCLUDE_DIR})
+
+ file(GLOB data_files RELATIVE
+ "${CMAKE_SOURCE_DIR}/test/data"
+diff --git a/test/test_main.cpp b/test/test_main.cpp
+index a52fe3c..d823a24 100644
+--- a/test/test_main.cpp
++++ b/test/test_main.cpp
+@@ -65,7 +65,7 @@ mstch::node parse_with_rapidjson(const std::string& str) {
+ }
+
+ #define SPECS_TEST(x) TEST_CASE("specs_" #x) { \
+- using boost::get; \
++ using std::get; \
+ auto data = parse_with_rapidjson(x ## _json); \
+ for (auto& test_item: get<mstch::array>(get<mstch::map>(data)["tests"])) {\
+ auto test = get<mstch::map>(test_item); \
+--
+2.17.1
+