2 #include <Core/RaCore.hpp>
4 #include <Core/Utils/Log.hpp>
5 #include <Core/Utils/StdExperimentalTypeTraits.hpp>
6 #include <Core/Utils/StdOptional.hpp>
7 #include <Core/Utils/TypesUtils.hpp>
13 #include <unordered_map>
103 VariableSet() : m_vtable( VariableSetFunctions::getInstance() ) {}
107 m_vtable( VariableSetFunctions::getInstance() ) {
112 *
this = std::move( other );
134 void mergeKeepVariables(
const VariableSet& from );
140 void mergeReplaceVariables(
const VariableSet& from );
147 auto getStoredTypes() const -> const std::vector<std::type_index>& {
return m_storedType; }
159 template <
typename T>
160 auto insertVariable(
const std::string& name,
const T& value )
161 -> std::pair<VariableHandle<T>,
bool>;
167 template <
typename T>
168 auto getVariable(
const std::string& name )
const -> T&;
175 template <
typename T>
176 auto getVariableHandle(
const std::string& name )
const -> VariableHandle<T>;
182 template <
typename H>
183 bool isHandleValid(
const H& handle )
const;
188 template <
typename T>
189 auto insertOrAssignVariable(
const std::string& name,
const T& value )
190 -> std::pair<VariableHandle<T>,
bool>;
196 template <
typename T>
197 bool deleteVariable(
const std::string& name );
206 template <
typename H>
207 bool deleteVariable( H& handle );
212 template <
typename T>
213 auto existsVariable(
const std::string& name )
const -> Utils::optional<VariableHandle<T>>;
227 template <
typename T>
228 auto existsVariableType() const -> Utils::optional<VariableContainer<T>*>;
235 template <typename T>
236 bool deleteAllVariables();
243 template <typename T>
244 auto getAllVariables() const -> VariableContainer<T>&;
252 template <typename H>
253 auto getAllVariablesFromHandle( const H& handle )
254 -> VariableContainer<VariableTypeFromHandle<H>>&;
259 template <typename T>
260 size_t numberOf() const;
270 template <typename... TYPES>
272 using types = Utils::TypeList<TYPES...>;
290 virtual void operator()( std::any&& in, std::any&& userParam )
const = 0;
295 [[nodiscard]]
virtual bool accept(
const std::type_index&
id )
const = 0;
319 void operator()( std::any&& in, std::any&& userParam )
const override;
324 [[nodiscard]]
bool accept(
const std::type_index&
id )
const override;
333 template <
typename T,
typename F>
334 bool addOperator( F&& f );
339 template <
typename T>
348 template <
typename T,
typename F>
349 void addOrReplaceOperator( F&& f );
355 template <
typename T>
356 bool removeOperator();
360 using CallbackFunction = std::function<void( std::any&, std::any&& )>;
363 using OperatorsStorageType = std::unordered_map<std::type_index, CallbackFunction>;
366 template <
typename T,
typename F,
bool WithUserParam>
367 struct MakeVisitOperatorHelper {
368 auto makeOperator( F& f ) -> OperatorsStorageType::value_type;
373 template <
typename T,
typename F>
374 auto makeVisitorOperator( F& f ) -> OperatorsStorageType::value_type;
377 OperatorsStorageType m_visitorOperator;
390 template <
typename F>
391 void visit( F&& visitor )
const;
394 template <
typename F,
typename T>
395 void visit( F&& visitor, T& userParams )
const;
398 template <
typename F,
typename T>
399 void visit( F&& visitor, T&& userParams )
const;
425 template <
typename P =
bool>
426 void visitDynamic( DynamicVisitorBase& visitor, P&& params = P {} )
const;
445 template <
typename F>
446 void visitStatic( F&& visitor )
const;
449 template <
typename F,
typename T>
450 void visitStatic( F&& visitor, T& userParams )
const;
453 template <
typename F,
typename T>
454 void visitStatic( F&& visitor, T&& userParams )
const;
459 template <
typename T>
460 static auto getVariableVisitTypeIndex() -> std::type_index;
467 template <
typename T>
468 auto addVariableType() -> Utils::optional<VariableContainer<T>*>;
473 template <
typename F,
typename T>
474 using VisitFunction =
475 decltype( std::declval<F>().
operator()( std::declval<const std::string&>(),
476 std::declval<T&>() ) );
479 template <
typename F,
typename T,
typename U>
480 using VisitFunctionWithUserParam =
481 decltype( std::declval<F>().
operator()( std::declval<const std::string&>(),
483 std::declval<U&&>() ) );
486 template <
typename F,
typename T>
487 static constexpr
bool has_visit_callable_v =
488 Ra::Core::Utils::is_detected<VisitFunction, F, T>::value;
491 template <
typename F,
typename T,
typename U>
492 static constexpr
bool has_visit_callable_with_user_param_v =
493 Ra::Core::Utils::is_detected<VisitFunctionWithUserParam, F, T, U>::value;
496 template <
typename F,
template <
typename...>
typename TYPESLIST,
typename... TYPES>
497 void visitImpl( F&& visitor, TYPESLIST<TYPES...> )
const;
499 template <
typename F,
typename T>
500 void visitImplHelper( F& visitor )
const;
503 template <
typename F,
typename U,
template <
typename...>
typename TYPESLIST,
typename... TYPES>
504 void visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> )
const;
506 template <
typename F,
typename U,
typename T>
507 void visitImplHelperUserParam( F& visitor, U&& userParams )
const;
516 class VariableSetFunctions
519 using ClearFunctionType = std::function<void(
VariableSet& )>;
521 using SizeFunctionType = std::function<size_t(
const VariableSet& )>;
523 using VisitFunctorType =
524 std::function<std::pair<bool, std::function<void( DynamicVisitorBase&, std::any&& )>>(
526 const DynamicVisitorBase& )>;
528 VariableSetFunctions(
const VariableSetFunctions& ) =
delete;
529 void operator=(
const VariableSetFunctions& ) =
delete;
532 VariableSetFunctions() =
default;
533 ~VariableSetFunctions() =
default;
537 static auto getInstance() -> VariableSetFunctions*;
539 std::vector<MergeFunctionType> m_mergeKeepFunctions;
540 std::vector<MergeFunctionType> m_mergeReplaceFunctions;
541 std::vector<SizeFunctionType> m_sizeFunctions;
542 std::vector<VisitFunctorType> m_visitFunctions;
543 std::vector<std::type_index> m_storedType;
546 VariableSetFunctions* m_vtable;
553 mutable std::unordered_map<std::type_index, std::any> m_variables;
554 std::unordered_map<std::type_index, size_t> m_typeIndexToVtableIndex;
556 std::vector<std::type_index> m_storedType;
561 template <
typename T>
562 auto createVariableStorage() -> VariableContainer<T>*;
566 template <
typename T>
567 auto getVariableStorage() const -> VariableContainer<T>&;
571 template <typename T>
572 void removeVariableStorage();
581 template <typename T>
582 auto VariableSet::createVariableStorage() -> VariableContainer<T>* {
583 m_variables[std::type_index {
typeid( T ) }].emplace<VariableContainer<T>>();
584 return std::any_cast<VariableContainer<T>>( &( m_variables[std::type_index {
typeid( T ) }] ) );
587 template <
typename T>
588 auto VariableSet::getVariableStorage() const -> VariableContainer<T>& {
589 return std::any_cast<VariableContainer<T>&>( m_variables[std::type_index {
typeid( T ) }] );
592 template <
typename T>
593 void VariableSet::removeVariableStorage() {
594 auto type = std::type_index {
typeid( T ) };
595 m_variables.erase( type );
596 m_typeIndexToVtableIndex.erase( type );
598 auto newEnd = std::remove( m_storedType.begin(), m_storedType.end(), type );
599 m_storedType.erase( newEnd, m_storedType.end() );
605 template <
typename T>
607 -> std::pair<VariableHandle<T>,
bool> {
608 auto typeAccess = existsVariableType<T>();
610 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
612 return ( *typeAccess )->insert( { name, value } );
615 template <
typename T>
617 assert( existsVariable<T>( name ) );
618 return getVariableHandle<T>( name )->second;
621 template <
typename T>
623 assert( existsVariableType<T>() );
624 return getVariableStorage<T>().find( name );
627 template <
typename H>
630 return handle != getVariableStorage<VariableTypeFromHandle<H>>().end();
633 template <
typename T>
635 -> std::pair<VariableHandle<T>,
bool> {
636 auto typeAccess = existsVariableType<T>();
638 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
640 return ( *typeAccess )->insert_or_assign( name, value );
643 template <
typename T>
645 if (
auto typeAccess = existsVariableType<T>(); typeAccess ) {
646 auto removed = ( *typeAccess )->erase( name );
648 if ( numberOf<T>() == 0 ) { deleteAllVariables<T>(); }
654 template <
typename H>
656 assert( isHandleValid( handle ) );
657 auto varname = handle->first;
658 handle = getVariableStorage<VariableTypeFromHandle<H>>().end();
659 return deleteVariable<VariableTypeFromHandle<H>>( varname );
662 template <
typename T>
664 -> Utils::optional<VariableHandle<T>> {
665 if (
auto typeAccess = existsVariableType<T>(); typeAccess ) {
666 auto itr = ( *typeAccess )->find( name );
667 if ( itr != ( *typeAccess )->cend() ) {
return itr; }
672 template <
typename T>
673 auto VariableSet::getVariableVisitTypeIndex() -> std::type_index {
674 static std::type_index idT(
679 template <
typename T>
680 auto VariableSet::addVariableType() -> Utils::optional<VariableContainer<T>*> {
681 auto storage = createVariableStorage<T>();
683 auto tidx = std::type_index(
typeid( T ) );
684 auto it = std::find( m_vtable->m_storedType.begin(), m_vtable->m_storedType.end(), tidx );
687 m_typeIndexToVtableIndex[tidx] = it - m_vtable->m_storedType.begin();
688 m_storedType.push_back( tidx );
691 if ( it == m_vtable->m_storedType.end() ) {
693 m_vtable->m_storedType.emplace_back( tidx );
695 m_vtable->m_mergeKeepFunctions.emplace_back(
698 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
699 auto& toStorage = *( toStorageAccess.value() );
700 auto& fromStorage = from.getVariableStorage<T>();
701 for (
const auto& t : fromStorage ) {
702 toStorage.insert( t );
706 m_vtable->m_mergeReplaceFunctions.emplace_back(
707 [](
const VariableSet& from, VariableSet& to ) {
708 auto toStorageAccess = to.existsVariableType<T>();
709 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
710 auto& toStorage = *( toStorageAccess.value() );
711 auto& fromStorage = from.getVariableStorage<T>();
712 for (
const auto& t : fromStorage ) {
713 toStorage.insert_or_assign( t.first, t.second );
717 m_vtable->m_sizeFunctions.emplace_back(
718 [](
const VariableSet& c ) {
return c.getVariableStorage<T>().size(); } );
720 m_vtable->m_visitFunctions.emplace_back(
721 [](
const VariableSet& c,
const DynamicVisitorBase& v )
722 -> std::pair<bool, std::function<void( DynamicVisitorBase&, std::any && )>> {
723 auto id = getVariableVisitTypeIndex<T>();
724 if ( v.accept(
id ) ) {
725 auto& storage = c.getVariableStorage<T>();
726 auto coll = std::ref( storage );
727 return {
true, [coll]( DynamicVisitorBase& visitor, std::any&& userParam ) {
728 for (
auto&& t : coll.get() ) {
729 visitor( { std::ref( t ) },
730 std::forward<std::any>( userParam ) );
734 else {
return {
false,
nullptr }; }
740 template <
typename T>
742 auto iter = m_variables.find( std::type_index {
typeid( T ) } );
743 if ( iter == m_variables.cend() ) {
return {}; }
744 else {
return std::any_cast<VariableSet::VariableContainer<T>>( &( iter->second ) ); }
747 template <
typename T>
749 if ( existsVariableType<T>() ) {
750 removeVariableStorage<T>();
756 template <
typename T>
760 assert( existsVariableType<T>() );
762 return getVariableStorage<T>();
765 template <
typename H>
769 return getVariableStorage<VariableTypeFromHandle<H>>();
772 template <
typename T>
774 if (
auto variables = existsVariableType<T>(); variables ) {
return ( *variables )->size(); }
778 template <
typename P>
779 void VariableSet::visitDynamic( DynamicVisitorBase& visitor, P&& params )
const {
780 for (
const auto& [type, index] : m_typeIndexToVtableIndex ) {
781 auto [accepted, loop] = m_vtable->m_visitFunctions[index]( *
this, visitor );
782 if ( accepted ) { loop( visitor, std::forward<P>( params ) ); }
786 template <
typename F>
787 void VariableSet::visitStatic( F&& visitor )
const {
788 visitImpl( visitor,
typename std::decay_t<F>::types {} );
791 template <
typename F,
template <
typename...>
typename TYPESLIST,
typename... TYPES>
792 void VariableSet::visitImpl( F&& visitor, TYPESLIST<TYPES...> )
const {
793 ( ..., visitImplHelper<std::decay_t<F>, TYPES>( visitor ) );
796 template <
typename F,
typename T>
797 void VariableSet::visitImplHelper( F& visitor )
const {
798 static_assert( has_visit_callable_v<F, T>,
799 "Static visitors must provide a function with profile "
800 "void( const std::string& name, [const ]T[&] value) for each "
801 "declared visitable type T" );
802 if (
auto variables = existsVariableType<T>(); variables ) {
803 for (
auto& element : *( variables.value() ) ) {
804 visitor( element.first, element.second );
809 template <
typename F,
typename U>
810 void VariableSet::visitStatic( F&& visitor, U& userParams )
const {
812 visitor, std::forward<U>( userParams ),
typename std::decay_t<F>::types {} );
815 template <
typename F,
typename U>
816 void VariableSet::visitStatic( F&& visitor, U&& userParams )
const {
818 visitor, std::forward<U>( userParams ),
typename std::decay_t<F>::types {} );
821 template <
typename F,
typename U,
template <
typename...>
typename TYPESLIST,
typename... TYPES>
822 void VariableSet::visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> )
const {
824 visitImplHelperUserParam<std::decay_t<F>, U, TYPES>( visitor,
825 std::forward<U>( userParam ) ) );
828 template <
typename F,
typename U,
typename T>
829 void VariableSet::visitImplHelperUserParam( F& visitor, U&& userParams )
const {
830 static_assert( has_visit_callable_with_user_param_v<F, T, U>,
831 "Static visitors must provide a function with profile "
832 "void( const std::string& name, [const ]T[&] value, [const] U&&) for each "
833 "declared visitable type T" );
834 if (
auto variables = existsVariableType<T>(); variables ) {
835 for (
auto& element : *( variables.value() ) ) {
836 visitor( element.first, element.second, std::forward<U>( userParams ) );
841 template <
typename T,
typename F>
843 auto [it, inserted] = m_visitorOperator.insert( makeVisitorOperator<T, F>( f ) );
847 template <
typename T>
849 return m_visitorOperator.find( getVariableVisitTypeIndex<T>() ) != m_visitorOperator.end();
852 template <
typename T,
typename F>
854 auto op = makeVisitorOperator<T, F>( f );
855 m_visitorOperator.insert_or_assign( op.first, op.second );
858 template <
typename T>
860 assert( hasOperator<T>() );
861 auto res = m_visitorOperator.erase( getVariableVisitTypeIndex<T>() ) > 0;
865 template <
typename T,
typename F>
866 struct VariableSet::DynamicVisitor::MakeVisitOperatorHelper<T, F, true> {
867 inline auto makeOperator( F& f ) -> OperatorsStorageType::value_type {
868 return { getVariableVisitTypeIndex<T>(), [&f]( std::any& a, std::any&& userParam ) {
869 auto rp = std::any_cast<std::reference_wrapper<VariableSet::Variable<T>>&>( a );
871 f( p.first, p.second, std::forward<std::any>( userParam ) );
876 template <
typename T,
typename F>
877 struct VariableSet::DynamicVisitor::MakeVisitOperatorHelper<T, F, false> {
878 inline auto makeOperator( F& f ) -> OperatorsStorageType::value_type {
879 return { getVariableVisitTypeIndex<T>(), [&f]( std::any& a, std::any&& ) {
880 auto rp = std::any_cast<std::reference_wrapper<VariableSet::Variable<T>>&>( a );
882 f( p.first, p.second );
887 template <
class T,
class F>
888 inline auto VariableSet::DynamicVisitor::makeVisitorOperator( F& f )
889 -> OperatorsStorageType::value_type {
890 auto opBuilder = MakeVisitOperatorHelper < T, F,
891 std::is_invocable<F, const std::string&, T, std::any&&>::value ||
892 std::is_invocable<F, const std::string&, T&, std::any&&>::value > {};
893 return opBuilder.makeOperator( f );
896 template <
typename F>
899 visitDynamic( visitor );
901 else { visitStatic( visitor ); }
904 template <
typename F,
typename T>
907 visitDynamic( visitor, std::forward<T&>( userParams ) );
909 else { visitStatic( visitor, std::forward<T&>( userParams ) ); }
912 template <
typename F,
typename T>
915 visitDynamic( visitor, std::forward<T&&>( userParams ) );
917 else { visitStatic( visitor, std::forward<T&&>( userParams ) ); }
Base class for dynamically configurable visitors Users can implement this interface to build custom v...
virtual bool accept(const std::type_index &id) const =0
Acceptance function for the visitor.
virtual void operator()(std::any &&in, std::any &&userParam) const =0
Execute a visiting operator on accepted types.
Base class for visitors with configurable per-type callbacks. Visiting will be prepared at running ti...
bool removeOperator()
Remove a visiting operator.
~DynamicVisitor() override=default
allows the class to be derived
bool hasOperator()
Test the existence of an operator associated with a type.
void addOrReplaceOperator(F &&f)
Add or replace a visiting operator.
bool addOperator(F &&f)
Add a visiting operator.
Heterogeneous container storing "Variables", that maps a name (std::string) to a value (of any type T...
auto getStoredTypes() const -> const std::vector< std::type_index > &
Gets the stored data type.
auto getVariable(const std::string &name) const -> T &
get the value of the given variable
typename VariableContainer< T >::iterator VariableHandle
Handle of a variable A handle on a variable with type T is an iterator into the BaseContainer....
auto insertOrAssignVariable(const std::string &name, const T &value) -> std::pair< VariableHandle< T >, bool >
reset (or set if the variable does not exist yet) the value of the variable.
bool isHandleValid(const H &handle) const
Test the validity of a handle.
auto getVariableHandle(const std::string &name) const -> VariableHandle< T >
get the handle on the variable with the given name
bool deleteAllVariables()
Removes all variables of the given type.
auto existsVariable(const std::string &name) const -> Utils::optional< VariableHandle< T >>
test the existence of the given variable
bool deleteVariable(const std::string &name)
Remove a variable, i.e. a name->value association.
typename Variable< T >::second_type VariableType
Type of the variable value.
auto getAllVariables() const -> VariableContainer< T > &
Get the whole container for variables of a given type.
std::map< std::string, T > VariableContainer
Container type for the mapping name->value of variables with type T.
VariableSet(const VariableSet &other) noexcept
A VariableSet is copyable.
typename VariableContainer< T >::value_type Variable
Variable type as stored in the VariableSet.
size_t numberOf() const
Get the number of variables of the given type.
VariableSet(VariableSet &&other) noexcept
A VariableSet is movable.
auto getAllVariablesFromHandle(const H &handle) -> VariableContainer< VariableTypeFromHandle< H >> &
Get the whole container for variables of the same type than the given handled variable.
auto existsVariableType() const -> Utils::optional< VariableContainer< T > * >
Test if the storage supports a given variable type.
auto insertVariable(const std::string &name, const T &value) -> std::pair< VariableHandle< T >, bool >
Add a variable, i.e. an association name->value, into the container.
void visit(F &&visitor) const
Visit the container using a user defined visitor.
typename std::iterator_traits< H >::value_type::second_type VariableTypeFromHandle
Type of the variable referenced by a VariableHandle.
Base class for visitors with static supported types. Visiting will be prepared at compile time by unf...