Skip to content

Commit

Permalink
refactor: slightly sleeker variant matching
Browse files Browse the repository at this point in the history
  • Loading branch information
mhx committed Jan 24, 2024
1 parent 905ac66 commit 34ef888
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 111 deletions.
49 changes: 24 additions & 25 deletions include/dwarfs/integral_value_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include <folly/Conv.h>
#include <folly/String.h>

#include "dwarfs/overloaded.h"
#include "dwarfs/match.h"

namespace dwarfs {

Expand All @@ -51,30 +51,29 @@ class integral_value_parser {
T parse(std::string_view arg) const {
auto val = folly::to<T>(arg);

std::visit(overloaded{
[](std::monostate const&) {},
[val](std::pair<T, T> 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<T> 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<bool(T)> 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<T, T> 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<T> 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<bool(T)> const& check) {
if (!check(val)) {
throw std::range_error(
fmt::format("value {} out of range", val));
}
},
};

return val;
}
Expand Down
31 changes: 29 additions & 2 deletions include/dwarfs/overloaded.h → include/dwarfs/match.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,41 @@

#pragma once

#include <type_traits>
#include <variant>

namespace dwarfs {

template <typename... Ts>
struct overloaded : Ts... {
struct match : Ts... {
using Ts::operator()...;
};

template <typename... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
match(Ts...) -> match<Ts...>;

namespace detail {

template <typename T>
struct is_a_variant : std::false_type {};

template <typename... Ts>
struct is_a_variant<std::variant<Ts...>> : std::true_type {};

template <typename T>
struct is_a_match : std::false_type {};

template <typename... Ts>
struct is_a_match<match<Ts...>> : std::true_type {};

} // namespace detail

template <typename T, typename U>
constexpr decltype(auto) operator|(T&& v, U&& m)
requires(detail::is_a_variant<std::decay_t<T>>::value &&
detail::is_a_match<std::decay_t<U>>::value)
{
return std::visit(std::forward<U>(m), std::forward<T>(v));
}

} // namespace dwarfs
32 changes: 14 additions & 18 deletions src/dwarfs/inode_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
51 changes: 23 additions & 28 deletions src/dwarfs/metadata_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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; },
};
}

/**
Expand Down
51 changes: 24 additions & 27 deletions src/mkdwarfs_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1248,14 +1248,13 @@ int mkdwarfs_main(int argc, sys_char** argv, iolayer const& iol) {
std::unique_ptr<filesystem_writer> fsw;

try {
std::ostream& fsw_os = std::visit(
overloaded{
[&](std::monostate) -> std::ostream& { return iol.out; },
[&](std::unique_ptr<output_stream>& 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<output_stream>& os) -> std::ostream& {
return os->os();
},
[&](std::ostringstream& oss) -> std::ostream& { return oss; }};

fsw = std::make_unique<filesystem_writer>(
fsw_os, lgr, wg_compress, prog, schema_bc, metadata_bc, history_bc,
Expand Down Expand Up @@ -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<output_stream>& 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<output_stream>& 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;
Expand Down
21 changes: 10 additions & 11 deletions test/test_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
#include <folly/String.h>
#include <folly/portability/Unistd.h>

#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"
Expand Down Expand Up @@ -448,16 +448,15 @@ os_access_mock::map_file(fs::path const& path, size_t size) const {
}

return std::make_unique<mmap_mock>(
std::visit(overloaded{
[this](std::string const& str) { return str; },
[this](std::function<std::string()> 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<std::string()> const& fun) {
return fun();
},
[this](auto const&) -> std::string {
throw std::runtime_error("oops in match");
},
},
size);
}

Expand Down

0 comments on commit 34ef888

Please sign in to comment.