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