Skip to content

Commit 5bcf23a

Browse files
author
Fytch
committed
implement .bind
1 parent 8dde854 commit 5bcf23a

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

ProgramOptions.hxx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
#include <cmath>
2222
#include <limits>
2323
#include <vector>
24+
#include <deque>
25+
#include <list>
26+
#include <stack>
27+
#include <queue>
2428
#include <memory>
2529
#include <unordered_map>
2630
#include <type_traits>
@@ -357,6 +361,50 @@ namespace po {
357361
template< value_type type >
358362
using vt2type = typename detail::vt2type_impl< type >::type;
359363

364+
namespace detail {
365+
template<
366+
typename T,
367+
bool is_integral = std::is_integral< T >::value,
368+
bool is_floating_point = std::is_floating_point< T >::value,
369+
bool is_signed = std::numeric_limits< T >::is_signed
370+
>
371+
struct type2vt_impl {
372+
// Not using false because then it would trigger without instatiation.
373+
// Instead, use an expression that always evaluates to false but depends on T.
374+
static_assert( !std::is_same< T, T >::value, "type2vt: unsupported type" );
375+
static constexpr value_type value = void_;
376+
};
377+
template<>
378+
struct type2vt_impl< void, false, false, false > {
379+
static constexpr value_type value = void_;
380+
};
381+
template<>
382+
struct type2vt_impl< std::string, false, false, false > {
383+
static constexpr value_type value = string;
384+
};
385+
template< typename T >
386+
struct type2vt_impl< T, true, false, true > {
387+
static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits;
388+
static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide signed integral types supported" );
389+
static constexpr value_type value = ( T_bits == 32 ) ? i32 : i64;
390+
};
391+
template< typename T >
392+
struct type2vt_impl< T, true, false, false > {
393+
static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits;
394+
static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide unsigned integral types supported" );
395+
static constexpr value_type value = ( T_bits == 32 ) ? u32 : u64;
396+
};
397+
template< typename T >
398+
struct type2vt_impl< T, false, true, true > {
399+
static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits;
400+
static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide floating point types supported" );
401+
static constexpr value_type value = ( T_bits == 32 ) ? f32 : f64;
402+
};
403+
}
404+
template< typename T >
405+
struct type2vt : detail::type2vt_impl< typename std::remove_cv< T >::type > {
406+
};
407+
360408
template< typename T >
361409
T pow( T base, unsigned exp ) {
362410
if( exp == 0 )
@@ -1604,6 +1652,47 @@ namespace po {
16041652
return *this;
16051653
}
16061654

1655+
template< typename T >
1656+
option& bind_container( T& target ) {
1657+
using value_type = typename T::value_type;
1658+
type( type2vt< value_type >::value );
1659+
multi();
1660+
callback( [ &target ]( value_type const& x ){ target.push_back( x ); } );
1661+
return *this;
1662+
}
1663+
1664+
template< typename T >
1665+
option& bind( T& target ) {
1666+
type( type2vt< T >::value );
1667+
single();
1668+
callback( [ &target ]( T const& x ){ target = x; } );
1669+
return *this;
1670+
}
1671+
template< typename T >
1672+
option& bind( std::vector< T >& target ) {
1673+
return bind_container( target );
1674+
}
1675+
template< typename T >
1676+
option& bind( std::deque< T >& target ) {
1677+
return bind_container( target );
1678+
}
1679+
template< typename T >
1680+
option& bind( std::list< T >& target ) {
1681+
return bind_container( target );
1682+
}
1683+
template< typename T >
1684+
option& bind( std::stack< T >& target ) {
1685+
return bind_container( target );
1686+
}
1687+
template< typename T >
1688+
option& bind( std::queue< T >& target ) {
1689+
return bind_container( target );
1690+
}
1691+
template< typename T >
1692+
option& bind( std::priority_queue< T >& target ) {
1693+
return bind_container( target );
1694+
}
1695+
16071696
private:
16081697
std::unique_ptr< value_vector_base > make_vector() const {
16091698
const bool arg1 = ( get_type() == void_ );

test/bind.cxx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <catch.hpp>
2+
#include <ProgramOptions.hxx>
3+
#include "arg_provider.hxx"
4+
5+
TEST_CASE( "bind", "[ProgramOptions]" ) {
6+
po::parser parser;
7+
parser.silent();
8+
9+
std::string a;
10+
std::int32_t b{};
11+
std::int64_t c{};
12+
std::uint32_t d{};
13+
std::uint64_t e{};
14+
// float f{};
15+
// double g{};
16+
std::vector< std::int32_t > h;
17+
std::deque< std::string > i;
18+
19+
auto&& a_opt = parser[ "a" ].bind( a );
20+
auto&& b_opt = parser[ "b" ].bind( b );
21+
auto&& c_opt = parser[ "c" ].bind( c );
22+
auto&& d_opt = parser[ "d" ].bind( d );
23+
auto&& e_opt = parser[ "e" ].bind( e );
24+
// auto&& f_opt = parser[ "f" ].bind( f );
25+
// auto&& g_opt = parser[ "g" ].bind( g );
26+
auto&& h_opt = parser[ "h" ].bind( h );
27+
auto&& i_opt = parser[ "i" ].bind( i );
28+
29+
REQUIRE( a_opt.is_single() );
30+
REQUIRE( a_opt.get_type() == po::string );
31+
REQUIRE( b_opt.is_single() );
32+
REQUIRE( b_opt.get_type() == po::i32 );
33+
REQUIRE( c_opt.is_single() );
34+
REQUIRE( c_opt.get_type() == po::i64 );
35+
REQUIRE( d_opt.is_single() );
36+
REQUIRE( d_opt.get_type() == po::u32 );
37+
REQUIRE( e_opt.is_single() );
38+
REQUIRE( e_opt.get_type() == po::u64 );
39+
// REQUIRE( f_opt.is_single() );
40+
// REQUIRE( f_opt.get_type() == po::f32 );
41+
// REQUIRE( g_opt.is_single() );
42+
// REQUIRE( g_opt.get_type() == po::f64 );
43+
REQUIRE( h_opt.is_multi() );
44+
REQUIRE( h_opt.get_type() == po::i32 );
45+
REQUIRE( i_opt.is_multi() );
46+
REQUIRE( i_opt.get_type() == po::string );
47+
48+
SECTION( "good scenario" ) {
49+
const arg_provider A {
50+
"/Test",
51+
"-a" "hello",
52+
"-h 36",
53+
"-h 42",
54+
"-i" "foo",
55+
"-i" "bar",
56+
"-b 36",
57+
"-b 42",
58+
};
59+
60+
CHECK( parser( A.argc, A.argv ) );
61+
62+
REQUIRE( a_opt.count() == 1 );
63+
CHECK( a == "hello" );
64+
65+
REQUIRE( b_opt.count() == 1 );
66+
CHECK( b == 42 );
67+
68+
REQUIRE( h_opt.count() == 2 );
69+
REQUIRE( h.size() == 2 );
70+
CHECK( h[ 0 ] == 36 );
71+
CHECK( h[ 1 ] == 42 );
72+
CHECK( h == h_opt.to_vector< po::i32 >() );
73+
74+
REQUIRE( i_opt.count() == 2 );
75+
REQUIRE( i.size() == 2 );
76+
CHECK( i[ 0 ] == "foo" );
77+
CHECK( i[ 1 ] == "bar" );
78+
}
79+
}

0 commit comments

Comments
 (0)