Finish Memory boiler plate
This commit is contained in:
parent
2cfd43e2d7
commit
102ba39a6d
2
Makefile
2
Makefile
@ -10,7 +10,7 @@ FLAGS = -pipe
|
||||
|
||||
CFLAGS = -Wall
|
||||
CFLAGS += -Ofast
|
||||
CFLAGS += -std=c++17
|
||||
CFLAGS += -std=c++20
|
||||
#CFLAGS += -g
|
||||
#CFLAGS += -pg
|
||||
|
||||
|
@ -13,6 +13,7 @@ Features/TODO
|
||||
- Display who is home
|
||||
- Display network speed
|
||||
- Display plex currently playing
|
||||
- Play audio files (background music/tracks)?
|
||||
|
||||
Depends on
|
||||
==========
|
||||
|
371
src/board.cpp
Normal file
371
src/board.cpp
Normal file
@ -0,0 +1,371 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Tyler Perkins
|
||||
// 8-23-21
|
||||
// Board implementation
|
||||
//
|
||||
|
||||
#include "board.hpp"
|
||||
|
||||
using namespace dashboard;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Structs ////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t font_and_size_hash::operator()(const font_and_size& value) const{
|
||||
size_t hlhs = std::hash<std::string>{}(value._font);
|
||||
size_t hrhs = std::hash<size_t>{}(value._ptsize);
|
||||
|
||||
hlhs ^= hrhs + 0x9e3779b9 + (hlhs << 6) + (hlhs >> 2);
|
||||
return hlhs;
|
||||
}
|
||||
|
||||
size_t string_and_font_hash::operator()(const string_and_font& value) const {
|
||||
size_t hlhs = std::hash<std::string>{}(value._string);
|
||||
size_t hrhs = font_and_size_hash{}(value._fs);
|
||||
|
||||
hlhs ^= hrhs + 0x9e3779b9 + (hlhs << 6) + (hlhs >> 2);
|
||||
return hlhs;
|
||||
}
|
||||
|
||||
bool font_and_size::operator==(const font_and_size& rhs) const{
|
||||
if(this->_font == rhs._font && this->_ptsize == rhs._ptsize)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool font_and_size::operator!=(const font_and_size& rhs) const{
|
||||
if(this->_font == rhs._font && this->_ptsize == rhs._ptsize)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool font_and_size::operator> (const font_and_size& rhs) const{
|
||||
if(this->_font > rhs._font)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool font_and_size::operator< (const font_and_size& rhs) const{
|
||||
if(this->_font < rhs._font)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool font_and_size::operator>=(const font_and_size& rhs) const{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
bool font_and_size::operator<=(const font_and_size& rhs) const{
|
||||
return !(*this > rhs);
|
||||
}
|
||||
|
||||
bool string_and_font::operator==(const string_and_font& rhs) const{
|
||||
if(this->_string == rhs._string && this->_fs == rhs._fs)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool string_and_font::operator!=(const string_and_font& rhs) const{
|
||||
if(this->_string == rhs._string && this->_fs == rhs._fs)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool string_and_font::operator> (const string_and_font& rhs) const{
|
||||
if(this->_string > rhs._string)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool string_and_font::operator< (const string_and_font& rhs) const{
|
||||
if(this->_string < rhs._string)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool string_and_font::operator>=(const string_and_font& rhs) const{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
bool string_and_font::operator<=(const string_and_font& rhs) const{
|
||||
return !(*this > rhs);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SDL_Texture_Wrapper ////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SDL_Texture_Wrapper::SDL_Texture_Wrapper(){
|
||||
_texture = nullptr;
|
||||
}
|
||||
|
||||
SDL_Texture_Wrapper::~SDL_Texture_Wrapper(){
|
||||
if(_texture != nullptr)
|
||||
SDL_DestroyTexture(_texture);
|
||||
}
|
||||
|
||||
SDL_Texture_Wrapper::SDL_Texture_Wrapper(const std::string& text, const font_and_size& fs){
|
||||
SDL_Surface* tmpSurface;
|
||||
|
||||
TTF_Font* fs_font = board::getFont(fs);
|
||||
|
||||
tmpSurface = TTF_RenderText_Solid(fs_font, text.c_str(),
|
||||
{ BOARD_RED, BOARD_GREEN, BOARD_BLUE });
|
||||
|
||||
if(tmpSurface == NULL){
|
||||
SDL_Log("SDL_Texture_Wrapper: Failed to create surface from string (%s): %s\n",
|
||||
text.c_str(), SDL_GetError());
|
||||
_texture = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
_texture = SDL_CreateTextureFromSurface(board::getRenderer(), tmpSurface);
|
||||
|
||||
if(_texture == NULL){
|
||||
SDL_Log("SDL_Texture_Wrapper: failed to create texture from surface of string (%s): %s\n",
|
||||
text.c_str(), SDL_GetError());
|
||||
SDL_FreeSurface(tmpSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
//texture was created sucessfully, cleanup surface
|
||||
|
||||
SDL_FreeSurface(tmpSurface);
|
||||
SDL_UnlockTexture(_texture);
|
||||
}
|
||||
|
||||
SDL_Texture_Wrapper::SDL_Texture_Wrapper(const string_and_font& sf)
|
||||
: SDL_Texture_Wrapper(sf._string, sf._fs) {};
|
||||
|
||||
SDL_Texture_Wrapper::SDL_Texture_Wrapper(const texture_path& path){
|
||||
SDL_Surface* tmpSurface;
|
||||
|
||||
tmpSurface = IMG_Load(path.c_str());
|
||||
|
||||
if(tmpSurface == NULL){
|
||||
SDL_Log("SDL_Texture_Wrapper: failed to load image (%s): %s\n",
|
||||
path.c_str(), SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
_texture = SDL_CreateTextureFromSurface(board::getRenderer(), tmpSurface);
|
||||
|
||||
if(_texture == NULL){
|
||||
SDL_Log("SDL_Texture_Wrapper: failed to create texture from surface of image (%s): %s\n",
|
||||
path.c_str(), SDL_GetError());
|
||||
SDL_FreeSurface(tmpSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
//texture was created sucessfully, cleanup surface
|
||||
|
||||
SDL_FreeSurface(tmpSurface);
|
||||
SDL_UnlockTexture(_texture);
|
||||
}
|
||||
|
||||
SDL_Texture* SDL_Texture_Wrapper::texture() const {
|
||||
return _texture;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SDL_Font_Wrapper ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SDL_Font_Wrapper::SDL_Font_Wrapper(){
|
||||
_font = nullptr;
|
||||
}
|
||||
|
||||
SDL_Font_Wrapper::~SDL_Font_Wrapper(){
|
||||
if(_font != nullptr)
|
||||
TTF_CloseFont(_font);
|
||||
}
|
||||
|
||||
SDL_Font_Wrapper::SDL_Font_Wrapper(const font_path& fp, const size_t ptsize){
|
||||
_font = TTF_OpenFont(fp.c_str(), ptsize);
|
||||
|
||||
if(_font == NULL){
|
||||
SDL_Log("SDL_Font_Wrapper: Failed to open font (%s) with ptsize (%lu): %s\n",
|
||||
fp.c_str(), ptsize, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Font_Wrapper::SDL_Font_Wrapper(const font_and_size& fs){
|
||||
_font = TTF_OpenFont(fs._font.c_str(), fs._ptsize);
|
||||
|
||||
if(_font == NULL){
|
||||
SDL_Log("SDL_Font_Wrapper: Failed to open font (%s) with ptsize (%lu): %s\n",
|
||||
fs._font.c_str(), fs._ptsize, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TTF_Font* SDL_Font_Wrapper::font() const {
|
||||
return _font;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Static functions ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SDL_Window* board::getWindow(){
|
||||
static SDL_Window* _window = nullptr;
|
||||
|
||||
if(_window == nullptr){
|
||||
_window = SDL_CreateWindow(WINDOW_TITLE,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SCREEN_WIDTH, SCREEN_HEIGHT,
|
||||
SDL_WINDOW_FLAGS);
|
||||
|
||||
if(_window == NULL)
|
||||
SDL_Log("Window could not be created, %s\n", SDL_GetError());
|
||||
}
|
||||
return _window;
|
||||
}
|
||||
|
||||
SDL_Renderer* board::getRenderer(){
|
||||
static SDL_Renderer* _renderer = nullptr;
|
||||
|
||||
if(_renderer == nullptr){
|
||||
_renderer = SDL_CreateRenderer(board::getWindow(), -1,
|
||||
SDL_RENDERER_ACCELERATED);
|
||||
|
||||
if(_renderer == NULL)
|
||||
SDL_Log("Renderer could not be created, %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
return _renderer;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors ///////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
board::board(const bool init = true){
|
||||
_window = nullptr;
|
||||
_renderer = nullptr;
|
||||
|
||||
if(init)
|
||||
this->init();
|
||||
}
|
||||
|
||||
board::~board(){
|
||||
if(_renderer != nullptr)
|
||||
SDL_DestroyRenderer(_renderer);
|
||||
|
||||
if(_window != nullptr)
|
||||
SDL_DestroyWindow(_window);
|
||||
|
||||
//allocated resources will be taken care of by the LRUCache
|
||||
|
||||
TTF_Quit();
|
||||
IMG_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
int board::init(){
|
||||
SDL_Log("Init SDL...\n");
|
||||
|
||||
//check if already has been init
|
||||
if(_window != NULL || _renderer != NULL){
|
||||
SDL_Log("Failed to init SDL: Already init\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//setup sdl
|
||||
if(SDL_Init(SDL_FLAGS) != 0){
|
||||
SDL_Log("Failed to init SDL: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
//create window
|
||||
_window = board::getWindow();
|
||||
if(_window == NULL){
|
||||
SDL_Log("Failed to init SDL; Window could not be created: %s\n",
|
||||
SDL_GetError());
|
||||
return -2;
|
||||
}
|
||||
|
||||
//create renderer
|
||||
_renderer = board::getRenderer();
|
||||
if(_renderer == NULL){
|
||||
SDL_Log("Failed to init SDL; Renderer could not be created: %s\n",
|
||||
SDL_GetError());
|
||||
return -3;
|
||||
}
|
||||
|
||||
//set cursor mode
|
||||
SDL_ShowCursor(SDL_SHOW_CURSOR);
|
||||
|
||||
|
||||
//enable alpha
|
||||
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
//init sdl_image
|
||||
if((IMG_Init(IMG_FLAGS) & IMG_FLAGS) != IMG_FLAGS){
|
||||
SDL_Log("Failed to init SDL; Failed to init SDL_Image: %s\n",
|
||||
IMG_GetError());
|
||||
return -4;
|
||||
}
|
||||
|
||||
//init sdl_ttf
|
||||
if(TTF_Init() == -1){
|
||||
SDL_Log("Failed to init SDL; Failed to init SDL_TTF: %s\n",
|
||||
TTF_GetError());
|
||||
return -5;
|
||||
}
|
||||
|
||||
SDL_Log("Sucessfully setup SDL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// This is called to start the main loop.
|
||||
// This is where most of the logic lives
|
||||
void board::start(){
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Functions ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SDL_Texture* board::getString(const std::string& text, const font_and_size& fs){
|
||||
//check for string in static strings, then check in dynamic strings
|
||||
|
||||
string_and_font sf = {text, fs};
|
||||
if(_strings.find(sf) != _strings.end())
|
||||
return _strings.find(sf)->second.texture();
|
||||
|
||||
//is dynamic string, generate:
|
||||
return _dynamic_strings.get(sf).texture();
|
||||
}
|
||||
|
||||
SDL_Texture* board::getImage(const std::string& path){
|
||||
if(_textures.find(path) != _textures.end())
|
||||
return _textures.find(path)->second.texture();
|
||||
|
||||
//TODO: Dynamic Images?
|
||||
//not found, return null
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TTF_Font* board::getFont(const font_and_size& fs){
|
||||
if(_fonts.find(fs) != _fonts.end())
|
||||
return _fonts.find(fs)->second.font();
|
||||
|
||||
//Dynamic Fonts? Is the needed?
|
||||
//not found, return null
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDL_Texture* board::setString(const std::string& text, const font_and_size& fs){
|
||||
string_and_font sf = {text, fs};
|
||||
_strings.insert_or_assign(sf, SDL_Texture_Wrapper(text, fs));
|
||||
return _strings[sf].texture();
|
||||
}
|
||||
|
||||
SDL_Texture* board::setImage(const std::string& path){
|
||||
_textures.insert_or_assign(path, SDL_Texture_Wrapper(path));
|
||||
return _textures[path].texture();
|
||||
}
|
||||
|
||||
TTF_Font* board::setFont(const font_and_size& fs){
|
||||
_fonts.insert_or_assign(fs, SDL_Font_Wrapper(fs));
|
||||
return _fonts[fs].font();
|
||||
}
|
135
src/board.hpp
Normal file
135
src/board.hpp
Normal file
@ -0,0 +1,135 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Tyler Perkins
|
||||
// 8-23-21
|
||||
// Board defintions
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
#include "util/lru.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
namespace dashboard {
|
||||
struct font_and_size {
|
||||
std::string _font;
|
||||
size_t _ptsize;
|
||||
|
||||
bool operator==(const font_and_size&) const;
|
||||
bool operator!=(const font_and_size&) const;
|
||||
bool operator> (const font_and_size&) const;
|
||||
bool operator< (const font_and_size&) const;
|
||||
bool operator>=(const font_and_size&) const;
|
||||
bool operator<=(const font_and_size&) const;
|
||||
|
||||
};
|
||||
|
||||
struct string_and_font {
|
||||
std::string _string;
|
||||
font_and_size _fs;
|
||||
|
||||
bool operator==(const string_and_font&) const;
|
||||
bool operator!=(const string_and_font&) const;
|
||||
bool operator> (const string_and_font&) const;
|
||||
bool operator< (const string_and_font&) const;
|
||||
bool operator>=(const string_and_font&) const;
|
||||
bool operator<=(const string_and_font&) const;
|
||||
};
|
||||
|
||||
struct font_and_size_hash {
|
||||
std::size_t operator()(const font_and_size&) const;
|
||||
};
|
||||
|
||||
struct string_and_font_hash {
|
||||
std::size_t operator()(const string_and_font&) const;
|
||||
};
|
||||
|
||||
typedef std::string texture_path;
|
||||
class SDL_Texture_Wrapper {
|
||||
public:
|
||||
SDL_Texture_Wrapper();
|
||||
~SDL_Texture_Wrapper();
|
||||
|
||||
SDL_Texture_Wrapper(const std::string&, const font_and_size&);
|
||||
SDL_Texture_Wrapper(const string_and_font&);
|
||||
|
||||
SDL_Texture_Wrapper(const texture_path&);
|
||||
|
||||
SDL_Texture* texture() const;
|
||||
|
||||
private:
|
||||
SDL_Texture* _texture;
|
||||
};
|
||||
|
||||
typedef std::string font_path;
|
||||
class SDL_Font_Wrapper {
|
||||
public:
|
||||
SDL_Font_Wrapper();
|
||||
~SDL_Font_Wrapper();
|
||||
|
||||
SDL_Font_Wrapper(const font_path&, const size_t);
|
||||
SDL_Font_Wrapper(const font_and_size&);
|
||||
|
||||
TTF_Font* font() const;
|
||||
|
||||
private:
|
||||
TTF_Font* _font;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class board {
|
||||
public:
|
||||
board(const bool = true);
|
||||
~board();
|
||||
|
||||
//sdl setup function
|
||||
int init();
|
||||
|
||||
//start main loop
|
||||
void start();
|
||||
|
||||
//globals
|
||||
inline static SDL_Window* getWindow();
|
||||
inline static SDL_Renderer* getRenderer();
|
||||
|
||||
//memory functions (also globals)
|
||||
//these are called by other objects to get their memory
|
||||
inline static SDL_Texture* getString(const std::string&, const font_and_size&);
|
||||
inline static SDL_Texture* getImage (const std::string&);
|
||||
inline static TTF_Font* getFont (const font_and_size&);
|
||||
|
||||
private:
|
||||
//setup memory management with
|
||||
//all const resrouces
|
||||
void initConstResources();
|
||||
|
||||
//setup static memory. These are run in initConstResources()
|
||||
SDL_Texture* setString(const std::string&, const font_and_size&);
|
||||
SDL_Texture* setImage (const std::string&);
|
||||
TTF_Font* setFont (const font_and_size&);
|
||||
|
||||
//containers for resources
|
||||
inline static std::unordered_map<std::string, SDL_Texture_Wrapper> _textures;
|
||||
inline static std::unordered_map<font_and_size,
|
||||
SDL_Font_Wrapper, font_and_size_hash> _fonts;
|
||||
inline static std::unordered_map<string_and_font, SDL_Texture_Wrapper,
|
||||
string_and_font_hash> _strings;
|
||||
|
||||
static clortox::LRUCache<string_and_font,
|
||||
SDL_Texture_Wrapper, string_and_font_hash> _dynamic_strings;
|
||||
|
||||
//TODO: Dynamic images?
|
||||
|
||||
//local pointers to the globals
|
||||
SDL_Window* _window;
|
||||
SDL_Renderer* _renderer;
|
||||
};
|
||||
}
|
@ -6,11 +6,13 @@
|
||||
|
||||
#include "config.hpp"
|
||||
#include "handler/handler.hpp"
|
||||
|
||||
#include "board.hpp"
|
||||
|
||||
int main(int argc, char** argv){
|
||||
dashboard::handlers::setHandlers();
|
||||
|
||||
dashboard::board _board;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
7
src/pannel/pannel.cpp
Normal file
7
src/pannel/pannel.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Tyler Perkins
|
||||
// 8-23-21
|
||||
// pannel implementation
|
||||
//
|
||||
|
||||
#include "pannel.hpp"
|
30
src/pannel/pannel.hpp
Normal file
30
src/pannel/pannel.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Tyler Perkins
|
||||
// 8-23-21
|
||||
// pannel definition
|
||||
//
|
||||
///////////////////////////////////////
|
||||
// Note:
|
||||
// This class is a pure virtual class. board has an array of these, and
|
||||
// each of them is a different page that will be shown. Whatever pannel is
|
||||
// set as pannel_border will not check its own time elapsed, and will be
|
||||
// displayed on top of all other pannels
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
namespace dashboard {
|
||||
class pannel {
|
||||
public:
|
||||
pannel() = default;
|
||||
~pannel() = default;
|
||||
|
||||
virtual void draw() = 0;
|
||||
|
||||
size_t _time_on_screen = 0;
|
||||
};
|
||||
}
|
272
src/util/lru.hpp
Normal file
272
src/util/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_
|
Loading…
Reference in New Issue
Block a user