Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:48

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2022-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file corecel/io/StringEnumMapper.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <string_view>
0011 #include <type_traits>
0012 #include <unordered_map>
0013 
0014 #include "corecel/Assert.hh"
0015 #include "corecel/cont/Range.hh"
0016 
0017 namespace celeritas
0018 {
0019 //---------------------------------------------------------------------------//
0020 /*!
0021  * Map strings to enums for user input.
0022  *
0023  * Note that since a map is built at construction time, instances of this class
0024  * should be \c static to amortize the cost. The strings being converted *must*
0025  * exceed the lifetime of this class. (Usually it references `const char*`.)
0026  *
0027  * \todo If the size of the strings is short and there aren't a lot of them, it
0028  * will be faster to use a fixed-size array and search over them.
0029  *
0030  * Example:
0031  * \code
0032 void from_json(const nlohmann::json& j, GeantSetupOptions& opts)
0033 {
0034     static auto gspl_from_string
0035         = StringEnumMapper<PhysicsList>::from_cstring_func(
0036             to_cstring, "physics list");
0037     opts.physics = gspl_from_string(j.at("physics").get<std::string>());
0038 }
0039    \endcode
0040  */
0041 template<class T>
0042 class StringEnumMapper
0043 {
0044     static_assert(std::is_enum<T>::value, "not an enum type");
0045     static_assert(static_cast<int>(T::size_) >= 0, "invalid enum type");
0046 
0047   public:
0048     //!@{
0049     //! \name Type aliases
0050     using EnumCStringFuncPtr = char const*(T);
0051     //!@}
0052 
0053   public:
0054     // Construct from a "to_cstring" function pointer
0055     static inline StringEnumMapper<T>
0056     from_cstring_func(EnumCStringFuncPtr, char const* desc = nullptr);
0057 
0058     // Construct with a function that takes an enum and returns a stringlike
0059     template<class U>
0060     explicit inline StringEnumMapper(U&& enum_to_string,
0061                                      char const* desc = nullptr);
0062 
0063     // Convert from a string
0064     inline T operator()(std::string_view s) const;
0065 
0066   private:
0067     char const* description_;
0068     std::unordered_map<std::string_view, T> map_;
0069 };
0070 
0071 //---------------------------------------------------------------------------//
0072 // INLINE DEFINITIONS
0073 //---------------------------------------------------------------------------//
0074 /*!
0075  * Construct using a \c to_cstring function.
0076  */
0077 template<class T>
0078 StringEnumMapper<T>
0079 StringEnumMapper<T>::from_cstring_func(EnumCStringFuncPtr fp, char const* desc)
0080 {
0081     CELER_EXPECT(fp);
0082     return StringEnumMapper<T>{fp, desc};
0083 }
0084 
0085 //---------------------------------------------------------------------------//
0086 /*!
0087  * Construct with a "stringify" function.
0088  *
0089  * The result just has to be implicitly convertible to a \c std::string_view .
0090  */
0091 template<class T>
0092 template<class U>
0093 StringEnumMapper<T>::StringEnumMapper(U&& enum_to_string, char const* desc)
0094     : description_(desc)
0095 {
0096     map_.reserve(static_cast<std::size_t>(T::size_));
0097     for (auto v : celeritas::range(T::size_))
0098     {
0099         auto iter_inserted = map_.insert({enum_to_string(v), v});
0100         CELER_ASSERT(iter_inserted.second);
0101     }
0102 }
0103 
0104 //---------------------------------------------------------------------------//
0105 /*!
0106  * Convert a string_view to the corresponding enum.
0107  */
0108 template<class T>
0109 T StringEnumMapper<T>::operator()(std::string_view s) const
0110 {
0111     auto result = map_.find(s);
0112     CELER_VALIDATE(result != map_.end(),
0113                    << "invalid " << (description_ ? description_ : "value")
0114                    << " '" << s << '\'');
0115     return result->second;
0116 }
0117 
0118 //---------------------------------------------------------------------------//
0119 }  // namespace celeritas