Initial Commit
This commit is contained in:
commit
5c81b63fe8
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ignore all .o files
|
||||||
|
src/**/*.o
|
||||||
|
|
||||||
|
#ignore all swp files
|
||||||
|
**/*.swp
|
||||||
|
|
||||||
|
#ignore all executables, but still keep the bin folder
|
||||||
|
bin/*
|
||||||
|
!bin/.gitkeep
|
43
Makefile
Normal file
43
Makefile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Tyler Perkins
|
||||||
|
# 7-21-21
|
||||||
|
# Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
CC = g++
|
||||||
|
|
||||||
|
FLAGS = -pipe
|
||||||
|
|
||||||
|
CFLAGS = -Wall
|
||||||
|
CFLAGS += -Ofast
|
||||||
|
#CFLAGS += -g
|
||||||
|
CFLAGS += -pg
|
||||||
|
|
||||||
|
LIBRARIES =
|
||||||
|
|
||||||
|
SRC = $(shell find . -name '*.cpp')
|
||||||
|
HPP = $(shell find . -name '*.hpp')
|
||||||
|
OBJ = $(subst .cpp,.o,$(SRC))
|
||||||
|
BIN = ./bin
|
||||||
|
|
||||||
|
TARGET = lrucache-test.out
|
||||||
|
|
||||||
|
all : $(BIN)/$(TARGET)
|
||||||
|
|
||||||
|
$(BIN)/$(TARGET) : $(OBJ)
|
||||||
|
@echo LD $(TARGET)
|
||||||
|
@$(CC) $(FLAGS) $(CFLAGS) -o $(BIN)/$(TARGET) $(OBJ) $(LIBRARIES)
|
||||||
|
|
||||||
|
.cpp.o :
|
||||||
|
@echo CC $<
|
||||||
|
@$(CC) $(FLAGS) $(CFLAGS) $(LIBRARIES) -c $< -o $@ -D_LRU_DEBUG_
|
||||||
|
|
||||||
|
clean :
|
||||||
|
find . -type f -name '*.o' -delete
|
||||||
|
rm -rf $(TARGET) performance.prof gmon.out
|
||||||
|
|
||||||
|
sanity : $(BIN)/$(TARGET)
|
||||||
|
$(BIN)/$(TARGET)
|
||||||
|
|
||||||
|
profile: sanity
|
||||||
|
gprof $(BIN)/$(TARGET) > performance.prof
|
104
README.md
Normal file
104
README.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
LRUCache
|
||||||
|
========
|
||||||
|
|
||||||
|
This is my implementation of a LRU (Least Recently Used) Cache.
|
||||||
|
The cache will store values and keep track of what was accessed most recently.
|
||||||
|
This is great to help reduce the amount of repetitive malloc calls, for
|
||||||
|
example.
|
||||||
|
|
||||||
|
This implementation differs from most in that:
|
||||||
|
|
||||||
|
1. It is associate
|
||||||
|
2. Get always returns a value
|
||||||
|
|
||||||
|
The big use for me was get() creating values. If a value is not found in the
|
||||||
|
cache, it creates the value T(Key) and returns that. This does not have to be
|
||||||
|
used, however, if you only use get() on values you are positive have been put()
|
||||||
|
into the cache.
|
||||||
|
|
||||||
|
To use this in a project, just copy lru.hpp into your own projects source tree.
|
||||||
|
The namespace it uses is clortox
|
||||||
|
|
||||||
|
Run tests
|
||||||
|
=========
|
||||||
|
|
||||||
|
You can run the test suite with the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make sanity
|
||||||
|
|
||||||
|
# Relies on gprof
|
||||||
|
make profile
|
||||||
|
```
|
||||||
|
|
||||||
|
Interface
|
||||||
|
=========
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
```
|
||||||
|
LRUCache()
|
||||||
|
LRUCache(size_t max_size)
|
||||||
|
```
|
||||||
|
|
||||||
|
Defaults size of cache to 50
|
||||||
|
|
||||||
|
Utility
|
||||||
|
-------
|
||||||
|
|
||||||
|
```
|
||||||
|
void clear()
|
||||||
|
```
|
||||||
|
|
||||||
|
Clears out the contents of the cache
|
||||||
|
|
||||||
|
```
|
||||||
|
bool empty() const
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns true if the cache is empty
|
||||||
|
|
||||||
|
```
|
||||||
|
bool full() const
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns true if the cache is full
|
||||||
|
|
||||||
|
```
|
||||||
|
size_t getMaxCacheSize() const
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the cache size, passed as `max_size` when constructing
|
||||||
|
|
||||||
|
Accessors
|
||||||
|
--------
|
||||||
|
|
||||||
|
```
|
||||||
|
T& get(const Key&)
|
||||||
|
T& operator[](const Key&)
|
||||||
|
T& operator[](Key&)
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns T associated with Key. If none exists, creates T(key), inserts it into
|
||||||
|
the cache, and returns a reference to it
|
||||||
|
|
||||||
|
```
|
||||||
|
void put(const Key&, const T&)
|
||||||
|
```
|
||||||
|
|
||||||
|
Places (Key, T) into the cache as the most recent item
|
||||||
|
|
||||||
|
```
|
||||||
|
bool erase(const Key&)
|
||||||
|
```
|
||||||
|
|
||||||
|
Erases element associated with Key. Use this if you know that item is not
|
||||||
|
likely to accessed soon and would like to delete ahead of time
|
||||||
|
|
||||||
|
```
|
||||||
|
void pop_back()
|
||||||
|
```
|
||||||
|
|
||||||
|
Removes oldest element from the cache. Can be used, however is more often used
|
||||||
|
internally
|
0
bin/.gitkeep
Normal file
0
bin/.gitkeep
Normal file
272
src/lru/lru.hpp
Normal file
272
src/lru/lru.hpp
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tyler Perkins
|
||||||
|
// 8-23-21
|
||||||
|
// LRU cache implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef _LRUCACHE_HPP_
|
||||||
|
#define _LRUCACHE_HPP_
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace clortox {
|
||||||
|
constexpr size_t __default_max_cache_size = 50;
|
||||||
|
|
||||||
|
|
||||||
|
template<class Key, class T>
|
||||||
|
struct value_iterator {
|
||||||
|
typename std::list<Key>::iterator it;
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Key, class T, class Hash = std::hash<Key>>
|
||||||
|
class LRUCache{
|
||||||
|
public:
|
||||||
|
LRUCache();
|
||||||
|
LRUCache(size_t);
|
||||||
|
~LRUCache();
|
||||||
|
LRUCache(const LRUCache&);
|
||||||
|
LRUCache& operator=(const LRUCache&);
|
||||||
|
|
||||||
|
void swap(LRUCache&);
|
||||||
|
|
||||||
|
//utility
|
||||||
|
void clear ();
|
||||||
|
inline bool empty () const;
|
||||||
|
inline bool full () const;
|
||||||
|
inline size_t getMaxCacheSize() const;
|
||||||
|
|
||||||
|
//accessors functions
|
||||||
|
T& get (const Key&);
|
||||||
|
inline T& operator[](const Key&);
|
||||||
|
inline T& operator[](Key&);
|
||||||
|
void put (const Key&, const T&);
|
||||||
|
bool erase (const Key&);
|
||||||
|
void pop_back ();
|
||||||
|
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
bool wasHit = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
//list
|
||||||
|
std::list<Key> _list;
|
||||||
|
//hashmap
|
||||||
|
std::unordered_map<Key, value_iterator<Key, T>, Hash> _hash_map;
|
||||||
|
|
||||||
|
size_t _max_cache_size;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Implementation /////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Default Ctor
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
clortox::LRUCache<Key, T, Hash>::LRUCache()
|
||||||
|
: LRUCache(__default_max_cache_size) {};
|
||||||
|
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
clortox::LRUCache<Key, T, Hash>::LRUCache(
|
||||||
|
size_t max_size) : _max_cache_size(max_size){
|
||||||
|
|
||||||
|
_hash_map.reserve(max_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Dector
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
clortox::LRUCache<Key, T, Hash>::~LRUCache(){
|
||||||
|
while(!empty()){
|
||||||
|
pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Copy ctor
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
clortox::LRUCache<Key, T, Hash>::LRUCache(const LRUCache& rhs){
|
||||||
|
_max_cache_size = rhs._max_cache_size;
|
||||||
|
_hash_map = rhs._hash_map;
|
||||||
|
_list = rhs._list;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Assignment operator
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
clortox::LRUCache<Key, T, Hash>& clortox::LRUCache<
|
||||||
|
Key, T, Hash>::operator=(const LRUCache& rhs){
|
||||||
|
|
||||||
|
if(this != &rhs){
|
||||||
|
_max_cache_size = rhs._max_cache_size;
|
||||||
|
_hash_map = rhs._hash_map;
|
||||||
|
_list = rhs._list;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Swap function
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
void clortox::LRUCache<Key, T, Hash>::swap(LRUCache& rhs){
|
||||||
|
decltype(_hash_map) tmphashmap = rhs._hash_map;
|
||||||
|
rhs._hash_map = _hash_map;
|
||||||
|
_hash_map = tmphashmap;
|
||||||
|
|
||||||
|
decltype(_list) tmplist = rhs._list;
|
||||||
|
rhs._list = _list;
|
||||||
|
_list = tmplist;
|
||||||
|
|
||||||
|
decltype(_max_cache_size) tmpmax = rhs._max_cache_size;
|
||||||
|
rhs._max_cache_size = _max_cache_size;
|
||||||
|
_max_cache_size = tmpmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Clears out all elements from cache
|
||||||
|
// This should only be called if all
|
||||||
|
// elements in the cache are not likely
|
||||||
|
// to be used again
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
void clortox::LRUCache<Key, T, Hash>::clear(){
|
||||||
|
for(auto it = _hash_map.begin(); it != _hash_map.end();){
|
||||||
|
_list.erase(it->second.it);
|
||||||
|
it = _hash_map.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Returns true if the cache is empty
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
bool clortox::LRUCache<Key, T, Hash>::empty() const{
|
||||||
|
return _list.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Check if cache is full
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
bool clortox::LRUCache<Key, T, Hash>::full() const{
|
||||||
|
return _list.size() == _max_cache_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Returns the max cache size
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
size_t clortox::LRUCache<Key, T, Hash>::getMaxCacheSize() const{
|
||||||
|
return _max_cache_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor functions /////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// get element from cache. If it does
|
||||||
|
// not exist, create it
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
T& clortox::LRUCache<Key, T, Hash>::get(const Key& key){
|
||||||
|
if(_hash_map.find(key) != _hash_map.end()){ //cache hit
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
wasHit = true;
|
||||||
|
#endif
|
||||||
|
//update list
|
||||||
|
_list.erase(_hash_map[key].it);
|
||||||
|
_list.push_front(key);
|
||||||
|
_hash_map[key].it = _list.begin();
|
||||||
|
|
||||||
|
return _hash_map[key].value;
|
||||||
|
} else { //cache miss
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
wasHit = false;
|
||||||
|
#endif
|
||||||
|
//if cache is full, remove oldest element
|
||||||
|
if(_list.size() == _max_cache_size){
|
||||||
|
_hash_map.erase(_list.back());
|
||||||
|
_list.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
//add new element
|
||||||
|
_list.push_front(key);
|
||||||
|
|
||||||
|
_hash_map[key] = { .it = _list.begin(), .value = T(key) };
|
||||||
|
return _hash_map[key].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Index operator returns value with
|
||||||
|
// assoc key. If it does not exist, we
|
||||||
|
// create it
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
T& clortox::LRUCache<Key, T, Hash>::operator[](const Key& key){
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
T& clortox::LRUCache<Key, T, Hash>::operator[](Key& key){
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Puts the key value pair into the
|
||||||
|
// cache
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
void clortox::LRUCache<Key, T, Hash>::put(const Key& key, const T& value){
|
||||||
|
if(_hash_map.find(key) != _hash_map.end()){ //cache hit
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
wasHit = true;
|
||||||
|
#endif
|
||||||
|
//update list
|
||||||
|
_list.erase(_hash_map[key].it);
|
||||||
|
_list.push_front(key);
|
||||||
|
_hash_map[key].it = _list.begin();
|
||||||
|
|
||||||
|
_hash_map[key].value = value;
|
||||||
|
} else { //cache hit, insert new element
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
wasHit = false;
|
||||||
|
#endif
|
||||||
|
//if cache is full, remove oldest element
|
||||||
|
if(_list.size() == _max_cache_size){
|
||||||
|
_hash_map.erase(_list.back());
|
||||||
|
_list.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
//add new element
|
||||||
|
_list.push_front(key);
|
||||||
|
_hash_map[key] = { .it = _list.begin(), .value = value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Remove element from cache. Only do
|
||||||
|
// this if positive it will not be
|
||||||
|
// referenced again
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
bool clortox::LRUCache<Key, T, Hash>::erase(const Key& key){
|
||||||
|
if(_hash_map.find(key) != _hash_map.end()){ //cache hit
|
||||||
|
//remove element
|
||||||
|
_list.erase(_hash_map[key].it);
|
||||||
|
_hash_map.erase(key);
|
||||||
|
return true;
|
||||||
|
} //not in cache, return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Remove oldest element
|
||||||
|
template<class Key, class T, class Hash>
|
||||||
|
void clortox::LRUCache<Key, T, Hash>::pop_back(){
|
||||||
|
if(!_list.empty()){
|
||||||
|
_hash_map.erase(_list.back());
|
||||||
|
_list.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //!_LRUCACHE_HPP_
|
172
src/main.cpp
Normal file
172
src/main.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tyler Perkins
|
||||||
|
// 8-23-21
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "lru/lru.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using clortox::LRUCache;
|
||||||
|
|
||||||
|
class arr{
|
||||||
|
public:
|
||||||
|
arr() { ptr = nullptr; };
|
||||||
|
arr(int size){
|
||||||
|
ptr = new int[size];
|
||||||
|
for(int i = 0; i < size; ++i)
|
||||||
|
ptr[i] = i;
|
||||||
|
}
|
||||||
|
~arr(){ delete[] ptr; };
|
||||||
|
int get(int index) const { return ptr[index]; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
int* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv){
|
||||||
|
std::cout << "===== LRUCache Tests =====" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing if cannonical..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, char> cache;
|
||||||
|
assert(cache.getMaxCacheSize() == clortox::__default_max_cache_size);
|
||||||
|
assert(cache.empty());
|
||||||
|
|
||||||
|
LRUCache<int, char> ccache(25);
|
||||||
|
assert(ccache.getMaxCacheSize() == 25);
|
||||||
|
|
||||||
|
LRUCache<int, char> dcache(ccache);
|
||||||
|
assert(dcache.getMaxCacheSize() == 25);
|
||||||
|
|
||||||
|
ccache = cache;
|
||||||
|
assert(ccache.getMaxCacheSize() == clortox::__default_max_cache_size);
|
||||||
|
|
||||||
|
ccache.swap(dcache);
|
||||||
|
assert(ccache.getMaxCacheSize() == 25);
|
||||||
|
assert(dcache.getMaxCacheSize() == clortox::__default_max_cache_size);
|
||||||
|
}
|
||||||
|
std::cout << "Testing if cannonical passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing put functions..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, char> cache(5);
|
||||||
|
cache.put(1, 'a');
|
||||||
|
cache.put(26, 'z');
|
||||||
|
cache.put(10, 'j');
|
||||||
|
cache.put(3, 'b');
|
||||||
|
|
||||||
|
assert(cache.get(26) == 'z');
|
||||||
|
cache.put(10, 'j');
|
||||||
|
assert(cache.get(10) == 'j');
|
||||||
|
cache.put(2, 'b');
|
||||||
|
assert(cache.get(2) == 'b');
|
||||||
|
|
||||||
|
cache.put(1, 'a');
|
||||||
|
assert(cache.get(1) == 'a');
|
||||||
|
|
||||||
|
}
|
||||||
|
std::cout << "Testing put functions passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing get functions with custom types..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, arr> cache(3);
|
||||||
|
assert(cache.get(5).get(3) == 3);
|
||||||
|
assert(cache.get(6).get(5) == 5);
|
||||||
|
assert(cache.get(10).get(7) == 7);
|
||||||
|
//cache hit
|
||||||
|
assert(cache.get(6).get(5) == 5);
|
||||||
|
|
||||||
|
//drop last element of cache
|
||||||
|
assert(cache.get(2).get(1) == 1);
|
||||||
|
}
|
||||||
|
std::cout << "Testing get functions with custom types passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing operator[] with custom types..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, arr> cache(3);
|
||||||
|
assert(cache[5].get(3) == 3);
|
||||||
|
assert(cache[6].get(5) == 5);
|
||||||
|
assert(cache[10].get(7) == 7);
|
||||||
|
//cache hit
|
||||||
|
assert(cache[6].get(5) == 5);
|
||||||
|
|
||||||
|
//drop last element of cache
|
||||||
|
assert(cache[2].get(1) == 1);
|
||||||
|
}
|
||||||
|
std::cout << "Testing operator[] with custom passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing erase function..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, char> cache(5);
|
||||||
|
cache.put(1, 'a');
|
||||||
|
cache.put(2, 'b');
|
||||||
|
cache.put(3, 'c');
|
||||||
|
cache.put(4, 'd');
|
||||||
|
cache.put(5, 'e');
|
||||||
|
|
||||||
|
assert(cache.full() == true);
|
||||||
|
|
||||||
|
assert(cache.erase(26) == false);
|
||||||
|
|
||||||
|
assert(cache.erase(1) == true);
|
||||||
|
|
||||||
|
assert(cache.full() == false);
|
||||||
|
}
|
||||||
|
std::cout << "Testing erase function passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Testing pop_back..." << std::endl;
|
||||||
|
{
|
||||||
|
LRUCache<int, char> cache(5);
|
||||||
|
cache.put(1, 'a');
|
||||||
|
cache.put(2, 'b');
|
||||||
|
cache.put(3, 'c');
|
||||||
|
cache.put(4, 'd');
|
||||||
|
cache.put(5, 'e');
|
||||||
|
|
||||||
|
assert(cache.full() == true);
|
||||||
|
|
||||||
|
cache.pop_back();
|
||||||
|
|
||||||
|
assert(cache.full() == false);
|
||||||
|
|
||||||
|
}
|
||||||
|
std::cout << "Testing pop_back passed!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Performance testing..." << std::endl;
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
size_t hits = 0;
|
||||||
|
|
||||||
|
std::cout << "Cache size : 1000\n";
|
||||||
|
std::cout << "Range of elements : 10000\n";
|
||||||
|
std::cout << "Iterations : 1000000\n";
|
||||||
|
|
||||||
|
LRUCache<int, arr> cache(1000);
|
||||||
|
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
for(size_t i = 0; i < 1000000; ++i){
|
||||||
|
cache.get(rand() % 10000 + 1);
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
if(cache.wasHit)
|
||||||
|
hits++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
std::cout << "Running time: " <<
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count()
|
||||||
|
<< " milliseconds" << std::endl;
|
||||||
|
#ifdef _LRU_DEBUG_
|
||||||
|
std::cout << "Cache hits: " << hits << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
std::cout << "Performance testing finished!" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "===== LRUCache Tests =====" << std::endl;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user