1// expanded-fst.h
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// Copyright 2005-2010 Google, Inc.
16// Author: riley@google.com (Michael Riley)
17//
18// \file
19// Generic FST augmented with state count - interface class definition.
20//
21
22#ifndef FST_LIB_EXPANDED_FST_H__
23#define FST_LIB_EXPANDED_FST_H__
24
25#include <sys/types.h>
26#include <string>
27
28#include <fst/fst.h>
29
30
31namespace fst {
32
33// A generic FST plus state count.
34template <class A>
35class ExpandedFst : public Fst<A> {
36 public:
37  typedef A Arc;
38  typedef typename A::StateId StateId;
39
40  virtual StateId NumStates() const = 0;  // State count
41
42  // Get a copy of this ExpandedFst. See Fst<>::Copy() for further doc.
43  virtual ExpandedFst<A> *Copy(bool safe = false) const = 0;
44
45  // Read an ExpandedFst from an input stream; return NULL on error.
46  static ExpandedFst<A> *Read(istream &strm, const FstReadOptions &opts) {
47    FstReadOptions ropts(opts);
48    FstHeader hdr;
49    if (ropts.header)
50      hdr = *opts.header;
51    else {
52      if (!hdr.Read(strm, opts.source))
53        return 0;
54      ropts.header = &hdr;
55    }
56    if (!(hdr.Properties() & kExpanded)) {
57      LOG(ERROR) << "ExpandedFst::Read: Not an ExpandedFst: " << ropts.source;
58      return 0;
59    }
60    FstRegister<A> *registr = FstRegister<A>::GetRegister();
61    const typename FstRegister<A>::Reader reader =
62      registr->GetReader(hdr.FstType());
63    if (!reader) {
64      LOG(ERROR) << "ExpandedFst::Read: Unknown FST type \"" << hdr.FstType()
65                 << "\" (arc type = \"" << A::Type()
66                 << "\"): " << ropts.source;
67      return 0;
68    }
69    Fst<A> *fst = reader(strm, ropts);
70    if (!fst) return 0;
71    return static_cast<ExpandedFst<A> *>(fst);
72  }
73
74  // Read an ExpandedFst from a file; return NULL on error.
75  // Empty filename reads from standard input.
76  static ExpandedFst<A> *Read(const string &filename) {
77    if (!filename.empty()) {
78      ifstream strm(filename.c_str(), ifstream::in | ifstream::binary);
79      if (!strm) {
80        LOG(ERROR) << "ExpandedFst::Read: Can't open file: " << filename;
81        return 0;
82      }
83      return Read(strm, FstReadOptions(filename));
84    } else {
85      return Read(cin, FstReadOptions("standard input"));
86    }
87  }
88};
89
90
91namespace internal {
92
93//  ExpandedFst<A> case - abstract methods.
94template <class A> inline
95typename A::Weight Final(const ExpandedFst<A> &fst, typename A::StateId s) {
96  return fst.Final(s);
97}
98
99template <class A> inline
100ssize_t NumArcs(const ExpandedFst<A> &fst, typename A::StateId s) {
101  return fst.NumArcs(s);
102}
103
104template <class A> inline
105ssize_t NumInputEpsilons(const ExpandedFst<A> &fst, typename A::StateId s) {
106  return fst.NumInputEpsilons(s);
107}
108
109template <class A> inline
110ssize_t NumOutputEpsilons(const ExpandedFst<A> &fst, typename A::StateId s) {
111  return fst.NumOutputEpsilons(s);
112}
113
114}  // namespace internal
115
116
117// A useful alias when using StdArc.
118typedef ExpandedFst<StdArc> StdExpandedFst;
119
120
121// This is a helper class template useful for attaching an ExpandedFst
122// interface to its implementation, handling reference counting. It
123// delegates to ImplToFst the handling of the Fst interface methods.
124template < class I, class F = ExpandedFst<typename I::Arc> >
125class ImplToExpandedFst : public ImplToFst<I, F> {
126 public:
127  typedef typename I::Arc Arc;
128  typedef typename Arc::Weight Weight;
129  typedef typename Arc::StateId StateId;
130
131  using ImplToFst<I, F>::GetImpl;
132
133  virtual StateId NumStates() const { return GetImpl()->NumStates(); }
134
135 protected:
136  ImplToExpandedFst() : ImplToFst<I, F>() {}
137
138  ImplToExpandedFst(I *impl) : ImplToFst<I, F>(impl) {}
139
140  ImplToExpandedFst(const ImplToExpandedFst<I, F> &fst)
141      : ImplToFst<I, F>(fst) {}
142
143  ImplToExpandedFst(const ImplToExpandedFst<I, F> &fst, bool safe)
144      : ImplToFst<I, F>(fst, safe) {}
145
146  // Read FST implementation from a file; return NULL on error.
147  // Empty filename reads from standard input.
148  static I *Read(const string &filename) {
149    if (!filename.empty()) {
150      ifstream strm(filename.c_str(), ifstream::in | ifstream::binary);
151      if (!strm) {
152        LOG(ERROR) << "ExpandedFst::Read: Can't open file: " << filename;
153        return 0;
154      }
155      return I::Read(strm, FstReadOptions(filename));
156    } else {
157      return I::Read(cin, FstReadOptions("standard input"));
158    }
159  }
160
161 private:
162  // Disallow
163  ImplToExpandedFst<I, F> &operator=(const ImplToExpandedFst<I, F> &fst);
164
165  ImplToExpandedFst<I, F> &operator=(const Fst<Arc> &fst) {
166    FSTERROR() << "ImplToExpandedFst: Assignment operator disallowed";
167    GetImpl()->SetProperties(kError, kError);
168    return *this;
169  }
170};
171
172// Function to return the number of states in an FST, counting them
173// if necessary.
174template <class Arc>
175typename Arc::StateId CountStates(const Fst<Arc> &fst) {
176  if (fst.Properties(kExpanded, false)) {
177    const ExpandedFst<Arc> *efst = static_cast<const ExpandedFst<Arc> *>(&fst);
178    return efst->NumStates();
179  } else {
180    typename Arc::StateId nstates = 0;
181    for (StateIterator< Fst<Arc> > siter(fst); !siter.Done(); siter.Next())
182      ++nstates;
183    return nstates;
184  }
185}
186
187}  // namespace fst
188
189#endif  // FST_LIB_EXPANDED_FST_H__
190