• 一个带LRU的哈希缓存的实现


    在做三角网格文件转换的时候需要对从文件中读取的顶点坐标进行缓存,于是索性做了一个哈希缓存以提高访问效率,同时以LRU原则在缓存满的情况下清楚缓存中的单元。在hash表中我用了最简单的取摸的方法,由于原顶点有一个索引而且这种索引连续,所以取摸的方法已经可以达到平均散列。在处理碰撞的时候我使用了链表,而所有在缓存中的单元都按放入缓存的时间串成一个链表,这样在清除单元的时候选择队尾的元素进行清除即可。

    /*
        manipulations for the vertex binary file
        there is a least recent used hash cache
        for reading vertices
    
        the hash bucket with lru list is like this
    
        _____________        _____          _____
        |bucket_head| ---->  |   | -> .. -> |   | -> Null
        _____________        _____          _____
        |bucket_head| ---->  |   | -> .. -> |   | -> Null
        _____________        
        |bucket_head| ---->  Null
        
        ...
        _____________        _____          _____
        |bucket_head| ---->  |   | -> .. -> |   | -> Null
    
        while all the nodes in the buckets are linked
        based on the time they are accessed, thus the
        newly accessed node are inserted into the head
        of the lru list, if it has already existed in
        the list, it will be deleted from the list first
    
        author: waytofall
    */
    
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    class VertexBinary
    {
        typedef struct __Vertex
        {
            float x, y, z;
        } __Vertex;
    
        typedef struct __CacheUnit
        {
            struct __CacheUnit *bucket_prev; // bucket pointer
            struct __CacheUnit *bucket_next;
            struct __CacheUnit *use_prev; // lru pointer
             struct __CacheUnit *use_next;
            __Vertex vert;
            unsigned int index;
        } __CacheUnit;
    
    public:
        VertexBinary();
        ~VertexBinary();
    
        /* write */
        int openForWrite(const char* filename);
        int closeWriteFile();
        int writeVertexFloat(float x, float y, float z);
    
        /* read */
        int initCache(unsigned int size);
        int openForRead(const char* filename);
        int indexedRead(unsigned int index);
        int closeReadFile();
        float getXFloat();
        float getYFloat();
        float getZFloat();
    
        void writeCacheDebug();
    
    private:
        void insertBucketList(__CacheUnit **head, __CacheUnit *new_unit);
        void deleteBucketList(__CacheUnit **head, __CacheUnit *unit);
        void insertLruList(__CacheUnit *new_unit);
        void deleteLruList(__CacheUnit *unit);
        int indexedReadFromFile(unsigned int index, float &x, float &y, float &z);
    
    private:
        ifstream fin;
        ofstream fout;
        unsigned int cache_size;
        unsigned int cache_count;
        __CacheUnit **cache_bucket;
        __CacheUnit *lru_head;
        __CacheUnit *lru_tail;
        __CacheUnit *current_unit;
    
    public:
        unsigned int read_count;
        unsigned int hit_count;
    };
    /*
        manipulations for the vertex binary file
        author: waytofall
    */
    
    #include "vert_bin.h"
    #include <fstream>
    #include <iostream>
    
    // if dump the cache to the file
    //#define _WRITE_CACHE_DEBUG
    
    VertexBinary::VertexBinary()
    {
        cache_bucket = NULL;
        cache_size = 0;
        cache_count = 0;
    }
    
    VertexBinary::~VertexBinary()
    {
        if (cache_bucket)
        {
            delete[] cache_bucket;
        }
    }
    
    int VertexBinary::openForWrite(const char *filename)
    {
        fout.open(filename, ios::out | ios::binary);
    
        if(fout.good())
            return 1;
        else
            return 0;
    }
    
    int VertexBinary::writeVertexFloat(float x, float y, float z)
    {
        if (!fout.good())
        {
            return 0;
        }
    
        fout.write((char*)&x, sizeof(float));
        fout.write((char*)&y, sizeof(float));
        fout.write((char*)&z, sizeof(float));
    
        return 1;
    }
    
    int VertexBinary::openForRead(const char* filename)
    {
        fin.open(filename, ios::binary | ios::in);
        if (fin.good())
            return 1;
        else
            return 0;
    }
    
    int VertexBinary::indexedRead(unsigned int index)
    {
        if (cache_size <= 0)
        {
            cerr << "#error : no cache while indexed reading" << endl;
            return 0;
        }
        
        read_count ++;
    
        int hash_index = index % cache_size;
        __CacheUnit *hit_unit = NULL;
    
        // check if the cache hit
        if(cache_bucket[hash_index])
        {
            __CacheUnit *bucket_head;
            for(bucket_head = cache_bucket[hash_index]; bucket_head; bucket_head = bucket_head->bucket_next)
            {
                if (bucket_head->index == index)
                {
                    hit_unit = bucket_head;
                    break;
                }
            }
        }
    
        // the the cache has the queried unit
        if (hit_unit)
        {
            deleteLruList(hit_unit);
            insertLruList(hit_unit);
            current_unit = hit_unit;
            hit_count ++;
            return 1;
        }
    
        // the cache doesn't store the queried unit
    
        // check if needed to delete the least recent used unit
        if (cache_count == cache_size)
        {
            // delete the tail unit from the two lists
            hit_unit = lru_tail;
            deleteBucketList(&cache_bucket[hit_unit->index % cache_size], hit_unit);
            deleteLruList(hit_unit);
        }
        else
        {
            hit_unit =  new __CacheUnit();
            cache_count ++;
        }
    
        hit_unit->index = index;
        indexedReadFromFile(index, hit_unit->vert.x, hit_unit->vert.y, hit_unit->vert.z);
        insertBucketList(&cache_bucket[hash_index], hit_unit);
        insertLruList(hit_unit);
        current_unit = hit_unit;
    
        #ifdef _WRITE_CACHE_DEBUG
        writeCacheDebug();
        #endif
    
        return 1;
    }
    
    int VertexBinary::initCache(unsigned int size)
    {
        if(size <= 0)
            return 0;
    
        cache_size = size;
        cache_bucket = new __CacheUnit*[cache_size];
    
        for(unsigned int i = 0; i < cache_size; i ++)
        {
            cache_bucket[i] = NULL;
        }
    
        cache_count = 0;
        lru_head = NULL;
        lru_tail = NULL;
    
        read_count = 0; 
        hit_count = 0;
    
        return 1;
    }
    
    // insert from head
    void VertexBinary::insertBucketList(__CacheUnit **head, __CacheUnit *new_unit)
    {
        new_unit->bucket_prev = NULL;
        new_unit->bucket_next = *head;
        if (*head)
        {
            (*head)->bucket_prev = new_unit;
        }
        (*head) = new_unit;
    }
    
    // delete from any place
    void VertexBinary::deleteBucketList(__CacheUnit **head, __CacheUnit *unit)
    {
        if(*head == NULL)
            return;
    
        if(*head == unit)
        {
            *head = unit->bucket_next;
        }
        if (unit->bucket_prev)
        {
            unit->bucket_prev->bucket_next = unit->bucket_next;
        }
        if (unit->bucket_next)
        {
            unit->bucket_next->bucket_prev = unit->bucket_prev;
        }
    }
    
    void VertexBinary::insertLruList(__CacheUnit *new_unit)
    {
        new_unit->use_prev = NULL;
        new_unit->use_next = lru_head;
        if (lru_head)
        {
            lru_head->use_prev = new_unit;
        }
    
        if (lru_head == NULL)
        {
            lru_tail = new_unit;
        }
    
        lru_head = new_unit;
    }
    
    // delete the lru list from the tail
    void VertexBinary::deleteLruList(__CacheUnit *unit)
    {
        if (lru_head == NULL)
            return;
    
        if (unit->use_next)
        {
            unit->use_next->use_prev = unit->use_prev;
        }
        if (unit->use_prev)
        {
            unit->use_prev->use_next = unit->use_next;
        }
        
        if (lru_head == unit)
        {
            lru_head = unit->use_next;
        }
        if (lru_tail == unit)
        {
            lru_tail = unit->use_prev;
        }
    }
    
    int VertexBinary::indexedReadFromFile(unsigned int index, float &x, float &y, float &z)
    {
        if (!fin.good())
        {
            return 0;
        }
    
        fin.seekg(index * 3 * sizeof(float));
        fin.read((char*)&x, sizeof(float));
        fin.read((char*)&y, sizeof(float));
        fin.read((char*)&z, sizeof(float));
    
        return 1;
    }
    
    int VertexBinary::closeWriteFile()
    {
        fout.close();
    
        return 1;
    }
    
    int VertexBinary::closeReadFile()
    {
        fin.close();
    
        return 1;
    }
    
    float VertexBinary::getXFloat()
    {
        return current_unit->vert.x;
    }
    
    float VertexBinary::getYFloat()
    {
        return current_unit->vert.y;
    }
    
    float VertexBinary::getZFloat()
    {
        return current_unit->vert.z;
    }
    
    void VertexBinary::writeCacheDebug()
    {
        int i, c1, c2;
        using namespace std;
        ofstream fout ("cache_dump.txt", ios::out | ios::app);
        __CacheUnit *pUnit;
    
        for(i = 0, c1 = 0; i < cache_size; i ++)
        {
            if (cache_bucket[i] == NULL)
                continue;
    
            fout << "bucket #" << i << ": ";
            for(pUnit = cache_bucket[i], c2 = 0; pUnit; pUnit = pUnit->bucket_next, c2 ++)
            {
                fout << pUnit->index << " ";
            }
            fout << "count: " << c2 << " " << endl;
            c1 += c2;
        }
    
        fout << "total count: " << c1 << endl << "lru list: ";
        for(c1 = 0, pUnit = lru_head; pUnit; pUnit = pUnit->use_next, c1 ++)
        {
            fout << pUnit->index << " ";
        }
    
        fout << endl << "lru count: " << c1 << endl << endl;
    
        fout.close();
    }

    一个大小为20的cache的打印结果

    bucket #0: 420 count: 1 
    bucket #1: 421 261 301 count: 3 
    bucket #2: 422 count: 1 
    bucket #5: 425 count: 1 
    bucket #6: 306 446 386 count: 3 
    bucket #8: 368 448 count: 2 
    bucket #9: 409 count: 1 
    bucket #10: 410 390 count: 2 
    bucket #11: 411 count: 1 
    bucket #12: 412 count: 1 
    bucket #14: 434 count: 1 
    bucket #16: 436 count: 1 
    bucket #17: 297 count: 1 
    bucket #19: 259 count: 1 
    total count: 20
    lru list: 412 306 409 368 410 422 420 421 436 434 259 261 446 448 411 386 390 297 425 301 
    lru count: 20



    ____________________________
    本博客文章主要供博主学习交流用,所有描述、代码无法保证准确性,如有问题可以留言共同讨论。
  • 相关阅读:
    11.分类与监督学习,朴素贝叶斯分类算法
    14 深度学习-卷积
    13-垃圾邮件分类2
    12.朴素贝叶斯-垃圾邮件分类
    9、主成分分析
    8、特征选择
    7.逻辑回归实践
    6.逻辑归回
    5.线性回归算法
    15 手写数字识别-小数据集
  • 原文地址:https://www.cnblogs.com/waytofall/p/2532536.html
Copyright © 2020-2023  润新知