forked from Alepha/Alepha
UnifiedEnum
-- union construction of enumerates
This commit is contained in:
129
UnifiedEnum.h
Normal file
129
UnifiedEnum.h
Normal file
@ -0,0 +1,129 @@
|
||||
static_assert( __cplusplus > 2023'00 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include "Enum.h"
|
||||
|
||||
namespace Alepha::Hydrogen ::detail:: UnifiedEnum_m
|
||||
{
|
||||
inline namespace exports {}
|
||||
|
||||
template< typename T >
|
||||
constexpr bool is_alepha_enum_v= false;
|
||||
|
||||
using detail::Enum_m::EnumValueString;
|
||||
|
||||
template< detail::Enum_m::EnumValueString ... values >
|
||||
constexpr bool is_alepha_enum_v< Enum< values... > >{ true };
|
||||
|
||||
template< typename T >
|
||||
concept EnhancedEnumerate= is_alepha_enum_v< T >;
|
||||
|
||||
namespace exports
|
||||
{
|
||||
template< EnhancedEnumerate ... >
|
||||
class UnifiedEnum;
|
||||
}
|
||||
|
||||
template< EnumValueString cs_strs >
|
||||
struct StringWrapper;
|
||||
|
||||
template< EnhancedEnumerate ... enums >
|
||||
struct unify_values;
|
||||
|
||||
template< detail::Enum_m::EnumValueString ... cs_str >
|
||||
struct unify_values< Enum< cs_str... > >
|
||||
{
|
||||
using type= TypeList< StringWrapper< cs_str >... >;
|
||||
};
|
||||
|
||||
template< detail::Enum_m::EnumValueString ... cs_str, EnhancedEnumerate ... next >
|
||||
struct unify_values< Enum< cs_str... >, next... >
|
||||
{
|
||||
using type= list_cat_t< TypeList< StringWrapper< cs_str >... >,
|
||||
typename unify_values< next... >::type >;
|
||||
};
|
||||
|
||||
// Because of the way that this works, I do wind up with a possibility of duplicates
|
||||
// in the enumerate list. This is (hopefully) benign. The underlying `Enum`
|
||||
// type doesn't check for duplicates for the same reason we'll not check here.
|
||||
// It's hopefully benign as the duplicated enumerate values simply become an
|
||||
// unused index by the `get_index` and `set_index` functions. For the most
|
||||
// part users of the class shouldn't be calling those functions. If they are,
|
||||
// it should merely be for serialization. As such, skipping a value in the
|
||||
// sequential indexing shouldn't be observable.
|
||||
//
|
||||
// Without good enough support for a compiletime search and dedupe on types,
|
||||
// we have to resort to O( N ** 2 ) or worse algorithms to remove duplicates.
|
||||
// With so much compiletime algorithm pressure already, this would become a
|
||||
// significant pain point for TUs which have a lot of `Enum`s.
|
||||
//
|
||||
// An unfortunate side-effect of this design choice is that when/if this design
|
||||
// is changed to support deduplication of enumerate values (strings), that
|
||||
// will create a massive but subtle ABI break:
|
||||
// `UnifiedEnum< Enum< "a"_value >, Enum< "a"_value > >` would now use a
|
||||
// different index scheme, despite having the same typename.
|
||||
template< TypeListType > struct build_enum;
|
||||
|
||||
template< detail::Enum_m::EnumValueString ... cs_str >
|
||||
struct build_enum< TypeList< StringWrapper< cs_str >... > >
|
||||
{
|
||||
using type= Enum< cs_str... >;
|
||||
};
|
||||
|
||||
template< EnhancedEnumerate ... EnumType >
|
||||
class exports::UnifiedEnum
|
||||
: protected build_enum< typename unify_values< EnumType... >::type >::type
|
||||
{
|
||||
private:
|
||||
using Base= typename build_enum< typename unify_values< EnumType... >::type >::type;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
using Base::name;
|
||||
using Base::accepts;
|
||||
using Base::set_index;
|
||||
using Base::get_index;
|
||||
|
||||
template< typename Enumerate >
|
||||
requires( list_contains_v< TypeList< EnumType... >, Enumerate > )
|
||||
UnifiedEnum( const Enumerate e )
|
||||
{
|
||||
unsigned value= 0;
|
||||
for( const auto &next: this->keys() )
|
||||
{
|
||||
if( next == e.key() )
|
||||
{
|
||||
set_index( value );
|
||||
return;
|
||||
}
|
||||
++value;
|
||||
}
|
||||
|
||||
// It should not be possible to reach here.
|
||||
abort();
|
||||
}
|
||||
|
||||
friend std::ostream &
|
||||
operator << ( std::ostream &os, const UnifiedEnum &rhs )
|
||||
{
|
||||
return os << static_cast< const Base & >( rhs );
|
||||
}
|
||||
|
||||
friend std::istream &
|
||||
operator >> ( std::istream &is, UnifiedEnum &rhs )
|
||||
{
|
||||
return is >> static_cast< Base & >( rhs );
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator == ( const UnifiedEnum &, const UnifiedEnum & )= default;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::inline exports::inline UnifiedEnum_m
|
||||
{
|
||||
using namespace detail::UnifiedEnum_m::exports;
|
||||
}
|
Reference in New Issue
Block a user