Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible Solution #23

Open
JimChengLin opened this issue Apr 25, 2018 · 1 comment
Open

Possible Solution #23

JimChengLin opened this issue Apr 25, 2018 · 1 comment

Comments

@JimChengLin
Copy link

JimChengLin commented Apr 25, 2018

Thanks for the simple and efficient implementation!
Here is my solution based on your work.

#pragma once
#ifndef LEVIDB_LRU_CACHE_H
#define LEVIDB_LRU_CACHE_H

/*
 * Original File:   lrucache.hpp
 * Original Author: Alexander Ponomarev
 */

#include <list>
#include <unordered_map>
#include <utility>

namespace levidb {
    template<typename K, typename V, size_t MAX>
    class LRUCache {
    private:
        typedef typename std::pair<K, V> key_value_pair_t;
        typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;

        std::list<key_value_pair_t> cache_items_list_;
        std::unordered_map<K, list_iterator_t> cache_items_map_;

    public:
        template<typename T>
        void Add(const K & k, T && v) {
            auto it = cache_items_map_.find(k);
            if (it == cache_items_map_.end()) {
                if (size() >= MAX) {
                    auto last = cache_items_list_.end();
                    --last;
#if defined(__cpp_lib_node_extract)
                    auto nh = cache_items_map_.extract(last->first);
                    nh.key() = k;
                    cache_items_map_.insert(std::move(nh));

                    last->first = k;
                    last->second = std::forward<T>(v);
                    cache_items_list_.splice(cache_items_list_.begin(), cache_items_list_, last);
                    return;
#else
                    cache_items_map_.erase(last->first);
                    cache_items_list_.pop_back();
#endif
                }
                cache_items_list_.emplace_front(k, std::forward<T>(v));
                cache_items_map_[k] = cache_items_list_.begin();
            } else {
                it->second->second = std::forward<T>(v);
                cache_items_list_.splice(cache_items_list_.begin(), cache_items_list_, it->second);
            }
        }

        bool Get(const K & k, V * v) const {
            auto it = cache_items_map_.find(k);
            if (it == cache_items_map_.cend()) {
                return false;
            } else {
                const_cast<LRUCache *>(this)->
                        cache_items_list_.splice(cache_items_list_.begin(), cache_items_list_, it->second);
                *v = it->second->second;
                return true;
            }
        }

        bool Exists(const K & k) const {
            return cache_items_map_.find(k) != cache_items_map_.cend();
        }

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

#endif //LEVIDB_LRU_CACHE_H
@JimChengLin
Copy link
Author

JimChengLin commented Apr 25, 2018

Sorry for the different code style...

I am used to Google(except exception, etc.)/Facebook cpp code style. It is hard to make me accept "_" prefixed private class member names instead of "_" suffixed ones. XD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant