C ++缓存设计建议 [英] C++ Cache Design Advice

查看:125
本文介绍了C ++缓存设计建议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个c ++应用程序与几种图像类型(RGB,灰色...),每个类型都有属性,如旋转或缩放。每个图像类型都是通过其他类型的计算生成的。例如,通过旋转 GrayImage 产生A旋转的 GrayImage ,GrayImage c $ c> RGBImage 。



我想设计一个带有 GetX ,它缓存各种图像(以及可能的计算路径中的所有图像)。



这个类必须满足一些约束:


  1. 由于我们处理不同类型和表示的图像(RGB,GrayScale等),所以缓存必须为调用代码返回一个具体类能够使用它没有某种铸造。因此,高速缓存机制必须保持包含具体类型的不同高速缓存结构。 (修复我,如果我错了这里)

     地图< ...,RGBImage> 
    map< ...,GrayImage>


  2. 缓存必须能灵活适应图像计算的变化。


当前版本我附加了一个结构到每个图像类型。
GrayKey RGBKey 等。各种键保持诸如缩放和旋转的属性,并且可以具有特定于图像的属性(例如,用于 GrayKey 的toGrayConvertingMethod)。
缓存保存以下形式的地图:

  map< XKey,XImage& 

GetX a Key struct作为参数,例如请求旋转的GrayImage。
虽然,这个实现强制缓存应用大量的逻辑计算图像。它必须检查GrayKey是否请求旋转的图像,并相应地执行操作。
我想以更优雅的方式编码这个图像计算关系,但似乎找不到一个。



任何建议? >

非常感谢。

解决方案

也许你可以使用 Boost.MultiIndex container?它将允许您创建一个类型来存储图像数据,以及如何操作的细节,然后根据您想要的键的任何组合查找值。如果你以前没有使用它,它可能看起来有点令人生畏,但我附上一个例子下面。



显然,我的例子只处理存储/检索缓存机制的一部分,如果你粘在一起的东西,如果查找失败可以生成图像,它应该做你想要的一切。扩展它很容易...需要查找额外的参数?你只需要在 ImageCache typedef中添加另一个索引。

  include< boost / multi_index_container.hpp> 
#include< boost / multi_index / composite_key.hpp>
#include< boost / multi_index / member.hpp>
#include< boost / multi_index / ordered_index.hpp>
#include< boost / multi_index / hashed_index.hpp>
#include< boost / multi_index / tag.hpp>

#include< boost / shared_array.hpp>

#include< algorithm>
#include< iostream>
#include< utility>

//缓存项,存储图像数据,以及我们需要的任何值
// index on。
struct ImageCacheItem
{
enum RgbMode {RGB_MODE_COLOUR,RGB_MODE_GREYSCALE};

//我不知道容器中有多少拷贝,
//因此使用智能指针防止复制大量的
//数据。
boost :: shared_array< char> imageBuffer;

双旋转;
double scale;
RgbMode rgbMode;

ImageCacheItem(double r,double s)
:rotation(r),scale(s)
{
}
};

//这些是标签结构,它们用作
// multi_index_container的一部分,作为区分标记的一种方法。
struct ByRotation {};
struct ByScale {};
struct ByRgb {};
struct ByRotationScale {};

//容器本身的Typedef。
typedef boost :: multi_index_container<
ImageCacheItem,//容器的数据类型。
//注意没有key类型,因为键值
//是从数据项中提取的。
boost :: multi_index :: indexed_by<

//定义旋转值的索引
boost :: multi_index :: ordered_non_unique<
boost :: multi_index :: tag< ByRotation>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,rotation)
>,

//定义缩放的索引value
boost :: multi_index :: ordered_non_unique<
boost :: multi_index :: tag< ByScale>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,scale)
>,

//定义rgb的索引value
boost :: multi_index :: hashed_non_unique<
boost :: multi_index :: tag< ByRgb>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,ImageCacheItem :: RgbMode,rgbMode)
>,

//定义索引by rotation + scale
boost :: multi_index :: hashed_unique<
boost :: multi_index :: tag< ByRotationScale>,
boost :: multi_index :: composite_key<
ImageCacheItem,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,rotation),
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,scale)
>
>

