refactor: limit magic paths use - #4102
Open
kdrienCG wants to merge 5 commits into
Open
Conversation
kdrienCG
requested review from
MelReyCG,
OmarDuran,
acitrain,
bd713,
corbett5,
cssherman,
dkachuma,
frankfeifan,
jafranc,
jhuang2601,
joshua-white,
rrsettgast,
sframba,
tjb-ltk and
wrtobin
as code owners
July 23, 2026 15:27
kdrienCG
marked this pull request as draft
July 23, 2026 15:28
kdrienCG
marked this pull request as ready for review
July 23, 2026 15:37
MelReyCG
requested changes
Aug 3, 2026
| /** | ||
| * @struct GlobalViewKeys | ||
| */ | ||
| struct GlobalViewKeys |
Contributor
There was a problem hiding this comment.
Suggested change
| struct GlobalViewKeys | |
| struct ProblemViewKeys |
| struct GlobalViewKeys | ||
| { | ||
| /// @return Root problem group name | ||
| static constexpr char const * problem() { return "Problem"; } |
Contributor
There was a problem hiding this comment.
Suggested change
| static constexpr char const * problem() { return "Problem"; } | |
| static constexpr char const * problemManager() { return "Problem"; } |
Comment on lines
+30
to
+32
| /** | ||
| * @struct GlobalViewKeys | ||
| */ |
Contributor
There was a problem hiding this comment.
Suggested change
| /** | |
| * @struct GlobalViewKeys | |
| */ | |
| /** | |
| * @brief All root data-repository view-keys of a given GEOS problem. | |
| */ |
Comment on lines
+16
to
+135
| /** | ||
| * @file ProblemManagerBase.hpp | ||
| */ | ||
|
|
||
| #ifndef GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ | ||
| #define GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ | ||
|
|
||
| #include "dataRepository/Group.hpp" | ||
|
|
||
| namespace geos | ||
| { | ||
|
|
||
| class DomainPartition; | ||
| class EventManager; | ||
| class ExternalDataSourceManager; | ||
| class FieldSpecificationManager; | ||
| class FunctionManager; | ||
| class GeometricObjectManager; | ||
| class MeshManager; | ||
| class NumericalMethodsManager; | ||
| class OutputManager; | ||
| class PhysicsSolverManager; | ||
| class TasksManager; | ||
| namespace constitutive | ||
| { | ||
| class ConstitutiveManager; | ||
| } | ||
|
|
||
| namespace dataRepository | ||
| { | ||
|
|
||
|
|
||
| /** | ||
| * @class ProblemManagerBase | ||
| */ | ||
| class ProblemManagerBase : public Group | ||
| { | ||
| public: | ||
|
|
||
| using Group::Group; | ||
|
|
||
| virtual DomainPartition & getDomainPartition() = 0; | ||
| virtual DomainPartition const & getDomainPartition() const = 0; | ||
|
|
||
| virtual constitutive::ConstitutiveManager & getConstitutiveManager() = 0; | ||
| virtual constitutive::ConstitutiveManager const & getConstitutiveManager() const = 0; | ||
|
|
||
| virtual EventManager & getEventManager() = 0; | ||
| virtual EventManager const & getEventManager() const = 0; | ||
|
|
||
| virtual ExternalDataSourceManager & getExternalDataSourceManager() = 0; | ||
| virtual ExternalDataSourceManager const & getExternalDataSourceManager() const = 0; | ||
|
|
||
| virtual FieldSpecificationManager & getFieldSpecificationManager() = 0; | ||
| virtual FieldSpecificationManager const & getFieldSpecificationManager() const = 0; | ||
|
|
||
| virtual FunctionManager & getFunctionManager() = 0; | ||
| virtual FunctionManager const & getFunctionManager() const = 0; | ||
|
|
||
| virtual GeometricObjectManager & getGeometricObjectManager() = 0; | ||
| virtual GeometricObjectManager const & getGeometricObjectManager() const = 0; | ||
|
|
||
| virtual MeshManager & getMeshManager() = 0; | ||
| virtual MeshManager const & getMeshManager() const = 0; | ||
|
|
||
| virtual NumericalMethodsManager & getNumericalMethodsManager() = 0; | ||
| virtual NumericalMethodsManager const & getNumericalMethodsManager() const = 0; | ||
|
|
||
| virtual OutputManager & getOutputManager() = 0; | ||
| virtual OutputManager const & getOutputManager() const = 0; | ||
|
|
||
| virtual PhysicsSolverManager & getPhysicsSolverManager() = 0; | ||
| virtual PhysicsSolverManager const & getPhysicsSolverManager() const = 0; | ||
|
|
||
| virtual TasksManager & getTasksManager() = 0; | ||
| virtual TasksManager const & getTasksManager() const = 0; | ||
|
|
||
|
|
||
| virtual string const & getProblemName() const = 0; | ||
| virtual string const & getInputFileName() const = 0; | ||
| virtual string const & getRestartFileName() const = 0; | ||
| virtual string const & getSchemaFileName() const = 0; | ||
|
|
||
| }; | ||
|
|
||
| /** | ||
| * @brief Gives the ProblemManagerBase from the given Group | ||
| * @param group The current Group in the Problem tree | ||
| * @return A reference to the ProblemManagerBase | ||
| */ | ||
| inline ProblemManagerBase & getProblemManagerBase( Group & group ) | ||
| { | ||
| Group * current = &group; | ||
| while( current->hasParent() ) | ||
| { | ||
| current = ¤t->getParent(); | ||
| } | ||
| ProblemManagerBase * const root = dynamic_cast< ProblemManagerBase * >( current ); | ||
| return *root; | ||
| } | ||
|
|
||
| /** | ||
| * @copydoc getProblemManagerBase( Group & ) | ||
| */ | ||
| inline ProblemManagerBase const & getProblemManagerBase( Group const & group ) | ||
| { | ||
| Group const * current = &group; | ||
| while( current->hasParent() ) | ||
| { | ||
| current = ¤t->getParent(); | ||
| } | ||
| ProblemManagerBase const * const root = dynamic_cast< ProblemManagerBase const * >( current ); | ||
| return *root; | ||
| } | ||
|
|
||
| } /* namespace dataRepository */ | ||
| } /* namespace geos */ | ||
|
|
||
|
|
||
| #endif /* GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ */ |
Contributor
There was a problem hiding this comment.
I would like to propose a new version to go all the way with this approach:
Suggested change
| /** | |
| * @file ProblemManagerBase.hpp | |
| */ | |
| #ifndef GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ | |
| #define GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ | |
| #include "dataRepository/Group.hpp" | |
| namespace geos | |
| { | |
| class DomainPartition; | |
| class EventManager; | |
| class ExternalDataSourceManager; | |
| class FieldSpecificationManager; | |
| class FunctionManager; | |
| class GeometricObjectManager; | |
| class MeshManager; | |
| class NumericalMethodsManager; | |
| class OutputManager; | |
| class PhysicsSolverManager; | |
| class TasksManager; | |
| namespace constitutive | |
| { | |
| class ConstitutiveManager; | |
| } | |
| namespace dataRepository | |
| { | |
| /** | |
| * @class ProblemManagerBase | |
| */ | |
| class ProblemManagerBase : public Group | |
| { | |
| public: | |
| using Group::Group; | |
| virtual DomainPartition & getDomainPartition() = 0; | |
| virtual DomainPartition const & getDomainPartition() const = 0; | |
| virtual constitutive::ConstitutiveManager & getConstitutiveManager() = 0; | |
| virtual constitutive::ConstitutiveManager const & getConstitutiveManager() const = 0; | |
| virtual EventManager & getEventManager() = 0; | |
| virtual EventManager const & getEventManager() const = 0; | |
| virtual ExternalDataSourceManager & getExternalDataSourceManager() = 0; | |
| virtual ExternalDataSourceManager const & getExternalDataSourceManager() const = 0; | |
| virtual FieldSpecificationManager & getFieldSpecificationManager() = 0; | |
| virtual FieldSpecificationManager const & getFieldSpecificationManager() const = 0; | |
| virtual FunctionManager & getFunctionManager() = 0; | |
| virtual FunctionManager const & getFunctionManager() const = 0; | |
| virtual GeometricObjectManager & getGeometricObjectManager() = 0; | |
| virtual GeometricObjectManager const & getGeometricObjectManager() const = 0; | |
| virtual MeshManager & getMeshManager() = 0; | |
| virtual MeshManager const & getMeshManager() const = 0; | |
| virtual NumericalMethodsManager & getNumericalMethodsManager() = 0; | |
| virtual NumericalMethodsManager const & getNumericalMethodsManager() const = 0; | |
| virtual OutputManager & getOutputManager() = 0; | |
| virtual OutputManager const & getOutputManager() const = 0; | |
| virtual PhysicsSolverManager & getPhysicsSolverManager() = 0; | |
| virtual PhysicsSolverManager const & getPhysicsSolverManager() const = 0; | |
| virtual TasksManager & getTasksManager() = 0; | |
| virtual TasksManager const & getTasksManager() const = 0; | |
| virtual string const & getProblemName() const = 0; | |
| virtual string const & getInputFileName() const = 0; | |
| virtual string const & getRestartFileName() const = 0; | |
| virtual string const & getSchemaFileName() const = 0; | |
| }; | |
| /** | |
| * @brief Gives the ProblemManagerBase from the given Group | |
| * @param group The current Group in the Problem tree | |
| * @return A reference to the ProblemManagerBase | |
| */ | |
| inline ProblemManagerBase & getProblemManagerBase( Group & group ) | |
| { | |
| Group * current = &group; | |
| while( current->hasParent() ) | |
| { | |
| current = ¤t->getParent(); | |
| } | |
| ProblemManagerBase * const root = dynamic_cast< ProblemManagerBase * >( current ); | |
| return *root; | |
| } | |
| /** | |
| * @copydoc getProblemManagerBase( Group & ) | |
| */ | |
| inline ProblemManagerBase const & getProblemManagerBase( Group const & group ) | |
| { | |
| Group const * current = &group; | |
| while( current->hasParent() ) | |
| { | |
| current = ¤t->getParent(); | |
| } | |
| ProblemManagerBase const * const root = dynamic_cast< ProblemManagerBase const * >( current ); | |
| return *root; | |
| } | |
| } /* namespace dataRepository */ | |
| } /* namespace geos */ | |
| #endif /* GEOS_DATAREPOSITORY_PROBLEMMANAGERBASE_HPP_ */ | |
| /** | |
| * @file IProblemRepository.hpp | |
| */ | |
| #ifndef GEOS_DATAREPOSITORY_IPROBLEMREPOSITORY_HPP_ | |
| #define GEOS_DATAREPOSITORY_IPROBLEMREPOSITORY_HPP_ | |
| #include "dataRepository/Group.hpp" | |
| namespace geos | |
| { | |
| namespace dataRepository | |
| { | |
| /** | |
| * @brief Gives the problem data repository interface from the given Group | |
| * @param group The current Group in the Problem tree | |
| * @return A reference to the problem data repository interface | |
| */ | |
| inline IProblemRepository & getProblemRepository( Group & group ) | |
| /** | |
| * @copydoc getIProblemRepository( Group & ) | |
| */ | |
| inline IProblemRepository const & getProblemRepository( Group const & group ) | |
| /** | |
| * @brief Interface for an object which contain all the problem data-repository | |
| */ | |
| class IProblemRepository | |
| { | |
| public: | |
| /** | |
| * @brief Get a root data-repository object (a manager) of a given problem. | |
| * - The consumer need to include the type definition | |
| * - The interface implementation needs to implement a specialization for each types manager. | |
| * @tparam ManagerType the type of the root data-repository object we want to get (DomainPartition, EventManager...) | |
| * @return ManagerType& the root data-repository object instance reference | |
| */ | |
| template< typename ManagerType > | |
| virtual ManagerType & getRootObject() = 0; | |
| /** | |
| * @brief Get a root data-repository object (a manager) of a given problem. | |
| * - The consumer need to include the type definition | |
| * - The interface implementation needs to implement a specialization for each types manager. | |
| * @tparam ManagerType the type of the root data-repository object we want to get (DomainPartition, EventManager...) | |
| * @return ManagerType const & the root data-repository object instance reference | |
| */ | |
| template< typename ManagerType > | |
| virtual ManagerType const & getRootObject() const = 0; | |
| // if an abstract Group getting method is absolutely needed, we can add: | |
| // | |
| // virtual Group & getManager( string_view managerKey ) = 0; | |
| // virtual Group const & getManager( string_view managerKey ) const = 0; | |
| // | |
| // ... but ideally, we don't want to propose these to remove any "invisible" circular dependency practice. | |
| }; | |
| /** | |
| * @name Inline functions implementation | |
| */ | |
| ///@{ | |
| inline IProblemRepository & getManagerRegistry( Group & group ) | |
| { | |
| Group * current = &group; | |
| while( current->hasParent() ) | |
| { | |
| current = ¤t->getParent(); | |
| } | |
| IProblemRepository * const root = dynamic_cast< IProblemRepository * >( current ); | |
| return *root; | |
| } | |
| inline IProblemRepository const & getIProblemRepository( Group const & group ) | |
| { | |
| Group const * current = &group; | |
| while( current->hasParent() ) | |
| { | |
| current = ¤t->getParent(); | |
| } | |
| IProblemRepository const * const root = dynamic_cast< IProblemRepository const * >( current ); | |
| return *root; | |
| } | |
| ///@} | |
| } /* namespace dataRepository */ | |
| } /* namespace geos */ | |
| #endif /* GEOS_DATAREPOSITORY_IPROBLEMREPOSITORY_HPP_ */ |
I push your almost-interface type approach a bit further, and I see the following benefits:
- Each interface consumer need the declaration of the needed type,
- Only need to add template specialisation for each possible
getRootObject()type inProblemManager.cpp, - No need to manipulate
ProblemManagerview-keys, only the type of the manager is needed (excepted for implementation, which I think is ideal), - We discourage a lot to create invisible circular dependancy
- no need for forward declaration, explicit type will be used by consumer,
- no abstract Group obtained by a name,
- no assumption on the data-hierarchy structure.
- We lock the mutability of the root-
Group(unable to add sub-Groups toProblemManagerwithout being explicit with its type).
Last remarks:
- If that does not compile (linkage) or if we don't want virtual method implemented in the
ProblemManagerpackage, we can implement that in aProblemRepositoryImplclass (with its own cpp) and keep the interface approach (noGroupinheritance/exposure). - I would let the commented versions to consolidate and explain the approach.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR reduces the use of magic paths to access common objects for developers (
"/Problem/domain/","/Problem/domain/Constitutive","/Problem/Events/", etc)It introduces a
GlobalViewKeysstruct to provide a centralized definition of the names of these common objects.It also adds a
ProblemManagerBaselightweight interface over theProblemManagerthat gives typed access to these objects without requiring to bring the fullProblemManagerExample of its use:
is replaced by:
PhysicsSolverManager & physicsSolverManager = getProblemManagerBase( *this ).getPhysicsSolverManager();