diff --git a/docs/sphinx/tutorial/resources.rst b/docs/sphinx/tutorial/resources.rst index a54921ba6..0411f4419 100644 --- a/docs/sphinx/tutorial/resources.rst +++ b/docs/sphinx/tutorial/resources.rst @@ -35,6 +35,21 @@ example: :end-before: _sphinx_tag_tut_get_allocator_end :language: C++ +If you would prefer to avoid exceptions when an allocator is not available, +you can instead use :func:`umpire::ResourceManager::tryGetAllocator`, which +returns a ``std::optional`` that is empty when the +requested allocator cannot be found: + +.. code-block:: cpp + + auto& rm = umpire::ResourceManager::getInstance(); + auto maybe_allocator = rm.tryGetAllocator("HOST"); + + if (maybe_allocator) { + auto allocator = *maybe_allocator; + // use allocator + } + Note that since every allocator supports the same calls, no matter which resource it is for, this means we can run the same code for all the resources available in the system. diff --git a/src/umpire/ResourceManager.cpp b/src/umpire/ResourceManager.cpp index d4926652c..820a96680 100644 --- a/src/umpire/ResourceManager.cpp +++ b/src/umpire/ResourceManager.cpp @@ -209,6 +209,29 @@ strategy::AllocationStrategy* ResourceManager::getAllocationStrategy(const std:: return m_allocators_by_name[name]; } +std::optional ResourceManager::tryGetAllocator(const std::string& name) +{ + UMPIRE_LOG(Debug, "(\"" << name << "\")"); + + resource::MemoryResourceRegistry& registry{resource::MemoryResourceRegistry::getInstance()}; + auto resource_names = registry.getResourceNames(); + + auto allocator = m_allocators_by_name.find(name); + if (allocator == m_allocators_by_name.end()) { + auto resource_name = std::find(resource_names.begin(), resource_names.end(), name); + if (resource_name != std::end(resource_names)) { + makeResource(name); + allocator = m_allocators_by_name.find(name); + } + } + + if (allocator == m_allocators_by_name.end()) { + return std::nullopt; + } + + return Allocator{allocator->second}; +} + Allocator ResourceManager::getAllocator(const std::string& name) { UMPIRE_LOG(Debug, "(\"" << name << "\")"); diff --git a/src/umpire/ResourceManager.hpp b/src/umpire/ResourceManager.hpp index 9ab5fc902..4bc0c7de3 100644 --- a/src/umpire/ResourceManager.hpp +++ b/src/umpire/ResourceManager.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,14 @@ class ResourceManager { */ Allocator getAllocator(const std::string& name); + /*! + * \brief Try to get the Allocator with the given name. + * + * This function returns an empty optional if the allocator does not exist + * or cannot be created, instead of throwing an exception. + */ + std::optional tryGetAllocator(const std::string& name); + Allocator getAllocator(const char* name); /*! diff --git a/tests/integration/allocator_integration_tests.cpp b/tests/integration/allocator_integration_tests.cpp index a33f6a59c..01cfd6b40 100644 --- a/tests/integration/allocator_integration_tests.cpp +++ b/tests/integration/allocator_integration_tests.cpp @@ -230,6 +230,18 @@ TEST(Allocator, registerAllocator) ASSERT_FALSE(rm.isAllocator("BANANAS")); } +TEST(Allocator, TryGetAllocator) +{ + auto& rm = umpire::ResourceManager::getInstance(); + + auto host_allocator = rm.tryGetAllocator("HOST"); + ASSERT_TRUE(host_allocator.has_value()); + EXPECT_EQ(std::string{"HOST"}, host_allocator->getName()); + + auto bad_allocator = rm.tryGetAllocator("BANANAS"); + EXPECT_FALSE(bad_allocator.has_value()); +} + TEST(Allocator, GetSetDefault) { auto& rm = umpire::ResourceManager::getInstance();