14a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// fst-register.h
24a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
34a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Licensed under the Apache License, Version 2.0 (the "License");
44a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// you may not use this file except in compliance with the License.
54a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// You may obtain a copy of the License at
64a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
74a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//      http://www.apache.org/licenses/LICENSE-2.0
84a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
94a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Unless required by applicable law or agreed to in writing, software
104a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// distributed under the License is distributed on an "AS IS" BASIS,
114a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// See the License for the specific language governing permissions and
134a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// limitations under the License.
144a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
154a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
164a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// \file
174a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Classes for registering derived Fsts for generic reading
184a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project//
194a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
204a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#ifndef FST_LIB_REGISTER_H__
214a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#define FST_LIB_REGISTER_H__
224a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
234a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include <map>
244a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
254a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include <dlfcn.h>
264a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include <pthread.h>
274a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
284a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#include "fst/lib/compat.h"
294a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
304a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectextern "C" {
314a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef void (*FstInitFunc)();
324a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project}
334a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
344a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectnamespace fst {
354a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
364a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A> class Fst;
374a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectstruct FstReadOptions;
384a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
394a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// This class holds the mapping from Fst name string to its reader
404a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// and converter.
414a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A>
424a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectclass FstRegister {
434a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project public:
444a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef Fst<A> *(*Reader)(istream &strm, const FstReadOptions &opts);
454a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef Fst<A> *(*Converter)(const Fst<A> &fst);
464a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
474a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  struct Entry {
484a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    Reader reader;
494a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    Converter converter;
504a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    Entry() : reader(0), converter(0) {}
514a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  };
524a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
534a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static FstRegister<A> *GetRegister() {
544a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    pthread_once(&register_init_, &FstRegister<A>::Init);
554a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    return register_;
564a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
574a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
5873018b4a1d088cdda0e7bd059fddf1f308a8195aIan Rogers  Reader GetReader(const string &type) const {
594a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    return GetEntry(type).reader;
604a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
614a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
6273018b4a1d088cdda0e7bd059fddf1f308a8195aIan Rogers  Converter GetConverter(const string &type) const {
634a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    return GetEntry(type).converter;
644a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
654a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
664a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  void SetEntry(const string &type, const Entry &entry) {
674a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    MutexLock l(register_lock_);
684a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    fst_table_.insert(make_pair(type, entry));
694a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
704a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
714a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project private:
724a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static void Init() {
734a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    register_lock_ = new Mutex;
744a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    register_ = new FstRegister<A>;
754a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
764a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
774a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  Entry LookupEntry(const string &type) const {
784a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    MutexLock l(register_lock_);
794a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    typename map<string, Entry>::const_iterator it = fst_table_.find(type);
804a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    if (it != fst_table_.end())
814a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      return it->second;
824a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    else
834a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      return Entry();
844a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
854a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
864a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  Entry GetEntry(const string &type) const {
874a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#ifdef FST_DL
884a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    Entry entry = LookupEntry(type);
894a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    if (entry.reader)
904a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      return entry;
914a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    string so_file = type + "-fst.so";
924a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    void *handle = dlopen(so_file.c_str(), RTLD_LAZY);
934a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    if (handle == 0) {
944a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
954a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      return entry;
964a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    }
974a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    string init_name = type + "_fst_init";
984a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    FstInitFunc init_func =
994a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project        bit_cast<FstInitFunc>(dlsym(handle, init_name.c_str()));
1004a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    if (init_func == 0) {
1014a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      LOG(ERROR) << "FstRegister::GetEntry: " << dlerror();
1024a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      return entry;
1034a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    }
1044a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    (*init_func)();
1054a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#endif  // FST_DL
1064a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    return LookupEntry(type);
1074a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
1084a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1094a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static pthread_once_t register_init_;   // ensures only called once
1104a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static Mutex* register_lock_;           // multithreading lock
1114a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static FstRegister<A> *register_;
1124a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1134a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  map<string, Entry> fst_table_;
1144a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project};
1154a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1164a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A>
1174a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectpthread_once_t FstRegister<A>::register_init_ = PTHREAD_ONCE_INIT;
1184a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1194a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A>
1204a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source ProjectMutex *FstRegister<A>::register_lock_ = 0;
1214a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1224a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A>
1234a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source ProjectFstRegister<A> *FstRegister<A>::register_ = 0;
1244a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1254a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// This class registers an Fst type for generic reading and creating.
1264a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// The Fst type must have a default constructor and a copy constructor
1274a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// from 'Fst<Arc>' for this to work.
1284a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class F>
1294a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectclass FstRegisterer {
1304a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project public:
1314a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef typename F::Arc Arc;
1324a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef typename FstRegister<Arc>::Entry Entry;
1334a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  typedef typename FstRegister<Arc>::Reader Reader;
1344a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1354a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  FstRegisterer() {
1364a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    F fst;
1374a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    F *(*reader)(istream &strm,
1384a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project                 const FstReadOptions &opts) = &F::Read;
1394a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    Entry entry;
1404a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    entry.reader = reinterpret_cast<Reader>(reader);
1414a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    entry.converter = &FstRegisterer<F>::Convert;
1424a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    FstRegister<Arc> *registr = FstRegister<Arc>::GetRegister();
1434a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    registr->SetEntry(fst.Type(), entry);
1444a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
1454a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1464a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project private:
1474a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  static Fst<Arc> *Convert(const Fst<Arc> &fst) { return new F(fst); }
1484a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project};
1494a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1504a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1514a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Convenience macro to generate static FstRegisterer instance.
1524a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#define REGISTER_FST(F, A) \
1534a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projectstatic fst::FstRegisterer< F<A> > F ## _ ## A ## _registerer
1544a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1554a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1564a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project// Converts an fst to type 'type'.
1574a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Projecttemplate <class A>
1584a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source ProjectFst<A> *Convert(const Fst<A> &fst, const string &ftype) {
1594a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  FstRegister<A> *registr = FstRegister<A>::GetRegister();
1604a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  const typename FstRegister<A>::Converter
1614a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project      converter = registr->GetConverter(ftype);
1624a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  if (!converter) {
1634a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    string atype = A::Type();
1644a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    LOG(ERROR) << "Fst::Convert: Unknown FST type \"" << ftype
1654a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project               << "\" (arc type = \"" << atype << "\")";
1664a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project    return 0;
1674a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  }
1684a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project  return converter(fst);
1694a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project}
1704a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1714a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project}  // namespace fst;
1724a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project
1734a68b3365c8c50aa93505e99ead2565ab73dcdb0The Android Open Source Project#endif  // FST_LIB_REGISTER_H__
174