diff --git a/include/dwarfs/integral_value_parser.h b/include/dwarfs/integral_value_parser.h index 3861e37c..4abefb26 100644 --- a/include/dwarfs/integral_value_parser.h +++ b/include/dwarfs/integral_value_parser.h @@ -33,7 +33,7 @@ #include #include -#include "dwarfs/overloaded.h" +#include "dwarfs/match.h" namespace dwarfs { @@ -51,30 +51,29 @@ class integral_value_parser { T parse(std::string_view arg) const { auto val = folly::to(arg); - std::visit(overloaded{ - [](std::monostate const&) {}, - [val](std::pair const& minmax) { - if (val < minmax.first || val > minmax.second) { - throw std::range_error( - fmt::format("value {} out of range [{}..{}]", val, - minmax.first, minmax.second)); - } - }, - [val](std::set const& choices) { - if (auto it = choices.find(val); it == choices.end()) { - throw std::range_error( - fmt::format("invalid value {}, must be one of [{}]", - val, folly::join(", ", choices))); - } - }, - [val](std::function const& check) { - if (!check(val)) { - throw std::range_error( - fmt::format("value {} out of range", val)); - } - }, - }, - valid_); + valid_ | match{ + [](std::monostate const&) {}, + [val](std::pair const& minmax) { + if (val < minmax.first || val > minmax.second) { + throw std::range_error( + fmt::format("value {} out of range [{}..{}]", val, + minmax.first, minmax.second)); + } + }, + [val](std::set const& choices) { + if (auto it = choices.find(val); it == choices.end()) { + throw std::range_error( + fmt::format("invalid value {}, must be one of [{}]", + val, folly::join(", ", choices))); + } + }, + [val](std::function const& check) { + if (!check(val)) { + throw std::range_error( + fmt::format("value {} out of range", val)); + } + }, + }; return val; } diff --git a/include/dwarfs/overloaded.h b/include/dwarfs/match.h similarity index 57% rename from include/dwarfs/overloaded.h rename to include/dwarfs/match.h index c29ad354..947940d6 100644 --- a/include/dwarfs/overloaded.h +++ b/include/dwarfs/match.h @@ -21,14 +21,41 @@ #pragma once +#include +#include + namespace dwarfs { template -struct overloaded : Ts... { +struct match : Ts... { using Ts::operator()...; }; template -overloaded(Ts...) -> overloaded; +match(Ts...) -> match; + +namespace detail { + +template +struct is_a_variant : std::false_type {}; + +template +struct is_a_variant> : std::true_type {}; + +template +struct is_a_match : std::false_type {}; + +template +struct is_a_match> : std::true_type {}; + +} // namespace detail + +template +[[nodiscard]] constexpr decltype(auto) operator|(T&& v, U&& m) + requires(detail::is_a_variant>::value && + detail::is_a_match>::value) +{ + return std::visit(std::forward(m), std::forward(v)); +} } // namespace dwarfs diff --git a/src/dwarfs/inode_manager.cpp b/src/dwarfs/inode_manager.cpp index e981c277..d4f7421d 100644 --- a/src/dwarfs/inode_manager.cpp +++ b/src/dwarfs/inode_manager.cpp @@ -49,11 +49,11 @@ #include "dwarfs/inode_manager.h" #include "dwarfs/inode_ordering.h" #include "dwarfs/logger.h" +#include "dwarfs/match.h" #include "dwarfs/mmif.h" #include "dwarfs/nilsimsa.h" #include "dwarfs/options.h" #include "dwarfs/os_access.h" -#include "dwarfs/overloaded.h" #include "dwarfs/progress.h" #include "dwarfs/promise_receiver.h" #include "dwarfs/scanner_progress.h" @@ -273,37 +273,33 @@ class inode_ : public inode { os << " similarity: "; - auto basic_hash_visitor = [&os](uint32_t sh) { + auto basic_hash_matcher = [&os](uint32_t sh) { os << fmt::format("basic ({0:08x})\n", sh); }; - auto nilsimsa_hash_visitor = [&os](nilsimsa::hash_type const& nh) { + auto nilsimsa_hash_matcher = [&os](nilsimsa::hash_type const& nh) { os << fmt::format("nilsimsa ({0:016x}{1:016x}{2:016x}{3:016x})\n", nh[0], nh[1], nh[2], nh[3]); }; - auto similarity_map_visitor = [&](similarity_map_type const& map) { + auto similarity_map_matcher = [&](similarity_map_type const& map) { os << "map\n"; for (auto const& [cat, val] : map) { os << " "; dump_category(cat); - std::visit( - overloaded{ - basic_hash_visitor, - nilsimsa_hash_visitor, - }, - val); + val | match{ + basic_hash_matcher, + nilsimsa_hash_matcher, + }; } }; - std::visit( - overloaded{ - [&os](std::monostate const&) { os << "none\n"; }, - basic_hash_visitor, - nilsimsa_hash_visitor, - similarity_map_visitor, - }, - similarity_); + similarity_ | match{ + [&os](std::monostate const&) { os << "none\n"; }, + basic_hash_matcher, + nilsimsa_hash_matcher, + similarity_map_matcher, + }; } void set_scan_error(file const* fp, std::exception_ptr ep) override { diff --git a/src/dwarfs/metadata_types.cpp b/src/dwarfs/metadata_types.cpp index cc0941a3..b8a90cac 100644 --- a/src/dwarfs/metadata_types.cpp +++ b/src/dwarfs/metadata_types.cpp @@ -28,8 +28,8 @@ #include "dwarfs/error.h" #include "dwarfs/logger.h" +#include "dwarfs/match.h" #include "dwarfs/metadata_types.h" -#include "dwarfs/overloaded.h" #include "dwarfs/util.h" #include "dwarfs/gen-cpp2/metadata_types_custom_protocol.h" @@ -590,39 +590,34 @@ auto inode_view::getgid() const -> gid_type { // TODO: pretty certain some of this stuff can be simplified std::string dir_entry_view::name() const { - return std::visit(overloaded{ - [this](DirEntryView const& dev) { - return g_->names()[dev.name_index()]; - }, - [this](InodeView const& iv) { - return std::string( - g_->meta().names()[iv.name_index_v2_2()]); - }, - }, - v_); + return v_ | + match{ + [this](DirEntryView const& dev) { + return g_->names()[dev.name_index()]; + }, + [this](InodeView const& iv) { + return std::string(g_->meta().names()[iv.name_index_v2_2()]); + }, + }; } inode_view dir_entry_view::inode() const { - return std::visit(overloaded{ - [this](DirEntryView const& dev) { - return inode_view( - g_->meta().inodes()[dev.inode_num()], - dev.inode_num(), g_->meta()); - }, - [this](InodeView const& iv) { - return inode_view(iv, iv.inode_v2_2(), g_->meta()); - }, - }, - v_); + return v_ | match{ + [this](DirEntryView const& dev) { + return inode_view(g_->meta().inodes()[dev.inode_num()], + dev.inode_num(), g_->meta()); + }, + [this](InodeView const& iv) { + return inode_view(iv, iv.inode_v2_2(), g_->meta()); + }, + }; } bool dir_entry_view::is_root() const { - return std::visit( - overloaded{ - [](DirEntryView const& dev) { return dev.inode_num() == 0; }, - [](InodeView const& iv) { return iv.inode_v2_2() == 0; }, - }, - v_); + return v_ | match{ + [](DirEntryView const& dev) { return dev.inode_num() == 0; }, + [](InodeView const& iv) { return iv.inode_v2_2() == 0; }, + }; } /** diff --git a/src/mkdwarfs_main.cpp b/src/mkdwarfs_main.cpp index 7261059a..840b7ab4 100644 --- a/src/mkdwarfs_main.cpp +++ b/src/mkdwarfs_main.cpp @@ -73,11 +73,11 @@ #include "dwarfs/integral_value_parser.h" #include "dwarfs/iolayer.h" #include "dwarfs/logger.h" +#include "dwarfs/match.h" #include "dwarfs/mmap.h" #include "dwarfs/options.h" #include "dwarfs/options_interface.h" #include "dwarfs/os_access.h" -#include "dwarfs/overloaded.h" #include "dwarfs/program_options_helpers.h" #include "dwarfs/progress.h" #include "dwarfs/scanner.h" @@ -1248,14 +1248,13 @@ int mkdwarfs_main(int argc, sys_char** argv, iolayer const& iol) { std::unique_ptr fsw; try { - std::ostream& fsw_os = std::visit( - overloaded{ - [&](std::monostate) -> std::ostream& { return iol.out; }, - [&](std::unique_ptr& os) -> std::ostream& { - return os->os(); - }, - [&](std::ostringstream& oss) -> std::ostream& { return oss; }}, - os); + std::ostream& fsw_os = + os | + match{[&](std::monostate) -> std::ostream& { return iol.out; }, + [&](std::unique_ptr& os) -> std::ostream& { + return os->os(); + }, + [&](std::ostringstream& oss) -> std::ostream& { return oss; }}; fsw = std::make_unique( fsw_os, lgr, wg_compress, prog, schema_bc, metadata_bc, history_bc, @@ -1339,24 +1338,22 @@ int mkdwarfs_main(int argc, sys_char** argv, iolayer const& iol) { } { - auto ec = std::visit( - overloaded{[](std::monostate) -> int { return 0; }, - [&](std::unique_ptr& os) -> int { - std::error_code ec; - os->close(ec); - if (ec) { - LOG_ERROR << "failed to close output file '" << output - << "': " << ec.message(); - return 1; - } - os.reset(); - return 0; - }, - [](std::ostringstream& oss [[maybe_unused]]) -> int { - assert(oss.str().empty()); - return 0; - }}, - os); + auto ec = os | match{[](std::monostate) -> int { return 0; }, + [&](std::unique_ptr& os) -> int { + std::error_code ec; + os->close(ec); + if (ec) { + LOG_ERROR << "failed to close output file '" + << output << "': " << ec.message(); + return 1; + } + os.reset(); + return 0; + }, + [](std::ostringstream& oss [[maybe_unused]]) -> int { + assert(oss.str().empty()); + return 0; + }}; if (ec != 0) { return ec; diff --git a/test/test_helpers.cpp b/test/test_helpers.cpp index 8a942264..179715b0 100644 --- a/test/test_helpers.cpp +++ b/test/test_helpers.cpp @@ -33,8 +33,8 @@ #include #include +#include "dwarfs/match.h" #include "dwarfs/os_access_generic.h" -#include "dwarfs/overloaded.h" #include "dwarfs/util.h" #include "loremipsum.h" #include "mmap_mock.h" @@ -448,16 +448,15 @@ os_access_mock::map_file(fs::path const& path, size_t size) const { } return std::make_unique( - std::visit(overloaded{ - [this](std::string const& str) { return str; }, - [this](std::function const& fun) { - return fun(); - }, - [this](auto const&) -> std::string { - throw std::runtime_error("oops in overloaded"); - }, - }, - de->v), + de->v | match{ + [this](std::string const& str) { return str; }, + [this](std::function const& fun) { + return fun(); + }, + [this](auto const&) -> std::string { + throw std::runtime_error("oops in match"); + }, + }, size); }