1 // cache.h
2 
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // Copyright 2005-2010 Google, Inc.
16 // Author: riley@google.com (Michael Riley)
17 //
18 // \file
19 // An Fst implementation that caches FST elements of a delayed
20 // computation.
21 
22 #ifndef FST_LIB_CACHE_H__
23 #define FST_LIB_CACHE_H__
24 
25 #include <functional>
26 #include <list>
27 #include <unordered_map>
28 using std::unordered_map;
29 using std::unordered_multimap;
30 #include <vector>
31 using std::vector;
32 
33 
34 #include <fst/vector-fst.h>
35 
36 
37 DECLARE_bool(fst_default_cache_gc);
38 DECLARE_int64(fst_default_cache_gc_limit);
39 
40 namespace fst {
41 
42 // Options for controlling caching behavior; higher
43 // level than CacheImplOptions.
44 struct CacheOptions {
45   bool gc;          // enable GC
46   size_t gc_limit;  // # of bytes allowed before GC
47 
CacheOptionsCacheOptions48   CacheOptions(bool g, size_t l) : gc(g), gc_limit(l) {}
CacheOptionsCacheOptions49   CacheOptions()
50       : gc(FLAGS_fst_default_cache_gc),
51         gc_limit(FLAGS_fst_default_cache_gc_limit) {}
52 };
53 
54 // Options for controlling caching behavior; lower
55 // level than CacheOptions - templated on the
56 // cache store and allows passing the store.
57 template <class C>
58 struct CacheImplOptions {
59   bool gc;          // enable GC
60   size_t gc_limit;  // # of bytes allowed before GC
61   C *store;         // cache store
62 
63   CacheImplOptions(bool g, size_t l, C s = 0)
gcCacheImplOptions64       : gc(g), gc_limit(l), store(0) {}
65 
CacheImplOptionsCacheImplOptions66  explicit CacheImplOptions(const CacheOptions &opts)
67       : gc(opts.gc), gc_limit(opts.gc_limit), store(0) {}
68 
CacheImplOptionsCacheImplOptions69   CacheImplOptions()
70       : gc(FLAGS_fst_default_cache_gc),
71         gc_limit(FLAGS_fst_default_cache_gc_limit),
72         store(0) {}
73 };
74 
75 // CACHE FLAGS
76 
77 const uint32 kCacheFinal =    0x0001;    // Final weight has been cached
78 const uint32 kCacheArcs =     0x0002;    // Arcs have been cached
79 const uint32 kCacheInit =     0x0004;    // Initialized by GC
80 const uint32 kCacheRecent =   0x0008;    // Visited since GC
81 const uint32 kCacheFlags = kCacheFinal | kCacheArcs | kCacheInit |
82     kCacheRecent;
83 
84 
85 // CACHE STATE - Arcs implemented by an STL vector per state.
86 template <class A, class M = PoolAllocator<A> >
87 class CacheState {
88  public:
89   typedef A Arc;
90   typedef typename A::Weight Weight;
91   typedef typename A::StateId StateId;
92   typedef M ArcAllocator;
93   typedef typename ArcAllocator::template
94   rebind<CacheState<A, M> >::other StateAllocator;
95 
96   // Provide STL allocator for arcs
CacheState(const ArcAllocator & alloc)97   explicit CacheState(const ArcAllocator &alloc)
98     : final_(Weight::Zero()), niepsilons_(0), noepsilons_(0),
99       arcs_(alloc), flags_(0), ref_count_(0) {}
100 
CacheState(const CacheState<A> & state,const ArcAllocator & alloc)101   CacheState(const CacheState<A> &state, const ArcAllocator &alloc)
102     : final_(state.Final()),
103       niepsilons_(state.NumInputEpsilons()),
104       noepsilons_(state.NumOutputEpsilons()),
105       arcs_(state.arcs_.begin(), state.arcs_.end(), alloc),
106       flags_(state.Flags()),
107       ref_count_(0) { }
108 
Reset()109   void Reset() {
110     final_ = Weight::Zero();
111     niepsilons_ = 0;
112     noepsilons_ = 0;
113     ref_count_ = 0;
114     flags_ = 0;
115     arcs_.clear();
116   }
117 
Final()118   Weight Final() const { return final_; }
NumInputEpsilons()119   size_t NumInputEpsilons() const { return niepsilons_; }
NumOutputEpsilons()120   size_t NumOutputEpsilons() const { return noepsilons_; }
NumArcs()121   size_t NumArcs() const { return arcs_.size(); }
GetArc(size_t n)122   const A &GetArc(size_t n) const { return arcs_[n]; }
123 
124   // Used by the ArcIterator<Fst<A>> efficient implementation.
Arcs()125   const A *Arcs() const { return arcs_.size() > 0 ? &arcs_[0] : 0; }
126 
127   // Accesses flags; used by the caller
Flags()128   uint32 Flags() const { return flags_; }
129   // Accesses ref count; used by the caller
RefCount()130   int RefCount() const { return ref_count_; }
131 
SetFinal(Weight final)132   void SetFinal(Weight final) { final_ = final; }
133 
ReserveArcs(size_t n)134   void ReserveArcs(size_t n) { arcs_.reserve(n); }
135 
136   // Adds one arc at a time with all needed book-keeping.
137   // Can use PushArc's and SetArcs instead as more efficient alternative.
AddArc(const A & arc)138   void AddArc(const A &arc) {
139     arcs_.push_back(arc);
140     if (arc.ilabel == 0)
141       ++niepsilons_;
142     if (arc.olabel == 0)
143       ++noepsilons_;
144   }
145 
146   // Adds one arc at a time with delayed book-keeping; finalize with SetArcs()
PushArc(const A & arc)147   void PushArc(const A &arc) { arcs_.push_back(arc); }
148 
149   // Finalizes arcs book-keeping; call only once
SetArcs()150   void SetArcs() {
151     for (size_t a = 0; a < arcs_.size(); ++a) {
152       const Arc &arc = arcs_[a];
153       if (arc.ilabel == 0)
154         ++niepsilons_;
155       if (arc.olabel == 0)
156         ++noepsilons_;
157     }
158   }
159 
160   // Modifies nth arc
SetArc(const A & arc,size_t n)161   void SetArc(const A &arc, size_t n) {
162     if (arcs_[n].ilabel == 0)
163       --niepsilons_;
164     if (arcs_[n].olabel == 0)
165       --noepsilons_;
166     if (arc.ilabel == 0)
167       ++niepsilons_;
168     if (arc.olabel == 0)
169       ++noepsilons_;
170     arcs_[n] = arc;
171   }
172 
173   // Deletes all arcs
DeleteArcs()174   void DeleteArcs() {
175     niepsilons_ = 0;
176     noepsilons_ = 0;
177     arcs_.clear();
178   }
179 
DeleteArcs(size_t n)180   void DeleteArcs(size_t n) {
181     for (size_t i = 0; i < n; ++i) {
182       if (arcs_.back().ilabel == 0)
183         --niepsilons_;
184       if (arcs_.back().olabel == 0)
185         --noepsilons_;
186       arcs_.pop_back();
187     }
188   }
189 
190   // Sets status flags; used by the caller
SetFlags(uint32 flags,uint32 mask)191   void SetFlags(uint32 flags, uint32 mask) const {
192     flags_ &= ~mask;
193     flags_ |= flags;
194   }
195 
196   // Mutates ref counts; used by the caller
IncrRefCount()197   int IncrRefCount() const { return  ++ref_count_; }
DecrRefCount()198   int DecrRefCount() const { return --ref_count_; }
199 
200   // Used by the ArcIterator<Fst<A>> efficient implementation.
MutableRefCount()201   int *MutableRefCount() const { return &ref_count_; }
202 
203   // For state class allocation
new(size_t size,StateAllocator * alloc)204   void *operator new(size_t size, StateAllocator *alloc) {
205     return alloc->allocate(1);
206   }
207 
208   // For state destruction and memory freeing
Destroy(CacheState<A> * state,StateAllocator * alloc)209   static void Destroy(CacheState<A> *state, StateAllocator *alloc) {
210     if (state) {
211       state->~CacheState<A>();
212       alloc->deallocate(state, 1);
213     }
214   }
215 
216  private:
217   Weight final_;                   // Final weight
218   size_t niepsilons_;              // # of input epsilons
219   size_t noepsilons_;              // # of output epsilons
220   vector<A, ArcAllocator> arcs_;   // Arcs represenation
221   mutable uint32 flags_;
222   mutable int ref_count_;          // if 0, avail. for GC; used by arc iterators
223 
224   DISALLOW_COPY_AND_ASSIGN(CacheState);
225 };
226 
227 
228 // CACHE STORE - these allocate and store states, provide a mapping
229 // from state IDs to cached states and an iterator over
230 // the states. The state template argument should be a CacheState
231 // as above (or have the same interface). The state for StateId s
232 // is constructed when requested by GetMutableState(s) if it not
233 // yet stored. Initially a state has RefCount() = 0; the user may increment
234 // and decrement to control the time of destruction. In particular, this state
235 // is destroyed when:
236 //    (1) this class is destroyed or
237 //    (2) Clear() is called or Delete() for it is called or
238 //    (3) possibly when:
239 //         (a) opts.gc = true and
240 //         (b) the cache store size exceeds opts.gc_limit bytes and
241 //         (c) the state's RefCount() is zero and
242 //         (d) the state is not the most recently requested state.
243 //        The actual GC behavior is up to the specific store.
244 //
245 // template <class S>
246 // class CacheStore {
247 //  public:
248 //   typedef S State;
249 //   typedef typename State::Arc Arc;
250 //   typedef typename Arc::StateId StateId;
251 //
252 //   // Required constructors/assignment operators
253 //   explicit CacheStore(const CacheOptions &opts);
254 //   CacheStore(const CacheStore &store);
255 //   CacheStore<State> &operator=(const CacheStore<State> &store);
256 //
257 //   // Returns 0 if state is not stored
258 //   const State *GetState(StateId s);
259 //
260 //   // Creates state if state is not stored
261 //   State *GetMutableState(StateId s);
262 //
263 //   // Similar to State::AddArc() but updates cache store book-keeping
264 //   void AddArc(StateId *state, const Arc &arc);
265 //
266 //   // Similar to State::SetArcs() but updates cache store book-keeping
267 //   // Call only once.
268 //   void SetArcs(StateId *state);
269 //
270 //   // Similar to State::DeleteArcs() but updates cache store book-keeping
271 //   void DeleteArcs(State *state);
272 //   void DeleteArcs(State *state, size_t n);
273 //
274 //   // Deletes all cached states
275 //   void Clear();
276 //
277 //
278 //   // Iterates over cached states (in an arbitrary order).
279 //   // Only needed if opts.gc is true
280 //   bool Done() const;      // End of iteration
281 //   StateId Value() const;  // Current state
282 //   void Next();            // Advances to next state (when !Done)
283 //   void Reset();           // Return to initial condition
284 //   void Delete();          // Deletes current state and advances to next
285 // };
286 
287 //
288 // CONTAINER CACHE STORES - these simply hold states
289 //
290 
291 // This class uses a vector of pointers to states to store cached states.
292 template <class S>
293 class VectorCacheStore {
294  public:
295   typedef S State;
296   typedef typename State::Arc Arc;
297   typedef typename Arc::StateId StateId;
298   typedef list<StateId, PoolAllocator<StateId> > StateList;
299 
300   // Required constructors/assignment operators
VectorCacheStore(const CacheOptions & opts)301   explicit VectorCacheStore(const CacheOptions &opts) : cache_gc_(opts.gc) {
302     Clear();
303     Reset();
304   }
305 
VectorCacheStore(const VectorCacheStore<S> & store)306   VectorCacheStore(const VectorCacheStore<S> &store)
307       : cache_gc_(store.cache_gc_) {
308     CopyStates(store);
309     Reset();
310   }
311 
~VectorCacheStore()312   ~VectorCacheStore() {
313     Clear();
314   }
315 
316   VectorCacheStore<State> &operator=(const VectorCacheStore<State> &store) {
317     if (this != &store) {
318       CopyStates(store);
319       Reset();
320     }
321     return *this;
322   }
323 
324   // Returns 0 if state is not stored
GetState(StateId s)325   const State *GetState(StateId s) const {
326     return s < state_vec_.size() ? state_vec_[s] : 0;
327   }
328 
329   // Creates state if state is not stored
GetMutableState(StateId s)330   State *GetMutableState(StateId s) {
331     State *state = 0;
332     if (s >= state_vec_.size()) {
333       state_vec_.resize(s + 1, 0);
334     } else {
335       state = state_vec_[s];
336     }
337 
338     if (state == 0) {
339       state = new(&state_alloc_) State(arc_alloc_);
340       state_vec_[s] = state;
341       if (cache_gc_)
342         state_list_.push_back(s);
343     }
344     return state;
345   }
346 
347   // Similar to State::AddArc() but updates cache store book-keeping
AddArc(State * state,const Arc & arc)348   void AddArc(State *state, const Arc &arc) { state->AddArc(arc); }
349 
350   // Similar to State::SetArcs() but updates internal cache size.
351   // Call only once.
SetArcs(State * state)352   void SetArcs(State *state) { state->SetArcs(); }
353 
354   // Deletes all arcs
DeleteArcs(State * state)355   void DeleteArcs(State *state) { state->DeleteArcs(); }
356 
357   // Deletes some arcs
DeleteArcs(State * state,size_t n)358   void DeleteArcs(State *state, size_t n) { state->DeleteArcs(n); }
359 
360   // Deletes all cached states
Clear()361   void Clear() {
362     for (StateId s = 0; s < state_vec_.size(); ++s)
363       State::Destroy(state_vec_[s], &state_alloc_);
364     state_vec_.clear();
365     state_list_.clear();
366   }
367 
368   // Iterates over cached states (in an arbitrary order).
369   // Only works if GC is enabled (o.w. avoiding state_list_ overhead).
Done()370   bool Done() const { return iter_ == state_list_.end(); }
Value()371   StateId Value() const { return *iter_; }
Next()372   void Next() { ++iter_; }
Reset()373   void Reset() { iter_ = state_list_.begin();  }
374 
375   // Deletes current state and advances to next.
Delete()376   void Delete() {
377     State::Destroy(state_vec_[*iter_], &state_alloc_);
378     state_vec_[*iter_] = 0;
379     state_list_.erase(iter_++);
380   }
381 
382  private:
CopyStates(const VectorCacheStore<State> & store)383   void CopyStates(const VectorCacheStore<State> &store) {
384     Clear();
385     state_vec_.reserve(store.state_vec_.size());
386     for (StateId s = 0; s < store.state_vec_.size(); ++s) {
387       S *state = 0;
388       const State *store_state = store.state_vec_[s];
389       if (store_state) {
390         state = new(&state_alloc_) State(*store_state, arc_alloc_);
391         if (cache_gc_)
392           state_list_.push_back(s);
393       }
394       state_vec_.push_back(state);
395     }
396   }
397 
398   bool cache_gc_;                          // supports iteration when true
399   vector<State *> state_vec_;              // vector of states (NULL if empty)
400   StateList state_list_;                   // list of states
401   typename StateList::iterator iter_;      // state list iterator
402   typename State::StateAllocator state_alloc_;  // for state allocation
403   typename State::ArcAllocator arc_alloc_;      // for arc allocation
404 };
405 
406 
407 // This class uses a hash map from state Ids to pointers to states
408 // to store cached states.
409 template <class S>
410 class HashCacheStore {
411  public:
412   typedef S State;
413   typedef typename State::Arc Arc;
414   typedef typename Arc::StateId StateId;
415   typedef unordered_map<StateId, State *, std::hash<StateId>, std::equal_to<StateId>,
416                    PoolAllocator<pair<const StateId, State *> > > StateMap;
417 
418   // Required constructors/assignment operators
HashCacheStore(const CacheOptions & opts)419   explicit HashCacheStore(const CacheOptions &opts) {
420     Clear();
421     Reset();
422   }
423 
HashCacheStore(const HashCacheStore<S> & store)424   HashCacheStore(const HashCacheStore<S> &store) {
425     CopyStates(store);
426     Reset();
427   }
428 
~HashCacheStore()429   ~HashCacheStore() { Clear(); }
430 
431   HashCacheStore<State> &operator=(const HashCacheStore<State> &store) {
432     if (this != &store) {
433       CopyStates(store);
434       Reset();
435     }
436     return *this;
437   }
438 
439   // Returns 0 if state is not stoed
GetState(StateId s)440   const State *GetState(StateId s) const {
441     const typename StateMap::const_iterator it = state_map_.find(s);
442     return it != state_map_.end() ? it->second : 0;
443   }
444 
445   // Creates state if state is not stored
GetMutableState(StateId s)446   State *GetMutableState(StateId s) {
447     State* &state = state_map_[s];
448     if (state == 0)
449       state = new(&state_alloc_) State(arc_alloc_);
450     return state;
451   }
452 
453   // Similar to State::AddArc() but updates cache store book-keeping
AddArc(State * state,const Arc & arc)454   void AddArc(State *state, const Arc &arc) { state->AddArc(arc); }
455 
456   // Similar to State::SetArcs() but updates internal cache size.
457   // Call only once.
SetArcs(State * state)458   void SetArcs(State *state) { state->SetArcs(); }
459 
460   // Deletes all arcs
DeleteArcs(State * state)461   void DeleteArcs(State *state) { state->DeleteArcs(); }
462 
463   // Deletes some arcs
DeleteArcs(State * state,size_t n)464   void DeleteArcs(State *state, size_t n) { state->DeleteArcs(n); }
465 
466   // Deletes all cached states
Clear()467   void Clear() {
468     for (typename StateMap::iterator it = state_map_.begin();
469          it != state_map_.end();
470          ++it) {
471       State::Destroy(it->second, &state_alloc_);
472     }
473     state_map_.clear();
474   }
475 
476   // Iterates over cached states (in an arbitrary order).
Done()477   bool Done() const {
478     typename StateMap::const_iterator citer = iter_;
479     return citer == state_map_.end();
480   }
481 
Value()482   StateId Value() const { return iter_->first; }
Next()483   void Next() { ++iter_; }
Reset()484   void Reset() { iter_ = state_map_.begin();  }
485 
486   // Deletes current state and advances to next.
Delete()487   void Delete() {
488     State::Destroy(iter_->second, &state_alloc_);
489     state_map_.erase(iter_++);
490   }
491 
492  private:
CopyStates(const HashCacheStore<State> & store)493   void CopyStates(const HashCacheStore<State> &store) {
494     Clear();
495     for (typename StateMap::const_iterator it = store.state_map_.begin();
496          it != store.state_map_.end();
497          ++it) {
498       StateId s = it->first;
499       const S *state = it->second;
500       state_map_[s] = new(&state_alloc_) State(*state, arc_alloc_);
501     }
502   }
503 
504   StateMap state_map_;                     // map from State Id to state
505   typename StateMap::iterator iter_;       // state map iterator
506   typename State::StateAllocator state_alloc_;  // for state allocation
507   typename State::ArcAllocator arc_alloc_;      // for arc allocation
508 };
509 
510 
511 //
512 // GARBAGE COLLECTION CACHE STORES - these garbage collect underlying
513 // container cache stores.
514 //
515 
516 // This class implements a simple garbage collection scheme when
517 // 'opts.gc_limit' is 0. In particular, the first cached state is reused
518 // for each new state so long as the reference count is zero on
519 // the to-be-reused state. Otherwise, the full underlying store is used.
520 // The caller can increment the reference count to inhibit the
521 // GC of in-use states (e.g., in an ArcIterator).
522 //
523 // The typical use case for this optimization is when a single pass over
524 // a cached FST is performed with only one-state expanded at a time.
525 template <class C>
526 class FirstCacheStore {
527  public:
528   typedef typename C::State State;
529   typedef typename State::Arc Arc;
530   typedef typename Arc::StateId StateId;
531 
532   // Required constructors/assignment operators
FirstCacheStore(const CacheOptions & opts)533   explicit FirstCacheStore(const CacheOptions &opts) :
534       store_(opts),
535       cache_gc_(opts.gc_limit == 0),     // opts.gc ignored historically
536       cache_first_state_id_(kNoStateId),
537       cache_first_state_(0) { }
538 
FirstCacheStore(const FirstCacheStore<C> & store)539   FirstCacheStore(const FirstCacheStore<C> &store) :
540       store_(store.store_),
541       cache_gc_(store.cache_gc_),
542       cache_first_state_id_(store.cache_first_state_id_),
543       cache_first_state_(store.cache_first_state_id_ != kNoStateId ?
544                          store_.GetMutableState(0) : 0) { }
545 
546   FirstCacheStore<C> &operator=(const FirstCacheStore<C> &store) {
547     if (this != &store) {
548       store_ = store.store_;
549       cache_gc_ = store.cache_gc_;
550       cache_first_state_id_ = store.cache_first_state_id_;
551       cache_first_state_ = store.cache_first_state_id_ != kNoStateId ?
552           store_.GetMutableState(0) : 0;
553     }
554     return *this;
555   }
556 
557 
558   // Returns 0 if state is not stored
GetState(StateId s)559   const State *GetState(StateId s) const {
560     // store_ state 0 may hold first cached state; rest shifted + 1
561     return s == cache_first_state_id_ ?
562         cache_first_state_ : store_.GetState(s + 1);
563   }
564 
565   // Creates state if state is not stored
GetMutableState(StateId s)566   State *GetMutableState(StateId s) {
567     // store_ state 0 used to hold first cached state; rest shifted + 1
568     if (cache_first_state_id_ == s)
569       return cache_first_state_;          // request for first cached state
570 
571     if (cache_gc_) {
572       if (cache_first_state_id_ == kNoStateId) {
573         cache_first_state_id_ = s;        // sets first cached state
574         cache_first_state_ = store_.GetMutableState(0);
575         cache_first_state_->SetFlags(kCacheInit, kCacheInit);
576         cache_first_state_->ReserveArcs(2 * kAllocSize);
577         return cache_first_state_;
578       } else if (cache_first_state_->RefCount() == 0) {
579         cache_first_state_id_ = s;        // updates first cached state
580         cache_first_state_->Reset();
581         cache_first_state_->SetFlags(kCacheInit, kCacheInit);
582         return cache_first_state_;
583       } else {                            // keeps first cached state
584         cache_first_state_->SetFlags(0, kCacheInit);  // clears initialized bit
585         cache_gc_ = false;                // disable GC
586       }
587     }
588 
589     State *state = store_.GetMutableState(s + 1);
590     return state;
591   }
592 
593   // Similar to State::AddArc() but updates cache store book-keeping
AddArc(State * state,const Arc & arc)594   void AddArc(State *state, const Arc &arc) {
595     store_.AddArc(state, arc);
596   }
597 
598   // Similar to State::SetArcs() but updates internal cache size.
599   // Call only once.
SetArcs(State * state)600   void SetArcs(State *state) {
601     store_.SetArcs(state);
602   }
603 
604   // Deletes all arcs
DeleteArcs(State * state)605   void DeleteArcs(State *state) {
606     store_.DeleteArcs(state);
607   }
608 
609   // Deletes some arcs
DeleteArcs(State * state,size_t n)610   void DeleteArcs(State *state, size_t n) {
611     store_.DeleteArcs(state, n);
612   }
613 
614   // Deletes all cached states
Clear()615   void Clear() {
616     store_.Clear();
617     cache_first_state_id_ = kNoStateId;
618     cache_first_state_ = 0;
619   }
620 
621   // Iterates over cached states (in an arbitrary order).
622   // Only needed if GC is enabled.
Done()623   bool Done() const { return store_.Done(); }
624 
Value()625   StateId Value() const {
626     // store_ state 0 may hold first cached state; rest shifted + 1
627     StateId s = store_.Value();
628     return s == 0 ? cache_first_state_id_ : s - 1;
629   }
630 
Next()631   void Next() { store_.Next(); }
Reset()632   void Reset() { store_.Reset(); }
633 
634   // Deletes current state and advances to next.
Delete()635   void Delete() {
636     if (Value() == cache_first_state_id_) {
637       cache_first_state_id_ = kNoStateId;
638       cache_first_state_ = 0;
639     }
640     store_.Delete();
641   }
642 
643  private:
644   C store_;                            // Underlying store
645   bool cache_gc_;                      // GC enabled
646   StateId cache_first_state_id_;       // First cached state ID
647   State *cache_first_state_;           // First cached state
648 };
649 
650 
651 // This class implements mark-sweep garbage collection on an
652 // underlying cache store.  If the 'gc' option is 'true', garbage
653 // collection of states is performed in a rough approximation of LRU
654 // order, when 'gc_limit' bytes is reached - controlling memory
655 // use. The caller can increment the reference count to inhibit the
656 // GC of in-use states (e.g., in an ArcIterator). With GC enabled,
657 // the 'gc_limit' parameter allows the caller to trade-off time vs space.
658 template <class C>
659 class GCCacheStore {
660  public:
661   typedef typename C::State State;
662   typedef typename State::Arc Arc;
663   typedef typename Arc::StateId StateId;
664 
665   // Required constructors/assignment operators
GCCacheStore(const CacheOptions & opts)666   explicit GCCacheStore(const CacheOptions &opts) :
667       store_(opts),
668       cache_gc_request_(opts.gc),
669       cache_limit_(opts.gc_limit > kMinCacheLimit ?
670                    opts.gc_limit : kMinCacheLimit),
671       cache_gc_(false),
672       cache_size_(0) { }
673 
674   // Returns 0 if state is not stored
GetState(StateId s)675   const State *GetState(StateId s) const { return store_.GetState(s); }
676 
677   // Creates state if state is not stored
GetMutableState(StateId s)678   State *GetMutableState(StateId s) {
679     State *state = store_.GetMutableState(s);
680 
681     if (cache_gc_request_ && !(state->Flags() & kCacheInit)) {
682       state->SetFlags(kCacheInit, kCacheInit);
683       cache_size_ += sizeof(State) + state->NumArcs() * sizeof(Arc);
684       // GC is enabled once an uninited state (from underlying store) is seen
685       cache_gc_ = true;
686       if (cache_size_ > cache_limit_)
687         GC(state, false);
688     }
689     return state;
690   }
691 
692   // Similar to State::AddArc() but updates cache store book-keeping
AddArc(State * state,const Arc & arc)693   void AddArc(State *state, const Arc &arc) {
694     store_.AddArc(state, arc);
695     if (cache_gc_ && (state->Flags() & kCacheInit)) {
696       cache_size_ += sizeof(Arc);
697       if (cache_size_ > cache_limit_)
698         GC(state, false);
699     }
700   }
701 
702   // Similar to State::SetArcs() but updates internal cache size.
703   // Call only once.
SetArcs(State * state)704   void SetArcs(State *state) {
705     store_.SetArcs(state);
706     if (cache_gc_ && (state->Flags() & kCacheInit)) {
707       cache_size_ += state->NumArcs() * sizeof(Arc);
708       if (cache_size_ > cache_limit_)
709         GC(state, false);
710     }
711   }
712 
713   // Deletes all arcs
DeleteArcs(State * state)714   void DeleteArcs(State *state) {
715     if (cache_gc_ && (state->Flags() & kCacheInit))
716       cache_size_ -= state->NumArcs() * sizeof(Arc);
717     store_.DeleteArcs(state);
718   }
719 
720   // Deletes some arcs
DeleteArcs(State * state,size_t n)721   void DeleteArcs(State *state, size_t n) {
722     if (cache_gc_ && (state->Flags() & kCacheInit))
723       cache_size_ -= n * sizeof(Arc);
724     store_.DeleteArcs(state, n);
725   }
726 
727   // Deletes all cached states
Clear()728   void Clear() {
729     store_.Clear();
730     cache_size_ = 0;
731   }
732 
733   // Iterates over cached states (in an arbitrary order).
734   // Only needed if GC is enabled.
Done()735   bool Done() const { return store_.Done(); }
736 
Value()737   StateId Value() const { return store_.Value(); }
Next()738   void Next() { store_.Next(); }
Reset()739   void Reset() { store_.Reset(); }
740 
741   // Deletes current state and advances to next.
Delete()742   void Delete() {
743     if (cache_gc_) {
744       const State *state = store_.GetState(Value());
745       if (state->Flags() & kCacheInit)
746         cache_size_ -= sizeof(State) + state->NumArcs() * sizeof(Arc);
747     }
748     store_.Delete();
749   }
750 
751   // Removes from the cache store (not referenced-counted and not the
752   // current) states that have not been accessed since the last GC
753   // until at most cache_fraction * cache_limit_ bytes are cached.  If
754   // that fails to free enough, recurs uncaching recently visited
755   // states as well. If still unable to free enough memory, then
756   // widens cache_limit_ to fulfill condition.
757   void GC(const State *current, bool free_recent,
758           float cache_fraction = 0.666);
759 
760  private:
761   static const size_t kMinCacheLimit = 8096;   // Min. cache limit
762 
763   C store_;                 // Underlying store
764   bool cache_gc_request_;   // GC requested but possibly not yet enabled
765   size_t cache_limit_;      // # of bytes allowed before GC
766   bool cache_gc_;           // GC enabled
767   size_t cache_size_;       // # of bytes cached
768 };
769 
770 
771 // Removes from the cache store (not referenced-counted and not the
772 // current) states that have not been accessed since the last GC until
773 // at most cache_fraction * cache_limit_ bytes are cached.  If that
774 // fails to free enough, recurs uncaching recently visited states as
775 // well. If still unable to free enough memory, then widens
776 // cache_limit_ to fulfill condition.
777 template <class C>
GC(const State * current,bool free_recent,float cache_fraction)778 void GCCacheStore<C>::GC(const State *current,
779                          bool free_recent, float cache_fraction) {
780   if (!cache_gc_)
781     return;
782 
783   VLOG(2) << "GCCacheStore: Enter GC: object = " << "(" << this
784           << "), free recently cached = " << free_recent
785           << ", cache size = " << cache_size_
786           << ", cache frac = " << cache_fraction
787           << ", cache limit = " << cache_limit_ << "\n";
788 
789   size_t cache_target = cache_fraction * cache_limit_;
790   store_.Reset();
791   while (!store_.Done()) {
792     State* state = store_.GetMutableState(store_.Value());
793     if (cache_size_ > cache_target && state->RefCount() == 0 &&
794         (free_recent || !(state->Flags() & kCacheRecent)) &&
795         state != current) {
796       if (state->Flags() & kCacheInit) {
797         size_t size = sizeof(State) + state->NumArcs() * sizeof(Arc);
798         CHECK_LE(size, cache_size_);
799         cache_size_ -= size;
800       }
801       store_.Delete();
802     } else {
803       state->SetFlags(0, kCacheRecent);
804       store_.Next();
805     }
806   }
807 
808   if (!free_recent && cache_size_ > cache_target) {   // recurses on recent
809     GC(current, true, cache_fraction);
810   } else if (cache_target > 0) {                      // widens cache limit
811     while (cache_size_ > cache_target) {
812       cache_limit_ *= 2;
813       cache_target *= 2;
814     }
815   } else if (cache_size_ > 0) {
816     FSTERROR() << "GCCacheStore:GC: Unable to free all cached states";
817   }
818   VLOG(2) << "GCCacheStore: Exit GC: object = " << "(" << this
819           << "), free recently cached = " << free_recent
820           << ", cache size = " << cache_size_
821           << ", cache frac = " << cache_fraction
822           << ", cache limit = " << cache_limit_ << "\n";
823 }
824 
825 template <class C> const size_t GCCacheStore<C>::kMinCacheLimit;
826 
827 
828 // This class is the default cache state and store used by CacheBaseImpl.
829 // It uses VectorCacheStore for storage decorated by FirstCacheStore
830 // and GCCacheStore to do (optional) garbage collection.
831 template <class A>
832 class DefaultCacheStore
833     : public GCCacheStore<FirstCacheStore<
834                             VectorCacheStore<CacheState<A> > > > {
835  public:
DefaultCacheStore(const CacheOptions & opts)836   explicit DefaultCacheStore(const CacheOptions &opts)
837       : GCCacheStore<FirstCacheStore<
838                        VectorCacheStore<CacheState<A> > > >(opts) { }
839 };
840 
841 
842 // This class is used to cache FST elements stored in states of type S
843 // (see CacheState) with the flags used to indicate what has been
844 // cached. Use HasStart() HasFinal(), and HasArcs() to determine if
845 // cached and SetStart(), SetFinal(), AddArc(), (or PushArc() and
846 // SetArcs()) to cache. Note you must set the final weight even if the
847 // state is non-final to mark it as cached. The state storage method
848 // and any garbage collection policy are determined by the cache store C.
849 // If the store is passed in with the options, CacheBaseImpl takes ownership.
850 template <class S, class C = DefaultCacheStore<typename S::Arc> >
851 class CacheBaseImpl : public FstImpl<typename S::Arc> {
852  public:
853   typedef S State;
854   typedef C Store;
855 
856   typedef typename State::Arc Arc;
857   typedef typename Arc::Weight Weight;
858   typedef typename Arc::StateId StateId;
859 
860   using FstImpl<Arc>::Type;
861   using FstImpl<Arc>::Properties;
862 
CacheBaseImpl()863   CacheBaseImpl()
864       : has_start_(false), cache_start_(kNoStateId), nknown_states_(0),
865         min_unexpanded_state_id_(0),
866         max_expanded_state_id_(-1),
867         cache_gc_(FLAGS_fst_default_cache_gc),
868         cache_limit_(FLAGS_fst_default_cache_gc_limit),
869         cache_store_(new C(CacheOptions())),
870         new_cache_store_(true) { }
871 
CacheBaseImpl(const CacheOptions & opts)872   explicit CacheBaseImpl(const CacheOptions &opts)
873       : has_start_(false), cache_start_(kNoStateId), nknown_states_(0),
874         min_unexpanded_state_id_(0),  max_expanded_state_id_(-1),
875         cache_gc_(opts.gc), cache_limit_(opts.gc_limit),
876         cache_store_(new C(opts)),
877         new_cache_store_(true) { }
878 
CacheBaseImpl(const CacheImplOptions<C> & opts)879   explicit CacheBaseImpl(const CacheImplOptions<C> &opts)
880       : has_start_(false), cache_start_(kNoStateId), nknown_states_(0),
881         min_unexpanded_state_id_(0),  max_expanded_state_id_(-1),
882         cache_gc_(opts.gc), cache_limit_(opts.gc_limit),
883         cache_store_(opts.store ? opts.store :
884                      new C(CacheOptions(opts.gc, opts.gc_limit))),
885         new_cache_store_(!opts.store) { }
886 
887   // Preserve gc parameters. If preserve_cache true, also preserves
888   // cache data.
889   CacheBaseImpl(const CacheBaseImpl<S, C> &impl, bool preserve_cache = false)
890       : FstImpl<Arc>(),
891         has_start_(false), cache_start_(kNoStateId),
892         nknown_states_(0), min_unexpanded_state_id_(0),
893         max_expanded_state_id_(-1), cache_gc_(impl.cache_gc_),
894         cache_limit_(impl.cache_limit_),
895         cache_store_(new C(CacheOptions(cache_gc_, cache_limit_))),
896         new_cache_store_(impl.new_cache_store_ || !preserve_cache) {
897     if (preserve_cache) {
898       *cache_store_ = *impl.cache_store_;
899       has_start_ = impl.has_start_;
900       cache_start_ = impl.cache_start_;
901       nknown_states_ = impl.nknown_states_;
902       expanded_states_ = impl.expanded_states_;
903       min_unexpanded_state_id_ = impl.min_unexpanded_state_id_;
904       max_expanded_state_id_ = impl.max_expanded_state_id_;
905     }
906   }
907 
~CacheBaseImpl()908   ~CacheBaseImpl() {
909     delete cache_store_;
910   }
911 
SetStart(StateId s)912   void SetStart(StateId s) {
913     cache_start_ = s;
914     has_start_ = true;
915     if (s >= nknown_states_)
916       nknown_states_ = s + 1;
917   }
918 
SetFinal(StateId s,Weight w)919   void SetFinal(StateId s, Weight w) {
920     S *state = cache_store_->GetMutableState(s);
921     state->SetFinal(w);
922     int32 flags = kCacheFinal | kCacheRecent;
923     state->SetFlags(flags, flags);
924   }
925 
926   // Disabled to ensure PushArc not AddArc is used in existing code
927   // TODO(sorenj): re-enable for backing store
928 #if 0
929   // AddArc adds a single arc to state s and does incremental cache
930   // book-keeping.  For efficiency, prefer PushArc and SetArcs below
931   // when possible.
932   void AddArc(StateId s, const Arc &arc) {
933     S *state = cache_store_->GetMutableState(s);
934     cache_store_->AddArc(state, arc);
935     if (arc.nextstate >= nknown_states_)
936       nknown_states_ = arc.nextstate + 1;
937     SetExpandedState(s);
938     int32 flags = kCacheArcs | kCacheRecent;
939     state->SetFlags(flags, flags);
940   }
941 #endif
942 
943   // Adds a single arc to state s but delays cache book-keeping.
944   // SetArcs must be called when all PushArc calls at a state are
945   // complete.  Do not mix with calls to AddArc.
PushArc(StateId s,const Arc & arc)946   void PushArc(StateId s, const Arc &arc) {
947     S *state = cache_store_->GetMutableState(s);
948     state->PushArc(arc);
949   }
950 
951   // Marks arcs of state s as cached and does cache book-keeping after all
952   // calls to PushArc have been completed.  Do not mix with calls to AddArc.
SetArcs(StateId s)953   void SetArcs(StateId s) {
954     S *state = cache_store_->GetMutableState(s);
955     cache_store_->SetArcs(state);
956     size_t narcs = state->NumArcs();
957     for (size_t a = 0; a < narcs; ++a) {
958       const Arc &arc = state->GetArc(a);
959       if (arc.nextstate >= nknown_states_)
960         nknown_states_ = arc.nextstate + 1;
961     }
962     SetExpandedState(s);
963     int32 flags = kCacheArcs | kCacheRecent;
964     state->SetFlags(flags, flags);
965   }
966 
ReserveArcs(StateId s,size_t n)967   void ReserveArcs(StateId s, size_t n) {
968     S *state = cache_store_->GetMutableState(s);
969     state->ReserveArcs(n);
970   }
971 
DeleteArcs(StateId s)972   void DeleteArcs(StateId s) {
973     S *state = cache_store_->GetMutableState(s);
974     cache_store_->DeleteArcs(state);
975   }
976 
DeleteArcs(StateId s,size_t n)977   void DeleteArcs(StateId s, size_t n) {
978     S *state = cache_store_->GetMutableState(s);
979     cache_store_->DeleteArcs(state, n);
980   }
981 
Clear()982   void Clear() {
983     nknown_states_ = 0;
984     min_unexpanded_state_id_ = 0;
985     max_expanded_state_id_ = -1;
986     has_start_ = false;
987     cache_start_ = kNoStateId;
988     cache_store_->Clear();
989   }
990 
991   // Is the start state cached?
HasStart()992   bool HasStart() const {
993     if (!has_start_ && Properties(kError))
994       has_start_ = true;
995     return has_start_;
996   }
997 
998   // Is the final weight of state s cached?
HasFinal(StateId s)999   bool HasFinal(StateId s) const {
1000     const S *state = cache_store_->GetState(s);
1001     if (state && state->Flags() & kCacheFinal) {
1002       state->SetFlags(kCacheRecent, kCacheRecent);
1003       return true;
1004     } else {
1005       return false;
1006     }
1007   }
1008 
1009   // Are arcs of state s cached?
HasArcs(StateId s)1010   bool HasArcs(StateId s) const {
1011     const S *state = cache_store_->GetState(s);
1012     if (state && state->Flags() & kCacheArcs) {
1013       state->SetFlags(kCacheRecent, kCacheRecent);
1014       return true;
1015     } else {
1016       return false;
1017     }
1018   }
1019 
Start()1020   StateId Start() const {
1021     return cache_start_;
1022   }
1023 
Final(StateId s)1024   Weight Final(StateId s) const {
1025     const S *state = cache_store_->GetState(s);
1026     return state->Final();
1027   }
1028 
NumArcs(StateId s)1029   size_t NumArcs(StateId s) const {
1030     const S *state = cache_store_->GetState(s);
1031     return state->NumArcs();
1032   }
1033 
NumInputEpsilons(StateId s)1034   size_t NumInputEpsilons(StateId s) const {
1035     const S *state = cache_store_->GetState(s);
1036     return state->NumInputEpsilons();
1037   }
1038 
NumOutputEpsilons(StateId s)1039   size_t NumOutputEpsilons(StateId s) const {
1040     const S *state = cache_store_->GetState(s);
1041     return state->NumOutputEpsilons();
1042   }
1043 
1044   // Provides information needed for generic arc iterator.
InitArcIterator(StateId s,ArcIteratorData<Arc> * data)1045   void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
1046     const S *state = cache_store_->GetState(s);
1047     data->base = 0;
1048     data->narcs = state->NumArcs();
1049     data->arcs = state->Arcs();
1050     data->ref_count = state->MutableRefCount();
1051     state->IncrRefCount();
1052   }
1053 
1054   // Number of known states.
NumKnownStates()1055   StateId NumKnownStates() const { return nknown_states_; }
1056 
1057   // Update number of known states taking in account the existence of state s.
UpdateNumKnownStates(StateId s)1058   void UpdateNumKnownStates(StateId s) {
1059     if (s >= nknown_states_)
1060       nknown_states_ = s + 1;
1061   }
1062 
1063   // Finds the mininum never-expanded state Id
MinUnexpandedState()1064   StateId MinUnexpandedState() const {
1065     while (min_unexpanded_state_id_ <= max_expanded_state_id_ &&
1066            ExpandedState(min_unexpanded_state_id_))
1067       ++min_unexpanded_state_id_;
1068     return min_unexpanded_state_id_;
1069   }
1070 
1071   // Returns maxinum ever-expanded state Id
MaxExpandedState()1072   StateId MaxExpandedState() const {
1073     return max_expanded_state_id_;
1074   }
1075 
SetExpandedState(StateId s)1076   void SetExpandedState(StateId s) {
1077     if (s > max_expanded_state_id_)
1078       max_expanded_state_id_ = s;
1079     if (s < min_unexpanded_state_id_)
1080       return;
1081     if (s == min_unexpanded_state_id_)
1082       ++min_unexpanded_state_id_;
1083     if (cache_gc_ || cache_limit_ == 0) {
1084       while (expanded_states_.size() <= s)
1085         expanded_states_.push_back(false);
1086       expanded_states_[s] = true;
1087     }
1088   }
1089 
ExpandedState(StateId s)1090   bool ExpandedState(StateId s) const {
1091     if (cache_gc_ || cache_limit_ == 0) {
1092       return expanded_states_[s];
1093     } else if (new_cache_store_) {
1094       return cache_store_->GetState(s) != 0;
1095     } else {
1096       // If the cache was not created by this class (but provided as opt),
1097       // then the cached state needs to be inspected to update nknown_states_.
1098       return false;
1099     }
1100   }
1101 
GetCacheStore()1102   const C *GetCacheStore() const { return cache_store_; }
GetCacheStore()1103   C *GetCacheStore() { return cache_store_; }
1104 
1105   // Caching on/off switch, limit and size accessors.
GetCacheGc()1106   bool GetCacheGc() const { return cache_gc_; }
GetCacheLimit()1107   size_t GetCacheLimit() const { return cache_limit_; }
1108 
1109  private:
1110   mutable bool has_start_;                   // Is the start state cached?
1111   StateId cache_start_;                      // State Id of start state
1112   StateId nknown_states_;                    // # of known states
1113   vector<bool> expanded_states_;             // states that have been expanded
1114   mutable StateId min_unexpanded_state_id_;  // minimum never-expanded state Id
1115   mutable StateId max_expanded_state_id_;    // maximum ever-expanded state Id
1116   bool cache_gc_;                            // GC enabled
1117   size_t cache_limit_;                       // # of bytes allowed before GC
1118   Store *cache_store_;                       // store of cached states
1119   bool new_cache_store_;                     // store was created by class
1120 
1121   void operator=(const CacheBaseImpl<S, C> &impl);    // disallow
1122 };
1123 
1124 // A CacheBaseImpl with the default cache state type.
1125 template <class A>
1126 class CacheImpl : public CacheBaseImpl< CacheState<A> > {
1127  public:
1128   typedef CacheState<A> State;
1129 
CacheImpl()1130   CacheImpl() {}
1131 
CacheImpl(const CacheOptions & opts)1132   explicit CacheImpl(const CacheOptions &opts)
1133       : CacheBaseImpl< CacheState<A> >(opts) {}
1134 
1135   CacheImpl(const CacheImpl<A> &impl, bool preserve_cache = false)
1136       : CacheBaseImpl<State>(impl, preserve_cache) {}
1137 
1138  private:
1139   void operator=(const CacheImpl<State> &impl);    // disallow
1140 };
1141 
1142 
1143 // Use this to make a state iterator for a CacheBaseImpl-derived Fst,
1144 // which must have types 'Arc' and 'Store' defined.  Note this iterator only
1145 // returns those states reachable from the initial state, so consider
1146 // implementing a class-specific one.
1147 template <class F>
1148 class CacheStateIterator : public StateIteratorBase<typename F::Arc> {
1149  public:
1150   typedef typename F::Arc Arc;
1151   typedef typename F::Store Store;
1152   typedef typename Arc::StateId StateId;
1153   typedef typename Store::State State;
1154   typedef CacheBaseImpl<State, Store> Impl;
1155 
CacheStateIterator(const F & fst,Impl * impl)1156   CacheStateIterator(const F &fst, Impl *impl)
1157       : fst_(fst), impl_(impl), s_(0) {
1158         fst_.Start();  // force start state
1159       }
1160 
Done()1161   bool Done() const {
1162     if (s_ < impl_->NumKnownStates())
1163       return false;
1164     for (StateId u = impl_->MinUnexpandedState();
1165          u < impl_->NumKnownStates();
1166          u = impl_->MinUnexpandedState()) {
1167       // force state expansion
1168       ArcIterator<F> aiter(fst_, u);
1169       aiter.SetFlags(kArcValueFlags, kArcValueFlags | kArcNoCache);
1170       for (; !aiter.Done(); aiter.Next())
1171         impl_->UpdateNumKnownStates(aiter.Value().nextstate);
1172       impl_->SetExpandedState(u);
1173       if (s_ < impl_->NumKnownStates())
1174         return false;
1175     }
1176     return true;
1177   }
1178 
Value()1179   StateId Value() const { return s_; }
1180 
Next()1181   void Next() { ++s_; }
1182 
Reset()1183   void Reset() { s_ = 0; }
1184 
1185  private:
1186   // This allows base class virtual access to non-virtual derived-
1187   // class members of the same name. It makes the derived class more
1188   // efficient to use but unsafe to further derive.
Done_()1189   virtual bool Done_() const { return Done(); }
Value_()1190   virtual StateId Value_() const { return Value(); }
Next_()1191   virtual void Next_() { Next(); }
Reset_()1192   virtual void Reset_() { Reset(); }
1193 
1194   const F &fst_;
1195   Impl *impl_;
1196   StateId s_;
1197 };
1198 
1199 
1200 // Use this to make an arc iterator for a CacheBaseImpl-derived Fst,
1201 // which must have types 'Arc' and 'State' defined.
1202 template <class F>
1203 class CacheArcIterator {
1204  public:
1205   typedef typename F::Arc Arc;
1206   typedef typename F::Store Store;
1207   typedef typename Arc::StateId StateId;
1208   typedef typename Store::State State;
1209   typedef CacheBaseImpl<State, Store> Impl;
1210 
CacheArcIterator(Impl * impl,StateId s)1211   CacheArcIterator(Impl *impl, StateId s) : i_(0) {
1212     state_ = impl->GetCacheStore()->GetMutableState(s);
1213     state_->IncrRefCount();
1214   }
1215 
~CacheArcIterator()1216   ~CacheArcIterator() { state_->DecrRefCount();  }
1217 
Done()1218   bool Done() const { return i_ >= state_->NumArcs(); }
1219 
Value()1220   const Arc& Value() const { return state_->GetArc(i_); }
1221 
Next()1222   void Next() { ++i_; }
1223 
Position()1224   size_t Position() const { return i_; }
1225 
Reset()1226   void Reset() { i_ = 0; }
1227 
Seek(size_t a)1228   void Seek(size_t a) { i_ = a; }
1229 
Flags()1230   uint32 Flags() const {
1231     return kArcValueFlags;
1232   }
1233 
SetFlags(uint32 flags,uint32 mask)1234   void SetFlags(uint32 flags, uint32 mask) {}
1235 
1236  private:
1237   const State *state_;
1238   size_t i_;
1239 
1240   DISALLOW_COPY_AND_ASSIGN(CacheArcIterator);
1241 };
1242 
1243 // Use this to make a mutable arc iterator for a CacheBaseImpl-derived Fst,
1244 // which must have types 'Arc' and 'Store' defined.
1245 template <class F>
1246 class CacheMutableArcIterator
1247     : public MutableArcIteratorBase<typename F::Arc> {
1248  public:
1249   typedef typename F::Arc Arc;
1250   typedef typename F::Store Store;
1251   typedef typename Arc::StateId StateId;
1252   typedef typename Arc::Weight Weight;
1253   typedef typename Store::State State;
1254   typedef CacheBaseImpl<State, Store> Impl;
1255 
1256   // You will need to call MutateCheck() in the constructor.
CacheMutableArcIterator(Impl * impl,StateId s)1257   CacheMutableArcIterator(Impl *impl, StateId s) : i_(0), s_(s), impl_(impl) {
1258     state_ = impl_->GetCacheStore()->GetMutableState(s_);
1259     state_->IncrRefCount();
1260   }
1261 
~CacheMutableArcIterator()1262   ~CacheMutableArcIterator() {
1263     state_->DecrRefCount();
1264   }
1265 
Done()1266   bool Done() const { return i_ >= state_->NumArcs(); }
1267 
Value()1268   const Arc& Value() const { return state_->GetArc(i_); }
1269 
Next()1270   void Next() { ++i_; }
1271 
Position()1272   size_t Position() const { return i_; }
1273 
Reset()1274   void Reset() { i_ = 0; }
1275 
Seek(size_t a)1276   void Seek(size_t a) { i_ = a; }
1277 
SetValue(const Arc & arc)1278   void SetValue(const Arc& arc) { state_->SetArc(arc, i_); }
1279 
Flags()1280   uint32 Flags() const {
1281     return kArcValueFlags;
1282   }
1283 
SetFlags(uint32 f,uint32 m)1284   void SetFlags(uint32 f, uint32 m) {}
1285 
1286  private:
Done_()1287   virtual bool Done_() const { return Done(); }
Value_()1288   virtual const Arc& Value_() const { return Value(); }
Next_()1289   virtual void Next_() { Next(); }
Position_()1290   virtual size_t Position_() const { return Position(); }
Reset_()1291   virtual void Reset_() { Reset(); }
Seek_(size_t a)1292   virtual void Seek_(size_t a) { Seek(a); }
SetValue_(const Arc & a)1293   virtual void SetValue_(const Arc &a) { SetValue(a); }
Flags_()1294   uint32 Flags_() const { return Flags(); }
SetFlags_(uint32 f,uint32 m)1295   void SetFlags_(uint32 f, uint32 m) { SetFlags(f, m); }
1296 
1297   size_t i_;
1298   StateId s_;
1299   Impl *impl_;
1300   State *state_;
1301 
1302   DISALLOW_COPY_AND_ASSIGN(CacheMutableArcIterator);
1303 };
1304 
1305 }  // namespace fst
1306 
1307 #endif  // FST_LIB_CACHE_H__
1308