Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

参数规范文件支持自定义枚举类型 #99

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 185 additions & 78 deletions cmake/RMVLGenPara.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function(system_date out_y out_m out_d)
endfunction()

# ----------------------------------------------------------------------------
# 修正类型符号: 增加作用域
# 修正类型符号: 增加 C++ 的作用域
# string -> std::string vector -> std::vector
# Point... -> cv::Point... Matx... -> cv::Matx...
# 用法:
Expand All @@ -59,41 +59,159 @@ endfunction()
# ----------------------------------------------------------------------------
function(_type_correct value_type out_value_type)
set(retval ${value_type})
string(REGEX REPLACE "string" "std::string" retval "${retval}")
string(REGEX REPLACE "vector" "std::vector" retval "${retval}")
string(REGEX REPLACE "Point" "cv::Point" retval "${retval}")
string(REGEX REPLACE "Vec" "cv::Vec" retval "${retval}")
string(REGEX REPLACE "Mat" "cv::Mat" retval "${retval}")
string(REGEX REPLACE "([^\\.])51f" "\\1<float, 5, 1>" retval "${retval}")
string(REGEX REPLACE "([^\\.])51d" "\\1<double, 5, 1>" retval "${retval}")
string(REGEX REPLACE "([^\\.])15f" "\\1<float, 1, 5>" retval "${retval}")
string(REGEX REPLACE "([^\\.])15d" "\\1<double, 1, 5>" retval "${retval}")
string(REGEX REPLACE "([^\\.])61f" "\\1<float, 6, 1>" retval "${retval}")
string(REGEX REPLACE "([^\\.])61d" "\\1<double, 6, 1>" retval "${retval}")
string(REGEX REPLACE "([^\\.])16f" "\\1<float, 1, 6>" retval "${retval}")
string(REGEX REPLACE "([^\\.])16d" "\\1<double, 1, 6>" retval "${retval}")
string(REGEX REPLACE "(size_t|string|vector)" "std::\\1" retval "${retval}")
string(REGEX REPLACE "(Point|Vec|Mat)" "cv::\\1" retval "${retval}")
string(REGEX REPLACE "Matx([1-9])([1-9])f" "Matx<float,\\1,\\2>" retval "${retval}")
string(REGEX REPLACE "Matx([1-9])([1-9])d" "Matx<double,\\1,\\2>" retval "${retval}")
string(REGEX REPLACE "Vec([1-9])f" "Vec<float,\\1>" retval "${retval}")
string(REGEX REPLACE "Vec([1-9])d" "Vec<double,\\1>" retval "${retval}")
set(${out_value_type} ${retval} PARENT_SCOPE)
endfunction()

# ----------------------------------------------------------------------------
# 按照常规的赋值模式解析参数规范文件的某一行内容
# 用法:
# _parse_assign(
# <line_str> <header> <source>
# )
# 示例:
# _parse_assign(
# line_str # 传入字符串: 一行的内容
# ret_header # 传出字符串: 头文件内容
# ret_source # 传出字符串: 源文件内容
# )
# ----------------------------------------------------------------------------
function(_parse_assign content_line header_line source_line)
list(LENGTH ${content_line} l)
if(l GREATER 1)
# get value type symbol
list(GET ${content_line} 0 type_sym)
# correct the value type
_type_correct("${type_sym}" type_sym_correct)
# get id symbol
list(GET ${content_line} 1 id_sym)
# get default value and comment
if(l GREATER 2)
list(SUBLIST ${content_line} 2 -1 default_cmt)
else()
set(default_cmt "")
endif()
string(REGEX REPLACE ";" "" default_cmt "${default_cmt}")
# split default value and comment
string(FIND "${default_cmt}" "#" cmt_idx)
if(cmt_idx EQUAL -1)
set(default_sym "${default_cmt}")
set(comment_sym "${id_sym}")
else()
string(SUBSTRING "${default_cmt}" 0 ${cmt_idx} default_sym)
math(EXPR cmt_idx "${cmt_idx} + 1")
string(SUBSTRING "${default_cmt}" ${cmt_idx} -1 comment_sym)
endif()
# add default value to comment
if(NOT default_sym STREQUAL "")
set(comment_sym "${comment_sym} @note 默认值:`${default_sym}`")
endif()
# correct default_sym
if(NOT type_sym STREQUAL "string")
_type_correct("${default_sym}" default_sym)
string(REGEX REPLACE "," ", " default_sym "${default_sym}")
endif()
else()
return()
endif()
# get return value (header)
set(ret_header_line "${ret_header_line} //! ${comment_sym}\n")
if("${default_sym}" STREQUAL "")
set(ret_header_line "${ret_header_line} ${type_sym_correct} ${id_sym}{};\n")
else()
set(ret_header_line "${ret_header_line} ${type_sym_correct} ${id_sym} = ${default_sym};\n")
endif()
# get return value (source)
set(ret_source_line "${ret_source_line} node = fs[\"${id_sym}\"];\n")
if(type_sym MATCHES "^uint\\w*|size_t")
set(ret_source_line "${ret_source_line} if (!node.isNone())\n {\n")
set(ret_source_line "${ret_source_line} int tmp{};\n node >> tmp;\n")
set(ret_source_line "${ret_source_line} ${id_sym} = static_cast<${type_sym_correct}>(tmp);\n }\n")
elseif(type_sym MATCHES "int|float|double|string|vector|Point\\w*|Mat\\w*|Vec\\w*")
set(ret_source_line "${ret_source_line} node.isNone() ? void(0) : (node >> ${id_sym});\n")
else() # enum type
set(ret_source_line "${ret_source_line} if (!node.isNone())\n {\n")
set(ret_source_line "${ret_source_line} std::string tmp{};\n node >> tmp;\n")
set(ret_source_line "${ret_source_line} ${id_sym} = map_${type_sym}.at(tmp);\n }\n")
endif()
# return to parent scope
set(${header_line} "${ret_header_line}" PARENT_SCOPE)
set(${source_line} "${ret_source_line}" PARENT_SCOPE)
endfunction()

