1f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// cache.h
2f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
3f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Licensed under the Apache License, Version 2.0 (the "License");
4f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// you may not use this file except in compliance with the License.
5f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// You may obtain a copy of the License at
6f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
7f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//     http://www.apache.org/licenses/LICENSE-2.0
8f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
9f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Unless required by applicable law or agreed to in writing, software
10f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// distributed under the License is distributed on an "AS IS" BASIS,
11f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// See the License for the specific language governing permissions and
13f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// limitations under the License.
14f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
15f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Copyright 2005-2010 Google, Inc.
16f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Author: riley@google.com (Michael Riley)
17f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
18f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// \file
19f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// An Fst implementation that caches FST elements of a delayed
20f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// computation.
21f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
22f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#ifndef FST_LIB_CACHE_H__
23f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#define FST_LIB_CACHE_H__
24f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
25f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <vector>
26f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonusing std::vector;
27f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <list>
28f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
29f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#include <fst/vector-fst.h>
30f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
31f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
32f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian HodsonDECLARE_bool(fst_default_cache_gc);
33f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian HodsonDECLARE_int64(fst_default_cache_gc_limit);
34f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
35f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonnamespace fst {
36f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
37f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonstruct CacheOptions {
38f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool gc;          // enable GC
39f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t gc_limit;  // # of bytes allowed before GC
40f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
41f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheOptions(bool g, size_t l) : gc(g), gc_limit(l) {}
42f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheOptions()
43f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      : gc(FLAGS_fst_default_cache_gc),
44f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        gc_limit(FLAGS_fst_default_cache_gc_limit) {}
45f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
46f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
47f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// A CacheStateAllocator allocates and frees CacheStates
48f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// template <class S>
49f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// struct CacheStateAllocator {
50f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//   S *Allocate(StateId s);
51f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//   void Free(S *state, StateId s);
52f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// };
53f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson//
54f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
55f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// A simple allocator class, can be overridden as needed,
56f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// maintains a single entry cache.
57f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S>
58f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonstruct DefaultCacheStateAllocator {
59f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename S::Arc::StateId StateId;
60f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
61f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  DefaultCacheStateAllocator() : mru_(NULL) { }
62f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
63f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  ~DefaultCacheStateAllocator() {
64f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    delete mru_;
65f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
66f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
67f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  S *Allocate(StateId s) {
68f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (mru_) {
69f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      S *state = mru_;
70f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      mru_ = NULL;
71f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      state->Reset();
72f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return state;
73f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
74f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return new S();
75f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
76f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
77f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Free(S *state, StateId s) {
78f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (mru_) {
79f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      delete mru_;
80f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
81f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    mru_ = state;
82f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
83f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
84f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
85f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  S *mru_;
86f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
87f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
88f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// VectorState but additionally has a flags data member (see
89f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// CacheState below). This class is used to cache FST elements with
90f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// the flags used to indicate what has been cached. Use HasStart()
91f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// HasFinal(), and HasArcs() to determine if cached and SetStart(),
925b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// SetFinal(), AddArc(), (or PushArc() and SetArcs()) to cache. Note
935b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// you must set the final weight even if the state is non-final to
945b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// mark it as cached. If the 'gc' option is 'false', cached items have
955b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// the extent of the FST - minimizing computation. If the 'gc' option
965b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// is 'true', garbage collection of states (not in use in an arc
975b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// iterator and not 'protected') is performed, in a rough
985b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// approximation of LRU order, when 'gc_limit' bytes is reached -
995b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// controlling memory use. When 'gc_limit' is 0, special optimizations
1005b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// apply - minimizing memory use.
101f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
102f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C = DefaultCacheStateAllocator<S> >
103f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonclass CacheBaseImpl : public VectorFstBaseImpl<S> {
104f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
105f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef S State;
106f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef C Allocator;
107f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename State::Arc Arc;
108f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::Weight Weight;
109f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::StateId StateId;
110f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
111f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using FstImpl<Arc>::Type;
112f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using FstImpl<Arc>::Properties;
113f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using FstImpl<Arc>::SetProperties;
114f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using VectorFstBaseImpl<State>::NumStates;
1155b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  using VectorFstBaseImpl<State>::Start;
116f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using VectorFstBaseImpl<State>::AddState;
117f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  using VectorFstBaseImpl<State>::SetState;
1185b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  using VectorFstBaseImpl<State>::ReserveStates;
119f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
120f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  explicit CacheBaseImpl(C *allocator = 0)
121f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      : cache_start_(false), nknown_states_(0), min_unexpanded_state_id_(0),
122f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        cache_first_state_id_(kNoStateId), cache_first_state_(0),
123f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        cache_gc_(FLAGS_fst_default_cache_gc),  cache_size_(0),
124f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        cache_limit_(FLAGS_fst_default_cache_gc_limit > kMinCacheLimit ||
125f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson                     FLAGS_fst_default_cache_gc_limit == 0 ?
1265b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin                     FLAGS_fst_default_cache_gc_limit : kMinCacheLimit),
1275b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        protect_(false) {
1285b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    allocator_ = allocator ? allocator : new C();
1295b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
130f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
131f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  explicit CacheBaseImpl(const CacheOptions &opts, C *allocator = 0)
132f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      : cache_start_(false), nknown_states_(0),
133f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        min_unexpanded_state_id_(0), cache_first_state_id_(kNoStateId),
134f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        cache_first_state_(0), cache_gc_(opts.gc), cache_size_(0),
135f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        cache_limit_(opts.gc_limit > kMinCacheLimit || opts.gc_limit == 0 ?
1365b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin                     opts.gc_limit : kMinCacheLimit),
1375b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        protect_(false) {
1385b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    allocator_ = allocator ? allocator : new C();
1395b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
140f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
1415b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // Preserve gc parameters. If preserve_cache true, also preserves
1425b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // cache data.
1435b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  CacheBaseImpl(const CacheBaseImpl<S, C> &impl, bool preserve_cache = false)
1445b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      : VectorFstBaseImpl<S>(), cache_start_(false), nknown_states_(0),
1455b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        min_unexpanded_state_id_(0), cache_first_state_id_(kNoStateId),
1465b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_first_state_(0), cache_gc_(impl.cache_gc_), cache_size_(0),
1475b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_limit_(impl.cache_limit_),
1485b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        protect_(impl.protect_) {
1495b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    allocator_ = new C();
1505b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (preserve_cache) {
1515b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_start_ = impl.cache_start_;
1525b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      nknown_states_ = impl.nknown_states_;
1535b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      expanded_states_ = impl.expanded_states_;
1545b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      min_unexpanded_state_id_ = impl.min_unexpanded_state_id_;
1555b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (impl.cache_first_state_id_ != kNoStateId) {
1565b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_first_state_id_ = impl.cache_first_state_id_;
1575b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_first_state_ = allocator_->Allocate(cache_first_state_id_);
1585b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        *cache_first_state_ = *impl.cache_first_state_;
159f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
1605b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_states_ = impl.cache_states_;
1615b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_size_ = impl.cache_size_;
1625b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      ReserveStates(impl.NumStates());
1635b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      for (StateId s = 0; s < impl.NumStates(); ++s) {
1645b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        const S *state =
1655b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin            static_cast<const VectorFstBaseImpl<S> &>(impl).GetState(s);
1665b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        if (state) {
1675b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          S *copied_state = allocator_->Allocate(s);
1685b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          *copied_state = *state;
1695b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          AddState(copied_state);
1705b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        } else {
1715b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          AddState(0);
1725b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        }
1735b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
1745b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      VectorFstBaseImpl<S>::SetStart(impl.Start());
1755b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
1765b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
177f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
178f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  ~CacheBaseImpl() {
179f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    allocator_->Free(cache_first_state_, cache_first_state_id_);
180f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    delete allocator_;
181f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
182f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
183f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Gets a state from its ID; state must exist.
184f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const S *GetState(StateId s) const {
185f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s == cache_first_state_id_)
186f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return cache_first_state_;
187f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    else
188f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return VectorFstBaseImpl<S>::GetState(s);
189f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
190f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
191f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Gets a state from its ID; state must exist.
192f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  S *GetState(StateId s) {
193f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s == cache_first_state_id_)
194f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return cache_first_state_;
195f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    else
196f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return VectorFstBaseImpl<S>::GetState(s);
197f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
198f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
199f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Gets a state from its ID; return 0 if it doesn't exist.
200f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const S *CheckState(StateId s) const {
201f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s == cache_first_state_id_)
202f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return cache_first_state_;
203f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    else if (s < NumStates())
204f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return VectorFstBaseImpl<S>::GetState(s);
205f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    else
206f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return 0;
207f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
208f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
209f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Gets a state from its ID; add it if necessary.
2105b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  S *ExtendState(StateId s);
211f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
212f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetStart(StateId s) {
213f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    VectorFstBaseImpl<S>::SetStart(s);
214f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    cache_start_ = true;
215f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s >= nknown_states_)
216f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      nknown_states_ = s + 1;
217f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
218f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
219f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetFinal(StateId s, Weight w) {
220f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
221f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->final = w;
222f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->flags |= kCacheFinal | kCacheRecent | kCacheModified;
223f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
224f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
225f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // AddArc adds a single arc to state s and does incremental cache
226f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // book-keeping.  For efficiency, prefer PushArc and SetArcs below
227f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // when possible.
228f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void AddArc(StateId s, const Arc &arc) {
229f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
230f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->arcs.push_back(arc);
231f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.ilabel == 0) {
232f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ++state->niepsilons;
233f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
234f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.olabel == 0) {
235f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ++state->noepsilons;
236f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
237f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const Arc *parc = state->arcs.empty() ? 0 : &(state->arcs.back());
238f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    SetProperties(AddArcProperties(Properties(), s, arc, parc));
239f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->flags |= kCacheModified;
2405b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (cache_gc_ && s != cache_first_state_id_ &&
2415b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        !(state->flags & kCacheProtect)) {
242f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      cache_size_ += sizeof(Arc);
243f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (cache_size_ > cache_limit_)
244f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        GC(s, false);
245f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
246f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
247f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
248f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Adds a single arc to state s but delays cache book-keeping.
249f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // SetArcs must be called when all PushArc calls at a state are
250f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // complete.  Do not mix with calls to AddArc.
251f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void PushArc(StateId s, const Arc &arc) {
252f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
253f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->arcs.push_back(arc);
254f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
255f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
256f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Marks arcs of state s as cached and does cache book-keeping after all
257f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // calls to PushArc have been completed.  Do not mix with calls to AddArc.
258f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetArcs(StateId s) {
259f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
260f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    vector<Arc> &arcs = state->arcs;
261f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->niepsilons = state->noepsilons = 0;
262f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    for (size_t a = 0; a < arcs.size(); ++a) {
263f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      const Arc &arc = arcs[a];
264f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arc.nextstate >= nknown_states_)
265f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        nknown_states_ = arc.nextstate + 1;
266f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arc.ilabel == 0)
267f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        ++state->niepsilons;
268f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arc.olabel == 0)
269f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        ++state->noepsilons;
270f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
271f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ExpandedState(s);
272f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->flags |= kCacheArcs | kCacheRecent | kCacheModified;
2735b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (cache_gc_ && s != cache_first_state_id_ &&
2745b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        !(state->flags & kCacheProtect)) {
275f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      cache_size_ += arcs.capacity() * sizeof(Arc);
276f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (cache_size_ > cache_limit_)
277f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        GC(s, false);
278f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
279f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  };
280f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
281f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void ReserveArcs(StateId s, size_t n) {
282f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
283f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->arcs.reserve(n);
284f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
285f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
286f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void DeleteArcs(StateId s, size_t n) {
287f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
288dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin    const vector<Arc> &arcs = state->arcs;
289f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    for (size_t i = 0; i < n; ++i) {
290f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      size_t j = arcs.size() - i - 1;
291f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arcs[j].ilabel == 0)
292dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin        --state->niepsilons;
293f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arcs[j].olabel == 0)
294dfd8b8327b93660601d016cdc6f29f433b45a8d8Alexander Gutkin        --state->noepsilons;
295f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
2965b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
297f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->arcs.resize(arcs.size() - n);
298f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    SetProperties(DeleteArcsProperties(Properties()));
299f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->flags |= kCacheModified;
3005b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (cache_gc_ && s != cache_first_state_id_ &&
3015b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        !(state->flags & kCacheProtect)) {
3025b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_size_ -= n * sizeof(Arc);
3035b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
304f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
305f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
306f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void DeleteArcs(StateId s) {
307f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    S *state = ExtendState(s);
3085b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    size_t n = state->arcs.size();
309f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->niepsilons = 0;
310f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->noepsilons = 0;
311f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->arcs.clear();
312f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    SetProperties(DeleteArcsProperties(Properties()));
313f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state->flags |= kCacheModified;
3145b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (cache_gc_ && s != cache_first_state_id_ &&
3155b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        !(state->flags & kCacheProtect)) {
3165b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_size_ -= n * sizeof(Arc);
3175b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
3185b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
3195b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
3205b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  void DeleteStates(const vector<StateId> &dstates) {
3215b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    size_t old_num_states = NumStates();
3225b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    vector<StateId> newid(old_num_states, 0);
3235b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    for (size_t i = 0; i < dstates.size(); ++i)
3245b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      newid[dstates[i]] = kNoStateId;
3255b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    StateId nstates = 0;
3265b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    for (StateId s = 0; s < old_num_states; ++s) {
3275b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (newid[s] != kNoStateId) {
3285b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        newid[s] = nstates;
3295b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        ++nstates;
3305b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
3315b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
3325b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    // just for states_.resize(), does unnecessary walk.
3335b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    VectorFstBaseImpl<S>::DeleteStates(dstates);
3345b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    SetProperties(DeleteStatesProperties(Properties()));
3355b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    // Update list of cached states.
3365b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    typename list<StateId>::iterator siter = cache_states_.begin();
3375b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    while (siter != cache_states_.end()) {
3385b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (newid[*siter] != kNoStateId) {
3395b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        *siter = newid[*siter];
3405b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        ++siter;
3415b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      } else {
3425b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_states_.erase(siter++);
3435b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
3445b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
3455b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
3465b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
3475b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  void DeleteStates() {
3485b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_states_.clear();
3495b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    allocator_->Free(cache_first_state_, cache_first_state_id_);
3505b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    for (int s = 0; s < NumStates(); ++s) {
3515b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      allocator_->Free(VectorFstBaseImpl<S>::GetState(s), s);
3525b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      SetState(s, 0);
3535b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
3545b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    nknown_states_ = 0;
3555b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    min_unexpanded_state_id_ = 0;
3565b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_id_ = kNoStateId;
3575b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_ = 0;
3585b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_size_ = 0;
3595b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_start_ = false;
3605b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    VectorFstBaseImpl<State>::DeleteStates();
3615b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    SetProperties(DeleteAllStatesProperties(Properties(),
3625b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin                                            kExpanded | kMutable));
363f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
364f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
365f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Is the start state cached?
366f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool HasStart() const {
367f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (!cache_start_ && Properties(kError))
368f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      cache_start_ = true;
369f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return cache_start_;
370f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
371f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
372f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Is the final weight of state s cached?
373f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool HasFinal(StateId s) const {
374f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = CheckState(s);
375f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (state && state->flags & kCacheFinal) {
376f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      state->flags |= kCacheRecent;
377f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return true;
378f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    } else {
379f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return false;
380f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
381f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
382f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
383f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Are arcs of state s cached?
384f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool HasArcs(StateId s) const {
385f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = CheckState(s);
386f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (state && state->flags & kCacheArcs) {
387f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      state->flags |= kCacheRecent;
388f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return true;
389f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    } else {
390f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return false;
391f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
392f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
393f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
394f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  Weight Final(StateId s) const {
395f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = GetState(s);
396f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return state->final;
397f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
398f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
399f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t NumArcs(StateId s) const {
400f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = GetState(s);
401f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return state->arcs.size();
402f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
403f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
404f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t NumInputEpsilons(StateId s) const {
405f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = GetState(s);
406f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return state->niepsilons;
407f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
408f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
409f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t NumOutputEpsilons(StateId s) const {
410f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = GetState(s);
411f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return state->noepsilons;
412f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
413f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
414f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Provides information needed for generic arc iterator.
415f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void InitArcIterator(StateId s, ArcIteratorData<Arc> *data) const {
416f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    const S *state = GetState(s);
417f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    data->base = 0;
418f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    data->narcs = state->arcs.size();
419f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    data->arcs = data->narcs > 0 ? &(state->arcs[0]) : 0;
420f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    data->ref_count = &(state->ref_count);
421f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ++(*data->ref_count);
422f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
423f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
424f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Number of known states.
425f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId NumKnownStates() const { return nknown_states_; }
426f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
427f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Update number of known states taking in account the existence of state s.
428f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void UpdateNumKnownStates(StateId s) {
429f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s >= nknown_states_)
430f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      nknown_states_ = s + 1;
431f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
432f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
433f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Find the mininum never-expanded state Id
434f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId MinUnexpandedState() const {
435f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    while (min_unexpanded_state_id_ < expanded_states_.size() &&
436f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          expanded_states_[min_unexpanded_state_id_])
437f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ++min_unexpanded_state_id_;
438f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return min_unexpanded_state_id_;
439f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
440f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
4415b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // Removes from cache_states_ and uncaches (not referenced-counted
4425b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // or protected) states that have not been accessed since the last
4435b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // GC until at most cache_fraction * cache_limit_ bytes are cached.
4445b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // If that fails to free enough, recurs uncaching recently visited
4455b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // states as well. If still unable to free enough memory, then
4465b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // widens cache_limit_ to fulfill condition.
4475b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  void GC(StateId current, bool free_recent,  float cache_fraction = 0.666);
448f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
4495b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // Setc/clears GC protection: if true, new states are protected
4505b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // from garbage collection.
4515b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  void GCProtect(bool on) { protect_ = on; }
452f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
453f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void ExpandedState(StateId s) {
454f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s < min_unexpanded_state_id_)
455f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return;
456f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    while (expanded_states_.size() <= s)
457f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      expanded_states_.push_back(false);
458f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    expanded_states_[s] = true;
459f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
460f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
4615b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  C *GetAllocator() const {
4625b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return allocator_;
4635b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
4645b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
465f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // Caching on/off switch, limit and size accessors.
466f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool GetCacheGc() const { return cache_gc_; }
467f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t GetCacheLimit() const { return cache_limit_; }
468f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t GetCacheSize() const { return cache_size_; }
469f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
470f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
4715b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const size_t kMinCacheLimit = 8096;   // Minimum (non-zero) cache limit
4725b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
4735b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const uint32 kCacheFinal =    0x0001;  // Final weight has been cached
4745b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const uint32 kCacheArcs =     0x0002;  // Arcs have been cached
4755b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const uint32 kCacheRecent =   0x0004;  // Mark as visited since GC
4765b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const uint32 kCacheProtect =  0x0008;  // Mark state as GC protected
477f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
478f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
4795b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  static const uint32 kCacheModified = 0x0010;  // Mark state as modified
480f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  static const uint32 kCacheFlags = kCacheFinal | kCacheArcs | kCacheRecent
4815b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      | kCacheProtect | kCacheModified;
482f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
483f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
4845b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  C *allocator_;                             // used to allocate new states
485f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  mutable bool cache_start_;                 // Is the start state cached?
486f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId nknown_states_;                    // # of known states
487f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  vector<bool> expanded_states_;             // states that have been expanded
488f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  mutable StateId min_unexpanded_state_id_;  // minimum never-expanded state Id
489f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId cache_first_state_id_;             // First cached state id
490f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  S *cache_first_state_;                     // First cached state
491f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  list<StateId> cache_states_;               // list of currently cached states
492f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool cache_gc_;                            // enable GC
493f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t cache_size_;                        // # of bytes cached
494f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t cache_limit_;                       // # of bytes allowed before GC
4955b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  bool protect_;                             // Protect new states from GC
496f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
4975b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  void operator=(const CacheBaseImpl<S, C> &impl);    // disallow
498f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
499f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
5005b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// Gets a state from its ID; add it if necessary.
5015b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkintemplate <class S, class C>
5025b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander GutkinS *CacheBaseImpl<S, C>::ExtendState(typename S::Arc::StateId s) {
5035b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  // If 'protect_' true and a new state, protects from garbage collection.
5045b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  if (s == cache_first_state_id_) {
5055b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return cache_first_state_;                   // Return 1st cached state
5065b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  } else if (cache_limit_ == 0 && cache_first_state_id_ == kNoStateId) {
5075b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_id_ = s;                   // Remember 1st cached state
5085b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_ = allocator_->Allocate(s);
5095b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (protect_) cache_first_state_->flags |= kCacheProtect;
5105b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return cache_first_state_;
5115b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  } else if (cache_first_state_id_ != kNoStateId &&
5125b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin             cache_first_state_->ref_count == 0 &&
5135b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin             !(cache_first_state_->flags & kCacheProtect)) {
5145b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    // With Default allocator, the Free and Allocate will reuse the same S*.
5155b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    allocator_->Free(cache_first_state_, cache_first_state_id_);
5165b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_id_ = s;
5175b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    cache_first_state_ = allocator_->Allocate(s);
5185b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (protect_) cache_first_state_->flags |= kCacheProtect;
5195b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return cache_first_state_;                   // Return 1st cached state
5205b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  } else {
5215b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    while (NumStates() <= s)                     // Add state to main cache
5225b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      AddState(0);
5235b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    S *state = VectorFstBaseImpl<S>::GetState(s);
5245b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (!state) {
5255b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      state = allocator_->Allocate(s);
5265b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (protect_) state->flags |= kCacheProtect;
5275b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      SetState(s, state);
5285b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (cache_first_state_id_ != kNoStateId) {  // Forget 1st cached state
5295b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        while (NumStates() <= cache_first_state_id_)
5305b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          AddState(0);
5315b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        SetState(cache_first_state_id_, cache_first_state_);
5325b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        if (cache_gc_ && !(cache_first_state_->flags & kCacheProtect)) {
5335b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          cache_states_.push_back(cache_first_state_id_);
5345b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          cache_size_ += sizeof(S) +
5355b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin                         cache_first_state_->arcs.capacity() * sizeof(Arc);
5365b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        }
5375b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_limit_ = kMinCacheLimit;
5385b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_first_state_id_ = kNoStateId;
5395b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_first_state_ = 0;
5405b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
5415b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      if (cache_gc_ && !protect_) {
5425b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_states_.push_back(s);
5435b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        cache_size_ += sizeof(S);
5445b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        if (cache_size_ > cache_limit_)
5455b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          GC(s, false);
5465b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
5475b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
5485b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return state;
5495b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
5505b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin}
5515b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
5525b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// Removes from cache_states_ and uncaches (not referenced-counted or
5535b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// protected) states that have not been accessed since the last GC
5545b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// until at most cache_fraction * cache_limit_ bytes are cached.  If
5555b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// that fails to free enough, recurs uncaching recently visited states
5565b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// as well. If still unable to free enough memory, then widens cache_limit_
5575b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin// to fulfill condition.
5585b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkintemplate <class S, class C>
5595b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkinvoid CacheBaseImpl<S, C>::GC(typename S::Arc::StateId current,
5605b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin                             bool free_recent, float cache_fraction) {
5615b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  if (!cache_gc_)
5625b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    return;
5635b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  VLOG(2) << "CacheImpl: Enter GC: object = " << Type() << "(" << this
5645b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << "), free recently cached = " << free_recent
5655b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache size = " << cache_size_
5665b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache frac = " << cache_fraction
5675b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache limit = " << cache_limit_ << "\n";
5685b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  typename list<StateId>::iterator siter = cache_states_.begin();
5695b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
5705b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  size_t cache_target = cache_fraction * cache_limit_;
5715b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  while (siter != cache_states_.end()) {
5725b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    StateId s = *siter;
5735b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    S* state = VectorFstBaseImpl<S>::GetState(s);
5745b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    if (cache_size_ > cache_target && state->ref_count == 0 &&
5755b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        (free_recent || !(state->flags & kCacheRecent)) && s != current) {
5765b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_size_ -= sizeof(S) + state->arcs.capacity() * sizeof(Arc);
5775b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      allocator_->Free(state, s);
5785b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      SetState(s, 0);
5795b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_states_.erase(siter++);
5805b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    } else {
5815b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      state->flags &= ~kCacheRecent;
5825b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      ++siter;
5835b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
5845b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
5855b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  if (!free_recent && cache_size_ > cache_target) {   // recurses on recent
5865b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    GC(current, true);
5875b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  } else if (cache_target > 0) {                      // widens cache limit
5885b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    while (cache_size_ > cache_target) {
5895b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_limit_ *= 2;
5905b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      cache_target *= 2;
5915b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    }
5925b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  } else if (cache_size_ > 0) {
5935b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin    FSTERROR() << "CacheImpl:GC: Unable to free all cached states";
5945b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  }
5955b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  VLOG(2) << "CacheImpl: Exit GC: object = " << Type() << "(" << this
5965b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << "), free recently cached = " << free_recent
5975b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache size = " << cache_size_
5985b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache frac = " << cache_fraction
5995b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin          << ", cache limit = " << cache_limit_ << "\n";
6005b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin}
6015b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin
602f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C> const uint32 CacheBaseImpl<S, C>::kCacheFinal;
603f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C> const uint32 CacheBaseImpl<S, C>::kCacheArcs;
604f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C> const uint32 CacheBaseImpl<S, C>::kCacheRecent;
605f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C> const uint32 CacheBaseImpl<S, C>::kCacheModified;
606f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class S, class C> const size_t CacheBaseImpl<S, C>::kMinCacheLimit;
607f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
608f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Arcs implemented by an STL vector per state. Similar to VectorState
609f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// but adds flags and ref count to keep track of what has been cached.
610f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class A>
611f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonstruct CacheState {
612f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef A Arc;
613f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename A::Weight Weight;
614f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename A::StateId StateId;
615f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
616f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheState() :  final(Weight::Zero()), flags(0), ref_count(0) {}
617f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
618f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Reset() {
619f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    flags = 0;
620f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ref_count = 0;
621f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    arcs.resize(0);
622f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
623f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
624f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  Weight final;              // Final weight
625f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  vector<A> arcs;            // Arcs represenation
626f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t niepsilons;         // # of input epsilons
627f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t noepsilons;         // # of output epsilons
628f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  mutable uint32 flags;
629f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  mutable int ref_count;
630f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
631f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
632f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// A CacheBaseImpl with a commonly used CacheState.
633f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class A>
634f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonclass CacheImpl : public CacheBaseImpl< CacheState<A> > {
635f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
636f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef CacheState<A> State;
637f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
638f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheImpl() {}
639f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
640f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  explicit CacheImpl(const CacheOptions &opts)
641f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      : CacheBaseImpl< CacheState<A> >(opts) {}
642f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
6435b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin  CacheImpl(const CacheImpl<A> &impl, bool preserve_cache = false)
6445b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      : CacheBaseImpl<State>(impl, preserve_cache) {}
645f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
646f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
647f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void operator=(const CacheImpl<State> &impl);    // disallow
648f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
649f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
650f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
651f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Use this to make a state iterator for a CacheBaseImpl-derived Fst,
652f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// which must have type 'State' defined.  Note this iterator only
653f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// returns those states reachable from the initial state, so consider
654f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// implementing a class-specific one.
655f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class F>
656f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonclass CacheStateIterator : public StateIteratorBase<typename F::Arc> {
657f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
658f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::Arc Arc;
659f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::StateId StateId;
660f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::State State;
661f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef CacheBaseImpl<State> Impl;
662f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
663f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheStateIterator(const F &fst, Impl *impl)
6645b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      : fst_(fst), impl_(impl), s_(0) {
6655b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin        fst_.Start();  // force start state
6665b6dc79427b8f7eeb6a7ff68034ab8548ce670eaAlexander Gutkin      }
667f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
668f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool Done() const {
669f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s_ < impl_->NumKnownStates())
670f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return false;
671f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (s_ < impl_->NumKnownStates())
672f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      return false;
673f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    for (StateId u = impl_->MinUnexpandedState();
674f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson         u < impl_->NumKnownStates();
675f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson         u = impl_->MinUnexpandedState()) {
676f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      // force state expansion
677f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ArcIterator<F> aiter(fst_, u);
678f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      aiter.SetFlags(kArcValueFlags, kArcValueFlags | kArcNoCache);
679f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      for (; !aiter.Done(); aiter.Next())
680f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        impl_->UpdateNumKnownStates(aiter.Value().nextstate);
681f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      impl_->ExpandedState(u);
682f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (s_ < impl_->NumKnownStates())
683f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        return false;
684f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
685f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return true;
686f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
687f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
688f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId Value() const { return s_; }
689f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
690f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Next() { ++s_; }
691f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
692f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Reset() { s_ = 0; }
693f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
694f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
695f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // This allows base class virtual access to non-virtual derived-
696f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // class members of the same name. It makes the derived class more
697f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // efficient to use but unsafe to further derive.
698f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual bool Done_() const { return Done(); }
699f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual StateId Value_() const { return Value(); }
700f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void Next_() { Next(); }
701f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void Reset_() { Reset(); }
702f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
703f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const F &fst_;
704f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  Impl *impl_;
705f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId s_;
706f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
707f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
708f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
709f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Use this to make an arc iterator for a CacheBaseImpl-derived Fst,
710f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// which must have types 'Arc' and 'State' defined.
711f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class F,
712f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          class C = DefaultCacheStateAllocator<CacheState<typename F::Arc> > >
713f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonclass CacheArcIterator {
714f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
715f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::Arc Arc;
716f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::State State;
717f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::StateId StateId;
718f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef CacheBaseImpl<State, C> Impl;
719f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
720f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheArcIterator(Impl *impl, StateId s) : i_(0) {
721f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state_ = impl->ExtendState(s);
722f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ++state_->ref_count;
723f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
724f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
725f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  ~CacheArcIterator() { --state_->ref_count;  }
726f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
727f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool Done() const { return i_ >= state_->arcs.size(); }
728f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
729f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const Arc& Value() const { return state_->arcs[i_]; }
730f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
731f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Next() { ++i_; }
732f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
733f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t Position() const { return i_; }
734f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
735f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Reset() { i_ = 0; }
736f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
737f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Seek(size_t a) { i_ = a; }
738f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
739f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint32 Flags() const {
740f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return kArcValueFlags;
741f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
742f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
743f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetFlags(uint32 flags, uint32 mask) {}
744f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
745f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
746f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const State *state_;
747f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t i_;
748f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
749f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  DISALLOW_COPY_AND_ASSIGN(CacheArcIterator);
750f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
751f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
752f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// Use this to make a mutable arc iterator for a CacheBaseImpl-derived Fst,
753f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson// which must have types 'Arc' and 'State' defined.
754f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsontemplate <class F,
755f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson          class C = DefaultCacheStateAllocator<CacheState<typename F::Arc> > >
756f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodsonclass CacheMutableArcIterator
757f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    : public MutableArcIteratorBase<typename F::Arc> {
758f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson public:
759f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::State State;
760f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename F::Arc Arc;
761f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::StateId StateId;
762f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef typename Arc::Weight Weight;
763f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  typedef CacheBaseImpl<State, C> Impl;
764f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
765f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  // You will need to call MutateCheck() in the constructor.
766f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  CacheMutableArcIterator(Impl *impl, StateId s) : i_(0), s_(s), impl_(impl) {
767f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state_ = impl_->ExtendState(s_);
768f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    ++state_->ref_count;
769f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  };
770f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
771f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  ~CacheMutableArcIterator() {
772f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    --state_->ref_count;
773f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
774f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
775f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  bool Done() const { return i_ >= state_->arcs.size(); }
776f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
777f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  const Arc& Value() const { return state_->arcs[i_]; }
778f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
779f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Next() { ++i_; }
780f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
781f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t Position() const { return i_; }
782f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
783f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Reset() { i_ = 0; }
784f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
785f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void Seek(size_t a) { i_ = a; }
786f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
787f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetValue(const Arc& arc) {
788f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    state_->flags |= CacheBaseImpl<State, C>::kCacheModified;
789f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    uint64 properties = impl_->Properties();
790f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    Arc& oarc = state_->arcs[i_];
791f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (oarc.ilabel != oarc.olabel)
792f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kNotAcceptor;
793f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (oarc.ilabel == 0) {
794f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      --state_->niepsilons;
795f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kIEpsilons;
796f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (oarc.olabel == 0)
797f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        properties &= ~kEpsilons;
798f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
799f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (oarc.olabel == 0) {
800f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      --state_->noepsilons;
801f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kOEpsilons;
802f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
803f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (oarc.weight != Weight::Zero() && oarc.weight != Weight::One())
804f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kWeighted;
805f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    oarc = arc;
806f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.ilabel != arc.olabel) {
807f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties |= kNotAcceptor;
808f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kAcceptor;
809f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
810f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.ilabel == 0) {
811f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ++state_->niepsilons;
812f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties |= kIEpsilons;
813f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kNoIEpsilons;
814f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      if (arc.olabel == 0) {
815f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        properties |= kEpsilons;
816f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        properties &= ~kNoEpsilons;
817f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      }
818f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
819f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.olabel == 0) {
820f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      ++state_->noepsilons;
821f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties |= kOEpsilons;
822f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kNoOEpsilons;
823f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
824f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    if (arc.weight != Weight::Zero() && arc.weight != Weight::One()) {
825f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties |= kWeighted;
826f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson      properties &= ~kUnweighted;
827f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    }
828f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    properties &= kSetArcProperties | kAcceptor | kNotAcceptor |
829f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        kEpsilons | kNoEpsilons | kIEpsilons | kNoIEpsilons |
830f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson        kOEpsilons | kNoOEpsilons | kWeighted | kUnweighted;
831f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    impl_->SetProperties(properties);
832f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
833f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
834f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint32 Flags() const {
835f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson    return kArcValueFlags;
836f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  }
837f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
838f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetFlags(uint32 f, uint32 m) {}
839f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
840f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson private:
841f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual bool Done_() const { return Done(); }
842f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual const Arc& Value_() const { return Value(); }
843f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void Next_() { Next(); }
844f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual size_t Position_() const { return Position(); }
845f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void Reset_() { Reset(); }
846f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void Seek_(size_t a) { Seek(a); }
847f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  virtual void SetValue_(const Arc &a) { SetValue(a); }
848f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  uint32 Flags_() const { return Flags(); }
849f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  void SetFlags_(uint32 f, uint32 m) { SetFlags(f, m); }
850f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
851f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  size_t i_;
852f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  StateId s_;
853f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  Impl *impl_;
854f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  State *state_;
855f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
856f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson  DISALLOW_COPY_AND_ASSIGN(CacheMutableArcIterator);
857f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson};
858f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
859f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson}  // namespace fst
860f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson
861f4c12fce1ee58e670f9c3fce46c40296ba9ee8a2Ian Hodson#endif  // FST_LIB_CACHE_H__
862