Skip to content

Commit

Permalink
[Feature] メッセージ履歴内の同一メッセージを共有する
Browse files Browse the repository at this point in the history
std::shared_ptr を用いて、同一のメッセージの場合はメッセージ領域を共有する。
メッセージの検索には std::map を使用し、O(log(N))で検索できるようにする。
  • Loading branch information
habu1010 committed May 4, 2021
1 parent 3f5ea18 commit b92a423
Showing 1 changed file with 52 additions and 5 deletions.
57 changes: 52 additions & 5 deletions src/view/display-messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "world/world.h"

#include <deque>
#include <map>
#include <memory>
#include <string>

/* Used in msg_print() for "buffering" */
Expand All @@ -21,7 +23,36 @@ bool msg_flag;
COMMAND_CODE now_message;

namespace {
std::deque<std::string> message_history;
/** メッセージが同一かどうかを比較するためのラムダ式 */
auto string_ptr_cmp = [](const std::string *a, const std::string *b) { return *a < *b; };

/** 同一メッセージの検索に使用するmapオブジェクト。
* 同一メッセージがあるかどうかを検索し、ヒットしたらweak_ptrからshared_ptrを作成しメッセージを共有する。
* message_historyのカスタムデリータの中で参照するので、message_historyより先に宣言しなければならない事に注意。
*/
std::map<std::string *, std::weak_ptr<std::string>, decltype(string_ptr_cmp)> message_map(string_ptr_cmp);

/** メッセージ履歴 */
std::deque<std::shared_ptr<std::string>> message_history;

/**
* @brief メッセージを保持するstd::shared_ptr<std::string>オブジェクトを生成する
*
* @tparam T メッセージの型。std::string / std::string_view / const char* 等
* @param str メッセージ
* @return 生成したstd::shared_ptr<std::string>オブジェクト
*/
template <typename T>
std::shared_ptr<std::string> make_message(T&& str)
{
/** std::stringオブジェクトと同時にmessage_mapのエントリも削除するカスタムデリータ */
auto deleter = [](std::string *s) {
message_map.erase(s);
delete s;
};

return std::shared_ptr<std::string>(new std::string(std::forward<T>(str)), std::move(deleter));
}
}

/*!
Expand All @@ -43,7 +74,7 @@ concptr message_str(int age)
if ((age < 0) || (age >= message_num()))
return ("");

return message_history[age].c_str();
return message_history[age]->c_str();
}

static void message_add_aux(std::string str)
Expand Down Expand Up @@ -80,7 +111,7 @@ static void message_add_aux(std::string str)
// 直前と同じメッセージの場合、「~ <xNN>」と表示する
if (!message_history.empty()) {
const char *t;
std::string_view last_message = message_history.front();
std::string_view last_message = *message_history.front();
#ifdef JP
for (t = last_message.data(); *t && (*t != '<' || (*(t + 1) != 'x')); t++)
if (iskanji(*t))
Expand Down Expand Up @@ -109,7 +140,20 @@ static void message_add_aux(std::string str)
}
}

message_history.push_front(std::move(str));
std::shared_ptr<std::string> add_msg;

// メッセージ履歴から同一のメッセージを探す
if (const auto& it = message_map.find(&str); it != message_map.end()) {
// 同一のメッセージが見つかったならそのメッセージのstd::shared_ptrオブジェクトを複製
add_msg = it->second.lock();
} else {
// 見つからなかった場合は新たにstd::shared_ptrオブジェクトを作成し、検索用mapオブジェクトに追加する
add_msg = make_message(std::move(str));
message_map.emplace(add_msg.get(), std::weak_ptr(add_msg));
}

// メッセージ履歴に追加
message_history.push_front(std::move(add_msg));

if (message_history.size() == MESSAGE_MAX)
message_history.pop_back();
Expand Down Expand Up @@ -186,7 +230,10 @@ static void msg_flush(player_type *player_ptr, int x)
term_erase(0, 0, 255);
}

void msg_erase(void) { msg_print(NULL); }
void msg_erase(void)
{
msg_print(NULL);
}

/*!
* @briefOutput a message to the top line of the screen.
Expand Down

0 comments on commit b92a423

Please sign in to comment.