Loading [MathJax]/extensions/TeX/AMSmath.js
Radium Engine  1.5.24
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VariableSet.hpp
1#pragma once
2#include <Core/RaCore.hpp>
3
4#include <Core/Containers/DynamicVisitorBase.hpp>
5#include <Core/Utils/Log.hpp>
6#include <Core/Utils/StdExperimentalTypeTraits.hpp>
7#include <Core/Utils/StdOptional.hpp>
8#include <Core/Utils/TypesUtils.hpp>
9
10#include <any>
11#include <functional>
12#include <map>
13#include <typeindex>
14#include <unordered_map>
15#include <vector>
16
17namespace Ra {
18namespace Core {
19
20namespace detail {
21template <typename type_t, class orig_t>
22struct unwrap_impl {
23 using type = orig_t;
24};
25
26template <typename type_t, class V>
27struct unwrap_impl<std::reference_wrapper<type_t>, V> {
28 using type = type_t;
29};
30} // namespace detail
31
32template <class T>
33struct unwrap {
34 using type = typename detail::unwrap_impl<std::decay_t<T>, T>::type;
35};
36template <typename type_t>
37using unwrap_t = typename unwrap<type_t>::type;
38
39class DynamicVisitorBase;
40class DynamicVisitor;
41
94class RA_CORE_API VariableSet
95{
96 public:
98 template <typename T>
100
102 template <typename T>
104
106 template <typename T>
108
114 template <typename T>
115 using VariableHandle = typename VariableContainer<T>::iterator;
116
120 template <typename H>
122
123 // ----------------------------------------------------------
126 VariableSet() : m_vtable( VariableSetFunctions::getInstance() ) {}
127 ~VariableSet() = default;
129 VariableSet( const VariableSet& other ) noexcept :
130 m_vtable( VariableSetFunctions::getInstance() ) {
131 *this = other;
132 }
134 VariableSet( VariableSet&& other ) noexcept : m_vtable( VariableSetFunctions::getInstance() ) {
135 *this = std::move( other );
136 }
138
139 // ------------------------------------------------------------------------------------------
140 // Global variable set operation
141 // ------------------------------------------------------------------------------------------
145 auto operator=( const VariableSet& other ) -> VariableSet&;
146
148 auto operator=( VariableSet&& other ) noexcept -> VariableSet&;
149
151 void clear();
152
157 void mergeKeepVariables( const VariableSet& from );
158
163 void mergeReplaceVariables( const VariableSet& from );
164
166 size_t size() const;
167
170 auto getStoredTypes() const -> const std::vector<std::type_index>& { return m_storedType; }
171
173 // ------------------------------------------------------------------------------------------
174 // Per variable operations
175 // ------------------------------------------------------------------------------------------
182 template <typename T>
183 auto insertVariable( const std::string& name, const T& value )
185
190 template <typename T>
191 auto getVariable( const std::string& name ) const -> const T&;
192 template <typename T>
193 auto getVariable( const std::string& name ) -> T&;
194
200 template <typename T>
201 auto getVariableHandle( const std::string& name ) const -> const VariableHandle<T>;
202
207 template <typename H>
208 bool isHandleValid( const H& handle ) const;
209
213 template <typename T>
214 auto setVariable( const std::string& name, const T& value )
216
221 template <typename T>
222 bool deleteVariable( const std::string& name );
223
231 template <typename H>
232 bool deleteVariable( H& handle );
233
237 template <typename T>
238 auto existsVariable( const std::string& name ) const -> Utils::optional<VariableHandle<T>>;
239
241
242 // ------------------------------------------------------------------------------------------
243 // Per type access
244 // ------------------------------------------------------------------------------------------
252 template <typename T>
253 auto existsVariableType() const -> Utils::optional<VariableContainer<T>*>;
254
260 template <typename T>
261 bool deleteAllVariables();
262
268 template <typename T>
269 auto getAllVariables() const -> VariableContainer<T>&;
270
277 template <typename H>
278 auto getAllVariablesFromHandle( const H& handle )
280
284 template <typename T>
285 size_t numberOf() const;
287
290
295 template <typename... TYPES>
297 using types = Utils::TypeList<TYPES...>;
298 };
299
310 template <typename F>
311 void visit( F&& visitor ) const;
312
314 template <typename F, typename T>
315 void visit( F&& visitor, T& userParams ) const;
316
318 template <typename F, typename T>
319 void visit( F&& visitor, T&& userParams ) const;
320
321 private:
345 template <typename P = bool>
346 void visitDynamic( DynamicVisitorBase& visitor, P&& params = P {} ) const;
347
365 template <typename F>
366 void visitStatic( F&& visitor ) const;
367
369 template <typename F, typename T>
370 void visitStatic( F&& visitor, T& userParams ) const;
371
373 template <typename F, typename T>
374 void visitStatic( F&& visitor, T&& userParams ) const;
375
382 template <typename T>
383 static auto getVariableVisitTypeIndex() -> std::type_index;
384 template <typename VariableType>
385 // same but more complex
386 // std::reference_wrapper<std::decay_t<unwrap_t<typename
387 // VariableSet::VariableContainer<VariableType>::mapped_type>>>;
389
395 template <typename T>
396 auto addVariableType() -> Utils::optional<VariableContainer<T>*>;
397
401 template <typename F, typename T>
402 using VisitFunction =
403 decltype( std::declval<F>().operator()( std::declval<const std::string&>(),
404 std::declval<T&>() ) );
405
407 template <typename F, typename T, typename U>
408 using VisitFunctionWithUserParam =
409 decltype( std::declval<F>().operator()( std::declval<const std::string&>(),
411 std::declval<U&&>() ) );
412
414 template <typename F, typename T>
415 static constexpr bool has_visit_callable_v =
416 Ra::Core::Utils::is_detected<VisitFunction, F, T>::value;
417
419 template <typename F, typename T, typename U>
420 static constexpr bool has_visit_callable_with_user_param_v =
421 Ra::Core::Utils::is_detected<VisitFunctionWithUserParam, F, T, U>::value;
422
424 template <typename F, template <typename...> typename TYPESLIST, typename... TYPES>
425 void visitImpl( F&& visitor, TYPESLIST<TYPES...> ) const;
426
427 template <typename F, typename T>
428 void visitImplHelper( F& visitor ) const;
429
431 template <typename F, typename U, template <typename...> typename TYPESLIST, typename... TYPES>
432 void visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> ) const;
433
434 template <typename F, typename U, typename T>
435 void visitImplHelperUserParam( F& visitor, U&& userParams ) const;
436
438
442
444 class VariableSetFunctions
445 {
446 public:
447 using ClearFunctionType = std::function<void( VariableSet& )>;
448 using MergeFunctionType = std::function<void( const VariableSet&, VariableSet& )>;
449 using SizeFunctionType = std::function<size_t( const VariableSet& )>;
450 // Should be these simplified ????
451 using VisitFunctorType =
452 std::function<std::pair<bool, std::function<void( DynamicVisitorBase&, std::any&& )>>(
453 const VariableSet&,
454 const DynamicVisitorBase& )>;
455
456 VariableSetFunctions( const VariableSetFunctions& ) = delete;
457 void operator=( const VariableSetFunctions& ) = delete;
458
459 protected:
460 VariableSetFunctions() = default;
461 ~VariableSetFunctions() = default;
462
463 public:
464 // static variable ref singleton implementation.
465 static auto getInstance() -> VariableSetFunctions*;
466
467 std::vector<MergeFunctionType> m_mergeKeepFunctions;
468 std::vector<MergeFunctionType> m_mergeReplaceFunctions;
469 std::vector<SizeFunctionType> m_sizeFunctions;
470 std::vector<VisitFunctorType> m_visitFunctions;
471 std::vector<std::type_index> m_storedType;
472 };
473
474 VariableSetFunctions* m_vtable;
475
477
480 // Storage of the variable in a type-erased associative container
482 std::unordered_map<std::type_index, size_t> m_typeIndexToVtableIndex;
484 std::vector<std::type_index> m_storedType;
485
489 template <typename T>
490 auto createVariableStorage() -> VariableContainer<T>*;
491
495 template <typename T>
496 auto getVariableStorage() const -> VariableContainer<T>&;
497
500 template <typename T>
501 void removeVariableStorage();
502
504 friend class DynamicVisitor;
505};
506
507// ------------------------------------------------------------------------------------------
508// Storage management
509// ------------------------------------------------------------------------------------------
510
511template <typename T>
512auto VariableSet::createVariableStorage() -> VariableContainer<T>* {
513 m_variables[std::type_index { typeid( T ) }].emplace<VariableContainer<T>>();
514 return std::any_cast<VariableContainer<T>>( &( m_variables[std::type_index { typeid( T ) }] ) );
515}
516
517template <typename T>
518auto VariableSet::getVariableStorage() const -> VariableContainer<T>& {
519 assert( existsVariableType<T>() );
520 return std::any_cast<VariableContainer<T>&>( m_variables[std::type_index { typeid( T ) }] );
521}
522
523template <typename T>
524void VariableSet::removeVariableStorage() {
525 auto type = std::type_index { typeid( T ) };
526 m_variables.erase( type );
527 m_typeIndexToVtableIndex.erase( type );
528
529 auto newEnd = std::remove( m_storedType.begin(), m_storedType.end(), type );
530 m_storedType.erase( newEnd, m_storedType.end() );
531}
532
533// ------------------------------------------------------------------------------------------
534// Templated methods definition
535// ------------------------------------------------------------------------------------------
536template <typename T>
537auto VariableSet::insertVariable( const std::string& name, const T& value )
539 auto typeAccess = existsVariableType<T>();
540 // If it is the first parameter of the given type, first register the type
541 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
542 // insert the parameter.
543 return ( *typeAccess )->insert( { name, value } );
544}
545
546template <typename T>
547auto VariableSet::getVariable( const std::string& name ) -> T& {
548 return const_cast<T&>( const_cast<const VariableSet*>( this )->getVariable<T>( name ) );
549}
550
551template <typename T>
552auto VariableSet::getVariable( const std::string& name ) const -> const T& {
553 return getVariableHandle<T>( name )->second;
554}
555
556template <typename T>
557auto VariableSet::getVariableHandle( const std::string& name ) const -> const VariableHandle<T> {
558 assert( existsVariableType<T>() );
559 return getVariableStorage<T>().find( name );
560}
561
562template <typename H>
563bool VariableSet::isHandleValid( const H& handle ) const {
564 if ( !existsVariableType<VariableTypeFromHandle<H>>() ) { return false; }
565 return handle != getVariableStorage<VariableTypeFromHandle<H>>().end();
566}
567
568template <typename T>
569auto VariableSet::setVariable( const std::string& name, const T& value )
571 auto typeAccess = existsVariableType<T>();
572 // If it is the first parameter of the given type, first register the type
573 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
574 // insert the parameter.
575
576 return ( *typeAccess )->insert_or_assign( name, value );
577}
578
579template <typename T>
580bool VariableSet::deleteVariable( const std::string& name ) {
581 if ( auto typeAccess = existsVariableType<T>(); typeAccess ) {
582 auto removed = ( *typeAccess )->erase( name );
583 // remove the type related function when the container has no more data of this type
584 if ( numberOf<T>() == 0 ) { deleteAllVariables<T>(); }
585 return removed > 0;
586 }
587 return false;
588}
589
590template <typename H>
591bool VariableSet::deleteVariable( H& handle ) {
592 assert( isHandleValid( handle ) );
593 auto varname = handle->first;
594 handle = getVariableStorage<VariableTypeFromHandle<H>>().end();
595 return deleteVariable<VariableTypeFromHandle<H>>( varname );
596}
597
598template <typename T>
599auto VariableSet::existsVariable( const std::string& name ) const
600 -> Utils::optional<VariableHandle<T>> {
601 if ( auto typeAccess = existsVariableType<T>(); typeAccess ) {
602 auto itr = ( *typeAccess )->find( name );
603 if ( itr != ( *typeAccess )->cend() ) { return itr; }
604 }
605 return {};
606}
607
608template <typename T>
609auto VariableSet::getVariableVisitTypeIndex() -> std::type_index {
610 static std::type_index idT( typeid( VisitTypeIndex<T> ) );
611 return idT;
612}
613template <typename T>
614auto VariableSet::addVariableType() -> Utils::optional<VariableContainer<T>*> {
615 auto storage = createVariableStorage<T>();
616
617 auto tidx = std::type_index( typeid( T ) );
618 auto it = std::find( m_vtable->m_storedType.begin(), m_vtable->m_storedType.end(), tidx );
619
620 // remember the stored type and its rank for the instance
621 m_typeIndexToVtableIndex[tidx] = it - m_vtable->m_storedType.begin();
622 m_storedType.push_back( tidx );
623
624 // If the type is not already there, add type operations and identifier in the global vtable
625 if ( it == m_vtable->m_storedType.end() ) {
626 // remember the stored type in the global vtable
627 m_vtable->m_storedType.emplace_back( tidx );
628 // used to merge (keep) the stored data from container "from" to container "to"
629 m_vtable->m_mergeKeepFunctions.emplace_back(
630 []( const VariableSet& from, VariableSet& to ) {
631 auto toStorageAccess = to.existsVariableType<T>();
632 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
633 auto& toStorage = *( toStorageAccess.value() );
634 auto& fromStorage = from.getVariableStorage<T>();
635 for ( const auto& t : fromStorage ) {
636 toStorage.insert( t );
637 }
638 } );
639 // used to merge (replace) the stored data from container "from" to container "to"
640 m_vtable->m_mergeReplaceFunctions.emplace_back(
641 []( const VariableSet& from, VariableSet& to ) {
642 auto toStorageAccess = to.existsVariableType<T>();
643 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
644 auto& toStorage = *( toStorageAccess.value() );
645 auto& fromStorage = from.getVariableStorage<T>();
646 for ( const auto& t : fromStorage ) {
647 toStorage.insert_or_assign( t.first, t.second );
648 }
649 } );
650 // use to compute gauge on the stored data
651 m_vtable->m_sizeFunctions.emplace_back( []( const VariableSet& c ) {
652 if ( auto cs = c.existsVariableType<T>(); cs ) return ( *cs )->size();
653 return size_t { 0 }; // use 0uz when c++23
654 } );
655 // used to visit the variableSet with a dynamic visitor
656 m_vtable->m_visitFunctions.emplace_back(
657 []( const VariableSet& c, const DynamicVisitorBase& v )
658 -> std::pair<bool, std::function<void( DynamicVisitorBase&, std::any&& )>> {
659 auto id = getVariableVisitTypeIndex<T>();
660 if ( v.accept( id ) ) {
661 auto coll = std::ref( c.getVariableStorage<T>() );
662 return { true, [coll]( DynamicVisitorBase& visitor, std::any&& userParam ) {
663 for ( auto&& t : coll.get() ) {
664 visitor( t.first,
665 std::any { std::ref( t.second ) },
666 std::forward<std::any>( userParam ) );
667 }
668 } };
669 }
670 else { return { false, nullptr }; }
671 } );
672 }
673 return storage;
674}
675
676template <typename T>
677auto VariableSet::existsVariableType() const -> Utils::optional<VariableContainer<T>*> {
678 auto iter = m_variables.find( std::type_index { typeid( T ) } );
679 if ( iter == m_variables.cend() ) { return {}; }
680 else { return std::any_cast<VariableSet::VariableContainer<T>>( &( iter->second ) ); }
681}
682
683template <typename T>
684bool VariableSet::deleteAllVariables() {
685 if ( existsVariableType<T>() ) {
686 removeVariableStorage<T>();
687 return true;
688 }
689 return false;
690}
691
692template <typename T>
693auto VariableSet::getAllVariables() const -> VariableContainer<T>& {
694 // just assert on the existence of the type to prevent undefined behavior when dereferencing
695 // the optional
696 assert( existsVariableType<T>() );
697 // trows std::bad_any_cast if type does not exist
698 return getVariableStorage<T>();
699}
700
701template <typename H>
702auto VariableSet::getAllVariablesFromHandle( const H& )
704 assert( existsVariableType<VariableTypeFromHandle<H>>() );
705 return getVariableStorage<VariableTypeFromHandle<H>>();
706}
707
708template <typename T>
709size_t VariableSet::numberOf() const {
710 if ( auto variables = existsVariableType<T>(); variables ) { return ( *variables )->size(); }
711 return 0;
712}
713
714/* --------------- Visitors */
715
716template <typename P>
717void VariableSet::visitDynamic( DynamicVisitorBase& visitor, P&& params ) const {
718 for ( const auto& [type, index] : m_typeIndexToVtableIndex ) {
719 auto [accepted, loop] = m_vtable->m_visitFunctions[index]( *this, visitor );
720 if ( accepted ) { loop( visitor, std::forward<P>( params ) ); }
721 }
722}
723
724template <typename F>
725void VariableSet::visitStatic( F&& visitor ) const {
726 visitImpl( visitor, typename std::decay_t<F>::types {} );
727}
728
729template <typename F, template <typename...> typename TYPESLIST, typename... TYPES>
730void VariableSet::visitImpl( F&& visitor, TYPESLIST<TYPES...> ) const {
731 ( ..., visitImplHelper<std::decay_t<F>, TYPES>( visitor ) );
732}
733
734template <typename F, typename T>
735void VariableSet::visitImplHelper( F& visitor ) const {
736 static_assert( has_visit_callable_v<F, T>,
737 "Static visitors must provide a function with profile "
738 "void( const std::string& name, [const ]T[&] value) for each "
739 "declared visitable type T" );
740 if ( auto variables = existsVariableType<T>() ) {
741 for ( auto& element : *( variables.value() ) ) {
742 visitor( element.first, element.second );
743 }
744 }
745 if ( auto variables = existsVariableType<std::reference_wrapper<T>>(); variables ) {
746 for ( auto& element : *( variables.value() ) ) {
747 visitor( element.first, element.second.get() );
748 }
749 }
750}
751
752template <typename F, typename U>
753void VariableSet::visitStatic( F&& visitor, U& userParams ) const {
754 visitImplUserParam(
755 visitor, std::forward<U>( userParams ), typename std::decay_t<F>::types {} );
756}
757
758template <typename F, typename U>
759void VariableSet::visitStatic( F&& visitor, U&& userParams ) const {
760 visitImplUserParam(
761 visitor, std::forward<U>( userParams ), typename std::decay_t<F>::types {} );
762}
763
764template <typename F, typename U, template <typename...> typename TYPESLIST, typename... TYPES>
765void VariableSet::visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> ) const {
766 ( ...,
767 visitImplHelperUserParam<std::decay_t<F>, U, TYPES>( visitor,
768 std::forward<U>( userParam ) ) );
769}
770
771template <typename F, typename U, typename T>
772void VariableSet::visitImplHelperUserParam( F& visitor, U&& userParams ) const {
773 static_assert( has_visit_callable_with_user_param_v<F, T, U>,
774 "Static visitors must provide a function with profile "
775 "void( const std::string& name, [const ]T[&] value, [const] U&&) for each "
776 "declared visitable type T" );
777 if ( auto variables = existsVariableType<T>(); variables ) {
778 for ( auto& element : *( variables.value() ) ) {
779 visitor( element.first, element.second, std::forward<U>( userParams ) );
780 }
781 }
782 if ( auto variables = existsVariableType<std::reference_wrapper<T>>(); variables ) {
783 for ( auto& element : *( variables.value() ) ) {
784 visitor( element.first, element.second.get(), std::forward<U>( userParams ) );
785 }
786 }
787}
788
789template <typename F>
790inline void VariableSet::visit( F&& visitor ) const {
792 visitDynamic( visitor );
793 }
794 else { visitStatic( visitor ); }
795}
796
797template <typename F, typename T>
798inline void VariableSet::visit( F&& visitor, T& userParams ) const {
800 visitDynamic( visitor, std::forward<T&>( userParams ) );
801 }
802 else { visitStatic( visitor, std::forward<T&>( userParams ) ); }
803}
804
805template <typename F, typename T>
806inline void VariableSet::visit( F&& visitor, T&& userParams ) const {
808 visitDynamic( visitor, std::forward<T&&>( userParams ) );
809 }
810 else { visitStatic( visitor, std::forward<T&&>( userParams ) ); }
811}
812
813} // namespace Core
814} // namespace Ra
T begin(T... args)
Base class for dynamically configurable visitors Users can implement this interface to build custom v...
Base class for visitors with configurable per-type callbacks. Visiting will be prepared at running ti...
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.
typename VariableContainer< T >::iterator VariableHandle
Handle of a variable A handle on a variable with type T is an iterator into the BaseContainer....
typename Variable< T >::second_type VariableType
Type of the variable value.
VariableSet(const VariableSet &other) noexcept
A VariableSet is copyable.
typename VariableContainer< T >::value_type Variable
Variable type as stored in the VariableSet.
VariableSet(VariableSet &&other) noexcept
A VariableSet is movable.
auto getVariable(const std::string &name) const -> const T &
get the value of the given variable
auto existsVariableType() const -> Utils::optional< VariableContainer< T > * >
Test if the storage supports a given variable type.
typename std::iterator_traits< H >::value_type::second_type VariableTypeFromHandle
Type of the variable referenced by a VariableHandle.
T declval(T... args)
T emplace(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T forward(T... args)
T move(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:4
STL namespace.
T push_back(T... args)
T ref(T... args)
T remove(T... args)
Base class for visitors with static supported types. Visiting will be prepared at compile time by unf...