blob: 4f8b5125210368e19de890735aa4d4328ead678c [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2005-2010 Google, Inc.
// Author: jpr@google.com (Jake Ratkiewicz)
#ifndef FST_LIB_GENERIC_REGISTER_H_
#define FST_LIB_GENERIC_REGISTER_H_
#include <map>
#include <string>
#include <fst/compat.h>
#include <fst/types.h>
// Generic class representing a globally-stored correspondence between
// objects of KeyType and EntryType.
// KeyType must:
// a) be such as can be stored as a key in a map<>
// b) be concatenable with a const char* with the + operator
// (or you must subclass and redefine LoadEntryFromSharedObject)
// EntryType must be default constructible.
//
// The third template parameter should be the type of a subclass of this class
// (think CRTP). This is to allow GetRegister() to instantiate and return
// an object of the appropriate type.
namespace fst {
template<class KeyType, class EntryType, class RegisterType>
class GenericRegister {
public:
typedef KeyType Key;
typedef EntryType Entry;
static RegisterType *GetRegister() {
FstOnceInit(&register_init_,
&RegisterType::Init);
return register_;
}
void SetEntry(const KeyType &key,
const EntryType &entry) {
MutexLock l(register_lock_);
register_table_.insert(make_pair(key, entry));
}
EntryType GetEntry(const KeyType &key) const {
const EntryType *entry = LookupEntry(key);
if (entry) {
return *entry;
} else {
return LoadEntryFromSharedObject(key);
}
}
virtual ~GenericRegister() { }
protected:
// Override this if you want to be able to load missing definitions from
// shared object files.
virtual EntryType LoadEntryFromSharedObject(const KeyType &key) const {
string so_filename = ConvertKeyToSoFilename(key);
void *handle = dlopen(so_filename.c_str(), RTLD_LAZY);
if (handle == 0) {
LOG(ERROR) << "GenericRegister::GetEntry : " << dlerror();
return EntryType();
}
// We assume that the DSO constructs a static object in its global
// scope that does the registration. Thus we need only load it, not
// call any methods.
const EntryType *entry = this->LookupEntry(key);
if (entry == 0) {
LOG(ERROR) << "GenericRegister::GetEntry : "
<< "lookup failed in shared object: " << so_filename;
return EntryType();
}
return *entry;
}
// Override this to define how to turn a key into an SO filename.
virtual string ConvertKeyToSoFilename(const KeyType& key) const = 0;
virtual const EntryType *LookupEntry(
const KeyType &key) const {
MutexLock l(register_lock_);
typename RegisterMapType::const_iterator it = register_table_.find(key);
if (it != register_table_.end()) {
return &it->second;
} else {
return 0;
}
}
private:
typedef map<KeyType, EntryType> RegisterMapType;
static void Init() {
register_lock_ = new Mutex;
register_ = new RegisterType;
}
static FstOnceType register_init_;
static Mutex *register_lock_;
static RegisterType *register_;
RegisterMapType register_table_;
};
template<class KeyType, class EntryType, class RegisterType>
FstOnceType GenericRegister<KeyType, EntryType,
RegisterType>::register_init_ = FST_ONCE_INIT;
template<class KeyType, class EntryType, class RegisterType>
Mutex *GenericRegister<KeyType, EntryType, RegisterType>::register_lock_ = 0;
template<class KeyType, class EntryType, class RegisterType>
RegisterType *GenericRegister<KeyType, EntryType, RegisterType>::register_ = 0;
//
// GENERIC REGISTRATION
//
// Generic register-er class capable of creating new register entries in the
// given RegisterType template parameter. This type must define types Key
// and Entry, and have appropriate static GetRegister() and instance
// SetEntry() functions. An easy way to accomplish this is to have RegisterType
// be the type of a subclass of GenericRegister.
template<class RegisterType>
class GenericRegisterer {
public:
typedef typename RegisterType::Key Key;
typedef typename RegisterType::Entry Entry;
GenericRegisterer(Key key, Entry entry) {
RegisterType *reg = RegisterType::GetRegister();
reg->SetEntry(key, entry);
}
};
} // namespace fst
#endif // FST_LIB_GENERIC_REGISTER_H_