# ----------------------------------------------------------------------------
# 按照枚举定义模式解析参数规范文件的某一行内容
# 用法:
# _parse_enumdef(
# <line_str> <name of the enum> <header_extra_line> <source_extra_line>
# )
# 示例:
# _parse_enumdef(
# line_str # [in] 一行的内容
# enum_name # [in] 枚举名称
# header_extra_line # [out] 头文件额外内容
# source_extra_line # [out] 源文件额外内容
# )
# ----------------------------------------------------------------------------
function(_parse_enumdef content_line enum_name header_extra_line source_extra_line)
list(LENGTH ${content_line} l)
# get tag symbol
list(GET ${content_line} 0 tag_sym)
# get ref value and comment
if(l GREATER 1)
list(SUBLIST ${content_line} 1 -1 ref_cmt)
else()
set(ref_cmt "")
endif()
string(REGEX REPLACE ";" "" ref_cmt "${ref_cmt}")
# split ref value and comment
string(FIND "${ref_cmt}" "#" cmt_idx)
if(cmt_idx EQUAL -1)
set(ref_sym "${ref_cmt}")
set(comment_sym "${tag_sym}")
else()
string(SUBSTRING "${ref_cmt}" 0 ${cmt_idx} ref_sym)
math(EXPR cmt_idx "${cmt_idx} + 1")
string(SUBSTRING "${ref_cmt}" ${cmt_idx} -1 comment_sym)
endif()
# get return value (extra header)
set(ret_header_extra_line " //! ${comment_sym}\n")
if("${ref_sym}" STREQUAL "")
set(ret_header_extra_line "${ret_header_extra_line} ${tag_sym},\n")
else()
set(ret_header_extra_line "${ret_header_extra_line} ${tag_sym} = ${ref_sym},\n")
endif()
# get return value (extra source)
set(ret_source_extra_line " {\"${tag_sym}\", ${enum_name}::${tag_sym}},\n")
# return to parent scope
set(${header_extra_line} "${ret_header_extra_line}" PARENT_SCOPE)
set(${source_extra_line} "${ret_source_extra_line}" PARENT_SCOPE)
endfunction()