>
> ImageCache;

//实用程序typedef,你会希望这些缩短迭代器
//数据类型,当你看东西(见main)。
typedef ImageCache :: index< ByRotation> :: type ImageCacheByRotation;
typedef ImageCache :: index< ByScale> :: type ImageCacheByScale;
typedef ImageCache :: index< ByRgb> :: type ImageCacheByRgb;
typedef ImageCache :: index< ByRotationScale> :: type ImageCacheByRotationScale;

int main()
{
//创建缓存并向其添加时间images。
ImageCache缓存;
cache.insert(ImageCacheItem(10,10));
cache.insert(ImageCacheItem(10,20));
cache.insert(ImageCacheItem(20,20));

//查找标度为20的图像。
typedef ImageCacheByScale :: iterator ScaleIter;

std :: pair< ScaleIter,ScaleIter> scaleResult = cache.get< ByScale>()。equal_range(20);
std :: cout<< Found< std :: distance(scaleResult.first,scaleResult.second)<< 结果<< std :: endl;

//查找带有rotation = 10和&& scale = 20.
ImageCacheByRotationScale :: iterator rsResult = cache.get< ByRotationScale>()。find(boost :: make_tuple(10,20));
std :: cout<< Found< (rsResult!= cache.get< ByRotationScale>()。end()?1:0)< 结果<< std :: endl;

return 0;
}

Edit:it a big one ...



我在扩展上述示例时发现,在缓存中查找与您搜索最接近的图片,但是偏差,因此,如果你想要旋转45°,而标度为10,如果没有发现精确匹配,它将有利于一个结果与一个属性相同,另一个为0(即10的标度,但是0旋转,所以你需要做的是旋转)。



代码被注释来解释它的作用,但基本上,它使用模板递归搜索索引按顺序,一旦索引找到一些匹配,它尝试按照相关性的顺序对它们进行排序,并返回最佳匹配。要添加另一个属性,您需要执行以下操作:


  1. 将属性添加到 ImageCacheItem

  2. 将属性的比较添加到 ImageCacheSimilarity

  3. ImageCache typedef

匹配的索引可能不是

 #最佳解决方案,但我认为涵盖了您在评论中提及的用例。 include< boost / multi_index_container.hpp> 
#include< boost / multi_index / composite_key.hpp>
#include< boost / multi_index / member.hpp>
#include< boost / multi_index / ordered_index.hpp>
#include< boost / multi_index / hashed_index.hpp>
#include< boost / multi_index / tag.hpp>

#include< boost / mpl / list.hpp>
#include< boost / optional.hpp>
#include< boost / ref.hpp>
#include< boost / shared_array.hpp>

#include< algorithm>
#include< cmath>
#include< iostream>
#include< utility>
#include< vector>
#include< typeinfo>

//缓存项,存储图像数据,以及我们需要的任何值
// index on。
struct ImageCacheItem
{
enum RgbMode {RGB_MODE_COLOUR,RGB_MODE_GREYSCALE};

//我不知道容器中有多少复制,
//因此使用智能指针防止复制大量的
//数据。
boost :: shared_array< char> imageBuffer;

双旋转;
double scale;
RgbMode rgbMode;

ImageCacheItem(double r,double s)
:rotation(r),scale(s)
{
}
};

//计算两个ImageCacheItem对象之间的相似性。
int ImageCacheSimilarity(const ImageCacheItem& item,const ImageCacheItem& target)
{
const double EPSILON = 0.0000001;

int score = 0;

// 2分精确匹配
//如果值为0,则为1分(例如,不旋转,因此可以用作起点)
// - 1点否则
得分+ =(std :: fabs(item.rotation - target.rotation)< EPSILON)
? 2
:((std :: fabs(item.rotation)< EPSILON)?1:-1);

score + =(std :: fabs(item.scale - target.scale)< EPSILON)
? 2
:((std :: fabs(item.scale)< EPSILON)?1:-1);

score + =(item.rgbMode == target.rgbMode)? 2:0;

return score;
}

