Radium Engine  1.7.2
Loading...
Searching...
No Matches
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 <algorithm>
11#include <any>
12#include <functional>
13#include <map>
14#include <typeindex>
15#include <unordered_map>
16#include <vector>
17
18namespace Ra {
19namespace Core {
20
21namespace detail {
22template <typename type_t, class orig_t>
23struct unwrap_impl {
24 using type = orig_t;
25};
26
27template <typename type_t, class V>
28struct unwrap_impl<std::reference_wrapper<type_t>, V> {
29 using type = type_t;
30};
31} // namespace detail
32
33template <class T>
34struct unwrap {
35 using type = typename detail::unwrap_impl<std::decay_t<T>, T>::type;
36};
37template <typename type_t>
38using unwrap_t = typename unwrap<type_t>::type;
39
40class DynamicVisitorBase;
41class DynamicVisitor;
42
95class RA_CORE_API VariableSet
96{
97 public:
99 template <typename T>
101
103 template <typename T>
105
107 template <typename T>
109
115 template <typename T>
116 using VariableHandle = typename VariableContainer<T>::iterator;
117
121 template <typename H>
123
124 // ----------------------------------------------------------
127 VariableSet() : m_vtable( VariableSetFunctions::getInstance() ) {}
128 ~VariableSet() = default;
130 VariableSet( const VariableSet& other ) noexcept :
131 m_vtable( VariableSetFunctions::getInstance() ) {
132 *this = other;
133 }
135 VariableSet( VariableSet&& other ) noexcept : m_vtable( VariableSetFunctions::getInstance() ) {
136 *this = std::move( other );
137 }
139
140 // ------------------------------------------------------------------------------------------
141 // Global variable set operation
142 // ------------------------------------------------------------------------------------------
146 auto operator=( const VariableSet& other ) -> VariableSet&;
147
149 auto operator=( VariableSet&& other ) noexcept -> VariableSet&;
150
152 void clear();
153
158 void mergeKeepVariables( const VariableSet& from );
159
164 void mergeReplaceVariables( const VariableSet& from );
165
167 size_t size() const;
168
171 auto getStoredTypes() const -> const std::vector<std::type_index>& { return m_storedType; }
172
174 // ------------------------------------------------------------------------------------------
175 // Per variable operations
176 // ------------------------------------------------------------------------------------------
183 template <typename T>
184 auto insertVariable( const std::string& name, const T& value )
186
191 template <typename T>
192 auto getVariable( const std::string& name ) const -> const T&;
193 template <typename T>
194 auto getVariable( const std::string& name ) -> T&;
195
201 template <typename T>
202 auto getVariableHandle( const std::string& name ) const -> const VariableHandle<T>;
203
208 template <typename H>
209 bool isHandleValid( const H& handle ) const;
210
214 template <typename T>
215 auto setVariable( const std::string& name, const T& value )
217
222 template <typename T>
223 bool deleteVariable( const std::string& name );
224
232 template <typename H>
233 bool deleteVariable( H& handle );
234
238 template <typename T>
239 auto existsVariable( const std::string& name ) const -> Utils::optional<VariableHandle<T>>;
240
242
243 // ------------------------------------------------------------------------------------------
244 // Per type access
245 // ------------------------------------------------------------------------------------------
253 template <typename T>
254 auto existsVariableType() const -> Utils::optional<VariableContainer<T>*>;
255
261 template <typename T>
262 bool deleteAllVariables();
263
269 template <typename T>
270 auto getAllVariables() const -> VariableContainer<T>&;
271
278 template <typename H>
279 auto getAllVariablesFromHandle( const H& handle )
281
285 template <typename T>
286 size_t numberOf() const;
288
291
296 template <typename... TYPES>
298 using types = Utils::TypeList<TYPES...>;
299 };
300
311 template <typename F>
312 void visit( F&& visitor ) const;
313
315 template <typename F, typename T>
316 void visit( F&& visitor, T& userParams ) const;
317
319 template <typename F, typename T>
320 void visit( F&& visitor, T&& userParams ) const;
321
322 private:
346 template <typename P = bool>
347 void visitDynamic( DynamicVisitorBase& visitor, P&& params = P {} ) const;
348
366 template <typename F>
367 void visitStatic( F&& visitor ) const;
368
370 template <typename F, typename T>
371 void visitStatic( F&& visitor, T& userParams ) const;
372
374 template <typename F, typename T>
375 void visitStatic( F&& visitor, T&& userParams ) const;
376
383 template <typename T>
384 static auto getVariableVisitTypeIndex() -> std::type_index;
385 template <typename VariableType>
386 // same but more complex
387 // std::reference_wrapper<std::decay_t<unwrap_t<typename
388 // VariableSet::VariableContainer<VariableType>::mapped_type>>>;
390
396 template <typename T>
397 auto addVariableType() -> Utils::optional<VariableContainer<T>*>;
398
402 template <typename F, typename T>
403 using VisitFunction =
404 decltype( std::declval<F>().operator()( std::declval<const std::string&>(),
405 std::declval<T&>() ) );
406
408 template <typename F, typename T, typename U>
409 using VisitFunctionWithUserParam =
410 decltype( std::declval<F>().operator()( std::declval<const std::string&>(),
412 std::declval<U&&>() ) );
413
415 template <typename F, typename T>
416 static constexpr bool has_visit_callable_v =
417 Ra::Core::Utils::is_detected<VisitFunction, F, T>::value;
418
420 template <typename F, typename T, typename U>
421 static constexpr bool has_visit_callable_with_user_param_v =
422 Ra::Core::Utils::is_detected<VisitFunctionWithUserParam, F, T, U>::value;
423
425 template <typename F, template <typename...> typename TYPESLIST, typename... TYPES>
426 void visitImpl( F&& visitor, TYPESLIST<TYPES...> ) const;
427
428 template <typename F, typename T>
429 void visitImplHelper( F& visitor ) const;
430
432 template <typename F, typename U, template <typename...> typename TYPESLIST, typename... TYPES>
433 void visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> ) const;
434
435 template <typename F, typename U, typename T>
436 void visitImplHelperUserParam( F& visitor, U&& userParams ) const;
437
439
443
445 class VariableSetFunctions
446 {
447 public:
448 using ClearFunctionType = std::function<void( VariableSet& )>;
449 using MergeFunctionType = std::function<void( const VariableSet&, VariableSet& )>;
450 using SizeFunctionType = std::function<size_t( const VariableSet& )>;
451 // Should be these simplified ????
452 using VisitFunctorType =
453 std::function<std::pair<bool, std::function<void( DynamicVisitorBase&, std::any&& )>>(
454 const VariableSet&,
455 const DynamicVisitorBase& )>;
456
457 VariableSetFunctions( const VariableSetFunctions& ) = delete;
458 void operator=( const VariableSetFunctions& ) = delete;
459
460 protected:
461 VariableSetFunctions() = default;
462 ~VariableSetFunctions() = default;
463
464 public:
465 // static variable ref singleton implementation.
466 static auto getInstance() -> VariableSetFunctions*;
467
468 std::vector<MergeFunctionType> m_mergeKeepFunctions;
469 std::vector<MergeFunctionType> m_mergeReplaceFunctions;
470 std::vector<SizeFunctionType> m_sizeFunctions;
471 std::vector<VisitFunctorType> m_visitFunctions;
472 std::vector<std::type_index> m_storedType;
473 };
474
475 VariableSetFunctions* m_vtable;
476
478
481 // Storage of the variable in a type-erased associative container
483 std::unordered_map<std::type_index, size_t> m_typeIndexToVtableIndex;
485 std::vector<std::type_index> m_storedType;
486
490 template <typename T>
491 auto createVariableStorage() -> VariableContainer<T>*;
492
496 template <typename T>
497 auto getVariableStorage() const -> VariableContainer<T>&;
498
501 template <typename T>
502 void removeVariableStorage();
503
505 friend class DynamicVisitor;
506};
507
508// ------------------------------------------------------------------------------------------
509// Storage management
510// ------------------------------------------------------------------------------------------
511
512template <typename T>
513auto VariableSet::createVariableStorage() -> VariableContainer<T>* {
514 m_variables[std::type_index { typeid( T ) }].emplace<VariableContainer<T>>();
515 return std::any_cast<VariableContainer<T>>( &( m_variables[std::type_index { typeid( T ) }] ) );
516}
517
518template <typename T>
519auto VariableSet::getVariableStorage() const -> VariableContainer<T>& {
520 assert( existsVariableType<T>() );
521 return std::any_cast<VariableContainer<T>&>( m_variables[std::type_index { typeid( T ) }] );
522}
523
524template <typename T>
525void VariableSet::removeVariableStorage() {
526 auto type = std::type_index { typeid( T ) };
527 m_variables.erase( type );
528 m_typeIndexToVtableIndex.erase( type );
529
530 auto newEnd = std::remove( m_storedType.begin(), m_storedType.end(), type );
531 m_storedType.erase( newEnd, m_storedType.end() );
532}
533
534// ------------------------------------------------------------------------------------------
535// Templated methods definition
536// ------------------------------------------------------------------------------------------
537template <typename T>
538auto VariableSet::insertVariable( const std::string& name, const T& value )
540 auto typeAccess = existsVariableType<T>();
541 // If it is the first parameter of the given type, first register the type
542 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
543 // insert the parameter.
544 return ( *typeAccess )->insert( { name, value } );
545}
546
547template <typename T>
548auto VariableSet::getVariable( const std::string& name ) -> T& {
549 return const_cast<T&>( const_cast<const VariableSet*>( this )->getVariable<T>( name ) );
550}
551
552template <typename T>
553auto VariableSet::getVariable( const std::string& name ) const -> const T& {
554 return getVariableHandle<T>( name )->second;
555}
556
557template <typename T>
558auto VariableSet::getVariableHandle( const std::string& name ) const -> const VariableHandle<T> {
559 assert( existsVariableType<T>() );
560 return getVariableStorage<T>().find( name );
561}
562
563template <typename H>
564bool VariableSet::isHandleValid( const H& handle ) const {
565 if ( !existsVariableType<VariableTypeFromHandle<H>>() ) { return false; }
566 return handle != getVariableStorage<VariableTypeFromHandle<H>>().end();
567}
568
569template <typename T>
570auto VariableSet::setVariable( const std::string& name, const T& value )
572 auto typeAccess = existsVariableType<T>();
573 // If it is the first parameter of the given type, first register the type
574 if ( !typeAccess ) { typeAccess = addVariableType<T>(); }
575 // insert the parameter.
576
577 return ( *typeAccess )->insert_or_assign( name, value );
578}
579
580template <typename T>
581bool VariableSet::deleteVariable( const std::string& name ) {
582 if ( auto typeAccess = existsVariableType<T>(); typeAccess ) {
583 auto removed = ( *typeAccess )->erase( name );
584 // remove the type related function when the container has no more data of this type
585 if ( numberOf<T>() == 0 ) { deleteAllVariables<T>(); }
586 return removed > 0;
587 }
588 return false;
589}
590
591template <typename H>
592bool VariableSet::deleteVariable( H& handle ) {
593 assert( isHandleValid( handle ) );
594 auto varname = handle->first;
595 handle = getVariableStorage<VariableTypeFromHandle<H>>().end();
596 return deleteVariable<VariableTypeFromHandle<H>>( varname );
597}
598
599template <typename T>
600auto VariableSet::existsVariable( const std::string& name ) const
601 -> Utils::optional<VariableHandle<T>> {
602 if ( auto typeAccess = existsVariableType<T>(); typeAccess ) {
603 auto itr = ( *typeAccess )->find( name );
604 if ( itr != ( *typeAccess )->cend() ) { return itr; }
605 }
606 return {};
607}
608
609template <typename T>
610auto VariableSet::getVariableVisitTypeIndex() -> std::type_index {
611 static std::type_index idT( typeid( VisitTypeIndex<T> ) );
612 return idT;
613}
614template <typename T>
615auto VariableSet::addVariableType() -> Utils::optional<VariableContainer<T>*> {
616 auto storage = createVariableStorage<T>();
617
618 auto tidx = std::type_index( typeid( T ) );
619 auto it = std::find( m_vtable->m_storedType.begin(), m_vtable->m_storedType.end(), tidx );
620
621 // remember the stored type and its rank for the instance
622 m_typeIndexToVtableIndex[tidx] = it - m_vtable->m_storedType.begin();
623 m_storedType.push_back( tidx );
624
625 // If the type is not already there, add type operations and identifier in the global vtable
626 if ( it == m_vtable->m_storedType.end() ) {
627 // remember the stored type in the global vtable
628 m_vtable->m_storedType.emplace_back( tidx );
629 // used to merge (keep) the stored data from container "from" to container "to"
630 m_vtable->m_mergeKeepFunctions.emplace_back(
631 []( const VariableSet& from, VariableSet& to ) {
632 auto toStorageAccess = to.existsVariableType<T>();
633 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
634 auto& toStorage = *( toStorageAccess.value() );
635 auto& fromStorage = from.getVariableStorage<T>();
636 for ( const auto& t : fromStorage ) {
637 toStorage.insert( t );
638 }
639 } );
640 // used to merge (replace) the stored data from container "from" to container "to"
641 m_vtable->m_mergeReplaceFunctions.emplace_back(
642 []( const VariableSet& from, VariableSet& to ) {
643 auto toStorageAccess = to.existsVariableType<T>();
644 if ( !toStorageAccess ) { toStorageAccess = to.addVariableType<T>(); }
645 auto& toStorage = *( toStorageAccess.value() );
646 auto& fromStorage = from.getVariableStorage<T>();
647 for ( const auto& t : fromStorage ) {
648 toStorage.insert_or_assign( t.first, t.second );
649 }
650 } );
651 // use to compute gauge on the stored data
652 m_vtable->m_sizeFunctions.emplace_back( []( const VariableSet& c ) {
653 if ( auto cs = c.existsVariableType<T>(); cs ) return ( *cs )->size();
654 return size_t { 0 }; // use 0uz when c++23
655 } );
656 // used to visit the variableSet with a dynamic visitor
657 m_vtable->m_visitFunctions.emplace_back(
658 []( const VariableSet& c, const DynamicVisitorBase& v )
659 -> std::pair<bool, std::function<void( DynamicVisitorBase&, std::any&& )>> {
660 auto id = getVariableVisitTypeIndex<T>();
661 if ( v.accept( id ) ) {
662 auto coll = std::ref( c.getVariableStorage<T>() );
663 return { true, [coll]( DynamicVisitorBase& visitor, std::any&& userParam ) {
664 for ( auto&& t : coll.get() ) {
665 visitor( t.first,
666 std::any { std::ref( t.second ) },
667 std::forward<std::any>( userParam ) );
668 }
669 } };
670 }
671 else { return { false, nullptr }; }
672 } );
673 }
674 return storage;
675}
676
677template <typename T>
678auto VariableSet::existsVariableType() const -> Utils::optional<VariableContainer<T>*> {
679 auto iter = m_variables.find( std::type_index { typeid( T ) } );
680 if ( iter == m_variables.cend() ) { return {}; }
681 else { return std::any_cast<VariableSet::VariableContainer<T>>( &( iter->second ) ); }
682}
683
684template <typename T>
685bool VariableSet::deleteAllVariables() {
686 if ( existsVariableType<T>() ) {
687 removeVariableStorage<T>();
688 return true;
689 }
690 return false;
691}
692
693template <typename T>
694auto VariableSet::getAllVariables() const -> VariableContainer<T>& {
695 // just assert on the existence of the type to prevent undefined behavior when dereferencing
696 // the optional
697 assert( existsVariableType<T>() );
698 // trows std::bad_any_cast if type does not exist
699 return getVariableStorage<T>();
700}
701
702template <typename H>
703auto VariableSet::getAllVariablesFromHandle( const H& )
705 assert( existsVariableType<VariableTypeFromHandle<H>>() );
706 return getVariableStorage<VariableTypeFromHandle<H>>();
707}
708
709template <typename T>
710size_t VariableSet::numberOf() const {
711 if ( auto variables = existsVariableType<T>(); variables ) { return ( *variables )->size(); }
712 return 0;
713}
714
715/* --------------- Visitors */
716
717template <typename P>
718void VariableSet::visitDynamic( DynamicVisitorBase& visitor, P&& params ) const {
719 for ( const auto& [type, index] : m_typeIndexToVtableIndex ) {
720 auto [accepted, loop] = m_vtable->m_visitFunctions[index]( *this, visitor );
721 if ( accepted ) { loop( visitor, std::forward<P>( params ) ); }
722 }
723}
724
725template <typename F>
726void VariableSet::visitStatic( F&& visitor ) const {
727 visitImpl( visitor, typename std::decay_t<F>::types {} );
728}
729
730template <typename F, template <typename...> typename TYPESLIST, typename... TYPES>
731void VariableSet::visitImpl( F&& visitor, TYPESLIST<TYPES...> ) const {
732 ( ..., visitImplHelper<std::decay_t<F>, TYPES>( visitor ) );
733}
734
735template <typename F, typename T>
736void VariableSet::visitImplHelper( F& visitor ) const {
737 static_assert( has_visit_callable_v<F, T>,
738 "Static visitors must provide a function with profile "
739 "void( const std::string& name, [const ]T[&] value) for each "
740 "declared visitable type T" );
741 if ( auto variables = existsVariableType<T>() ) {
742 for ( auto& element : *( variables.value() ) ) {
743 visitor( element.first, element.second );
744 }
745 }
746 if ( auto variables = existsVariableType<std::reference_wrapper<T>>(); variables ) {
747 for ( auto& element : *( variables.value() ) ) {
748 visitor( element.first, element.second.get() );
749 }
750 }
751}
752
753template <typename F, typename U>
754void VariableSet::visitStatic( F&& visitor, U& userParams ) const {
755 visitImplUserParam(
756 visitor, std::forward<U>( userParams ), typename std::decay_t<F>::types {} );
757}
758
759template <typename F, typename U>
760void VariableSet::visitStatic( F&& visitor, U&& userParams ) const {
761 visitImplUserParam(
762 visitor, std::forward<U>( userParams ), typename std::decay_t<F>::types {} );
763}
764
765template <typename F, typename U, template <typename...> typename TYPESLIST, typename... TYPES>
766void VariableSet::visitImplUserParam( F&& visitor, U&& userParam, TYPESLIST<TYPES...> ) const {
767 ( ...,
768 visitImplHelperUserParam<std::decay_t<F>, U, TYPES>( visitor,
769 std::forward<U>( userParam ) ) );
770}
771
772template <typename F, typename U, typename T>
773void VariableSet::visitImplHelperUserParam( F& visitor, U&& userParams ) const {
774 static_assert( has_visit_callable_with_user_param_v<F, T, U>,
775 "Static visitors must provide a function with profile "
776 "void( const std::string& name, [const ]T[&] value, [const] U&&) for each "
777 "declared visitable type T" );
778 if ( auto variables = existsVariableType<T>(); variables ) {
779 for ( auto& element : *( variables.value() ) ) {
780 visitor( element.first, element.second, std::forward<U>( userParams ) );
781 }
782 }
783 if ( auto variables = existsVariableType<std::reference_wrapper<T>>(); variables ) {
784 for ( auto& element : *( variables.value() ) ) {
785 visitor( element.first, element.second.get(), std::forward<U>( userParams ) );
786 }
787 }
788}
789
790template <typename F>
791inline void VariableSet::visit( F&& visitor ) const {
793 visitDynamic( visitor );
794 }
795 else { visitStatic( visitor ); }
796}
797
798template <typename F, typename T>
799inline void VariableSet::visit( F&& visitor, T& userParams ) const {
801 visitDynamic( visitor, std::forward<T&>( userParams ) );
802 }
803 else { visitStatic( visitor, std::forward<T&>( userParams ) ); }
804}
805
806template <typename F, typename T>
807inline void VariableSet::visit( F&& visitor, T&& userParams ) const {
809 visitDynamic( visitor, std::forward<T&&>( userParams ) );
810 }
811 else { visitStatic( visitor, std::forward<T&&>( userParams ) ); }
812}
813
814} // namespace Core
815} // 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...