# ----------------------------------------------------------------------------
# 将指定的 *.para 参数规范文件解析成 C++ 风格的内容
# 用法:
# _para_parser(
# <file_name>
# <header_details> <source_details>
# <header_details> <header_extra> <source_details>
# )
# 示例:
# _para_parser(
# core.para # 名为 core.para 的参数规范文件
# core_header_details # 对应 .h/.hpp 文件的细节
# core_source_details # 对应 .cpp 文件的实现细节
# para_header_details # 对应 .h/.hpp 文件的细节
# para_header_extra # 对应 .h/.hpp 文件的额外细节
# para_source_details # 对应 .cpp 文件的实现细节
# para_source_extra # 对应 .cpp 文件的额外实现细节
# status # 返回值: 解析是否成功,成功返回 TRUE,失败返回 FALSE
# )
# ----------------------------------------------------------------------------
function(_para_parser file_name header_details source_details status)
function(_para_parser file_name header_details header_extra source_details source_extra status)
# init
set(ret_header "")
set(ret_source "")
file(READ ${file_name} out_val)
if(NOT out_val)
set(${status} FALSE PARENT_SCOPE)
Expand All @@ -102,72 +220,58 @@ function(_para_parser file_name header_details source_details status)
string(REGEX REPLACE "\n" ";" out_val "${out_val}")
# parser each line
foreach(substr ${out_val})
# get substring: line_str
################ get subing: line_str ################
string(REGEX REPLACE "[ =]" ";" line_str "${substr}")
set(tmp)
foreach(word ${line_str})
list(APPEND tmp "${word}")
endforeach()
set(line_str ${tmp})
unset(tmp)
# parser
list(LENGTH line_str l)
if(l GREATER 1)
# get value type symbol
list(GET line_str 0 type_sym)
if(type_sym MATCHES "^#")
continue()
endif()
# correct the value type
_type_correct("${type_sym}" type_sym)
# get id symbol
list(GET line_str 1 id_sym)
# get default value and comment
list(SUBLIST line_str 2 -1 default_cmt)
string(REGEX REPLACE ";" "" default_cmt "${default_cmt}")
# split default value and comment
string(FIND "${default_cmt}" "#" cmt_idx)
# parser mode
if(line_str MATCHES "^enum")
list(GET line_str 1 enum_name)
string(REGEX REPLACE ";" "" enum_cmt "${line_str}")
# find comment of enum
string(FIND "${enum_cmt}" "#" cmt_idx)
if(cmt_idx EQUAL -1)
set(default_sym "${default_cmt}")
set(comment_sym "${id_sym}")
set(enum_cmt "${enum_name} 枚举类型")
else()
string(SUBSTRING "${default_cmt}" 0 ${cmt_idx} default_sym)
math(EXPR cmt_idx "${cmt_idx} + 1")
string(SUBSTRING "${default_cmt}" ${cmt_idx} -1 comment_sym)
string(SUBSTRING "${enum_cmt}" ${cmt_idx} -1 enum_cmt)
endif()
# add default value to comment
if(NOT default_sym STREQUAL "")
set(comment_sym "${comment_sym} @note 默认值:`${default_sym}`")
endif()
# correct default_sym
if(NOT type_sym STREQUAL "std::string")
_type_correct("${default_sym}" default_sym)
string(REGEX REPLACE "," ", " default_sym "${default_sym}")
endif()
else()
set(ret_header_extra "${ret_header_extra}//! ${enum_cmt}\nenum class ${enum_name}\n{\n")
set(ret_source_extra "${ret_source_extra}static const std::unordered_map<std::string, ${enum_name}> map_${enum_name} = {\n")
set(parse_mode "enum")
continue()
elseif(line_str MATCHES "^endenum")
set(ret_header_extra "${ret_header_extra}};\n")
set(ret_source_extra "${ret_source_extra}};\n")
unset(parse_mode)
continue()
endif()
# get return value (header)
set(ret_header "${ret_header} //! ${comment_sym}\n")
if("${default_sym}" STREQUAL "")
set(ret_header "${ret_header} ${type_sym} ${id_sym}{};\n")
else()
set(ret_header "${ret_header} ${type_sym} ${id_sym} = ${default_sym};\n")
endif()
# get return value (source)
set(ret_source "${ret_source} node = fs[\"${id_sym}\"];\n")
if(type_sym MATCHES "uint" OR type_sym STREQUAL "size_t")
set(ret_source "${ret_source} if (!node.isNone())\n {\n")
set(ret_source "${ret_source} int tmp_${id_sym}{};\n node >> tmp_${id_sym};\n")
set(ret_source "${ret_source} ${id_sym} = static_cast<${type_sym}>(tmp_${id_sym});\n }\n")
# parser
unset(ret_header_extra_line)
unset(ret_header_line)
unset(ret_source_line)
if(line_str MATCHES "^#")
continue()
elseif("${parse_mode}" STREQUAL "enum")
_parse_enumdef(line_str "${enum_name}" ret_header_extra_line ret_source_extra_line)
set(ret_header_extra "${ret_header_extra}${ret_header_extra_line}")
set(ret_source_extra "${ret_source_extra}${ret_source_extra_line}")
else()
set(ret_source "${ret_source} node.isNone() ? void(0) : (node >> ${id_sym});\n")
_parse_assign(line_str ret_header_line ret_source_line)
set(ret_header "${ret_header}${ret_header_line}")
set(ret_source "${ret_source}${ret_source_line}")
endif()
endforeach(substr ${out_val})
set(${header_details} "${ret_header}" PARENT_SCOPE)
set(${header_extra} "${ret_header_extra}" PARENT_SCOPE)
set(${source_details} "${ret_source}" PARENT_SCOPE)
set(${source_extra} "${ret_source_extra}" PARENT_SCOPE)
set(${status} TRUE PARENT_SCOPE)
endfunction(_para_parser file_name header_details source_details)
endfunction()