//根据与目标值的相似性对ImageCacheItem对象进行排序。
struct ImageCacheCmp
{
const ImageCacheItem&目标;

ImageCacheCmp(const ImageCacheItem& t)
:target(t)
{
}

bool operator()(const ImageCacheItem& a,const ImageCacheItem& b)
{
return(ImageCacheSimilarity(a,target)> ImageCacheSimilarity(b,target)
}
};

//这些是标签结构,它们用作
// multi_index_container的一部分,作为区分标记的一种方法。
struct ByRotation {};
structure ByScale {};
struct ByRgb {};
struct ByRotationScale {};

//容器本身的Typedef。
typedef boost :: multi_index_container<
ImageCacheItem,//容器的数据类型。
//注意没有key类型,因为键值
//是从数据项中提取的。
boost :: multi_index :: indexed_by<

//这里的索引顺序会影响性能,把
//首先匹配大多数字段。它不需要
//来使它工作,但它会减少匹配的数量到
//与以后比较。

//通过rotation + scale定义一个索引
boost :: multi_index :: hashed_unique<
boost :: multi_index :: tag< ByRotationScale>,
boost :: multi_index :: composite_key<
ImageCacheItem,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,rotation),
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,scale)
>
>,

//定义旋转值的索引
boost :: multi_index :: ordered_non_unique<
boost :: multi_index :: tag< ByRotation>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,rotation)
>,

//定义标尺的索引value
boost :: multi_index :: ordered_non_unique<
boost :: multi_index :: tag< ByScale>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,double,scale)
>,

//定义rgb的索引value
boost :: multi_index :: hashed_non_unique<
boost :: multi_index :: tag< ByRgb>,
BOOST_MULTI_INDEX_MEMBER(ImageCacheItem,ImageCacheItem :: RgbMode,rgbMode)
>
>
> ImageCache;

//收集索引结果时使用的向量类型。它存储
//引用缓存中的值以最小化复制。
typedef std :: vector< boost :: reference_wrapper< const ImageCacheItem> > ImageCacheResults;

//重载解析的实用程序类
template< int I>
struct Int2Type
{
enum {value = I};
};

void FindMatches(
const ImageCacheItem& item,
const ImageCache& cache,
ImageCacheResults& results,
const Int2Type< boost :: mpl :: size< ImageCache :: index_type_list> :: type :: value>&)
{
//模板递归结束
}

template< int I> ;
void FindMatches(
const ImageCacheItem& item,
const ImageCache& cache,
ImageCacheResults& results,
const Int2Type< I&)

//获取被搜索的索引
typedef typename ImageCache :: nth_index< I> :: type Index;

//这种类型知道如何提取这个特定索引的ImageCacheItem
//的相关位。
typename Index :: key_from_value keyExtractor;

//在索引中查找匹配项。
std :: pair< typename Index :: const_iterator,typename Index :: const_iterator> iter =
cache.get< I>()。equal_range(keyExtractor(item));

//如果我们发现任何结果,将它们添加到'results',否则
//继续下一个索引。
if(iter.first!= iter.second)
{
results.reserve(std :: distance(iter.first,iter.second));

for(; iter.first!= iter.second; ++ iter.first)
{
results.push_back(boost :: cref(* iter.first)) ;
}
}
else
{
FindMatches(item,cache,results,Int2Type< I + 1>());
}
}

boost :: optional< ImageCacheItem> FindClosestImage(const ImageCacheItem& item,const ImageCache& cache)
{
//根据指示查找完全匹配/部分匹配。
ImageCacheResults结果;
FindMatches(item,cache,results,Int2Type< 0>());

//如果没有找到匹配,则返回一个空值
if(results.empty())
{
return boost :: optional< ImageCacheItem> );
}

//我们得到了这么远,所以我们必须有一些candiates,问题是
//我们不知道哪个是最好的匹配,所以这里我们排序结果
//基于接近项目。然而,我们只对最好的匹配
//感兴趣,所以做一个partial_sort。
std :: partial_sort(results.begin(),results.begin()+ 1,results.end(),ImageCacheCmp(item));

return results.front()。get();
}

