From 09d27310b3b27f427dba593882e63a2d5beac542 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Wed, 21 May 2025 11:38:47 +0800 Subject: [PATCH] osd: migrate from boost::variant to std::variant Replace boost::variant with std::variant throughout the OSD-related codebase. This change reduces third-party dependencies by leveraging the C++ standard library alternative. Changes: - common/inline_variant.h: Replace the existing match() helper with a wrapper around std::visit. The previous implementation constructed a visitor class from given functions; the new implementation provides equivalent functionality using standard library primitives. - osd/osd_types.h: Add templated operator<< overload for std::variant. Since boost::variant provided a built-in operator<< that we relied on, and std::variant does not include this functionality, we implement our own formatter. To avoid ambiguous overload resolution (where types implicitly convertible to variant alternatives could match both the variant formatter and their native formatters), the template requires at least one alternative type parameter. This migration maintains existing functionality while eliminating the boost::variant dependency. Signed-off-by: Kefu Chai --- src/common/inline_variant.h | 204 +--------------------------- src/osd/ECTransactionL.h | 2 +- src/osd/PGTransaction.h | 24 ++-- src/osd/osd_types.cc | 10 +- src/osd/osd_types.h | 16 ++- src/test/osd/test_pg_transaction.cc | 22 +-- 6 files changed, 47 insertions(+), 231 deletions(-) diff --git a/src/common/inline_variant.h b/src/common/inline_variant.h index 28426ba7104a9..8d64c230ca498 100644 --- a/src/common/inline_variant.h +++ b/src/common/inline_variant.h @@ -1,211 +1,19 @@ // -*- mode:C++; tab-width:8; c-basic-offset:4; indent-tabs-mode:t -*- // vim: ts=8 sw=4 smarttab -/* - * Copied from: - * https://github.com/exclipy/inline_variant_visitor/blob/master/inline_variant.hpp - */ #ifndef INLINE_VARIANT_H #define INLINE_VARIANT_H -#include -#include -#include -#include -#include -#include -#include +#include +#include -#include "function_signature.h" - -namespace detail { - -// A metafunction class for getting the argument type from a unary function or functor type -struct function_arg_extractor -{ - // Function is either a function type like void(int const&), or a functor - eg. a class with void operator(int) - // Sets type to the argument type with the constness and referenceness stripped (eg. int) - template - struct apply - { - private: - typedef typename boost::remove_const< typename boost::remove_reference::type >::type bare_type; - typedef typename signature_of::type normalized_function_type; - typedef typename boost::function_types::function_arity::type arity; - typedef typename boost::function_types::parameter_types::type parameter_types; - typedef typename boost::function_types::result_type::type result_type; - - BOOST_STATIC_ASSERT_MSG((arity::value == 1), "make_visitor called with a non-unary function"); - - typedef typename boost::mpl::front::type parameter_type; - public: - typedef typename boost::remove_const< typename boost::remove_reference::type >::type type; - }; -}; - -struct make_pair -{ - template - struct apply { - typedef boost::mpl::pair type; - }; -}; - -// A metafunction class that asserts the second argument is in Allowed, and returns void -template -struct check_in -{ - template - struct apply - { - private: - BOOST_STATIC_ASSERT_MSG((boost::mpl::contains::type>::value), - "make_visitor called with spurious handler functions"); - public: - typedef void type; - }; -}; - -template -struct as_map -{ -private: - struct insert_helper { - template - struct apply - { - typedef typename boost::mpl::insert< - M, - P>::type type; - }; - }; -public: - typedef typename boost::mpl::fold, insert_helper>::type type; -}; - -// A functor template suitable for passing into apply_visitor. The constructor accepts the list of handler functions, -// which are then exposed through a set of operator()s -template -struct generic_visitor : boost::static_visitor, boost::noncopyable -{ -private: - typedef generic_visitor type; - - // Compute the function_map type - typedef boost::mpl::vector function_types; - typedef typename boost::mpl::transform::type arg_types; - typedef typename boost::mpl::transform< - arg_types, - boost::mpl::range_c::value>, - make_pair - >::type pair_list; - typedef typename as_map::type fmap; - - // Check that the argument types are unique - BOOST_STATIC_ASSERT_MSG((boost::mpl::size::value == boost::mpl::size::value), - "make_visitor called with non-unique argument types for handler functions"); - - // Check that there aren't any argument types not in the variant types - typedef typename boost::mpl::fold >::type dummy; - - boost::fusion::vector fvec; - - - template - Result apply_helper(const T& object, boost::mpl::true_) const { - typedef typename boost::mpl::at::type Ind; - return boost::fusion::at(fvec)(object); - } - - template - Result apply_helper(const T& object, boost::mpl::false_) const { - return Result(); - } - - BOOST_MOVABLE_BUT_NOT_COPYABLE(generic_visitor) - -public: - generic_visitor(BOOST_RV_REF(type) other) - : - fvec(boost::move(other.fvec)) - { - } - generic_visitor(Functions&&... functions) - : - fvec(std::forward(functions)...) - { - } - - template - Result operator()(const T& object) const { - typedef typename boost::mpl::has_key::type correct_key; - BOOST_STATIC_ASSERT_MSG(correct_key::value, - "make_visitor called without specifying handlers for all required types"); - return apply_helper(object, correct_key()); - } -}; - -// A metafunction class for getting the return type of a function -struct function_return_extractor -{ - template - struct apply : boost::function_types::result_type::type> - { - }; -}; - -// A metafunction class that asserts the two arguments are the same and returns the first one -struct check_same -{ - template - struct apply - { - private: - BOOST_STATIC_ASSERT_MSG((boost::is_same::value), - "make_visitor called with functions of differing return types"); - public: - typedef Type1 type; - }; -}; - -// A metafunction for getting the required generic_visitor type for the set of Functions -template -struct get_generic_visitor -{ -private: - typedef boost::mpl::vector function_types; - typedef typename boost::mpl::transform< - function_types, - boost::remove_const< boost::remove_reference > - >::type bare_function_types; - typedef typename boost::mpl::transform::type return_types; - -public: - // Set result_type to the return type of the first function - typedef typename boost::mpl::front::type result_type; - typedef generic_visitor type; - -private: - // Assert that every return type is the same as the first one - typedef typename boost::mpl::fold::type dummy; -}; - -// Accepts a set of functions and returns an object suitable for apply_visitor -template -auto make_visitor(BOOST_RV_REF(Functions)... functions) - -> typename detail::get_generic_visitor::type -{ - return typename detail::get_generic_visitor::type(boost::forward(functions)...); -} - -} +template +struct overloaded : Functions... { using Functions::operator()...; }; template -auto match(Variant const& variant, BOOST_RV_REF(Functions)... functions) - -> typename detail::get_generic_visitor::result_type +auto match(Variant const& variant, Functions... functions) { - return boost::apply_visitor(detail::make_visitor( - boost::forward(functions)...), variant); + return std::visit(overloaded{std::forward(functions)...}, variant); } #endif diff --git a/src/osd/ECTransactionL.h b/src/osd/ECTransactionL.h index 16febce8cd5a4..16f8cd0cf3201 100644 --- a/src/osd/ECTransactionL.h +++ b/src/osd/ECTransactionL.h @@ -84,7 +84,7 @@ namespace ECTransactionL { extent_set raw_write_set; for (auto &&extent: op.buffer_updates) { using BufferUpdate = PGTransaction::ObjectOperation::BufferUpdate; - if (boost::get(&(extent.get_val()))) { + if (std::holds_alternative(extent.get_val())) { ceph_assert( 0 == "CloneRange is not allowed, do_op should have returned ENOTSUPP"); diff --git a/src/osd/PGTransaction.h b/src/osd/PGTransaction.h index 5055b3b42e7f9..928d9483966ae 100644 --- a/src/osd/PGTransaction.h +++ b/src/osd/PGTransaction.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "common/hobject.h" #ifndef WITH_CRIMSON @@ -55,7 +56,7 @@ public: hobject_t source; // must be temp object }; }; - using InitType = boost::variant< + using InitType = std::variant< Init::None, Init::Create, Init::Clone, @@ -91,16 +92,16 @@ public: return delete_first; } bool is_delete() const { - return boost::get(&init_type) != nullptr && delete_first; + return std::holds_alternative(init_type) && delete_first; } bool is_none() const { - return boost::get(&init_type) != nullptr && !delete_first; + return std::holds_alternative(init_type) && !delete_first; } bool is_fresh_object() const { - return boost::get(&init_type) == nullptr; + return !std::holds_alternative(init_type); } bool is_rename() const { - return boost::get(&init_type) != nullptr; + return std::holds_alternative(init_type); } bool has_source(hobject_t *source = nullptr) const { return match( @@ -163,7 +164,7 @@ public: uint64_t len; }; }; - using BufferUpdateType = boost::variant< + using BufferUpdateType = std::variant< BufferUpdate::Write, BufferUpdate::Zero, BufferUpdate::CloneRange>; @@ -208,12 +209,11 @@ public: return match( left, [&](const BufferUpdate::Write &w) -> bool { - auto r = boost::get(&right); + auto r = std::get_if(&right); return r != nullptr && (w.fadvise_flags == r->fadvise_flags); }, [&](const BufferUpdate::Zero &) -> bool { - auto r = boost::get(&right); - return r != nullptr; + return std::holds_alternative(right); }, [&](const BufferUpdate::CloneRange &c) -> bool { return false; @@ -225,15 +225,15 @@ public: return match( left, [&](const BufferUpdate::Write &w) -> BufferUpdateType { - auto r = boost::get(&right); + auto r = std::get_if(&right); ceph_assert(r && w.fadvise_flags == r->fadvise_flags); ceph::buffer::list bl = w.buffer; bl.append(r->buffer); return BufferUpdate::Write{bl, w.fadvise_flags}; }, [&](const BufferUpdate::Zero &z) -> BufferUpdateType { - auto r = boost::get(&right); - ceph_assert(r); + auto r = std::get_if(&right); + ceph_assert(r != nullptr); return BufferUpdate::Zero{z.len + r->len}; }, [&](const BufferUpdate::CloneRange &c) -> BufferUpdateType { diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc index 0c47e84dc6c25..3e04c28f31fb6 100644 --- a/src/osd/osd_types.cc +++ b/src/osd/osd_types.cc @@ -1416,7 +1416,7 @@ bool pool_opts_t::unset(pool_opts_t::key_t key) { return opts.erase(key) > 0; } -class pool_opts_dumper_t : public boost::static_visitor<> { +class pool_opts_dumper_t { public: pool_opts_dumper_t(const std::string& name_, Formatter* f_) : name(name_.c_str()), f(f_) {} @@ -1443,7 +1443,7 @@ void pool_opts_t::dump(const std::string& name, Formatter* f) const if (i == opts.end()) { return; } - boost::apply_visitor(pool_opts_dumper_t(name, f), i->second); + std::visit(pool_opts_dumper_t(name, f), i->second); } void pool_opts_t::dump(Formatter* f) const @@ -1455,11 +1455,11 @@ void pool_opts_t::dump(Formatter* f) const if (j == opts.end()) { continue; } - boost::apply_visitor(pool_opts_dumper_t(name, f), j->second); + std::visit(pool_opts_dumper_t(name, f), j->second); } } -class pool_opts_encoder_t : public boost::static_visitor<> { +class pool_opts_encoder_t { public: explicit pool_opts_encoder_t(ceph::buffer::list& bl_, uint64_t features) : bl(bl_), @@ -1498,7 +1498,7 @@ void pool_opts_t::encode(ceph::buffer::list& bl, uint64_t features) const encode(n, bl); for (auto i = opts.cbegin(); i != opts.cend(); ++i) { encode(static_cast(i->first), bl); - boost::apply_visitor(pool_opts_encoder_t(bl, features), i->second); + std::visit(pool_opts_encoder_t(bl, features), i->second); } ENCODE_FINISH(bl); } diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 5a58dddaf80e3..c6d29d1e6a659 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -27,8 +27,8 @@ #include #include #include +#include -#include #ifdef WITH_CRIMSON #include #endif @@ -1148,7 +1148,7 @@ public: } }; - typedef boost::variant value_t; + typedef std::variant value_t; static bool is_opt_name(const std::string& name); static opt_desc_t get_opt_desc(const std::string& name); @@ -1168,7 +1168,7 @@ public: if (i == opts.end()) { return false; } - *val = boost::get(i->second); + *val = std::get(i->second); return true; } @@ -1178,7 +1178,7 @@ public: if (i == opts.end()) { return std::forward(default_value); } - return boost::get(i->second); + return std::get(i->second); } const value_t& get(key_t key) const; @@ -1200,6 +1200,14 @@ private: }; WRITE_CLASS_ENCODER_FEATURES(pool_opts_t) +template +std::ostream& operator<<(std::ostream& out, const std::variant& v) { + std::visit([&out](const auto& value) { + out << value; + }, v); + return out; +} + struct pg_merge_meta_t { pg_t source_pgid; epoch_t ready_epoch = 0; diff --git a/src/test/osd/test_pg_transaction.cc b/src/test/osd/test_pg_transaction.cc index 6aa26920d4601..dfd7d79c97897 100644 --- a/src/test/osd/test_pg_transaction.cc +++ b/src/test/osd/test_pg_transaction.cc @@ -29,7 +29,7 @@ TEST(pgtransaction, simple) [&](const pair &p) { ASSERT_EQ(p.first, h); using T = PGTransaction::ObjectOperation::Init; - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); ++num; }); ASSERT_EQ(num, 1u); @@ -50,13 +50,13 @@ TEST(pgtransaction, clone_safe_create_traverse) using T = PGTransaction::ObjectOperation::Init; if (num == 0) { ASSERT_EQ(p.first, h); - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); ASSERT_EQ( - boost::get(&p.second.init_type)->source, + std::get_if(&p.second.init_type)->source, h2); } else if (num == 1) { ASSERT_EQ(p.first, h2); - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); } else { ASSERT_LT(num, 2u); } @@ -83,19 +83,19 @@ TEST(pgtransaction, clone_safe_create_traverse2) using T = PGTransaction::ObjectOperation::Init; if (num == 0) { ASSERT_EQ(p.first, h); - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); ASSERT_EQ( - boost::get(&p.second.init_type)->source, + std::get_if(&p.second.init_type)->source, h2); } else if (num == 1) { ASSERT_EQ(p.first, h2); - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); ASSERT_EQ( - boost::get(&p.second.init_type)->source, + std::get_if(&p.second.init_type)->source, h3); } else if (num == 2) { ASSERT_EQ(p.first, h3); - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); } else { ASSERT_LT(num, 3u); } @@ -120,9 +120,9 @@ TEST(pgtransaction, clone_safe_create_traverse3) if (p.first == h) { ASSERT_TRUE(p.second.is_delete()); } else if (p.first == h2) { - ASSERT_TRUE(boost::get(&p.second.init_type)); + ASSERT_TRUE(std::holds_alternative(p.second.init_type)); ASSERT_EQ( - boost::get(&p.second.init_type)->source, + std::get_if(&p.second.init_type)->source, h3); } ASSERT_LT(num, 2u); -- 2.39.5