Boost logo

Boost :

From: Stefan Slapeta (stefan_at_[hidden])
Date: 2005-02-24 09:31:41


Vladimir Prus wrote:
>
> Can you give the specific use cases. I think that fully generic solution can
> be overly complex, and we can get away with some helper functions. Say,
> 'mutially_excluse_options' can check than only one option of a group is
> specified.
>

what about this syntax?

po::options_validator v =
        ( po::exists("option_a") & po::exists("option_c")
         |
         ( po::exists("option_c") & po::exists("option_d")
         ;

bool valid = v.validate(desc);

I attach a working basic solution (many things copied from spirit ;) ),
feel free to do anything you want with it.
I used operator ^ for mutually exclusive options, but I'm afraid it's
not perfect as it's not the same as xor!

Cheers,

Stefan


#ifndef VALIDATOR_H_INCLUDED
#define VALIDATOR_H_INCLUDED

// Copyright Stefan Slapeta 2005.
// 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)

#include <boost/shared_ptr.hpp>
#include <boost/compressed_pair.hpp>
#include <boost/program_options/options_description.hpp>

namespace boost { namespace program_options {

template <typename DerivedT>
class validator_base
{
public:
    bool validate(options_description const& desc) const
    {
        return derived().do_validate(desc);
    }

    DerivedT const& derived() const
    {
        return *static_cast<DerivedT const*>(this);
    }

    DerivedT& derived()
    {
        return *static_cast<DerivedT*>(this);
    }
};

template <typename L, typename R, typename BaseT>
class binary_validator : public BaseT
{
public:
    typedef typename boost::call_traits<L>::param_type left_param_t;
    typedef typename boost::call_traits<L>::const_reference left_return_t;
    typedef typename boost::call_traits<R>::param_type right_param_t;
    typedef typename boost::call_traits<R>::const_reference right_return_t;

    typedef typename boost::remove_reference<L>::type left_embed_t;
    typedef typename boost::remove_reference<R>::type right_embed_t;

    binary_validator(left_param_t left, right_param_t right)
        : m_subj(left, right)
    {
    }

    left_return_t left() const {
        return m_subj.first();
    }

    right_return_t right() const {
        return m_subj.second();
    }

private:
    boost::compressed_pair<left_embed_t, right_embed_t> m_subj;
};

template <typename L, typename R>
class exists_composite :
    public binary_validator<L, R, validator_base<exists_composite<L, R> > >
{
public:
    typedef exists_composite<L, R> self_t;
    typedef binary_validator<L, R, validator_base<self_t> > base_t;

    exists_composite(L const& left, R const& right)
        : base_t(left, right)
    {
    }

    bool do_validate(options_description const& desc) const
    {
        return left().validate(desc) && right().validate(desc);
    }
};

template <typename L, typename R>
class exists_alternative :
    public binary_validator<L, R, validator_base<exists_alternative<L, R> > >
{
public:
    typedef exists_alternative<L, R> self_t;
    typedef binary_validator<L, R, validator_base<self_t> > base_t;

    exists_alternative(L const& left, R const& right)
        : base_t(left, right)
    {
    }

    bool do_validate(options_description const& desc) const
    {
        return left().validate(desc) || right().validate(desc);
    }
};

template <typename L, typename R>
class mutually_exclusive :
    public binary_validator<L, R, validator_base<mutually_exclusive<L, R> > >
{
public:
    typedef mutually_exclusive<L, R> self_t;
    typedef binary_validator<L, R, validator_base<self_t> > base_t;

    mutually_exclusive(L const& left, R const& right)
        : base_t(left, right)
    {
    }

    bool do_validate(options_description const& desc) const
    {
        return left().validate(desc) || right().validate(desc);
    }
};

class exists :
    public validator_base<exists>
{
public:
    exists(std::string const& option)
        : m_option(option)
    {
    }

    bool do_validate(options_description const& desc) const
    {
        return desc.count(m_option) != 0;
    }

private:
    std::string m_option;
};

template <typename LeftValidatorT, typename RightValidatorT>
exists_alternative<LeftValidatorT, RightValidatorT>
operator | (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r)
{
    return exists_alternative<LeftValidatorT, RightValidatorT>(l.derived(), r.derived());
}

template <typename LeftValidatorT, typename RightValidatorT>
exists_composite<LeftValidatorT, RightValidatorT>
operator & (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r)
{
    return exists_composite<LeftValidatorT, RightValidatorT>(l.derived(), r.derived());
}

template <typename LeftValidatorT, typename RightValidatorT>
mutually_exclusive<LeftValidatorT, RightValidatorT>
operator ^ (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r)
{
    return mutually_exclusive<LeftValidatorT, RightValidatorT>(l.derived(), r.derived());
}

class validator_impl_base
{
public:
    bool validate(options_description const& desc) const
    {
        return validate_virtual(desc);
    }

private:
    virtual bool validate_virtual(options_description const& desc) const = 0;
};

template <typename ValidatorT>
class validator_impl : public validator_impl_base
{
public:
    validator_impl(ValidatorT const& v)
        : m_validator(v)
    {
    }

private:
    bool validate_virtual(options_description const& desc) const
    {
        return m_validator.validate(desc);
    }

    ValidatorT m_validator;
};

class options_validator
{
public:
    template <typename ValidatorT>
    options_validator(validator_base<ValidatorT> const& v)
        : m_validator(new validator_impl<ValidatorT>(v.derived()))
    {
    }

    bool validate(options_description const& desc) const
    {
        return m_validator->validate(desc);
    }

private:

    boost::shared_ptr<validator_impl_base> m_validator;
};

}}

#endif


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk