A trim implementation for std::string

本文探讨了三种实现C++ STL标准库中std::string类的trim操作的方法,旨在去除字符串两端的空白字符。第一种方法通过提取子串实现;第二种方法通过定位非空格字符并删除多余部分来提升效率;第三种方法则利用C++11的lambda表达式简化代码。

Introduction

The C++ Standard Template Library (STL, for short) provides the handy std::string class, which provides a lot of common string facilities. However, the well-known trim operation was not implemented. The trimoperation consists of removing all unused spaces placed before and after the characters into a string. For example, let's say you have a textbox in a program where the user should type their name. Then, the user types the following:

"  Rodrigo Dias "

It would be interesting if you could remove the spaces before and after the name if, for example, you are about to include this string in a database. In this article, we will discuss three easy implementations of trim, both applied to the std::string class.


First implementation

In this first implementation, the idea is to extract the substring within the string, so we have just what interests. The code is shown below:

void trim1(string& str)
{
  string::size_type pos1 = str.find_first_not_of(' ');
  string::size_type pos2 = str.find_last_not_of(' ');
  str = str.substr(pos1 == string::npos ? 0 : pos1, 
    pos2 == string::npos ? str.length() - 1 : pos2 - pos1 + 1);
}


Second implementation, faster

The second implementation is faster, as you can see yourself if you perform some benchmarks as I did. The idea here is to search the string for the last character before the last space characters. If none is found, then the string is composed only of spaces, so it's completely erased. Else we remove the spaces at the end of the string, based on the found index.

Next step, we search for the first character different from space. Then we remove everything before it. The code of this implementation is shown below:

void trim2(string& str)
{
  string::size_type pos = str.find_last_not_of(' ');
  if(pos != string::npos) {
    str.erase(pos + 1);
    pos = str.find_first_not_of(' ');
    if(pos != string::npos) str.erase(0, pos);
  }
  else str.erase(str.begin(), str.end());
}
This implementation is faster because we have two calls to erase, instead of a string copy (more expensive).


Third implementation, C++11