int main()
{
//创建缓存并向其中添加一些图像。
ImageCache缓存;
cache.insert(ImageCacheItem(10,20));
cache.insert(ImageCacheItem(10,10));
cache.insert(ImageCacheItem(10,2));
cache.insert(ImageCacheItem(20,20));
cache.insert(ImageCacheItem(30,20));
cache.insert(ImageCacheItem(30,0));

//查找类似于rotation = 30&&& scale = 2.
boost :: optional< ImageCacheItem> result = FindClosestImage(ImageCacheItem(30,2),cache);

//必须检查结果是否为使用前的值,如果不匹配,将为空
//。
if(result)
{
std :: cout< Found(<< result> rotation
<<,<< result-> scale<<)
< std :: endl;
}
else
{
std :: cout< 无结果< std :: endl;
}

return 0;
}


I have a c++ application with several image types(RGB, Gray...) and every type has properties like Rotation or Scale. Every image type is generated via some computation from the other types. For example, A rotated GrayImage is generated by rotating a GrayImage which in turn is generated by "graying" an RGBImage.

I would like to design a cache class with methods GetX(...) that caches the various images (and possibly all images in the computation path). This class would also know how to generate each image in case it is not in the cache.

The class must fulfill some constraints:

  1. Since we are dealing with images of different types and representations(RGB, GrayScale etc.) the cache must return a concrete class for the calling code to be able to use it without some sort of casting. Thus, the cache mechanism must hold different cache structures containing concrete types. (fix me if I'm wrong here)

    map<...,RGBImage> 
    map<...,GrayImage> 
    

    for example.

  2. The cache must be flexible to changes in computation of images. Changes to code are acceptable as long as they are not too large.

The current version I have attaches a Key struct to each image type. There's GrayKey, RGBKey and so on. the various keys hold properties like Scale and Rotation and can have properties specific to the image (e.g. toGrayConvertingMethod for GrayKey). The cache holds maps of the form:

    map <XKey,XImage>

GetX(...) method receives a Key struct as parameter requesting a Rotated GrayImage for example. Though, this implementation forces the cache to apply lots of logic for computations of images. It must check whether GrayKey requests a rotated image or not and act accordingly. I would like to "encode" this image computation relationship in a more elegant way but can't seem to find one.

Any suggestions?

Thanks a lot.

解决方案

Perhaps you could do something using the Boost.MultiIndex container? It would allow you to make a type that stores the image data, and details of how it was manipulated, then lookup values based on whatever combination of keys you want. If you haven't used it before, it could seem a bit daunting, but i've attached an example below.

Obviously, my example only handles the storage/retrieval part of the caching mechanism, if you stick this together which something that can generate the images if the lookups fail, it should do everything you want. Extending it is easy too...need to lookup on extra parameters? you just need to add another index to the ImageCache typedef.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/tag.hpp>

#include <boost/shared_array.hpp>

#include <algorithm>
#include <iostream>
#include <utility>

// A cache item, stores the image data, and any values we need to 
// index on.
struct ImageCacheItem
{
    enum RgbMode { RGB_MODE_COLOUR, RGB_MODE_GREYSCALE };

    // Im not sure how much copying goes on in the container,
    // so using a smart pointer to prevent copying large amounts
    // of data.
    boost::shared_array<char> imageBuffer;

    double  rotation;
    double  scale;
    RgbMode rgbMode;

    ImageCacheItem(double r, double s)
    : rotation(r), scale(s)
    {
    }
};

// These are "tag" structures, they are used as part of the 
// multi_index_container as a way to distinguish between indicies.
struct ByRotation {};
struct ByScale {};
struct ByRgb {};
struct ByRotationScale {};

// Typedef of the container itself.
typedef boost::multi_index_container<
    ImageCacheItem, // The data type for the container.  
                    // Note there is no "key" type, as the key values 
                    // are extracted from the data items theselves.
    boost::multi_index::indexed_by<

        // Define an index for the rotation value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByRotation>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation)
        >,

        // Define an index for the scale value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByScale>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
        >,

        // Define an index for the rgb value
        boost::multi_index::hashed_non_unique<
            boost::multi_index::tag<ByRgb>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, ImageCacheItem::RgbMode, rgbMode)
        >,

        // Define an index by rotation + scale
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<ByRotationScale>,
            boost::multi_index::composite_key<
                ImageCacheItem,
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation),
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
            >
        >

    >
> ImageCache;

