Home | History | Annotate | Download | only in fst
      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 (at) 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 
     76   EditFstData() : num_new_states_(0) {
     77     SetEmptyAndDeleteKeysForInternalMaps();
     78   }
     79 
     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 
     87   ~EditFstData() {
     88   }
     89 
     90   static EditFstData<A, WrappedFstT, MutableFstT> *Read(istream &strm,
     91                                                         const FstReadOptions &opts);
     92 
     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 
    108   int RefCount() const { return ref_count_.count(); }
    109   int IncrRefCount() { return ref_count_.Incr(); }
    110   int DecrRefCount() { return ref_count_.Decr(); }
    111 
    112   StateId NumNewStates() const {
    113     return num_new_states_;
    114   }
    115 
    116   // accessor methods for the fst holding edited states
    117   StateId EditedStart() const {
    118     return edits_.Start();
    119   }
    120 
    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 
    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 
    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 
    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 
    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.
    160   void SetStart(StateId s) {
    161     edits_.SetStart(s);
    162   }
    163 
    164   // Sets the final state for this fst.
    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.
    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.
    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 
    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.
    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.
    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.
    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.
    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).
    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:
    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.
    264   IdMapIterator GetEditedIdMapIterator(StateId s) const {
    265     return external_to_internal_ids_.find(s);
    266   }
    267   IdMapIterator NotInEditedMap() const {
    268     return external_to_internal_ids_.end();
    269   }
    270 
    271   FinalWeightIterator GetFinalWeightIterator(StateId s) const {
    272     return edited_final_weights_.find(s);
    273   }
    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_
    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> *
    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.
    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.
    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.
    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 
    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
    449   StateId Start() const {
    450     StateId edited_start = data_->EditedStart();
    451     return edited_start == kNoStateId ? wrapped_->Start() : edited_start;
    452   }
    453 
    454   Weight Final(StateId s) const {
    455     return data_->Final(s, wrapped_);
    456   }
    457 
    458   size_t NumArcs(StateId s) const {
    459     return data_->NumArcs(s, wrapped_);
    460   }
    461 
    462   size_t NumInputEpsilons(StateId s) const {
    463     return data_->NumInputEpsilons(s, wrapped_);
    464   }
    465 
    466   size_t NumOutputEpsilons(StateId s) const {
    467     return data_->NumOutputEpsilons(s, wrapped_);
    468   }
    469 
    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 
    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.
    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.
    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.
    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.
    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 
    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.
    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.
    550   void DeleteArcs(StateId s) {
    551     MutateCheck();
    552     data_->DeleteArcs(s, wrapped_);
    553     SetProperties(DeleteArcsProperties(FstImpl<A>::Properties()));
    554   }
    555 
    556   void ReserveStates(StateId s) {
    557   }
    558 
    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.
    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.
    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.
    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.
    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().
    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>
    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> *
    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 
    694   EditFst() : ImplToMutableFst<Impl>(new Impl()) {}
    695 
    696   explicit EditFst(const Fst<A> &fst) :
    697       ImplToMutableFst<Impl>(new Impl(fst)) {}
    698 
    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 
    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> *
    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.
    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 
    741   virtual bool Write(ostream &strm, const FstWriteOptions &opts) const {
    742     return GetImpl()->Write(strm, opts);
    743   }
    744 
    745   virtual bool Write(const string &filename) const {
    746     return Fst<A>::WriteFile(filename);
    747   }
    748 
    749   virtual void InitStateIterator(StateIteratorData<Arc> *data) const {
    750     GetImpl()->InitStateIterator(data);
    751   }
    752 
    753   virtual void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
    754     GetImpl()->InitArcIterator(s, data);
    755   }
    756 
    757   virtual
    758   void InitMutableArcIterator(StateId s, MutableArcIteratorData<A> *data) {
    759     GetImpl()->InitMutableArcIterator(s, data);
    760   }
    761  private:
    762   explicit EditFst(Impl *impl) : ImplToMutableFst<Impl>(impl) {}
    763 
    764   // Makes visible to friends.
    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