This implementation is possibly the most elegant, and it uses C++11 lambdas (also, I'm writing this 9 years later, so my programming skills are slightly better). Here, we strip space characters from the beginning and from the end using the erase method, which works upon iterators. The two erase calls are in fact a left-trim and a right-trim. The catch is that we directly pass iterators returned from the find_if function, which runs through the string searching for the bounds. The isspace function is responsible to decide what is a space character.

#include <algorithm>
#include <cctype>
#include <string>

string& trim3(string& str)
{
  str.erase(str.begin(), find_if(str.begin(), str.end(),
    [](char& ch)->bool { return !isspace(ch); }));
  str.erase(find_if(str.rbegin(), str.rend(),
    [](char& ch)->bool { return !isspace(ch); }).base(), str.end());
  return str;
}  

On the second erase call, we need to call the base method because we're using reverse iterators to search from the end of the string; base returns a copy of the same iterator that can go forward. Also, as a bonus, ourtrim3 returns a reference to the same passed string object.

Conclusion

The trim method may be very useful sometimes, and we discussed an implementation of a good one if we are working with the std::string class. Below is the simplest example of how to use it, dealing with the previously given input:





不是,而是修改下面的源代码 /****************************************************************************** * SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix * Completely fixed template class DLL API marker position issue * Enhanced to support .cpp file class definitions and comment formats ******************************************************************************/ #include <iostream> #include <fstream> #include <string> #include <vector> #include <algorithm> #include <set> #include <cctype> #include <windows.h> // VS2015 Check #ifdef _MSC_VER #if _MSC_VER < 1900 #error "This program requires Visual Studio 2015 or later" #endif #endif // Configuration structure struct Config { std::string systemcDllApi = "SYSTEMC_DLL_API"; std::string tlmDllApi = "TLM_DLL_API"; std::string includeConfig = "#include \"config.hpp\""; std::set<std::string> headerExtensions = { ".h", ".hpp", ".hxx" }; std::set<std::string> sourceExtensions = { ".cpp", ".cxx", ".cc" }; std::set<std::string> excludeFiles = { "config.hpp", "Makefile", "CMakeLists.txt" }; std::set<std::string> excludeDirs = { ".git", ".svn", ".vs", "Debug", "Release", "build", "x64", "x86" }; }; // Statistics struct Statistics { int totalFiles = 0; int processedFiles = 0; int modifiedFiles = 0; int skippedFiles = 0; int errorFiles = 0; }; // String Utilities Class class StringUtils { public: static std::string trim(const std::string& str) { if (str.empty()) return str; size_t start = 0; while (start < str.length() && std::isspace(static_cast<unsigned char>(str[start]))) { ++start; } if (start >= str.length()) return ""; size_t end = str.length() - 1; while (end > start && std::isspace(static_cast<unsigned char>(str[end]))) { --end; } return str.substr(start, end - start + 1); } static bool startsWith(const std::string& str, const std::string& prefix) { if (str.length() < prefix.length()) return false; return str.compare(0, prefix.length(), prefix) == 0; } static bool endsWith(const std::string& str, const std::string& suffix) { if (str.length() < suffix.length()) return false; return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0; } static bool contains(const std::string& str, const std::string& substr) { if (substr.empty()) return true; if (str.empty()) return false; return str.find(substr) != std::string::npos; } static std::string replace(const std::string& str, const std::string& from, const std::string& to) { if (from.empty() || str.empty()) return str; std::string result = str; size_t pos = 0; while ((pos = result.find(from, pos)) != std::string::npos) { result.replace(pos, from.length(), to); pos += to.length(); } return result; } static std::string toLower(const std::string& str) { std::string result = str; std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); }); return result; } static std::string toUpper(const std::string& str) { std::string result = str; std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return static_cast<char>(std::toupper(c)); }); return result; } static std::string getFileName(const std::string& path) { if (path.empty()) return ""; size_t pos = path.find_last_of("\\/"); if (pos == std::string::npos) return path; return path.substr(pos + 1); } static std::string getExtension(const std::string& path) { if (path.empty()) return ""; size_t pos = path.find_last_of("."); if (pos == std::string::npos) return ""; return path.substr(pos); } static std::string getDirectory(const std::string& path) { if (path.empty()) return ""; size_t pos = path.find_last_of("\\/"); if (pos == std::string::npos) return ""; return path.substr(0, pos); } static std::vector<std::string> split(const std::string& str, char delimiter) { std::vector<std::string> tokens; if (str.empty()) return tokens; size_t start = 0; size_t end = 0; while ((end = str.find(delimiter, start)) != std::string::npos) { if (end != start) { tokens.push_back(str.substr(start, end - start)); } start = end + 1; } if (start < str.length()) { tokens.push_back(str.substr(start)); } return tokens; } // Check if line is a comment separator static bool isCommentSeparator(const std::string& str) { std::string trimmed = trim(str); return startsWith(trimmed, "// ---") || startsWith(trimmed, "/* ---") || (contains(trimmed, "---") && (startsWith(trimmed, "//") || startsWith(trimmed, "/*"))); } // Check if line is a class comment header static bool isClassCommentHeader(const std::string& str) { std::string trimmed = trim(str); return (contains(trimmed, "CLASS :") || contains(trimmed, "class")) && (startsWith(trimmed, "//") || startsWith(trimmed, "/*")); } }; // File System Utilities Class class FileSystemUtils { public: static bool fileExists(const std::string& path) { if (path.empty()) return false; DWORD attrs = GetFileAttributesA(path.c_str()); if (attrs == INVALID_FILE_ATTRIBUTES) return false; return (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0; } static bool directoryExists(const std::string& path) { if (path.empty()) return false; DWORD attrs = GetFileAttributesA(path.c_str()); if (attrs == INVALID_FILE_ATTRIBUTES) return false; return (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; } static bool createDirectory(const std::string& path) { if (path.empty()) return false; if (directoryExists(path)) return true; return CreateDirectoryA(path.c_str(), NULL) != 0; } static bool createDirectoryRecursive(const std::string& path) { if (path.empty()) return false; if (directoryExists(path)) return true; std::string normalizedPath = path; std::replace(normalizedPath.begin(), normalizedPath.end(), '/', '\\'); std::vector<std::string> components = StringUtils::split(normalizedPath, '\\'); if (components.empty()) return false; std::string currentPath; if (components[0].find(':') != std::string::npos) { currentPath = components[0] + "\\"; components.erase(components.begin()); } for (const auto& component : components) { if (component.empty()) continue; if (!currentPath.empty() && currentPath.back() != '\\') { currentPath += "\\"; } currentPath += component; if (!createDirectory(currentPath)) { return false; } } return true; } static bool copyFile(const std::string& from, const std::string& to) { if (from.empty() || to.empty()) return false; if (!fileExists(from)) return false; std::string targetDir = StringUtils::getDirectory(to); if (!targetDir.empty() && !createDirectoryRecursive(targetDir)) { return false; } return ::CopyFileA(from.c_str(), to.c_str(), FALSE) != 0; } static bool findFiles(const std::string& directory, std::vector<std::string>& files, std::vector<std::string>& directories, bool recursive = true) { if (!directoryExists(directory)) return false; std::string searchPath = directory + "\\*"; WIN32_FIND_DATAA findData; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return false; } do { if (strcmp(findData.cFileName, ".") == 0 || strcmp(findData.cFileName, "..") == 0) { continue; } std::string fullPath = directory + "\\" + findData.cFileName; if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { std::string dirName = findData.cFileName; if (isDirectoryExcluded(dirName)) continue; directories.push_back(fullPath); if (recursive) { findFiles(fullPath, files, directories, recursive); } } else { files.push_back(fullPath); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); return true; } private: static bool isDirectoryExcluded(const std::string& dirName) { static std::set<std::string> excludedDirs = { ".git", ".svn", ".vs", "Debug", "Release", "build", "x64", "x86", "obj", "bin" }; std::string lowerName = StringUtils::toLower(dirName); return excludedDirs.find(lowerName) != excludedDirs.end(); } }; // Main Processor Class - Ultimate Template API Fix class SystemCDLLModifier { private: Config config; Statistics stats; bool dryRun; bool createBackup; std::string backupDir; public: SystemCDLLModifier(bool dryRunMode = false, bool backup = false) : dryRun(dryRunMode), createBackup(backup) {} bool processDirectory(const std::string& sourceDir) { std::cout << "Processing directory: " << sourceDir << std::endl; if (!FileSystemUtils::directoryExists(sourceDir)) { std::cerr << "Error: Directory does not exist: " << sourceDir << std::endl; return false; } // Create backup if (createBackup && !dryRun) { std::cout << "\nCreating backup..." << std::endl; if (!createBackupDirectory(sourceDir)) { std::cout << "Backup creation had issues!" << std::endl; std::cout << "Do you want to continue without backup? (y/n): "; char response; std::cin >> response; if (response != 'y' && response != 'Y') { return false; } } } // Process files std::vector<std::string> files; std::vector<std::string> directories; if (!FileSystemUtils::findFiles(sourceDir, files, directories, true)) { std::cerr << "Failed to enumerate files" << std::endl; return false; } stats.totalFiles = static_cast<int>(files.size()); std::cout << "Found " << stats.totalFiles << " files to process" << std::endl; for (int i = 0; i < stats.totalFiles; ++i) { processFile(files[i]); if ((i + 1) % 10 == 0 || (i + 1) == stats.totalFiles) { int percent = (i + 1) * 100 / stats.totalFiles; std::cout << "Processing: " << (i + 1) << "/" << stats.totalFiles << " files (" << percent << "%)" << std::endl; } } // Generate config.hpp if (!dryRun) { generateConfigFile(sourceDir); } return true; } const Statistics& getStatistics() const { return stats; } const std::string& getBackupDir() const { return backupDir; } private: void processFile(const std::string& filePath) { if (!FileSystemUtils::fileExists(filePath)) { stats.skippedFiles++; return; } std::string filename = StringUtils::getFileName(filePath); std::string ext = StringUtils::getExtension(filePath); // Check excluded files if (config.excludeFiles.find(StringUtils::toLower(filename)) != config.excludeFiles.end()) { stats.skippedFiles++; return; } // Check extension bool isHeader = config.headerExtensions.find(ext) != config.headerExtensions.end(); bool isSource = config.sourceExtensions.find(ext) != config.sourceExtensions.end(); if (!isHeader && !isSource) { stats.skippedFiles++; return; } stats.processedFiles++; if (isHeader) { processHeaderFile(filePath); } else { processSourceFile(filePath); } } void processHeaderFile(const std::string& filePath) { std::vector<std::string> lines; if (!readFile(filePath, lines)) { stats.errorFiles++; return; } bool isSystemcFile = false; bool isTlmFile = false; std::string filename = StringUtils::getFileName(filePath); // Check file type if (filename == "systemc.h" || StringUtils::startsWith(filename, "sc_") || StringUtils::contains(StringUtils::toLower(filename), "vcd") || StringUtils::contains(StringUtils::toLower(filename), "trace")) { isSystemcFile = true; } else if (filename == "tlm.h" || StringUtils::contains(StringUtils::toLower(filename), "tlm")) { isTlmFile = true; } else { // Check content for (const auto& line : lines) { std::string trimmed = StringUtils::trim(line); if (StringUtils::contains(trimmed, "namespace sc_core") || StringUtils::contains(trimmed, "SC_MODULE") || StringUtils::contains(trimmed, "class sc_") || StringUtils::contains(trimmed, "class vcd_") || StringUtils::contains(trimmed, "vcd_trace")) { isSystemcFile = true; break; } else if (StringUtils::contains(trimmed, "namespace tlm") || StringUtils::contains(trimmed, "class tlm_")) { isTlmFile = true; break; } } } if (!isSystemcFile && !isTlmFile) { stats.skippedFiles++; return; } std::string dllApi = isTlmFile ? config.tlmDllApi : config.systemcDllApi; bool modified = false; // Check if config.hpp is already included bool hasConfigInclude = false; for (size_t i = 0; i < lines.size(); ++i) { std::string trimmed = StringUtils::trim(lines[i]); if (StringUtils::contains(trimmed, "#include \"config.hpp\"") || StringUtils::contains(trimmed, "#include <config.hpp>")) { hasConfigInclude = true; break; } } // Add config.hpp include if (!hasConfigInclude) { bool inserted = false; for (size_t i = 0; i < lines.size(); ++i) { std::string trimmed = StringUtils::trim(lines[i]); if (StringUtils::startsWith(trimmed, "#include")) { lines.insert(lines.begin() + i, config.includeConfig); inserted = true; modified = true; break; } } if (!inserted) { lines.insert(lines.begin(), config.includeConfig); modified = true; } } // Process class declarations and templates with enhanced pattern matching for (size_t i = 0; i < lines.size(); ++i) { std::string line = lines[i]; std::string trimmed = StringUtils::trim(line); // Skip preprocessor directives and comments if (StringUtils::startsWith(trimmed, "#") || StringUtils::startsWith(trimmed, "//") || StringUtils::startsWith(trimmed, "/*")) { continue; } // Process regular classes (including those with comment headers) if (isClassDeclarationLine(trimmed)) { if (!StringUtils::contains(trimmed, config.systemcDllApi) && !StringUtils::contains(trimmed, config.tlmDllApi)) { // Check if this class has a comment header above it if (i > 0 && hasCommentHeader(lines, i)) { // Find the start of the comment block size_t commentStart = findCommentBlockStart(lines, i); if (commentStart != std::string::npos && commentStart < i) { // Insert API after the comment block, before the class declaration lines[i] = addAPIToClassDeclaration(trimmed, dllApi); modified = true; } } else { // No comment header, just add API to the class line lines[i] = addAPIToClassDeclaration(trimmed, dllApi); modified = true; } } } // ULTIMATE FIX: Template class API placement with inheritance support if (isTemplateClassDeclaration(trimmed)) { modified = ultimateTemplateFix(lines, i, dllApi, filePath) || modified; } } if (modified) { if (dryRun) { std::cout << "[DRY RUN] Would modify header: " << filePath << std::endl; stats.modifiedFiles++; } else { if (writeFile(filePath, lines)) { std::cout << "Modified header: " << filePath << std::endl; stats.modifiedFiles++; } else { std::cerr << "Failed to write header: " << filePath << std::endl; stats.errorFiles++; } } } } // Check if line is a class declaration bool isClassDeclarationLine(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Match patterns like: // class class_name // class class_name { // class class_name : if (StringUtils::startsWith(trimmed, "class ") && !StringUtils::contains(trimmed, "template")) { // Extract class name part (after "class ") size_t classPos = trimmed.find("class "); size_t afterClass = classPos + 6; if (afterClass >= trimmed.length()) return false; std::string afterClassStr = trimmed.substr(afterClass); StringUtils::trim(afterClassStr); // Check if it's a real class name (not a template parameter) if (afterClassStr.empty()) return false; // Exclude single-letter template parameters if (afterClassStr.length() == 1 && (afterClassStr[0] == 'T' || afterClassStr[0] == 'U' || afterClassStr[0] == 'V' || afterClassStr[0] == 'W')) { return false; } return true; } return false; } // Check if line is a template class declaration bool isTemplateClassDeclaration(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Match patterns like: // template <class T> class class_name // template <typename T> class class_name // template <class T> class class_name : if (StringUtils::startsWith(trimmed, "template") && (StringUtils::contains(trimmed, "class") || StringUtils::contains(trimmed, "typename")) && StringUtils::contains(trimmed, "class ")) { // Check if it's a template parameter declaration (like template<class T>) if (isTemplateParameterDeclaration(trimmed)) { return false; } return true; } return false; } // Check if line is a template parameter declaration bool isTemplateParameterDeclaration(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Template parameter declarations end with > and don't have a second class keyword if (!StringUtils::contains(trimmed, ">")) return false; // Check if it's a simple template parameter like template<class T> size_t templatePos = trimmed.find("template"); size_t angleBracketPos = trimmed.find(">", templatePos); if (angleBracketPos == std::string::npos) return false; // Check if there's content after the > that indicates it's a real class std::string afterAngleBracket = trimmed.substr(angleBracketPos + 1); StringUtils::trim(afterAngleBracket); // If there's no content after >, it's likely a template parameter declaration if (afterAngleBracket.empty()) return true; // If there's content but it doesn't contain "class", it's probably not a class declaration return !StringUtils::contains(afterAngleBracket, "class"); } // Check if class has a comment header above it bool hasCommentHeader(const std::vector<std::string>& lines, size_t currentLine) { if (currentLine == 0) return false; // Check previous lines for comment patterns for (int i = static_cast<int>(currentLine) - 1; i >= 0 && i >= static_cast<int>(currentLine) - 10; --i) { std::string line = lines[i]; std::string trimmed = StringUtils::trim(line); if (trimmed.empty()) continue; // Check for comment separators or class comment headers if (StringUtils::isCommentSeparator(trimmed) || StringUtils::isClassCommentHeader(trimmed)) { return true; } // If we hit a non-comment, non-empty line, stop searching if (!StringUtils::startsWith(trimmed, "//") && !StringUtils::startsWith(trimmed, "/*") && !trimmed.empty()) { break; } } return false; } // Find the start of a comment block before a class declaration size_t findCommentBlockStart(const std::vector<std::string>& lines, size_t currentLine) { if (currentLine == 0) return std::string::npos; for (int i = static_cast<int>(currentLine) - 1; i >= 0; --i) { std::string line = lines[i]; std::string trimmed = StringUtils::trim(line); if (trimmed.empty()) continue; // Look for the start of the comment block (first comment line) if (StringUtils::startsWith(trimmed, "//") || StringUtils::startsWith(trimmed, "/*")) { // Check if this is the first comment in the block if (i == 0 || !StringUtils::startsWith(StringUtils::trim(lines[i - 1]), "//") && !StringUtils::startsWith(StringUtils::trim(lines[i - 1]), "/*")) { return i; } } else { // Non-comment line, stop searching break; } } return std::string::npos; } // Add API to class declaration (handles inheritance) std::string addAPIToClassDeclaration(const std::string& line, const std::string& dllApi) { std::string result = line; // Find "class " position size_t classPos = result.find("class "); if (classPos == std::string::npos) return line; // Position after "class " size_t afterClass = classPos + 6; while (afterClass < result.length() && std::isspace(result[afterClass])) { afterClass++; } if (afterClass >= result.length()) return line; // Insert API after "class " but before the class name result = result.substr(0, afterClass) + dllApi + " " + result.substr(afterClass); return result; } void processSourceFile(const std::string& filePath) { std::vector<std::string> lines; if (!readFile(filePath, lines)) { stats.errorFiles++; return; } bool isSystemcFile = false; bool isTlmFile = false; std::string filename = StringUtils::getFileName(filePath); // Check file type if (StringUtils::startsWith(filename, "sc_") || StringUtils::contains(filename, "tlm") || StringUtils::contains(filename, "vcd") || StringUtils::contains(filename, "trace")) { isSystemcFile = true; } else { // Check content for SystemC/TLM indicators for (const auto& line : lines) { std::string trimmed = StringUtils::trim(line); if (StringUtils::contains(trimmed, "namespace sc_core") || StringUtils::contains(trimmed, "SC_MODULE") || StringUtils::contains(trimmed, "class sc_") || StringUtils::contains(trimmed, "sc_vcd_trace") || StringUtils::contains(trimmed, "vcd_trace") || StringUtils::contains(trimmed, "sc_main")) { isSystemcFile = true; break; } else if (StringUtils::contains(trimmed, "namespace tlm") || StringUtils::contains(trimmed, "class tlm_")) { isTlmFile = true; break; } } } if (!isSystemcFile && !isTlmFile) { stats.skippedFiles++; return; } std::string dllApi = isTlmFile ? config.tlmDllApi : config.systemcDllApi; bool modified = false; // Check if config.hpp is already included bool hasConfigInclude = false; for (size_t i = 0; i < lines.size(); ++i) { std::string trimmed = StringUtils::trim(lines[i]); if (StringUtils::contains(trimmed, "#include \"config.hpp\"") || StringUtils::contains(trimmed, "#include <config.hpp>")) { hasConfigInclude = true; break; } } // Add config.hpp include to source files if (!hasConfigInclude) { bool inserted = false; for (size_t i = 0; i < lines.size(); ++i) { std::string trimmed = StringUtils::trim(lines[i]); if (StringUtils::startsWith(trimmed, "#include")) { lines.insert(lines.begin() + i, config.includeConfig); inserted = true; modified = true; break; } } if (!inserted) { // If no #include found, add at the beginning lines.insert(lines.begin(), config.includeConfig); modified = true; } } // Process class definitions in .cpp files for (size_t i = 0; i < lines.size(); ++i) { std::string line = lines[i]; std::string trimmed = StringUtils::trim(line); // Skip preprocessor directives and comments if (StringUtils::startsWith(trimmed, "#") || StringUtils::startsWith(trimmed, "//") || StringUtils::startsWith(trimmed, "/*")) { continue; } // Process class member function definitions in .cpp files if (isClassMemberFunctionDefinition(trimmed)) { modified = processClassMemberFunction(lines, i, dllApi, filePath) || modified; } // Process template specializations in .cpp files if (isTemplateSpecialization(trimmed)) { modified = processTemplateSpecialization(lines, i, dllApi, filePath) || modified; } // Process static member definitions in .cpp files if (isStaticMemberDefinition(trimmed)) { modified = processStaticMemberDefinition(lines, i, dllApi, filePath) || modified; } } if (modified) { if (dryRun) { std::cout << "[DRY RUN] Would modify source: " << filePath << std::endl; stats.modifiedFiles++; } else { if (writeFile(filePath, lines)) { std::cout << "Modified source: " << filePath << std::endl; stats.modifiedFiles++; } else { std::cerr << "Failed to write source: " << filePath << std::endl; stats.errorFiles++; } } } } // Check if line is a class member function definition bool isClassMemberFunctionDefinition(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Pattern: return_type class_name::function_name if (!StringUtils::contains(trimmed, "::")) return false; if (!StringUtils::contains(trimmed, "(")) return false; if (!StringUtils::contains(trimmed, ")")) return false; if (StringUtils::contains(trimmed, ";")) return false; // Not a declaration // Check if it's a SystemC related class std::vector<std::string> systemcClasses = { "sc_", "tlm_", "vcd_", "wif_", "signal_", "module_", "port_" }; for (const auto& className : systemcClasses) { if (StringUtils::contains(trimmed, className) && StringUtils::contains(trimmed, "::")) { return true; } } return false; } // Process class member function definition bool processClassMemberFunction(std::vector<std::string>& lines, size_t currentLine, const std::string& dllApi, const std::string& filePath) { std::string line = lines[currentLine]; std::string trimmed = StringUtils::trim(line); // Check if already has API if (StringUtils::contains(trimmed, dllApi)) { return false; } // Add API to function definition std::string fixedLine = addAPIToFunctionDefinition(trimmed, dllApi); if (fixedLine != line) { lines[currentLine] = fixedLine; std::cout << "ADDED API to function definition in " << filePath << ":\n"; std::cout << " BEFORE: " << trimmed << "\n"; std::cout << " AFTER: " << fixedLine << std::endl; return true; } return false; } // Check if line is a template specialization bool isTemplateSpecialization(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Pattern: template class ClassName<Args>; if (!StringUtils::contains(trimmed, "template class")) return false; if (!StringUtils::contains(trimmed, ";")) return false; // Check if it's a SystemC related class std::vector<std::string> systemcClasses = { "sc_", "tlm_", "vcd_", "signal_" }; for (const auto& className : systemcClasses) { if (StringUtils::contains(trimmed, className)) { return true; } } return false; } // Process template specialization bool processTemplateSpecialization(std::vector<std::string>& lines, size_t currentLine, const std::string& dllApi, const std::string& filePath) { std::string line = lines[currentLine]; std::string trimmed = StringUtils::trim(line); // Check if already has API if (StringUtils::contains(trimmed, dllApi)) { return false; } // Add API to template specialization std::string fixedLine = addAPIToTemplateSpecialization(trimmed, dllApi); if (fixedLine != line) { lines[currentLine] = fixedLine; std::cout << "ADDED API to template specialization in " << filePath << ":\n"; std::cout << " BEFORE: " << trimmed << "\n"; std::cout << " AFTER: " << fixedLine << std::endl; return true; } return false; } // Check if line is a static member definition bool isStaticMemberDefinition(const std::string& line) { std::string trimmed = StringUtils::trim(line); // Pattern: type class_name::member = value; if (!StringUtils::contains(trimmed, "::")) return false; if (!StringUtils::contains(trimmed, "=")) return false; if (!StringUtils::contains(trimmed, ";")) return false; // Check if it's a SystemC related class std::vector<std::string> systemcClasses = { "sc_", "tlm_", "vcd_", "signal_" }; for (const auto& className : systemcClasses) { if (StringUtils::contains(trimmed, className) && StringUtils::contains(trimmed, "::")) { return true; } } return false; } // Process static member definition bool processStaticMemberDefinition(std::vector<std::string>& lines, size_t currentLine, const std::string& dllApi, const std::string& filePath) { std::string line = lines[currentLine]; std::string trimmed = StringUtils::trim(line); // Check if already has API if (StringUtils::contains(trimmed, dllApi)) { return false; } // Add API to static member definition std::string fixedLine = addAPIToStaticMemberDefinition(trimmed, dllApi); if (fixedLine != line) { lines[currentLine] = fixedLine; std::cout << "ADDED API to static member definition in " << filePath << ":\n"; std::cout << " BEFORE: " << trimmed << "\n"; std::cout << " AFTER: " << fixedLine << std::endl; return true; } return false; } // Add API to function definition std::string addAPIToFunctionDefinition(const std::string& line, const std::string& dllApi) { // Add API at the beginning of function definition return dllApi + " " + line; } // Add API to template specialization std::string addAPIToTemplateSpecialization(const std::string& line, const std::string& dllApi) { // Pattern: template class ClassName<Args>; // Change to: template class SYSTEMC_DLL_API ClassName<Args>; return StringUtils::replace(line, "template class", "template class " + dllApi); } // Add API to static member definition std::string addAPIToStaticMemberDefinition(const std::string& line, const std::string& dllApi) { // Add API at the beginning of static member definition return dllApi + " " + line; } // ULTIMATE FIX: Template class API placement for header files with inheritance support bool ultimateTemplateFix(std::vector<std::string>& lines, size_t currentLine, const std::string& dllApi, const std::string& filePath) { std::string line = lines[currentLine]; std::string trimmed = StringUtils::trim(line); // Debug output std::cout << "DEBUG Processing template: " << trimmed << std::endl; // Basic checks if (!StringUtils::contains(trimmed, "template") || (!StringUtils::contains(trimmed, "class") && !StringUtils::contains(trimmed, "typename"))) { return false; } // Skip if already has API if (StringUtils::contains(trimmed, dllApi)) { std::cout << "DEBUG: Already has API, skipping" << std::endl; return false; } // Check if this is a template parameter declaration (like template<class T>) if (isTemplateParameterDeclaration(trimmed)) { std::cout << "DEBUG: Skipping template parameter declaration" << std::endl; return false; } // For all other cases, add API std::string fixedLine = addAPIToTemplateClass(trimmed, dllApi); if (fixedLine != line) { lines[currentLine] = fixedLine; std::cout << "SUCCESS: Added API to template in " << filePath << ":\n"; std::cout << " BEFORE: " << trimmed << "\n"; std::cout << " AFTER: " << fixedLine << std::endl; return true; } return false; } // Add API to template class (handles inheritance) std::string addAPIToTemplateClass(const std::string& line, const std::string& dllApi) { std::string result = line; // Find the class keyword after template size_t templatePos = result.find("template"); if (templatePos == std::string::npos) return line; // Find the second "class" keyword (the actual class declaration) size_t firstClassPos = result.find("class", templatePos); if (firstClassPos == std::string::npos) { firstClassPos = result.find("typename", templatePos); if (firstClassPos == std::string::npos) return line; } // Find the actual class declaration (second "class" keyword) size_t secondClassPos = result.find("class", firstClassPos + 5); if (secondClassPos == std::string::npos) { // If no second class, it might be a template alias or other construct return line; } // Position after second "class" size_t afterClass = secondClassPos + 5; while (afterClass < result.length() && std::isspace(result[afterClass])) { afterClass++; } if (afterClass >= result.length()) return line; // Insert API after the second "class" keyword result = result.substr(0, afterClass) + dllApi + " " + result.substr(afterClass); return result; } void generateConfigFile(const std::string& outputDir) { std::string configPath = outputDir + "\\config.hpp"; if (FileSystemUtils::fileExists(configPath)) { std::cout << "config.hpp already exists, skipping generation" << std::endl; return; } std::string content = "#ifndef __CONFIG_HPP__\r\n" "#define __CONFIG_HPP__\r\n" "\r\n" "#undef SYSTEMC_DLL_API\r\n" "#undef TLM_DLL_API\r\n" "\r\n" "// C++11 Configuration for VS2015\r\n" "#if defined(_MSC_VER) && (_MSC_VER < 1900)\r\n" " #error \"Visual Studio 2015 (VC++ 14.0) or later is required for C++11 support\"\r\n" "#endif\r\n" "\r\n" "// DLL Configuration\r\n" "#define SYSTEMC_DLL // Enable DLL support\r\n" "#define SYSTEMC_DLL_EXPORT // Define this to export DLL symbols\r\n" "\r\n" "#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS)\r\n" " #ifdef SYSTEMC_DLL\r\n" " #ifdef SYSTEMC_DLL_EXPORT\r\n" " #define SYSTEMC_DLL_API __declspec(dllexport)\r\n" " #else\r\n" " #define SYSTEMC_DLL_API __declspec(dllimport)\r\n" " #endif\r\n" "\r\n" " // Disable VS2015 warnings for DLL exports\r\n" " #ifdef _MSC_VER\r\n" " #pragma warning(push)\r\n" " #pragma warning(disable: 4251) // class needs dll-interface\r\n" " #pragma warning(disable: 4275) // non dll-interface base class\r\n" " #endif\r\n" "\r\n" " #else\r\n" " #define SYSTEMC_DLL_API\r\n" " #endif\r\n" "#else\r\n" " #define SYSTEMC_DLL_API\r\n" "#endif\r\n" "\r\n" "// TLM DLL API definition\r\n" "#define TLM_DLL_API SYSTEMC_DLL_API\r\n" "\r\n" "// C++11 standard library includes\r\n" "#include <cstdint>\r\n" "#include <memory>\r\n" "#include <string>\r\n" "#include <vector>\r\n" "\r\n" "#endif // __CONFIG_HPP__\r\n"; std::ofstream file(configPath, std::ios::binary); if (file.is_open()) { file.write(content.c_str(), content.length()); file.close(); std::cout << "Generated config.hpp at: " << configPath << std::endl; } else { std::cerr << "Failed to generate config.hpp" << std::endl; } } bool readFile(const std::string& filePath, std::vector<std::string>& lines) { std::ifstream file(filePath, std::ios::binary); if (!file.is_open()) { std::cerr << "Cannot open file for reading: " << filePath << std::endl; return false; } lines.clear(); std::string line; while (std::getline(file, line)) { // Handle Windows line endings if (!line.empty() && line.back() == '\r') { line.pop_back(); } lines.push_back(line); } if (file.bad()) { std::cerr << "Error reading file: " << filePath << std::endl; file.close(); return false; } file.close(); return true; } bool writeFile(const std::string& filePath, const std::vector<std::string>& lines) { std::ofstream file(filePath, std::ios::binary); if (!file.is_open()) { std::cerr << "Cannot open file for writing: " << filePath << std::endl; return false; } for (const auto& line : lines) { file << line << "\r\n"; } if (file.bad()) { std::cerr << "Error writing file: " << filePath << std::endl; file.close(); return false; } file.close(); return true; } bool createBackupDirectory(const std::string& sourceDir) { if (!FileSystemUtils::directoryExists(sourceDir)) { std::cerr << "Source directory does not exist: " << sourceDir << std::endl; return false; } // Generate timestamped backup directory name SYSTEMTIME st; GetLocalTime(&st); char timeBuffer[256]; sprintf_s(timeBuffer, "SystemC_Backup_%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); backupDir = timeBuffer; std::cout << "Creating backup: " << backupDir << std::endl; // Create backup directory if (!FileSystemUtils::createDirectoryRecursive(backupDir)) { std::cerr << "Failed to create backup directory: " << backupDir << std::endl; return false; } // Copy files std::vector<std::string> files; std::vector<std::string> directories; if (!FileSystemUtils::findFiles(sourceDir, files, directories, true)) { std::cerr << "Failed to enumerate files for backup" << std::endl; return false; } int copiedFiles = 0; int failedFiles = 0; int totalFiles = static_cast<int>(files.size()); std::cout << "Found " << totalFiles << " files to backup" << std::endl; for (int i = 0; i < totalFiles; ++i) { const auto& file = files[i]; // Calculate relative path std::string relativePath = getRelativePath(sourceDir, file); if (relativePath.empty()) { failedFiles++; continue; } std::string targetPath = backupDir + "\\" + relativePath; if (FileSystemUtils::copyFile(file, targetPath)) { copiedFiles++; } else { failedFiles++; std::cerr << "Failed to copy: " << file << std::endl; } // Show progress if ((i + 1) % 100 == 0 || (i + 1) == totalFiles) { int percent = (i + 1) * 100 / totalFiles; std::cout << "Backup progress: " << (i + 1) << "/" << totalFiles << " files (" << percent << "%)" << std::endl; } } std::cout << "\nBackup completed:" << std::endl; std::cout << " Successfully copied: " << copiedFiles << " files" << std::endl; std::cout << " Failed: " << failedFiles << " files" << std::endl; std::cout << " Backup location: " << backupDir << std::endl; if (failedFiles > 0) { std::cout << "WARNING: " << failedFiles << " files failed to backup!" << std::endl; } return failedFiles == 0; } std::string getRelativePath(const std::string& baseDir, const std::string& fullPath) { if (fullPath.find(baseDir) != 0) { return fullPath; } std::string relative = fullPath.substr(baseDir.length()); // Remove leading path separators while (!relative.empty() && (relative[0] == '\\' || relative[0] == '/')) { relative = relative.substr(1); } return relative; } }; // Help information void printHelp() { std::cout << R"( ======================================================================== SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix ================================================================ ENHANCED VERSION: Now supports .cpp file class definitions and comment headers! ULTIMATE FIX: - Completely fixed template class DLL API placement error - Now supports .cpp file class definitions - Handles comment headers above class declarations - Supports template class inheritance patterns ================================================================ Usage: systemc_modifier_ultimate.exe <SystemC_directory> [options] Options: /dryrun Dry run mode (test without modifying files) /backup Create backup directory before modifications /help Display this help information /force Force processing even if backup fails Examples: systemc_modifier_ultimate.exe C:\systemc-2.3.1a systemc_modifier_ultimate.exe C:\systemc-2.3.1a /dryrun systemc_modifier_ultimate.exe C:\systemc-2.3.1a /backup systemc_modifier_ultimate.exe /help NEW FEATURES: 1. Support for .cpp file class member function definitions 2. Support for template specializations in .cpp files 3. Support for static member definitions in .cpp files 4. Enhanced pattern matching for comment headers 5. Improved template class API placement Supported Patterns in .cpp files: Pattern 1: Class member function definitions void sc_vcd_trace::write_comment(const std::string& comment) { // implementation } Pattern 2: Template specializations template class vcd_T_trace<bool>; template class vcd_T_trace<sc_dt::sc_logic>; Pattern 3: Static member definitions int sc_vcd_trace::instance_count = 0; Fixed Output for .cpp files: SYSTEMC_DLL_API void sc_vcd_trace::write_comment(const std::string& comment) { // implementation } template class SYSTEMC_DLL_API vcd_T_trace<bool>; template class SYSTEMC_DLL_API vcd_T_trace<sc_dt::sc_logic>; SYSTEMC_DLL_API int sc_vcd_trace::instance_count = 0; Supported Patterns in .h files: Pattern 1: Comment headers // ---------------------------------------------------------------------------- // CLASS : vcd_trace // // Base class for VCD traces. // ---------------------------------------------------------------------------- class vcd_trace { Pattern 2: Template class inheritance template <class T> class vcd_T_trace : public vcd_trace { Fixed Output for .h files: // ---------------------------------------------------------------------------- // CLASS : vcd_trace // // Base class for VCD traces. // ---------------------------------------------------------------------------- class SYSTEMC_DLL_API vcd_trace { template <class T> class SYSTEMC_DLL_API vcd_T_trace : public vcd_trace { Enhanced Features: 1. Automatically add #include "config.hpp" to SystemC headers AND source files 2. Add SYSTEMC_DLL_API or TLM_DLL_API export macros to classes 3. Generate config.hpp configuration file 4. Create timestamped backup directories 5. Process .h and .cpp files recursively 6. Skip build directories and version control directories 7. Retry mechanism for file operations 8. Detailed progress reporting 9. ULTIMATE template API placement fix 10. .cpp file class definition support 11. Comment header support 12. Template inheritance support Important Notes: 1. Always backup your important code before making modifications! 2. Test with /dryrun first to see what will be modified 3. The program will ask for confirmation if backup fails 4. Generated config.hpp includes proper warning suppression 5. Run as Administrator for system-protected directories ================================================================ )" << std::endl; } // Print statistics void printStatistics(const Statistics& stats, bool dryRun, const std::string& backupDir) { std::cout << "\n" << std::string(60, '=') << "\n"; std::cout << "PROCESSING COMPLETED\n"; std::cout << std::string(60, '=') << "\n"; std::cout << "Total files: " << stats.totalFiles << "\n"; std::cout << "Processed files: " << stats.processedFiles << "\n"; std::cout << "Modified files: " << stats.modifiedFiles << "\n"; std::cout << "Skipped files: " << stats.skippedFiles << "\n"; std::cout << "Error files: " << stats.errorFiles << "\n"; if (!backupDir.empty()) { std::cout << "\nBackup created: " << backupDir << "\n"; } if (dryRun) { std::cout << "\nMODE: DRY RUN - No files were actually modified\n"; std::cout << "To actually modify files, run without /dryrun option\n"; } std::cout << std::string(60, '=') << "\n"; } // Main function int main(int argc, char* argv[]) { std::cout << "========================================================================\n"; std::cout << " SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix\n"; std::cout << " ================================================================\n"; std::cout << " Enhanced Version: Now supports .cpp file class definitions!\n"; std::cout << " Completely fixed template class DLL API position error\n"; std::cout << "========================================================================\n\n"; if (argc < 2) { printHelp(); return 1; } std::string sourceDir = argv[1]; bool dryRun = false; bool createBackup = false; bool forceMode = false; // Parse command line arguments for (int i = 2; i < argc; ++i) { std::string arg = argv[i]; std::string lowerArg = arg; std::transform(lowerArg.begin(), lowerArg.end(), lowerArg.begin(), ::tolower); if (lowerArg == "/dryrun" || lowerArg == "-dryrun" || lowerArg == "/d") { dryRun = true; } else if (lowerArg == "/backup" || lowerArg == "-backup" || lowerArg == "/b") { createBackup = true; } else if (lowerArg == "/help" || lowerArg == "-help" || lowerArg == "/h" || lowerArg == "/?") { printHelp(); return 0; } else if (lowerArg == "/force" || lowerArg == "-force" || lowerArg == "/f") { forceMode = true; } else { std::cout << "Unknown option: " << arg << "\n"; std::cout << "Use /help for usage information\n"; return 1; } } // Display mode information std::cout << "Mode: " << (dryRun ? "Dry Run (no modifications)" : createBackup ? "Normal with Backup" : "Normal") << "\n"; std::cout << "Target: " << sourceDir << "\n"; std::cout << "Force mode: " << (forceMode ? "Yes" : "No") << "\n"; std::cout << "C++ Standard: C++11\n"; std::cout << "Compiler: Visual Studio 2015\n"; std::cout << "Fix: Ultimate template API placement fix\n"; std::cout << "Enhanced: .cpp file class definition support\n"; std::cout << std::string(60, '-') << "\n\n"; // Create processor SystemCDLLModifier modifier(dryRun, createBackup); try { if (modifier.processDirectory(sourceDir)) { Statistics stats = modifier.getStatistics(); std::string backupDir = modifier.getBackupDir(); printStatistics(stats, dryRun, backupDir); std::cout << "\nNEXT STEPS:\n"; std::cout << "1. Review modified files for any issues\n"; std::cout << "2. Create a new DLL project in Visual Studio 2015\n"; std::cout << "3. Add SYSTEMC_DLL_EXPORT to preprocessor definitions\n"; std::cout << "4. Add all SystemC source files to the project\n"; std::cout << "5. Build the systemc.dll\n"; std::cout << "6. Test with your SystemC applications\n"; if (!dryRun && backupDir.empty() && createBackup) { std::cout << "\nWARNING: Backup was not created!\n"; std::cout << "Consider creating a manual backup before proceeding.\n"; } std::cout << "\nProcessing completed " << (dryRun ? "in dry run mode" : "successfully") << "!\n"; } else { std::cout << "\nERROR: Processing failed!\n"; std::cout << "Possible reasons:\n"; std::cout << "1. Invalid SystemC directory\n"; std::cout << "2. Permission issues\n"; std::cout << "3. Disk space problems\n"; std::cout << "4. File system errors\n"; return 1; } } catch (const std::exception& e) { std::cerr << "\nFATAL ERROR: " << e.what() << "\n"; std::cerr << "Please check:\n"; std::cerr << "1. Directory permissions\n"; std::cerr << "2. Disk space\n"; std::cerr << "3. File system integrity\n"; return 1; } return 0; }
01-02
plugins { id 'com.android.application' } final def ISA_NAVI_INTERNAL_VERSION = getInternalVersionCode() android { compileSdkVersion 30 //buildToolsVersion "29.0.3" signingConfigs { releaseConfig { keyAlias 'android_box' keyPassword 'android_box' storeFile file(rootDir.getAbsolutePath() + '/KeyStore/platform.keystore') storePassword 'android_box' } debugConfig { keyAlias 'android_box' keyPassword 'android_box' storeFile file(rootDir.getAbsolutePath() + '/KeyStore/platform.keystore') storePassword 'android_box' } } defaultConfig { applicationId "com.isa.navi" minSdkVersion 27 targetSdkVersion 30 versionCode getVersionCode() versionName getVersionName() signingConfig signingConfigs.releaseConfig buildConfigField "String", "BUILD_TIMESTAMP", getDate() ndk { // abiFilters "arm64-v8a", "armeabi-v7a", "x86", "x86_64" abiFilters "armeabi-v7a" } } packagingOptions { // exclude 'lib/armeabi-v7a/libIsaEngineJni.so' exclude 'lib/armeabi-v7a/libupdate-sdk.so' exclude 'lib/armeabi-v7a/libnative-lib.so' } buildTypes { debug { shrinkResources false minifyEnabled false zipAlignEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debugConfig buildConfigField("String", "ISA_NAVI_VERSION_INFO", '"DEBUG_' + ISA_NAVI_INTERNAL_VERSION + '; ' + getVersionName() + '; ' + getVersionCode() + '"') buildConfigField "int", "LOG_FLAG", "0" externalNativeBuild { cmake { // 设置 CMAKE_BUILD_TYPE arguments "-DCMAKE_BUILD_TYPE=Release" arguments "-DENABLE_VIEWER_TOOL=ON" } } } release_st { shrinkResources true minifyEnabled true zipAlignEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.releaseConfig buildConfigField("String", "ISA_NAVI_VERSION_INFO", '"RELEASE_ST_' + ISA_NAVI_INTERNAL_VERSION + '; ' + getVersionName() + '; ' + getVersionCode() + '"') buildConfigField "int", "LOG_FLAG", "1" externalNativeBuild { cmake { // 设置 CMAKE_BUILD_TYPE arguments "-DCMAKE_BUILD_TYPE=Release" arguments "-DENABLE_VIEWER_TOOL=ON" } } } release { shrinkResources true minifyEnabled true zipAlignEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.releaseConfig buildConfigField("String", "ISA_NAVI_VERSION_INFO", '"RELEASE_' + ISA_NAVI_INTERNAL_VERSION + '; ' + getVersionName() + '; ' + getVersionCode() + '"') buildConfigField "int", "LOG_FLAG", "2" externalNativeBuild { cmake { // 设置 CMAKE_BUILD_TYPE arguments "-DCMAKE_BUILD_TYPE=Release" arguments "-DENABLE_VIEWER_TOOL=ON" } } } release_sop { shrinkResources true minifyEnabled true zipAlignEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.releaseConfig buildConfigField("String", "ISA_NAVI_VERSION_INFO", '"RELEASE_SOP_' + ISA_NAVI_INTERNAL_VERSION + '; ' + getVersionName() + '; ' + getVersionCode() + '"') buildConfigField "int", "LOG_FLAG", "3" externalNativeBuild { cmake { // 设置 CMAKE_BUILD_TYPE arguments "-DCMAKE_BUILD_TYPE=Release" arguments "-DENABLE_VIEWER_TOOL=OFF" } } } } externalNativeBuild { cmake { path "../../CMakeLists.txt" // version "3.10.2" } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } android.applicationVariants.all { variant -> variant.outputs.all { //这里修改apk文件名 outputFileName = "S32_ISA_Navi.apk" } } sourceSets { main { // jniLibs.srcDirs = ["libs"] java.srcDirs = ['src/main/java'] aidl.srcDirs = ['src/main/aidl'] // assets.srcDirs = ['src/main/assets'] // manifest.srcFile 'src/main/AndroidManifest.xml' } } repositories { flatDir { dirs 'libs' } } ndkVersion '21.4.7075529' /*lintOptions { checkReleaseBuilds false }*/ } dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' implementation files('libs/dfcar.jar') // implementation 'org.jetbrains:annotations:15.0' compileOnly files('libs/DFAPI.jar') compileOnly files('libs/framework.jar') implementation files('libs/dfcert_hal.jar') implementation project(':isa-navilib') implementation project(':isa-cplib') implementation 'com.google.code.gson:gson:2.8.6' implementation 'org.bouncycastle:bcprov-jdk15on:1.70' implementation 'org.bouncycastle:bcpkix-jdk15on:1.70' } static def getVersionCode() { // def cmd = 'git rev-list --count HEAD' def code = 1 // if (cmd.execute().text.length() > 0) { // try { // code = Integer.decode(cmd.execute().text.trim()) // } catch (Exception ignore) { // } // } println("getVersionCode -> " + code) code } static def getGitCommitDate() { // def cmd = 'git log --pretty=format:%at -1' //def gitCommit = cmd.execute().text.trim() + "000" def formattedDate = "2023-11-10"//new Date(Long.decode(gitCommit)).format('yyyy-MM-dd') println("getGitCommitDate -> " + formattedDate) formattedDate } static def getVersionName() { // def xml = new XmlSlurper().parse(new File("AndroidManifest.xml")) // xml.declareNamespace('android': 'http://schemas.android.com/apk/res/android') // return xml.application.@'android:versionName' return getGitCommitDate(); } static def getInternalVersionCode() { def result = 'UNKONWN' // tryitId.length() - 8).toUpperCase() // } catch (Exception { //// def cmd = 'git rev-list HEAD --max-count=1' //// def commitId = cmd.execute().text.trim() //// result = commitId.substring(comm ignore) { // } result } std::String getDate() { Date date = new Date(); String dates = "\""+date.format("yyyy-MM-dd hh:mm:ss", TimeZone.getTimeZone("UTC"))+"\""; return dates; }
08-02
下载前可以先看下教程 https://pan.quark.cn/s/a426667488ae 标题“仿淘宝jquery图片左右切换带数字”揭示了这是一个关于运用jQuery技术完成的图片轮播机制,其特色在于具备淘宝在线平台普遍存在的图片切换表现,并且在整个切换环节中会展示当前图片的序列号。 此类功能一般应用于电子商务平台的产品呈现环节,使用户可以便捷地查看多张商品的照片。 说明中的“NULL”表示未提供进一步的信息,但我们可以借助标题来揣摩若干核心的技术要点。 在构建此类功能时,开发者通常会借助以下技术手段:1. **jQuery库**:jQuery是一个应用广泛的JavaScript框架,它简化了HTML文档的遍历、事件管理、动画效果以及Ajax通信。 在此项目中,jQuery将负责处理用户的点击动作(实现左右切换),并且制造流畅的过渡效果。 2. **图片轮播扩展工具**:开发者或许会采用现成的jQuery扩展,例如Slick、Bootstrap Carousel或个性化的轮播函数,以达成图片切换的功能。 这些扩展能够辅助迅速构建功能完善的轮播模块。 3. **即时数字呈现**:展示当前图片的序列号,这需要通过JavaScript或jQuery来追踪并调整。 每当图片切换时,相应的数字也会同步更新。 4. **CSS美化**:为了达成淘宝图片切换的视觉效果,可能需要设计特定的CSS样式,涵盖图片的排列方式、过渡效果、点状指示器等。 CSS3的动画和过渡特性(如`transition`和`animation`)在此过程中扮演关键角色。 5. **事件监测**:运用jQuery的`.on()`方法来监测用户的操作,比如点击左右控制按钮或自动按时间间隔切换。 根据用户的交互,触发相应的函数来执行...
垃圾实例分割数据集 一、基础信息 • 数据集名称:垃圾实例分割数据集 • 图片数量: 训练集:7,000张图片 验证集:426张图片 测试集:644张图片 • 训练集:7,000张图片 • 验证集:426张图片 • 测试集:644张图片 • 分类类别: 垃圾(Sampah) • 垃圾(Sampah) • 标注格式:YOLO格式,包含实例分割的多边形点坐标,适用于实例分割任务。 • 数据格式:图片文件 二、适用场景 • 智能垃圾检测系统开发:数据集支持实例分割任务,帮助构建能够自动识别和分割图像中垃圾区域的AI模型,适用于智能清洁机器人、自动垃圾桶等应用。 • 环境监控与管理:集成到监控系统中,用于实时检测公共区域的垃圾堆积,辅助环境清洁和治理决策。 • 计算机视觉研究:支持实例分割算法的研究和优化,特别是在垃圾识别领域,促进AI在环保方面的创新。 • 教育与实践:可用于高校或培训机构的AI课程,作为实例分割技术的实践数据集,帮助学生理解计算机视觉应用。 三、数据集优势 • 精确的实例分割标注:每个垃圾实例都使用详细的多边形点进行标注,确保分割边界准确,提升模型训练效果。 • 数据多样性:包含多种垃圾物品实例,覆盖不同场景,增强模型的泛化能力和鲁棒性。 • 格式兼容性强:YOLO标注格式易于与主流深度学习框架集成,如YOLO系列、PyTorch等,方便研究人员和开发者使用。 • 实际应用价值:直接针对现实世界的垃圾管理需求,为自动化环保解决方案提供可靠数据支持,具有重要的社会意义。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值