#pragma once
#include "common.cuh"

namespace gpucache {
    struct CacheConfig {
        enum CacheEvictStrategy {
            FIFO,
            LRU,
            LFU
        };
        CacheEvictStrategy strategy;
        uint64_t capacity;
        uint32_t keySize;
        uint32_t valueSize;
        uint32_t maxQueryNum;
    };


// Cache Interface
    template<typename KeyType, typename ElemType>
    class Cache {
    public:
        // using Strategy = CacheConfig::CacheEvictStrategy;

        Cache() = default;

        virtual ~Cache() = default;


//        Cache(const Cache &) = delete;
//
//        Cache &operator=(const Cache &) = delete;
//
//        Cache(Cache &&) = delete;
//
//        Cache &operator=(Cache &&) = delete;

        virtual uint32_t KeySize() = 0;

        virtual uint32_t ValueSize() = 0;

        virtual CacheConfig::CacheEvictStrategy Strategy() = 0;

        virtual uint64_t Capacity() = 0;

        virtual uint32_t NumElemsPerValue() = 0;

        virtual void Get(cudaStream_t *stream, uint32_t num_keys, KeyType *keys, ElemType *values, bool* find_mask) = 0;

        virtual void Put(cudaStream_t *stream, uint32_t num_keys, KeyType *keys, ElemType *values,uint32_t *n_evict, KeyType* evict_keys) = 0;


        virtual void* Mutex() = 0;

        virtual void Clear() = 0;

        virtual uint32_t MaxQueryNum() = 0;
    };


// TODO: 添加其他种类的cache
    template<typename KeyType, typename ElemType > class LRUCache;

    template<typename KeyType, typename ElemType>
    std::unique_ptr<Cache<KeyType, ElemType>> NewLRUCache(const CacheConfig &cfg) {
        assert(cfg.keySize > 0);
        assert(cfg.valueSize > 0);
        assert(cfg.capacity > 0);
        return nullptr;
    }


//    template<typename KeyType, typename ElemType>
//    std::unique_ptr<>
}
