Last active
March 20, 2020 15:50
-
-
Save ChunMinChang/d5a9229ff2bc5ba55385e0b601d43581 to your computer and use it in GitHub Desktop.
A <Key, Value> LRU sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef LRU_TABLE_H | |
#define LRU_TABLE_H | |
#include <list> | |
#include <optional> | |
#include <unordered_map> | |
#include <utility> | |
#ifdef LRU_TABLE_DEBUG | |
#include <iostream> | |
#include <iterator> | |
#endif // LRU_TABLE_DEBUG | |
template <class K, class V> | |
class LRUTable { | |
typedef std::list<std::pair<K, V>> List; | |
typedef std::unordered_map<K, typename List::iterator> Position; | |
public: | |
LRUTable() {} | |
~LRUTable() {} | |
std::optional<std::pair<K, V>> least_recently_used() { | |
return list.empty() ? std::nullopt : std::make_optional(list.back()); | |
} | |
std::optional<std::pair<K, V>> most_recently_used() { | |
return list.empty() ? std::nullopt : std::make_optional(list.front()); | |
} | |
std::optional<V> lookup(K key) { | |
auto pos = position.find(key); | |
if (pos == position.end()) { | |
return std::nullopt; | |
} | |
move_to_front(pos); | |
typename List::iterator& it = pos->second; | |
return std::make_optional(it->second); | |
} | |
void insert(K key, V value) { | |
auto pos = position.find(key); | |
// Insert a new item in the front | |
if (pos == position.end()) { | |
list.emplace_front(std::make_pair(key, value)); | |
position[key] = list.begin(); | |
return; | |
} | |
// Otherwise, update the value and move it to the front | |
typename List::iterator& it = pos->second; | |
it->second = value; | |
move_to_front(pos); | |
} | |
bool erase(K key) { | |
auto pos = position.find(key); | |
if (pos == position.end()) { | |
return false; | |
} | |
list.erase(pos->second); | |
position.erase(pos); | |
return true; | |
} | |
#ifdef LRU_TABLE_DEBUG | |
void display() { | |
for (auto i = list.begin(); i != list.end(); ++i) { | |
std::cout << "<" << i->first << ", " << i->second << ">"; | |
if (std::next(i) != list.end()) { | |
std::cout << ", "; | |
} | |
} | |
std::cout << std::endl; | |
} | |
#endif // LRU_TABLE_DEBUG | |
private: | |
void move_to_front(typename Position::iterator& it) { | |
list.splice(list.begin(), list, it->second); | |
it->second = list.begin(); | |
} | |
List list; | |
Position position; | |
}; | |
#endif // LRU_TABLE_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Build C++ client example | |
# Process with GNU make | |
all: test | |
check: all | |
./test | |
HEADER := lru_table.h | |
CXXFLAGS = -g -Wall -std=c++17 -fsanitize=address -DLRU_TABLE_DEBUG=1 | |
test: test.cc $(HEADER) | |
$(CXX) $(CXXFLAGS) -c $(filter %.cc,$^) | |
$(CXX) $(CXXFLAGS) -o $@ *.o | |
clean: | |
$(RM) test | |
$(RM) *.a.out | |
$(RM) *.o *.a | |
$(RM) *.d | |
$(RM) -rf *.dSYM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// #define LRU_TABLE_DEBUG 1 | |
#include "lru_table.h" | |
#include <cassert> | |
#include <string> | |
#define assertm(exp, msg) assert(((void)msg, exp)) | |
using std::string; | |
int main() { | |
LRUTable<int, string> table; | |
assertm(!table.most_recently_used().has_value(), "table should be empty"); | |
assertm(!table.least_recently_used().has_value(), "table should be empty"); | |
assertm(!table.lookup(1).has_value(), "table[1] should be empty"); | |
table.insert(1, "this"); | |
table.insert(2, "world"); | |
assertm((table.most_recently_used().value() == | |
std::make_pair<int, string>(2, "world")), | |
"table front should be `<2, world>`"); | |
assertm((table.least_recently_used().value() == | |
std::make_pair<int, string>(1, "this")), | |
"table front should be `<1, this>`"); | |
table.insert(1, "crazy"); | |
assertm(table.lookup(1).value() == "crazy", "table[1] should be `crazy`"); | |
assertm((table.most_recently_used().value() == | |
std::make_pair<int, string>(1, "crazy")), | |
"table front should be `<1, crazy>`"); | |
assertm((table.least_recently_used().value() == | |
std::make_pair<int, string>(2, "world")), | |
"table front should be `<2, world>`"); | |
table.insert(6, "web"); | |
table.insert(5, "wide"); | |
assertm(!table.erase(0xdeadbeef), "table should remove nothing"); | |
assertm(table.erase(1), "table[1] should be removed"); | |
assertm(table.lookup(2).value() == "world", "table[2] should be `world`"); | |
assertm((table.most_recently_used().value() == | |
std::make_pair<int, string>(2, "world")), | |
"table front should be `<2, world>`"); | |
assertm((table.least_recently_used().value() == | |
std::make_pair<int, string>(6, "web")), | |
"table front should be `<6, web>`"); | |
#ifdef LRU_TABLE_DEBUG | |
table.display(); | |
#endif // LRU_TABLE_DEBUG | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
make check && make clean |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment