1 // Copyright (c) 2016 Thomas Heller 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #include <hpx/throw_exception.hpp> 7 #include <hpx/runtime/actions/detail/action_factory.hpp> 8 #include <hpx/util/assert.hpp> 9 10 #include <cstdint> 11 #include <string> 12 #include <unordered_map> 13 #include <utility> 14 #include <vector> 15 16 namespace hpx { namespace actions { namespace detail 17 { action_registry()18 action_registry::action_registry() 19 : max_id_(0) 20 {} 21 register_factory(std::string const & type_name,ctor_t ctor)22 void action_registry::register_factory(std::string const& type_name, ctor_t ctor) 23 { 24 HPX_ASSERT(ctor != nullptr); 25 26 typename_to_ctor_.emplace(std::string(type_name), ctor); 27 28 // populate cache 29 typename_to_id_t::const_iterator it = typename_to_id_.find(type_name); 30 if (it != typename_to_id_.end()) 31 cache_id(it->second, ctor); 32 } 33 register_typename(std::string const & type_name,std::uint32_t id)34 void action_registry::register_typename( 35 std::string const& type_name, std::uint32_t id) 36 { 37 HPX_ASSERT(id != invalid_id); 38 39 std::pair<typename_to_id_t::iterator, bool> p = 40 typename_to_id_.emplace(type_name, id); 41 42 if (!p.second) 43 { 44 HPX_THROW_EXCEPTION(invalid_status, 45 "action_registry::register_typename", 46 "failed to insert " + type_name + 47 " into typename to id registry."); 48 } 49 50 // populate cache 51 typename_to_ctor_t::const_iterator it = 52 typename_to_ctor_.find(type_name); 53 if (it != typename_to_ctor_.end()) 54 cache_id(id, it->second); 55 56 if (id > max_id_) max_id_ = id; 57 } 58 59 // This makes sure that the registries are consistent. fill_missing_typenames()60 void action_registry::fill_missing_typenames() 61 { 62 // Register all type-names and ssign missing ids 63 for (std::string const& str : get_unassigned_typenames()) 64 register_typename(str, ++max_id_); 65 66 // Go over all registered mappings from type-names to ids and 67 // fill in missing id to constructor mappings. 68 for (auto const& d: typename_to_id_) 69 { 70 typename_to_ctor_t::const_iterator it = 71 typename_to_ctor_.find(d.first); 72 if (it != typename_to_ctor_.end()) 73 cache_id(d.second, it->second); 74 } 75 76 // Go over all registered mappings from type-names to ctors and 77 // fill in missing id to constructor mappings. 78 for (auto const& d: typename_to_ctor_) 79 { 80 typename_to_id_t::const_iterator it = 81 typename_to_id_.find(d.first); 82 HPX_ASSERT(it != typename_to_id_.end()); 83 cache_id(it->second, d.second); 84 } 85 } 86 try_get_id(std::string const & type_name) const87 std::uint32_t action_registry::try_get_id(std::string const& type_name) const 88 { 89 typename_to_id_t::const_iterator it = 90 typename_to_id_.find(type_name); 91 if (it == typename_to_id_.end()) 92 return invalid_id; 93 94 return it->second; 95 } 96 get_unassigned_typenames() const97 std::vector<std::string> action_registry::get_unassigned_typenames() const 98 { 99 typedef typename_to_ctor_t::value_type value_type; 100 101 std::vector<std::string> result; 102 103 for (const value_type& v: typename_to_ctor_) 104 if (!typename_to_id_.count(v.first)) 105 result.push_back(v.first); 106 107 return result; 108 } 109 get_id(std::string const & type_name)110 std::uint32_t action_registry::get_id(std::string const& type_name) 111 { 112 std::uint32_t id = instance().try_get_id(type_name); 113 114 if (id == invalid_id) 115 { 116 HPX_THROW_EXCEPTION(serialization_error, 117 "action_registry::get_id", 118 "Unknown typename: " + type_name + "\n" + 119 instance().collect_registered_typenames()); 120 } 121 122 return id; 123 } 124 create(std::uint32_t id,bool with_continuation,std::string const * name)125 base_action* action_registry::create( 126 std::uint32_t id, bool with_continuation, std::string const* name) 127 { 128 action_registry& this_ = instance(); 129 130 if (id >= this_.cache_.size()) 131 { 132 std::string msg("Unknown type descriptor " + std::to_string(id)); 133 #if defined(HPX_DEBUG) 134 if (name != nullptr) 135 { 136 msg += ", for typename " + *name; 137 } 138 msg += this_.collect_registered_typenames(); 139 #endif 140 HPX_THROW_EXCEPTION(serialization_error, 141 "action_registry::create", msg); 142 return nullptr; 143 } 144 145 ctor_t ctor = this_.cache_[id]; 146 if (ctor == nullptr) 147 { 148 std::string msg("Unknown type descriptor " + std::to_string(id)); 149 #if defined(HPX_DEBUG) 150 if (name != nullptr) 151 { 152 msg += ", for typename " + *name; 153 } 154 msg += this_.collect_registered_typenames(); 155 #endif 156 HPX_THROW_EXCEPTION(serialization_error, 157 "action_registry::create", msg); 158 return nullptr; 159 } 160 return ctor(with_continuation); 161 } 162 instance()163 action_registry& action_registry::instance() 164 { 165 static action_registry this_; 166 return this_; 167 } 168 cache_id(std::uint32_t id,action_registry::ctor_t ctor)169 void action_registry::cache_id(std::uint32_t id, action_registry::ctor_t ctor) 170 { 171 if (id >= cache_.size()) 172 { 173 cache_.resize(id + 1, nullptr); 174 cache_[id] = nullptr; 175 return; 176 } 177 178 if (cache_[id] == nullptr) 179 { 180 cache_[id] = ctor; 181 } 182 } 183 collect_registered_typenames()184 std::string action_registry::collect_registered_typenames() 185 { 186 #if defined(HPX_DEBUG) 187 std::string msg("\nknown constructors:\n"); 188 189 for (auto const& desc : typename_to_ctor_) 190 { 191 msg += desc.first + "\n"; 192 } 193 194 msg += "\nknown typenames:\n"; 195 for (auto const& desc : typename_to_id_) 196 { 197 msg += desc.first + " ("; 198 msg += std::to_string(desc.second) + ")\n"; 199 } 200 return msg; 201 #else 202 return std::string(); 203 #endif 204 } 205 206 /////////////////////////////////////////////////////////////////////////// get_action_id_from_name(char const * action_name)207 std::uint32_t get_action_id_from_name(char const* action_name) 208 { 209 using hpx::actions::detail::action_registry; 210 return action_registry::get_id(action_name); 211 } 212 }}} 213