refactor: 优化与 TaskData 的 get_raw 和 get 相关部分

fix: 使用 std::erase & std::erase_if, 避免使用具有不同定义的 ranges::remove & ranges::remove_if

现在 get_raw 只能获取任务的继承信息,其它详细信息会在 get 的时候解析。

另:
- 增加 TaskDerivedType 表示任务的继承类型
- 增加 TaskPipelineInfo 表示任务的流程信息(name + 5个TaskList的任务列表)
- 增加 TaskDerivedInfo 表示任务的继承信息,包含 base & prefix & TaskDerivedType
- 给各个任务类型的 shared_ptr 增加了别名;

(cherry picked from commit 6b5b0d5ec2)
This commit is contained in:
zzyyyl
2023-11-03 16:40:04 +08:00
parent d86e5dc770
commit e4dbdb9017
10 changed files with 414 additions and 377 deletions

View File

@@ -335,53 +335,106 @@ namespace asst
}
return "Invalid";
}
enum class TaskDerivedType
{
Invalid = -1,
Raw, // 原始任务
BaseTask, // BaseTask
Implicit, // 隐式 TemplateTask
Template, // 显式 TemplateTask
};
inline std::string enum_to_string(TaskDerivedType task_derived_type)
{
static const std::unordered_map<TaskDerivedType, std::string> task_derived_type_map = {
{ TaskDerivedType::Raw, "Raw" },
{ TaskDerivedType::BaseTask, "BaseTask" },
{ TaskDerivedType::Implicit, "Implicit" },
{ TaskDerivedType::Template, "Template" },
};
if (auto it = task_derived_type_map.find(task_derived_type); it != task_derived_type_map.end()) {
return it->second;
}
return "Invalid";
}
} // namespace asst
namespace asst
{
// 任务信息
struct TaskInfo
using TaskList = std::vector<std::string>;
// 任务流程信息
struct TaskPipelineInfo
{
TaskInfo() = default;
virtual ~TaskInfo() = default;
TaskInfo(const TaskInfo&) = default;
TaskInfo(TaskInfo&&) noexcept = default;
TaskInfo& operator=(const TaskInfo&) = default;
TaskInfo& operator=(TaskInfo&&) noexcept = default;
std::string name; // 任务名
AlgorithmType algorithm = // 图像算法类型
AlgorithmType::Invalid;
ProcessTaskAction action = // 要进行的操作
ProcessTaskAction::Invalid;
std::vector<std::string> sub; // 子任务(列表)
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
std::vector<std::string> next; // 下一个可能的任务(列表)
int max_times = INT_MAX; // 任务最多执行多少次
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
std::vector<std::string> on_error_next; // 任务出错之后要去执行什么
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。
// 例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,
// 所以蓝色开始行动要-1
Rect specific_rect; // 指定区域目前仅针对ClickRect任务有用会点这个区域
int pre_delay = 0; // 执行该任务前的延时
int post_delay = 0; // 执行该任务后的延时
int retry_times = INT_MAX; // 未找到图像时的重试次数
Rect roi; // 要识别的区域若为0则全图识别
constexpr TaskPipelineInfo() = default;
constexpr virtual ~TaskPipelineInfo() = default;
constexpr TaskPipelineInfo(const TaskPipelineInfo&) = default;
constexpr TaskPipelineInfo(TaskPipelineInfo&&) noexcept = default;
constexpr TaskPipelineInfo& operator=(const TaskPipelineInfo&) = default;
constexpr TaskPipelineInfo& operator=(TaskPipelineInfo&&) noexcept = default;
std::string name; // 任务名
TaskList next; // 下一个可能的任务(列表)
TaskList sub; // 子任务(列表)
TaskList on_error_next; // 任务出错之后要去执行什么
TaskList exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
TaskList reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,
// 则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
};
using TaskPipelinePtr = std::shared_ptr<TaskPipelineInfo>;
using TaskPipelineConstPtr = std::shared_ptr<const TaskPipelineInfo>;
// 任务继承信息
struct TaskDerivedInfo : public TaskPipelineInfo
{
constexpr TaskDerivedInfo() = default;
constexpr virtual ~TaskDerivedInfo() = default;
constexpr TaskDerivedInfo(const TaskDerivedInfo&) = default;
constexpr TaskDerivedInfo(TaskDerivedInfo&&) noexcept = default;
constexpr TaskDerivedInfo& operator=(const TaskDerivedInfo&) = default;
constexpr TaskDerivedInfo& operator=(TaskDerivedInfo&&) noexcept = default;
TaskDerivedType type = TaskDerivedType::Raw; // 任务类型
std::string base = ""; // 继承自哪个任务Raw 任务不需要)
std::string prefix = ""; // 需要添加的前缀(仅对 TemplateTask 生效)
};
using TaskDerivedPtr = std::shared_ptr<TaskDerivedInfo>;
using TaskDerivedConstPtr = std::shared_ptr<const TaskDerivedInfo>;
// 任务信息
struct TaskInfo : public TaskPipelineInfo
{
constexpr TaskInfo() = default;
constexpr virtual ~TaskInfo() = default;
constexpr TaskInfo(const TaskInfo&) = default;
constexpr TaskInfo(TaskInfo&&) noexcept = default;
constexpr TaskInfo& operator=(const TaskInfo&) = default;
constexpr TaskInfo& operator=(TaskInfo&&) noexcept = default;
AlgorithmType algorithm = AlgorithmType::Invalid; // 图像算法类型
ProcessTaskAction action = ProcessTaskAction::Invalid; // 要进行的操作
bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务
int max_times = INT_MAX; // 任务最多执行多少次
Rect specific_rect; // 指定区域目前仅针对ClickRect任务有用会点这个区域
int pre_delay = 0; // 执行该任务前的延时
int post_delay = 0; // 执行该任务后的延时
int retry_times = INT_MAX; // 未找到图像时的重试次数
Rect roi; // 要识别的区域若为0则全图识别
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。
// 即识别到了res点击res + result_move的位置
bool cache = false; // 是否使用缓存区域
std::vector<int> special_params; // 某些任务会用到的特殊参数
};
using TaskPtr = std::shared_ptr<TaskInfo>;
using TaskConstPtr = std::shared_ptr<const TaskInfo>;
// 文字识别任务的信息
struct OcrTaskInfo : public TaskInfo
{
OcrTaskInfo() = default;
virtual ~OcrTaskInfo() override = default;
OcrTaskInfo(const OcrTaskInfo&) = default;
OcrTaskInfo(OcrTaskInfo&&) noexcept = default;
OcrTaskInfo& operator=(const OcrTaskInfo&) = default;
OcrTaskInfo& operator=(OcrTaskInfo&&) noexcept = default;
constexpr OcrTaskInfo() = default;
constexpr virtual ~OcrTaskInfo() override = default;
constexpr OcrTaskInfo(const OcrTaskInfo&) = default;
constexpr OcrTaskInfo(OcrTaskInfo&&) noexcept = default;
constexpr OcrTaskInfo& operator=(const OcrTaskInfo&) = default;
constexpr OcrTaskInfo& operator=(OcrTaskInfo&&) noexcept = default;
std::vector<std::string> text; // 文字的容器,匹配到这里面任一个,就算匹配上了
bool full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
bool is_ascii = false; // 是否启用字符数字模型
@@ -390,35 +443,41 @@ namespace asst
std::vector<std::pair<std::string, std::string>>
replace_map; // 部分文字容易识别错字符串强制replace之后再进行匹配
};
using OcrTaskPtr = std::shared_ptr<OcrTaskInfo>;
using OcrTaskConstPtr = std::shared_ptr<const OcrTaskInfo>;
// 图片匹配任务的信息
struct MatchTaskInfo : public TaskInfo
{
MatchTaskInfo() = default;
virtual ~MatchTaskInfo() override = default;
MatchTaskInfo(const MatchTaskInfo&) = default;
MatchTaskInfo(MatchTaskInfo&&) noexcept = default;
MatchTaskInfo& operator=(const MatchTaskInfo&) = default;
MatchTaskInfo& operator=(MatchTaskInfo&&) noexcept = default;
constexpr MatchTaskInfo() = default;
constexpr virtual ~MatchTaskInfo() override = default;
constexpr MatchTaskInfo(const MatchTaskInfo&) = default;
constexpr MatchTaskInfo(MatchTaskInfo&&) noexcept = default;
constexpr MatchTaskInfo& operator=(const MatchTaskInfo&) = default;
constexpr MatchTaskInfo& operator=(MatchTaskInfo&&) noexcept = default;
std::vector<std::string> templ_names; // 匹配模板图片文件名
std::vector<double> templ_thresholds; // 模板匹配阈值
std::pair<int, int> mask_range; // 掩码的二值化范围
};
using MatchTaskPtr = std::shared_ptr<MatchTaskInfo>;
using MatchTaskConstPtr = std::shared_ptr<const MatchTaskInfo>;
// hash 计算任务的信息
struct HashTaskInfo : public TaskInfo
{
HashTaskInfo() = default;
virtual ~HashTaskInfo() override = default;
HashTaskInfo(const HashTaskInfo&) = default;
HashTaskInfo(HashTaskInfo&&) noexcept = default;
HashTaskInfo& operator=(const HashTaskInfo&) = default;
HashTaskInfo& operator=(HashTaskInfo&&) noexcept = default;
constexpr HashTaskInfo() = default;
constexpr virtual ~HashTaskInfo() override = default;
constexpr HashTaskInfo(const HashTaskInfo&) = default;
constexpr HashTaskInfo(HashTaskInfo&&) noexcept = default;
constexpr HashTaskInfo& operator=(const HashTaskInfo&) = default;
constexpr HashTaskInfo& operator=(HashTaskInfo&&) noexcept = default;
std::vector<std::string> hashes; // 需要多个哈希值
int dist_threshold = 0; // 汉明距离阈值
std::pair<int, int> mask_range; // 掩码的二值化范围
bool bound = false; // 是否裁剪周围黑边
};
using HashTaskPtr = std::shared_ptr<HashTaskInfo>;
using HashTaskConstPtr = std::shared_ptr<const HashTaskInfo>;
inline static const std::string UploadDataSource = "MeoAssistant";
} // namespace asst

