* Copyright (c) 2025-2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef NN_TESTS_UT_COMMON_UT_STRING_UTILS_H_
#define NN_TESTS_UT_COMMON_UT_STRING_UTILS_H_
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
#ifndef _WIN32
#include <limits.h>
#include <unistd.h>
#endif
#if __has_include("aclnn/aclnn_base.h")
#include "aclnn/aclnn_base.h"
#if __has_include("opdev/op_errno.h")
#include "opdev/op_errno.h"
#endif
#if __has_include("opdev/platform.h")
#include "opdev/platform.h"
#endif
#define NN_TESTS_UT_COMMON_HAS_ACLNN_TYPES
#ifndef ACLNN_SUCCESS
#define ACLNN_SUCCESS static_cast<aclnnStatus>(0)
#endif
#ifndef ACLNN_ERR_PARAM_NULLPTR
#define ACLNN_ERR_PARAM_NULLPTR static_cast<aclnnStatus>(161001)
#endif
#ifndef ACLNN_ERR_PARAM_INVALID
#define ACLNN_ERR_PARAM_INVALID static_cast<aclnnStatus>(161002)
#endif
#endif
#if __has_include("exe_graph/runtime/shape.h") && __has_include("exe_graph/runtime/storage_shape.h") && \
__has_include("graph/types.h")
#include "exe_graph/runtime/shape.h"
#include "exe_graph/runtime/storage_shape.h"
#include "graph/types.h"
#define NN_TESTS_UT_COMMON_HAS_GE_TYPES
#endif
namespace ut_str {
inline std::string GetExeDirPath()
{
#ifdef _WIN32
return "./";
#else
std::string exePath("./");
char path[PATH_MAX];
ssize_t n = readlink("/proc/self/exe", path, sizeof(path));
if (n > 0) {
path[n] = '\0';
exePath.assign(path);
auto pos = exePath.find_last_of('/');
if (pos != std::string::npos) {
exePath.erase(pos + 1);
} else {
exePath.assign("./");
}
}
return exePath;
#endif
}
inline std::string Trim(const std::string &input)
{
const auto first = std::find_if_not(input.begin(), input.end(), [](unsigned char ch) {
return std::isspace(ch) != 0;
});
if (first == input.end()) {
return "";
}
const auto last = std::find_if_not(input.rbegin(), input.rend(), [](unsigned char ch) {
return std::isspace(ch) != 0;
}).base();
return std::string(first, last);
}
inline void SplitStr2Vec(const std::string &input, const std::string &delimiter, std::vector<std::string> &output)
{
output.clear();
if (delimiter.empty()) {
if (!input.empty()) {
output.emplace_back(input);
}
return;
}
const auto delimiterLen = delimiter.size();
std::string::size_type currPos = 0;
std::string::size_type nextPos = input.find(delimiter, currPos);
while (nextPos != std::string::npos) {
output.emplace_back(input.substr(currPos, nextPos - currPos));
currPos = nextPos + delimiterLen;
nextPos = input.find(delimiter, currPos);
}
if (currPos <= input.size()) {
output.emplace_back(input.substr(currPos));
}
}
inline std::vector<int64_t> ParseInt64Vec(const std::string &value)
{
std::vector<int64_t> result;
const std::string trimmed = Trim(value);
if (trimmed.empty()) {
return result;
}
std::vector<std::string> items;
SplitStr2Vec(trimmed, " ", items);
for (size_t tokenIdx = 0; tokenIdx < items.size(); ++tokenIdx) {
const auto &item = items[tokenIdx];
const std::string token = Trim(item);
if (token.empty()) {
continue;
}
try {
result.push_back(static_cast<int64_t>(std::stoll(token)));
} catch (const std::exception &e) {
std::cerr << "ParseInt64Vec skip invalid token, original value: \"" << value
<< "\", token index: " << tokenIdx << ", token: \"" << token
<< "\", error: " << e.what() << std::endl;
continue;
}
}
return result;
}
inline bool ParseBool(const std::string &value)
{
std::string t = Trim(value);
std::transform(t.begin(), t.end(), t.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return t == "true" || t == "1";
}
inline int ParseIntOrDefault(const std::string &value, int defaultValue)
{
const std::string trimmed = Trim(value);
if (trimmed.empty()) {
return defaultValue;
}
try {
return std::stoi(trimmed);
} catch (const std::exception &) {
return defaultValue;
}
}
inline int64_t ParseInt64OrDefault(const std::string &value, int64_t defaultValue)
{
const std::string trimmed = Trim(value);
if (trimmed.empty()) {
return defaultValue;
}
try {
return static_cast<int64_t>(std::stoll(trimmed));
} catch (const std::exception &) {
return defaultValue;
}
}
#ifdef NN_TESTS_UT_COMMON_HAS_GE_TYPES
inline ge::graphStatus ParseGraphStatus(const std::string &value, ge::graphStatus defaultValue = ge::GRAPH_FAILED)
{
std::string lowered = Trim(value);
std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
if (lowered == "graph_success" || lowered == "success" || lowered == "1") {
return ge::GRAPH_SUCCESS;
}
if (lowered == "graph_failed" || lowered == "failed" || lowered == "0") {
return ge::GRAPH_FAILED;
}
return defaultValue;
}
inline gert::Shape ToShape(const std::vector<int64_t> &dims)
{
gert::Shape shape;
for (const auto dim : dims) {
shape.AppendDim(dim);
}
return shape;
}
inline gert::StorageShape MakeStorageShape(const std::vector<int64_t> &dims)
{
gert::StorageShape shape;
shape.MutableStorageShape() = ToShape(dims);
shape.MutableOriginShape() = shape.MutableStorageShape();
return shape;
}
inline gert::Shape ParseShape(const std::string &value)
{
return ToShape(ParseInt64Vec(value));
}
inline ge::DataType ParseDtype(const std::string &value, ge::DataType defaultValue = ge::DT_FLOAT16)
{
static const std::map<std::string, ge::DataType> kDtypeMap = {
{"FLOAT16", ge::DT_FLOAT16},
{"FP16", ge::DT_FLOAT16},
{"DT_FLOAT16", ge::DT_FLOAT16},
{"FLOAT", ge::DT_FLOAT},
{"FLOAT32", ge::DT_FLOAT},
{"FP32", ge::DT_FLOAT},
{"DT_FLOAT", ge::DT_FLOAT},
{"DT_FLOAT32", ge::DT_FLOAT},
{"BF16", ge::DT_BF16},
{"DT_BF16", ge::DT_BF16},
{"INT8", ge::DT_INT8},
{"DT_INT8", ge::DT_INT8},
{"INT4", ge::DT_INT4},
{"DT_INT4", ge::DT_INT4},
{"INT2", ge::DT_INT2},
{"DT_INT2", ge::DT_INT2},
{"UINT1", ge::DT_UINT1},
{"DT_UINT1", ge::DT_UINT1},
{"UINT64", ge::DT_UINT64},
{"DT_UINT64", ge::DT_UINT64},
{"INT32", ge::DT_INT32},
{"DT_INT32", ge::DT_INT32},
{"INT64", ge::DT_INT64},
{"DT_INT64", ge::DT_INT64},
{"HIFLOAT8", ge::DT_HIFLOAT8},
{"DT_HIFLOAT8", ge::DT_HIFLOAT8},
{"FLOAT8-E8M0", ge::DT_FLOAT8_E8M0},
{"FP8-E8M0", ge::DT_FLOAT8_E8M0},
{"DT_FLOAT8_E8M0", ge::DT_FLOAT8_E8M0},
{"FLOAT8-E5M2", ge::DT_FLOAT8_E5M2},
{"FP8-E5M2", ge::DT_FLOAT8_E5M2},
{"DT_FLOAT8_E5M2", ge::DT_FLOAT8_E5M2},
{"FLOAT8-E4M3", ge::DT_FLOAT8_E4M3FN},
{"FP8-E4M3", ge::DT_FLOAT8_E4M3FN},
{"DT_FLOAT8_E4M3FN", ge::DT_FLOAT8_E4M3FN},
{"FLOAT4-E2M1", ge::DT_FLOAT4_E2M1},
{"FP4-E2M1", ge::DT_FLOAT4_E2M1},
{"DT_FLOAT4_E2M1", ge::DT_FLOAT4_E2M1},
};
const auto dtypeStr = Trim(value);
const auto it = kDtypeMap.find(dtypeStr);
if (it != kDtypeMap.end()) {
return it->second;
}
return defaultValue;
}
inline ge::Format ParseFormat(const std::string &value, ge::Format defaultValue = ge::FORMAT_ND)
{
static const std::map<std::string, ge::Format> kFormatMap = {
{"ND", ge::FORMAT_ND},
{"FORMAT_ND", ge::FORMAT_ND},
{"NZ", ge::FORMAT_FRACTAL_NZ},
{"FORMAT_FRACTAL_NZ", ge::FORMAT_FRACTAL_NZ},
};
const auto formatStr = Trim(value);
const auto it = kFormatMap.find(formatStr);
if (it != kFormatMap.end()) {
return it->second;
}
return defaultValue;
}
#endif
#ifdef NN_TESTS_UT_COMMON_HAS_ACLNN_TYPES
inline aclDataType ParseAclDataType(const std::string &value, aclDataType defaultValue = ACL_FLOAT16)
{
static const std::map<std::string, aclDataType> kDtypeMap = {
{"ACL_INT4", ACL_INT4},
{"ACL_INT8", ACL_INT8},
{"ACL_INT64", ACL_INT64},
{"ACL_INT32", ACL_INT32},
{"ACL_UINT64", ACL_UINT64},
{"ACL_FLOAT", ACL_FLOAT},
{"ACL_FLOAT16", ACL_FLOAT16},
{"ACL_BF16", ACL_BF16},
{"ACL_HIFLOAT8", ACL_HIFLOAT8},
{"ACL_FLOAT8_E4M3FN", ACL_FLOAT8_E4M3FN},
{"ACL_FLOAT8_E5M2", ACL_FLOAT8_E5M2},
{"ACL_FLOAT8_E8M0", ACL_FLOAT8_E8M0},
{"ACL_FLOAT4_E2M1", ACL_FLOAT4_E2M1},
};
const auto it = kDtypeMap.find(Trim(value));
if (it != kDtypeMap.end()) {
return it->second;
}
return defaultValue;
}
inline aclnnStatus ParseAclnnStatus(const std::string &value)
{
static const std::map<std::string, aclnnStatus> kStatusMap = {
{"ACLNN_SUCCESS", ACLNN_SUCCESS},
{"ACLNN_ERR_PARAM_INVALID", ACLNN_ERR_PARAM_INVALID},
{"ACLNN_ERR_PARAM_NULLPTR", ACLNN_ERR_PARAM_NULLPTR},
};
const auto it = kStatusMap.find(Trim(value));
if (it != kStatusMap.end()) {
return it->second;
}
return ACLNN_ERR_PARAM_INVALID;
}
inline aclFormat ParseAclFormat(const std::string &value)
{
static const std::map<std::string, aclFormat> kFormatMap = {
{"ACL_FORMAT_ND", ACL_FORMAT_ND},
{"ACL_FORMAT_NCHW", ACL_FORMAT_NCHW},
{"ACL_FORMAT_FRACTAL_NZ", ACL_FORMAT_FRACTAL_NZ},
{"ACL_FORMAT_FRACTAL_NZ_C0_32", ACL_FORMAT_FRACTAL_NZ_C0_32},
};
const auto it = kFormatMap.find(Trim(value));
if (it != kFormatMap.end()) {
return it->second;
}
return ACL_FORMAT_ND;
}
#endif
inline std::vector<int64_t> MakeDefaultStride(const std::vector<int64_t> &shape)
{
std::vector<int64_t> stride(shape.size(), 1);
for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) {
stride[static_cast<size_t>(i)] =
stride[static_cast<size_t>(i + 1)] * shape[static_cast<size_t>(i + 1)];
}
return stride;
}
}
#endif