FST  openfst-1.8.3
OpenFst Library
generic-register.h
Go to the documentation of this file.
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 
18 #ifndef FST_GENERIC_REGISTER_H_
19 #define FST_GENERIC_REGISTER_H_
20 
21 #include <functional>
22 
23 #include <fst/compat.h>
24 #include <string_view>
25 #include <fst/lock.h>
26 #ifndef FST_NO_DYNAMIC_LINKING
27 #include <dlfcn.h>
28 #endif
29 #include <map>
30 #include <string>
31 
32 #include <fst/log.h>
33 
34 // Generic class representing a globally-stored correspondence between
35 // objects of KeyType and EntryType.
36 //
37 // KeyType must:
38 //
39 // * be such as can be stored as a key in a std::map<>.
40 //
41 // EntryType must be default constructible.
42 //
43 // The third template parameter should be the type of a subclass of this class
44 // (think CRTP). This is to allow GetRegister() to instantiate and return an
45 // object of the appropriate type.
46 
47 namespace fst {
48 
49 namespace internal {
50 template <class T>
52  using type = const T &;
53 };
54 
55 template <>
56 struct KeyLookupReferenceType<std::string> {
57  using type = std::string_view;
58 };
59 } // namespace internal
60 
61 template <class KeyType, class EntryType, class RegisterType>
63  public:
64  using Key = KeyType;
66  using Entry = EntryType;
67 
68  static RegisterType *GetRegister() {
69  static auto reg = new RegisterType;
70  return reg;
71  }
72 
73  void SetEntry(const KeyType &key, const EntryType &entry) {
74  MutexLock l(&register_lock_);
75  register_table_.emplace(key, entry);
76  }
77 
78  EntryType GetEntry(KeyLookupRef key) const {
79  const auto *entry = LookupEntry(key);
80  if (entry) {
81  return *entry;
82  } else {
83  return LoadEntryFromSharedObject(key);
84  }
85  }
86 
87  virtual ~GenericRegister() = default;
88 
89  protected:
90  // Override this if you want to be able to load missing definitions from
91  // shared object files.
92  virtual EntryType LoadEntryFromSharedObject(KeyLookupRef key) const {
93 #ifdef FST_NO_DYNAMIC_LINKING
94  return EntryType();
95 #else
96  const auto so_filename = ConvertKeyToSoFilename(key);
97  void *handle = dlopen(so_filename.c_str(), RTLD_LAZY);
98  if (handle == nullptr) {
99  LOG(ERROR) << "GenericRegister::GetEntry: " << dlerror();
100  return EntryType();
101  }
102 #ifdef RUN_MODULE_INITIALIZERS
103  RUN_MODULE_INITIALIZERS();
104 #endif
105  // We assume that the DSO constructs a static object in its global scope
106  // that does the registration. Thus we need only load it, not call any
107  // methods.
108  const auto *entry = this->LookupEntry(key);
109  if (entry == nullptr) {
110  LOG(ERROR) << "GenericRegister::GetEntry: "
111  << "lookup failed in shared object: " << so_filename;
112  return EntryType();
113  }
114  return *entry;
115 #endif // FST_NO_DYNAMIC_LINKING
116  }
117 
118  // Override this to define how to turn a key into an SO filename.
119  virtual std::string ConvertKeyToSoFilename(KeyLookupRef key) const = 0;
120 
121  virtual const EntryType *LookupEntry(KeyLookupRef key) const {
122  MutexLock l(&register_lock_);
123  if (const auto it = register_table_.find(key);
124  it != register_table_.end()) {
125  return &it->second;
126  } else {
127  return nullptr;
128  }
129  }
130 
131  private:
132  mutable Mutex register_lock_;
133  std::map<KeyType, EntryType, std::less<>> register_table_;
134 };
135 
136 // Generic register-er class capable of creating new register entries in the
137 // given RegisterType template parameter. This type must define types Key and
138 // Entry, and have appropriate static GetRegister() and instance SetEntry()
139 // functions. An easy way to accomplish this is to have RegisterType be the
140 // type of a subclass of GenericRegister.
141 template <class RegisterType>
143  public:
144  using Key = typename RegisterType::Key;
145  using Entry = typename RegisterType::Entry;
146 
148  RegisterType::GetRegister()->SetEntry(key, entry);
149  }
150 };
151 
152 } // namespace fst
153 
154 #endif // FST_GENERIC_REGISTER_H_
typename FstRegister< FST::Arc >::Key Key
GenericRegisterer(Key key, Entry entry)
#define LOG(type)
Definition: log.h:53
virtual EntryType LoadEntryFromSharedObject(KeyLookupRef key) const
static RegisterType * GetRegister()
EntryType GetEntry(KeyLookupRef key) const
virtual const EntryType * LookupEntry(KeyLookupRef key) const
void SetEntry(const KeyType &key, const EntryType &entry)
typename FstRegister< FST::Arc >::Entry Entry