Skip to main content
Glama
ilogger.cc30.6 kB
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Based on https://github.com/shouxieai/tensorRT_Pro // Copyright (c) 2022 TensorRTPro // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software && associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, &&/|| sell // copies of the Software, && to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice && this permission notice shall be included in // all copies || substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include "ilogger.h" #include <math.h> #include <signal.h> #include <stdarg.h> #include <string.h> #include <time.h> #include <algorithm> #include <atomic> #include <fstream> #include <functional> #include <memory> #include <mutex> #include <sstream> #include <stack> #include <string> #include <thread> #include <vector> #if defined(U_OS_WINDOWS) #define HAS_UUID #include <Shlwapi.h> #include <Windows.h> #include <wingdi.h> #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "ole32.lib") #pragma comment(lib, "gdi32.lib") #undef min #undef max #endif #if defined(U_OS_LINUX) //# include <sys/io.h> #include <dirent.h> #include <stdarg.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #define strtok_s strtok_r #endif #if defined(U_OS_LINUX) #define __GetTimeBlock \ time_t timep; \ time(&timep); \ tm &t = *(tm *)localtime(&timep); #endif #if defined(U_OS_WINDOWS) #define __GetTimeBlock \ tm t; \ _getsystime(&t); #endif namespace iLogger { using namespace std; const char *level_string(LogLevel level) { switch (level) { case LogLevel::Debug: return "debug"; case LogLevel::Verbose: return "verbo"; case LogLevel::Info: return "info"; case LogLevel::Warning: return "warn"; case LogLevel::Error: return "error"; case LogLevel::Fatal: return "fatal"; default: return "unknown"; } } std::tuple<uint8_t, uint8_t, uint8_t> hsv2bgr(float h, float s, float v) { const int h_i = static_cast<int>(h * 6); const float f = h * 6 - h_i; const float p = v * (1 - s); const float q = v * (1 - f * s); const float t = v * (1 - (1 - f) * s); float r, g, b; switch (h_i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; default: r = 1; g = 1; b = 1; break; } return make_tuple(static_cast<uint8_t>(b * 255), static_cast<uint8_t>(g * 255), static_cast<uint8_t>(r * 255)); } std::tuple<uint8_t, uint8_t, uint8_t> random_color(int id) { float h_plane = ((((unsigned int)id << 2) ^ 0x937151) % 100) / 100.0f; ; float s_plane = ((((unsigned int)id << 3) ^ 0x315793) % 100) / 100.0f; return hsv2bgr(h_plane, s_plane, 1); } string date_now() { char time_string[20]; __GetTimeBlock; sprintf(time_string, "%04d-%02d-%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday); return time_string; } string time_now() { char time_string[20]; __GetTimeBlock; sprintf(time_string, "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); return time_string; } size_t file_size(const string &file) { #if defined(U_OS_LINUX) struct stat st; stat(file.c_str(), &st); return st.st_size; #elif defined(U_OS_WINDOWS) WIN32_FIND_DATAA find_data; HANDLE hFind = FindFirstFileA(file.c_str(), &find_data); if (hFind == INVALID_HANDLE_VALUE) return 0; FindClose(hFind); return (uint64_t)find_data.nFileSizeLow | ((uint64_t)find_data.nFileSizeHigh << 32); #endif } time_t last_modify(const string &file) { #if defined(U_OS_LINUX) struct stat st; stat(file.c_str(), &st); return st.st_mtim.tv_sec; #elif defined(U_OS_WINDOWS) INFOW("LastModify has not support on windows os"); return 0; #endif } void sleep(int ms) { this_thread::sleep_for(std::chrono::milliseconds(ms)); } int get_month_by_name(char *month) { if (strcmp(month, "Jan") == 0) return 0; if (strcmp(month, "Feb") == 0) return 1; if (strcmp(month, "Mar") == 0) return 2; if (strcmp(month, "Apr") == 0) return 3; if (strcmp(month, "May") == 0) return 4; if (strcmp(month, "Jun") == 0) return 5; if (strcmp(month, "Jul") == 0) return 6; if (strcmp(month, "Aug") == 0) return 7; if (strcmp(month, "Sep") == 0) return 8; if (strcmp(month, "Oct") == 0) return 9; if (strcmp(month, "Nov") == 0) return 10; if (strcmp(month, "Dec") == 0) return 11; return -1; } int get_week_day_by_name(char *wday) { if (strcmp(wday, "Sun") == 0) return 0; if (strcmp(wday, "Mon") == 0) return 1; if (strcmp(wday, "Tue") == 0) return 2; if (strcmp(wday, "Wed") == 0) return 3; if (strcmp(wday, "Thu") == 0) return 4; if (strcmp(wday, "Fri") == 0) return 5; if (strcmp(wday, "Sat") == 0) return 6; return -1; } time_t gmtime2ctime(const string &gmt) { char week[4] = {0}; char month[4] = {0}; tm date; sscanf(gmt.c_str(), "%3s, %2d %3s %4d %2d:%2d:%2d GMT", week, &date.tm_mday, month, &date.tm_year, &date.tm_hour, &date.tm_min, &date.tm_sec); date.tm_mon = get_month_by_name(month); date.tm_wday = get_week_day_by_name(week); date.tm_year = date.tm_year - 1900; return mktime(&date); } string gmtime(time_t t) { t += 28800; tm *gmt = ::gmtime(&t); // http://en.cppreference.com/w/c/chrono/strftime // e.g.: Sat, 22 Aug 2015 11:48:50 GMT // 5+ 3+4+ 5+ 9+ 3 = 29 const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; char tstr[30]; strftime(tstr, sizeof(tstr), fmt, gmt); return tstr; } string gmtime_now() { return gmtime(time(nullptr)); } bool mkdir(const string &path) { #ifdef U_OS_WINDOWS return CreateDirectoryA(path.c_str(), nullptr); #else return ::mkdir(path.c_str(), 0755) == 0; #endif } bool mkdirs(const string &path) { if (path.empty()) return false; if (exists(path)) return true; string _path = path; char *dir_ptr = (char *)_path.c_str(); char *iter_ptr = dir_ptr; bool keep_going = *iter_ptr != 0; while (keep_going) { if (*iter_ptr == 0) keep_going = false; #ifdef U_OS_WINDOWS if (*iter_ptr == '/' || *iter_ptr == '\\' || *iter_ptr == 0) { #else if ((*iter_ptr == '/' && iter_ptr != dir_ptr) || *iter_ptr == 0) { #endif char old = *iter_ptr; *iter_ptr = 0; if (!exists(dir_ptr)) { if (!mkdir(dir_ptr)) { if (!exists(dir_ptr)) { INFOE("mkdirs %s return false.", dir_ptr); return false; } } } *iter_ptr = old; } iter_ptr++; } return true; } bool isfile(const string &file) { #if defined(U_OS_LINUX) struct stat st; stat(file.c_str(), &st); return S_ISREG(st.st_mode); #elif defined(U_OS_WINDOWS) INFOW("is_file has not support on windows os"); return 0; #endif } FILE *fopen_mkdirs(const string &path, const string &mode) { FILE *f = fopen(path.c_str(), mode.c_str()); if (f) return f; int p = path.rfind('/'); #if defined(U_OS_WINDOWS) int e = path.rfind('\\'); p = std::max(p, e); #endif if (p == -1) return nullptr; string directory = path.substr(0, p); if (!mkdirs(directory)) return nullptr; return fopen(path.c_str(), mode.c_str()); } bool exists(const string &path) { #ifdef U_OS_WINDOWS return ::PathFileExistsA(path.c_str()); #elif defined(U_OS_LINUX) return access(path.c_str(), R_OK) == 0; #endif } string format(const char *fmt, ...) { va_list vl; va_start(vl, fmt); char buffer[2048]; vsnprintf(buffer, sizeof(buffer), fmt, vl); return buffer; } string file_name(const string &path, bool include_suffix) { if (path.empty()) return ""; int p = path.rfind('/'); #ifdef U_OS_WINDOWS int e = path.rfind('\\'); p = std::max(p, e); #endif p += 1; // include suffix if (include_suffix) return path.substr(p); int u = path.rfind('.'); if (u == -1) return path.substr(p); if (u <= p) u = path.size(); return path.substr(p, u - p); } string directory(const string &path) { if (path.empty()) return "."; int p = path.rfind('/'); #ifdef U_OS_WINDOWS int e = path.rfind('\\'); p = std::max(p, e); #endif if (p == -1) return "."; return path.substr(0, p + 1); } bool begin_with(const string &str, const string &with) { if (str.length() < with.length()) return false; return strncmp(str.c_str(), with.c_str(), with.length()) == 0; } bool end_with(const string &str, const string &with) { if (str.length() < with.length()) return false; return strncmp(str.c_str() + str.length() - with.length(), with.c_str(), with.length()) == 0; } long long timestamp_now() { #ifdef _WIN32 FILETIME ft; GetSystemTimeAsFileTime(&ft); ULARGE_INTEGER li; li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; return (li.QuadPart - 116444736000000000LL) / 10000LL; #else return chrono::duration_cast<chrono::milliseconds>( chrono::system_clock::now().time_since_epoch()) .count(); #endif } double timestamp_now_float() { #ifdef _WIN32 FILETIME ft; GetSystemTimeAsFileTime(&ft); ULARGE_INTEGER li; li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; return ((li.QuadPart - 116444736000000000LL) / 10000.0); #else return chrono::duration_cast<chrono::microseconds>( chrono::system_clock::now().time_since_epoch()) .count() / 1000.0; #endif } static struct Logger { mutex logger_lock_; string logger_directory; LogLevel logger_level{LogLevel::Info}; vector<string> cache_, local_; shared_ptr<thread> flush_thread_; atomic<bool> keep_run_{false}; shared_ptr<FILE> handler; bool logger_shutdown{false}; void write(const string &line) { lock_guard<mutex> l(logger_lock_); if (logger_shutdown) return; if (!keep_run_) { if (flush_thread_) return; cache_.reserve(1000); keep_run_ = true; flush_thread_.reset(new thread(std::bind(&Logger::flush_job, this))); } cache_.emplace_back(line); } void flush() { if (cache_.empty()) return; { std::lock_guard<mutex> l(logger_lock_); std::swap(local_, cache_); } if (!local_.empty() && !logger_directory.empty()) { auto now = date_now(); auto file = format("%s%s.txt", logger_directory.c_str(), now.c_str()); if (!exists(file)) { handler.reset(fopen_mkdirs(file, "wb"), fclose); } else if (!handler) { handler.reset(fopen_mkdirs(file, "a+"), fclose); } if (handler) { for (auto &line : local_) fprintf(handler.get(), "%s\n", line.c_str()); fflush(handler.get()); handler.reset(); } } local_.clear(); } void flush_job() { auto tick_begin = timestamp_now(); std::vector<string> local; while (keep_run_) { if (timestamp_now() - tick_begin < 1000) { this_thread::sleep_for(std::chrono::milliseconds(100)); continue; } tick_begin = timestamp_now(); flush(); } flush(); } void set_save_directory(const string &loggerDirectory) { logger_directory = loggerDirectory; if (logger_directory.empty()) logger_directory = "."; #if defined(U_OS_LINUX) if (logger_directory.back() != '/') { logger_directory.push_back('/'); } #endif #if defined(U_OS_WINDOWS) if (logger_directory.back() != '/' && logger_directory.back() != '\\') { logger_directory.push_back('/'); } #endif } void set_logger_level(LogLevel level) { logger_level = level; } void close() { { lock_guard<mutex> l(logger_lock_); if (logger_shutdown) return; logger_shutdown = true; }; if (!keep_run_) return; keep_run_ = false; flush_thread_->join(); flush_thread_.reset(); handler.reset(); } virtual ~Logger() { close(); } } __g_logger; void destroy_logger() { __g_logger.close(); } static void remove_color_text(char *buffer) { //"\033[31m%s\033[0m" char *p = buffer; while (*p) { if (*p == 0x1B) { char np = *(p + 1); if (np == '[') { // has token char *t = p + 2; while (*t) { if (*t == 'm') { t = t + 1; char *k = p; while (*t) { *k++ = *t++; } *k = 0; break; } t++; } } } p++; } } void set_logger_save_directory(const string &loggerDirectory) { __g_logger.set_save_directory(loggerDirectory); } void set_log_level(LogLevel level) { __g_logger.set_logger_level(level); } LogLevel get_log_level() { return __g_logger.logger_level; } void __log_func(const char *file, int line, LogLevel level, const char *fmt, ...) { if (level > __g_logger.logger_level) return; string now = time_now(); va_list vl; va_start(vl, fmt); char buffer[2048]; string filename = file_name(file, true); int n = snprintf(buffer, sizeof(buffer), "[%s]", now.c_str()); #if defined(U_OS_WINDOWS) if (level == LogLevel::Fatal || level == LogLevel::Error) { n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); } else if (level == LogLevel::Warning) { n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); } else { n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); } #elif defined(U_OS_LINUX) if (level == LogLevel::Fatal || level == LogLevel::Error) { n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[31m%s\033[0m]", level_string(level)); } else if (level == LogLevel::Warning) { n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[33m%s\033[0m]", level_string(level)); } else if (level == LogLevel::Info) { n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[35m%s\033[0m]", level_string(level)); } else if (level == LogLevel::Verbose) { n += snprintf(buffer + n, sizeof(buffer) - n, "[\033[34m%s\033[0m]", level_string(level)); } else { n += snprintf(buffer + n, sizeof(buffer) - n, "[%s]", level_string(level)); } #endif n += snprintf(buffer + n, sizeof(buffer) - n, "[%s:%d]:", filename.c_str(), line); vsnprintf(buffer + n, sizeof(buffer) - n, fmt, vl); if (level == LogLevel::Fatal || level == LogLevel::Error) { fprintf(stderr, "%s\n", buffer); } else if (level == LogLevel::Warning) { fprintf(stdout, "%s\n", buffer); } else { fprintf(stdout, "%s\n", buffer); } if (!__g_logger.logger_directory.empty()) { #ifdef U_OS_LINUX // remove save color txt remove_color_text(buffer); #endif __g_logger.write(buffer); if (level == LogLevel::Fatal) { __g_logger.flush(); } } if (level == LogLevel::Fatal) { fflush(stdout); abort(); } } string load_text_file(const string &file) { ifstream in(file, ios::in | ios::binary); if (!in.is_open()) return {}; in.seekg(0, ios::end); size_t length = in.tellg(); string data; if (length > 0) { in.seekg(0, ios::beg); data.resize(length); in.read((char *)&data[0], length); } in.close(); return data; } std::vector<uint8_t> load_file(const string &file) { ifstream in(file, ios::in | ios::binary); if (!in.is_open()) return {}; in.seekg(0, ios::end); size_t length = in.tellg(); std::vector<uint8_t> data; if (length > 0) { in.seekg(0, ios::beg); data.resize(length); in.read((char *)&data[0], length); } in.close(); return data; } bool alphabet_equal(char a, char b, bool ignore_case) { if (ignore_case) { a = a > 'a' && a < 'z' ? a - 'a' + 'A' : a; b = b > 'a' && b < 'z' ? b - 'a' + 'A' : b; } return a == b; } static bool pattern_match_body(const char *str, const char *matcher, bool igrnoe_case) { // abcdefg.pnga *.png > false // abcdefg.png *.png > true // abcdefg.png a?cdefg.png > true if (!matcher || !*matcher || !str || !*str) return false; const char *ptr_matcher = matcher; while (*str) { if (*ptr_matcher == '?') { ptr_matcher++; } else if (*ptr_matcher == '*') { if (*(ptr_matcher + 1)) { if (pattern_match_body(str, ptr_matcher + 1, igrnoe_case)) return true; } else { return true; } } else if (!alphabet_equal(*ptr_matcher, *str, igrnoe_case)) { return false; } else { if (*ptr_matcher) ptr_matcher++; else return false; } str++; } while (*ptr_matcher) { if (*ptr_matcher != '*') return false; ptr_matcher++; } return true; } bool pattern_match(const char *str, const char *matcher, bool igrnoe_case) { // abcdefg.pnga *.png > false // abcdefg.png *.png > true // abcdefg.png a?cdefg.png > true if (!matcher || !*matcher || !str || !*str) return false; char filter[500]; strcpy(filter, matcher); vector<const char *> arr; char *ptr_str = filter; char *ptr_prev_str = ptr_str; while (*ptr_str) { if (*ptr_str == ';') { *ptr_str = 0; arr.push_back(ptr_prev_str); ptr_prev_str = ptr_str + 1; } ptr_str++; } if (*ptr_prev_str) arr.push_back(ptr_prev_str); for (int i = 0; i < arr.size(); ++i) { if (pattern_match_body(str, arr[i], igrnoe_case)) return true; } return false; } #ifdef U_OS_WINDOWS vector<string> find_files(const string &directory, const string &filter, bool findDirectory, bool includeSubDirectory) { string realpath = directory; if (realpath.empty()) realpath = "./"; char backchar = realpath.back(); if (backchar != '\\' && backchar != '/') realpath += "/"; vector<string> out; _WIN32_FIND_DATAA find_data; stack<string> ps; ps.push(realpath); while (!ps.empty()) { string search_path = ps.top(); ps.pop(); HANDLE hFind = FindFirstFileA((search_path + "*").c_str(), &find_data); if (hFind != INVALID_HANDLE_VALUE) { do { if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) continue; if (!findDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY || findDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) { if (PathMatchSpecA(find_data.cFileName, filter.c_str())) out.push_back(search_path + find_data.cFileName); } if (includeSubDirectory && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) ps.push(search_path + find_data.cFileName + "/"); } while (FindNextFileA(hFind, &find_data)); FindClose(hFind); } } return out; } #endif #ifdef U_OS_LINUX vector<string> find_files(const string &directory, const string &filter, bool findDirectory, bool includeSubDirectory) { string realpath = directory; if (realpath.empty()) realpath = "./"; char backchar = realpath.back(); if (backchar != '\\' && backchar != '/') realpath += "/"; struct dirent *fileinfo; DIR *handle; stack<string> ps; vector<string> out; ps.push(realpath); while (!ps.empty()) { string search_path = ps.top(); ps.pop(); handle = opendir(search_path.c_str()); if (handle != 0) { while (fileinfo = readdir(handle)) { struct stat file_stat; if (strcmp(fileinfo->d_name, ".") == 0 || strcmp(fileinfo->d_name, "..") == 0) continue; if (lstat((search_path + fileinfo->d_name).c_str(), &file_stat) < 0) continue; if (!findDirectory && !S_ISDIR(file_stat.st_mode) || findDirectory && S_ISDIR(file_stat.st_mode)) { if (pattern_match(fileinfo->d_name, filter.c_str())) out.push_back(search_path + fileinfo->d_name); } if (includeSubDirectory && S_ISDIR(file_stat.st_mode)) ps.push(search_path + fileinfo->d_name + "/"); } closedir(handle); } } return out; } #endif string align_blank(const string &input, int align_size, char blank) { if (input.size() >= align_size) return input; string output = input; for (int i = 0; i < align_size - input.size(); ++i) output.push_back(blank); return output; } vector<string> split_string(const string &str, const std::string &spstr) { vector<string> res; if (str.empty()) return res; if (spstr.empty()) return {str}; auto p = str.find(spstr); if (p == string::npos) return {str}; res.reserve(5); string::size_type prev = 0; int lent = spstr.length(); const char *ptr = str.c_str(); while (p != string::npos) { int len = p - prev; if (len > 0) { res.emplace_back(str.substr(prev, len)); } prev = p + lent; p = str.find(spstr, prev); } int len = str.length() - prev; if (len > 0) { res.emplace_back(str.substr(prev, len)); } return res; } string replace_string(const string &str, const string &token, const string &value, int nreplace, int *out_num_replace) { if (nreplace == -1) { nreplace = str.size(); } if (nreplace == 0) { return str; } string result; result.resize(str.size()); char *dest = &result[0]; const char *src = str.c_str(); const char *value_ptr = value.c_str(); int old_nreplace = nreplace; bool keep = true; string::size_type pos = 0; string::size_type prev = 0; size_t token_length = token.length(); size_t value_length = value.length(); do { pos = str.find(token, pos); if (pos == string::npos) { keep = false; pos = str.length(); } else { if (nreplace == 0) { pos = str.length(); keep = false; } else { nreplace--; } } size_t copy_length = pos - prev; if (copy_length > 0) { size_t dest_length = dest - &result[0]; // Extended memory space if needed. if (dest_length + copy_length > result.size()) { result.resize((result.size() + copy_length) * 1.2); dest = &result[dest_length]; } memcpy(dest, src + prev, copy_length); dest += copy_length; } if (keep) { pos += token_length; prev = pos; size_t dest_length = dest - &result[0]; // Extended memory space if needed. if (dest_length + value_length > result.size()) { result.resize((result.size() + value_length) * 1.2); dest = &result[dest_length]; } memcpy(dest, value_ptr, value_length); dest += value_length; } } while (keep); if (out_num_replace) { *out_num_replace = old_nreplace - nreplace; } // Crop extra space size_t valid_size = dest - &result[0]; result.resize(valid_size); return result; } bool save_file(const string &file, const void *data, size_t length, bool mk_dirs) { if (mk_dirs) { int p = (int)file.rfind('/'); #ifdef U_OS_WINDOWS int e = (int)file.rfind('\\'); p = std::max(p, e); #endif if (p != -1) { if (!mkdirs(file.substr(0, p))) return false; } } FILE *f = fopen(file.c_str(), "wb"); if (!f) return false; if (data && length > 0) { if (fwrite(data, 1, length, f) != length) { fclose(f); return false; } } fclose(f); return true; } bool save_file(const string &file, const string &data, bool mk_dirs) { return save_file(file, data.data(), data.size(), mk_dirs); } bool save_file(const string &file, const vector<uint8_t> &data, bool mk_dirs) { return save_file(file, data.data(), data.size(), mk_dirs); } static volatile bool g_has_exit_signal = false; static int g_signum = 0; static void signal_callback_handler(int signum) { INFO("Capture interrupt signal."); g_has_exit_signal = true; g_signum = signum; } int while_loop() { signal(SIGINT, signal_callback_handler); // signal(SIGQUIT, signal_callback_handler); while (!g_has_exit_signal) { this_thread::yield(); } INFO("Loop over."); return g_signum; } static unsigned char from_b64(unsigned char ch) { /* Inverse lookup map */ static const unsigned char tab[128] = { 255, 255, 255, 255, 255, 255, 255, 255, /* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 16 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 24 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 32 */ 255, 255, 255, 62, 255, 255, 255, 63, /* 40 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 48 */ 60, 61, 255, 255, 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */ 255, 0, 1, 2, 3, 4, 5, 6, /* 64 */ 7, 8, 9, 10, 11, 12, 13, 14, /* 72 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 80 */ 23, 24, 25, 255, 255, 255, 255, 255, /* 88 */ 255, 26, 27, 28, 29, 30, 31, 32, /* 96 */ 33, 34, 35, 36, 37, 38, 39, 40, /* 104 */ 41, 42, 43, 44, 45, 46, 47, 48, /* 112 */ 49, 50, 51, 255, 255, 255, 255, 255, /* 120 */ }; return tab[ch & 127]; } string base64_decode(const string &base64) { if (base64.empty()) return ""; int len = base64.size(); auto s = (const unsigned char *)base64.data(); unsigned char a, b, c, d; int orig_len = len; int dec_len = 0; string out_data; auto end_s = s + base64.size(); int count_eq = 0; while (*--end_s == '=') { count_eq++; } out_data.resize(len / 4 * 3 - count_eq); char *dst = const_cast<char *>(out_data.data()); char *orig_dst = dst; while (len >= 4 && (a = from_b64(s[0])) != 255 && (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && (d = from_b64(s[3])) != 255) { s += 4; len -= 4; if (a == 200 || b == 200) break; /* '=' can't be there */ *dst++ = a << 2 | b >> 4; if (c == 200) break; *dst++ = b << 4 | c >> 2; if (d == 200) break; *dst++ = c << 6 | d; } dec_len = (dst - orig_dst); return out_data; } string base64_encode(const void *data, size_t size) { string encode_result; encode_result.reserve(size / 3 * 4 + (size % 3 != 0 ? 4 : 0)); const unsigned char *current = static_cast<const unsigned char *>(data); static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; while (size > 2) { encode_result += base64_table[current[0] >> 2]; encode_result += base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; encode_result += base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; encode_result += base64_table[current[2] & 0x3f]; current += 3; size -= 3; } if (size > 0) { encode_result += base64_table[current[0] >> 2]; if (size % 3 == 1) { encode_result += base64_table[(current[0] & 0x03) << 4]; encode_result += "=="; } else if (size % 3 == 2) { encode_result += base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; encode_result += base64_table[(current[1] & 0x0f) << 2]; encode_result += "="; } } return encode_result; } bool delete_file(const string &path) { #ifdef U_OS_WINDOWS return DeleteFileA(path.c_str()); #else return ::remove(path.c_str()) == 0; #endif } bool rmtree(const string &directory, bool ignore_fail) { if (directory.empty()) return false; auto files = find_files(directory, "*", false); auto dirs = find_files(directory, "*", true); bool success = true; for (int i = 0; i < files.size(); ++i) { if (::remove(files[i].c_str()) != 0) { success = false; if (!ignore_fail) { return false; } } } dirs.insert(dirs.begin(), directory); for (int i = (int)dirs.size() - 1; i >= 0; --i) { #ifdef U_OS_WINDOWS if (!::RemoveDirectoryA(dirs[i].c_str())) { #else if (::rmdir(dirs[i].c_str()) != 0) { #endif success = false; if (!ignore_fail) return false; } } return success; } string join_dims(const vector<int64_t> &dims) { stringstream output; char buf[64]; const char *fmts[] = {"%d", " x %d"}; for (int i = 0; i < dims.size(); ++i) { snprintf(buf, sizeof(buf), fmts[i != 0], dims[i]); output << buf; } return output.str(); } }; // namespace iLogger

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PaddlePaddle/PaddleOCR'

If you have feedback or need assistance with the MCP directory API, please join our Discord server