// bi-table.h
// 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: riley@google.com (Michael Riley)
//
// \file
// Classes for representing a bijective mapping between an arbitrary entry
// of type T and a signed integral ID.
#ifndef FST_LIB_BI_TABLE_H__
#define FST_LIB_BI_TABLE_H__
#include <deque>
using std::deque;
#include <functional>
#include <vector>
using std::vector;
#include <tr1/unordered_set>
using std::tr1::unordered_set;
using std::tr1::unordered_multiset;
namespace fst {
// BI TABLES - these determine a bijective mapping between an
// arbitrary entry of type T and an signed integral ID of type I. The IDs are
// allocated starting from 0 in order.
//
// template <class I, class T>
// class BiTable {
// public:
//
// // Required constructors.
// BiTable();
//
// // Lookup integer ID from entry. If it doesn't exist and 'insert'
// / is true, then add it. Otherwise return -1.
// I FindId(const T &entry, bool insert = true);
// // Lookup entry from integer ID.
// const T &FindEntry(I) const;
// // # of stored entries.
// I Size() const;
// };
// An implementation using a hash map for the entry to ID mapping.
// H is the hash function and E is the equality function.
// If passed to the constructor, ownership is given to this class.
template <class I, class T, class H, class E = std::equal_to<T> >
class HashBiTable {
public:
// Reserves space for 'table_size' elements.
explicit HashBiTable(size_t table_size = 0, H *h = 0, E *e = 0)
: hash_func_(h),
hash_equal_(e),
entry2id_(table_size, (h ? *h : H()), (e ? *e : E())) {
if (table_size)
id2entry_.reserve(table_size);
}
HashBiTable(const HashBiTable<I, T, H, E> &table)
: hash_func_(table.hash_func_ ? new H(*table.hash_func_) : 0),
hash_equal_(table.hash_equal_ ? new E(*table.hash_equal_) : 0),
entry2id_(table.entry2id_.begin(), table.entry2id_.end(),
table.entry2id_.size(),
(hash_func_ ? *hash_func_ : H()),
(hash_equal_ ? *hash_equal_ : E())),
id2entry_(table.id2entry_) { }
~HashBiTable() {
delete hash_func_;
delete hash_equal_;
}
I FindId(const T &entry, bool insert = true) {
I &id_ref = entry2id_[entry];
if (id_ref == 0) { // T not found
if (insert) { // store and assign it a new ID
id2entry_.push_back(entry);
id_ref = id2entry_.size();
} else {
return -1;
}
}
return id_ref - 1; // NB: id_ref = ID + 1
}
const T &FindEntry(I s) const {
return id2entry_[s];
}
I Size() const { return id2entry_.size(); }
private:
H *hash_func_;
E *hash_equal_;
unordered_map<T, I, H, E> entry2id_;
vector<T> id2entry_;
void operator=(const HashBiTable<I, T, H, E> &table); // disallow
};
// Enables alternative hash set representations below.
// typedef enum { HS_STL = 0, HS_DENSE = 1, HS_SPARSE = 2 } HSType;
typedef enum { HS_STL = 0, HS_DENSE = 1, HS_SPARSE = 2 } HSType;
// Default hash set is STL hash_set
template<class K, class H, class E, HSType>
struct HashSet : public unordered_set<K, H, E> {
HashSet(size_t n = 0, const H &h = H(), const E &e = E())
: unordered_set<K, H, E>(n, h, e) { }
void rehash(size_t n) { }
};
// An implementation using a hash set for the entry to ID mapping.
// The hash set holds 'keys' which are either the ID or kCurrentKey.
// These keys can be mapped to entrys either by looking up in the
// entry vector or, if kCurrentKey, in current_entry_ member. The hash
// and key equality functions map to entries first. H
// is the hash function and E is the equality function. If passed to
// the constructor, ownership is given to this class.
template <class I, class T, class H,
class E = std::equal_to<T>, HSType HS = HS_DENSE>
class CompactHashBiTable {
public:
friend class HashFunc;
friend class HashEqual;
// Reserves space for 'table_size' elements.
explicit CompactHashBiTable(size_t table_size = 0, H *h = 0, E *e = 0)
: hash_func_(h),
hash_equal_(e),
compact_hash_func_(*this),
compact_hash_equal_(*this),
keys_(table_size, compact_hash_func_, compact_hash_equal_) {
if (table_size)
id2entry_.reserve(table_size);
}
CompactHashBiTable(const CompactHashBiTable<I, T, H, E, HS> &table)
: hash_func_(table.hash_func_ ? new H(*table.hash_func_) : 0),
hash_equal_(table.hash_equal_ ? new E(*table.hash_equal_) : 0),
compact_hash_func_(*this),
compact_hash_equal_(*this),
keys_(table.keys_.size(), compact_hash_func_, compact_hash_equal_),
id2entry_(table.id2entry_) {
keys_.insert(table.keys_.begin(), table.keys_.end());
}
~CompactHashBiTable() {
delete hash_func_;
delete hash_equal_;
}
I FindId(const T &entry, bool insert = true) {
current_entry_ = &entry;
typename KeyHashSet::const_iterator it = keys_.find(kCurrentKey);
if (it == keys_.end()) { // T not found
if (insert) { // store and assign it a new ID
I key = id2entry_.size();
id2entry_.push_back(entry);
keys_.insert(key);
return key;
} else {
return -1;
}
} else {
return *it;
}
}
const T &FindEntry(I s) const { return id2entry_[s]; }
I Size() const { return id2entry_.size(); }
// Clear content. With argument, erases last n IDs.
void Clear(ssize_t n = -1) {
if (n < 0 || n > id2entry_.size())
n = id2entry_.size();
while (n-- > 0) {
I key = id2entry_.size() - 1;
keys_.erase(key);
id2entry_.pop_back();
}
keys_.rehash(0);
}
private:
static const I kCurrentKey; // -1
static const I kEmptyKey; // -2
static const I kDeletedKey; // -3
class HashFunc {
public:
HashFunc(const CompactHashBiTable &ht) : ht_(&ht) {}
size_t operator()(I k) const {
if (k >= kCurrentKey) {
return (*ht_->hash_func_)(ht_->Key2Entry