Created
August 28, 2017 20:25
-
-
Save dodheim/d838ea0ff6e3cbd9a494e45c6c3f59f4 to your computer and use it in GitHub Desktop.
Boost.Hana fusion_map demo for /u/Bitter_Peter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define BOOST_HANA_CONFIG_ENABLE_STRING_UDL 1 | |
#include <type_traits> | |
#include <utility> | |
#include <optional> | |
#include <string_view> | |
#include <array> | |
#include <range/v3/core.hpp> | |
#include <range/v3/algorithm/lower_bound.hpp> | |
#include <boost/hana.hpp> | |
#include <boost/hana/ext/std/integer_sequence.hpp> | |
#include <boost/hana/ext/std/pair.hpp> | |
namespace hana = boost::hana; | |
using namespace hana::literals; | |
// named type to hold desired registry values for expositional purposes | |
struct pressure_value { | |
explicit constexpr pressure_value(int const val) noexcept : value(val) { } | |
int value; | |
}; | |
using pressure = std::pair<std::string_view, pressure_value>; | |
// registry-entry types; it must be possible to derive a pressure_value from each | |
struct foo { pressure_value pressure_val{1}; /*other state*/ }; | |
struct bar { pressure_value pressure_val{2}; /*other state*/ }; | |
struct baz { constexpr auto pressure_val() const { return pressure_value{3}; } /*other state*/ }; | |
struct qux { constexpr int get_pressure_val() const { return 4; } /*other state*/ }; | |
// compile-time registry | |
auto constexpr registry = hana::make_map( | |
hana::make_pair("foo"_s, foo{}), | |
hana::make_pair("bar"_s, bar{}), | |
hana::make_pair("baz"_s, baz{}), | |
hana::make_pair("qux"_s, qux{}) | |
); | |
namespace detail { | |
// customization point in case registry-entry types do not expose their desired value uniformly; | |
// unnecessary if they do | |
auto constexpr extract_pressure_val = hana::overload( | |
// default case | |
[](auto const& re) { return re.pressure_val; }, | |
// specialized cases | |
[](baz const& b) { return b.pressure_val(); }, | |
[](qux const& q) { return pressure_value{q.get_pressure_val()}; } | |
); | |
// converts hana::pair<StringT, RegistryEntryT> to std::pair<string_view, pressure_value> | |
auto constexpr make_pressure = [](auto const n, auto const& re) -> pressure { | |
return {{n.c_str(), hana::length(n)}, detail::extract_pressure_val(re)}; | |
}; | |
} | |
// runtime registry; (constexpr) std::array for this demo, but could be any container type e.g. unordered_map | |
auto constexpr pressure_registry = hana::unpack( | |
std::make_index_sequence<hana::length(registry)>{}, | |
[](auto const... is) -> std::array<pressure, sizeof...(is)> { | |
auto constexpr ns = hana::sort(hana::to_tuple(hana::keys(registry))); | |
return {{detail::make_pressure(ns[is], registry[ns[is]])...}}; | |
} | |
); | |
auto constexpr lookup_pressure_val = hana::overload( | |
// compile-time key lookup | |
[](auto const n) -> std::enable_if_t<hana::is_a<hana::string_tag, decltype(n)>(), std::optional<pressure_value>> { | |
if constexpr(auto re = hana::find(registry, n); hana::is_just(re)) { | |
return {detail::extract_pressure_val(*re)}; | |
} else { | |
return {}; | |
} | |
}, | |
// runtime key lookup | |
[](std::string_view const n) { | |
std::optional<pressure_value> ret; | |
// using lower_bound since we have a sorted array; use appropriate logic depending | |
// on the actual type of pressure_registry e.g. member .find() if it is an unordered_map | |
if (auto const it = ranges::lower_bound(pressure_registry, n, ranges::ordered_less{}, hana::first); | |
it != ranges::end(pressure_registry) && it->first == n) | |
{ | |
ret = it->second; | |
} | |
return ret; | |
} | |
); | |
//////////////////////////////////////////////////////////////////////////////// | |
// demo | |
#include <cstdlib> | |
#include <exception> | |
#include <string> | |
#include <iomanip> | |
#include <iostream> | |
#include <boost/hana/experimental/printable.hpp> | |
using namespace std::string_view_literals; | |
std::ostream& operator <<(std::ostream& os, foo const& f) { | |
return os << "foo{"sv << f.pressure_val.value << "}\n"sv; | |
} | |
std::ostream& operator <<(std::ostream& os, bar const& b) { | |
return os << "bar{"sv << b.pressure_val.value << "}\n"sv; | |
} | |
std::ostream& operator <<(std::ostream& os, baz const& b) { | |
return os << "baz{"sv << b.pressure_val().value << "}\n"sv; | |
} | |
std::ostream& operator <<(std::ostream& os, qux const& q) { | |
return os << "qux{"sv << q.get_pressure_val() << "}\n"sv; | |
} | |
static void demo() { | |
using namespace std::string_literals; | |
std::cout << "registry:\n"sv << hana::experimental::print(registry) << '\n'; | |
std::cout << "\npressure_registry: \n"sv; | |
for (auto const [n, pv] : pressure_registry) { | |
std::cout << '\t' << std::quoted(n) << " :: "sv << pv.value << '\n'; | |
} | |
std::cout << "\nlookup results: \n"sv; | |
static auto constexpr print_lookup_results = [](auto const n) { | |
std::cout << '\t'; | |
if constexpr(hana::is_a<hana::string_tag, decltype(n)>()) { | |
std::cout << std::quoted(n.c_str()) << " (compile-time lookup)"sv; | |
} else { | |
std::cout << std::quoted(n) << " (runtime lookup)"sv; | |
} | |
std::cout << " :: "sv; | |
if (auto const pv = lookup_pressure_val(n)) { | |
std::cout << pv->value; | |
} else { | |
std::cout << "{nullopt}"sv; | |
} | |
std::cout << '\n'; | |
}; | |
print_lookup_results("qux"_s); // pass (hana::string) | |
print_lookup_results("baz"sv); // pass (std::string_view) | |
print_lookup_results("bar"s); // pass (std::string) | |
print_lookup_results("foo"); // pass (char const*) | |
print_lookup_results("corge"sv); // fail (std::string_view) | |
print_lookup_results("corge"_s); // fail (hana::string) | |
} | |
int main() { | |
std::ios::sync_with_stdio(false); | |
std::cout << std::boolalpha; | |
std::cerr << std::boolalpha; | |
try { | |
demo(); | |
return EXIT_SUCCESS; | |
} catch (std::exception const& ex) { | |
std::cerr << ex.what() << '\n'; | |
} catch (...) { | |
std::cerr << "unknown exception (...)\n"sv; | |
} | |
return EXIT_FAILURE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment