Boost Cache
ライブラリ
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公式サイト
- Boost.Compute program_cache
- Boost Software License
- Boost Documentation
- Boost.MultiIndex
- OpenCL最適化ガイド
書き方の例
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;
}