-
-
Save kou-yeung/212d252eef30dadc9505ba4477798cab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> // for std::shared_ptr | |
#include <vector> // for std::vector | |
#include <map> // for std::map | |
#include <functional> // for std::function | |
#include <random> // for std::random_device , std::mt19937 | |
class CardData | |
{ | |
public: | |
// 本来は sqlite3_stmt* を受け取りますが、IDがわかればいいのでID簡易化しました | |
// CardData(sqlite3_stmt* stmt) {/* ... */} | |
CardData(uint32_t id):_id(id) {} | |
uint32_t _id; // カードID | |
}; | |
using CardDataPtr = std::shared_ptr<CardData>; | |
using CardDatas = std::vector<CardDataPtr>; | |
class CardDataCache | |
{ | |
public: | |
// id を受け取り、キャッシュされた CardDataPtr を返します。なければ nullptr を返す | |
CardDataPtr fetch(uint32_t id) const | |
{ | |
auto it = cache.find(id); | |
return (it != cache.end()) ? it->second : nullptr; | |
} | |
// CardDataPtr を受け取り、キャッシュされてない場合キャッシュに登録する | |
CardDataPtr store(CardDataPtr cardData) | |
{ | |
auto it = cache.find(cardData->_id); | |
if (it == cache.end()) cache.emplace(cardData->_id, cardData); | |
return cardData; | |
} | |
private: | |
std::map<uint32_t, CardDataPtr> cache; // キャッシュ : KEY( カードID ) VALUE(CardDataPtr) | |
}; | |
class DatabaseManager | |
{ | |
public: | |
static DatabaseManager* getInstance() | |
{ | |
static DatabaseManager _instance; | |
return &_instance; | |
} | |
// 今回の不具合を再現するのが目的です | |
// 受け取るID一覧を呼び出しデータの順が保証しなければ再現できるため | |
// std::vector<uint32_t> を受け取り、順がランダムのCardDataPtr を渡すように変更しています。 | |
// void query(const std::string& sql, std::function<void(sqlite3_stmt*)> cb) | |
void query(const std::vector<uint32_t>& ids, std::function<void(CardDataPtr)> cb) const | |
{ | |
// ids をコピーしてシャッフルする | |
auto result = std::vector<uint32_t>(std::begin(ids), std::end(ids)); | |
std::random_device seed_gen; | |
std::mt19937 engine(seed_gen()); | |
std::shuffle(std::begin(result), std::end(result), engine); | |
// シャッフルしたID一覧で CardDataPtr を生成しラムダを呼び出す | |
for (const auto& id : result) | |
{ | |
cb(std::make_shared<CardData>( id )); | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "class.h" | |
class CardModel | |
{ | |
public: | |
CardModel() | |
{ | |
// 公式サイトから引用 | |
//======================= | |
// ・表示に必要なカードIDリスト: 1, 2, 3, 4, 5 | |
// ・メモリ上のカードIDリスト: 1, 2, "空白", 4, 5 | |
//======================= | |
// とりあえず、[1,2,4,5] のデータをキャッシュさせれば 3 を取得時空白(nullptr)になります | |
_cardDataCache.store(std::make_shared<CardData>(1)); | |
_cardDataCache.store(std::make_shared<CardData>(2)); | |
_cardDataCache.store(std::make_shared<CardData>(4)); | |
_cardDataCache.store(std::make_shared<CardData>(5)); | |
} | |
// 実装は公式が提供されたソースコードをベースにしてインターフェースに合わせて調整しています | |
CardDatas getMasterCardDataByIds(const std::vector<uint32_t>& masterCardIds) const | |
{ | |
std::vector<CardDataPtr> result; | |
result.resize(masterCardIds.size()); | |
size_t exists = 0; | |
for (int i = 0; i < masterCardIds.size(); i++) | |
{ | |
auto p = result[i] = _cardDataCache.fetch(masterCardIds[i]); | |
if (p != nullptr) { | |
exists++; | |
} | |
} | |
if (masterCardIds.size() == exists) { | |
return result; | |
} | |
// 今回のサンプルでは使用しないため、コメントアウトしました。form(...) join(...) の実装を省く! | |
// string sql = form("SELECT * FROM cache.cards where id IN (%s);", join(masterCardIds, ",").c_str()); | |
int i = 0; | |
// 注 : SQL 文字列を受け取る代わりに、直接 ID一覧を受け取るようにしています | |
DatabaseManager::getInstance()->query(masterCardIds, [this, &result, &i](CardDataPtr cardData){ | |
if (result[i] == nullptr) { | |
result[i] = _cardDataCache.store(cardData); | |
} | |
i++; | |
}); | |
return result; | |
} | |
private: | |
mutable CardDataCache _cardDataCache; | |
}; | |
int main() | |
{ | |
auto model = CardModel{}; | |
auto masterCardIds = std::vector<uint32_t>{ 1,2,3,4,5 }; | |
auto cardDatas = model.getMasterCardDataByIds(masterCardIds); | |
for (const auto& card : cardDatas) | |
{ | |
std::cout << card->_id << " "; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment