Skip to content

Commit

Permalink
参数规范文件支持自定义枚举类型
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoxi-scut committed Jun 22, 2024
1 parent 5ea3cb6 commit 9cc8a5e
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 79 deletions.
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

0 comments on commit 9cc8a5e

Please sign in to comment.