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