1// fst-register.h 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// 16// \file 17// Classes for registering derived Fsts for generic reading 18// 19 20#ifndef FST_LIB_REGISTER_H__ 21#define FST_LIB_REGISTER_H__ 22 23#include <map> 24 25#include <dlfcn.h> 26#include <pthread.h> 27 28#include "fst/lib/compat.h" 29 30extern "C" { 31 typedef void (*FstInitFunc)(); 32} 33 34namespace fst { 35 36template <class A> class Fst; 37struct FstReadOptions; 38 39// This class holds the mapping from Fst name string to its reader 40// and converter. 41template <class A> 42class FstRegister { 43 public: 44 typedef Fst<A> *(*Reader)(istream &strm, const FstReadOptions &opts); 45 typedef Fst<A> *(*Converter)(const Fst<A> &fst); 46 47 struct Entry { 48 Reader reader; 49 Converter converter; 50 Entry() : reader(0), converter(0) {} 51 }; 52 53 static FstRegister<A> *GetRegister() { 54 pthread_once(®ister_init_, &FstRegister<A>::Init); 55 return register_; 56 } 57 58 const Reader GetReader(const string &type) const { 59 return GetEntry(type).reader; 60 } 61 62 const Converter GetConverter(const string &type) const { 63 return GetEntry(type).converter; 64 } 65 66 void SetEntry(const string &type, const Entry &entry) { 67 MutexLock l(register_lock_); 68 fst_table_.insert(make_pair(type, entry)); 69 } 70 71 private: 72 static void Init() { 73 register_lock_ = new Mutex; 74 register_ = new FstRegister<A>; 75 } 76 77 Entry LookupEntry(const string &type) const { 78 MutexLock l(register_lock_); 79 typename map<string, Entry>::const_iterator it = fst_table_.find(type); 80 if (it != fst_table_.end()) 81 return it->second; 82 else 83 return Entry(); 84 } 85 86 Entry GetEntry(const string &type) const { 87#ifdef FST_DL 88 Entry entry = LookupEntry(type); 89 if (entry.reader) 90 return entry; 91 string so_file = type + "-fst.so"; 92 void *handle = dlopen(so_file.c_str(), RTLD_LAZY); 93 if (handle == 0) { 94 LOG(ERROR) << "FstRegister::GetEntry: " << dlerror(); 95 return entry; 96 } 97 string init_name = type + "_fst_init"; 98 FstInitFunc init_func = 99 bit_cast<FstInitFunc>(dlsym(handle, init_name.c_str())); 100 if (init_func == 0) { 101 LOG(ERROR) << "FstRegister::GetEntry: " << dlerror(); 102 return entry; 103 } 104 (*init_func)(); 105#endif // FST_DL 106 return LookupEntry(type); 107 } 108 109 static pthread_once_t register_init_; // ensures only called once 110 static Mutex* register_lock_; // multithreading lock 111 static FstRegister<A> *register_; 112 113 map<string, Entry> fst_table_; 114}; 115 116template <class A> 117pthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT; 118 119template <class A> 120Mutex *FstRegister<A>::register_lock_ = 0; 121 122template <class A> 123FstRegister<A> *FstRegister<A>::register_ = 0; 124 125// This class registers an Fst type for generic reading and creating. 126// The Fst type must have a default constructor and a copy constructor 127// from 'Fst<Arc>' for this to work. 128template <class F> 129class FstRegisterer { 130 public: 131 typedef typename F::Arc Arc; 132 typedef typename FstRegister<Arc>::Entry Entry; 133 typedef typename FstRegister<Arc>::Reader Reader; 134 135 FstRegisterer() { 136 F fst; 137 F *(*reader)(istream &strm, 138 const FstReadOptions &opts) = &F::Read; 139 Entry entry; 140 entry.reader = reinterpret_cast<Reader>(reader); 141 entry.converter = &FstRegisterer<F>::Convert; 142 FstRegister<Arc> *registr = FstRegister<Arc>::GetRegister(); 143 registr->SetEntry(fst.Type(), entry); 144 } 145 146 private: 147 static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new F(fst); } 148}; 149 150 151// Convenience macro to generate static FstRegisterer instance. 152#define REGISTER_FST(F, A) \ 153static fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer 154 155 156// Converts an fst to type 'type'. 157template <class A> 158Fst<A> *Convert(const Fst<A> &fst, const string &ftype) { 159 FstRegister<A> *registr = FstRegister<A>::GetRegister(); 160 const typename FstRegister<A>::Converter 161 converter = registr->GetConverter(ftype); 162 if (!converter) { 163 string atype = A::Type(); 164 LOG(ERROR) << "Fst::Convert: Unknown FST type \"" << ftype 165 << "\" (arc type = \"" << atype << "\")"; 166 return 0; 167 } 168 return converter(fst); 169} 170 171} // namespace fst; 172 173#endif // FST_LIB_REGISTER_H__ 174