Home | History | Annotate | Download | only in lib
      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 
     30 extern "C" {
     31   typedef void (*FstInitFunc)();
     32 }
     33 
     34 namespace fst {
     35 
     36 template <class A> class Fst;
     37 struct FstReadOptions;
     38 
     39 // This class holds the mapping from Fst name string to its reader
     40 // and converter.
     41 template <class A>
     42 class 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(&register_init_, &FstRegister<A>::Init);
     55     return register_;
     56   }
     57 
     58   Reader GetReader(const string &type) const {
     59     return GetEntry(type).reader;
     60   }
     61 
     62   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 
    116 template <class A>
    117 pthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT;
    118 
    119 template <class A>
    120 Mutex *FstRegister<A>::register_lock_ = 0;
    121 
    122 template <class A>
    123 FstRegister<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.
    128 template <class F>
    129 class 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) \
    153 static fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer
    154 
    155 
    156 // Converts an fst to type 'type'.
    157 template <class A>
    158 Fst<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