Skip to content
Snippets Groups Projects
clipp.h 188 KiB
Newer Older
/*****************************************************************************
 *
 * CLIPP - command line interfaces for modern C++
 *
 * released under MIT license
 *
 * (c) 2017 André Müller; foss@andremueller-online.de
 *
 *****************************************************************************/

#ifndef AM_CLIPP_H__
#define AM_CLIPP_H__

#include <cstring>
#include <string>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <memory>
#include <vector>
#include <limits>
#include <stack>
#include <algorithm>
#include <sstream>
#include <utility>
#include <iterator>
#include <functional>


/*************************************************************************//**
 *
 * @brief primary namespace
 *
 *****************************************************************************/
namespace clipp {



/*****************************************************************************
 *
 * basic constants and datatype definitions
 *
 *****************************************************************************/
using arg_index = int;

using arg_string = std::string;
using doc_string = std::string;

using arg_list  = std::vector<arg_string>;



/*************************************************************************//**
 *
 * @brief tristate
 *
 *****************************************************************************/
enum class tri : char { no, yes, either };

inline constexpr bool operator == (tri t, bool b) noexcept {
    return b ? t != tri::no : t != tri::yes;
}
inline constexpr bool operator == (bool b, tri t) noexcept { return  (t == b); }
inline constexpr bool operator != (tri t, bool b) noexcept { return !(t == b); }
inline constexpr bool operator != (bool b, tri t) noexcept { return !(t == b); }



/*************************************************************************//**
 *
 * @brief (start,size) index range
 *
 *****************************************************************************/
class subrange {
public:
    using size_type = arg_string::size_type;

    /** @brief default: no match */
    explicit constexpr
    subrange() noexcept :
        at_{arg_string::npos}, length_{0}
    {}

    /** @brief match length & position within subject string */
    explicit constexpr
    subrange(size_type pos, size_type len) noexcept :
        at_{pos}, length_{len}
    {}

    /** @brief position of the match within the subject string */
    constexpr size_type at()     const noexcept { return at_; }
    /** @brief length of the matching subsequence */
    constexpr size_type length() const noexcept { return length_; }

    /** @brief returns true, if query string is a prefix of the subject string */
    constexpr bool prefix() const noexcept {
        return at_ == 0 && length_ > 0;
    }

    /** @brief returns true, if query is a substring of the query string */
    constexpr explicit operator bool () const noexcept {
        return at_ != arg_string::npos && length_ > 0;
    }

private:
    size_type at_;
    size_type length_;
};



/*************************************************************************//**
 *
 * @brief match predicates
 *
 *****************************************************************************/
using match_predicate = std::function<bool(const arg_string&)>;
using match_function  = std::function<subrange(const arg_string&)>;






/*************************************************************************//**
 *
 * @brief type traits (NOT FOR DIRECT USE IN CLIENT CODE!)
 *        no interface guarantees; might be changed or removed in the future
 *
 *****************************************************************************/
namespace traits {

/*************************************************************************//**
 *
 * @brief function (class) signature type trait
 *
 *****************************************************************************/
template<class Fn, class Ret, class... Args>
constexpr auto
check_is_callable(int) -> decltype(
    std::declval<Fn>()(std::declval<Args>()...),
    std::integral_constant<bool,
        std::is_same<Ret,typename std::result_of<Fn(Args...)>::type>::value>{} );

template<class,class,class...>
constexpr auto
check_is_callable(long) -> std::false_type;

template<class Fn, class Ret>
constexpr auto
check_is_callable_without_arg(int) -> decltype(
    std::declval<Fn>()(),
    std::integral_constant<bool,
        std::is_same<Ret,typename std::result_of<Fn()>::type>::value>{} );

template<class,class>
constexpr auto
check_is_callable_without_arg(long) -> std::false_type;



template<class Fn, class... Args>
constexpr auto
check_is_void_callable(int) -> decltype(
    std::declval<Fn>()(std::declval<Args>()...), std::true_type{});

template<class,class,class...>
constexpr auto
check_is_void_callable(long) -> std::false_type;

template<class Fn>
constexpr auto
check_is_void_callable_without_arg(int) -> decltype(
    std::declval<Fn>()(), std::true_type{});

template<class>
constexpr auto
check_is_void_callable_without_arg(long) -> std::false_type;



template<class Fn, class Ret>
struct is_callable;


template<class Fn, class Ret, class... Args>
struct is_callable<Fn, Ret(Args...)> :
    decltype(check_is_callable<Fn,Ret,Args...>(0))
{};

template<class Fn, class Ret>
struct is_callable<Fn,Ret()> :
    decltype(check_is_callable_without_arg<Fn,Ret>(0))
{};


template<class Fn, class... Args>
struct is_callable<Fn, void(Args...)> :
    decltype(check_is_void_callable<Fn,Args...>(0))
Loading
Loading full blame...