Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #pragma once 11 : 12 : #include <functional> 13 : #include <map> 14 : #include <typeinfo> 15 : #include <typeindex> 16 : 17 : #include "libmesh/parameters.h" 18 : 19 : #include "MooseError.h" 20 : #include "MooseUtils.h" 21 : 22 : #ifdef MOOSE_UNIT_TEST 23 : #include "gtest/gtest.h" 24 : class GTEST_TEST_CLASS_NAME_(ParameterRegistryTest, add); 25 : class GTEST_TEST_CLASS_NAME_(ParameterRegistryTest, addExists); 26 : class GTEST_TEST_CLASS_NAME_(ParameterRegistryTest, set); 27 : class GTEST_TEST_CLASS_NAME_(ParameterRegistryTest, setNotRegistered); 28 : class GTEST_TEST_CLASS_NAME_(ParameterRegistryTest, setCatchMooseError); 29 : #endif 30 : 31 : namespace hit 32 : { 33 : class Field; 34 : } 35 : 36 : namespace Moose 37 : { 38 : 39 : /** 40 : * Registry that allows for the typeless setting of a parameter value 41 : * from a hit field 42 : */ 43 : class ParameterRegistry 44 : { 45 : public: 46 : /** 47 : * Get the singleton registry 48 : */ 49 : static ParameterRegistry & get(); 50 : 51 : /** 52 : * Add a parameter 53 : */ 54 : template <class T, class F> 55 : char add(F && f); 56 : 57 : /** 58 : * Sets a parameter value given a hit field 59 : */ 60 : void set(libMesh::Parameters::Value & value, const hit::Field & field) const; 61 : 62 : private: 63 : /** 64 : * Constructor; private so that it can only be created with the singleton 65 : */ 66 57044 : ParameterRegistry() {}; 67 : 68 : #ifdef MOOSE_UNIT_TEST 69 : FRIEND_TEST(::ParameterRegistryTest, add); 70 : FRIEND_TEST(::ParameterRegistryTest, addExists); 71 : FRIEND_TEST(::ParameterRegistryTest, set); 72 : FRIEND_TEST(::ParameterRegistryTest, setNotRegistered); 73 : FRIEND_TEST(::ParameterRegistryTest, setCatchMooseError); 74 : #endif 75 : 76 : /// Registration map of type -> function to fill each type 77 : std::unordered_map<std::type_index, 78 : std::function<void(libMesh::Parameters::Value & value, const hit::Field &)>> 79 : _registry; 80 : }; 81 : 82 : template <class T, class F> 83 : char 84 13566462 : ParameterRegistry::add(F && f) 85 : { 86 : static_assert(std::is_invocable_r_v<void, F &, T &, const hit::Field &>, 87 : "Setter function must be callable with (T &, const hit::Field &) and return void"); 88 : 89 : // We register a function that stores T &, but the registry will only ever be 90 : // called from a bare libMesh::Parameters::Value. Thus, we need to cast the 91 : // bare Value to the derived value and then call the setter. 92 19130428 : auto setter = [f = std::forward<F>(f)](libMesh::Parameters::Value & param_value, 93 : const hit::Field & field) -> void 94 : { 95 2782115 : auto cast_param_value = dynamic_cast<libMesh::Parameters::Parameter<T> *>(¶m_value); 96 : mooseAssert(cast_param_value, "Cast failed"); 97 2782115 : f(cast_param_value->set(), field); 98 : }; 99 : 100 13566462 : const std::type_index key(typeid(T)); 101 13566462 : const auto it_inserted_pair = _registry.emplace(key, std::move(setter)); 102 : 103 13566462 : if (!it_inserted_pair.second) 104 4 : mooseError("ParameterRegistry: Parameter with type '", 105 : MooseUtils::prettyCppType<T>(), 106 : "' is already registered"); 107 : 108 13566460 : return 0; 109 : } 110 : 111 : } // end of namespace Moose