|
|
// Copyright 2005-2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// See www.openfst.org for extensive documentation on this weighted
// finite-state transducer library.
#ifndef FST_GENERIC_REGISTER_H_
#define FST_GENERIC_REGISTER_H_
#include <functional>
#include <fst/compat.h>
#include <string_view>
#include <fst/lock.h>
#ifndef FST_NO_DYNAMIC_LINKING
#include <dlfcn.h>
#endif
#include <map>
#include <string>
#include <fst/log.h>
// Generic class representing a globally-stored correspondence between
// objects of KeyType and EntryType.
//
// KeyType must:
//
// * be such as can be stored as a key in a std::map<>.
//
// EntryType must be default constructible.
//
// The third template parameter should be the type of a subclass of this class
// (think CRTP). This is to allow GetRegister() to instantiate and return an
// object of the appropriate type.
namespace fst {
namespace internal { template <class T> struct KeyLookupReferenceType { using type = const T &; };
template <> struct KeyLookupReferenceType<std::string> { using type = std::string_view; }; } // namespace internal
template <class KeyType, class EntryType, class RegisterType> class GenericRegister { public: using Key = KeyType; using KeyLookupRef = typename internal::KeyLookupReferenceType<KeyType>::type; using Entry = EntryType;
static RegisterType *GetRegister() { static auto reg = new RegisterType; return reg; }
void SetEntry(const KeyType &key, const EntryType &entry) { MutexLock l(®ister_lock_); register_table_.emplace(key, entry); }
EntryType GetEntry(KeyLookupRef key) const { const auto *entry = LookupEntry(key); if (entry) { return *entry; } else { return LoadEntryFromSharedObject(key); } }
virtual ~GenericRegister() = default;
protected: // Override this if you want to be able to load missing definitions from
// shared object files.
virtual EntryType LoadEntryFromSharedObject(KeyLookupRef key) const { #ifdef FST_NO_DYNAMIC_LINKING
return EntryType(); #else
const auto so_filename = ConvertKeyToSoFilename(key); void *handle = dlopen(so_filename.c_str(), RTLD_LAZY); if (handle == nullptr) { LOG(ERROR) << "GenericRegister::GetEntry: " << dlerror(); return EntryType(); } #ifdef RUN_MODULE_INITIALIZERS
RUN_MODULE_INITIALIZERS(); #endif
// We assume that the DSO constructs a static object in its global scope
// that does the registration. Thus we need only load it, not call any
// methods.
const auto *entry = this->LookupEntry(key); if (entry == nullptr) { LOG(ERROR) << "GenericRegister::GetEntry: " << "lookup failed in shared object: " << so_filename; return EntryType(); } return *entry; #endif // FST_NO_DYNAMIC_LINKING
}
// Override this to define how to turn a key into an SO filename.
virtual std::string ConvertKeyToSoFilename(KeyLookupRef key) const = 0;
virtual const EntryType *LookupEntry(KeyLookupRef key) const { MutexLock l(®ister_lock_); if (const auto it = register_table_.find(key); it != register_table_.end()) { return &it->second; } else { return nullptr; } }
private: mutable Mutex register_lock_; std::map<KeyType, EntryType, std::less<>> register_table_; };
// Generic register-er class capable of creating new register entries in the
// given RegisterType template parameter. This type must define types Key and
// Entry, and have appropriate static GetRegister() and instance SetEntry()
// functions. An easy way to accomplish this is to have RegisterType be the
// type of a subclass of GenericRegister.
template <class RegisterType> class GenericRegisterer { public: using Key = typename RegisterType::Key; using Entry = typename RegisterType::Entry;
GenericRegisterer(Key key, Entry entry) { RegisterType::GetRegister()->SetEntry(key, entry); } };
} // namespace fst
#endif // FST_GENERIC_REGISTER_H_
|