mirror of
https://github.com/boostorg/hana.git
synced 2026-01-25 06:12:23 +00:00
[Doc] Add a section on performance in the tutorial
Also: - Introduce the .js charts we have in the reference - Remove the ugly "Generated by Doxygen" footer - Refactor the benchmarks
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<% hana = (1..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (1..50).step(2).to_a %>
|
||||
<% hana = (1...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (1...50).step(5).to_a + [50, 75, 100] %>
|
||||
<% mpl = hana %>
|
||||
|
||||
{
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/at.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
namespace fusion = boost::fusion;
|
||||
|
||||
|
||||
@@ -17,9 +14,7 @@ template <int>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "x<#{n}>{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "x<#{n}>{}" }) %>;
|
||||
auto result = fusion::at_c<<%= input_size-1 %>>(vector);
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,14 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/at.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
namespace fusion = boost::fusion;
|
||||
|
||||
|
||||
int main() {
|
||||
auto vector = fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "#{n}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "#{n}" }) %>;
|
||||
auto result = fusion::at_c<<%= input_size-1 %>>(vector);
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
<script src="chart.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var drawChart = function() {
|
||||
var compiler = $("#compiler").val();
|
||||
var dataset = $("#dataset").val();
|
||||
var repo = "https://raw.githubusercontent.com/ldionne/hana/datasets/release/";
|
||||
$.getJSON(repo + compiler + "/" + dataset, function(options) {
|
||||
var setDataset = function(dataset) {
|
||||
$.getJSON(dataset, function(options) {
|
||||
if ($("#container").highcharts())
|
||||
$("#container").highcharts().destroy();
|
||||
|
||||
@@ -22,29 +19,12 @@
|
||||
$("#container").highcharts().redraw();
|
||||
});
|
||||
};
|
||||
|
||||
window.onload = drawChart;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
|
||||
|
||||
<select id="compiler" onchange="drawChart()">
|
||||
<option value="clang-3.5.0">Clang 3.5.0</option>
|
||||
<option value="clang-3.6.1">Clang 3.6.1</option>
|
||||
<option value="clang-3.7.0">Clang 3.7.0 (trunk)</option>
|
||||
</select>
|
||||
|
||||
<select id="dataset" onchange="drawChart()">
|
||||
<option value="benchmark.fold_left.compile.json">Compile-time left fold</option>
|
||||
<option value="benchmark.fold_right.compile.json">Compile-time right fold</option>
|
||||
<option value="benchmark.transform.compile.json">Compile-time transform</option>
|
||||
<option value="benchmark.count_if.compile.json">Compile-time count_if</option>
|
||||
<option value="benchmark.at.compile.json">Compile-time at</option>
|
||||
<option value="benchmark.product.compile.json">Compile-time product</option>
|
||||
<option value="benchmark.including.compile.json">Include time</option>
|
||||
</select>
|
||||
<input type="text" size=100 name="dataset" class="enter" value="" onchange="setDataset(this.value)" />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% hana = (0..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0..50).step(2).to_a %>
|
||||
<% hana = (0...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a + [50, 75, 100] %>
|
||||
<% mpl = hana %>
|
||||
|
||||
{
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/count_if.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
#include <boost/hana/integral_constant.hpp>
|
||||
|
||||
@@ -22,9 +19,9 @@ struct is_even {
|
||||
};
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "boost::hana::int_<#{n}>" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n|
|
||||
"boost::hana::int_<#{n}>"
|
||||
}) %>;
|
||||
auto result = boost::fusion::count_if(vector, is_even{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/count_if.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
|
||||
struct is_even {
|
||||
@@ -18,9 +15,7 @@ struct is_even {
|
||||
};
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "#{n}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "#{n}" }) %>;
|
||||
auto result = boost::fusion::count_if(vector, is_even{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
25
benchmark/find_if/compile.erb.json
Normal file
25
benchmark/find_if/compile.erb.json
Normal file
@@ -0,0 +1,25 @@
|
||||
<% hana = (0...50).step(5).to_a + (50..200).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a %>
|
||||
<% mpl = hana %>
|
||||
|
||||
{
|
||||
"title": {
|
||||
"text": "Compile-time behavior of find_if"
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"name": "Heterogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.heterogeneous.erb.cpp', hana) %>
|
||||
}
|
||||
|
||||
<% if has_boost %>
|
||||
, {
|
||||
"name": "Heterogeneous fusion::vector",
|
||||
"data": <%= time_compilation('compile.fusion.vector.heterogeneous.erb.cpp', fusion) %>
|
||||
}, {
|
||||
"name": "mpl::vector",
|
||||
"data": <%= time_compilation('compile.mpl.vector.erb.cpp', mpl) %>
|
||||
}
|
||||
<% end %>
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/fusion/include/find_if.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
#include <boost/mpl/integral_c.hpp>
|
||||
|
||||
|
||||
struct is_last {
|
||||
template <typename N>
|
||||
struct apply
|
||||
: boost::mpl::integral_c<bool, N::type::value == <%= input_size %>>
|
||||
{ };
|
||||
};
|
||||
|
||||
int main() {
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n|
|
||||
"boost::mpl::integral_c<int, #{n}>{}"
|
||||
}) %>;
|
||||
auto result = boost::fusion::find_if<is_last>(vector);
|
||||
(void)result;
|
||||
}
|
||||
24
benchmark/find_if/compile.hana.tuple.heterogeneous.erb.cpp
Normal file
24
benchmark/find_if/compile.hana.tuple.heterogeneous.erb.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/integral_constant.hpp>
|
||||
#include <boost/hana/tuple.hpp>
|
||||
|
||||
|
||||
struct is_last {
|
||||
template <typename N>
|
||||
constexpr auto operator()(N) const {
|
||||
return boost::hana::bool_<N::value == <%= input_size %>>;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
constexpr auto tuple = boost::hana::make_tuple(
|
||||
<%= (1..input_size).map { |n| "boost::hana::int_<#{n}>" }.join(', ') %>
|
||||
);
|
||||
constexpr auto result = boost::hana::find_if(tuple, is_last{});
|
||||
(void)result;
|
||||
}
|
||||
29
benchmark/find_if/compile.mpl.vector.erb.cpp
Normal file
29
benchmark/find_if/compile.mpl.vector.erb.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/mpl/find_if.hpp>
|
||||
#include <boost/mpl/integral_c.hpp>
|
||||
#include <boost/mpl/push_back.hpp>
|
||||
#include <boost/mpl/quote.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
namespace mpl = boost::mpl;
|
||||
|
||||
|
||||
struct is_last {
|
||||
template <typename N>
|
||||
struct apply
|
||||
: mpl::integral_c<bool, N::type::value == <%= input_size %>>
|
||||
{ };
|
||||
};
|
||||
|
||||
using vector = <%= mpl_vector((1..input_size).to_a.map { |n|
|
||||
"mpl::integral_c<int, #{n}>"
|
||||
}) %>;
|
||||
|
||||
using result = mpl::find_if<vector, is_last>::type;
|
||||
|
||||
|
||||
int main() { }
|
||||
@@ -1,8 +1,8 @@
|
||||
<% hana = (1..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (1..50).step(2).to_a %>
|
||||
<% hana = (0...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a + [50, 75, 100] %>
|
||||
<% mpl = hana %>
|
||||
<% mpl11 = (1..50).step(2).to_a + (50..500).step(25).to_a %>
|
||||
<% cexpr = (1..50).step(2).to_a + (50..200).step(25).to_a %>
|
||||
<% mpl11 = (0...50).step(5).to_a + (50..500).step(25).to_a %>
|
||||
<% cexpr = (0...50).step(5).to_a + (50..200).step(25).to_a %>
|
||||
|
||||
|
||||
{
|
||||
@@ -17,7 +17,7 @@
|
||||
"name": "Homogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.homogeneous.erb.cpp', hana) %>
|
||||
}, {
|
||||
"name": "hana::tuple_t with a hana::Metafunction",
|
||||
"name": "hana::tuple_t with hana::Metafunction",
|
||||
"data": <%= time_compilation('compile.hana.tuple_t.metafunction.erb.cpp', hana) %>
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"name": "Homogeneous fusion::vector",
|
||||
"data": <%= time_compilation('compile.fusion.vector.homogeneous.erb.cpp', fusion) %>
|
||||
}, {
|
||||
"name": "mpl::vector with a MPL metafunction class",
|
||||
"name": "mpl::vector",
|
||||
"data": <%= time_compilation('compile.mpl.vector.erb.cpp', mpl) %>
|
||||
}
|
||||
<% end %>
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/fold.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
|
||||
struct f {
|
||||
@@ -23,9 +20,7 @@ template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "x<#{n}>{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "x<#{n}>{}" }) %>;
|
||||
auto result = boost::fusion::fold(vector, state{}, f{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/fold.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
|
||||
struct f {
|
||||
@@ -22,9 +19,7 @@ struct state { };
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { "x{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { "x{}" }) %>;
|
||||
auto result = boost::fusion::fold(vector, state{}, f{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% hana = (1..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (1..50).step(2).to_a %>
|
||||
<% hana = (0...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a + [50, 75, 100] %>
|
||||
<% mpl = hana %>
|
||||
|
||||
{
|
||||
@@ -14,7 +14,7 @@
|
||||
"name": "Homogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.homogeneous.erb.cpp', hana) %>
|
||||
}, {
|
||||
"name": "hana::tuple_t with a hana::Metafunction",
|
||||
"name": "hana::tuple_t with hana::Metafunction",
|
||||
"data": <%= time_compilation('compile.hana.tuple_t.metafunction.erb.cpp', hana) %>
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"name": "Homogeneous fusion::vector",
|
||||
"data": <%= time_compilation('compile.fusion.vector.homogeneous.erb.cpp', fusion) %>
|
||||
}, {
|
||||
"name": "mpl::vector with a MPL metafunction class",
|
||||
"name": "mpl::vector ",
|
||||
"data": <%= time_compilation('compile.mpl.vector.erb.cpp', mpl) %>
|
||||
}
|
||||
<% end %>
|
||||
|
||||
@@ -4,11 +4,8 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
#include <boost/fusion/include/reverse_fold.hpp>
|
||||
|
||||
|
||||
@@ -23,9 +20,7 @@ template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "x<#{n}>{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "x<#{n}>{}" }) %>;
|
||||
auto result = boost::fusion::reverse_fold(vector, state{}, f{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/reverse_fold.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
#include <boost/fusion/include/reverse_fold.hpp>
|
||||
|
||||
|
||||
struct f {
|
||||
@@ -22,9 +19,7 @@ struct state { };
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { "x{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { "x{}" }) %>;
|
||||
auto result = boost::fusion::reverse_fold(vector, state{}, f{});
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
},
|
||||
"series": [{
|
||||
"name": "Libraries",
|
||||
"name": "Include time",
|
||||
"colorByPoint": true,
|
||||
"data": [
|
||||
{
|
||||
|
||||
36
benchmark/make/compile.erb.json
Normal file
36
benchmark/make/compile.erb.json
Normal file
@@ -0,0 +1,36 @@
|
||||
<% rng = (0...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a + [50, 75, 100] %>
|
||||
|
||||
{
|
||||
"title": {
|
||||
"text": "Compile-time behavior of creating a sequence"
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"name": "Heterogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.heterogeneous.erb.cpp', rng) %>
|
||||
}, {
|
||||
"name": "Homogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.homogeneous.erb.cpp', rng) %>
|
||||
}, {
|
||||
"name": "hana::tuple_t",
|
||||
"data": <%= time_compilation('compile.hana.tuple_t.erb.cpp', rng) %>
|
||||
}, {
|
||||
"name": "hana::tuple_c",
|
||||
"data": <%= time_compilation('compile.hana.tuple_c.erb.cpp', rng) %>
|
||||
}
|
||||
|
||||
<% if has_boost %>
|
||||
, {
|
||||
"name": "Heterogeneous fusion::vector",
|
||||
"data": <%= time_compilation('compile.fusion.vector.heterogeneous.erb.cpp', fusion) %>
|
||||
}, {
|
||||
"name": "Homogeneous fusion::vector",
|
||||
"data": <%= time_compilation('compile.fusion.vector.homogeneous.erb.cpp', fusion) %>
|
||||
}, {
|
||||
"name": "mpl::vector",
|
||||
"data": <%= time_compilation('compile.mpl.vector.erb.cpp', rng) %>
|
||||
}
|
||||
<% end %>
|
||||
]
|
||||
}
|
||||
17
benchmark/make/compile.fusion.vector.heterogeneous.erb.cpp
Normal file
17
benchmark/make/compile.fusion.vector.heterogeneous.erb.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
|
||||
template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "x<#{n}>{}" }) %>;
|
||||
(void)vector;
|
||||
}
|
||||
16
benchmark/make/compile.fusion.vector.homogeneous.erb.cpp
Normal file
16
benchmark/make/compile.fusion.vector.homogeneous.erb.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
|
||||
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = <%= fusion_vector((1..input_size).map { "x{}" }) %>;
|
||||
(void)vector;
|
||||
}
|
||||
18
benchmark/make/compile.hana.tuple.heterogeneous.erb.cpp
Normal file
18
benchmark/make/compile.hana.tuple.heterogeneous.erb.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/tuple.hpp>
|
||||
|
||||
|
||||
template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
constexpr auto tuple = boost::hana::make_tuple(
|
||||
<%= (1..input_size).map { |n| "x<#{n}>{}" }.join(', ') %>
|
||||
);
|
||||
(void)tuple;
|
||||
}
|
||||
15
benchmark/make/compile.hana.tuple.homogeneous.erb.cpp
Normal file
15
benchmark/make/compile.hana.tuple.homogeneous.erb.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/tuple.hpp>
|
||||
|
||||
|
||||
int main() {
|
||||
constexpr auto tuple = boost::hana::make_tuple(
|
||||
<%= (1..input_size).map { |n| "#{n}" }.join(', ') %>
|
||||
);
|
||||
(void)tuple;
|
||||
}
|
||||
15
benchmark/make/compile.hana.tuple_c.erb.cpp
Normal file
15
benchmark/make/compile.hana.tuple_c.erb.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/tuple.hpp>
|
||||
|
||||
|
||||
int main() {
|
||||
constexpr auto tuple = boost::hana::tuple_c<int,
|
||||
<%= (1..input_size).map { |n| "#{n}" }.join(', ') %>
|
||||
>;
|
||||
(void)tuple;
|
||||
}
|
||||
18
benchmark/make/compile.hana.tuple_t.erb.cpp
Normal file
18
benchmark/make/compile.hana.tuple_t.erb.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/tuple.hpp>
|
||||
|
||||
|
||||
template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
constexpr auto tuple = boost::hana::tuple_t<
|
||||
<%= (1..input_size).map { |n| "x<#{n}>" }.join(', ') %>
|
||||
>;
|
||||
(void)tuple;
|
||||
}
|
||||
16
benchmark/make/compile.mpl.vector.erb.cpp
Normal file
16
benchmark/make/compile.mpl.vector.erb.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/mpl/push_back.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
|
||||
template <int i>
|
||||
struct t { };
|
||||
|
||||
using vector = <%= mpl_vector((1..input_size).to_a.map { |n| "t<#{n}>" }) %>;
|
||||
|
||||
int main() { }
|
||||
@@ -29,7 +29,9 @@ def split_at(n, list)
|
||||
end
|
||||
|
||||
# types : A sequence of strings to put in the mpl::vector.
|
||||
# Using this method requires including <boost/mpl/push_back.hpp>
|
||||
# Using this method requires including
|
||||
# - <boost/mpl/vector.hpp>
|
||||
# - <boost/mpl/push_back.hpp>
|
||||
def mpl_vector(types)
|
||||
fast, rest = split_at(20, types)
|
||||
rest.inject("boost::mpl::vector#{fast.length}<#{fast.join(', ')}>") { |v, t|
|
||||
@@ -38,7 +40,9 @@ def mpl_vector(types)
|
||||
end
|
||||
|
||||
# types : A sequence of strings to put in the mpl::list.
|
||||
# Using this method requires including <boost/mpl/push_front.hpp>
|
||||
# Using this method requires including
|
||||
# - <boost/mpl/list.hpp>
|
||||
# - <boost/mpl/push_front.hpp>
|
||||
def mpl_list(types)
|
||||
prefix, fast = split_at([types.length - 20, 0].max, types)
|
||||
prefix.reverse.inject("boost::mpl::list#{fast.length}<#{fast.join(', ')}>") { |l, t|
|
||||
@@ -46,6 +50,17 @@ def mpl_list(types)
|
||||
}
|
||||
end
|
||||
|
||||
# values : A sequence of strings representing values to put in the fusion::vector.
|
||||
# Using this method requires including
|
||||
# - <boost/fusion/include/make_vector.hpp>
|
||||
# - <boost/fusion/include/push_back.hpp>
|
||||
def fusion_vector(values)
|
||||
fast, rest = split_at(10, values)
|
||||
rest.inject("boost::fusion::make_vector(#{fast.join(', ')})") { |xs, v|
|
||||
"boost::fusion::push_back(#{xs}, #{v})"
|
||||
}
|
||||
end
|
||||
|
||||
# aspect must be one of :compilation_time, :bloat, :execution_time
|
||||
def measure(aspect, template_relative, range)
|
||||
measure_file = Pathname.new("@CMAKE_CURRENT_SOURCE_DIR@/measure.cpp")
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/bool.hpp>
|
||||
#include <boost/hana/fwd/searchable.hpp>
|
||||
|
||||
#include "benchmark.hpp"
|
||||
|
||||
<%= setup %>
|
||||
|
||||
template <int i> struct x { };
|
||||
|
||||
|
||||
int main() {
|
||||
auto searchable = <%= searchable %>;
|
||||
auto pred = [](auto&& x) { return boost::hana::false_; };
|
||||
|
||||
boost::hana::benchmark::measure([=] {
|
||||
boost::hana::find_if(searchable, pred);
|
||||
});
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2015
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/fwd/sequence.hpp>
|
||||
|
||||
#include "benchmark.hpp"
|
||||
|
||||
<%= setup %>
|
||||
|
||||
template <int i> struct x { };
|
||||
|
||||
int main() {
|
||||
using L = <%= datatype %>;
|
||||
|
||||
boost::hana::benchmark::measure([] {
|
||||
boost::hana::make<L>(
|
||||
<%= (1..input_size).to_a.map { |i| "x<#{i}>{}" }.join(', ') %>
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<% hana = (1..50).step(2).to_a + (50..500).step(25).to_a %>
|
||||
<% hana = (0...50).step(5).to_a + (50..500).step(25).to_a %>
|
||||
|
||||
{
|
||||
"title": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<% hana = (1..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (1..50).step(2).to_a %>
|
||||
<% mpl = (1..50).step(2).to_a + (50..400).step(25).to_a %>
|
||||
<% hana = (0...50).step(5).to_a + (50..400).step(25).to_a %>
|
||||
<% fusion = (0...50).step(5).to_a + [50, 75, 100] %>
|
||||
<% mpl = hana %>
|
||||
|
||||
{
|
||||
"title": {
|
||||
@@ -14,7 +14,7 @@
|
||||
"name": "Homogeneous hana::tuple",
|
||||
"data": <%= time_compilation('compile.hana.tuple.homogeneous.erb.cpp', hana) %>
|
||||
}, {
|
||||
"name": "hana::tuple_t (hana::Metafunction)",
|
||||
"name": "hana::tuple_t with hana::Metafunction",
|
||||
"data": <%= time_compilation('compile.hana.tuple_t.metafunction.erb.cpp', hana) %>
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/as_vector.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
#include <boost/fusion/include/transform.hpp>
|
||||
|
||||
|
||||
@@ -23,9 +19,7 @@ template <int i>
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "x<#{n}>{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { |n| "x<#{n}>{}" }) %>;
|
||||
auto result = boost::fusion::as_vector(boost::fusion::transform(vector, f{}));
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
<% if input_size > 10 %>
|
||||
#define FUSION_MAX_VECTOR_SIZE <%= ((input_size + 9) / 10) * 10 %>
|
||||
<% end %>
|
||||
|
||||
#include <boost/fusion/include/as_vector.hpp>
|
||||
#include <boost/fusion/include/make_vector.hpp>
|
||||
#include <boost/fusion/include/push_back.hpp>
|
||||
#include <boost/fusion/include/transform.hpp>
|
||||
|
||||
|
||||
@@ -21,9 +18,7 @@ struct f {
|
||||
struct x { };
|
||||
|
||||
int main() {
|
||||
auto vector = boost::fusion::make_vector(
|
||||
<%= (1..input_size).map { |n| "x{}" }.join(', ') %>
|
||||
);
|
||||
auto vector = <%= fusion_vector((1..input_size).map { "x{}" }) %>;
|
||||
auto result = boost::fusion::as_vector(boost::fusion::transform(vector, f{}));
|
||||
(void)result;
|
||||
}
|
||||
|
||||
@@ -101,10 +101,10 @@ VERBATIM_HEADERS = NO
|
||||
# HTML output
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_HEADER = @Boost.Hana_SOURCE_DIR@/doc/header.html
|
||||
HTML_FOOTER = @Boost.Hana_SOURCE_DIR@/doc/footer.html
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_EXTRA_FILES = @Boost.Hana_SOURCE_DIR@/benchmark/chart.js
|
||||
HTML_COLORSTYLE_HUE = 75 # 0 - 359
|
||||
HTML_COLORSTYLE_SAT = 100 # 0 - 255
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
|
||||
18
doc/footer.html
Normal file
18
doc/footer.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- HTML footer for doxygen 1.8.9.1-->
|
||||
<!-- start footer part -->
|
||||
<!--BEGIN GENERATE_TREEVIEW-->
|
||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||
<ul>
|
||||
$navpath
|
||||
</ul>
|
||||
</div>
|
||||
<!--END GENERATE_TREEVIEW-->
|
||||
<!--BEGIN !GENERATE_TREEVIEW-->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
$generatedby  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
|
||||
</a> $doxygenversion
|
||||
</small></address>
|
||||
<!--END !GENERATE_TREEVIEW-->
|
||||
</body>
|
||||
</html>
|
||||
75
doc/header.html
Normal file
75
doc/header.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!-- HTML header for doxygen 1.8.9.1-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||
$treeview
|
||||
$search
|
||||
$mathjax
|
||||
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
|
||||
|
||||
<!-- Additional javascript for drawing charts. -->
|
||||
<script type="text/javascript" src="http://code.highcharts.com/highcharts.js"></script>
|
||||
<script type="text/javascript" src="http://code.highcharts.com/modules/data.js"></script>
|
||||
<script type="text/javascript" src="http://code.highcharts.com/modules/exporting.js"></script>
|
||||
<script type="text/javascript" src="$relpath^chart.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
$(".benchmark-chart").each(function(index, div) {
|
||||
var compiler = "clang-3.5.0";
|
||||
var dataset = div.getAttribute("data-dataset");
|
||||
var repo = "https://raw.githubusercontent.com/ldionne/hana/datasets/release/";
|
||||
$.getJSON(repo + compiler + "/" + dataset, function(options) {
|
||||
Hana.initChart($(div), options);
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
$extrastylesheet
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
|
||||
<!--BEGIN TITLEAREA-->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<!--BEGIN PROJECT_LOGO-->
|
||||
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||
<!--END PROJECT_LOGO-->
|
||||
<!--BEGIN PROJECT_NAME-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectname">$projectname
|
||||
<!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
|
||||
</div>
|
||||
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||
</td>
|
||||
<!--END PROJECT_NAME-->
|
||||
<!--BEGIN !PROJECT_NAME-->
|
||||
<!--BEGIN PROJECT_BRIEF-->
|
||||
<td style="padding-left: 0.5em;">
|
||||
<div id="projectbrief">$projectbrief</div>
|
||||
</td>
|
||||
<!--END PROJECT_BRIEF-->
|
||||
<!--END !PROJECT_NAME-->
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
<td>$searchbox</td>
|
||||
<!--END SEARCHENGINE-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!--END TITLEAREA-->
|
||||
<!-- end header part -->
|
||||
@@ -48,15 +48,14 @@ BOOST_HANA_RUNTIME_CHECK(
|
||||
|
||||
//! [reverse_transform_copy]
|
||||
reverse(
|
||||
transform(xs, to_str) // <-- copy into reverse(...) here
|
||||
transform(xs, to_str) // <-- copy into reverse(...) here?
|
||||
);
|
||||
//! [reverse_transform_copy]
|
||||
|
||||
//! [reverse_transform_move]
|
||||
reverse(
|
||||
transform(xs, to_str) // <-- move from the temporary
|
||||
transform(xs, to_str) // <-- nah, move from the temporary!
|
||||
);
|
||||
//! [reverse_transform_move]
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -103,10 +103,10 @@ insightful conversations with several attendees. The idea that it was
|
||||
possible to unify the [Boost.Fusion][] and the [Boost.MPL][] libraries
|
||||
made its way and I became convinced of it after writing the first prototype
|
||||
for what is now Boost.Hana. After working on Hana and polishing many rough
|
||||
edges during several months, Hana will soon go through informal and then
|
||||
formal reviews with the goal of being part of Boost.
|
||||
edges during several months, Hana will be going through formal review for
|
||||
inclusion in Boost from June 10 2015 to June 24 2015.
|
||||
|
||||
Let the fun begin.
|
||||
Let the fun begin!
|
||||
|
||||
|
||||
|
||||
@@ -120,15 +120,15 @@ Let the fun begin.
|
||||
@section tutorial-introduction Introduction
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Hana is a small, header-only library for C++ metaprogramming suited for
|
||||
computations on both types and values. The functionality it provides is
|
||||
a superset of what is provided by the well established Boost.MPL and
|
||||
Boost.Fusion libraries. By leveraging C++11/14 implementation techniques
|
||||
and idioms, Hana boasts faster compilation times and runtime performance on
|
||||
par or better than previous metaprogramming libraries, while increasing the
|
||||
level of expressiveness in the process. Hana is easy to extend in a ad-hoc
|
||||
manner and it provides out-of-the-box inter-operation with Boost.Fusion,
|
||||
Boost.MPL and the standard library.
|
||||
Hana is a header-only library for C++ metaprogramming suited for computations
|
||||
on both types and values. The functionality it provides is a superset of what
|
||||
is provided by the well established Boost.MPL and Boost.Fusion libraries. By
|
||||
leveraging C++11/14 implementation techniques and idioms, Hana boasts faster
|
||||
compilation times and runtime performance on par or better than previous
|
||||
metaprogramming libraries, while noticeably increasing the level of
|
||||
expressiveness in the process. Hana is easy to extend in a ad-hoc manner
|
||||
and it provides out-of-the-box inter-operation with Boost.Fusion, Boost.MPL
|
||||
and the standard library.
|
||||
|
||||
|
||||
__Motivation__\n
|
||||
@@ -290,6 +290,7 @@ function | concept | description
|
||||
`remove_at(index, sequence)` | Sequence | Remove the element at the given index. The index must be an `integral_constant`.
|
||||
`reverse(sequence)` | Sequence | Reverse the order of the elements in a sequence.
|
||||
`slice(sequence, from, to)` | Sequence | Returns the elements of a sequence at indices contained in `[from, to)`.
|
||||
`subsequence(sequence, indices)` | Sequence | Returns the elements of a sequence at the `indices` in the given sequence.
|
||||
`sort(sequence[, predicate])` | Sequence | Sort (stably) the elements of a sequence, optionally according to a predicate. The elements must be Orderable if no predicate is provided.
|
||||
`take(number, sequence)` | Sequence | Take the first n elements of a sequence. n must be an `integral_constant`.
|
||||
`take_{while,until}(sequence, predicate)` | Sequence | Take elements of a sequence while/until some predicate is satisfied, and return that.
|
||||
@@ -331,10 +332,7 @@ it also provides the `make_xxx` shortcut to reduce typing. Also, an
|
||||
interesting point that can be raised in this example is the fact that
|
||||
`r` is `constexpr`. In general, whenever a Hana sequence is initialized
|
||||
only with constant expressions (which is the case for `int_<...>`), that
|
||||
sequence may be marked as `constexpr`. However, there are some limitations
|
||||
to this because we sometimes use lambdas in the implementation and C++14
|
||||
does not allow lambdas to appear in constant expressions, so this should be
|
||||
considered a work in progress.
|
||||
sequence may be marked as `constexpr`.
|
||||
|
||||
|
||||
|
||||
@@ -430,21 +428,23 @@ that most of the time, we want to access all or almost all the elements in a
|
||||
sequence anyway, and hence performance is not a big argument in favor of
|
||||
laziness.
|
||||
|
||||
|
||||
@subsection tutorial-sem-perf Performance considerations
|
||||
|
||||
One might think that returning full sequences from an algorithm would lead to
|
||||
tons of undesirable copies. For example, when using `reverse` and `transform`,
|
||||
one could think that an intermediate copy is made after the call to `transform`:
|
||||
One might think that returning full sequences that own their elements from an
|
||||
algorithm would lead to tons of undesirable copies. For example, when using
|
||||
`reverse` and `transform`, one could think that an intermediate copy is made
|
||||
after the call to `transform`:
|
||||
|
||||
@snippet example/tutorial/sem.cpp reverse_transform_copy
|
||||
|
||||
To make sure this does not happen, Hana uses perfect forwarding and move
|
||||
semantics heavily so it can provide almost optimal runtime performance.
|
||||
semantics heavily so it can provide an almost optimal runtime performance.
|
||||
So instead of doing a copy, a move occurs between `reverse` and `transform`:
|
||||
|
||||
@snippet example/tutorial/sem.cpp reverse_transform_move
|
||||
|
||||
Ultimately, the goal is that code written using Hana should be equivalent to
|
||||
clever hand-written code, except it should be enjoyable to write. Performance
|
||||
considerations are explained in depth in their own [section](@ref tutorial-perf).
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -519,10 +519,10 @@ you would need to already know the result of the algorithm!):
|
||||
|
||||
@snippet example/tutorial/amphi.cpp all_of_compile_time_integral_constant
|
||||
|
||||
We just saw how some algorithms are able to return IntegralConstants when their
|
||||
inputs satisfy some constraints with respect to `compile-time`ness. However,
|
||||
other algorithms are more restrictive and they _require_ their inputs to
|
||||
satisfy some constraints regarding `compile-time`ness, without which they
|
||||
We just saw how some algorithms are able to return `IntegralConstant`s when
|
||||
their inputs satisfy some constraints with respect to `compile-time`ness.
|
||||
However, other algorithms are more restrictive and they _require_ their inputs
|
||||
to satisfy some constraints regarding `compile-time`ness, without which they
|
||||
are not able to operate at all. An example of this is `filter`, which takes a
|
||||
sequence and a predicate, and returns a new sequence containing only those
|
||||
elements for which the predicate is satisfied. `filter` requires the predicate
|
||||
@@ -683,9 +683,6 @@ a couple of interesting examples scattered in the documentation if you want
|
||||
more. There's also a minimal reimplementation of the MPL using Hana under
|
||||
the hood in `example/misc/mini_mpl.cpp`.
|
||||
|
||||
|
||||
@subsection tutorial-type-perf Performance considerations
|
||||
|
||||
@todo
|
||||
- Provide links to the scattered examples, and also to example/misc/mini_mpl.
|
||||
For some reason, I can't get Doxygen to generate a link.
|
||||
@@ -706,7 +703,206 @@ the hood in `example/misc/mini_mpl.cpp`.
|
||||
|
||||
|
||||
|
||||
@section tutorial-constexpr Limitations of constexpr
|
||||
@section tutorial-perf Performance considerations
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
C++ programmers love performance, so here's a whole section dedicated to it.
|
||||
Since Hana lives on the frontier between runtime and compile-time computations,
|
||||
we are not only interested in runtime performance, but also compile-time
|
||||
performance. Since both topics are pretty much disjoint, we treat them
|
||||
separately below.
|
||||
|
||||
@note
|
||||
The benchmarks presented in this section are updated automatically when we
|
||||
push to the repository. If you notice results that do not withstand the
|
||||
claims made here, open a [GitHub issue][GitHub.issues]; it could
|
||||
be a performance regression.
|
||||
|
||||
|
||||
@subsection tutorial-perf-compile Compile-time performance
|
||||
|
||||
C++ metaprogramming brings its share of awful things. One of the most annoying
|
||||
and well-known problem associated to it is interminable compilation times.
|
||||
Hana claims to be more compile-time efficient than its predecessors; this is
|
||||
a bold claim and we will now try to back it. Of course, Hana can't do miracles;
|
||||
metaprogramming is a byproduct of the C++ template system and the compiler is
|
||||
not meant to be used as an interpreter for some meta language. However, by
|
||||
using cutting edge and intensely benchmarked techniques, Hana is able to
|
||||
minimize the strain on the compiler.
|
||||
|
||||
Before we dive, let me make a quick note on the methodology used to measure
|
||||
compile-time performance in Hana. Previous metaprogramming libraries measured
|
||||
the compile-time complexity of their meta-algorithms and meta-sequences by
|
||||
looking at the number of instantiations the compiler had to perform. While
|
||||
easy to understand, this way of measuring the compile-time complexity actually
|
||||
does not give us a lot of information regarding the compilation time, which
|
||||
is what we're interested in minimizing at the end of the day. Basically, the
|
||||
reason for this is that template metaprogramming is such a twisted model of
|
||||
computation that it's very hard to find a standard way of measuring the
|
||||
performance of algorithms. Hence, instead of presenting meaningless complexity
|
||||
analyses, we prefer to benchmark everything on every supported compiler and to
|
||||
pick the best implementation on that compiler. Now, let's dive.
|
||||
|
||||
First, Hana minimizes its dependency on the preprocessor. In addition to
|
||||
yielding cleaner error messages in many cases, this reduces the overall
|
||||
parsing and preprocessing time for header files. Also, because Hana only
|
||||
supports cutting edge compilers, there are very few workarounds in the
|
||||
library, which results in a cleaner and smaller library. Finally, Hana
|
||||
minimizes reliance on any kind of external dependencies. In particular,
|
||||
it only uses other Boost libraries in a few specific cases, and it does
|
||||
not rely on the standard library for the largest part. There are several
|
||||
reasons (other than include times) for doing so; they are documented in
|
||||
the [rationales](@ref tutorial-rationales).
|
||||
|
||||
Below is a chart showing the time required to include different libraries. The
|
||||
chart shows the time for including everything in the (non-external) public API
|
||||
of each library. For example, for Hana this means the `<boost/hana.hpp>` header,
|
||||
which excludes the external adapters. For other libraries like Boost.Fusion,
|
||||
this means including all the public headers in the `boost/fusion/` directory,
|
||||
but not the adapters for external libraries like the MPL.
|
||||
|
||||
<div class="benchmark-chart"
|
||||
style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
data-dataset="benchmark.including.compile.json">
|
||||
</div>
|
||||
|
||||
In addition to reduced preprocessing times, Hana uses modern techniques to
|
||||
implement heterogeneous sequences and algorithms in the most compile-time
|
||||
efficient way possible. Before jumping to the compile-time performance of
|
||||
the algorithms, we will have a look at the compile-time cost of creating
|
||||
heterogeneous sequences. Indeed, since we will be presenting algorithms that
|
||||
work on sequences, we must be aware of the cost of creating the sequences
|
||||
themselves, since that will influence the benchmarks for the algorithms.
|
||||
The following chart presents the compile-time cost of creating sequences
|
||||
of `n` elements.
|
||||
|
||||
<div class="benchmark-chart"
|
||||
style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
data-dataset="benchmark.make.compile.json">
|
||||
</div>
|
||||
|
||||
@note
|
||||
You can zoom on the chart by selecting an area to zoom into.
|
||||
|
||||
The benchmark methodology is to always create the sequences in the most
|
||||
efficient way possible. For Hana, this simply means using the `make<Tuple>`
|
||||
function. However, for the MPL, this means creating a `mpl::vectorN` of size
|
||||
up to 20, and then using `mpl::push_back` to create larger vectors. We use a
|
||||
similar technique for Fusion sequences. The reason for doing so is that
|
||||
Fusion and MPL sequences have fixed size limits, and the techniques used
|
||||
here have been found to be the fastest way to create longer sequences.
|
||||
|
||||
As you can see, Hana's compile-time _complexity_ is better than the alternatives.
|
||||
However, if you look closer at the curves, you will see that the MPL has lower
|
||||
compile-times for small numbers of elements. This is because including Hana's
|
||||
`Tuple` takes more time than including `mpl::vector`, and you are witnessing
|
||||
that slowdown by a constant amount. The reason why including Hana's `Tuple` is
|
||||
slower than including `mpl::vector` is that Hana's `Tuple` includes all the
|
||||
algorithms it can be used with, while `mpl::vector` only includes the strict
|
||||
minimum. Considering you need to include most of them manually when using the
|
||||
MPL, this constant slowdown will be nonexistent in real code and Hana's
|
||||
approach just makes it less painful for the programmer.
|
||||
|
||||
You can also see that creating sequences has a non-negligible cost. Actually,
|
||||
this is really the most expensive part, as you will see in the following charts
|
||||
showing the compile-time performance of algorithms. When you look at the charts
|
||||
here and elsewhere in the library, keep in mind the cost of merely creating the
|
||||
sequences. Also note that only the most important algorithms will be presented
|
||||
here, but micro benchmarks for compile-time performance are scattered in the
|
||||
reference documentation. Also, the benchmarks we present compare several
|
||||
different libraries. However, since Hana and Fusion can work with values and
|
||||
not only types, comparing their algorithms with type-only libraries like MPL
|
||||
is not really fair. Indeed, Hana and Fusion algorithms are more powerful since
|
||||
they also allow runtime effects to be performed. However, the comparison
|
||||
between Fusion and Hana is fair, because both libraries are just as powerful
|
||||
(strictly speaking).
|
||||
|
||||
The first algorithm which is ubiquitous in metaprogramming is `transform`.
|
||||
It takes a sequence and a function, and returns a new sequence containing the
|
||||
result of applying the function to each element. The following chart presents
|
||||
the compile-time performance of applying `transform` to a sequence of `n`
|
||||
elements. The `x` axis represents the number of elements in the sequence, and
|
||||
the `y` axis represents the compilation time in seconds. Also note that we're
|
||||
using the `transform` equivalent in each library; we're not using the
|
||||
`transform` algorithm from Hana through the Boost.Fusion adapters, for
|
||||
example, which would likely be less efficient.
|
||||
|
||||
<div class="benchmark-chart"
|
||||
style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
data-dataset="benchmark.transform.compile.json">
|
||||
</div>
|
||||
|
||||
You probably also noticed how there are multiple slightly different curves for
|
||||
Fusion and Hana's `Tuple`. Those curves measure slightly different usage
|
||||
patterns for the `transform` algorithm. First, we benchmark `transform` when
|
||||
applied to sequences that contain both homogeneous and heterogeneous elements.
|
||||
The reason is that sequences holding heterogeneous elements tend to be less
|
||||
compile-time efficient, because the compiler has to instantiate more different
|
||||
types. Second, we benchmark the algorithm both on a standard Hana `Tuple` and
|
||||
on a `Tuple` created through `hana::tuple_t`, and mapping a Hana `Metafunction`
|
||||
instead of a regular function. The reason is that it is possible to optimize
|
||||
some algorithms (like `transform`) when we know we're actually mapping a
|
||||
metafunction on a type sequence. Basically, we can do the whole algorithm at
|
||||
the type level behind the scenes, which is more efficient, but you still get
|
||||
the nice value-level interface.
|
||||
|
||||
@note
|
||||
The representation of `tuple_t` is not really optimized right now, so there is
|
||||
no difference between using it and not using it. You should still use `tuple_t`
|
||||
to create type-only `Tuple`s, as some nice optimizations can be implemented.
|
||||
|
||||
The second important class of algorithms are folds. Folds can be used to
|
||||
implement many other algorithms like `count_if`, `minimum` and so on.
|
||||
Hence, a good compile-time performance for fold algorithms ensures a good
|
||||
compile-time performance for those derived algorithms, which is why we're
|
||||
only presenting folds here. Also note that all the non-monadic fold variants
|
||||
are somewhat equivalent in terms of compile-time, so we only present the left
|
||||
folds. The following chart presents the compile-time performance of applying
|
||||
`fold.left` to a sequence of `n` elements. The `x` axis represents the number
|
||||
of elements in the sequence, and the `y` axis represents the compilation time
|
||||
in seconds. The function used for folding is a dummy function that does nothing.
|
||||
In real code, you would likely fold with a nontrivial operation, so the curves
|
||||
would be worse than that. However, these are micro benchmarks and hence they
|
||||
only show the performance of the algorithm itself.
|
||||
|
||||
<div class="benchmark-chart"
|
||||
style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
data-dataset="benchmark.fold_left.compile.json">
|
||||
</div>
|
||||
|
||||
The third and last algorithm that we present here is the `find_if` algorithm.
|
||||
This algorithm is difficult to implement efficiently, because it requires
|
||||
stopping at the first element which satisfies the given predicate. For the
|
||||
same reason, modern techniques don't really help us here, so this algorithm
|
||||
constitutes a good test of the implementation quality of Hana disregarding
|
||||
the metaprogramming free lunch given to us by C++14.
|
||||
|
||||
<div class="benchmark-chart"
|
||||
style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
data-dataset="benchmark.find_if.compile.json">
|
||||
</div>
|
||||
|
||||
As you can see, Hana performs better than Fusion, and as well as MPL, yet
|
||||
Hana's `find_if` can be used with values too, unlike MPL's. This concludes
|
||||
the section on compile-time performance, but there are micro benchmarks of
|
||||
compile-time performance scattered around the documentation if you want to
|
||||
see the compile-time behavior of a particular algorithm.
|
||||
|
||||
|
||||
@subsection tutorial-perf-runtime Runtime performance
|
||||
|
||||
@todo Write this section.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@section tutorial-constexpr The limitations of constexpr
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
In C++, the border between compile-time and runtime is hazy, a fact that is
|
||||
@@ -1223,15 +1419,46 @@ the library, and please leave feedback on GitHub so we can improve the library!
|
||||
|
||||
|
||||
|
||||
@section tutorial-rationales Rationales/FAQ
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
This section documents the rationale for some design choices. It also serves
|
||||
as a FAQ for some (not so) frequently asked questions. If you think something
|
||||
should be added to this list, open a GitHub issue and we'll consider either
|
||||
improving the documentation or adding the question here.
|
||||
|
||||
|
||||
1. Why restrict usage of Boost and the standard library? After all, isn't this a (proposed) Boost library?
|
||||
There are several reasons for doing so. First, Hana is a very fundamental
|
||||
library; we are basically reimplementing the core language and the standard
|
||||
library with support for heterogeneous types. When you go through the code,
|
||||
you quickly realize that you very rarely need other libraries, and that
|
||||
almost everything must be implemented from scratch. Also, since Hana is very
|
||||
fundamental, there is even more incentive for keeping the dependencies minimal,
|
||||
because those dependencies will be handed down to the users.
|
||||
Finally, one big reason for using Boost is that it is highly portable. As an
|
||||
exception to the rule, this library only targets very recent compilers. Hence,
|
||||
we can afford to depend on modern constructs and the portability brought by
|
||||
using most Boost libraries is just dead weight.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Links -->
|
||||
[Boost.Fusion]: http://www.boost.org/doc/libs/release/libs/fusion/doc/html/index.html
|
||||
[Boost.MPL]: http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html
|
||||
[C++Now]: http://cppnow.org
|
||||
[constexpr_throw]: http://stackoverflow.com/a/8626450/627587
|
||||
[GitHub.issues]: https://github.com/ldionne/hana/issues
|
||||
[GOTW]: http://www.gotw.ca/gotw/index.htm
|
||||
[GSoC]: http://www.google-melange.com/gsoc/homepage/google/gsoc2014
|
||||
[MPL11]: http://github.com/ldionne/mpl11
|
||||
[constexpr_throw]: http://stackoverflow.com/a/8626450/627587
|
||||
[GOTW]: http://www.gotw.ca/gotw/index.htm
|
||||
|
||||
[Wikipedia.C++14]: http://en.wikipedia.org/wiki/C%2B%2B14
|
||||
[Wikipedia.CXX14_udl]: http://en.wikipedia.org/wiki/C%2B%2B11#User-defined_literals
|
||||
|
||||
@@ -245,6 +245,18 @@ namespace boost { namespace hana {
|
||||
//! fold.right(xs, f) -> fold_right_nostate_impl<Xs>::apply(xs, f)
|
||||
//! @endcode
|
||||
//! `fold` is not tag-dispatched because it is just an alias to `fold.left`.
|
||||
//!
|
||||
//!
|
||||
//! Benchmarks
|
||||
//! ----------
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.fold_left.compile.json">
|
||||
//! </div>
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.fold_right.compile.json">
|
||||
//! </div>
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto fold = see documentation;
|
||||
#else
|
||||
@@ -1103,7 +1115,10 @@ namespace boost { namespace hana {
|
||||
//!
|
||||
//! Benchmarks
|
||||
//! ----------
|
||||
//! @image html benchmark/foldable/product.ctime.png
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.product.compile.json">
|
||||
//! </div>
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto product = [](auto&& foldable) -> decltype(auto) {
|
||||
return tag-dispatched;
|
||||
@@ -1159,7 +1174,10 @@ namespace boost { namespace hana {
|
||||
//!
|
||||
//! Benchmarks
|
||||
//! ----------
|
||||
//! @image html benchmark/foldable/count_if.ctime.png
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.count_if.compile.json">
|
||||
//! </div>
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto count_if = [](auto&& foldable, auto&& predicate) -> decltype(auto) {
|
||||
return tag-dispatched;
|
||||
|
||||
@@ -151,7 +151,10 @@ namespace boost { namespace hana {
|
||||
//!
|
||||
//! Benchmarks
|
||||
//! ----------
|
||||
//! @image html benchmark/functor/transform.ctime.png
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.transform.compile.json">
|
||||
//! </div>
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto transform = [](auto&& xs, auto&& f) -> decltype(auto) {
|
||||
return tag-dispatched;
|
||||
|
||||
@@ -352,6 +352,14 @@ namespace boost { namespace hana {
|
||||
//! Example
|
||||
//! -------
|
||||
//! @snippet example/iterable.cpp at
|
||||
//!
|
||||
//!
|
||||
//! Benchmarks
|
||||
//! ----------
|
||||
//! <div class="benchmark-chart"
|
||||
//! style="min-width: 310px; height: 400px; margin: 0 auto"
|
||||
//! data-dataset="benchmark.at.compile.json">
|
||||
//! </div>
|
||||
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
||||
constexpr auto at = [](auto&& n, auto&& iterable) -> decltype(auto) {
|
||||
return tag-dispatched;
|
||||
|
||||
Reference in New Issue
Block a user