# ----------------------------------------------------------------------------
# 根据指定的目标名在 param 文件夹下对应的 *.para 参数规范文件和可选的模块名生成对应的 C++ 代码
Expand Down Expand Up @@ -195,7 +299,7 @@ function(rmvl_generate_para target_name)
set(para_msg "Performing Conversion ${target_name}.para")
message(STATUS "${para_msg}")
if(DEFINED BUILD_${the_module}_INIT AND NOT BUILD_${the_module}_INIT)
message(STATUS "Performing Conversion ${target_name}.para - skipped")
message(STATUS "${para_msg} - skipped")
return()
endif()
################## snake to camel (get class name) ##################
Expand All @@ -215,25 +319,28 @@ function(rmvl_generate_para target_name)
set(RMVLPARA_${module_name} "${RMVLPARA_${module_name}}" "${target_name}" CACHE INTERNAL "${module_name} parameters")
endif()
# parser
_para_parser(${file_name} para_header_details para_source_details para_status)
_para_parser(
${file_name}
para_header_details para_header_extra
para_source_details para_source_extra
para_status
)
if(NOT para_status)
message(STATUS "${para_msg} - failed")
return()
endif()
set(para_include_path)
# has module
if(PARA_MODULE)
set(header_ext "h")
set(para_include_path "rmvlpara/${module_name}/${target_name}.${header_ext}")
set(para_include_path "rmvlpara/${module_name}/${target_name}.h")
configure_file(
${para_template_path}/para_generator_source.in
${CMAKE_CURRENT_LIST_DIR}/src/${target_name}/para/param.cpp
@ONLY
)
# dosen't have module
else()
set(header_ext "hpp")
set(para_include_path "rmvlpara/${module_name}.${header_ext}")
set(para_include_path "rmvlpara/${module_name}.hpp")
configure_file(
${para_template_path}/para_generator_source.in
${CMAKE_CURRENT_LIST_DIR}/src/para/param.cpp
Expand All @@ -253,7 +360,7 @@ function(rmvl_generate_para target_name)
unset(para_include_path)
############################ message end ############################
message(STATUS "${para_msg} - done")
endfunction(rmvl_generate_para target_name)
endfunction()

# ----------------------------------------------------------------------------
# 根据给定模块下所有的 para 目标,生成对应的 C++ 代码
Expand All @@ -272,10 +379,10 @@ function(rmvl_generate_module_para module_name)
system_date(year month day)
set(para_module_header_details "")
foreach(_sub ${RMVLPARA_${module_name}})
string(TOUPPER "${_sub}" upper)
set(para_module_header_details "${para_module_header_details}\n#ifdef HAVE_RMVL_${upper}\n")
string(TOUPPER "${_sub}" _upper)
set(para_module_header_details "${para_module_header_details}\n#ifdef HAVE_RMVL_${_upper}\n")
set(para_module_header_details "${para_module_header_details}#include \"${module_name}/${_sub}.h\"\n")
set(para_module_header_details "${para_module_header_details}#endif // HAVE_RMVL_${upper}\n")
set(para_module_header_details "${para_module_header_details}#endif // HAVE_RMVL_${_upper}\n")
endforeach()
# generate C++ file
configure_file(
Expand All @@ -285,4 +392,4 @@ function(rmvl_generate_module_para module_name)
)
############################ message end ############################
message(STATUS "${para_msg} - done")
endfunction(rmvl_generate_module_para module_name)
endfunction()
5 changes: 5 additions & 0 deletions cmake/templates/para_generator_header.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ namespace rm::para
//! @addtogroup para_@module_name@
//! @{

////////////////////// 扩展部分 //////////////////////

@para_header_extra@
////////////////////// 参数部分 //////////////////////

//! @class_name@ 参数模块
struct @class_name@
{
Expand Down
3 changes: 2 additions & 1 deletion cmake/templates/para_generator_source.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
namespace rm::para
{

@para_source_extra@
bool @class_name@::load(const std::string &path)
{
cv::FileStorage fs(path, cv::FileStorage::READ);
if(!fs.isOpened())
if (!fs.isOpened())
return false;
cv::FileNode node;

Expand Down
Loading