// Utility typedefs, you'll want these to shorten the iterator
// data types when you're looking things up (see main).
typedef ImageCache::index<ByRotation>::type      ImageCacheByRotation;
typedef ImageCache::index<ByScale>::type         ImageCacheByScale;
typedef ImageCache::index<ByRgb>::type           ImageCacheByRgb;
typedef ImageCache::index<ByRotationScale>::type ImageCacheByRotationScale;

int main()
{
    // Create the cache and add time "images" to it.
    ImageCache cache;
    cache.insert(ImageCacheItem(10, 10));
    cache.insert(ImageCacheItem(10, 20));
    cache.insert(ImageCacheItem(20, 20));

    // look up the images with scale of 20.
    typedef ImageCacheByScale::iterator ScaleIter;

    std::pair<ScaleIter, ScaleIter> scaleResult = cache.get<ByScale>().equal_range(20);
    std::cout << "Found " << std::distance(scaleResult.first, scaleResult.second) << " Results" << std::endl;

    // look up the image with rotation = 10 && scale = 20.
    ImageCacheByRotationScale::iterator rsResult = cache.get<ByRotationScale>().find(boost::make_tuple(10, 20));
    std::cout << "Found " << (rsResult != cache.get<ByRotationScale>().end() ? 1 : 0) << " Results" << std::endl;

    return 0;
}

Edit: its a big one...

I have had a stab at extending the above example to find the image in the cache that is closest to what you search for, but with a bias, so if you want rotation of 45, and a scale of 10, if no exact match is found, it would favour a result with one of the properties the same, and the other as 0 (i.e. a scale of 10, but 0 rotation, so all you need to do is rotate).

The code is commented to explain what its doing, but basically, it uses template recursion to search through the indices in order, as soon as an index finds some matches, it attempts to sort them in order of relevance, and returns the best match. To add another property, you would need to do the following:

  1. Add the property to ImageCacheItem
  2. Add comparison for the property to ImageCacheSimilarity
  3. (optional) Add another index that matches against it to the ImageCache typedef

It may not be the most optimal solution, but I think it covers the use case you mentioned in your comment.

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/tag.hpp>

#include <boost/mpl/list.hpp>
#include <boost/optional.hpp>
#include <boost/ref.hpp>
#include <boost/shared_array.hpp>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <utility>
#include <vector>
#include <typeinfo>

// A cache item, stores the image data, and any values we need to 
// index on.
struct ImageCacheItem
{
    enum RgbMode { RGB_MODE_COLOUR, RGB_MODE_GREYSCALE };

    // Im not sure how much copying goes on in the container,
    // so using a smart pointer to prevent copying large amounts
    // of data.
    boost::shared_array<char> imageBuffer;

    double  rotation;
    double  scale;
    RgbMode rgbMode;

    ImageCacheItem(double r, double s)
    : rotation(r), scale(s)
    {
    }
};

// Calculates the similarity between two ImageCacheItem objects.
int ImageCacheSimilarity(const ImageCacheItem& item, const ImageCacheItem& target)
{
    const double EPSILON = 0.0000001;

    int score = 0;

    // 2 points for an exact match
    // 1 point if the value is 0 (e.g. not rotated, so can be used as a starting point)
    // -1 point otherwise
    score += (std::fabs(item.rotation - target.rotation) < EPSILON) 
        ? 2 
        : ((std::fabs(item.rotation) < EPSILON) ? 1 : -1);

    score += (std::fabs(item.scale - target.scale) < EPSILON) 
        ? 2 
        : ((std::fabs(item.scale) < EPSILON) ? 1 : -1);

    score += (item.rgbMode == target.rgbMode) ? 2 : 0;

    return score;
}

// Orders ImageCacheItem objects based on their similarity to a target value.
struct ImageCacheCmp
{
    const ImageCacheItem& target;

    ImageCacheCmp(const ImageCacheItem& t)
    : target(t)
    {
    }

    bool operator()(const ImageCacheItem& a, const ImageCacheItem& b)
    {
        return (ImageCacheSimilarity(a, target) > ImageCacheSimilarity(b, target));
    }
};

// These are "tag" structures, they are used as part of the 
// multi_index_container as a way to distinguish between indicies.
struct ByRotation {};
struct ByScale {};
struct ByRgb {};
struct ByRotationScale {};

