From 0a4c5164c93a9c1c8ef7a8191fc46ca80f643168 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Jun 2022 17:29:18 -0400 Subject: cmArgumentParser: Offer cm::optional bindings to capture keyword presence Several clients have been using `keywordsMissingValue` or `parsedKeywords` to check for the presence of keywords. Offer them a type-encoded way to explicitly check whether a keyword is present. --- Source/cmArgumentParser.h | 11 ++++++++ Tests/CMakeLib/testArgumentParser.cxx | 49 +++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 2120a27..8be5a9c 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -39,6 +40,16 @@ public: void Bind(std::vector& val); void Bind(std::vector>& val); + // cm::optional<> records the presence the keyword to which it binds. + template + void Bind(cm::optional& optVal) + { + if (!optVal) { + optVal.emplace(); + } + this->Bind(*optVal); + } + void Consume(cm::string_view arg, void* result, std::vector* unparsedArguments, std::vector* keywordsMissingValue, diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 954c96f..52c5861 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -19,29 +20,38 @@ struct Result bool Option2 = false; std::string String1; - std::string String2; + cm::optional String2; + cm::optional String3; std::vector List1; std::vector List2; - std::vector List3; + cm::optional> List3; + cm::optional> List4; + cm::optional> List5; std::vector> Multi1; std::vector> Multi2; - std::vector> Multi3; + cm::optional>> Multi3; + cm::optional>> Multi4; }; std::initializer_list const args = { /* clang-format off */ "OPTION_1", // option + // "OPTION_2", // option that is not present "STRING_1", // string arg missing value - "STRING_2", "foo", "bar", // string arg + unparsed value + "STRING_2", "foo", "bar", // string arg + unparsed value, presence captured + // "STRING_3", // string arg that is not present "LIST_1", // list arg missing values "LIST_2", "foo", "bar", // list arg with 2 elems "LIST_3", "bar", // list arg ... "LIST_3", "foo", // ... with continuation + "LIST_4", // list arg missing values, presence captured + // "LIST_5", // list arg that is not present "MULTI_2", // multi list with 0 lists "MULTI_3", "foo", "bar", // multi list with first list with two elems "MULTI_3", "bar", "foo", // multi list with second list with two elems + // "MULTI_4", // multi list arg that is not present /* clang-format on */ }; @@ -52,7 +62,8 @@ bool verifyResult(Result const& result, static std::vector const foobar = { "foo", "bar" }; static std::vector const barfoo = { "bar", "foo" }; static std::vector const missing = { "STRING_1"_s, - "LIST_1"_s }; + "LIST_1"_s, + "LIST_4"_s }; #define ASSERT_TRUE(x) \ do { \ @@ -66,18 +77,26 @@ bool verifyResult(Result const& result, ASSERT_TRUE(!result.Option2); ASSERT_TRUE(result.String1.empty()); - ASSERT_TRUE(result.String2 == "foo"); + ASSERT_TRUE(result.String2); + ASSERT_TRUE(*result.String2 == "foo"); + ASSERT_TRUE(!result.String3); ASSERT_TRUE(result.List1.empty()); ASSERT_TRUE(result.List2 == foobar); - ASSERT_TRUE(result.List3 == barfoo); + ASSERT_TRUE(result.List3); + ASSERT_TRUE(*result.List3 == barfoo); + ASSERT_TRUE(result.List4); + ASSERT_TRUE(result.List4->empty()); + ASSERT_TRUE(!result.List5); ASSERT_TRUE(result.Multi1.empty()); ASSERT_TRUE(result.Multi2.size() == 1); ASSERT_TRUE(result.Multi2[0].empty()); - ASSERT_TRUE(result.Multi3.size() == 2); - ASSERT_TRUE(result.Multi3[0] == foobar); - ASSERT_TRUE(result.Multi3[1] == barfoo); + ASSERT_TRUE(result.Multi3); + ASSERT_TRUE((*result.Multi3).size() == 2); + ASSERT_TRUE((*result.Multi3)[0] == foobar); + ASSERT_TRUE((*result.Multi3)[1] == barfoo); + ASSERT_TRUE(!result.Multi4); ASSERT_TRUE(unparsedArguments.size() == 1); ASSERT_TRUE(unparsedArguments[0] == "bar"); @@ -97,12 +116,16 @@ bool testArgumentParserDynamic() .Bind("OPTION_2"_s, result.Option2) .Bind("STRING_1"_s, result.String1) .Bind("STRING_2"_s, result.String2) + .Bind("STRING_3"_s, result.String3) .Bind("LIST_1"_s, result.List1) .Bind("LIST_2"_s, result.List2) .Bind("LIST_3"_s, result.List3) + .Bind("LIST_4"_s, result.List4) + .Bind("LIST_5"_s, result.List5) .Bind("MULTI_1"_s, result.Multi1) .Bind("MULTI_2"_s, result.Multi2) .Bind("MULTI_3"_s, result.Multi3) + .Bind("MULTI_4"_s, result.Multi4) .Parse(args, &unparsedArguments, &keywordsMissingValue); return verifyResult(result, unparsedArguments, keywordsMissingValue); @@ -116,12 +139,16 @@ bool testArgumentParserStatic() .Bind("OPTION_2"_s, &Result::Option2) .Bind("STRING_1"_s, &Result::String1) .Bind("STRING_2"_s, &Result::String2) + .Bind("STRING_3"_s, &Result::String3) .Bind("LIST_1"_s, &Result::List1) .Bind("LIST_2"_s, &Result::List2) .Bind("LIST_3"_s, &Result::List3) + .Bind("LIST_4"_s, &Result::List4) + .Bind("LIST_5"_s, &Result::List5) .Bind("MULTI_1"_s, &Result::Multi1) .Bind("MULTI_2"_s, &Result::Multi2) - .Bind("MULTI_3"_s, &Result::Multi3); + .Bind("MULTI_3"_s, &Result::Multi3) + .Bind("MULTI_4"_s, &Result::Multi4); std::vector unparsedArguments; std::vector keywordsMissingValue; -- cgit v0.12