// fst-register.h // // 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. // // // \file // Classes for registering derived Fsts for generic reading // #ifndef FST_LIB_REGISTER_H__ #define FST_LIB_REGISTER_H__ #include #include #include #include "fst/lib/compat.h" extern "C" { typedef void (*FstInitFunc)(); } namespace fst { template class Fst; struct FstReadOptions; // This class holds the mapping from Fst name string to its reader // and converter. template class FstRegister { public: typedef Fst *(*Reader)(istream &strm, const FstReadOptions &opts); typedef Fst *(*Converter)(const Fst &fst); struct Entry { Reader reader; Converter converter; Entry() : reader(0), converter(0) {} }; static FstRegister *GetRegister() { pthread_once(®ister_init_, &FstRegister::Init); return register_; } Reader GetReader(const string &type) const { return GetEntry(type).reader; } Converter GetConverter(const string &type) const { return GetEntry(type).converter; } void SetEntry(const string &type, const Entry &entry) { MutexLock l(register_lock_); fst_table_.insert(make_pair(type, entry)); } private: static void Init() { register_lock_ = new Mutex; register_ = new FstRegister; } Entry LookupEntry(const string &type) const { MutexLock l(register_lock_); typename map::const_iterator it = fst_table_.find(type); if (it != fst_table_.end()) return it->second; else return Entry(); } Entry GetEntry(const string &type) const { #ifdef FST_DL Entry entry = LookupEntry(type); if (entry.reader) return entry; string so_file = type + "-fst.so"; void *handle = dlopen(so_file.c_str(), RTLD_LAZY); if (handle == 0) { LOG(ERROR) << "FstRegister::GetEntry: " << dlerror(); return entry; } string init_name = type + "_fst_init"; FstInitFunc init_func = bit_cast(dlsym(handle, init_name.c_str())); if (init_func == 0) { LOG(ERROR) << "FstRegister::GetEntry: " << dlerror(); return entry; } (*init_func)(); #endif // FST_DL return LookupEntry(type); } static pthread_once_t register_init_; // ensures only called once static Mutex* register_lock_; // multithreading lock static FstRegister *register_; map fst_table_; }; template pthread_once_t FstRegister::register_init_ = PTHREAD_ONCE_INIT; template Mutex *FstRegister::register_lock_ = 0; template FstRegister *FstRegister::register_ = 0; // This class registers an Fst type for generic reading and creating. // The Fst type must have a default constructor and a copy constructor // from 'Fst' for this to work. template class FstRegisterer { public: typedef typename F::Arc Arc; typedef typename FstRegister::Entry Entry; typedef typename FstRegister::Reader Reader; FstRegisterer() { F fst; F *(*reader)(istream &strm, const FstReadOptions &opts) = &F::Read; Entry entry; entry.reader = reinterpret_cast(reader); entry.converter = &FstRegisterer::Convert; FstRegister *registr = FstRegister::GetRegister(); registr->SetEntry(fst.Type(), entry); } private: static Fst *Convert(const Fst &fst) { return new F(fst); } }; // Convenience macro to generate static FstRegisterer instance. #define REGISTER_FST(F, A) \ static fst::FstRegisterer< F > F ## _ ## A ## _registerer // Converts an fst to type 'type'. template Fst *Convert(const Fst &fst, const string &ftype) { FstRegister *registr = FstRegister::GetRegister(); const typename FstRegister::Converter converter = registr->GetConverter(ftype); if (!converter) { string atype = A::Type(); LOG(ERROR) << "Fst::Convert: Unknown FST type \"" << ftype << "\" (arc type = \"" << atype << "\")"; return 0; } return converter(fst); } } // namespace fst; #endif // FST_LIB_REGISTER_H__