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@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
38namespace fst {
39
40template<class KeyType, class EntryType, class RegisterType>
41class 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
126template<class KeyType, class EntryType, class RegisterType>
127FstOnceType GenericRegister<KeyType, EntryType,
128                               RegisterType>::register_init_ = FST_ONCE_INIT;
129
130template<class KeyType, class EntryType, class RegisterType>
131Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0;
132
133template<class KeyType, class EntryType, class RegisterType>
134RegisterType *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.
145template<class RegisterType>
146class 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