From 4a3d4dbfe09478774aab71b96168370c63669d96 Mon Sep 17 00:00:00 2001 From: Jarryd Beck Date: Wed, 11 Jan 2023 17:33:53 +1100 Subject: [PATCH] Fixes #362. Fix comparing iterators from a different container. --- include/cxxopts.hpp | 27 ++++++++++++++++++++++++--- test/options.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 3042826..9548478 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1549,17 +1549,37 @@ class ParseResult Iterator() = default; Iterator(const Iterator&) = default; +// GCC complains about m_iter not being initialised in the member +// initializer list +CXXOPTS_IGNORE_WARNING("-Weffc++") Iterator(const ParseResult *pr, bool end=false) : m_pr(pr) - , m_iter(end? pr->m_defaults.end(): pr->m_sequential.begin()) { + if (end) + { + m_sequential = false; + m_iter = m_pr->m_defaults.end(); + } + else + { + m_sequential = true; + m_iter = m_pr->m_sequential.begin(); + + if (m_iter == m_pr->m_sequential.end()) + { + m_sequential = false; + m_iter = m_pr->m_defaults.begin(); + } + } } +CXXOPTS_DIAGNOSTIC_POP Iterator& operator++() { ++m_iter; - if(m_iter == m_pr->m_sequential.end()) + if(m_sequential && m_iter == m_pr->m_sequential.end()) { + m_sequential = false; m_iter = m_pr->m_defaults.begin(); return *this; } @@ -1575,7 +1595,7 @@ class ParseResult bool operator==(const Iterator& other) const { - return m_iter == other.m_iter; + return (m_sequential == other.m_sequential) && (m_iter == other.m_iter); } bool operator!=(const Iterator& other) const @@ -1596,6 +1616,7 @@ class ParseResult private: const ParseResult* m_pr; std::vector::const_iterator m_iter; + bool m_sequential = true; }; ParseResult() = default; diff --git a/test/options.cpp b/test/options.cpp index a950e02..9b4ae0a 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -1,4 +1,5 @@ #include "catch.hpp" +#include #include @@ -923,6 +924,35 @@ TEST_CASE("Iterator", "[iterator]") { REQUIRE(++iter == result.end()); } +TEST_CASE("Iterator no args", "[iterator]") { + cxxopts::Options options("tester", " - test iterating over parse result"); + + options.add_options() + ("value", "an option with a value", cxxopts::value()) + ("default", "an option with default value", cxxopts::value()->default_value("42")) + ("nothing", "won't exist", cxxopts::value()) + ; + + Argv argv({ + "tester", + }); + + auto** actual_argv = argv.argv(); + auto argc = argv.argc(); + + auto result = options.parse(argc, actual_argv); + + auto iter = result.begin(); + + REQUIRE(iter != result.end()); + CHECK(iter->key() == "default"); + CHECK(iter->value() == "42"); + + ++iter; + CHECK(iter == result.end()); +} + + TEST_CASE("No Options help", "[options]") { std::vector positional;