| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 | // Copyright 2017 Two Blue Cubes Ltd. All rights reserved.//// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// See https://github.com/philsquared/Clara for more details// Clara v1.1.5#ifndef CATCH_CLARA_HPP_INCLUDED#define CATCH_CLARA_HPP_INCLUDED#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80#endif#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH#endif#ifndef CLARA_CONFIG_OPTIONAL_TYPE#ifdef __has_include#if __has_include(<optional>) && __cplusplus >= 201703L#include <optional>#define CLARA_CONFIG_OPTIONAL_TYPE std::optional#endif#endif#endif// ----------- #included from clara_textflow.hpp -----------// TextFlowCpp//// A single-header library for wrapping and laying out basic text, by Phil Nash//// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// This project is hosted at https://github.com/philsquared/textflowcpp#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED#include <cassert>#include <ostream>#include <sstream>#include <vector>#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80#endifnamespace Catch {namespace clara {namespace TextFlow {inline auto isWhitespace(char c) -> bool {	static std::string chars = " \t\n\r";	return chars.find(c) != std::string::npos;}inline auto isBreakableBefore(char c) -> bool {	static std::string chars = "[({<|";	return chars.find(c) != std::string::npos;}inline auto isBreakableAfter(char c) -> bool {	static std::string chars = "])}>.,:;*+-=&/\\";	return chars.find(c) != std::string::npos;}class Columns;class Column {	std::vector<std::string> m_strings;	size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;	size_t m_indent = 0;	size_t m_initialIndent = std::string::npos;public:	class iterator {		friend Column;		Column const& m_column;		size_t m_stringIndex = 0;		size_t m_pos = 0;		size_t m_len = 0;		size_t m_end = 0;		bool m_suffix = false;		iterator(Column const& column, size_t stringIndex)			: m_column(column),			m_stringIndex(stringIndex) {}		auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }		auto isBoundary(size_t at) const -> bool {			assert(at > 0);			assert(at <= line().size());			return at == line().size() ||				(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||				isBreakableBefore(line()[at]) ||				isBreakableAfter(line()[at - 1]);		}		void calcLength() {			assert(m_stringIndex < m_column.m_strings.size());			m_suffix = false;			auto width = m_column.m_width - indent();			m_end = m_pos;			if (line()[m_pos] == '\n') {				++m_end;			}			while (m_end < line().size() && line()[m_end] != '\n')				++m_end;			if (m_end < m_pos + width) {				m_len = m_end - m_pos;			} else {				size_t len = width;				while (len > 0 && !isBoundary(m_pos + len))					--len;				while (len > 0 && isWhitespace(line()[m_pos + len - 1]))					--len;				if (len > 0) {					m_len = len;				} else {					m_suffix = true;					m_len = width - 1;				}			}		}		auto indent() const -> size_t {			auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;			return initial == std::string::npos ? m_column.m_indent : initial;		}		auto addIndentAndSuffix(std::string const &plain) const -> std::string {			return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);		}	public:		using difference_type = std::ptrdiff_t;		using value_type = std::string;		using pointer = value_type * ;		using reference = value_type & ;		using iterator_category = std::forward_iterator_tag;		explicit iterator(Column const& column) : m_column(column) {			assert(m_column.m_width > m_column.m_indent);			assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);			calcLength();			if (m_len == 0)				m_stringIndex++; // Empty string		}		auto operator *() const -> std::string {			assert(m_stringIndex < m_column.m_strings.size());			assert(m_pos <= m_end);			return addIndentAndSuffix(line().substr(m_pos, m_len));		}		auto operator ++() -> iterator& {			m_pos += m_len;			if (m_pos < line().size() && line()[m_pos] == '\n')				m_pos += 1;			else				while (m_pos < line().size() && isWhitespace(line()[m_pos]))					++m_pos;			if (m_pos == line().size()) {				m_pos = 0;				++m_stringIndex;			}			if (m_stringIndex < m_column.m_strings.size())				calcLength();			return *this;		}		auto operator ++(int) -> iterator {			iterator prev(*this);			operator++();			return prev;		}		auto operator ==(iterator const& other) const -> bool {			return				m_pos == other.m_pos &&				m_stringIndex == other.m_stringIndex &&				&m_column == &other.m_column;		}		auto operator !=(iterator const& other) const -> bool {			return !operator==(other);		}	};	using const_iterator = iterator;	explicit Column(std::string const& text) { m_strings.push_back(text); }	auto width(size_t newWidth) -> Column& {		assert(newWidth > 0);		m_width = newWidth;		return *this;	}	auto indent(size_t newIndent) -> Column& {		m_indent = newIndent;		return *this;	}	auto initialIndent(size_t newIndent) -> Column& {		m_initialIndent = newIndent;		return *this;	}	auto width() const -> size_t { return m_width; }	auto begin() const -> iterator { return iterator(*this); }	auto end() const -> iterator { return { *this, m_strings.size() }; }	inline friend std::ostream& operator << (std::ostream& os, Column const& col) {		bool first = true;		for (auto line : col) {			if (first)				first = false;			else				os << "\n";			os << line;		}		return os;	}	auto operator + (Column const& other)->Columns;	auto toString() const -> std::string {		std::ostringstream oss;		oss << *this;		return oss.str();	}};class Spacer : public Column {public:	explicit Spacer(size_t spaceWidth) : Column("") {		width(spaceWidth);	}};class Columns {	std::vector<Column> m_columns;public:	class iterator {		friend Columns;		struct EndTag {};		std::vector<Column> const& m_columns;		std::vector<Column::iterator> m_iterators;		size_t m_activeIterators;		iterator(Columns const& columns, EndTag)			: m_columns(columns.m_columns),			m_activeIterators(0) {			m_iterators.reserve(m_columns.size());			for (auto const& col : m_columns)				m_iterators.push_back(col.end());		}	public:		using difference_type = std::ptrdiff_t;		using value_type = std::string;		using pointer = value_type * ;		using reference = value_type & ;		using iterator_category = std::forward_iterator_tag;		explicit iterator(Columns const& columns)			: m_columns(columns.m_columns),			m_activeIterators(m_columns.size()) {			m_iterators.reserve(m_columns.size());			for (auto const& col : m_columns)				m_iterators.push_back(col.begin());		}		auto operator ==(iterator const& other) const -> bool {			return m_iterators == other.m_iterators;		}		auto operator !=(iterator const& other) const -> bool {			return m_iterators != other.m_iterators;		}		auto operator *() const -> std::string {			std::string row, padding;			for (size_t i = 0; i < m_columns.size(); ++i) {				auto width = m_columns[i].width();				if (m_iterators[i] != m_columns[i].end()) {					std::string col = *m_iterators[i];					row += padding + col;					if (col.size() < width)						padding = std::string(width - col.size(), ' ');					else						padding = "";				} else {					padding += std::string(width, ' ');				}			}			return row;		}		auto operator ++() -> iterator& {			for (size_t i = 0; i < m_columns.size(); ++i) {				if (m_iterators[i] != m_columns[i].end())					++m_iterators[i];			}			return *this;		}		auto operator ++(int) -> iterator {			iterator prev(*this);			operator++();			return prev;		}	};	using const_iterator = iterator;	auto begin() const -> iterator { return iterator(*this); }	auto end() const -> iterator { return { *this, iterator::EndTag() }; }	auto operator += (Column const& col) -> Columns& {		m_columns.push_back(col);		return *this;	}	auto operator + (Column const& col) -> Columns {		Columns combined = *this;		combined += col;		return combined;	}	inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {		bool first = true;		for (auto line : cols) {			if (first)				first = false;			else				os << "\n";			os << line;		}		return os;	}	auto toString() const -> std::string {		std::ostringstream oss;		oss << *this;		return oss.str();	}};inline auto Column::operator + (Column const& other) -> Columns {	Columns cols;	cols += *this;	cols += other;	return cols;}}}}#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED// ----------- end of #include from clara_textflow.hpp -----------// ........... back in clara.hpp#include <cctype>#include <string>#include <memory>#include <set>#include <algorithm>#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )#define CATCH_PLATFORM_WINDOWS#endifnamespace Catch { namespace clara {namespace detail {    // Traits for extracting arg and return type of lambdas (for single argument lambdas)    template<typename L>    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};    template<typename ClassT, typename ReturnT, typename... Args>    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {        static const bool isValid = false;    };    template<typename ClassT, typename ReturnT, typename ArgT>    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {        static const bool isValid = true;        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;        using ReturnType = ReturnT;    };    class TokenStream;    // Transport for raw args (copied from main args, or supplied via init list for testing)    class Args {        friend TokenStream;        std::string m_exeName;        std::vector<std::string> m_args;    public:        Args( int argc, char const* const* argv )            : m_exeName(argv[0]),              m_args(argv + 1, argv + argc) {}        Args( std::initializer_list<std::string> args )        :   m_exeName( *args.begin() ),            m_args( args.begin()+1, args.end() )        {}        auto exeName() const -> std::string {            return m_exeName;        }    };    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string    // may encode an option + its argument if the : or = form is used    enum class TokenType {        Option, Argument    };    struct Token {        TokenType type;        std::string token;    };    inline auto isOptPrefix( char c ) -> bool {        return c == '-'#ifdef CATCH_PLATFORM_WINDOWS            || c == '/'#endif        ;    }    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled    class TokenStream {        using Iterator = std::vector<std::string>::const_iterator;        Iterator it;        Iterator itEnd;        std::vector<Token> m_tokenBuffer;        void loadBuffer() {            m_tokenBuffer.resize( 0 );            // Skip any empty strings            while( it != itEnd && it->empty() )                ++it;            if( it != itEnd ) {                auto const &next = *it;                if( isOptPrefix( next[0] ) ) {                    auto delimiterPos = next.find_first_of( " :=" );                    if( delimiterPos != std::string::npos ) {                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );                    } else {                        if( next[1] != '-' && next.size() > 2 ) {                            std::string opt = "- ";                            for( size_t i = 1; i < next.size(); ++i ) {                                opt[1] = next[i];                                m_tokenBuffer.push_back( { TokenType::Option, opt } );                            }                        } else {                            m_tokenBuffer.push_back( { TokenType::Option, next } );                        }                    }                } else {                    m_tokenBuffer.push_back( { TokenType::Argument, next } );                }            }        }    public:        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {            loadBuffer();        }        explicit operator bool() const {            return !m_tokenBuffer.empty() || it != itEnd;        }        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }        auto operator*() const -> Token {            assert( !m_tokenBuffer.empty() );            return m_tokenBuffer.front();        }        auto operator->() const -> Token const * {            assert( !m_tokenBuffer.empty() );            return &m_tokenBuffer.front();        }        auto operator++() -> TokenStream & {            if( m_tokenBuffer.size() >= 2 ) {                m_tokenBuffer.erase( m_tokenBuffer.begin() );            } else {                if( it != itEnd )                    ++it;                loadBuffer();            }            return *this;        }    };    class ResultBase {    public:        enum Type {            Ok, LogicError, RuntimeError        };    protected:        ResultBase( Type type ) : m_type( type ) {}        virtual ~ResultBase() = default;        virtual void enforceOk() const = 0;        Type m_type;    };    template<typename T>    class ResultValueBase : public ResultBase {    public:        auto value() const -> T const & {            enforceOk();            return m_value;        }    protected:        ResultValueBase( Type type ) : ResultBase( type ) {}        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {            if( m_type == ResultBase::Ok )                new( &m_value ) T( other.m_value );        }        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {            new( &m_value ) T( value );        }        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {            if( m_type == ResultBase::Ok )                m_value.~T();            ResultBase::operator=(other);            if( m_type == ResultBase::Ok )                new( &m_value ) T( other.m_value );            return *this;        }        ~ResultValueBase() override {            if( m_type == Ok )                m_value.~T();        }        union {            T m_value;        };    };    template<>    class ResultValueBase<void> : public ResultBase {    protected:        using ResultBase::ResultBase;    };    template<typename T = void>    class BasicResult : public ResultValueBase<T> {    public:        template<typename U>        explicit BasicResult( BasicResult<U> const &other )        :   ResultValueBase<T>( other.type() ),            m_errorMessage( other.errorMessage() )        {            assert( type() != ResultBase::Ok );        }        template<typename U>        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }        static auto ok() -> BasicResult { return { ResultBase::Ok }; }        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }        explicit operator bool() const { return m_type == ResultBase::Ok; }        auto type() const -> ResultBase::Type { return m_type; }        auto errorMessage() const -> std::string { return m_errorMessage; }    protected:        void enforceOk() const override {            // Errors shouldn't reach this point, but if they do            // the actual error message will be in m_errorMessage            assert( m_type != ResultBase::LogicError );            assert( m_type != ResultBase::RuntimeError );            if( m_type != ResultBase::Ok )                std::abort();        }        std::string m_errorMessage; // Only populated if resultType is an error        BasicResult( ResultBase::Type type, std::string const &message )        :   ResultValueBase<T>(type),            m_errorMessage(message)        {            assert( m_type != ResultBase::Ok );        }        using ResultValueBase<T>::ResultValueBase;        using ResultBase::m_type;    };    enum class ParseResultType {        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame    };    class ParseState {    public:        ParseState( ParseResultType type, TokenStream const &remainingTokens )        : m_type(type),          m_remainingTokens( remainingTokens )        {}        auto type() const -> ParseResultType { return m_type; }        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }    private:        ParseResultType m_type;        TokenStream m_remainingTokens;    };    using Result = BasicResult<void>;    using ParserResult = BasicResult<ParseResultType>;    using InternalParseResult = BasicResult<ParseState>;    struct HelpColumns {        std::string left;        std::string right;    };    template<typename T>    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {        std::stringstream ss;        ss << source;        ss >> target;        if( ss.fail() )            return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );        else            return ParserResult::ok( ParseResultType::Matched );    }    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {        target = source;        return ParserResult::ok( ParseResultType::Matched );    }    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {        std::string srcLC = source;        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );        if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")            target = true;        else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")            target = false;        else            return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );        return ParserResult::ok( ParseResultType::Matched );    }#ifdef CLARA_CONFIG_OPTIONAL_TYPE    template<typename T>    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {        T temp;        auto result = convertInto( source, temp );        if( result )            target = std::move(temp);        return result;    }#endif // CLARA_CONFIG_OPTIONAL_TYPE    struct NonCopyable {        NonCopyable() = default;        NonCopyable( NonCopyable const & ) = delete;        NonCopyable( NonCopyable && ) = delete;        NonCopyable &operator=( NonCopyable const & ) = delete;        NonCopyable &operator=( NonCopyable && ) = delete;    };    struct BoundRef : NonCopyable {        virtual ~BoundRef() = default;        virtual auto isContainer() const -> bool { return false; }        virtual auto isFlag() const -> bool { return false; }    };    struct BoundValueRefBase : BoundRef {        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;    };    struct BoundFlagRefBase : BoundRef {        virtual auto setFlag( bool flag ) -> ParserResult = 0;        virtual auto isFlag() const -> bool { return true; }    };    template<typename T>    struct BoundValueRef : BoundValueRefBase {        T &m_ref;        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}        auto setValue( std::string const &arg ) -> ParserResult override {            return convertInto( arg, m_ref );        }    };    template<typename T>    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {        std::vector<T> &m_ref;        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}        auto isContainer() const -> bool override { return true; }        auto setValue( std::string const &arg ) -> ParserResult override {            T temp;            auto result = convertInto( arg, temp );            if( result )                m_ref.push_back( temp );            return result;        }    };    struct BoundFlagRef : BoundFlagRefBase {        bool &m_ref;        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}        auto setFlag( bool flag ) -> ParserResult override {            m_ref = flag;            return ParserResult::ok( ParseResultType::Matched );        }    };    template<typename ReturnType>    struct LambdaInvoker {        static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );        template<typename L, typename ArgType>        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {            return lambda( arg );        }    };    template<>    struct LambdaInvoker<void> {        template<typename L, typename ArgType>        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {            lambda( arg );            return ParserResult::ok( ParseResultType::Matched );        }    };    template<typename ArgType, typename L>    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {        ArgType temp{};        auto result = convertInto( arg, temp );        return !result           ? result           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );    }    template<typename L>    struct BoundLambda : BoundValueRefBase {        L m_lambda;        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}        auto setValue( std::string const &arg ) -> ParserResult override {            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );        }    };    template<typename L>    struct BoundFlagLambda : BoundFlagRefBase {        L m_lambda;        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}        auto setFlag( bool flag ) -> ParserResult override {            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );        }    };    enum class Optionality { Optional, Required };    struct Parser;    class ParserBase {    public:        virtual ~ParserBase() = default;        virtual auto validate() const -> Result { return Result::ok(); }        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;        virtual auto cardinality() const -> size_t { return 1; }        auto parse( Args const &args ) const -> InternalParseResult {            return parse( args.exeName(), TokenStream( args ) );        }    };    template<typename DerivedT>    class ComposableParserImpl : public ParserBase {    public:        template<typename T>        auto operator|( T const &other ) const -> Parser;		template<typename T>        auto operator+( T const &other ) const -> Parser;    };    // Common code and state for Args and Opts    template<typename DerivedT>    class ParserRefImpl : public ComposableParserImpl<DerivedT> {    protected:        Optionality m_optionality = Optionality::Optional;        std::shared_ptr<BoundRef> m_ref;        std::string m_hint;        std::string m_description;        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}    public:        template<typename T>        ParserRefImpl( T &ref, std::string const &hint )        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),            m_hint( hint )        {}        template<typename LambdaT>        ParserRefImpl( LambdaT const &ref, std::string const &hint )        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),            m_hint(hint)        {}        auto operator()( std::string const &description ) -> DerivedT & {            m_description = description;            return static_cast<DerivedT &>( *this );        }        auto optional() -> DerivedT & {            m_optionality = Optionality::Optional;            return static_cast<DerivedT &>( *this );        };        auto required() -> DerivedT & {            m_optionality = Optionality::Required;            return static_cast<DerivedT &>( *this );        };        auto isOptional() const -> bool {            return m_optionality == Optionality::Optional;        }        auto cardinality() const -> size_t override {            if( m_ref->isContainer() )                return 0;            else                return 1;        }        auto hint() const -> std::string { return m_hint; }    };    class ExeName : public ComposableParserImpl<ExeName> {        std::shared_ptr<std::string> m_name;        std::shared_ptr<BoundValueRefBase> m_ref;        template<typename LambdaT>        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;        }    public:        ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}        explicit ExeName( std::string &ref ) : ExeName() {            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );        }        template<typename LambdaT>        explicit ExeName( LambdaT const& lambda ) : ExeName() {            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );        }        // The exe name is not parsed out of the normal tokens, but is handled specially        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );        }        auto name() const -> std::string { return *m_name; }        auto set( std::string const& newName ) -> ParserResult {            auto lastSlash = newName.find_last_of( "\\/" );            auto filename = ( lastSlash == std::string::npos )                    ? newName                    : newName.substr( lastSlash+1 );            *m_name = filename;            if( m_ref )                return m_ref->setValue( filename );            else                return ParserResult::ok( ParseResultType::Matched );        }    };    class Arg : public ParserRefImpl<Arg> {    public:        using ParserRefImpl::ParserRefImpl;        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {            auto validationResult = validate();            if( !validationResult )                return InternalParseResult( validationResult );            auto remainingTokens = tokens;            auto const &token = *remainingTokens;            if( token.type != TokenType::Argument )                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );            assert( !m_ref->isFlag() );            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );            auto result = valueRef->setValue( remainingTokens->token );            if( !result )                return InternalParseResult( result );            else                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );        }    };    inline auto normaliseOpt( std::string const &optName ) -> std::string {#ifdef CATCH_PLATFORM_WINDOWS        if( optName[0] == '/' )            return "-" + optName.substr( 1 );        else#endif            return optName;    }    class Opt : public ParserRefImpl<Opt> {    protected:        std::vector<std::string> m_optNames;    public:        template<typename LambdaT>        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}        template<typename LambdaT>        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}        template<typename T>        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}        auto operator[]( std::string const &optName ) -> Opt & {            m_optNames.push_back( optName );            return *this;        }        auto getHelpColumns() const -> std::vector<HelpColumns> {            std::ostringstream oss;            bool first = true;            for( auto const &opt : m_optNames ) {                if (first)                    first = false;                else                    oss << ", ";                oss << opt;            }            if( !m_hint.empty() )                oss << " <" << m_hint << ">";            return { { oss.str(), m_description } };        }        auto isMatch( std::string const &optToken ) const -> bool {            auto normalisedToken = normaliseOpt( optToken );            for( auto const &name : m_optNames ) {                if( normaliseOpt( name ) == normalisedToken )                    return true;            }            return false;        }        using ParserBase::parse;        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {            auto validationResult = validate();            if( !validationResult )                return InternalParseResult( validationResult );            auto remainingTokens = tokens;            if( remainingTokens && remainingTokens->type == TokenType::Option ) {                auto const &token = *remainingTokens;                if( isMatch(token.token ) ) {                    if( m_ref->isFlag() ) {                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );                        auto result = flagRef->setFlag( true );                        if( !result )                            return InternalParseResult( result );                        if( result.value() == ParseResultType::ShortCircuitAll )                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );                    } else {                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );                        ++remainingTokens;                        if( !remainingTokens )                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );                        auto const &argToken = *remainingTokens;                        if( argToken.type != TokenType::Argument )                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );                        auto result = valueRef->setValue( argToken.token );                        if( !result )                            return InternalParseResult( result );                        if( result.value() == ParseResultType::ShortCircuitAll )                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );                    }                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );                }            }            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );        }        auto validate() const -> Result override {            if( m_optNames.empty() )                return Result::logicError( "No options supplied to Opt" );            for( auto const &name : m_optNames ) {                if( name.empty() )                    return Result::logicError( "Option name cannot be empty" );#ifdef CATCH_PLATFORM_WINDOWS                if( name[0] != '-' && name[0] != '/' )                    return Result::logicError( "Option name must begin with '-' or '/'" );#else                if( name[0] != '-' )                    return Result::logicError( "Option name must begin with '-'" );#endif            }            return ParserRefImpl::validate();        }    };    struct Help : Opt {        Help( bool &showHelpFlag )        :   Opt([&]( bool flag ) {                showHelpFlag = flag;                return ParserResult::ok( ParseResultType::ShortCircuitAll );            })        {            static_cast<Opt &>( *this )                    ("display usage information")                    ["-?"]["-h"]["--help"]                    .optional();        }    };    struct Parser : ParserBase {        mutable ExeName m_exeName;        std::vector<Opt> m_options;        std::vector<Arg> m_args;        auto operator|=( ExeName const &exeName ) -> Parser & {            m_exeName = exeName;            return *this;        }        auto operator|=( Arg const &arg ) -> Parser & {            m_args.push_back(arg);            return *this;        }        auto operator|=( Opt const &opt ) -> Parser & {            m_options.push_back(opt);            return *this;        }        auto operator|=( Parser const &other ) -> Parser & {            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());            return *this;        }        template<typename T>        auto operator|( T const &other ) const -> Parser {            return Parser( *this ) |= other;        }        // Forward deprecated interface with '+' instead of '|'        template<typename T>        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }        template<typename T>        auto operator+( T const &other ) const -> Parser { return operator|( other ); }        auto getHelpColumns() const -> std::vector<HelpColumns> {            std::vector<HelpColumns> cols;            for (auto const &o : m_options) {                auto childCols = o.getHelpColumns();                cols.insert( cols.end(), childCols.begin(), childCols.end() );            }            return cols;        }        void writeToStream( std::ostream &os ) const {            if (!m_exeName.name().empty()) {                os << "usage:\n" << "  " << m_exeName.name() << " ";                bool required = true, first = true;                for( auto const &arg : m_args ) {                    if (first)                        first = false;                    else                        os << " ";                    if( arg.isOptional() && required ) {                        os << "[";                        required = false;                    }                    os << "<" << arg.hint() << ">";                    if( arg.cardinality() == 0 )                        os << " ... ";                }                if( !required )                    os << "]";                if( !m_options.empty() )                    os << " options";                os << "\n\nwhere options are:" << std::endl;            }            auto rows = getHelpColumns();            size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;            size_t optWidth = 0;            for( auto const &cols : rows )                optWidth = (std::max)(optWidth, cols.left.size() + 2);            optWidth = (std::min)(optWidth, consoleWidth/2);            for( auto const &cols : rows ) {                auto row =                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +                        TextFlow::Spacer(4) +                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );                os << row << std::endl;            }        }        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {            parser.writeToStream( os );            return os;        }        auto validate() const -> Result override {            for( auto const &opt : m_options ) {                auto result = opt.validate();                if( !result )                    return result;            }            for( auto const &arg : m_args ) {                auto result = arg.validate();                if( !result )                    return result;            }            return Result::ok();        }        using ParserBase::parse;        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {            struct ParserInfo {                ParserBase const* parser = nullptr;                size_t count = 0;            };            const size_t totalParsers = m_options.size() + m_args.size();            assert( totalParsers < 512 );            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do            ParserInfo parseInfos[512];            {                size_t i = 0;                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;            }            m_exeName.set( exeName );            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );            while( result.value().remainingTokens() ) {                bool tokenParsed = false;                for( size_t i = 0; i < totalParsers; ++i ) {                    auto&  parseInfo = parseInfos[i];                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());                        if (!result)                            return result;                        if (result.value().type() != ParseResultType::NoMatch) {                            tokenParsed = true;                            ++parseInfo.count;                            break;                        }                    }                }                if( result.value().type() == ParseResultType::ShortCircuitAll )                    return result;                if( !tokenParsed )                    return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );            }            // !TBD Check missing required options            return result;        }    };    template<typename DerivedT>    template<typename T>    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {        return Parser() | static_cast<DerivedT const &>( *this ) | other;    }} // namespace detail// A Combined parserusing detail::Parser;// A parser for optionsusing detail::Opt;// A parser for argumentsusing detail::Arg;// Wrapper for argc, argv from main()using detail::Args;// Specifies the name of the executableusing detail::ExeName;// Convenience wrapper for option parser that specifies the help optionusing detail::Help;// enum of result types from a parseusing detail::ParseResultType;// Result type for parser operationusing detail::ParserResult;}} // namespace Catch::clara#endif // CATCH_CLARA_HPP_INCLUDED
 |