123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- #ifndef C10_UTIL_REGISTRY_H_
- #define C10_UTIL_REGISTRY_H_
- /**
- * Simple registry implementation that uses static variables to
- * register object creators during program initialization time.
- */
- // NB: This Registry works poorly when you have other namespaces.
- // Make all macro invocations from inside the at namespace.
- #include <algorithm>
- #include <cstdio>
- #include <cstdlib>
- #include <functional>
- #include <memory>
- #include <mutex>
- #include <string>
- #include <unordered_map>
- #include <vector>
- #include <c10/macros/Macros.h>
- #include <c10/util/Type.h>
- namespace c10 {
- template <typename KeyType>
- inline std::string KeyStrRepr(const KeyType& /*key*/) {
- return "[key type printing not supported]";
- }
- template <>
- inline std::string KeyStrRepr(const std::string& key) {
- return key;
- }
- enum RegistryPriority {
- REGISTRY_FALLBACK = 1,
- REGISTRY_DEFAULT = 2,
- REGISTRY_PREFERRED = 3,
- };
- /**
- * @brief A template class that allows one to register classes by keys.
- *
- * The keys are usually a std::string specifying the name, but can be anything
- * that can be used in a std::map.
- *
- * You should most likely not use the Registry class explicitly, but use the
- * helper macros below to declare specific registries as well as registering
- * objects.
- */
- template <class SrcType, class ObjectPtrType, class... Args>
- class Registry {
- public:
- typedef std::function<ObjectPtrType(Args...)> Creator;
- Registry(bool warning = true)
- : registry_(), priority_(), terminate_(true), warning_(warning) {}
- void Register(
- const SrcType& key,
- Creator creator,
- const RegistryPriority priority = REGISTRY_DEFAULT) {
- std::lock_guard<std::mutex> lock(register_mutex_);
- // The if statement below is essentially the same as the following line:
- // TORCH_CHECK_EQ(registry_.count(key), 0) << "Key " << key
- // << " registered twice.";
- // However, TORCH_CHECK_EQ depends on google logging, and since registration
- // is carried out at static initialization time, we do not want to have an
- // explicit dependency on glog's initialization function.
- if (registry_.count(key) != 0) {
- auto cur_priority = priority_[key];
- if (priority > cur_priority) {
- #ifdef DEBUG
- std::string warn_msg =
- "Overwriting already registered item for key " + KeyStrRepr(key);
- fprintf(stderr, "%s\n", warn_msg.c_str());
- #endif
- registry_[key] = creator;
- priority_[key] = priority;
- } else if (priority == cur_priority) {
- std::string err_msg =
- "Key already registered with the same priority: " + KeyStrRepr(key);
- fprintf(stderr, "%s\n", err_msg.c_str());
- if (terminate_) {
- std::exit(1);
- } else {
- throw std::runtime_error(err_msg);
- }
- } else if (warning_) {
- std::string warn_msg =
- "Higher priority item already registered, skipping registration of " +
- KeyStrRepr(key);
- fprintf(stderr, "%s\n", warn_msg.c_str());
- }
- } else {
- registry_[key] = creator;
- priority_[key] = priority;
- }
- }
- void Register(
- const SrcType& key,
- Creator creator,
- const std::string& help_msg,
- const RegistryPriority priority = REGISTRY_DEFAULT) {
- Register(key, creator, priority);
- help_message_[key] = help_msg;
- }
- inline bool Has(const SrcType& key) {
- return (registry_.count(key) != 0);
- }
- ObjectPtrType Create(const SrcType& key, Args... args) {
- auto it = registry_.find(key);
- if (it == registry_.end()) {
- // Returns nullptr if the key is not registered.
- return nullptr;
- }
- return it->second(args...);
- }
- /**
- * Returns the keys currently registered as a std::vector.
- */
- std::vector<SrcType> Keys() const {
- std::vector<SrcType> keys;
- keys.reserve(registry_.size());
- for (const auto& it : registry_) {
- keys.push_back(it.first);
- }
- return keys;
- }
- inline const std::unordered_map<SrcType, std::string>& HelpMessage() const {
- return help_message_;
- }
- const char* HelpMessage(const SrcType& key) const {
- auto it = help_message_.find(key);
- if (it == help_message_.end()) {
- return nullptr;
- }
- return it->second.c_str();
- }
- // Used for testing, if terminate is unset, Registry throws instead of
- // calling std::exit
- void SetTerminate(bool terminate) {
- terminate_ = terminate;
- }
- private:
- std::unordered_map<SrcType, Creator> registry_;
- std::unordered_map<SrcType, RegistryPriority> priority_;
- bool terminate_;
- const bool warning_;
- std::unordered_map<SrcType, std::string> help_message_;
- std::mutex register_mutex_;
- C10_DISABLE_COPY_AND_ASSIGN(Registry);
- };
- template <class SrcType, class ObjectPtrType, class... Args>
- class Registerer {
- public:
- explicit Registerer(
- const SrcType& key,
- Registry<SrcType, ObjectPtrType, Args...>* registry,
- typename Registry<SrcType, ObjectPtrType, Args...>::Creator creator,
- const std::string& help_msg = "") {
- registry->Register(key, creator, help_msg);
- }
- explicit Registerer(
- const SrcType& key,
- const RegistryPriority priority,
- Registry<SrcType, ObjectPtrType, Args...>* registry,
- typename Registry<SrcType, ObjectPtrType, Args...>::Creator creator,
- const std::string& help_msg = "") {
- registry->Register(key, creator, help_msg, priority);
- }
- template <class DerivedType>
- static ObjectPtrType DefaultCreator(Args... args) {
- return ObjectPtrType(new DerivedType(args...));
- }
- };
- /**
- * C10_DECLARE_TYPED_REGISTRY is a macro that expands to a function
- * declaration, as well as creating a convenient typename for its corresponding
- * registerer.
- */
- // Note on C10_IMPORT and C10_EXPORT below: we need to explicitly mark DECLARE
- // as import and DEFINE as export, because these registry macros will be used
- // in downstream shared libraries as well, and one cannot use *_API - the API
- // macro will be defined on a per-shared-library basis. Semantically, when one
- // declares a typed registry it is always going to be IMPORT, and when one
- // defines a registry (which should happen ONLY ONCE and ONLY IN SOURCE FILE),
- // the instantiation unit is always going to be exported.
- //
- // The only unique condition is when in the same file one does DECLARE and
- // DEFINE - in Windows compilers, this generates a warning that dllimport and
- // dllexport are mixed, but the warning is fine and linker will be properly
- // exporting the symbol. Same thing happens in the gflags flag declaration and
- // definition caes.
- #define C10_DECLARE_TYPED_REGISTRY( \
- RegistryName, SrcType, ObjectType, PtrType, ...) \
- C10_IMPORT ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
- RegistryName(); \
- typedef ::c10::Registerer<SrcType, PtrType<ObjectType>, ##__VA_ARGS__> \
- Registerer##RegistryName
- #define C10_DEFINE_TYPED_REGISTRY( \
- RegistryName, SrcType, ObjectType, PtrType, ...) \
- C10_EXPORT ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
- RegistryName() { \
- static ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
- registry = new ::c10:: \
- Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>(); \
- return registry; \
- }
- #define C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
- RegistryName, SrcType, ObjectType, PtrType, ...) \
- C10_EXPORT ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
- RegistryName() { \
- static ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
- registry = \
- new ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>( \
- false); \
- return registry; \
- }
- // Note(Yangqing): The __VA_ARGS__ below allows one to specify a templated
- // creator with comma in its templated arguments.
- #define C10_REGISTER_TYPED_CREATOR(RegistryName, key, ...) \
- static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
- key, RegistryName(), ##__VA_ARGS__);
- #define C10_REGISTER_TYPED_CREATOR_WITH_PRIORITY( \
- RegistryName, key, priority, ...) \
- static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
- key, priority, RegistryName(), ##__VA_ARGS__);
- #define C10_REGISTER_TYPED_CLASS(RegistryName, key, ...) \
- static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
- key, \
- RegistryName(), \
- Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
- ::c10::demangle_type<__VA_ARGS__>());
- #define C10_REGISTER_TYPED_CLASS_WITH_PRIORITY( \
- RegistryName, key, priority, ...) \
- static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
- key, \
- priority, \
- RegistryName(), \
- Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
- ::c10::demangle_type<__VA_ARGS__>());
- // C10_DECLARE_REGISTRY and C10_DEFINE_REGISTRY are hard-wired to use
- // std::string as the key type, because that is the most commonly used cases.
- #define C10_DECLARE_REGISTRY(RegistryName, ObjectType, ...) \
- C10_DECLARE_TYPED_REGISTRY( \
- RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
- #define C10_DEFINE_REGISTRY(RegistryName, ObjectType, ...) \
- C10_DEFINE_TYPED_REGISTRY( \
- RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
- #define C10_DEFINE_REGISTRY_WITHOUT_WARNING(RegistryName, ObjectType, ...) \
- C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
- RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
- #define C10_DECLARE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
- C10_DECLARE_TYPED_REGISTRY( \
- RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
- #define C10_DEFINE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
- C10_DEFINE_TYPED_REGISTRY( \
- RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
- #define C10_DEFINE_SHARED_REGISTRY_WITHOUT_WARNING( \
- RegistryName, ObjectType, ...) \
- C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
- RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
- // C10_REGISTER_CREATOR and C10_REGISTER_CLASS are hard-wired to use std::string
- // as the key
- // type, because that is the most commonly used cases.
- #define C10_REGISTER_CREATOR(RegistryName, key, ...) \
- C10_REGISTER_TYPED_CREATOR(RegistryName, #key, __VA_ARGS__)
- #define C10_REGISTER_CREATOR_WITH_PRIORITY(RegistryName, key, priority, ...) \
- C10_REGISTER_TYPED_CREATOR_WITH_PRIORITY( \
- RegistryName, #key, priority, __VA_ARGS__)
- #define C10_REGISTER_CLASS(RegistryName, key, ...) \
- C10_REGISTER_TYPED_CLASS(RegistryName, #key, __VA_ARGS__)
- #define C10_REGISTER_CLASS_WITH_PRIORITY(RegistryName, key, priority, ...) \
- C10_REGISTER_TYPED_CLASS_WITH_PRIORITY( \
- RegistryName, #key, priority, __VA_ARGS__)
- } // namespace c10
- #endif // C10_UTIL_REGISTRY_H_
|