// Typedef of the container itself.
typedef boost::multi_index_container<
    ImageCacheItem, // The data type for the container.  
                    // Note there is no "key" type, as the key values 
                    // are extracted from the data items theselves.
    boost::multi_index::indexed_by<

        // The order of indicies here will affect performance, put the 
        // ones that match against the most fields first.  Its not required
        // to make it work, but it will reduce the number of matches to 
        // compare against later on.

        // Define an index by rotation + scale
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<ByRotationScale>,
            boost::multi_index::composite_key<
                ImageCacheItem,
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation),
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
            >
        >,

        // Define an index for the rotation value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByRotation>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation)
        >,

        // Define an index for the scale value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByScale>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
        >,

        // Define an index for the rgb value
        boost::multi_index::hashed_non_unique<
            boost::multi_index::tag<ByRgb>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, ImageCacheItem::RgbMode, rgbMode)
        >
    >
> ImageCache;

// Type of the vector used when collecting index results.  It stores
// references to the values in the cache to minimise copying.
typedef std::vector<boost::reference_wrapper<const ImageCacheItem> > ImageCacheResults;

// Utility class for overload resolution
template <int I>
struct Int2Type
{
    enum { value = I };
};

void FindMatches(
    const ImageCacheItem& item, 
    const ImageCache& cache, 
    ImageCacheResults& results,
    const Int2Type<boost::mpl::size<ImageCache::index_type_list>::type::value>&)
{
    // End of template recursion
}

template <int I>
void FindMatches(
    const ImageCacheItem& item, 
    const ImageCache& cache, 
    ImageCacheResults& results,
    const Int2Type<I>&)
{
    // Get the index being searched
    typedef typename ImageCache::nth_index<I>::type Index;

    // This type knows how to extract the relevant bits of ImageCacheItem
    // for this particular index.
    typename Index::key_from_value keyExtractor;

    // Look for matches in the index.
    std::pair<typename Index::const_iterator, typename Index::const_iterator> iter = 
        cache.get<I>().equal_range(keyExtractor(item));

    // If we found any results, add them to 'results', otherwise
    // continue to the next index.
    if (iter.first != iter.second)
    {
        results.reserve(std::distance(iter.first, iter.second));

        for ( ; iter.first != iter.second; ++iter.first)
        {
            results.push_back(boost::cref(*iter.first));
        }
    }
    else
    {
        FindMatches(item, cache, results, Int2Type<I + 1>());
    }
}

boost::optional<ImageCacheItem> FindClosestImage(const ImageCacheItem& item, const ImageCache& cache)
{
    // Find exact/partial matches according to the indicies.
    ImageCacheResults results;
    FindMatches(item, cache, results, Int2Type<0>());

    // If no matches were found, return an empty value
    if (results.empty())
    {
        return boost::optional<ImageCacheItem>();
    }

    // We got this far, so we must have some candiates, the problem is
    // we dont know which is the best match, so here we sort the results
    // based on proximity to the "item".  However, we are only interested
    // in the best match, so do a partial_sort.
    std::partial_sort(results.begin(), results.begin() + 1, results.end(), ImageCacheCmp(item));

    return results.front().get();
}

int main()
{
    // Create the cache and add some "images" to it.
    ImageCache cache;
    cache.insert(ImageCacheItem(10, 20));
    cache.insert(ImageCacheItem(10, 10));
    cache.insert(ImageCacheItem(10, 2));
    cache.insert(ImageCacheItem(20, 20));
    cache.insert(ImageCacheItem(30, 20));
    cache.insert(ImageCacheItem(30, 0));

    // Look for an image similar to rotation = 30 && scale = 2.
    boost::optional<ImageCacheItem> result = FindClosestImage(ImageCacheItem(30, 2), cache);

    // Have to check if result is value before usage, it would be empty 
    // if not match is found.
    if (result)
    {
        std::cout << "Found (" << result->rotation 
                  << ", " << result->scale << ")" 
                  << std::endl;
    }
    else
    {
        std::cout << "No Results" << std::endl;
    }

    return 0;
}

这篇关于C ++缓存设计建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