Boost Cache

C++ライブラリキャッシュBoost標準化エンタープライズ

ライブラリ

Boost Cache

概要

Boost Cacheは、Boostライブラリの一部として提供されるキャッシュ機能です。堅牢性と標準化されたAPIを重視する設計により、エンタープライズレベルのC++開発において信頼性の高いキャッシュソリューションを提供します。

詳細

Boost Cache(ブーストキャッシュ)は、C++のBoostエコシステム内で提供されるキャッシュコンポーネントです。主にBoost.Computeライブラリ内でOpenCLプログラムキャッシュ(program_cache)として実装されており、OpenCLランタイムカーネルコンパイルモデルのオーバーヘッド軽減に使用されます。プログラムオブジェクトは、ユーザー定義のキャッシュキーとビルドオプションに基づいて永続的に保存・取得され、初回使用時のみコンパイルが実行されます。また、Boost.MultiIndexライブラリを使用してMRU(Most Recently Used)キャッシュやLFU(Least Frequently Used)キャッシュの実装も可能です。Boostエコシステム内での一貫した設計により、他のBoostライブラリとの統合が容易で、エンタープライズ開発において安定した採用実績があります。

メリット・デメリット

メリット

  • Boostエコシステム統合: 他のBoostライブラリとの一貫性と互換性
  • 標準化されたAPI: Boostの設計原則に基づく安定したインターフェース
  • 堅牢性重視: エンタープライズレベルでの信頼性確保
  • 永続化対応: プログラムキャッシュでの永続的保存機能
  • 豊富な文書化: Boostライブラリとしての包括的なドキュメント
  • 実績: 長期間にわたるBoostコミュニティでの使用実績
  • OpenCL最適化: GPU計算での効率的なプログラムキャッシュ

デメリット

  • 限定的な機能: 汎用キャッシュライブラリとしては機能が限定的
  • Boost依存: Boostライブラリ全体への依存が必要
  • パフォーマンス: 専用キャッシュライブラリと比較してパフォーマンスが劣る場合
  • 複雑性: 単純な用途には設計が過剰
  • サイズ: Boostライブラリ全体の導入によるバイナリサイズ増加

主要リンク

書き方の例

Boost.Compute Program Cache基本使用

#include <boost/compute.hpp>
#include <boost/compute/utility/program_cache.hpp>

namespace compute = boost::compute;

int main() {
    // OpenCLデバイスとコンテキストを取得
    compute::device device = compute::system::default_device();
    compute::context context(device);
    compute::command_queue queue(context, device);
    
    // プログラムキャッシュを作成
    compute::program_cache cache(context);
    
    // OpenCLカーネルソースコード
    const char source[] = R"(
        __kernel void vector_add(__global const float* a,
                               __global const float* b,
                               __global float* result)
        {
            int i = get_global_id(0);
            result[i] = a[i] + b[i];
        }
    )";
    
    // プログラムをキャッシュから取得または作成
    compute::program program = cache.get_or_build(
        "vector_add_program",  // キャッシュキー
        std::string(source),   // ソースコード
        context
    );
    
    // カーネルを作成
    compute::kernel kernel(program, "vector_add");
    
    return 0;
}

Boost.MultiIndexを使用したLRUキャッシュ

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>

using namespace boost::multi_index;

// キャッシュエントリ構造体
struct CacheEntry {
    std::string key;
    int value;
    
    CacheEntry(const std::string& k, int v) : key(k), value(v) {}
};

// MultiIndexコンテナ定義
typedef multi_index_container<
    CacheEntry,
    indexed_by<
        // アクセス順序用のシーケンシャルインデックス
        sequenced<>,
        // キー検索用の順序付きインデックス
        ordered_unique<
            member<CacheEntry, std::string, &CacheEntry::key>
        >
    >
> LRUCache;

class SimpleLRUCache {
private:
    LRUCache cache_;
    std::size_t max_size_;

public:
    SimpleLRUCache(std::size_t max_size) : max_size_(max_size) {}
    
    // 値を取得(LRU更新)
    bool get(const std::string& key, int& value) {
        auto& key_index = cache_.get<1>();
        auto it = key_index.find(key);
        
        if (it == key_index.end()) {
            return false; // 見つからない
        }
        
        value = it->value;
        
        // 最近使用したアイテムとして移動
        cache_.relocate(cache_.end(), cache_.project<0>(it));
        
        return true;
    }
    
