add-on.h revision f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// add-on.h
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Licensed under the Apache License, Version 2.0 (the "License");
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// you may not use this file except in compliance with the License.
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// You may obtain a copy of the License at
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//     http://www.apache.org/licenses/LICENSE-2.0
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Unless required by applicable law or agreed to in writing, software
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// distributed under the License is distributed on an "AS IS" BASIS,
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// See the License for the specific language governing permissions and
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// limitations under the License.
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Copyright 2005-2010 Google, Inc.
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Author: riley@google.com (Michael Riley)
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// \file
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Fst implementation class to attach an arbitrary object with a
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// read/write method to an FST and its file rep. The FST is given a
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// new type name.
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef FST_LIB_ADD_ON_FST_H__
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FST_LIB_ADD_ON_FST_H__
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <stddef.h>
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <string>
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <fst/fst.h>
307886ad3de1aa523d5c71f1fa9f355dfcb2412d1dreed@google.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comnamespace fst {
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Identifies stream data as an add-on fst.
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic const int32 kAddOnMagicNumber = 446681434;
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Some useful add-on objects.
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Nothing to save.
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass NullAddOn {
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  NullAddOn() {}
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  static NullAddOn *Read(istream &istrm) {
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return new NullAddOn();
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  };
5004423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
5104423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  bool Write(ostream &ostrm) const { return true; }
5204423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
5304423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  int RefCount() const { return ref_count_.count(); }
5404423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  int IncrRefCount() { return ref_count_.Incr(); }
5504423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  int DecrRefCount() { return ref_count_.Decr(); }
5604423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
5704423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com private:
58cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com  RefCounter ref_count_;
59cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
60cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com  DISALLOW_COPY_AND_ASSIGN(NullAddOn);
61cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com};
6204423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
6304423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
6404423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com// Create a new add-on from a pair of add-ons.
6504423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.comtemplate <class A1, class A2>
6604423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.comclass AddOnPair {
6704423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com public:
6804423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  // Argument reference count incremented.
6904423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  AddOnPair(A1 *a1, A2 *a2)
7004423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com      : a1_(a1), a2_(a2) {
713a52d68b4001afd8c7036e80558fba7c87f45a0cbsalomon@google.com    if (a1_)
723a52d68b4001afd8c7036e80558fba7c87f45a0cbsalomon@google.com      a1_->IncrRefCount();
733a52d68b4001afd8c7036e80558fba7c87f45a0cbsalomon@google.com    if (a2_)
743a52d68b4001afd8c7036e80558fba7c87f45a0cbsalomon@google.com      a2_->IncrRefCount();
7504423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  }
7604423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com
7704423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  ~AddOnPair() {
7804423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com    if (a1_ && !a1_->DecrRefCount())
7904423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com      delete a1_;
80fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com    if (a2_ && !a2_->DecrRefCount())
81fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com      delete a2_;
82fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com  }
83fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com
84fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com  A1 *First() const { return a1_; }
85fffb2f1bda1982d451bc249743b8cc414995d6a8justinlin@google.com  A2 *Second() const { return a2_; }
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  static AddOnPair<A1, A2> *Read(istream &istrm) {
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    A1 *a1 = 0;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_addon1 = false;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ReadType(istrm, &have_addon1);
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (have_addon1)
92c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com      a1 = A1::Read(istrm);
93c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com
94c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com    A2 *a2 = 0;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_addon2 = false;
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ReadType(istrm, &have_addon2);
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (have_addon2)
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      a2 = A2::Read(istrm);
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AddOnPair<A1, A2> *a = new AddOnPair<A1, A2>(a1, a2);
101b1277c96b0818550190be134fd5e9a971087120bbsalomon@google.com    if (a1)
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      a1->DecrRefCount();
103b1277c96b0818550190be134fd5e9a971087120bbsalomon@google.com    if (a2)
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      a2->DecrRefCount();
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return a;
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  };
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  bool Write(ostream &ostrm) const {
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_addon1 = a1_;
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    WriteType(ostrm, have_addon1);
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (have_addon1)
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      a1_->Write(ostrm);
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_addon2 = a2_;
1145c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    WriteType(ostrm, have_addon2);
1155c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    if (have_addon2)
1165c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com      a2_->Write(ostrm);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12016690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com  int RefCount() const { return ref_count_.count(); }
12116690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com
12216690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com  int IncrRefCount() {
12316690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com    return ref_count_.Incr();
12416690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com  }
12516690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int DecrRefCount() {
12716690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com    return ref_count_.Decr();
12816690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com  }
12916690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com
13016690af1c21dead3eedb25ebd0a4b9a091684ed4reed@android.com private:
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  A1 *a1_;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  A2 *a2_;
13304423805455de868b1b468cfe4057cb77f74b6b0bsalomon@google.com  RefCounter ref_count_;
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
135f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com  DISALLOW_COPY_AND_ASSIGN(AddOnPair);
136f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com};
137f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
138f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
139f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com// Add to an Fst F a type T object. T must have a 'T* Read(istream &)',
140f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com// a 'bool Write(ostream &)' method, and 'int RecCount(), 'int IncrRefCount()'
141f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com// and 'int DecrRefCount()' methods (e.g. 'MatcherData' in matcher-fst.h).
142f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com// The result is a new Fst implemenation with type name 'type'.
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtemplate<class F, class T>
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass AddOnImpl : public FstImpl<typename F::Arc> {
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  typedef typename F::Arc Arc;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  typedef typename Arc::Label Label;
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  typedef typename Arc::Weight Weight;
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  typedef typename Arc::StateId StateId;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  using FstImpl<Arc>::SetType;
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  using FstImpl<Arc>::SetProperties;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  using FstImpl<Arc>::WriteHeader;
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // If 't' is non-zero, its reference count is incremented.
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddOnImpl(const F &fst, const string &type, T *t = 0)
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      : fst_(fst), t_(t) {
15827661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetType(type);
15927661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetProperties(fst_.Properties(kFstProperties, false));
16027661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    if (t_)
16127661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com      t_->IncrRefCount();
16227661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com  }
16327661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com
16427661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com  // If 't' is non-zero, its reference count is incremented.
16527661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com  AddOnImpl(const Fst<Arc> &fst, const string &type, T *t = 0)
16627661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com      : fst_(fst), t_(t) {
16727661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetType(type);
16827661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetProperties(fst_.Properties(kFstProperties, false));
16927661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    if (t_)
17027661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com      t_->IncrRefCount();
17127661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com  }
17227661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com
17327661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com  AddOnImpl(const AddOnImpl<F, T> &impl)
17427661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com      : fst_(impl.fst_), t_(impl.t_) {
17527661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetType(impl.Type());
17627661181d757145d98f2dc3e02b88ee3fffce9e5bsalomon@google.com    SetProperties(fst_.Properties(kCopyProperties, false));
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (t_)
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      t_->IncrRefCount();
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ~AddOnImpl() {
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (t_ && !t_->DecrRefCount())
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      delete t_;
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  StateId Start() const { return fst_.Start(); }
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  Weight Final(StateId s) const { return fst_.Final(s); }
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  size_t NumArcs(StateId s) const { return fst_.NumArcs(s); }
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  size_t NumInputEpsilons(StateId s) const {
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fst_.NumInputEpsilons(s);
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  size_t NumOutputEpsilons(StateId s) const {
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fst_.NumOutputEpsilons(s);
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  size_t NumStates() const { return fst_.NumStates(); }
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  static AddOnImpl<F, T> *Read(istream &strm, const FstReadOptions &opts) {
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    FstReadOptions nopts(opts);
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    FstHeader hdr;
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!nopts.header) {
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      hdr.Read(strm, nopts.source);
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      nopts.header = &hdr;
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AddOnImpl<F, T> *impl = new AddOnImpl<F, T>(nopts.header->FstType());
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!impl->ReadHeader(strm, nopts, kMinFileVersion, &hdr))
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      return 0;
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    delete impl;       // Used here only for checking types.
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32 magic_number = 0;
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ReadType(strm, &magic_number);   // Ensures this is an add-on Fst.
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (magic_number != kAddOnMagicNumber) {
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      LOG(ERROR) << "AddOnImpl::Read: Bad add-on header: " << nopts.source;
2165c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com      return 0;
2175c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    }
2185c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com
2195c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    FstReadOptions fopts(opts);
2205c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    fopts.header = 0;  // Contained header was written out.
2215c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    F *fst = F::Read(strm, fopts);
2225c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    if (!fst)
2235c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com      return 0;
2245c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com
2255c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    T *t = 0;
2265c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    bool have_addon = false;
2275c80ea17d4e4a795bfaeb260fc27e952ba471f1dreed@android.com    ReadType(strm, &have_addon);
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (have_addon) {   // Read add-on object if present.
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      t = T::Read(strm);
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (!t)
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    impl = new AddOnImpl<F, T>(*fst, nopts.header->FstType(), t);
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    delete fst;
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (t)
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      t->DecrRefCount();
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return impl;
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  bool Write(ostream &strm, const FstWriteOptions &opts) const {
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    FstHeader hdr;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    FstWriteOptions nopts(opts);
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    nopts.write_isymbols = false;  // Let contained FST hold any symbols.
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    nopts.write_osymbols = false;
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    WriteHeader(strm, nopts, kFileVersion, &hdr);
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    WriteType(strm, kAddOnMagicNumber);  // Ensures this is an add-on Fst.
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    FstWriteOptions fopts(opts);
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fopts.write_header = true;     // Force writing contained header.
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!fst_.Write(strm, fopts))
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      return false;
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_addon = t_;
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    WriteType(strm, have_addon);
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (have_addon)                // Write add-on object if present.
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      t_->Write(strm);
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void InitStateIterator(StateIteratorData<Arc> *data) const {
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fst_.InitStateIterator(data);
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fst_.InitArcIterator(s, data);
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  F &GetFst() { return fst_; }
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const F &GetFst() const { return fst_; }
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  T *GetAddOn() const { return t_; }
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // If 't' is non-zero, its reference count is incremented.
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetAddOn(T *t) {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (t == t_)
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      return;
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (t_ && !t_->DecrRefCount())
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      delete t_;
2781341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com    t_ = t;
2791341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com    if (t_)
2801341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com      t_->IncrRefCount();
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2831341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com private:
2841341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com  explicit AddOnImpl(const string &type) : t_(0) {
2851341304449a60713bf9c8ea2e9489f35533f037atomhudson@google.com    SetType(type);
286ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com    SetProperties(kExpanded);
287ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  }
288ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com
289ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  // Current file format version
290ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  static const int kFileVersion = 1;
291ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  // Minimum file format version supported
292ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  static const int kMinFileVersion = 1;
293ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com
294ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  F fst_;
295ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  T *t_;
296ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com
297ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com  void operator=(const AddOnImpl<F, T> &fst);  // Disallow
298ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com};
299ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.com
300ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.comtemplate <class F, class T> const int AddOnImpl<F, T>::kFileVersion;
301ece0100c22e2184245efc380c8dede0fe47517b2george@mozilla.comtemplate <class F, class T> const int AddOnImpl<F, T>::kMinFileVersion;
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
304d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com}  // namespace fst
305d26147adbbdca85f07dff432025afee0c8614387caryclark@google.com
3063a67a668dbdc3a6bba68700a6dfdef8164ae0c69senorblanco@chromium.org#endif  // FST_LIB_ADD_ON_FST_H__
3073a67a668dbdc3a6bba68700a6dfdef8164ae0c69senorblanco@chromium.org