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