From 00b689ac0b3900c7c4c325396bafa40439033315 Mon Sep 17 00:00:00 2001 From: Joey Richey Date: Thu, 18 Apr 2024 16:40:29 -0400 Subject: [PATCH 1/4] variables_map: use transparent comparators in c++14 and later --- include/boost/program_options/config.hpp | 10 ++++++++-- include/boost/program_options/variables_map.hpp | 2 +- src/variables_map.cpp | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/boost/program_options/config.hpp b/include/boost/program_options/config.hpp index 8b70521741..38eb38d955 100644 --- a/include/boost/program_options/config.hpp +++ b/include/boost/program_options/config.hpp @@ -14,7 +14,7 @@ #if BOOST_VERSION >= 103100 // works beginning from Boost V1.31.0 /////////////////////////////////////////////////////////////////////////////// -// enable automatic library variant selection +// enable automatic library variant selection #if !defined(BOOST_PROGRAM_OPTIONS_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ !defined(BOOST_PROGRAM_OPTIONS_NO_LIB) @@ -47,6 +47,12 @@ #define BOOST_PROGRAM_OPTIONS_DECL #endif +#ifndef BOOST_PROGRAM_OPTIONS_COMPARATOR +#if BOOST_CXX_VERSION >= 201402L +#define BOOST_PROGRAM_OPTIONS_COMPARATOR std::less<> +#else +#define BOOST_PROGRAM_OPTIONS_COMPARATOR std::less +#endif +#endif #endif // PROGRAM_OPTIONS_CONFIG_HK_2004_01_11 - diff --git a/include/boost/program_options/variables_map.hpp b/include/boost/program_options/variables_map.hpp index 362dedf283..bb87ecef3f 100644 --- a/include/boost/program_options/variables_map.hpp +++ b/include/boost/program_options/variables_map.hpp @@ -144,7 +144,7 @@ namespace boost { namespace program_options { so you can use all map operators to examine its content. */ class BOOST_PROGRAM_OPTIONS_DECL variables_map : public abstract_variables_map, - public std::map + public std::map { public: variables_map(); diff --git a/src/variables_map.cpp b/src/variables_map.cpp index 94ac6148c4..0115da32f2 100644 --- a/src/variables_map.cpp +++ b/src/variables_map.cpp @@ -32,7 +32,7 @@ namespace boost { namespace program_options { // We need to access map's operator[], not the overriden version // variables_map. Ehmm.. messy. - std::map& m = xm; + std::map& m = xm; std::set new_final; @@ -194,7 +194,7 @@ namespace boost { namespace program_options { void variables_map::clear() { - std::map::clear(); + std::map::clear(); m_final.clear(); m_required.clear(); } From cdce0c7910496f20379656ad80a7853212693e0c Mon Sep 17 00:00:00 2001 From: Joey Richey Date: Fri, 19 Apr 2024 09:39:37 -0400 Subject: [PATCH 2/4] use a typedef instead of a macro --- include/boost/program_options/config.hpp | 8 -------- include/boost/program_options/variables_map.hpp | 13 ++++++++++++- src/variables_map.cpp | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/boost/program_options/config.hpp b/include/boost/program_options/config.hpp index 38eb38d955..e5b6d03d40 100644 --- a/include/boost/program_options/config.hpp +++ b/include/boost/program_options/config.hpp @@ -47,12 +47,4 @@ #define BOOST_PROGRAM_OPTIONS_DECL #endif -#ifndef BOOST_PROGRAM_OPTIONS_COMPARATOR -#if BOOST_CXX_VERSION >= 201402L -#define BOOST_PROGRAM_OPTIONS_COMPARATOR std::less<> -#else -#define BOOST_PROGRAM_OPTIONS_COMPARATOR std::less -#endif -#endif - #endif // PROGRAM_OPTIONS_CONFIG_HK_2004_01_11 diff --git a/include/boost/program_options/variables_map.hpp b/include/boost/program_options/variables_map.hpp index bb87ecef3f..9560db1d8b 100644 --- a/include/boost/program_options/variables_map.hpp +++ b/include/boost/program_options/variables_map.hpp @@ -138,13 +138,24 @@ namespace boost { namespace program_options { const abstract_variables_map* m_next; }; + namespace details + { + typedef + #if !defined(BOOST_PROGRAM_OPTIONS_NO_TRANSPARENT_COMPARATOR) && BOOST_CXX_VERSION >= 201402L + std::less<> + #else + std::less + #endif + comparator_t; + } + /** Concrete variables map which store variables in real map. This class is derived from std::map, so you can use all map operators to examine its content. */ class BOOST_PROGRAM_OPTIONS_DECL variables_map : public abstract_variables_map, - public std::map + public std::map { public: variables_map(); diff --git a/src/variables_map.cpp b/src/variables_map.cpp index 0115da32f2..3511ac8b12 100644 --- a/src/variables_map.cpp +++ b/src/variables_map.cpp @@ -32,7 +32,7 @@ namespace boost { namespace program_options { // We need to access map's operator[], not the overriden version // variables_map. Ehmm.. messy. - std::map& m = xm; + std::map& m = xm; std::set new_final; @@ -194,7 +194,7 @@ namespace boost { namespace program_options { void variables_map::clear() { - std::map::clear(); + std::map::clear(); m_final.clear(); m_required.clear(); } From f50424a6eeb4c558bb93e9079f479c509689203e Mon Sep 17 00:00:00 2001 From: Joey Richey Date: Fri, 19 Apr 2024 10:37:40 -0400 Subject: [PATCH 3/4] add unit test --- test/CMakeLists.txt | 1 + test/transparent_comparator_test.cpp | 56 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 test/transparent_comparator_test.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ea8832ec15..70f9b0242a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,5 +23,6 @@ boost_test(TYPE run SOURCES unrecognized_test.cpp) boost_test(TYPE run SOURCES required_test.cpp ARGUMENTS ${CMAKE_CURRENT_SOURCE_DIR}/required_test.cfg) boost_test(TYPE run SOURCES exception_txt_test.cpp) boost_test(TYPE run SOURCES optional_test.cpp) +boost_test(TYPE run SOURCES transparent_comparator_test.cpp) boost_test(TYPE run SOURCES quick.cpp ARGUMENTS --path=initial LINK_LIBRARIES Boost::core) diff --git a/test/transparent_comparator_test.cpp b/test/transparent_comparator_test.cpp new file mode 100644 index 0000000000..b51bd97c26 --- /dev/null +++ b/test/transparent_comparator_test.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW +#include +#endif + +namespace { +// Contrived class that proves no extra copies are being made and only operator< is being used +struct Dummy : private boost::noncopyable +{}; + +bool operator<(const Dummy&, const std::string& rhs) { return "test" < rhs; } +bool operator<(const std::string& lhs, const Dummy&) { return lhs < "test"; } +} + +void test_transparent_comparator() +{ + boost::program_options::variables_map vm; + vm.insert({"test", boost::program_options::variable_value(42, false)}); + + boost::program_options::variables_map::iterator iter; + + // c-string literal. + // If pre c++14, a std::string object will be implicitly created on the call to find() + // after c++14 no extra object will be created + iter = vm.find("test"); + BOOST_REQUIRE(iter != vm.end()); + BOOST_CHECK(boost::any_cast(iter->second.value()) == 42); + + // Rest of the checks require c++14 for a transparent comparator +#ifdef BOOST_CXX_VERSION > 201402L + // boost::string_view + const boost::string_view bsv("test"); + iter = vm.find(bsv); + BOOST_REQUIRE(iter != vm.end()); + BOOST_CHECK(boost::any_cast(iter->second.value()) == 42); + + #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW + // std::string_view + const std::string_view sv("test"); + iter = vm.find(sv); + BOOST_REQUIRE(iter != vm.end()); + BOOST_CHECK(boost::any_cast(iter->second.value()) == 42); + #endif + + // custom class + Dummy d; + iter = vm.find(d); + BOOST_REQUIRE(iter != vm.end()); + BOOST_CHECK(boost::any_cast(iter->second.value()) == 42); +#endif +} From 724151d67f54697d482ea64fc0e0958c82cc2fa6 Mon Sep 17 00:00:00 2001 From: Joey Richey Date: Mon, 1 Jul 2024 13:21:54 -0400 Subject: [PATCH 4/4] few other spots the comparator type is needed for defining the iterator type --- src/variables_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/variables_map.cpp b/src/variables_map.cpp index 3511ac8b12..97d3226728 100644 --- a/src/variables_map.cpp +++ b/src/variables_map.cpp @@ -220,7 +220,7 @@ namespace boost { namespace program_options { { const string& opt = r->first; const string& display_opt = r->second; - map::const_iterator iter = find(opt); + map::const_iterator iter = find(opt); if (iter == end() || iter->second.empty()) { boost::throw_exception(required_option(display_opt)); @@ -229,7 +229,7 @@ namespace boost { namespace program_options { } // Lastly, run notify actions. - for (map::iterator k = begin(); + for (map::iterator k = begin(); k != end(); ++k) {