From ce5b2c6a45a4f41fa8d2231036ca052dfe2d35fb Mon Sep 17 00:00:00 2001 From: River Li Date: Mon, 20 Jun 2022 08:22:39 +0800 Subject: [PATCH] Refine ov_partial_shape for OV API 2.0 C interface (#11891) * Refine ov_partial_shape for OV 2.0 C interface To avoid potential string security problem, remove string pointer from ov_partial_shape structure. * Remove redundant code * fix typo issue * fix shape test issue * fix some minor issues * Address reviewing comments Use Dimension to represent rank of parital shape. * Appy safer method to parse partialShape string 1. adopt ov::Dimension::value_type to construct ov::Dimension 2. safter method to convert string to dimension value 3. apply std::vector to replace std::vector during pasrsing partialShape string Change-Id: I0e0b70a915fc5c5fefad51de51f167798854f55e --- samples/c/hello_classification_ov/main.c | 6 +- src/bindings/c/ov/include/c_api/ov_c_api.h | 56 +++--- src/bindings/c/ov/src/ov_c_api.cpp | 192 +++++++++++++-------- src/bindings/c/ov/tests/ov_c_api_test.cpp | 157 +++++++++++------ 4 files changed, 259 insertions(+), 152 deletions(-) diff --git a/samples/c/hello_classification_ov/main.c b/samples/c/hello_classification_ov/main.c index b5f8f395d2c..372921c75c0 100644 --- a/samples/c/hello_classification_ov/main.c +++ b/samples/c/hello_classification_ov/main.c @@ -133,8 +133,8 @@ int main(int argc, char** argv) { ov_version_t version; CHECK_STATUS(ov_get_version(&version)); printf("---- OpenVINO INFO----\n"); - printf("description : %s \n", version.description); - printf("build number: %s \n", version.buildNumber); + printf("Description : %s \n", version.description); + printf("Build number: %s \n", version.buildNumber); ov_version_free(&version); // -------- Parsing and validation of input arguments -------- @@ -167,7 +167,7 @@ int main(int argc, char** argv) { c_mat_t img; image_read(input_image_path, &img); ov_element_type_e input_type = U8; - ov_shape_t input_shape = {1, (size_t)img.mat_height, (size_t)img.mat_width, 3}; + ov_shape_t input_shape = {4, {1, (size_t)img.mat_height, (size_t)img.mat_width, 3}}; CHECK_STATUS(ov_tensor_create_from_host_ptr(input_type, input_shape, img.mat_data, &tensor)); // -------- Step 4. Configure preprocessing -------- diff --git a/src/bindings/c/ov/include/c_api/ov_c_api.h b/src/bindings/c/ov/include/c_api/ov_c_api.h index e235ce19e6e..9fb46419046 100644 --- a/src/bindings/c/ov/include/c_api/ov_c_api.h +++ b/src/bindings/c/ov/include/c_api/ov_c_api.h @@ -278,25 +278,42 @@ typedef char ov_layout_t[MAX_DIMENSION]; * @struct ov_shape_t */ typedef struct { - int ranks; + size_t rank; size_t dims[MAX_DIMENSION]; } ov_shape_t; /** - * @struct ov_PartialShape_t + * @struct ov_partial_shape_t + * brief Class representing a shape that may be partially or totally dynamic. + * + * A PartialShape may have: + * Dynamic rank. (Informal notation: `?`) + * Static rank, but dynamic dimensions on some or all axes. + * (Informal notation examples: `{1,2,?,4}`, `{?,?,?}`) + * Static rank, and static dimensions on all axes. + * (Informal notation examples: `{1,2,3,4}`, `{6}`, `{}`) + * + * An interface to make user can initialize ov_partial_shape_t */ -typedef struct { - int ranks; - const char *dims[MAX_DIMENSION]; -} ov_partial_shape_t; +typedef struct ov_partial_shape ov_partial_shape_t; /** * @enum ov_performance_mode_e * @brief Enum to define possible performance mode hints * @brief This represents OpenVINO 2.0 ov::hint::PerformanceMode entity. + * It is same with enum class ov::hint::PerformanceMode as below: + * + * enum class PerformanceMode { + * UNDEFINED = -1, //!< Undefined value, performance setting may vary from device to device + * LATENCY = 1, //!< Optimize for latency + * THROUGHPUT = 2, //!< Optimize for throughput + * CUMULATIVE_THROUGHPUT = 3, //!< Optimize for cumulative throughput + * }; + * + * There also is a map in C implement to keep it aligned with C++ definition. */ typedef enum { - UNDEFINED_MODE = -1, //!< Undefined value, performance setting may vary from device to device + UNDEFINED_MODE = -1, //!< Undefined value, performance setting may vary from device to device LATENCY = 1, //!< Optimize for latency THROUGHPUT = 2, //!< Optimize for throughput CUMULATIVE_THROUGHPUT = 3, //!< Optimize for cumulative throughput @@ -349,9 +366,17 @@ typedef struct ov_property{ /** * @brief Initialize a partial shape. + * @param str is the input partial info string + * Dynamic rank: + * Example: "?" + * Static rank, but dynamic dimensions on some or all axes. + * Examples: "{1,2,?,4}" or "{?,?,?}" or "{1,2,-1,4}"" + * Static rank, and static dimensions on all axes. + * Examples: "{1,2,3,4}" or "{6}" or "{}"" + * * @param ov_status_e a status code. */ -OPENVINO_C_API(ov_status_e) ov_partial_shape_init(ov_partial_shape_t* partial_shape, const char* str); +OPENVINO_C_API(ov_status_e) ov_partial_shape_init(ov_partial_shape_t** partial_shape, const char* str); /** * @brief Parse the partial shape to readable string. @@ -509,14 +534,6 @@ OPENVINO_C_API(ov_status_e) ov_core_get_property(const ov_core_t* core, const ch const ov_property_key_e property_name, ov_property_value* property_value); -/** - * @brief Registers an extension to a Core object. - * @param core A pointer to the ie_core_t instance. - * @param library_path Path to the library with ov::Extension. - * @return Status code of the operation: OK(0) for success. - */ -OPENVINO_C_API(ov_status_e) ov_core_add_extension(const ov_core_t* core, const char* library_path); - /** * @brief Returns devices available for inference. * @param core A pointer to the ie_core_t instance. @@ -646,9 +663,8 @@ OPENVINO_C_API(bool) ov_model_is_dynamic(const ov_model_t* model); * @param tensor_name input tensor name (char *). * @param partialShape A PartialShape. */ -OPENVINO_C_API(ov_status_e) ov_model_reshape(const ov_model_t* model, - const char* tensor_name, - const ov_partial_shape_t partial_shape); +OPENVINO_C_API(ov_status_e) +ov_model_reshape(const ov_model_t* model, const char* tensor_name, const ov_partial_shape_t* partial_shape); /** * @brief Gets the friendly name for a model. @@ -673,7 +689,7 @@ OPENVINO_C_API(void) ov_output_node_free(ov_output_node_t *output_node); * @brief free char * @param content The pointer to the char to free. */ -OPENVINO_C_API(void) ov_free(char *content); +OPENVINO_C_API(void) ov_free(const char *content); /** * @brief Create a ov_preprocess_t instance. diff --git a/src/bindings/c/ov/src/ov_c_api.cpp b/src/bindings/c/ov/src/ov_c_api.cpp index 55985af746d..9e0c61ec339 100644 --- a/src/bindings/c/ov/src/ov_c_api.cpp +++ b/src/bindings/c/ov/src/ov_c_api.cpp @@ -76,6 +76,11 @@ struct ov_tensor { std::shared_ptr object; }; +struct ov_partial_shape { + ov::Dimension rank; // Support static rank and dynamic rank + std::vector dims; // Dimemsion vector +}; + /** * @variable global value for error info */ @@ -554,7 +559,7 @@ ov_status_e ov_node_get_tensor_shape(ov_output_node_list_t* nodes, size_t idx, if (shape.size() > MAX_DIMENSION) { return ov_status_e::GENERAL_ERROR; } - tensor_shape->ranks = shape.size(); + tensor_shape->rank = shape.size(); std::copy_n(shape.begin(), shape.size(), tensor_shape->dims); } CATCH_OV_EXCEPTIONS @@ -592,7 +597,7 @@ ov_status_e ov_model_get_input_by_name(const ov_model_t* model, ov_status_e ov_model_get_input_by_id(const ov_model_t* model, const size_t index, ov_output_node_t **input_node) { - if (!model || index < 0 || !input_node) { + if (!model || !input_node) { return ov_status_e::GENERAL_ERROR; } try { @@ -611,35 +616,75 @@ bool ov_model_is_dynamic(const ov_model_t* model) { return model->object->is_dynamic(); } -std::vector split(std::string s) { - std::vector result; - std::regex delimiter("[,]"); - std::sregex_token_iterator tokens(s.cbegin(), s.cend(), delimiter, -1); - std::sregex_token_iterator end; - for (; tokens != end; ++tokens) { - result.push_back(str_to_char_array(*tokens)); +std::vector split_to_dims(const std::string& partial_shape_str) { + std::vector result; + + std::regex delimiter("[^{},]+"); + auto words_begin = std::sregex_iterator(partial_shape_str.begin(), partial_shape_str.end(), delimiter); + auto words_end = std::sregex_iterator(); + for (auto iter = words_begin; iter != words_end; ++iter) { + result.push_back(iter->str()); } return result; } -ov_status_e ov_partial_shape_init(ov_partial_shape_t* partial_shape, const char* str) { - if (!partial_shape || !str) { +template +T str_to_value(const std::string& str) { + T ret{0}; + std::istringstream ss(str); + if (!ss.eof()) { + ss >> ret; + } + return ret; +} + +ov_status_e ov_partial_shape_init(ov_partial_shape_t** partial_shape_obj, const char* str) { + *partial_shape_obj = nullptr; + if (!str) { return ov_status_e::GENERAL_ERROR; } + ov_partial_shape_t* partial_shape = nullptr; try { std::string s = str; - std::regex reg("[^,0-9.?][^\\-1]"); + std::regex reg("[^,0-9.?}{}][^\\-1]"); bool res = std::regex_search(s, reg); if (res) { return ov_status_e::PARAMETER_MISMATCH; } - std::vector result = split(s); - partial_shape->ranks = result.size(); - if (partial_shape->ranks > MAX_DIMENSION) { - return ov_status_e::GENERAL_ERROR; + + partial_shape = new ov_partial_shape_t; + if (s == "?") { // dynamic rank + partial_shape->rank = ov::Dimension::dynamic(); + } else { // static rank + std::vector result = split_to_dims(s); + using value_type = ov::Dimension::value_type; + size_t cnt = result.size(); + if (cnt > MAX_DIMENSION) { + delete partial_shape; + return ov_status_e::GENERAL_ERROR; + } + partial_shape->rank = ov::Dimension(cnt); + for (auto& dim : result) { + if (dim == "?" || dim == "-1") { + partial_shape->dims.emplace_back(ov::Dimension::dynamic()); + } else { + const std::string range_divider = ".."; + size_t range_index = dim.find(range_divider); + if (range_index != std::string::npos) { + std::string min_str = dim.substr(0, range_index); + std::string max_str = dim.substr(range_index + range_divider.length()); + value_type min = min_str.empty() ? 0 : str_to_value(min_str); + value_type max = max_str.empty() ? -1 : str_to_value(max_str); + partial_shape->dims.emplace_back(min, max); + } else { + partial_shape->dims.emplace_back(str_to_value(dim)); + } + } + } } - std::copy_n(result.begin(), result.size(), partial_shape->dims); - } CATCH_OV_EXCEPTIONS + } + CATCH_OV_EXCEPTIONS + *partial_shape_obj = partial_shape; return ov_status_e::OK; } @@ -647,13 +692,28 @@ const char* ov_partial_shape_parse(ov_partial_shape_t* partial_shape) { if (!partial_shape) { return str_to_char_array("error"); } - std::string str; - for (int i = 0; i < partial_shape->ranks; ++i) { - std::string tmp = partial_shape->dims[i]; - str += tmp; - if (i != partial_shape->ranks - 1) + + // dynamic rank + if (partial_shape->rank.is_dynamic()) { + return str_to_char_array("?"); + } + + // static rank + auto rank = partial_shape->rank.get_length(); + if (rank != partial_shape->dims.size()) { + return str_to_char_array("rank error"); + } + std::string str = std::string("{"); + int i = 0; + for (auto& item : partial_shape->dims) { + std::ostringstream out; + out.str(""); + out << item; + str += out.str(); + if (i++ < rank - 1) str += ","; } + str += std::string("}"); const char* res = str_to_char_array(str); return res; } @@ -662,57 +722,44 @@ ov_status_e ov_partial_shape_to_shape(ov_partial_shape_t* partial_shape, ov_shap if (!partial_shape || !shape) { return ov_status_e::GENERAL_ERROR; } + try { - std::vector tmp_shape; - std::regex reg("[^0-9,]"); - auto tmp = ov_partial_shape_parse(partial_shape); - std::string dim(tmp); - bool res = std::regex_search(dim, reg); - if (res) { + if (partial_shape->rank.is_dynamic()) { return ov_status_e::PARAMETER_MISMATCH; } - for (int i = 0; i < partial_shape->ranks; ++i) { - shape->dims[i] = std::stoi(partial_shape->dims[i]); + auto rank = partial_shape->rank.get_length(); + if (rank > MAX_DIMENSION) { + return ov_status_e::PARAMETER_MISMATCH; } - shape->ranks = partial_shape->ranks; - delete tmp; - } CATCH_OV_EXCEPTIONS + for (auto i = 0; i < rank; ++i) { + auto& ov_dim = partial_shape->dims[i]; + if (ov_dim.is_static()) + shape->dims[i] = ov_dim.get_length(); + else + return ov_status_e::PARAMETER_MISMATCH; + } + shape->rank = rank; + } + CATCH_OV_EXCEPTIONS return ov_status_e::OK; } - ov_status_e ov_model_reshape(const ov_model_t* model, - const char* tensor_name, - const ov_partial_shape_t partial_shape) { - if (!model || !tensor_name) { + const char* tensor_name, + const ov_partial_shape_t* partial_shape) { + if (!model || !tensor_name || !partial_shape) { return ov_status_e::GENERAL_ERROR; } try { - std::vector shape; - for (int i = 0; i < partial_shape.ranks; i++) { - if (!partial_shape.dims[i]) - return ov_status_e::GENERAL_ERROR; - std::string dim = partial_shape.dims[i]; - if (dim == "?" || dim == "-1") { - shape.push_back(ov::Dimension::dynamic()); - } else { - const std::string range_divider = ".."; - size_t range_index = dim.find(range_divider); - if (range_index != std::string::npos) { - std::string min = dim.substr(0, range_index); - std::string max = dim.substr(range_index + range_divider.length()); - shape.emplace_back(min.empty() ? 0 : std::stoi(min), - max.empty() ? ngraph::Interval::s_max : std::stoi(max)); - } else { - shape.emplace_back(std::stoi(dim)); - } - } + std::map in_shape; + if (partial_shape->rank.is_static() && (partial_shape->rank.get_length() == partial_shape->dims.size())) { + in_shape[tensor_name] = partial_shape->dims; + } else { + return ov_status_e::PARAMETER_MISMATCH; } - - std::map const_pshape; - const_pshape[tensor_name] = shape; - model->object->reshape(const_pshape); - } CATCH_OV_EXCEPTIONS + model->object->reshape(in_shape); + } + CATCH_OV_EXCEPTIONS return ov_status_e::OK; } @@ -738,17 +785,14 @@ void ov_output_node_free(ov_output_node_t *output_node) { delete output_node; } -void ov_free(char *content) { - delete content; +void ov_free(const char *content) { + if (content) + delete content; } void ov_partial_shape_free(ov_partial_shape_t* partial_shape) { - if (partial_shape) { - std::for_each(&partial_shape->dims[0], - &partial_shape->dims[partial_shape->ranks], - [](const char* n){ delete [] n; }); - partial_shape->ranks = 0; - } + if (partial_shape) + delete partial_shape; } ov_status_e ov_preprocess_create(const ov_model_t* model, @@ -1334,7 +1378,7 @@ ov_status_e ov_tensor_create(const ov_element_type_e type, const ov_shape_t shap *tensor = new ov_tensor_t; auto tmp_type = GET_OV_ELEMENT_TYPE(type); ov::Shape tmp_shape; - std::copy_n(shape.dims, shape.ranks, std::back_inserter(tmp_shape)); + std::copy_n(shape.dims, shape.rank, std::back_inserter(tmp_shape)); (*tensor)->object = std::make_shared(tmp_type, tmp_shape); } CATCH_OV_EXCEPTIONS return ov_status_e::OK; @@ -1349,7 +1393,7 @@ ov_status_e ov_tensor_create_from_host_ptr(const ov_element_type_e type, const o *tensor = new ov_tensor_t; auto tmp_type = GET_OV_ELEMENT_TYPE(type); ov::Shape tmp_shape; - std::copy_n(shape.dims, shape.ranks, std::back_inserter(tmp_shape)); + std::copy_n(shape.dims, shape.rank, std::back_inserter(tmp_shape)); (*tensor)->object = std::make_shared(tmp_type, tmp_shape, host_ptr); } CATCH_OV_EXCEPTIONS return ov_status_e::OK; @@ -1361,7 +1405,7 @@ ov_status_e ov_tensor_set_shape(ov_tensor_t* tensor, const ov_shape_t shape) { } try { ov::Shape tmp_shape; - std::copy_n(shape.dims, shape.ranks, std::back_inserter(tmp_shape)); + std::copy_n(shape.dims, shape.rank, std::back_inserter(tmp_shape)); tensor->object->set_shape(tmp_shape); } CATCH_OV_EXCEPTIONS return ov_status_e::OK; @@ -1376,7 +1420,7 @@ ov_status_e ov_tensor_get_shape(const ov_tensor_t* tensor, ov_shape_t* shape) { if (tmp_shape.size() > MAX_DIMENSION) { return ov_status_e::GENERAL_ERROR; } - shape->ranks = tmp_shape.size(); + shape->rank = tmp_shape.size(); std::copy_n(tmp_shape.begin(), tmp_shape.size(), shape->dims); } CATCH_OV_EXCEPTIONS return ov_status_e::OK; diff --git a/src/bindings/c/ov/tests/ov_c_api_test.cpp b/src/bindings/c/ov/tests/ov_c_api_test.cpp index 30ba87e2ab9..5791a53f3fc 100644 --- a/src/bindings/c/ov/tests/ov_c_api_test.cpp +++ b/src/bindings/c/ov/tests/ov_c_api_test.cpp @@ -190,7 +190,7 @@ TEST(ov_core, ov_core_read_model_from_memory) { std::vector weights_content(content_from_file(bin, true)); ov_tensor_t* tensor = nullptr; - ov_shape_t shape = {1, weights_content.size()}; + ov_shape_t shape = {2, {1, weights_content.size()}}; OV_ASSERT_OK(ov_tensor_create_from_host_ptr(ov_element_type_e::U8, shape, weights_content.data(), &tensor)); ASSERT_NE(nullptr, tensor); @@ -553,7 +553,7 @@ TEST(ov_preprocess, ov_preprocess_input_tensor_info_set_tensor) { ASSERT_NE(nullptr, input_tensor_info); ov_tensor_t* tensor = nullptr; - ov_shape_t shape = {1, 416, 416, 3}; + ov_shape_t shape = {4, {1, 416, 416, 3}}; OV_ASSERT_OK(ov_tensor_create(ov_element_type_e::F32, shape, &tensor)); OV_ASSERT_OK(ov_preprocess_input_tensor_info_set_tensor(input_tensor_info, tensor)); @@ -1330,7 +1330,6 @@ void infer_request_callback(void *args) { ov_infer_request_t *infer_request = (ov_infer_request_t *)args; ov_tensor_t *out_tensor = nullptr; - printf("async infer callback...\n"); OV_EXPECT_OK(ov_infer_request_get_out_tensor(infer_request, 0, &out_tensor)); EXPECT_NE(nullptr, out_tensor); @@ -1378,7 +1377,7 @@ TEST_P(ov_infer_request, get_profiling_info) { TEST(ov_tensor, ov_tensor_create) { ov_element_type_e type = ov_element_type_e::U8; - ov_shape_t shape = {10, 20, 30, 40}; + ov_shape_t shape = {4, {10, 20, 30, 40}}; ov_tensor_t* tensor = nullptr; OV_EXPECT_OK(ov_tensor_create(type, shape, &tensor)); EXPECT_NE(nullptr, tensor); @@ -1387,7 +1386,7 @@ TEST(ov_tensor, ov_tensor_create) { TEST(ov_tensor, ov_tensor_create_from_host_ptr) { ov_element_type_e type = ov_element_type_e::U8; - ov_shape_t shape = {1, 3, 4, 4}; + ov_shape_t shape = {4, {1, 3, 4, 4}}; uint8_t host_ptr[1][3][4][4]= {0}; ov_tensor_t* tensor = nullptr; OV_EXPECT_OK(ov_tensor_create_from_host_ptr(type, shape, &host_ptr,&tensor)); @@ -1404,7 +1403,7 @@ TEST(ov_tensor, ov_tensor_get_shape) { ov_shape_t shape_res = {0,{0}}; OV_EXPECT_OK(ov_tensor_get_shape(tensor, &shape_res)); - EXPECT_EQ(shape.ranks, shape_res.ranks); + EXPECT_EQ(shape.rank, shape_res.rank); OV_EXPECT_ARREQ(shape.dims, shape_res.dims); ov_tensor_free(tensor); @@ -1421,7 +1420,7 @@ TEST(ov_tensor, ov_tensor_set_shape) { OV_EXPECT_OK(ov_tensor_set_shape(tensor, shape_update)); ov_shape_t shape_res = {0,{0}}; OV_EXPECT_OK(ov_tensor_get_shape(tensor, &shape_res)); - EXPECT_EQ(shape_update.ranks, shape_res.ranks); + EXPECT_EQ(shape_update.rank, shape_res.rank); OV_EXPECT_ARREQ(shape_update.dims, shape_res.dims); ov_tensor_free(tensor); @@ -1429,7 +1428,7 @@ TEST(ov_tensor, ov_tensor_set_shape) { TEST(ov_tensor, ov_tensor_get_element_type) { ov_element_type_e type = ov_element_type_e::U8; - ov_shape_t shape = {10, 20, 30, 40}; + ov_shape_t shape = {4, {10, 20, 30, 40}}; ov_tensor_t* tensor = nullptr; OV_EXPECT_OK(ov_tensor_create(type, shape, &tensor)); EXPECT_NE(nullptr, tensor); @@ -1449,7 +1448,7 @@ static size_t product(const std::vector& dims) { size_t calculate_size(ov_shape_t shape) { std::vector tmp_shape; - std::copy_n(shape.dims, shape.ranks, std::back_inserter(tmp_shape)); + std::copy_n(shape.dims, shape.rank, std::back_inserter(tmp_shape)); return product(tmp_shape); } @@ -1459,7 +1458,7 @@ size_t calculate_byteSize(ov_shape_t shape, ov_element_type_e type) { TEST(ov_tensor, ov_tensor_get_size) { ov_element_type_e type = ov_element_type_e::I16; - ov_shape_t shape = {1, 3, 4, 4}; + ov_shape_t shape = {4, {1, 3, 4, 4}}; ov_tensor_t* tensor = nullptr; OV_EXPECT_OK(ov_tensor_create(type, shape, &tensor)); EXPECT_NE(nullptr, tensor); @@ -1474,7 +1473,7 @@ TEST(ov_tensor, ov_tensor_get_size) { TEST(ov_tensor, ov_tensor_get_byte_size) { ov_element_type_e type = ov_element_type_e::I16; - ov_shape_t shape = {1, 3, 4, 4}; + ov_shape_t shape = {4, {1, 3, 4, 4}}; ov_tensor_t* tensor = nullptr; OV_EXPECT_OK(ov_tensor_create(type, shape, &tensor)); EXPECT_NE(nullptr, tensor); @@ -1489,7 +1488,7 @@ TEST(ov_tensor, ov_tensor_get_byte_size) { TEST(ov_tensor, ov_tensor_get_data) { ov_element_type_e type = ov_element_type_e::U8; - ov_shape_t shape = {10, 20, 30, 40}; + ov_shape_t shape = {4, {10, 20, 30, 40}}; ov_tensor_t *tensor = nullptr; OV_EXPECT_OK(ov_tensor_create(type, shape, &tensor)); EXPECT_NE(nullptr, tensor); @@ -1607,13 +1606,11 @@ TEST(ov_model, ov_model_reshape) { char* tensor_name = nullptr; OV_ASSERT_OK(ov_node_get_tensor_name(&input_node_list1, 0, &tensor_name)); - const char* str = "1,3,896,896"; + const char* str = "{1,3,896,896}"; ov_partial_shape_t* partial_shape; - partial_shape = new ov_partial_shape_t; - partial_shape->ranks = 0; - OV_ASSERT_OK(ov_partial_shape_init(partial_shape,str)); - OV_ASSERT_OK(ov_model_reshape(model, tensor_name, *partial_shape)); + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + OV_ASSERT_OK(ov_model_reshape(model, tensor_name, partial_shape)); ov_output_node_list_t input_node_list2; input_node_list2.output_nodes = nullptr; @@ -1622,6 +1619,7 @@ TEST(ov_model, ov_model_reshape) { EXPECT_NE(input_node_list1.output_nodes, input_node_list2.output_nodes); + ov_partial_shape_free(partial_shape); ov_free(tensor_name); ov_output_node_list_free(&input_node_list1); ov_output_node_list_free(&input_node_list2); @@ -1648,71 +1646,120 @@ TEST(ov_model, ov_model_get_friendly_name) { } TEST(ov_partial_shape, ov_partial_shape_init_and_parse) { - const char* str = "1,2,3,4..5"; + const char* str = "{1,20,300,40..100}"; + ov_partial_shape_t* partial_shape = nullptr; - ov_partial_shape_t partial_shape; - partial_shape.ranks = 0; - - OV_ASSERT_OK(ov_partial_shape_init(&partial_shape,str)); - auto tmp = ov_partial_shape_parse(&partial_shape); + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + auto tmp = ov_partial_shape_parse(partial_shape); EXPECT_STREQ(tmp, str); - delete tmp; - ov_partial_shape_free(&partial_shape); + ov_free(tmp); + ov_partial_shape_free(partial_shape); +} + +TEST(ov_partial_shape, ov_partial_shape_init_and_parse_dynamic) { + const char* str = "{1,?,300,40..100}"; + ov_partial_shape_t* partial_shape = nullptr; + + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + auto tmp = ov_partial_shape_parse(partial_shape); + EXPECT_STREQ(tmp, str); + + ov_free(tmp); + ov_partial_shape_free(partial_shape); +} + +TEST(ov_partial_shape, ov_partial_shape_init_and_parse_dynamic_mix) { + const char* str = "{1,?,?,40..100}"; + ov_partial_shape_t* partial_shape = nullptr; + + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + auto tmp = ov_partial_shape_parse(partial_shape); + EXPECT_STREQ(tmp, str); + + ov_free(tmp); + ov_partial_shape_free(partial_shape); +} + +TEST(ov_partial_shape, ov_partial_shape_init_and_parse_dynamic_mix_2) { + const char* str = "{1,?,-1,40..100}"; + ov_partial_shape_t* partial_shape = nullptr; + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + auto tmp = ov_partial_shape_parse(partial_shape); + + ov_partial_shape_t* partial_shape2 = nullptr; + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape2, tmp)); + auto tmp2 = ov_partial_shape_parse(partial_shape); + EXPECT_STREQ(tmp, tmp2); + + ov_free(tmp); + ov_free(tmp2); + ov_partial_shape_free(partial_shape); + ov_partial_shape_free(partial_shape2); +} + +TEST(ov_partial_shape, ov_partial_shape_init_and_parse_dynamic_rank) { + const char* str = "?"; + ov_partial_shape_t* partial_shape = nullptr; + + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); + auto tmp = ov_partial_shape_parse(partial_shape); + EXPECT_STREQ(tmp, str); + + ov_free(tmp); + ov_partial_shape_free(partial_shape); } TEST(ov_partial_shape, ov_partial_shape_init_and_parse_invalid) { - const char* str = "1,2+3;4..5"; + const char* str = "{1,2+3;4..5}"; + ov_partial_shape_t* partial_shape = nullptr; - ov_partial_shape_t partial_shape; - partial_shape.ranks = 0; + OV_EXPECT_NOT_OK(ov_partial_shape_init(&partial_shape, str)); - OV_EXPECT_NOT_OK(ov_partial_shape_init(&partial_shape,str)); - - ov_partial_shape_free(&partial_shape); + ov_partial_shape_free(partial_shape); } TEST(ov_partial_shape, ov_partial_shape_to_shape) { - const char* str = "1,2,3,4,5"; + const char* str = "{10,20,30,40,50}"; + ov_partial_shape_t* partial_shape = nullptr; - ov_partial_shape_t partial_shape; - partial_shape.ranks = 0; - - OV_ASSERT_OK(ov_partial_shape_init(&partial_shape,str)); + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); ov_shape_t shape; - shape.ranks = 0; - OV_ASSERT_OK(ov_partial_shape_to_shape(&partial_shape, &shape)); + shape.rank = 0; + OV_ASSERT_OK(ov_partial_shape_to_shape(partial_shape, &shape)); + EXPECT_EQ(shape.rank, 5); + EXPECT_EQ(shape.dims[0], 10); + EXPECT_EQ(shape.dims[1], 20); + EXPECT_EQ(shape.dims[2], 30); + EXPECT_EQ(shape.dims[3], 40); + EXPECT_EQ(shape.dims[4], 50); - ov_partial_shape_free(&partial_shape); + ov_partial_shape_free(partial_shape); } TEST(ov_partial_shape, ov_partial_shape_to_shape_invalid_num) { - const char* str = "-1,2,3,4,5"; + const char* str = "{-1,2,3,4,5}"; + ov_partial_shape_t* partial_shape = nullptr; - ov_partial_shape_t partial_shape; - partial_shape.ranks = 0; - - OV_ASSERT_OK(ov_partial_shape_init(&partial_shape,str)); + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); ov_shape_t shape; - shape.ranks = 0; - OV_EXPECT_NOT_OK(ov_partial_shape_to_shape(&partial_shape, &shape)); + shape.rank = 0; + OV_EXPECT_NOT_OK(ov_partial_shape_to_shape(partial_shape, &shape)); - ov_partial_shape_free(&partial_shape); + ov_partial_shape_free(partial_shape); } TEST(ov_partial_shape, ov_partial_shape_to_shape_invalid_sign) { - const char* str = "1,2,3,4..5"; + const char* str = "{1,2,3,4..5}"; + ov_partial_shape_t* partial_shape = nullptr; - ov_partial_shape_t partial_shape; - partial_shape.ranks = 0; - - OV_ASSERT_OK(ov_partial_shape_init(&partial_shape,str)); + OV_ASSERT_OK(ov_partial_shape_init(&partial_shape, str)); ov_shape_t shape; - shape.ranks = 0; - OV_EXPECT_NOT_OK(ov_partial_shape_to_shape(&partial_shape, &shape)); + shape.rank = 0; + OV_EXPECT_NOT_OK(ov_partial_shape_to_shape(partial_shape, &shape)); - ov_partial_shape_free(&partial_shape); + ov_partial_shape_free(partial_shape); } \ No newline at end of file