---
# System prepended metadata

title: LRU Cache in Chromium
tags: [Chromium-General, elkurin-daily-note]

---

baseディレクトリの中を散歩していたら[lru_cache.h](https://source.chromium.org/chromium/chromium/src/+/main:base/containers/lru_cache.h)というファイルを見つけたので読んでみる。

## LRU Cache とは
**L**east **R**ecently **U**sed **Cache**。  
キャッシュ容量がパンパンになったときに、使用履歴が一番古いものを消す方式のキャッシュのこと。
いろんなところで使われている有効なコンセプト。  
最近だと[Frame Eviction](/p7Xlv09bTgKBczGScYAnJA)のノートで読んだ[FrameEvictionManager](https://source.chromium.org/chromium/chromium/src/+/main:components/viz/client/frame_eviction_manager.h)で`unlocked_frames_`のリストを管理するために使用しているのを見た。  
上の例では自前で実装しているが、Chromiumには[base::LRUCache](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h)というデータ構造も実装されている。  
以下のように書くと使える。
```cpp=
base::LRUCache<GURL, std::unique_ptr<CacheEntry>> cache_;
```

## LRUCacheの実装
```cpp=
template <class ValueType, class GetKeyFromValue, class KeyIndexTemplate>
class LRUCacheBase {
```
ValueType型でストアするキャッシュの値。  
データは`std::list<value_type>`型の`ordering_`に保存される。  
キーはKeyIndex型の`index_`に保存されている。  
KeyIndexTemplateにはstd::unordered_mapの[HashingLRUCacheKeyIndex](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=237;drc=f09c12c84b39d13189a7039a05253ca3766d4751)か、std::mapの[LRUCacheKeyIndex](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=231;drc=f09c12c84b39d13189a7039a05253ca3766d4751)が使用される。  

`index_`がkeyとvalueの組み合わせをハッシュテーブルまたはマップで持ち、`ordering_`でLRUキャッシュとしての順番を保存している。  
LRUキャッシュの最大サイズは[コンストラクタ](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=78;drc=f09c12c84b39d13189a7039a05253ca3766d4751)で設定される。

### Look up
[Get](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=130;drc=f09c12c84b39d13189a7039a05253ca3766d4751)というAPIがやる。  

普通に`key`を受け取ってそれに対応するものを`index_`から探し返す。  
そして`ordering_.splice(ordering_.begin(), ordering_, iter);`で対応する`iter`を`ordering_`の先頭に持ってくる。

また[Peek](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=143;drc=f09c12c84b39d13189a7039a05253ca3766d4751)では順序に影響を与えずに値だけ参照することができる。そのため`const_iterator Peek(const key_type& key) const`の関数ではconst装飾子がついている。  

### 挿入
[Put](https://source.chromium.org/chromium/chromium/src/+/main:base/containers/lru_cache.h;l=96;drc=2efb465248fe03de205fdfea00a01b88e0665c07)というAPIがやる。  

`value`を代入すると以下の実装が呼ばれる。
```cpp=
iterator Put(value_type&& value) {
  key_type key = GetKeyFromValue{}(value);
  typename KeyIndex::iterator index_iter = index_.find(key);
  if (index_iter != index_.end()) {
    Erase(index_iter->second);
  } else if (max_size_ != NO_AUTO_EVICT) {
    ShrinkToSize(max_size_ - 1);
  }
  ordering_.push_front(std::move(value));
  index_.emplace(std::move(key), ordering_.begin());
  return ordering_.begin();
}
```
もしvalueに対応するkeyがあるなら[Erase](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=166;drc=f09c12c84b39d13189a7039a05253ca3766d4751)を呼んで`index_`と`ordering_`からデータを消して`ordering_`にpush_frontする。  
新しいvalueなら[ShrinkToSize](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=182;drc=f09c12c84b39d13189a7039a05253ca3766d4751)を呼んで、もしサイズが`max_size_`を超えたらその分うしろから消し、やはり`ordering_`にpush_front。  

## Note
KeyIndexの型定義がこうなっていた。  
```cpp=
typename KeyIndexTemplate::template Type<typename ValueList::iterator>;
```
全然読めない。

まず`<typename ValueList::iterator>`はなにか？  
これはテンプレートパラメータ内部にある型はそのままだと型名として解釈されないので、typenameをつけてやる必要がる。`using size_type = typename ValueList::size_type;`などでも、ValueListというテンプレートパラメータの内部にあるsize_type型を型名だと認識させるために`typename`装飾子をつけている。  
前半の`typename KeyIndexTemplate::template`でもKeyIndexTemplateの内部にある`template`を型名と認識させるためにつけている。  

次に`Type`は紛らわしいがただのテンプレート。[HashingLRUCacheKeyIndex](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=237;drc=f09c12c84b39d13189a7039a05253ca3766d4751)か[LRUCacheKeyIndex](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/containers/lru_cache.h;l=231;drc=f09c12c84b39d13189a7039a05253ca3766d4751)の中で定義されている。  

最後に`::template`。これはテンプレートパラメータに突っ込まれている型のメンバtemplateを取り出す際にそれがテンプレートだと示すためにつけるキーワードらしい。  

というわけで、この一行は`KeyIndexTemplate`型に突っ込まれたtemplateである`Type`のテンプレート引数に`ValueList::iterator`型を渡した型だよってこと。
読めた。