View File

@@ -10,7 +10,7 @@
#include "Common/AsstTypes.h"
#include "GeneralConfig.h"
#include "TaskData/TaskDataSymbolStream.h"
#include "TaskData/TaskDataTypes.hpp"
#include "TaskData/TaskDataTypes.h"
#include "TemplResource.h"
#include "Utils/JsonMisc.hpp"
#include "Utils/Logger.hpp"
@@ -21,9 +21,9 @@ const std::unordered_set<std::string>& asst::TaskData::get_templ_required() cons
{
return m_templ_required;
}
asst::TaskData::taskptr_t asst::TaskData::get_raw(std::string_view name)
asst::TaskDerivedConstPtr asst::TaskData::get_raw(std::string_view name)
{
if (!generate_task_and_its_base(name, true)) [[unlikely]] {
if (!generate_raw_task_and_base(name, true)) [[unlikely]] {
return nullptr;
}
@@ -37,35 +37,27 @@ asst::TaskData::taskptr_t asst::TaskData::get_raw(std::string_view name)
return nullptr;
}
// 隐式 TemplateTask
if (auto base_task_iter = get_raw(name.substr(name_len + 1))) {
return _generate_task_info(base_task_iter, name.substr(0, name_len));
}
return nullptr;
}
asst::TaskData::taskptr_t asst::TaskData::get(std::string_view name)
asst::TaskPtr asst::TaskData::get(std::string_view name)
{
// 普通任务 或 已经生成过的高级任务
if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) [[likely]] {
if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) {
return it->second;
}
auto raw_task = get_raw(name);
auto task = _generate_task_info(raw_task);
auto task = generate_task_info(name);
if (!task) [[unlikely]] {
return nullptr;
}
bool changed = false; // 任务列表是否发生变化(是否包含虚任务)
#define ASST_TASKDATA_GET_IF_BRANCH(list, m) \
if (auto opt = compile_tasklist(raw_task->list, name, m); !opt) [[unlikely]] { \
Log.error("Generate task_list", std::string(name) + "->" #list, "failed.", opt.what()); \
return nullptr; \
} \
else { \
changed |= opt.value().task_changed; \
task->list = std::move(opt.value().tasks); \
#define ASST_TASKDATA_GET_IF_BRANCH(list, m) \
if (auto opt = compile_tasklist(task->list, name, m); !opt) [[unlikely]] { \
Log.error("Generate task_list", std::string(name) + "->" #list, "failed.", opt.error()); \
return nullptr; \
} \
else { \
task->list = std::move(opt.value().tasks); \
}
// 展开五个任务列表中的虚任务
ASST_TASKDATA_GET_IF_BRANCH(next, false);
@@ -78,12 +70,12 @@ asst::TaskData::taskptr_t asst::TaskData::get(std::string_view name)
constexpr size_t MAX_TASKS_SIZE = 65535;
if (m_all_tasks_info.size() < MAX_TASKS_SIZE) [[likely]] {
// 保存最终生成的任务,下次查询时可以直接返回
return insert_or_assign_task(name, changed ? task : raw_task).first->second;
return insert_or_assign_task(name, task).first->second;
}
else {
// 个数超过上限时不保存,直接返回,防止内存占用过大
Log.warn("Task count has exceeded the upper limit:", MAX_TASKS_SIZE, "current task:", name);
return changed ? task : raw_task;
return task;
}
}
@@ -149,7 +141,7 @@ bool asst::TaskData::lazy_parse(const json::value& json)
validity = false;
continue;
}
auto check_tasklist = [&](const tasklist_t& task_list, std::string_view list_type,
auto check_tasklist = [&](const TaskList& task_list, std::string_view list_type,
bool enable_justreturn_check = false) {
std::unordered_set<std::string_view> tasks_set {};
std::string justreturn_task_name = "";
@@ -165,7 +157,7 @@ bool asst::TaskData::lazy_parse(const json::value& json)
validity = false;
}
if (auto ptr = get_raw(task_name); ptr == nullptr) [[unlikely]] {
if (auto ptr = get(task_name); ptr == nullptr) [[unlikely]] {
Log.error(task_name, "in", (std::string(name) += "->") += list_type, "is null");
validity = false;
continue;
@@ -217,7 +209,7 @@ bool asst::TaskData::parse(const json::value& json)
// 本来重构之后完全支持惰性加载,但是发现模板图片不支持(
for (std::string_view name : m_json_all_tasks_info | views::keys) {
generate_task_and_its_base(name, true);
generate_raw_task_and_base(name, true);
}
return true;
@@ -240,19 +232,37 @@ void asst::TaskData::set_task_base(const std::string_view task_name, std::string
clear_tasks();
}
bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must_true)
bool asst::TaskData::generate_raw_task_info(std::string_view name, std::string_view prefix, std::string_view base,
const json::value& json, TaskDerivedType type)
{
TaskPipelineConstPtr base_task = base.empty() ? nullptr : get_raw(base);
if (base_task == nullptr) {
base_task = default_task_info_ptr;
prefix = "";
}
TaskDerivedPtr task = std::make_shared<TaskDerivedInfo>();
task->name = name;
task->type = type;
task->base = base;
task->prefix = prefix;
utils::get_value_or(name, json, "next", task->next, [&]() { return append_prefix(base_task->next, prefix); });
utils::get_value_or(name, json, "sub", task->sub, [&]() { return append_prefix(base_task->sub, prefix); });
utils::get_value_or(name, json, "exceededNext", task->exceeded_next,
[&]() { return append_prefix(base_task->exceeded_next, prefix); });
utils::get_value_or(name, json, "onErrorNext", task->on_error_next,
[&]() { return append_prefix(base_task->on_error_next, prefix); });
utils::get_value_or(name, json, "reduceOtherTimes", task->reduce_other_times,
[&]() { return append_prefix(base_task->reduce_other_times, prefix); });
m_task_status[task_name_view(name)] = NotToBeGenerate;
// 保存虚任务未展开的任务
insert_or_assign_raw_task(name, task);
return true;
}
bool asst::TaskData::generate_raw_task_and_base(std::string_view name, bool must_true)
{
auto generate_task = [&](std::string_view name, std::string_view prefix, taskptr_t base_ptr,
const json::value& task_json) {
auto task_info_ptr = generate_task_info(name, task_json, base_ptr, prefix);
if (task_info_ptr == nullptr) {
return false;
}
m_task_status[task_name_view(name)] = NotToBeGenerate;
// 保存虚任务未展开的任务
insert_or_assign_raw_task(name, task_info_ptr);
return true;
};
switch (m_task_status[task_name_view(name)]) {
case NotToBeGenerate:
// 已经显式生成
@@ -262,7 +272,12 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must
// 隐式生成的资源
if (size_t p = name.find('@'); p != std::string::npos) {
return generate_task_and_its_base(name.substr(p + 1), must_true);
if (generate_raw_task_and_base(name.substr(p + 1), must_true)) {
// 隐式 TemplateTask
generate_raw_task_info(name, name.substr(0, p), name.substr(p + 1), {}, TaskDerivedType::Implicit);
return true;
}
return false;
}
m_task_status[name] = NotExists;
@@ -288,22 +303,17 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must
// BaseTask
if (auto opt = task_json.find<std::string>("baseTask")) {
std::string base = opt.value();
return generate_task_and_its_base(base, must_true) && generate_task(name, "", get_raw(base), task_json);
return generate_raw_task_and_base(base, must_true) &&
generate_raw_task_info(name, "", base, task_json, TaskDerivedType::BaseTask);
}
// TemplateTask
if (size_t p = name.find('@'); p != std::string::npos) {
if (std::string_view base = name.substr(p + 1); generate_task_and_its_base(base, false)) {
#ifdef ASST_DEBUG
if (task_json.as_object().empty() && get_raw(base)->algorithm != AlgorithmType::MatchTemplate) {
// 多余的空任务
Log.warn("Task", name, "is a redundant empty task because it is not MatchTemplate");
}
#endif
return generate_task(name, name.substr(0, p), get_raw(base), task_json);
if (std::string_view base = name.substr(p + 1); generate_raw_task_and_base(base, false)) {
return generate_raw_task_info(name, name.substr(0, p), base, task_json, TaskDerivedType::Template);
}
}
return generate_task(name, "", nullptr, task_json);
return generate_raw_task_info(name, "", "", task_json, TaskDerivedType::Raw);
}
[[unlikely]] case Generating:
Log.error("Task", name, "is generated cyclically");
@@ -314,59 +324,123 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must
}
}
asst::TaskData::taskptr_t asst::TaskData::generate_task_info(std::string_view name, const json::value& task_json,
taskptr_t default_ptr, std::string_view task_prefix)
asst::TaskPtr asst::TaskData::generate_task_info(std::string_view name)
{
if (default_ptr == nullptr) {
default_ptr = default_task_info_ptr;
task_prefix = "";
auto raw = get_raw(name);
if (!raw) [[unlikely]] {
Log.error("Task", name, "not found");
return nullptr;
}
auto json_it = m_json_all_tasks_info.find(name);
const json::value& json = json_it == m_json_all_tasks_info.cend() ? json::value {} : json_it->second;
if (raw->type == TaskDerivedType::Raw && json_it == m_json_all_tasks_info.cend()) [[unlikely]] {
Log.error("Task", name, "of type Raw has no json");
return nullptr;
}
if (raw->type == TaskDerivedType::Raw && !raw->base.empty()) [[unlikely]] {
Log.error("Task", name, "of type Raw has base", raw->base);
return nullptr;
}
if (raw->type != TaskDerivedType::Raw && raw->base.empty()) [[unlikely]] {
Log.error("Task", name, "of type", enum_to_string(raw->type), "has no base");
return nullptr;
}
if ((raw->type == TaskDerivedType::Implicit || raw->type == TaskDerivedType::Template) && raw->prefix.empty())
[[unlikely]] {
Log.error("Task", name, "of type", enum_to_string(raw->type), "has no prefix");
return nullptr;
}
if ((raw->type == TaskDerivedType::Raw || raw->type == TaskDerivedType::BaseTask) && !raw->prefix.empty())
[[unlikely]] {
Log.error("Task", name, "of type", enum_to_string(raw->type), "has prefix", raw->prefix);
return nullptr;
}
TaskConstPtr base = default_task_info_ptr;
if (!raw->base.empty()) {
base = get(raw->base);
if (!base) [[unlikely]] {
Log.error("Base task", raw->base, "of task", name, "not found");
return nullptr;
}
}
// 获取 algorithm 并按照 algorithm 生成 TaskInfo
AlgorithmType algorithm;
utils::get_value_or(name, task_json, "algorithm", algorithm, default_ptr->algorithm);
taskptr_t task_ptr = nullptr;
utils::get_value_or(name, json, "algorithm", algorithm, base->algorithm);
TaskPtr task = nullptr;
switch (algorithm) {
case AlgorithmType::MatchTemplate:
task_ptr = generate_match_task_info(name, task_json, std::dynamic_pointer_cast<MatchTaskInfo>(default_ptr));
task = generate_match_task_info(name, json, std::dynamic_pointer_cast<const MatchTaskInfo>(base), raw->type);
break;
case AlgorithmType::OcrDetect:
task_ptr = generate_ocr_task_info(name, task_json, std::dynamic_pointer_cast<OcrTaskInfo>(default_ptr));
task = generate_ocr_task_info(name, json, std::dynamic_pointer_cast<const OcrTaskInfo>(base));
break;
case AlgorithmType::Hash:
task_ptr = generate_hash_task_info(name, task_json, std::dynamic_pointer_cast<HashTaskInfo>(default_ptr));
task = generate_hash_task_info(name, json, std::dynamic_pointer_cast<const HashTaskInfo>(base));
break;
case AlgorithmType::JustReturn:
task_ptr = std::make_shared<TaskInfo>();
task = std::make_shared<TaskInfo>();
break;
default:
Log.error("Unknown algorithm in task", name);
return nullptr;
}
if (task_ptr == nullptr) {
if (task == nullptr) {
return nullptr;
}
// 不管什么algorithm都有基础成员next, roi, 等等)
if (!append_base_task_info(task_ptr, name, task_json, default_ptr, task_prefix)) {
return nullptr;
const auto& prefix = raw->prefix;
#define ASST_TASKDATA_GET_VALUE_OR(key, value) utils::get_value_or(name, json, key, task->value, base->value)
#define ASST_TASKDATA_GET_VALUE_OR_LAZY(key, value) \
utils::get_value_or(name, json, key, task->value, [&]() { return append_prefix(base->value, prefix); })
ASST_TASKDATA_GET_VALUE_OR("action", action);
ASST_TASKDATA_GET_VALUE_OR("cache", cache);
ASST_TASKDATA_GET_VALUE_OR("maxTimes", max_times);
ASST_TASKDATA_GET_VALUE_OR("preDelay", pre_delay);
ASST_TASKDATA_GET_VALUE_OR("postDelay", post_delay);
ASST_TASKDATA_GET_VALUE_OR("roi", roi);
ASST_TASKDATA_GET_VALUE_OR("subErrorIgnored", sub_error_ignored);
ASST_TASKDATA_GET_VALUE_OR("rectMove", rect_move);
ASST_TASKDATA_GET_VALUE_OR("specificRect", specific_rect);
ASST_TASKDATA_GET_VALUE_OR("specialParams", special_params);
ASST_TASKDATA_GET_VALUE_OR_LAZY("next", next);
ASST_TASKDATA_GET_VALUE_OR_LAZY("sub", sub);
ASST_TASKDATA_GET_VALUE_OR_LAZY("exceededNext", exceeded_next);
ASST_TASKDATA_GET_VALUE_OR_LAZY("onErrorNext", on_error_next);
ASST_TASKDATA_GET_VALUE_OR_LAZY("reduceOtherTimes", reduce_other_times);
#undef ASST_TASKDATA_GET_VALUE_OR
#undef ASST_TASKDATA_GET_VALUE_OR_LAZY
#ifdef ASST_DEBUG
// Debug 模式下检查 roi 是否超出边界
if (auto [x, y, w, h] = task->roi; x + w > WindowWidthDefault || y + h > WindowHeightDefault) {
Log.warn(name, "roi is out of bounds");
}
task_ptr->algorithm = algorithm;
task_ptr->name = name;
return task_ptr;
#endif
task->algorithm = algorithm;
task->name = name;
return task;
}
asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_view name, const json::value& task_json,
std::shared_ptr<MatchTaskInfo> default_ptr)
asst::TaskPtr asst::TaskData::generate_match_task_info(std::string_view name, const json::value& task_json,
MatchTaskConstPtr default_ptr, TaskDerivedType derived_type)
{
if (default_ptr == nullptr) {
default_ptr = default_match_task_info_ptr;
}
auto match_task_info_ptr = std::make_shared<MatchTaskInfo>();
if (!utils::get_value_or(name, task_json, "template", match_task_info_ptr->templ_names,
[&]() { return std::vector { std::string(name) + ".png" }; })) {
if (!utils::get_value_or(name, task_json, "template", match_task_info_ptr->templ_names, [&]() {
return derived_type == TaskDerivedType::Implicit // 隐式 Template Task 时继承,其它时默认值使用任务名
? default_ptr->templ_names
: std::vector { std::string(name) + ".png" };
})) {
return nullptr;
}
@@ -386,7 +460,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v
threshold_opt->as_double());
}
else if (threshold_opt->is_array()) {
ranges::copy(threshold_opt->as_array() | views::transform(&ranges::range_value_t<json::array>::as_double),
ranges::copy(threshold_opt->as_array() | views::transform(&json::value::as_double),
std::back_inserter(match_task_info_ptr->templ_thresholds));
}
else {
@@ -408,8 +482,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v
return match_task_info_ptr;
}
asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_view name, const json::value& task_json,
std::shared_ptr<OcrTaskInfo> default_ptr)
asst::TaskPtr asst::TaskData::generate_ocr_task_info(std::string_view name, const json::value& task_json,
OcrTaskConstPtr default_ptr)
{
if (default_ptr == nullptr) {
default_ptr = default_ocr_task_info_ptr;
@@ -432,8 +506,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_vie
return ocr_task_info_ptr;
}
asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_view name, const json::value& task_json,
std::shared_ptr<HashTaskInfo> default_ptr)
asst::TaskPtr asst::TaskData::generate_hash_task_info(std::string_view name, const json::value& task_json,
HashTaskConstPtr default_ptr)
{
if (default_ptr == nullptr) {
default_ptr = default_hash_task_info_ptr;
@@ -453,91 +527,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_vi
return hash_task_info_ptr;
}
bool asst::TaskData::append_base_task_info(taskptr_t task_info_ptr, std::string_view name, const json::value& task_json,
taskptr_t default_ptr, std::string_view task_prefix)
{
if (default_ptr == nullptr) {
default_ptr = default_task_info_ptr;
}
utils::get_value_or(name, task_json, "action", task_info_ptr->action, default_ptr->action);
utils::get_value_or(name, task_json, "cache", task_info_ptr->cache, default_ptr->cache);
utils::get_value_or(name, task_json, "maxTimes", task_info_ptr->max_times, default_ptr->max_times);
utils::get_value_or(name, task_json, "exceededNext", task_info_ptr->exceeded_next,
[&]() { return append_prefix(default_ptr->exceeded_next, task_prefix); });
utils::get_value_or(name, task_json, "onErrorNext", task_info_ptr->on_error_next,
[&]() { return append_prefix(default_ptr->on_error_next, task_prefix); });
utils::get_value_or(name, task_json, "preDelay", task_info_ptr->pre_delay, default_ptr->pre_delay);
utils::get_value_or(name, task_json, "postDelay", task_info_ptr->post_delay, default_ptr->post_delay);
utils::get_value_or(name, task_json, "reduceOtherTimes", task_info_ptr->reduce_other_times,
[&]() { return append_prefix(default_ptr->reduce_other_times, task_prefix); });
utils::get_value_or(name, task_json, "roi", task_info_ptr->roi, default_ptr->roi);
utils::get_value_or(name, task_json, "sub", task_info_ptr->sub,
[&]() { return append_prefix(default_ptr->sub, task_prefix); });
utils::get_value_or(name, task_json, "subErrorIgnored", task_info_ptr->sub_error_ignored,
default_ptr->sub_error_ignored);
utils::get_value_or(name, task_json, "next", task_info_ptr->next,
[&]() { return append_prefix(default_ptr->next, task_prefix); });
utils::get_value_or(name, task_json, "rectMove", task_info_ptr->rect_move, default_ptr->rect_move);
utils::get_value_or(name, task_json, "specificRect", task_info_ptr->specific_rect, default_ptr->specific_rect);
utils::get_value_or(name, task_json, "specialParams", task_info_ptr->special_params, default_ptr->special_params);
#ifdef ASST_DEBUG
// Debug 模式下检查 roi 是否超出边界
if (auto [x, y, w, h] = task_info_ptr->roi; x + w > WindowWidthDefault || y + h > WindowHeightDefault) {
Log.warn(name, "roi is out of bounds");
}
#endif
return true;
}
std::shared_ptr<asst::MatchTaskInfo> asst::TaskData::_default_match_task_info()
{
auto match_task_info_ptr = std::make_shared<MatchTaskInfo>();
match_task_info_ptr->templ_names = { "__INVALID__" };
match_task_info_ptr->templ_thresholds = { TemplThresholdDefault };
return match_task_info_ptr;
}
std::shared_ptr<asst::OcrTaskInfo> asst::TaskData::_default_ocr_task_info()
{
auto ocr_task_info_ptr = std::make_shared<OcrTaskInfo>();
ocr_task_info_ptr->full_match = false;
ocr_task_info_ptr->is_ascii = false;
ocr_task_info_ptr->without_det = false;
ocr_task_info_ptr->replace_full = false;
return ocr_task_info_ptr;
}
std::shared_ptr<asst::HashTaskInfo> asst::TaskData::_default_hash_task_info()
{
auto hash_task_info_ptr = std::make_shared<HashTaskInfo>();
hash_task_info_ptr->dist_threshold = 0;
hash_task_info_ptr->bound = true;
return hash_task_info_ptr;
}
asst::TaskData::taskptr_t asst::TaskData::_default_task_info()
{
auto task_info_ptr = std::make_shared<TaskInfo>();
task_info_ptr->algorithm = AlgorithmType::MatchTemplate;
task_info_ptr->action = ProcessTaskAction::DoNothing;
task_info_ptr->cache = true;
task_info_ptr->max_times = INT_MAX;
task_info_ptr->pre_delay = 0;
task_info_ptr->post_delay = 0;
task_info_ptr->roi = Rect();
task_info_ptr->sub_error_ignored = false;
task_info_ptr->rect_move = Rect();
task_info_ptr->specific_rect = Rect();
return task_info_ptr;
}
asst::ResultOrError<asst::TaskData::RawCompileResult> asst::TaskData::compile_raw_tasklist(
const tasklist_t& raw_tasks, std::string_view self_name, std::function<taskptr_t(std::string_view)> get_raw,
const TaskList& raw_tasks, std::string_view self_name, std::function<TaskDerivedConstPtr(std::string_view)> get_raw,
bool allow_duplicate)
{
RawCompileResult ret { .task_changed = false, .symbols = {} };
@@ -554,14 +545,14 @@ asst::ResultOrError<asst::TaskData::RawCompileResult> asst::TaskData::compile_ra
ret.task_changed = ret.task_changed || opt.value();
}
else {
return { std::nullopt, std::move(opt.what()) };
return { std::nullopt, std::move(opt.error()) };
}
auto opt = symbol_stream.decode(
[&](const TaskDataSymbol& symbol, const TaskDataSymbol& prefix) -> TaskDataSymbol::SymbolsOrError {
return TaskDataSymbol::append_prefix(
symbol, prefix, self_name, get_raw,
[&](const tasklist_t& raw_or_empty) -> TaskDataSymbol::SymbolsOrError {
[&](const TaskList& raw_or_empty) -> TaskDataSymbol::SymbolsOrError {
if (auto opt = compile_raw_tasklist(raw_or_empty, self_name, get_raw, allow_duplicate)) {
return opt.value().symbols;
}
@@ -572,7 +563,7 @@ asst::ResultOrError<asst::TaskData::RawCompileResult> asst::TaskData::compile_ra
// 记号流处理
if (!opt) {
return { std::nullopt, std::move(opt.what()) };
return { std::nullopt, std::move(opt.error()) };
}
for (const auto& task : *opt) {
@@ -589,7 +580,7 @@ asst::ResultOrError<asst::TaskData::RawCompileResult> asst::TaskData::compile_ra
return ret;
}
asst::ResultOrError<asst::TaskData::CompileResult> asst::TaskData::compile_tasklist(const tasklist_t& raw_tasks,
asst::ResultOrError<asst::TaskData::CompileResult> asst::TaskData::compile_tasklist(const TaskList& raw_tasks,
std::string_view self_name,
bool allow_duplicate)
{
@@ -598,7 +589,7 @@ asst::ResultOrError<asst::TaskData::CompileResult> asst::TaskData::compile_taskl
if (auto opt = compile_raw_tasklist(
raw_tasks, self_name, [&](std::string_view name) { return get_raw(name); }, allow_duplicate);
!opt) {
return { std::nullopt, std::move(opt.what()) };
return { std::nullopt, std::move(opt.error()) };
}
else {
new_symbols = std::move(opt.value().symbols);
@@ -634,6 +625,96 @@ asst::ResultOrError<asst::TaskData::CompileResult> asst::TaskData::compile_taskl
return ret;
}
std::string asst::TaskData::append_prefix(std::string_view task_name, std::string_view task_prefix)
{
if (task_prefix.ends_with('@')) [[unlikely]] {
task_prefix.remove_suffix(1);
}
if (task_prefix.empty()) [[unlikely]] {
return std::string(task_name);
}
if (task_name.empty()) {
return std::string(task_prefix);
}
if (task_name.starts_with('#')) {
return std::string(task_prefix) + std::string(task_name);
}
return std::string(task_prefix) + '@' + std::string(task_name);
}
asst::TaskList asst::TaskData::append_prefix(const TaskList& base_task_list, std::string_view task_prefix)
{
if (task_prefix.ends_with('@')) [[unlikely]] {
task_prefix.remove_suffix(1);
}
if (task_prefix.empty()) {
return base_task_list;
}
TaskList task_list = {};
for (const std::string& base : base_task_list) {
std::string_view base_view = base;
size_t l = 0;
bool has_same_prefix = false;
// base 任务里已经存在相同前缀,则不加前缀
// https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/2116#issuecomment-1270115238
for (size_t r = base_view.find('@'); r != std::string_view::npos; r = base_view.find('@', l)) {
if (task_prefix == base_view.substr(l, r - l)) [[unlikely]] {
has_same_prefix = true;
break;
}
l = r + 1;
}
task_list.emplace_back(has_same_prefix ? base : append_prefix(base_view, task_prefix));
}
return task_list;
}
asst::MatchTaskConstPtr asst::TaskData::_default_match_task_info()
{
auto match_task_info_ptr = std::make_shared<MatchTaskInfo>();
match_task_info_ptr->templ_names = { "__INVALID__" };
match_task_info_ptr->templ_thresholds = { TemplThresholdDefault };
return match_task_info_ptr;
}
asst::OcrTaskConstPtr asst::TaskData::_default_ocr_task_info()
{
auto ocr_task_info_ptr = std::make_shared<OcrTaskInfo>();
ocr_task_info_ptr->full_match = false;
ocr_task_info_ptr->is_ascii = false;
ocr_task_info_ptr->without_det = false;
ocr_task_info_ptr->replace_full = false;
return ocr_task_info_ptr;
}
asst::HashTaskConstPtr asst::TaskData::_default_hash_task_info()
{
auto hash_task_info_ptr = std::make_shared<HashTaskInfo>();
hash_task_info_ptr->dist_threshold = 0;
hash_task_info_ptr->bound = true;
return hash_task_info_ptr;
}
asst::TaskConstPtr asst::TaskData::_default_task_info()
{
auto task_info_ptr = std::make_shared<TaskInfo>();
task_info_ptr->algorithm = AlgorithmType::MatchTemplate;
task_info_ptr->action = ProcessTaskAction::DoNothing;
task_info_ptr->cache = true;
task_info_ptr->max_times = INT_MAX;
task_info_ptr->pre_delay = 0;
task_info_ptr->post_delay = 0;
task_info_ptr->roi = Rect();
task_info_ptr->sub_error_ignored = false;
task_info_ptr->rect_move = Rect();
task_info_ptr->specific_rect = Rect();
return task_info_ptr;
}
#ifdef ASST_DEBUG
// 为了解决类似 beddc7c828126c678391e0b4da288db6d2c2d58a 导致的问题,加载的时候做一个语法检查
// 主要是处理是否包含未知键值的问题

View File

@@ -2,8 +2,6 @@
#include "AbstractConfigWithTempl.h"
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>
@@ -12,166 +10,75 @@
namespace asst
{
struct TaskInfo;
class TaskData final : public SingletonHolder<TaskData>, public AbstractConfigWithTempl
{
public:
using tasklist_t = std::vector<std::string>;
using tasklistptr_t = std::shared_ptr<tasklist_t>;
using taskptr_t = std::shared_ptr<TaskInfo>;
private:
static std::shared_ptr<MatchTaskInfo> _default_match_task_info();
static std::shared_ptr<OcrTaskInfo> _default_ocr_task_info();
static std::shared_ptr<HashTaskInfo> _default_hash_task_info();
static taskptr_t _default_task_info();
static MatchTaskConstPtr _default_match_task_info();
static OcrTaskConstPtr _default_ocr_task_info();
static HashTaskConstPtr _default_hash_task_info();
static TaskConstPtr _default_task_info();
// 从模板任务生成
static inline const std::shared_ptr<MatchTaskInfo> default_match_task_info_ptr = _default_match_task_info();
static inline const std::shared_ptr<OcrTaskInfo> default_ocr_task_info_ptr = _default_ocr_task_info();
static inline const std::shared_ptr<HashTaskInfo> default_hash_task_info_ptr = _default_hash_task_info();
static inline const taskptr_t default_task_info_ptr = _default_task_info();
static inline const MatchTaskConstPtr default_match_task_info_ptr = _default_match_task_info();
static inline const OcrTaskConstPtr default_ocr_task_info_ptr = _default_ocr_task_info();
static inline const HashTaskConstPtr default_hash_task_info_ptr = _default_hash_task_info();
static inline const TaskConstPtr default_task_info_ptr = _default_task_info();
// 这是下面几个函数的封装
taskptr_t generate_task_info(std::string_view name, const json::value&, taskptr_t default_ptr,
std::string_view task_prefix = "");
static std::string append_prefix(std::string_view task_name, std::string_view task_prefix);
static TaskList append_prefix(const TaskList& base_task_list, std::string_view task_prefix);
taskptr_t generate_match_task_info(std::string_view name, const json::value&,
std::shared_ptr<MatchTaskInfo> default_ptr);
taskptr_t generate_ocr_task_info(std::string_view name, const json::value&,
std::shared_ptr<OcrTaskInfo> default_ptr);
taskptr_t generate_hash_task_info(std::string_view name, const json::value&,
std::shared_ptr<HashTaskInfo> default_ptr);
// TaskInfo 的基础成员
bool append_base_task_info(taskptr_t task_info_ptr, std::string_view name, const json::value& task_json,
taskptr_t default_ptr, std::string_view task_prefix = "");
static std::string append_prefix(std::string_view task_name, std::string_view task_prefix)
{
if (task_prefix.ends_with('@')) [[unlikely]] {
task_prefix.remove_suffix(1);
}
if (task_prefix.empty()) [[unlikely]] {
return std::string(task_name);
}
if (task_name.empty()) {
return std::string(task_prefix);
}
if (task_name.starts_with('#')) {
return std::string(task_prefix) + std::string(task_name);
}
return std::string(task_prefix) + '@' + std::string(task_name);
}
static tasklist_t append_prefix(const tasklist_t& base_task_list, std::string_view task_prefix)
{
if (task_prefix.ends_with('@')) [[unlikely]] {
task_prefix.remove_suffix(1);
}
if (task_prefix.empty()) {
return base_task_list;
}
tasklist_t task_list = {};
for (const std::string& base : base_task_list) {
std::string_view base_view = base;
size_t l = 0;
bool has_same_prefix = false;
// base 任务里已经存在相同前缀,则不加前缀
// https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/2116#issuecomment-1270115238
for (size_t r = base_view.find('@'); r != std::string_view::npos; r = base_view.find('@', l)) {
if (task_prefix == base_view.substr(l, r - l)) [[unlikely]] {
has_same_prefix = true;
break;
}
l = r + 1;
}
task_list.emplace_back(has_same_prefix ? base : append_prefix(base_view, task_prefix));
}
return task_list;
};
// 运行时动态生成任务
static taskptr_t _generate_task_info(const taskptr_t& base_ptr)
{
if (!base_ptr) [[unlikely]] {
return nullptr;
}
switch (base_ptr->algorithm) {
case AlgorithmType::MatchTemplate:
return std::make_shared<MatchTaskInfo>(*std::dynamic_pointer_cast<MatchTaskInfo>(base_ptr));
case AlgorithmType::OcrDetect:
return std::make_shared<OcrTaskInfo>(*std::dynamic_pointer_cast<OcrTaskInfo>(base_ptr));
case AlgorithmType::Hash:
return std::make_shared<HashTaskInfo>(*std::dynamic_pointer_cast<HashTaskInfo>(base_ptr));
default:
return std::make_shared<TaskInfo>(*base_ptr);
}
}
static taskptr_t _generate_task_info(const taskptr_t& base_ptr, std::string_view task_prefix)
{
taskptr_t task_info_ptr = _generate_task_info(base_ptr);
if (!task_prefix.empty()) {
task_info_ptr->name = append_prefix(base_ptr->name, task_prefix);
task_info_ptr->sub = append_prefix(base_ptr->sub, task_prefix);
task_info_ptr->next = append_prefix(base_ptr->next, task_prefix);
task_info_ptr->exceeded_next = append_prefix(base_ptr->exceeded_next, task_prefix);
task_info_ptr->on_error_next = append_prefix(base_ptr->on_error_next, task_prefix);
task_info_ptr->reduce_other_times = append_prefix(base_ptr->reduce_other_times, task_prefix);
}
return task_info_ptr;
}
template <ranges::forward_range ListType>
requires(!std::same_as<ranges::range_value_t<ListType>, std::string> &&
requires { std::declval<ranges::range_value_t<ListType>>().as_string(); })
static tasklist_t to_string_list(const ListType& other_string_list)
static TaskList to_string_list(const ListType& other_string_list)
{
tasklist_t task_list = {};
TaskList task_list = {};
task_list.reserve(other_string_list.size());
ranges::copy(other_string_list | views::transform(&ranges::range_value_t<ListType>::as_string),
std::back_inserter(task_list));
return task_list;
}
static std::string_view task_name_view(std::string_view task_name)
{
return *m_task_names.emplace(task_name).first;
}
decltype(auto) insert_or_assign_raw_task(std::string_view task_name, taskptr_t task_info_ptr)
{
return m_raw_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr);
}
decltype(auto) insert_or_assign_task(std::string_view task_name, taskptr_t task_info_ptr)
{
return m_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr);
}
static inline std::unordered_set<std::string> m_task_names {};
static const std::string& task_name_view(std::string_view name) { return *m_task_names.emplace(name).first; }
struct RawCompileResult
{
bool task_changed;
TaskDataSymbol::Symbols symbols;
};
static ResultOrError<RawCompileResult> compile_raw_tasklist(const tasklist_t& raw_tasks,
std::string_view self_name,
std::function<taskptr_t(std::string_view)> get_raw,
bool allow_duplicate);
static ResultOrError<RawCompileResult> compile_raw_tasklist(
const TaskList& raw_tasks, std::string_view self_name,
std::function<TaskDerivedConstPtr(std::string_view)> get_raw, bool allow_duplicate);
private:
TaskPtr generate_task_info(std::string_view name);
TaskPtr generate_match_task_info(std::string_view name, const json::value&, MatchTaskConstPtr default_ptr,
TaskDerivedType derived_type);
TaskPtr generate_ocr_task_info(std::string_view name, const json::value&, OcrTaskConstPtr default_ptr);
TaskPtr generate_hash_task_info(std::string_view name, const json::value&, HashTaskConstPtr default_ptr);
decltype(auto) insert_or_assign_raw_task(std::string_view task_name, TaskDerivedPtr task_info_ptr)
{
return m_raw_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr);
}
decltype(auto) insert_or_assign_task(std::string_view task_name, TaskPtr task_info_ptr)
{
return m_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr);
}
struct CompileResult
{
bool task_changed;
tasklist_t tasks;
TaskList tasks;
};
ResultOrError<CompileResult> compile_tasklist(const tasklist_t& raw_tasks, std::string_view self_name,
ResultOrError<CompileResult> compile_tasklist(const TaskList& raw_tasks, std::string_view self_name,
bool allow_duplicate);
bool generate_task_and_its_base(std::string_view name, bool must_true);
bool generate_raw_task_info(std::string_view name, std::string_view prefix, std::string_view base_name,
const json::value& task_json, TaskDerivedType type);
bool generate_raw_task_and_base(std::string_view name, bool must_true);
#ifdef ASST_DEBUG
bool syntax_check(std::string_view task_name, const json::value& task_json);
#endif
taskptr_t get_raw(std::string_view name);
template <typename TargetTaskInfoType>
requires(std::derived_from<TargetTaskInfoType, TaskInfo> &&
!std::same_as<TargetTaskInfoType, TaskInfo>) // Parameter must be a TaskInfo
std::shared_ptr<TargetTaskInfoType> get_raw(std::string_view name)
{
return std::dynamic_pointer_cast<TargetTaskInfoType>(get_raw(name));
}
TaskDerivedConstPtr get_raw(std::string_view name);
public:
virtual ~TaskData() override = default;
@@ -180,21 +87,15 @@ namespace asst
void set_task_base(const std::string_view task_name, std::string base_task_name);
bool lazy_parse(const json::value& json);
taskptr_t get(std::string_view name);
TaskPtr get(std::string_view name);
template <typename TargetTaskInfoType>
requires(std::derived_from<TargetTaskInfoType, TaskInfo> &&
!std::same_as<TargetTaskInfoType, TaskInfo>) // Parameter must be a TaskInfo
std::shared_ptr<TargetTaskInfoType> get(std::string_view name)
{
// TODO: should be const
return std::dynamic_pointer_cast<TargetTaskInfoType>(get(name));
}
std::optional<json::object> get_json(std::string_view name) const
{
if (m_json_all_tasks_info.find(name) != m_json_all_tasks_info.cend())
return m_json_all_tasks_info.at(name);
else
return std::nullopt;
}
protected:
enum TaskStatus
@@ -207,12 +108,11 @@ namespace asst
virtual bool parse(const json::value& json) override;
static inline std::unordered_set<std::string> m_task_names;
std::unordered_set<std::string> m_templ_required;
std::unordered_map<std::string_view, TaskStatus> m_task_status;
std::unordered_map<std::string_view, json::object> m_json_all_tasks_info; // 原始的 json 信息
std::unordered_map<std::string_view, taskptr_t> m_raw_all_tasks_info; // 未展开虚任务的任务信息
std::unordered_map<std::string_view, taskptr_t> m_all_tasks_info; // 已展开虚任务的任务信息
std::unordered_map<std::string_view, json::object> m_json_all_tasks_info; // 原始的 json 信息
std::unordered_map<std::string_view, TaskDerivedPtr> m_raw_all_tasks_info; // 未展开虚任务的任务信息
std::unordered_map<std::string_view, TaskPtr> m_all_tasks_info; // 已展开虚任务的任务信息
};
inline static auto& Task = TaskData::get_instance();

View File

@@ -2,11 +2,10 @@
asst::TaskDataSymbol::SymbolsOrError asst::TaskDataSymbol::append_prefix(
const TaskDataSymbol& symbol, const TaskDataSymbol& prefix, std::string_view self_name,
std::function<std::shared_ptr<TaskInfo>(std::string_view)> get_raw,
std::function<SymbolsOrError(const std::vector<std::string>&)> compile_tasklist)
std::function<TaskDerivedConstPtr(std::string_view)> get_raw,
std::function<SymbolsOrError(const TaskList&)> compile_tasklist)
{
// !!!注意:
// A@#self 是 A 而不是 A@self_name, #self@A 是 selfname@A 而不是 A
// 注意:A@#self 是 A 而不是 A@self_name, #self@A 是 self_name@A 而不是 A
std::string_view prefix_name;
if (prefix == SharpSelf) {
prefix_name = self_name;

View File

@@ -5,9 +5,8 @@
#include <unordered_map>
#include <variant>
#include "TaskDataTypes.hpp"
#include "Common/AsstTypes.h"
#include "TaskDataTypes.h"
#include "Utils/Logger.hpp"
namespace asst
@@ -122,10 +121,10 @@ namespace asst
return pos == symbol_repr_to_type.end() ? Name : pos->second;
}
static SymbolsOrError append_prefix(
const TaskDataSymbol& symbol, const TaskDataSymbol& prefix, std::string_view self_name,
std::function<std::shared_ptr<TaskInfo>(std::string_view)> get_raw,
std::function<SymbolsOrError(const std::vector<std::string>&)> compile_tasklist);
static SymbolsOrError append_prefix(const TaskDataSymbol& symbol, const TaskDataSymbol& prefix,
std::string_view self_name,
std::function<TaskDerivedConstPtr(std::string_view)> get_raw,
std::function<SymbolsOrError(const TaskList&)> compile_tasklist);
bool is_name() const noexcept { return m_symbol == Name; }
bool is_sharp_type() const noexcept { return is_sharp_type(m_symbol); }

View File

@@ -149,12 +149,11 @@ asst::TaskDataSymbolStream::SymbolsOrError asst::TaskDataSymbolStream::decode(Ap
// self_name + #self ^ #self = #none
// self_name + #self ^ self_name = #self
if (ranges::any_of(y, [&](const auto& sy) { return sy == Symbol::SharpSelf; })) {
auto remove_ret = ranges::remove(x, self_name);
x.erase(remove_ret.begin(), remove_ret.end());
std::erase(x, self_name);
}
auto remove_ret = ranges::remove_if(
x, [&](const auto& sx) { return ranges::any_of(y, [&](const auto& sy) { return sx == sy; }); });
x.erase(remove_ret.begin(), remove_ret.end());
std::erase_if(x, [&](const auto& sx) {
return ranges::any_of(y, [&](const auto& sy) { return sx == sy; });
});
}
}
return x;
@@ -224,7 +223,7 @@ asst::TaskDataSymbolStream::SymbolsOrError asst::TaskDataSymbolStream::decode(Ap
auto opt = append_prefix(sy, sx);
if (!opt) {
return { std::nullopt,
"decode_vtasks: failed while " + sx.name() + " @ " + sy.name() + ", " + opt.what() };
"decode_vtasks: failed while " + sx.name() + " @ " + sy.name() + ", " + opt.error() };
}
ranges::copy(*opt, std::back_inserter(x));
}

View File

@@ -5,7 +5,7 @@
#include "Config/TaskData.h"
#include "TaskDataSymbol.h"
#include "TaskDataTypes.hpp"
#include "TaskDataTypes.h"
namespace asst
{

View File

@@ -37,9 +37,9 @@ namespace asst
constexpr ResultT&& value() && { return std::move(std::get<0>(m_result_or_error)); }
constexpr const ResultT&& value() const&& { return std::move(std::get<0>(m_result_or_error)); }
constexpr std::string& what() & { return std::get<1>(m_result_or_error); }
constexpr const std::string& what() const& { return std::get<1>(m_result_or_error); }
constexpr std::string&& what() && { return std::move(std::get<1>(m_result_or_error)); }
constexpr const std::string&& what() const&& { return std::move(std::get<1>(m_result_or_error)); }
constexpr std::string& error() & { return std::get<1>(m_result_or_error); }
constexpr const std::string& error() const& { return std::get<1>(m_result_or_error); }
constexpr std::string&& error() && { return std::move(std::get<1>(m_result_or_error)); }
constexpr const std::string&& error() const&& { return std::move(std::get<1>(m_result_or_error)); }
};
} // namespace asst

View File

@@ -50,7 +50,7 @@
<ClInclude Include="Config\OnnxSessions.h" />
<ClInclude Include="Config\TaskData\TaskDataSymbol.h" />
<ClInclude Include="Config\TaskData\TaskDataSymbolStream.h" />
<ClInclude Include="Config\TaskData\TaskDataTypes.hpp" />
<ClInclude Include="Config\TaskData\TaskDataTypes.h" />
<ClInclude Include="Controller\adb-lite\client.hpp" />
<ClInclude Include="Controller\adb-lite\protocol.hpp" />
<ClInclude Include="Controller\Controller.h" />

View File

@@ -690,7 +690,7 @@
<ClInclude Include="Config\TaskData\TaskDataSymbolStream.h">
<Filter>Source\Resource\TaskData</Filter>
</ClInclude>
<ClInclude Include="Config\TaskData\TaskDataTypes.hpp">
<ClInclude Include="Config\TaskData\TaskDataTypes.h">
<Filter>Source\Resource\TaskData</Filter>
</ClInclude>
</ItemGroup>