You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.4 KiB

  1. // Copyright 2005-2024 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the 'License');
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an 'AS IS' BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // See www.openfst.org for extensive documentation on this weighted
  16. // finite-state transducer library.
  17. #ifndef FST_GENERIC_REGISTER_H_
  18. #define FST_GENERIC_REGISTER_H_
  19. #include <functional>
  20. #include <fst/compat.h>
  21. #include <string_view>
  22. #include <fst/lock.h>
  23. #ifndef FST_NO_DYNAMIC_LINKING
  24. #include <dlfcn.h>
  25. #endif
  26. #include <map>
  27. #include <string>
  28. #include <fst/log.h>
  29. // Generic class representing a globally-stored correspondence between
  30. // objects of KeyType and EntryType.
  31. //
  32. // KeyType must:
  33. //
  34. // * be such as can be stored as a key in a std::map<>.
  35. //
  36. // EntryType must be default constructible.
  37. //
  38. // The third template parameter should be the type of a subclass of this class
  39. // (think CRTP). This is to allow GetRegister() to instantiate and return an
  40. // object of the appropriate type.
  41. namespace fst {
  42. namespace internal {
  43. template <class T>
  44. struct KeyLookupReferenceType {
  45. using type = const T &;
  46. };
  47. template <>
  48. struct KeyLookupReferenceType<std::string> {
  49. using type = std::string_view;
  50. };
  51. } // namespace internal
  52. template <class KeyType, class EntryType, class RegisterType>
  53. class GenericRegister {
  54. public:
  55. using Key = KeyType;
  56. using KeyLookupRef = typename internal::KeyLookupReferenceType<KeyType>::type;
  57. using Entry = EntryType;
  58. static RegisterType *GetRegister() {
  59. static auto reg = new RegisterType;
  60. return reg;
  61. }
  62. void SetEntry(const KeyType &key, const EntryType &entry) {
  63. MutexLock l(&register_lock_);
  64. register_table_.emplace(key, entry);
  65. }
  66. EntryType GetEntry(KeyLookupRef key) const {
  67. const auto *entry = LookupEntry(key);
  68. if (entry) {
  69. return *entry;
  70. } else {
  71. return LoadEntryFromSharedObject(key);
  72. }
  73. }
  74. virtual ~GenericRegister() = default;
  75. protected:
  76. // Override this if you want to be able to load missing definitions from
  77. // shared object files.
  78. virtual EntryType LoadEntryFromSharedObject(KeyLookupRef key) const {
  79. #ifdef FST_NO_DYNAMIC_LINKING
  80. return EntryType();
  81. #else
  82. const auto so_filename = ConvertKeyToSoFilename(key);
  83. void *handle = dlopen(so_filename.c_str(), RTLD_LAZY);
  84. if (handle == nullptr) {
  85. LOG(ERROR) << "GenericRegister::GetEntry: " << dlerror();
  86. return EntryType();
  87. }
  88. #ifdef RUN_MODULE_INITIALIZERS
  89. RUN_MODULE_INITIALIZERS();
  90. #endif
  91. // We assume that the DSO constructs a static object in its global scope
  92. // that does the registration. Thus we need only load it, not call any
  93. // methods.
  94. const auto *entry = this->LookupEntry(key);
  95. if (entry == nullptr) {
  96. LOG(ERROR) << "GenericRegister::GetEntry: "
  97. << "lookup failed in shared object: " << so_filename;
  98. return EntryType();
  99. }
  100. return *entry;
  101. #endif // FST_NO_DYNAMIC_LINKING
  102. }
  103. // Override this to define how to turn a key into an SO filename.
  104. virtual std::string ConvertKeyToSoFilename(KeyLookupRef key) const = 0;
  105. virtual const EntryType *LookupEntry(KeyLookupRef key) const {
  106. MutexLock l(&register_lock_);
  107. if (const auto it = register_table_.find(key);
  108. it != register_table_.end()) {
  109. return &it->second;
  110. } else {
  111. return nullptr;
  112. }
  113. }
  114. private:
  115. mutable Mutex register_lock_;
  116. std::map<KeyType, EntryType, std::less<>> register_table_;
  117. };
  118. // Generic register-er class capable of creating new register entries in the
  119. // given RegisterType template parameter. This type must define types Key and
  120. // Entry, and have appropriate static GetRegister() and instance SetEntry()
  121. // functions. An easy way to accomplish this is to have RegisterType be the
  122. // type of a subclass of GenericRegister.
  123. template <class RegisterType>
  124. class GenericRegisterer {
  125. public:
  126. using Key = typename RegisterType::Key;
  127. using Entry = typename RegisterType::Entry;
  128. GenericRegisterer(Key key, Entry entry) {
  129. RegisterType::GetRegister()->SetEntry(key, entry);
  130. }
  131. };
  132. } // namespace fst
  133. #endif // FST_GENERIC_REGISTER_H_