1
0
forked from Alepha/Alepha
Files
Alepha/dumbhash.test/0.cc
ADAM David Alan Martin e41198c294 Initial draft of how short options work.
I went with expansion here, as it was easier to implement,
given the complexities of how the options parsing code works.

Rather than try to maintain state machines and parsing for both
forms of argument, we can transform the short options into the
long form options.  This, then, might lead to some issues when
the code is expanded to handle arguments to those options.
I'll probably just add a state tracking bit to that parameter to
say that it was expanded from a specific short form.

It might be worth it to permit a short form to expand to a long
form _with_ specific hardcoded option.  This gets into defaults,
which might be the better way to underpin that.

For expanding these into the automatic help documentation, the
Long options (the main option definition struct) should maintain
a list of the short forms that it supports.

I also need to add a neat syntax.  Something like:

```
-'o'_option <= --"long-option"_option
```

It might be beneficial to auto generate something like:

```
-'O'_option <= --"no-long-option"_option
```

for boolean toggles.  Should it always be so?  Maybe an extra
sigil to allow both?
2025-09-06 01:22:53 -04:00

358 lines
11 KiB
C++

static_assert( __cplusplus > 2020'99 );
#include <cstdint>
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <iomanip>
#include <boost/core/demangle.hpp>
#include <Alepha/Testing/test.h>
#include <Alepha/Testing/TableTest.h>
#include <Alepha/Utility/enroll.h>
#include <Alepha/comparisons.h>
namespace
{
using namespace Alepha::Testing::exports;
using namespace Alepha::Utility::exports::enroll_m;
using namespace Alepha::exports::types_m;
using hash_type= std::uint64_t;
namespace C
{
namespace best_constants_candidate
{
// These constants seem to produce a nice distribution
const std::uint64_t spinBase= 7;
const std::uint64_t spinRate= 191;
const int maxRounds= 40;
const std::uint64_t indexLimit= ( 1ull << 47 ) - 1;
}
namespace experimental_constants
{
using namespace best_constants_candidate;
const std::uint64_t spinRate= 379;
const int maxRounds= 20;
}
namespace weak_constants
{
using namespace best_constants_candidate;
//const std::uint64_t spinBase= 9;
//const std::uint64_t spinRate= 0;
//const int maxRounds= 25;
}
namespace second_experiment
{
using namespace best_constants_candidate;
const int maxRounds= 30;
const std::uint64_t spinBase= 5;
}
using namespace best_constants_candidate;
}
enum { Unit };
template< typename T >
constexpr const char *
typesig()
{
const char *p= __PRETTY_FUNCTION__;
if not consteval
{
std::cerr << p << std::endl;
}
while( *p++ != '[' );
return p + 5 + 4;
}
[[nodiscard]] constexpr std::uint64_t
rotl( const std::uint64_t value, const std::uint64_t amt )
{
if( amt >= 64 ) return rotl( value, amt % 64 );
if( amt == 0 ) return value;
return ( value << amt ) | ( value >> 64 - amt );
}
constexpr hash_type
computeHash( const char *str )
{
std::uint64_t rv= 0;
unsigned index= 0;
for( ; *str; ++str )
{
//++index;
for( int i= 0; i < C::maxRounds; ++i )
{
index+= C::spinRate;
index%= C::indexLimit;
std::uint64_t ch= *str; //|0xFF'FF'FF'FF'FF'FF'FF'00;
rv= rotl( rv, index + C::spinBase );
// engage the carry only occasionally, to help with bit-mixing
if( false ) ;
else if( not( i % 11 ) or not( i % 17 ) ) rv+= ch;
else rv^= ch;
}
}
return rv;
}
template< typename T >
constexpr auto
computeTypeHash()
{
return computeHash( typesig< T >() );
}
auto
printHash( const std::string &s )
{
std::cout << std::hex << std::setw( 16 ) << std::setfill( '0' ) << (std::uint64_t) computeHash( s.c_str() ) << ": " << s;
return Unit;
}
struct abc {};
struct abd {};
struct abcd {};
auto tests= enroll <=[]
{
"simple.case"_test <= TableTest< printHash >::Cases
{
{ "nothing", { "" }, Unit },
{ "cab", { "cab" }, Unit },
{ "cal", { "cal" }, Unit },
{ "cam", { "cam" }, Unit },
{ "can", { "can" }, Unit },
{ "car", { "car" }, Unit },
{ "cat", { "cat" }, Unit },
{ "hat", { "hat" }, Unit },
{ "hut", { "hut" }, Unit },
{ "dog", { "dog" }, Unit },
{ "pie", { "pie" }, Unit },
{ "spoon", { "spoon" }, Unit },
{ "frank", { "frank" }, Unit },
{ "fronk", { "fronk" }, Unit },
{ "typesig< void >", { typesig< void >() }, Unit },
{ "typesig< char >", { typesig< char >() }, Unit },
{ "typesig< int >", { typesig< int >() }, Unit },
{ "typesig< unsigned >", { typesig< unsigned >() }, Unit },
{ "typesig< signed >", { typesig< signed >() }, Unit },
{ "typesig< float >", { typesig< float >() }, Unit },
{ "typesig< double >", { typesig< double >() }, Unit },
{ "typesig< long double >", { typesig< long double >() }, Unit },
{ "typesig< std::vector< int > >", { typesig< std::vector< int > >() }, Unit },
{ "typesig< short >", { typesig< short >() }, Unit },
{ "typesig< unsigned short >", { typesig< unsigned short >() }, Unit },
{ "typesig< unsigned char >", { typesig< unsigned char >() }, Unit },
{ "typesig< signed char >", { typesig< signed char >() }, Unit },
{ "typesig< int * >", { typesig< int * >() }, Unit },
{ "typesig< int >", { typesig< int >() }, Unit },
{ "typesig< std::string >", { typesig< std::string >() }, Unit },
{ "typesig< std::vector< std::string > >", { typesig< std::vector< std::string > >() }, Unit },
{ "typesig< abc >", { typesig< abc >() }, Unit },
{ "typesig< abd >", { typesig< abd >() }, Unit },
{ "typesig< abcd >", { typesig< abcd >() }, Unit },
};
};
template< hash_type > struct type_registry;
#if 0
template<>
struct type_registry< computeTypeHash< std::string >() >
{
using type= std::string;
};
#endif
template< std::uint64_t val >
struct hash_hook
{
template< typename T >
friend constexpr auto hash_lookup( hash_hook, T );
};
template< typename T >
struct register_type
{
template< typename X >
friend constexpr auto
hash_lookup( hash_hook< computeTypeHash< T >() >, X )
{
return Alepha::Meta::type_value< T >{};
}
using type= void;
};
template< hash_type val >
struct type_registry
{
using type= typename decltype( hash_lookup( hash_hook< val >{}, nullptr ) )::type;
};
//using registration= register_type< int >::type;
template< typename T >
constexpr auto
calculateTypeHash()
{
using registration= typename register_type< T >::type;
return computeTypeHash< T >();
}
template< typename T >
constexpr bool verify_registry= std::is_same_v< typename type_registry< calculateTypeHash< T >() >::type, T >;
auto registry_test= "registry"_test <=[]
{
static_assert( std::is_same_v< type_registry< calculateTypeHash< std::string >() >::type, std::string > );
static_assert( std::is_same_v< type_registry< calculateTypeHash< int >() >::type, int > );
static_assert( std::is_same_v< type_registry< calculateTypeHash< char >() >::type, char > );
static_assert( std::is_same_v< type_registry< calculateTypeHash< unsigned char >() >::type, unsigned char > );
static_assert( verify_registry< long > );
static_assert( verify_registry< unsigned long > );
static_assert( verify_registry< unsigned long long > );
static_assert( verify_registry< signed long long > );
static_assert( verify_registry< double > );
static_assert( verify_registry< long double > );
static_assert( verify_registry< float > );
static_assert( verify_registry< std::vector< int * > > );
static_assert( verify_registry< void > );
static_assert( verify_registry< unsigned char > );
static_assert( verify_registry< signed char > );
static_assert( verify_registry< short > );
static_assert( verify_registry< unsigned short > );
static_assert( verify_registry< std::function< void( int, long, std::string & ) > > );
#ifndef DISABLE
static_assert( verify_registry< std::array< int, 1 > > );
static_assert( verify_registry< std::array< int, 2 > > );
static_assert( verify_registry< std::array< int, 3 > > );
static_assert( verify_registry< std::array< int, 4 > > );
static_assert( verify_registry< std::array< int, 5 > > );
static_assert( verify_registry< std::array< int, 6 > > );
static_assert( verify_registry< std::array< int, 7 > > );
static_assert( verify_registry< std::array< int, 8 > > );
static_assert( verify_registry< std::array< int, 9 > > );
static_assert( verify_registry< std::array< int, 10 > > );
static_assert( verify_registry< std::array< int, 11 > > );
static_assert( verify_registry< std::array< int, 12 > > );
static_assert( verify_registry< std::array< int, 13 > > );
static_assert( verify_registry< std::array< int, 14 > > );
static_assert( verify_registry< std::array< int, 15 > > );
static_assert( verify_registry< std::array< int, 16 > > );
static_assert( verify_registry< std::array< int, 17 > > );
static_assert( verify_registry< std::array< int, 18 > > );
static_assert( verify_registry< std::array< int, 19 > > );
static_assert( verify_registry< std::array< int, 20 > > );
#endif
static_assert( verify_registry< std::array< int, 1 > > );
static_assert( verify_registry< std::array< int, 2 > > );
static_assert( verify_registry< std::array< int, 3 > > );
static_assert( verify_registry< std::array< int, 4 > > );
static_assert( verify_registry< std::array< int, 5 > > );
static_assert( verify_registry< std::array< int, 6 > > );
static_assert( verify_registry< std::array< int, 7 > > );
static_assert( verify_registry< std::array< int, 8 > > );
static_assert( verify_registry< std::array< int, 9 > > );
static_assert( verify_registry< std::array< int, 10 > > );
static_assert( verify_registry< std::array< int, 11 > > );
static_assert( verify_registry< std::array< int, 12 > > );
static_assert( verify_registry< std::array< int, 13 > > );
static_assert( verify_registry< std::array< int, 14 > > );
static_assert( verify_registry< std::array< int, 15 > > );
static_assert( verify_registry< std::array< int, 16 > > );
static_assert( verify_registry< std::array< int, 17 > > );
static_assert( verify_registry< std::array< int, 18 > > );
static_assert( verify_registry< std::array< int, 19 > > );
static_assert( verify_registry< std::array< int, 20 > > );
};
enum class TypeNTTP : hash_type {};
template< typename T >
struct nttp_maker
{
static_assert( verify_registry< T > );
static constexpr auto value= TypeNTTP( calculateTypeHash< T >() );
};
template< typename T >
constexpr auto make_nttp_v= nttp_maker< T >::value;
template< TypeNTTP type_val >
using type_from_nttp_t= typename type_registry< hash_type( type_val ) >::type;
inline std::ostream &
operator << ( std::ostream &os, const TypeNTTP &val )
{
return os << "Type Code: " << std::hex << std::setw( 16 ) << std::setfill( '0' ) << (std::uint64_t) hash_type( val );
// With some more work, we can make a runtime code registry, if desired.
// But the codes are *NOT* portable!
//<< " which maps to " << typeid( type_from_nttp_t< val
}
auto type_nttp_test= "nttp"_test <=[]
{
std::cout << "NTTP of int: " << make_nttp_v< int > << std::endl;
constexpr auto nttpVal= make_nttp_v< std::map< std::vector< std::string >, std::function< void( int, long, short ) > > >;
std::cout << "type: " << boost::core::demangle( typeid( type_from_nttp_t< nttpVal > ).name() ) << std::endl;
};
template< typename ... Types >
constexpr auto type_array= std::array< TypeNTTP, sizeof...( Types ) >{ make_nttp_v< Types >... };
template< TypeNTTP ... type_codes >
using typeset= std::tuple< type_from_nttp_t< type_codes >... >;
template< typename T >
constexpr T *
max_element( const T *const first, const T *const last )
{
T *largest= first;
for( T *const pos= first; pos < last; ++pos )
{
if( *pos > *largest ) largest= pos;
}
return largest;
}
template< typename Container >
constexpr void
sort( Container &array )
{
for( auto pos= begin( array ); pos != end( array ); ++pos )
{
const auto largest= max_element( pos, end( array ) );
auto tmp= std::move( *largest );
*largest= std::move( *pos );
*pos= std::move( tmp );
}
}
}