    // 値を設定
    void put(const std::string& key, int value) {
        auto& key_index = cache_.get<1>();
        auto it = key_index.find(key);
        
        if (it != key_index.end()) {
            // 既存キーの更新
            key_index.modify(it, [value](CacheEntry& entry) {
                entry.value = value;
            });
            cache_.relocate(cache_.end(), cache_.project<0>(it));
        } else {
            // 新しいエントリを追加
            if (cache_.size() >= max_size_) {
                // 最も古いエントリを削除
                cache_.pop_front();
            }
            cache_.push_back(CacheEntry(key, value));
        }
    }
    
    std::size_t size() const { return cache_.size(); }
};

int main() {
    SimpleLRUCache cache(3); // 最大3エントリ
    
    cache.put("key1", 100);
    cache.put("key2", 200);
    cache.put("key3", 300);
    
    int value;
    if (cache.get("key1", value)) {
        std::cout << "key1: " << value << std::endl;
    }
    
    // キャパシティ超過でkey2が削除される
    cache.put("key4", 400);
    
    return 0;
}

カスタムキャッシュポリシー

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <chrono>
#include <string>

using namespace boost::multi_index;

// タイムスタンプ付きキャッシュエントリ
struct TimedCacheEntry {
    std::string key;
    std::string value;
    std::chrono::steady_clock::time_point timestamp;
    
    TimedCacheEntry(const std::string& k, const std::string& v)
        : key(k), value(v), timestamp(std::chrono::steady_clock::now()) {}
};

// TTL対応キャッシュ
typedef multi_index_container<
    TimedCacheEntry,
    indexed_by<
        // キー検索用
        ordered_unique<
            member<TimedCacheEntry, std::string, &TimedCacheEntry::key>
        >,
        // タイムスタンプ検索用
        ordered_non_unique<
            member<TimedCacheEntry, std::chrono::steady_clock::time_point, 
                   &TimedCacheEntry::timestamp>
        >
    >
> TTLCache;

class TimeBasedCache {
private:
    TTLCache cache_;
    std::chrono::seconds ttl_;

public:
    TimeBasedCache(std::chrono::seconds ttl) : ttl_(ttl) {}
    
    void put(const std::string& key, const std::string& value) {
        cleanup_expired();
        
        auto& key_index = cache_.get<0>();
        auto it = key_index.find(key);
        
        if (it != key_index.end()) {
            key_index.erase(it);
        }
        
        cache_.insert(TimedCacheEntry(key, value));
    }
    
    bool get(const std::string& key, std::string& value) {
        cleanup_expired();
        
        auto& key_index = cache_.get<0>();
        auto it = key_index.find(key);
        
        if (it == key_index.end()) {
            return false;
        }
        
        value = it->value;
        return true;
    }

private:
    void cleanup_expired() {
        auto now = std::chrono::steady_clock::now();
        auto& time_index = cache_.get<1>();
        
        auto expired_end = time_index.upper_bound(now - ttl_);
        time_index.erase(time_index.begin(), expired_end);
    }
};

Boost.Bimapを使用したキャッシュ

#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <string>
#include <iostream>

namespace bm = boost::bimaps;

class BiMapCache {
private:
    typedef boost::bimap<
        bm::unordered_set_of<std::string>,    // キー
        bm::list_of<std::string>              // 値(LRU順序)
    > CacheBiMap;
    
    CacheBiMap cache_;
    std::size_t max_size_;

public:
    BiMapCache(std::size_t max_size) : max_size_(max_size) {}
    
    void put(const std::string& key, const std::string& value) {
        auto it = cache_.left.find(key);
        
        if (it != cache_.left.end()) {
            // 既存エントリを更新し、最後に移動
            cache_.left.erase(it);
        } else if (cache_.size() >= max_size_) {
            // 最も古いエントリを削除
            cache_.right.erase(cache_.right.begin());
        }
        
        cache_.left.insert({key, value});
    }
    
    bool get(const std::string& key, std::string& value) {
        auto it = cache_.left.find(key);
        
        if (it == cache_.left.end()) {
            return false;
        }
        
        value = it->second;
        
        // LRU更新のため一度削除して再挿入
        std::string temp_value = value;
        cache_.left.erase(it);
        cache_.left.insert({key, temp_value});
        
        return true;
    }
    
    std::size_t size() const { return cache_.size(); }
};

int main() {
    BiMapCache cache(3);
    
    cache.put("name", "John");
    cache.put("age", "30");
    cache.put("city", "Tokyo");
    
    std::string value;
    if (cache.get("name", value)) {
        std::cout << "Name: " << value << std::endl;
    }
    
    return 0;
}