summaryrefslogtreecommitdiff
path: root/src/lru.hh
blob: 3279b356ebe57883a8fae018b909772dbe5d7315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// -*- mode: c++; c-basic-offset: 2; -*-

#ifndef LRU_HH
#define LRU_HH

#include <algorithm>
#include <deque>
#include <unordered_map>

template<typename K, typename V>
class lru {
public:
  lru(size_t size)
    : size_(size) {
  }

  bool empty() const {
    return usage_.empty();
  }

  size_t size() const {
    return usage_.size();
  }

  V* get(K const& key) {
    auto it = data_.find(key);
    if (it == data_.end()) return nullptr;
    auto it2 = std::find(usage_.begin(), usage_.end(), key);
    if (it2 != usage_.begin()) {
      usage_.erase(it2);
      usage_.push_front(key);
    }
    return &it->second;
  }

  void insert(K const& key, V const& data) {
    auto pair = data_.insert(std::make_pair(key, data));
    if (pair.second) {
      usage_.push_front(key);
      shrink_to_size();
    } else {
      pair.first->second = data;
      auto it = std::find(usage_.begin(), usage_.end(), key);
      if (it != usage_.begin()) {
        usage_.erase(it);
        usage_.push_front(key);
      }
    }
  }

  void erase(K const& key) {
    if (data_.erase(key)) {
      usage_.erase(std::find(usage_.begin(), usage_.end(), key));
    }
  }

private:
  void shrink_to_size() {
    if (usage_.size() > size_) {
      data_.erase(usage_.back());
      usage_.pop_back();
    }
  }

  size_t const size_;
  std::deque<K> usage_;
  std::unordered_map<K, V> data_;
};

#endif  // LRU_HH