Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:05

0001 
0002 //              Copyright Catch2 Authors
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //   (See accompanying file LICENSE.txt or copy at
0005 //        https://www.boost.org/LICENSE_1_0.txt)
0006 
0007 // SPDX-License-Identifier: BSL-1.0
0008 #ifndef CATCH_CLARA_HPP_INCLUDED
0009 #define CATCH_CLARA_HPP_INCLUDED
0010 
0011 #if defined( __clang__ )
0012 #    pragma clang diagnostic push
0013 #    pragma clang diagnostic ignored "-Wweak-vtables"
0014 #    pragma clang diagnostic ignored "-Wshadow"
0015 #    pragma clang diagnostic ignored "-Wdeprecated"
0016 #endif
0017 
0018 #if defined( __GNUC__ )
0019 #    pragma GCC diagnostic push
0020 #    pragma GCC diagnostic ignored "-Wsign-conversion"
0021 #endif
0022 
0023 #ifndef CLARA_CONFIG_OPTIONAL_TYPE
0024 #    ifdef __has_include
0025 #        if __has_include( <optional>) && __cplusplus >= 201703L
0026 #            include <optional>
0027 #            define CLARA_CONFIG_OPTIONAL_TYPE std::optional
0028 #        endif
0029 #    endif
0030 #endif
0031 
0032 #include <catch2/internal/catch_move_and_forward.hpp>
0033 #include <catch2/internal/catch_noncopyable.hpp>
0034 #include <catch2/internal/catch_void_type.hpp>
0035 
0036 #include <cassert>
0037 #include <memory>
0038 #include <ostream>
0039 #include <sstream>
0040 #include <string>
0041 #include <type_traits>
0042 #include <vector>
0043 
0044 namespace Catch {
0045     namespace Clara {
0046 
0047         class Args;
0048         class Parser;
0049 
0050         // enum of result types from a parse
0051         enum class ParseResultType {
0052             Matched,
0053             NoMatch,
0054             ShortCircuitAll,
0055             ShortCircuitSame
0056         };
0057 
0058         struct accept_many_t {};
0059         constexpr accept_many_t accept_many {};
0060 
0061         namespace Detail {
0062             struct fake_arg {
0063                 template <typename T>
0064                 operator T();
0065             };
0066 
0067             template <typename F, typename = void>
0068             struct is_unary_function : std::false_type {};
0069 
0070             template <typename F>
0071             struct is_unary_function<
0072                 F,
0073                 Catch::Detail::void_t<decltype(
0074                     std::declval<F>()( fake_arg() ) )
0075                 >
0076             > : std::true_type {};
0077 
0078             // Traits for extracting arg and return type of lambdas (for single
0079             // argument lambdas)
0080             template <typename L>
0081             struct UnaryLambdaTraits
0082                 : UnaryLambdaTraits<decltype( &L::operator() )> {};
0083 
0084             template <typename ClassT, typename ReturnT, typename... Args>
0085             struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
0086                 static const bool isValid = false;
0087             };
0088 
0089             template <typename ClassT, typename ReturnT, typename ArgT>
0090             struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
0091                 static const bool isValid = true;
0092                 using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
0093                 using ReturnType = ReturnT;
0094             };
0095 
0096             class TokenStream;
0097 
0098             // Wraps a token coming from a token stream. These may not directly
0099             // correspond to strings as a single string may encode an option +
0100             // its argument if the : or = form is used
0101             enum class TokenType { Option, Argument };
0102             struct Token {
0103                 TokenType type;
0104                 std::string token;
0105             };
0106 
0107             // Abstracts iterators into args as a stream of tokens, with option
0108             // arguments uniformly handled
0109             class TokenStream {
0110                 using Iterator = std::vector<std::string>::const_iterator;
0111                 Iterator it;
0112                 Iterator itEnd;
0113                 std::vector<Token> m_tokenBuffer;
0114 
0115                 void loadBuffer();
0116 
0117             public:
0118                 explicit TokenStream( Args const& args );
0119                 TokenStream( Iterator it, Iterator itEnd );
0120 
0121                 explicit operator bool() const {
0122                     return !m_tokenBuffer.empty() || it != itEnd;
0123                 }
0124 
0125                 size_t count() const {
0126                     return m_tokenBuffer.size() + ( itEnd - it );
0127                 }
0128 
0129                 Token operator*() const {
0130                     assert( !m_tokenBuffer.empty() );
0131                     return m_tokenBuffer.front();
0132                 }
0133 
0134                 Token const* operator->() const {
0135                     assert( !m_tokenBuffer.empty() );
0136                     return &m_tokenBuffer.front();
0137                 }
0138 
0139                 TokenStream& operator++();
0140             };
0141 
0142             //! Denotes type of a parsing result
0143             enum class ResultType {
0144                 Ok,          ///< No errors
0145                 LogicError,  ///< Error in user-specified arguments for
0146                              ///< construction
0147                 RuntimeError ///< Error in parsing inputs
0148             };
0149 
0150             class ResultBase {
0151             protected:
0152                 ResultBase( ResultType type ): m_type( type ) {}
0153                 virtual ~ResultBase(); // = default;
0154 
0155 
0156                 ResultBase(ResultBase const&) = default;
0157                 ResultBase& operator=(ResultBase const&) = default;
0158                 ResultBase(ResultBase&&) = default;
0159                 ResultBase& operator=(ResultBase&&) = default;
0160 
0161                 virtual void enforceOk() const = 0;
0162 
0163                 ResultType m_type;
0164             };
0165 
0166             template <typename T> class ResultValueBase : public ResultBase {
0167             public:
0168                 auto value() const -> T const& {
0169                     enforceOk();
0170                     return m_value;
0171                 }
0172 
0173             protected:
0174                 ResultValueBase( ResultType type ): ResultBase( type ) {}
0175 
0176                 ResultValueBase( ResultValueBase const& other ):
0177                     ResultBase( other ) {
0178                     if ( m_type == ResultType::Ok )
0179                         new ( &m_value ) T( other.m_value );
0180                 }
0181 
0182                 ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) {
0183                     new ( &m_value ) T( value );
0184                 }
0185 
0186                 auto operator=( ResultValueBase const& other )
0187                     -> ResultValueBase& {
0188                     if ( m_type == ResultType::Ok )
0189                         m_value.~T();
0190                     ResultBase::operator=( other );
0191                     if ( m_type == ResultType::Ok )
0192                         new ( &m_value ) T( other.m_value );
0193                     return *this;
0194                 }
0195 
0196                 ~ResultValueBase() override {
0197                     if ( m_type == ResultType::Ok )
0198                         m_value.~T();
0199                 }
0200 
0201                 union {
0202                     T m_value;
0203                 };
0204             };
0205 
0206             template <> class ResultValueBase<void> : public ResultBase {
0207             protected:
0208                 using ResultBase::ResultBase;
0209             };
0210 
0211             template <typename T = void>
0212             class BasicResult : public ResultValueBase<T> {
0213             public:
0214                 template <typename U>
0215                 explicit BasicResult( BasicResult<U> const& other ):
0216                     ResultValueBase<T>( other.type() ),
0217                     m_errorMessage( other.errorMessage() ) {
0218                     assert( type() != ResultType::Ok );
0219                 }
0220 
0221                 template <typename U>
0222                 static auto ok( U const& value ) -> BasicResult {
0223                     return { ResultType::Ok, value };
0224                 }
0225                 static auto ok() -> BasicResult { return { ResultType::Ok }; }
0226                 static auto logicError( std::string&& message )
0227                     -> BasicResult {
0228                     return { ResultType::LogicError, CATCH_MOVE(message) };
0229                 }
0230                 static auto runtimeError( std::string&& message )
0231                     -> BasicResult {
0232                     return { ResultType::RuntimeError, CATCH_MOVE(message) };
0233                 }
0234 
0235                 explicit operator bool() const {
0236                     return m_type == ResultType::Ok;
0237                 }
0238                 auto type() const -> ResultType { return m_type; }
0239                 auto errorMessage() const -> std::string const& {
0240                     return m_errorMessage;
0241                 }
0242 
0243             protected:
0244                 void enforceOk() const override {
0245 
0246                     // Errors shouldn't reach this point, but if they do
0247                     // the actual error message will be in m_errorMessage
0248                     assert( m_type != ResultType::LogicError );
0249                     assert( m_type != ResultType::RuntimeError );
0250                     if ( m_type != ResultType::Ok )
0251                         std::abort();
0252                 }
0253 
0254                 std::string
0255                     m_errorMessage; // Only populated if resultType is an error
0256 
0257                 BasicResult( ResultType type,
0258                              std::string&& message ):
0259                     ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
0260                     assert( m_type != ResultType::Ok );
0261                 }
0262 
0263                 using ResultValueBase<T>::ResultValueBase;
0264                 using ResultBase::m_type;
0265             };
0266 
0267             class ParseState {
0268             public:
0269                 ParseState( ParseResultType type,
0270                             TokenStream const& remainingTokens );
0271 
0272                 ParseResultType type() const { return m_type; }
0273                 TokenStream const& remainingTokens() const {
0274                     return m_remainingTokens;
0275                 }
0276 
0277             private:
0278                 ParseResultType m_type;
0279                 TokenStream m_remainingTokens;
0280             };
0281 
0282             using Result = BasicResult<void>;
0283             using ParserResult = BasicResult<ParseResultType>;
0284             using InternalParseResult = BasicResult<ParseState>;
0285 
0286             struct HelpColumns {
0287                 std::string left;
0288                 std::string right;
0289             };
0290 
0291             template <typename T>
0292             ParserResult convertInto( std::string const& source, T& target ) {
0293                 std::stringstream ss( source );
0294                 ss >> target;
0295                 if ( ss.fail() ) {
0296                     return ParserResult::runtimeError(
0297                         "Unable to convert '" + source +
0298                         "' to destination type" );
0299                 } else {
0300                     return ParserResult::ok( ParseResultType::Matched );
0301                 }
0302             }
0303             ParserResult convertInto( std::string const& source,
0304                                       std::string& target );
0305             ParserResult convertInto( std::string const& source, bool& target );
0306 
0307 #ifdef CLARA_CONFIG_OPTIONAL_TYPE
0308             template <typename T>
0309             auto convertInto( std::string const& source,
0310                               CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
0311                 -> ParserResult {
0312                 T temp;
0313                 auto result = convertInto( source, temp );
0314                 if ( result )
0315                     target = CATCH_MOVE( temp );
0316                 return result;
0317             }
0318 #endif // CLARA_CONFIG_OPTIONAL_TYPE
0319 
0320             struct BoundRef : Catch::Detail::NonCopyable {
0321                 virtual ~BoundRef() = default;
0322                 virtual bool isContainer() const;
0323                 virtual bool isFlag() const;
0324             };
0325             struct BoundValueRefBase : BoundRef {
0326                 virtual auto setValue( std::string const& arg )
0327                     -> ParserResult = 0;
0328             };
0329             struct BoundFlagRefBase : BoundRef {
0330                 virtual auto setFlag( bool flag ) -> ParserResult = 0;
0331                 bool isFlag() const override;
0332             };
0333 
0334             template <typename T> struct BoundValueRef : BoundValueRefBase {
0335                 T& m_ref;
0336 
0337                 explicit BoundValueRef( T& ref ): m_ref( ref ) {}
0338 
0339                 ParserResult setValue( std::string const& arg ) override {
0340                     return convertInto( arg, m_ref );
0341                 }
0342             };
0343 
0344             template <typename T>
0345             struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
0346                 std::vector<T>& m_ref;
0347 
0348                 explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
0349 
0350                 auto isContainer() const -> bool override { return true; }
0351 
0352                 auto setValue( std::string const& arg )
0353                     -> ParserResult override {
0354                     T temp;
0355                     auto result = convertInto( arg, temp );
0356                     if ( result )
0357                         m_ref.push_back( temp );
0358                     return result;
0359                 }
0360             };
0361 
0362             struct BoundFlagRef : BoundFlagRefBase {
0363                 bool& m_ref;
0364 
0365                 explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
0366 
0367                 ParserResult setFlag( bool flag ) override;
0368             };
0369 
0370             template <typename ReturnType> struct LambdaInvoker {
0371                 static_assert(
0372                     std::is_same<ReturnType, ParserResult>::value,
0373                     "Lambda must return void or clara::ParserResult" );
0374 
0375                 template <typename L, typename ArgType>
0376                 static auto invoke( L const& lambda, ArgType const& arg )
0377                     -> ParserResult {
0378                     return lambda( arg );
0379                 }
0380             };
0381 
0382             template <> struct LambdaInvoker<void> {
0383                 template <typename L, typename ArgType>
0384                 static auto invoke( L const& lambda, ArgType const& arg )
0385                     -> ParserResult {
0386                     lambda( arg );
0387                     return ParserResult::ok( ParseResultType::Matched );
0388                 }
0389             };
0390 
0391             template <typename ArgType, typename L>
0392             auto invokeLambda( L const& lambda, std::string const& arg )
0393                 -> ParserResult {
0394                 ArgType temp{};
0395                 auto result = convertInto( arg, temp );
0396                 return !result ? result
0397                                : LambdaInvoker<typename UnaryLambdaTraits<
0398                                      L>::ReturnType>::invoke( lambda, temp );
0399             }
0400 
0401             template <typename L> struct BoundLambda : BoundValueRefBase {
0402                 L m_lambda;
0403 
0404                 static_assert(
0405                     UnaryLambdaTraits<L>::isValid,
0406                     "Supplied lambda must take exactly one argument" );
0407                 explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
0408 
0409                 auto setValue( std::string const& arg )
0410                     -> ParserResult override {
0411                     return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
0412                         m_lambda, arg );
0413                 }
0414             };
0415 
0416             template <typename L> struct BoundManyLambda : BoundLambda<L> {
0417                 explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
0418                 bool isContainer() const override { return true; }
0419             };
0420 
0421             template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
0422                 L m_lambda;
0423 
0424                 static_assert(
0425                     UnaryLambdaTraits<L>::isValid,
0426                     "Supplied lambda must take exactly one argument" );
0427                 static_assert(
0428                     std::is_same<typename UnaryLambdaTraits<L>::ArgType,
0429                                  bool>::value,
0430                     "flags must be boolean" );
0431 
0432                 explicit BoundFlagLambda( L const& lambda ):
0433                     m_lambda( lambda ) {}
0434 
0435                 auto setFlag( bool flag ) -> ParserResult override {
0436                     return LambdaInvoker<typename UnaryLambdaTraits<
0437                         L>::ReturnType>::invoke( m_lambda, flag );
0438                 }
0439             };
0440 
0441             enum class Optionality { Optional, Required };
0442 
0443             class ParserBase {
0444             public:
0445                 virtual ~ParserBase() = default;
0446                 virtual auto validate() const -> Result { return Result::ok(); }
0447                 virtual auto parse( std::string const& exeName,
0448                                     TokenStream const& tokens ) const
0449                     -> InternalParseResult = 0;
0450                 virtual size_t cardinality() const;
0451 
0452                 InternalParseResult parse( Args const& args ) const;
0453             };
0454 
0455             template <typename DerivedT>
0456             class ComposableParserImpl : public ParserBase {
0457             public:
0458                 template <typename T>
0459                 auto operator|( T const& other ) const -> Parser;
0460             };
0461 
0462             // Common code and state for Args and Opts
0463             template <typename DerivedT>
0464             class ParserRefImpl : public ComposableParserImpl<DerivedT> {
0465             protected:
0466                 Optionality m_optionality = Optionality::Optional;
0467                 std::shared_ptr<BoundRef> m_ref;
0468                 std::string m_hint;
0469                 std::string m_description;
0470 
0471                 explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
0472                     m_ref( ref ) {}
0473 
0474             public:
0475                 template <typename LambdaT>
0476                 ParserRefImpl( accept_many_t,
0477                                LambdaT const& ref,
0478                                std::string const& hint ):
0479                     m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
0480                     m_hint( hint ) {}
0481 
0482                 template <typename T,
0483                           typename = typename std::enable_if_t<
0484                               !Detail::is_unary_function<T>::value>>
0485                 ParserRefImpl( T& ref, std::string const& hint ):
0486                     m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
0487                     m_hint( hint ) {}
0488 
0489                 template <typename LambdaT,
0490                           typename = typename std::enable_if_t<
0491                               Detail::is_unary_function<LambdaT>::value>>
0492                 ParserRefImpl( LambdaT const& ref, std::string const& hint ):
0493                     m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
0494                     m_hint( hint ) {}
0495 
0496                 auto operator()( std::string const& description ) -> DerivedT& {
0497                     m_description = description;
0498                     return static_cast<DerivedT&>( *this );
0499                 }
0500 
0501                 auto optional() -> DerivedT& {
0502                     m_optionality = Optionality::Optional;
0503                     return static_cast<DerivedT&>( *this );
0504                 }
0505 
0506                 auto required() -> DerivedT& {
0507                     m_optionality = Optionality::Required;
0508                     return static_cast<DerivedT&>( *this );
0509                 }
0510 
0511                 auto isOptional() const -> bool {
0512                     return m_optionality == Optionality::Optional;
0513                 }
0514 
0515                 auto cardinality() const -> size_t override {
0516                     if ( m_ref->isContainer() )
0517                         return 0;
0518                     else
0519                         return 1;
0520                 }
0521 
0522                 std::string const& hint() const { return m_hint; }
0523             };
0524 
0525         } // namespace detail
0526 
0527 
0528         // A parser for arguments
0529         class Arg : public Detail::ParserRefImpl<Arg> {
0530         public:
0531             using ParserRefImpl::ParserRefImpl;
0532             using ParserBase::parse;
0533 
0534             Detail::InternalParseResult
0535                 parse(std::string const&,
0536                       Detail::TokenStream const& tokens) const override;
0537         };
0538 
0539         // A parser for options
0540         class Opt : public Detail::ParserRefImpl<Opt> {
0541         protected:
0542             std::vector<std::string> m_optNames;
0543 
0544         public:
0545             template <typename LambdaT>
0546             explicit Opt(LambdaT const& ref) :
0547                 ParserRefImpl(
0548                     std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
0549 
0550             explicit Opt(bool& ref);
0551 
0552             template <typename LambdaT,
0553                       typename = typename std::enable_if_t<
0554                           Detail::is_unary_function<LambdaT>::value>>
0555             Opt( LambdaT const& ref, std::string const& hint ):
0556                 ParserRefImpl( ref, hint ) {}
0557 
0558             template <typename LambdaT>
0559             Opt( accept_many_t, LambdaT const& ref, std::string const& hint ):
0560                 ParserRefImpl( accept_many, ref, hint ) {}
0561 
0562             template <typename T,
0563                       typename = typename std::enable_if_t<
0564                           !Detail::is_unary_function<T>::value>>
0565             Opt( T& ref, std::string const& hint ):
0566                 ParserRefImpl( ref, hint ) {}
0567 
0568             auto operator[](std::string const& optName) -> Opt& {
0569                 m_optNames.push_back(optName);
0570                 return *this;
0571             }
0572 
0573             std::vector<Detail::HelpColumns> getHelpColumns() const;
0574 
0575             bool isMatch(std::string const& optToken) const;
0576 
0577             using ParserBase::parse;
0578 
0579             Detail::InternalParseResult
0580                 parse(std::string const&,
0581                       Detail::TokenStream const& tokens) const override;
0582 
0583             Detail::Result validate() const override;
0584         };
0585 
0586         // Specifies the name of the executable
0587         class ExeName : public Detail::ComposableParserImpl<ExeName> {
0588             std::shared_ptr<std::string> m_name;
0589             std::shared_ptr<Detail::BoundValueRefBase> m_ref;
0590 
0591         public:
0592             ExeName();
0593             explicit ExeName(std::string& ref);
0594 
0595             template <typename LambdaT>
0596             explicit ExeName(LambdaT const& lambda) : ExeName() {
0597                 m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
0598             }
0599 
0600             // The exe name is not parsed out of the normal tokens, but is
0601             // handled specially
0602             Detail::InternalParseResult
0603                 parse(std::string const&,
0604                       Detail::TokenStream const& tokens) const override;
0605 
0606             std::string const& name() const { return *m_name; }
0607             Detail::ParserResult set(std::string const& newName);
0608         };
0609 
0610 
0611         // A Combined parser
0612         class Parser : Detail::ParserBase {
0613             mutable ExeName m_exeName;
0614             std::vector<Opt> m_options;
0615             std::vector<Arg> m_args;
0616 
0617         public:
0618 
0619             auto operator|=(ExeName const& exeName) -> Parser& {
0620                 m_exeName = exeName;
0621                 return *this;
0622             }
0623 
0624             auto operator|=(Arg const& arg) -> Parser& {
0625                 m_args.push_back(arg);
0626                 return *this;
0627             }
0628 
0629             auto operator|=(Opt const& opt) -> Parser& {
0630                 m_options.push_back(opt);
0631                 return *this;
0632             }
0633 
0634             Parser& operator|=(Parser const& other);
0635 
0636             template <typename T>
0637             auto operator|(T const& other) const -> Parser {
0638                 return Parser(*this) |= other;
0639             }
0640 
0641             std::vector<Detail::HelpColumns> getHelpColumns() const;
0642 
0643             void writeToStream(std::ostream& os) const;
0644 
0645             friend auto operator<<(std::ostream& os, Parser const& parser)
0646                 -> std::ostream& {
0647                 parser.writeToStream(os);
0648                 return os;
0649             }
0650 
0651             Detail::Result validate() const override;
0652 
0653             using ParserBase::parse;
0654             Detail::InternalParseResult
0655                 parse(std::string const& exeName,
0656                       Detail::TokenStream const& tokens) const override;
0657         };
0658 
0659         // Transport for raw args (copied from main args, or supplied via
0660         // init list for testing)
0661         class Args {
0662             friend Detail::TokenStream;
0663             std::string m_exeName;
0664             std::vector<std::string> m_args;
0665 
0666         public:
0667             Args(int argc, char const* const* argv);
0668             Args(std::initializer_list<std::string> args);
0669 
0670             std::string const& exeName() const { return m_exeName; }
0671         };
0672 
0673 
0674         // Convenience wrapper for option parser that specifies the help option
0675         struct Help : Opt {
0676             Help(bool& showHelpFlag);
0677         };
0678 
0679         // Result type for parser operation
0680         using Detail::ParserResult;
0681 
0682         namespace Detail {
0683             template <typename DerivedT>
0684             template <typename T>
0685             Parser
0686                 ComposableParserImpl<DerivedT>::operator|(T const& other) const {
0687                 return Parser() | static_cast<DerivedT const&>(*this) | other;
0688             }
0689         }
0690 
0691     } // namespace Clara
0692 } // namespace Catch
0693 
0694 #if defined( __clang__ )
0695 #    pragma clang diagnostic pop
0696 #endif
0697 
0698 #if defined( __GNUC__ )
0699 #    pragma GCC diagnostic pop
0700 #endif
0701 
0702 #endif // CATCH_CLARA_HPP_INCLUDED