Home | History | Annotate | Download | only in fst
      1 
      2 // Licensed under the Apache License, Version 2.0 (the "License");
      3 // you may not use this file except in compliance with the License.
      4 // You may obtain a copy of the License at
      5 //
      6 //     http://www.apache.org/licenses/LICENSE-2.0
      7 //
      8 // Unless required by applicable law or agreed to in writing, software
      9 // distributed under the License is distributed on an "AS IS" BASIS,
     10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     11 // See the License for the specific language governing permissions and
     12 // limitations under the License.
     13 //
     14 // Copyright 2005-2010 Google, Inc.
     15 // Author: jpr (at) google.com (Jake Ratkiewicz)
     16 
     17 #ifndef FST_LIB_GENERIC_REGISTER_H_
     18 #define FST_LIB_GENERIC_REGISTER_H_
     19 
     20 #include <map>
     21 #include <string>
     22 
     23 #include <fst/compat.h>
     24 #include <fst/types.h>
     25 
     26 // Generic class representing a globally-stored correspondence between
     27 // objects of KeyType and EntryType.
     28 // KeyType must:
     29 //  a) be such as can be stored as a key in a map<>
     30 //  b) be concatenable with a const char* with the + operator
     31 //     (or you must subclass and redefine LoadEntryFromSharedObject)
     32 // EntryType must be default constructible.
     33 //
     34 // The third template parameter should be the type of a subclass of this class
     35 // (think CRTP). This is to allow GetRegister() to instantiate and return
     36 // an object of the appropriate type.
     37 
     38 namespace fst {
     39 
     40 template<class KeyType, class EntryType, class RegisterType>
     41 class GenericRegister {
     42  public:
     43   typedef KeyType Key;
     44   typedef EntryType Entry;
     45 
     46   static RegisterType *GetRegister() {
     47     FstOnceInit(&register_init_,
     48                    &RegisterType::Init);
     49 
     50     return register_;
     51   }
     52 
     53   void SetEntry(const KeyType &key,
     54                 const EntryType &entry) {
     55     MutexLock l(register_lock_);
     56 
     57     register_table_.insert(make_pair(key, entry));
     58   }
     59 
     60   EntryType GetEntry(const KeyType &key) const {
     61     const EntryType *entry = LookupEntry(key);
     62     if (entry) {
     63       return *entry;
     64     } else {
     65       return LoadEntryFromSharedObject(key);
     66     }
     67   }
     68 
     69   virtual ~GenericRegister() { }
     70 
     71  protected:
     72   // Override this if you want to be able to load missing definitions from
     73   // shared object files.
     74   virtual EntryType LoadEntryFromSharedObject(const KeyType &key) const {
     75     string so_filename = ConvertKeyToSoFilename(key);
     76 
     77     void *handle = dlopen(so_filename.c_str(), RTLD_LAZY);
     78     if (handle == 0) {
     79       LOG(ERROR) << "GenericRegister::GetEntry : " << dlerror();
     80       return EntryType();
     81     }
     82 
     83     // We assume that the DSO constructs a static object in its global
     84     // scope that does the registration. Thus we need only load it, not
     85     // call any methods.
     86     const EntryType *entry = this->LookupEntry(key);
     87     if (entry == 0) {
     88       LOG(ERROR) << "GenericRegister::GetEntry : "
     89                  << "lookup failed in shared object: " << so_filename;
     90       return EntryType();
     91     }
     92     return *entry;
     93   }
     94 
     95   // Override this to define how to turn a key into an SO filename.
     96   virtual string ConvertKeyToSoFilename(const KeyType& key) const = 0;
     97 
     98   virtual const EntryType *LookupEntry(
     99       const KeyType &key) const {
    100     MutexLock l(register_lock_);
    101 
    102     typename RegisterMapType::const_iterator it = register_table_.find(key);
    103 
    104     if (it != register_table_.end()) {
    105       return &it->second;
    106     } else {
    107       return 0;
    108     }
    109   }
    110 
    111  private:
    112   typedef map<KeyType, EntryType> RegisterMapType;
    113 
    114   static void Init() {
    115     register_lock_ = new Mutex;
    116     register_ = new RegisterType;
    117   }
    118 
    119   static FstOnceType register_init_;
    120   static Mutex *register_lock_;
    121   static RegisterType *register_;
    122 
    123   RegisterMapType register_table_;
    124 };
    125 
    126 template<class KeyType, class EntryType, class RegisterType>
    127 FstOnceType GenericRegister<KeyType, EntryType,
    128                                RegisterType>::register_init_ = FST_ONCE_INIT;
    129 
    130 template<class KeyType, class EntryType, class RegisterType>
    131 Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0;
    132 
    133 template<class KeyType, class EntryType, class RegisterType>
    134 RegisterType *GenericRegister<KeyType, EntryType, RegisterType>::register_ = 0;
    135 
    136 //
    137 // GENERIC REGISTRATION
    138 //
    139 
    140 // Generic register-er class capable of creating new register entries in the
    141 // given RegisterType template parameter. This type must define types Key
    142 // and Entry, and have appropriate static GetRegister() and instance
    143 // SetEntry() functions. An easy way to accomplish this is to have RegisterType
    144 // be the type of a subclass of GenericRegister.
    145 template<class RegisterType>
    146 class GenericRegisterer {
    147  public:
    148   typedef typename RegisterType::Key Key;
    149   typedef typename RegisterType::Entry Entry;
    150 
    151   GenericRegisterer(Key key, Entry entry) {
    152     RegisterType *reg = RegisterType::GetRegister();
    153     reg->SetEntry(key, entry);
    154   }
    155 };
    156 
    157 }  // namespace fst
    158 
    159 #endif  // FST_LIB_GENERIC_REGISTER_H_
    160