1
0
forked from Alepha/Alepha

UnifiedEnum -- union construction of enumerates

This commit is contained in:
2024-07-13 16:38:06 -04:00
parent 3c814a53c3
commit 308b64fc64
4 changed files with 223 additions and 0 deletions

129
UnifiedEnum.h Normal file
View 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;
}