• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // Copyright 2005-2010 Google, Inc.
15 // Author: dbikel@google.com (Dan Bikel)
16 //
17 // An \ref Fst implementation that allows non-destructive edit operations on an
18 // existing fst.
19 
20 #ifndef FST_LIB_EDIT_FST_H_
21 #define FST_LIB_EDIT_FST_H_
22 
23 #include <vector>
24 using std::vector;
25 
26 #include <fst/cache.h>
27 
28 namespace fst {
29 
30 // The EditFst class enables non-destructive edit operations on a wrapped
31 // ExpandedFst. The implementation uses copy-on-write semantics at the node
32 // level: if a user has an underlying fst on which he or she wants to perform a
33 // relatively small number of edits (read: mutations), then this implementation
34 // will copy the edited node to an internal MutableFst and perform any edits in
35 // situ on that copied node. This class supports all the methods of MutableFst
36 // except for DeleteStates(const vector<StateId> &); thus, new nodes may also be
37 // added, and one may add transitions from existing nodes of the wrapped fst to
38 // new nodes.
39 //
40 // N.B.: The documentation for Fst::Copy(true) says that its behavior is
41 // undefined if invoked on an fst that has already been accessed.  This class
42 // requires that the Fst implementation it wraps provides consistent, reliable
43 // behavior when its Copy(true) method is invoked, where consistent means
44 // the graph structure, graph properties and state numbering and do not change.
45 // VectorFst and CompactFst, for example, are both well-behaved in this regard.
46 
47 // The EditFstData class is a container for all mutable data for EditFstImpl;
48 // also, this class provides most of the actual implementation of what EditFst
49 // does (that is, most of EditFstImpl's methods delegate to methods in this, the
50 // EditFstData class).  Instances of this class are reference-counted and can be
51 // shared between otherwise independent EditFstImpl instances. This scheme
52 // allows EditFstImpl to implement the thread-safe, copy-on-write semantics
53 // required by Fst::Copy(true).
54 //
55 // template parameters:
56 //   A the type of arc to use
57 //   WrappedFstT the type of fst wrapped by the EditFst instance that
58 //     this EditFstData instance is backing
59 //   MutableFstT the type of mutable fst to use internally for edited states;
60 //     crucially, MutableFstT::Copy(false) *must* yield an fst that is
61 //     thread-safe for reading (VectorFst, for example, has this property)
62 template <typename A,
63           typename WrappedFstT = ExpandedFst<A>,
64           typename MutableFstT = VectorFst<A> >
65 class EditFstData {
66  public:
67   typedef A Arc;
68   typedef typename A::Weight Weight;
69   typedef typename A::StateId StateId;
70   typedef typename unordered_map<StateId, StateId>::const_iterator
71       IdMapIterator;
72   typedef typename unordered_map<StateId, Weight>::const_iterator
73       FinalWeightIterator;
74 
75 
EditFstData()76   EditFstData() : num_new_states_(0) {
77     SetEmptyAndDeleteKeysForInternalMaps();
78   }
79 
EditFstData(const EditFstData & other)80   EditFstData(const EditFstData &other) :
81       edits_(other.edits_),
82       external_to_internal_ids_(other.external_to_internal_ids_),
83       edited_final_weights_(other.edited_final_weights_),
84       num_new_states_(other.num_new_states_) {
85   }
86 
~EditFstData()87   ~EditFstData() {
88   }
89 
90   static EditFstData<A, WrappedFstT, MutableFstT> *Read(istream &strm,
91                                                         const FstReadOptions &opts);
92 
Write(ostream & strm,const FstWriteOptions & opts)93   bool Write(ostream &strm, const FstWriteOptions &opts) const {
94     // Serialize all private data members of this class.
95     FstWriteOptions edits_opts(opts);
96     edits_opts.write_header = true;  // Force writing contained header.
97     edits_.Write(strm, edits_opts);
98     WriteType(strm, external_to_internal_ids_);
99     WriteType(strm, edited_final_weights_);
100     WriteType(strm, num_new_states_);
101     if (!strm) {
102       LOG(ERROR) << "EditFstData::Write: write failed: " << opts.source;
103       return false;
104     }
105     return true;
106   }
107 
RefCount()108   int RefCount() const { return ref_count_.count(); }
IncrRefCount()109   int IncrRefCount() { return ref_count_.Incr(); }
DecrRefCount()110   int DecrRefCount() { return ref_count_.Decr(); }
111 
NumNewStates()112   StateId NumNewStates() const {
113     return num_new_states_;
114   }
115 
116   // accessor methods for the fst holding edited states
EditedStart()117   StateId EditedStart() const {
118     return edits_.Start();
119   }
120 
Final(StateId s,const WrappedFstT * wrapped)121   Weight Final(StateId s, const WrappedFstT *wrapped) const {
122     FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
123     if (final_weight_it == NotInFinalWeightMap()) {
124       IdMapIterator it = GetEditedIdMapIterator(s);
125       return it == NotInEditedMap() ?
126              wrapped->Final(s) : edits_.Final(it->second);
127     }
128     else {
129       return final_weight_it->second;
130     }
131   }
132 
NumArcs(StateId s,const WrappedFstT * wrapped)133   size_t NumArcs(StateId s, const WrappedFstT *wrapped) const {
134     IdMapIterator it = GetEditedIdMapIterator(s);
135     return it == NotInEditedMap() ?
136            wrapped->NumArcs(s) : edits_.NumArcs(it->second);
137   }
138 
NumInputEpsilons(StateId s,const WrappedFstT * wrapped)139   size_t NumInputEpsilons(StateId s, const WrappedFstT *wrapped) const {
140     IdMapIterator it = GetEditedIdMapIterator(s);
141     return it == NotInEditedMap() ?
142            wrapped->NumInputEpsilons(s) :
143            edits_.NumInputEpsilons(it->second);
144   }
145 
NumOutputEpsilons(StateId s,const WrappedFstT * wrapped)146   size_t NumOutputEpsilons(StateId s, const WrappedFstT *wrapped) const {
147     IdMapIterator it = GetEditedIdMapIterator(s);
148     return it == NotInEditedMap() ?
149            wrapped->NumOutputEpsilons(s) :
150            edits_.NumOutputEpsilons(it->second);
151   }
152 
SetEditedProperties(uint64 props,uint64 mask)153   void SetEditedProperties(uint64 props, uint64 mask) {
154     edits_.SetProperties(props, mask);
155   }
156 
157   // non-const MutableFst operations
158 
159   // Sets the start state for this fst.
SetStart(StateId s)160   void SetStart(StateId s) {
161     edits_.SetStart(s);
162   }
163 
164   // Sets the final state for this fst.
SetFinal(StateId s,Weight w,const WrappedFstT * wrapped)165   Weight SetFinal(StateId s, Weight w, const WrappedFstT *wrapped) {
166     Weight old_weight = Final(s, wrapped);
167     IdMapIterator it = GetEditedIdMapIterator(s);
168     // if we haven't already edited state s, don't add it to edited_ (which can
169     // be expensive if s has many transitions); just use the
170     // edited_final_weights_ map
171     if (it == NotInEditedMap()) {
172       edited_final_weights_[s] = w;
173     }
174     else {
175       edits_.SetFinal(GetEditableInternalId(s, wrapped), w);
176     }
177     return old_weight;
178   }
179 
180   // Adds a new state to this fst, initially with no arcs.
AddState(StateId curr_num_states)181   StateId AddState(StateId curr_num_states) {
182     StateId internal_state_id = edits_.AddState();
183     StateId external_state_id = curr_num_states;
184     external_to_internal_ids_[external_state_id] = internal_state_id;
185     num_new_states_++;
186     return external_state_id;
187   }
188 
189   // Adds the specified arc to the specified state of this fst.
AddArc(StateId s,const Arc & arc,const WrappedFstT * wrapped)190   const A *AddArc(StateId s, const Arc &arc, const WrappedFstT *wrapped) {
191     StateId internal_id = GetEditableInternalId(s, wrapped);
192 
193     size_t num_arcs = edits_.NumArcs(internal_id);
194     ArcIterator<MutableFstT> arc_it(edits_, internal_id);
195     const A *prev_arc = NULL;
196     if (num_arcs > 0) {
197       // grab the final arc associated with this state in edits_
198       arc_it.Seek(num_arcs - 1);
199       prev_arc = &(arc_it.Value());
200     }
201     edits_.AddArc(internal_id, arc);
202     return prev_arc;
203   }
204 
DeleteStates()205   void DeleteStates() {
206     edits_.DeleteStates();
207     num_new_states_ = 0;
208     external_to_internal_ids_.clear();
209     edited_final_weights_.clear();
210   }
211 
212   // Removes all but the first n outgoing arcs of the specified state.
DeleteArcs(StateId s,size_t n,const WrappedFstT * wrapped)213   void DeleteArcs(StateId s, size_t n, const WrappedFstT *wrapped) {
214     edits_.DeleteArcs(GetEditableInternalId(s, wrapped), n);
215   }
216 
217   // Removes all outgoing arcs from the specified state.
DeleteArcs(StateId s,const WrappedFstT * wrapped)218   void DeleteArcs(StateId s, const WrappedFstT *wrapped) {
219     edits_.DeleteArcs(GetEditableInternalId(s, wrapped));
220   }
221 
222   // end methods for non-const MutableFst operations
223 
224   // Provides information for the generic arc iterator.
InitArcIterator(StateId s,ArcIteratorData<Arc> * data,const WrappedFstT * wrapped)225   void InitArcIterator(StateId s, ArcIteratorData<Arc> *data,
226                        const WrappedFstT *wrapped) const {
227     IdMapIterator id_map_it = GetEditedIdMapIterator(s);
228     if (id_map_it == NotInEditedMap()) {
229       VLOG(3) << "EditFstData::InitArcIterator: iterating on state "
230           << s << " of original fst";
231       wrapped->InitArcIterator(s, data);
232     } else {
233       VLOG(2) << "EditFstData::InitArcIterator: iterating on edited state "
234           << s << " (internal state id: " << id_map_it->second << ")";
235       edits_.InitArcIterator(id_map_it->second, data);
236     }
237   }
238 
239     // Provides information for the generic mutable arc iterator.
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data,const WrappedFstT * wrapped)240   void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data,
241                               const WrappedFstT *wrapped) {
242     data->base =
243         new MutableArcIterator<MutableFstT>(&edits_,
244                                             GetEditableInternalId(s, wrapped));
245   }
246 
247   // Prints out the map from external to internal state id's (for debugging
248   // purposes).
PrintMap()249   void PrintMap() {
250     for (IdMapIterator map_it = external_to_internal_ids_.begin();
251         map_it != NotInEditedMap(); ++map_it) {
252       LOG(INFO) << "(external,internal)=("
253           << map_it->first << "," << map_it->second << ")";
254     }
255   }
256 
257 
258  private:
SetEmptyAndDeleteKeysForInternalMaps()259   void SetEmptyAndDeleteKeysForInternalMaps() {
260   }
261 
262   // Returns the iterator of the map from external to internal state id's
263   // of edits_ for the specified external state id.
GetEditedIdMapIterator(StateId s)264   IdMapIterator GetEditedIdMapIterator(StateId s) const {
265     return external_to_internal_ids_.find(s);
266   }
NotInEditedMap()267   IdMapIterator NotInEditedMap() const {
268     return external_to_internal_ids_.end();
269   }
270 
GetFinalWeightIterator(StateId s)271   FinalWeightIterator GetFinalWeightIterator(StateId s) const {
272     return edited_final_weights_.find(s);
273   }
NotInFinalWeightMap()274   FinalWeightIterator NotInFinalWeightMap() const {
275     return edited_final_weights_.end();
276   }
277 
278   // Returns the internal state id of the specified external id if the state has
279   // already been made editable, or else copies the state from wrapped_
280   // to edits_ and returns the state id of the newly editable state in edits_.
281   //
282   // \return makes the specified state editable if it isn't already and returns
283   //         its state id in edits_
GetEditableInternalId(StateId s,const WrappedFstT * wrapped)284   StateId GetEditableInternalId(StateId s, const WrappedFstT *wrapped) {
285     IdMapIterator id_map_it = GetEditedIdMapIterator(s);
286     if (id_map_it == NotInEditedMap()) {
287       StateId new_internal_id = edits_.AddState();
288       VLOG(2) << "EditFstData::GetEditableInternalId: editing state " << s
289           << " of original fst; new internal state id:" << new_internal_id;
290       external_to_internal_ids_[s] = new_internal_id;
291       for (ArcIterator< Fst<A> > arc_iterator(*wrapped, s);
292           !arc_iterator.Done();
293           arc_iterator.Next()) {
294         edits_.AddArc(new_internal_id, arc_iterator.Value());
295       }
296       // copy the final weight
297       FinalWeightIterator final_weight_it = GetFinalWeightIterator(s);
298       if (final_weight_it == NotInFinalWeightMap()) {
299         edits_.SetFinal(new_internal_id, wrapped->Final(s));
300       } else {
301         edits_.SetFinal(new_internal_id, final_weight_it->second);
302         edited_final_weights_.erase(s);
303       }
304       return new_internal_id;
305     } else {
306       return id_map_it->second;
307     }
308   }
309 
310   // A mutable fst (by default, a VectorFst) to contain new states, and/or
311   // copies of states from a wrapped ExpandedFst that have been modified in
312   // some way.
313   MutableFstT edits_;
314   // A mapping from external state id's to the internal id's of states that
315   // appear in edits_.
316   unordered_map<StateId, StateId> external_to_internal_ids_;
317   // A mapping from external state id's to final state weights assigned to
318   // those states.  The states in this map are *only* those whose final weight
319   // has been modified; if any other part of the state has been modified,
320   // the entire state is copied to edits_, and all modifications reside there.
321   unordered_map<StateId, Weight> edited_final_weights_;
322   // The number of new states added to this mutable fst impl, which is <= the
323   // number of states in edits_ (since edits_ contains both edited *and* new
324   // states).
325   StateId num_new_states_;
326   RefCounter ref_count_;
327 };
328 
329 // EditFstData method implementations: just the Read method.
330 template <typename A, typename WrappedFstT, typename MutableFstT>
331 EditFstData<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)332 EditFstData<A, WrappedFstT, MutableFstT>::Read(istream &strm,
333                                                const FstReadOptions &opts) {
334   EditFstData<A, WrappedFstT, MutableFstT> *data =
335       new EditFstData<A, WrappedFstT, MutableFstT>();
336     // next read in MutabelFstT machine that stores edits
337   FstReadOptions edits_opts(opts);
338   edits_opts.header = 0;  // Contained header was written out, so read it in.
339 
340   // Because our internal representation of edited states is a solid object
341   // of type MutableFstT (defaults to VectorFst<A>) and not a pointer,
342   // and because the static Read method allocates a new object on the heap,
343   // we need to call Read, check if there was a failure, use
344   // MutableFstT::operator= to assign the object (not the pointer) to the
345   // edits_ data member (which will increase the ref count by 1 on the impl)
346   // and, finally, delete the heap-allocated object.
347   MutableFstT *edits = MutableFstT::Read(strm, edits_opts);
348   if (!edits) {
349     return 0;
350   }
351   data->edits_ = *edits;
352   delete edits;
353   // finally, read in rest of private data members
354   ReadType(strm, &data->external_to_internal_ids_);
355   ReadType(strm, &data->edited_final_weights_);
356   ReadType(strm, &data->num_new_states_);
357   if (!strm) {
358     LOG(ERROR) << "EditFst::Read: read failed: " << opts.source;
359     return 0;
360   }
361   return data;
362 }
363 
364 // This class enables non-destructive edit operations on a wrapped ExpandedFst.
365 // The implementation uses copy-on-write semantics at the node level: if a user
366 // has an underlying fst on which he or she wants to perform a relatively small
367 // number of edits (read: mutations), then this implementation will copy the
368 // edited node to an internal MutableFst and perform any edits in situ on that
369 // copied node. This class supports all the methods of MutableFst except for
370 // DeleteStates(const vector<StateId> &); thus, new nodes may also be added, and
371 // one may add transitions from existing nodes of the wrapped fst to new nodes.
372 //
373 // template parameters:
374 //   A the type of arc to use
375 //   WrappedFstT the type of fst wrapped by the EditFst instance that
376 //     this EditFstImpl instance is backing
377 //   MutableFstT the type of mutable fst to use internally for edited states;
378 //     crucially, MutableFstT::Copy(false) *must* yield an fst that is
379 //     thread-safe for reading (VectorFst, for example, has this property)
380 template <typename A,
381           typename WrappedFstT = ExpandedFst<A>,
382           typename MutableFstT = VectorFst<A> >
383 class EditFstImpl : public FstImpl<A> {
384  public:
385   using FstImpl<A>::SetProperties;
386   using FstImpl<A>::SetInputSymbols;
387   using FstImpl<A>::SetOutputSymbols;
388   using FstImpl<A>::WriteHeader;
389 
390   typedef A Arc;
391   typedef typename Arc::Weight Weight;
392   typedef typename Arc::StateId StateId;
393 
394   // Constructs an editable fst implementation with no states.  Effectively,
395   // this initially-empty fst will in every way mimic the behavior of
396   // a VectorFst--more precisely, a VectorFstImpl instance--but with slightly
397   // slower performance (by a constant factor), due to the fact that
398   // this class maintains a mapping between external state id's and
399   // their internal equivalents.
EditFstImpl()400   EditFstImpl() {
401     FstImpl<A>::SetType("edit");
402     wrapped_ = new MutableFstT();
403     InheritPropertiesFromWrapped();
404     data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
405   }
406 
407   // Wraps the specified ExpandedFst. This constructor requires that the
408   // specified Fst is an ExpandedFst instance. This requirement is only enforced
409   // at runtime. (See below for the reason.)
410   //
411   // This library uses the pointer-to-implementation or "PIMPL" design pattern.
412   // In particular, to make it convenient to bind an implementation class to its
413   // interface, there are a pair of template "binder" classes, one for immutable
414   // and one for mutable fst's (ImplToFst and ImplToMutableFst, respectively).
415   // As it happens, the API for the ImplToMutableFst<I,F> class requires that
416   // the implementation class--the template parameter "I"--have a constructor
417   // taking a const Fst<A> reference.  Accordingly, the constructor here must
418   // perform a static_cast to the WrappedFstT type required by EditFst and
419   // therefore EditFstImpl.
EditFstImpl(const Fst<A> & wrapped)420   explicit EditFstImpl(const Fst<A> &wrapped)
421       : wrapped_(static_cast<WrappedFstT *>(wrapped.Copy())) {
422     FstImpl<A>::SetType("edit");
423 
424     data_ = new EditFstData<A, WrappedFstT, MutableFstT>();
425     // have edits_ inherit all properties from wrapped_
426     data_->SetEditedProperties(wrapped_->Properties(kFstProperties, false),
427                                kFstProperties);
428     InheritPropertiesFromWrapped();
429   }
430 
431   // A copy constructor for this implementation class, used to implement
432   // the Copy() method of the Fst interface.
EditFstImpl(const EditFstImpl & impl)433   EditFstImpl(const EditFstImpl &impl)
434       : wrapped_(static_cast<WrappedFstT *>(impl.wrapped_->Copy(true))),
435         data_(impl.data_) {
436     data_->IncrRefCount();
437     SetProperties(impl.Properties());
438   }
439 
~EditFstImpl()440   ~EditFstImpl() {
441     delete wrapped_;
442     if (!data_->DecrRefCount()) {
443       delete data_;
444     }
445   }
446 
447   // const Fst/ExpandedFst operations, declared in the Fst and ExpandedFst
448   // interfaces
Start()449   StateId Start() const {
450     StateId edited_start = data_->EditedStart();
451     return edited_start == kNoStateId ? wrapped_->Start() : edited_start;
452   }
453 
Final(StateId s)454   Weight Final(StateId s) const {
455     return data_->Final(s, wrapped_);
456   }
457 
NumArcs(StateId s)458   size_t NumArcs(StateId s) const {
459     return data_->NumArcs(s, wrapped_);
460   }
461 
NumInputEpsilons(StateId s)462   size_t NumInputEpsilons(StateId s) const {
463     return data_->NumInputEpsilons(s, wrapped_);
464   }
465 
NumOutputEpsilons(StateId s)466   size_t NumOutputEpsilons(StateId s) const {
467     return data_->NumOutputEpsilons(s, wrapped_);
468   }
469 
NumStates()470   StateId NumStates() const {
471     return wrapped_->NumStates() + data_->NumNewStates();
472   }
473 
474   static EditFstImpl<A, WrappedFstT, MutableFstT> *
475   Read(istream &strm,
476        const FstReadOptions &opts);
477 
Write(ostream & strm,const FstWriteOptions & opts)478   bool Write(ostream &strm, const FstWriteOptions &opts) const {
479     FstHeader hdr;
480     hdr.SetStart(Start());
481     hdr.SetNumStates(NumStates());
482     FstWriteOptions header_opts(opts);
483     header_opts.write_isymbols = false;  // Let contained FST hold any symbols.
484     header_opts.write_osymbols = false;
485     WriteHeader(strm, header_opts, kFileVersion, &hdr);
486 
487     // First, serialize wrapped fst to stream.
488     FstWriteOptions wrapped_opts(opts);
489     wrapped_opts.write_header = true;  // Force writing contained header.
490     wrapped_->Write(strm, wrapped_opts);
491 
492     data_->Write(strm, opts);
493 
494     strm.flush();
495     if (!strm) {
496       LOG(ERROR) << "EditFst::Write: write failed: " << opts.source;
497       return false;
498     }
499     return true;
500   }
501   // end const Fst operations
502 
503   // non-const MutableFst operations
504 
505   // Sets the start state for this fst.
SetStart(StateId s)506   void SetStart(StateId s) {
507     MutateCheck();
508     data_->SetStart(s);
509     SetProperties(SetStartProperties(FstImpl<A>::Properties()));
510   }
511 
512   // Sets the final state for this fst.
SetFinal(StateId s,Weight w)513   void SetFinal(StateId s, Weight w) {
514     MutateCheck();
515     Weight old_weight = data_->SetFinal(s, w, wrapped_);
516     SetProperties(SetFinalProperties(FstImpl<A>::Properties(), old_weight, w));
517   }
518 
519   // Adds a new state to this fst, initially with no arcs.
AddState()520   StateId AddState() {
521     MutateCheck();
522     SetProperties(AddStateProperties(FstImpl<A>::Properties()));
523     return data_->AddState(NumStates());
524   }
525 
526   // Adds the specified arc to the specified state of this fst.
AddArc(StateId s,const Arc & arc)527   void AddArc(StateId s, const Arc &arc) {
528     MutateCheck();
529     const A *prev_arc = data_->AddArc(s, arc, wrapped_);
530     SetProperties(AddArcProperties(FstImpl<A>::Properties(), s, arc, prev_arc));
531   }
532 
DeleteStates(const vector<StateId> & dstates)533   void DeleteStates(const vector<StateId>& dstates) {
534     FSTERROR() << ": EditFstImpl::DeleteStates(const std::vector<StateId>&): "
535                << " not implemented";
536     SetProperties(kError, kError);
537   }
538 
539   // Deletes all states in this fst.
540   void DeleteStates();
541 
542   // Removes all but the first n outgoing arcs of the specified state.
DeleteArcs(StateId s,size_t n)543   void DeleteArcs(StateId s, size_t n) {
544     MutateCheck();
545     data_->DeleteArcs(s, n, wrapped_);
546     SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
547   }
548 
549   // Removes all outgoing arcs from the specified state.
DeleteArcs(StateId s)550   void DeleteArcs(StateId s) {
551     MutateCheck();
552     data_->DeleteArcs(s, wrapped_);
553     SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
554   }
555 
ReserveStates(StateId s)556   void ReserveStates(StateId s) {
557   }
558 
ReserveArcs(StateId s,size_t n)559   void ReserveArcs(StateId s, size_t n) {
560   }
561 
562   // end non-const MutableFst operations
563 
564   // Provides information for the generic state iterator.
InitStateIterator(StateIteratorData<Arc> * data)565   void InitStateIterator(StateIteratorData<Arc> *data) const {
566     data->base = 0;
567     data->nstates = NumStates();
568   }
569 
570   // Provides information for the generic arc iterator.
InitArcIterator(StateId s,ArcIteratorData<Arc> * data)571   void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
572     data_->InitArcIterator(s, data, wrapped_);
573   }
574 
575   // Provides information for the generic mutable arc iterator.
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data)576   void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
577     MutateCheck();
578     data_->InitMutableArcIterator(s, data, wrapped_);
579   }
580 
581  private:
582   typedef typename unordered_map<StateId, StateId>::const_iterator
583     IdMapIterator;
584   typedef typename unordered_map<StateId, Weight>::const_iterator
585     FinalWeightIterator;
586   // Properties always true of this Fst class
587   static const uint64 kStaticProperties = kExpanded | kMutable;
588   // Current file format version
589   static const int kFileVersion = 2;
590   // Minimum file format version supported
591   static const int kMinFileVersion = 2;
592 
593   // Causes this fst to inherit all the properties from its wrapped fst, except
594   // for the two properties that always apply to EditFst instances: kExpanded
595   // and kMutable.
InheritPropertiesFromWrapped()596   void InheritPropertiesFromWrapped() {
597     SetProperties(wrapped_->Properties(kCopyProperties, false) |
598                   kStaticProperties);
599     SetInputSymbols(wrapped_->InputSymbols());
600     SetOutputSymbols(wrapped_->OutputSymbols());
601   }
602 
603   // This method ensures that any operations that alter the mutable data
604   // portion of this EditFstImpl cause the data_ member to be copied when its
605   // reference count is greater than 1.  Note that this method is distinct from
606   // MutableFst::Mutate, which gets invoked whenever one of the basic mutation
607   // methods defined in MutableFst is invoked, such as SetInputSymbols.
608   // The MutateCheck here in EditFstImpl is invoked whenever one of the
609   // mutating methods specifically related to the types of edits provided
610   // by EditFst is performed, such as changing an arc of an existing state
611   // of the wrapped fst via a MutableArcIterator, or adding a new state via
612   // AddState().
MutateCheck()613   void MutateCheck() {
614     if (data_->RefCount() > 1) {
615       EditFstData<A, WrappedFstT, MutableFstT> *data_copy =
616           new EditFstData<A, WrappedFstT, MutableFstT>(*data_);
617       if (data_ && !data_->DecrRefCount()) {
618         delete data_;
619       }
620       data_ = data_copy;
621     }
622   }
623 
624   // The fst that this fst wraps.  The purpose of this class is to enable
625   // non-destructive edits on this wrapped fst.
626   const WrappedFstT *wrapped_;
627   // The mutable data for this EditFst instance, with delegates for all the
628   // methods that can mutate data.
629   EditFstData<A, WrappedFstT, MutableFstT> *data_;
630 };
631 
632 template <typename A, typename WrappedFstT, typename MutableFstT>
633 const uint64 EditFstImpl<A, WrappedFstT, MutableFstT>::kStaticProperties;
634 
635 // EditFstImpl IMPLEMENTATION STARTS HERE
636 
637 template<typename A, typename WrappedFstT, typename MutableFstT>
DeleteStates()638 inline void EditFstImpl<A, WrappedFstT, MutableFstT>::DeleteStates() {
639   data_->DeleteStates();
640   delete wrapped_;
641   // we are deleting all states, so just forget about pointer to wrapped_
642   // and do what default constructor does: set wrapped_ to a new VectorFst
643   wrapped_ = new MutableFstT();
644   uint64 newProps = DeleteAllStatesProperties(FstImpl<A>::Properties(),
645                                               kStaticProperties);
646   FstImpl<A>::SetProperties(newProps);
647 }
648 
649 template <typename A, typename WrappedFstT, typename MutableFstT>
650 EditFstImpl<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)651 EditFstImpl<A, WrappedFstT, MutableFstT>::Read(istream &strm,
652                                                const FstReadOptions &opts) {
653   EditFstImpl<A, WrappedFstT, MutableFstT> *impl = new EditFstImpl();
654   FstHeader hdr;
655   if (!impl->ReadHeader(strm, opts, kMinFileVersion, &hdr)) {
656     return 0;
657   }
658   impl->SetStart(hdr.Start());
659 
660   // first, read in wrapped fst
661   FstReadOptions wrapped_opts(opts);
662   wrapped_opts.header = 0;  // Contained header was written out, so read it in.
663   Fst<A> *wrapped_fst = Fst<A>::Read(strm, wrapped_opts);
664   if (!wrapped_fst) {
665     return 0;
666   }
667   impl->wrapped_ = static_cast<WrappedFstT *>(wrapped_fst);
668 
669   impl->data_ = EditFstData<A, WrappedFstT, MutableFstT>::Read(strm, opts);
670 
671   if (!impl->data_) {
672     delete wrapped_fst;
673     return 0;
674   }
675 
676   return impl;
677 }
678 
679 // END EditFstImpl IMPLEMENTATION
680 
681 // Concrete, editable FST.  This class attaches interface to implementation.
682 template <typename A,
683           typename WrappedFstT = ExpandedFst<A>,
684           typename MutableFstT = VectorFst<A> >
685 class EditFst :
686   public ImplToMutableFst< EditFstImpl<A, WrappedFstT, MutableFstT> > {
687  public:
688   friend class MutableArcIterator< EditFst<A, WrappedFstT, MutableFstT> >;
689 
690   typedef A Arc;
691   typedef typename A::StateId StateId;
692   typedef EditFstImpl<A, WrappedFstT, MutableFstT> Impl;
693 
EditFst()694   EditFst() : ImplToMutableFst<Impl>(new Impl()) {}
695 
EditFst(const Fst<A> & fst)696   explicit EditFst(const Fst<A> &fst) :
697       ImplToMutableFst<Impl>(new Impl(fst)) {}
698 
EditFst(const WrappedFstT & fst)699   explicit EditFst(const WrappedFstT &fst) :
700       ImplToMutableFst<Impl>(new Impl(fst)) {}
701 
702   // See Fst<>::Copy() for doc.
703   EditFst(const EditFst<A, WrappedFstT, MutableFstT> &fst, bool safe = false) :
704     ImplToMutableFst<Impl>(fst, safe) {}
705 
~EditFst()706   virtual ~EditFst() {}
707 
708   // Get a copy of this EditFst. See Fst<>::Copy() for further doc.
709   virtual EditFst<A, WrappedFstT, MutableFstT> *Copy(bool safe = false) const {
710     return new EditFst<A, WrappedFstT, MutableFstT>(*this, safe);
711   }
712 
713   EditFst<A, WrappedFstT, MutableFstT> &
714   operator=(const EditFst<A, WrappedFstT, MutableFstT> &fst) {
715     SetImpl(fst.GetImpl(), false);
716     return *this;
717   }
718 
719   virtual EditFst<A, WrappedFstT, MutableFstT> &operator=(const Fst<A> &fst) {
720     if (this != &fst) {
721       SetImpl(new Impl(fst));
722     }
723     return *this;
724   }
725 
726   // Read an EditFst from an input stream; return NULL on error.
727   static EditFst<A, WrappedFstT, MutableFstT> *
Read(istream & strm,const FstReadOptions & opts)728   Read(istream &strm,
729        const FstReadOptions &opts) {
730     Impl* impl = Impl::Read(strm, opts);
731     return impl ? new EditFst<A>(impl) : 0;
732   }
733 
734   // Read an EditFst from a file; return NULL on error.
735   // Empty filename reads from standard input.
Read(const string & filename)736   static EditFst<A, WrappedFstT, MutableFstT> *Read(const string &filename) {
737     Impl* impl = ImplToExpandedFst<Impl, MutableFst<A> >::Read(filename);
738     return impl ? new EditFst<A, WrappedFstT, MutableFstT>(impl) : 0;
739   }
740 
Write(ostream & strm,const FstWriteOptions & opts)741   virtual bool Write(ostream &strm, const FstWriteOptions &opts) const {
742     return GetImpl()->Write(strm, opts);
743   }
744 
Write(const string & filename)745   virtual bool Write(const string &filename) const {
746     return Fst<A>::WriteFile(filename);
747   }
748 
InitStateIterator(StateIteratorData<Arc> * data)749   virtual void InitStateIterator(StateIteratorData<Arc> *data) const {
750     GetImpl()->InitStateIterator(data);
751   }
752 
InitArcIterator(StateId s,ArcIteratorData<Arc> * data)753   virtual void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
754     GetImpl()->InitArcIterator(s, data);
755   }
756 
757   virtual
InitMutableArcIterator(StateId s,MutableArcIteratorData<A> * data)758   void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
759     GetImpl()->InitMutableArcIterator(s, data);
760   }
761  private:
EditFst(Impl * impl)762   explicit EditFst(Impl *impl) : ImplToMutableFst<Impl>(impl) {}
763 
764   // Makes visible to friends.
GetImpl()765   Impl *GetImpl() const { return ImplToFst< Impl, MutableFst<A> >::GetImpl(); }
766 
767   void SetImpl(Impl *impl, bool own_impl = true) {
768     ImplToFst< Impl, MutableFst<A> >::SetImpl(impl, own_impl);
769   }
770 };
771 
772 }  // namespace fst
773 
774 #endif  // FST_LIB_EDIT_FST_H_
775