/** * @file * * @author Mamadou Babaei * * @section LICENSE * * Copyright (c) 2020 - 2026 SenseGlove * * @section DESCRIPTION * * String conversion, parsing and other utility stuff. Much more prominent in * C++. */ #pragma once #include #include #include #include #include #include #if SG_HAS_STD_FORMAT #include #endif /* SG_HAS_STD_FORMAT */ #include #include #include #include #include namespace SGCommon { /// Utility class to convert strings into usable values. class SGCOMMON_API StringUtils; }// namespace SGCommon /// Utility class to convert strings into usable values. class SGCOMMON_API SGCommon::StringUtils { public: static std::string QuickSplit(const std::string& input, char delimiter, int32_t getIndex); /// Split a std::string into a vector of std::strings by a delimiter static std::vector Split(const std::string& str, char delimiter); static bool Contains(const std::string& haystack, const std::string& needle); /// Replace all occurrences of a character with another one. static std::string ReplaceChars(const std::string& str, char from, char to); /// Convert a string into an integer value. static int32_t ToInt(const std::string& str, int32_t fallback = 0); static uint64_t ToUint64(const std::string& str, uint64_t fallback = 0); /// Convert a string into a decimal value. static float ToFloat(const std::string& str, float fallback = 0.0f); #if SG_TOOLCHAIN_ANDROID_NDK_R25B template requires ( std::is_floating_point_v || std::is_integral_v ) #else /* SG_TOOLCHAIN_ANDROID_NDK_R25B */ template requires ( std::floating_point || std::integral ) #endif /* SG_TOOLCHAIN_ANDROID_NDK_R25B */ static bool TryParse(const std::string& str, T& out_value) { const char* begin = str.data(); const char* end = begin + str.size(); const std::from_chars_result result{ std::from_chars(begin, end, out_value) }; return result.ec == std::errc{} && result.ptr == end; } // NOTE: // SG_HAS_STD_FORMAT is a mandatory workaround for Android NDK r25b and Epic // Native or Cross Toolchains v22, which lack full support. // Once support for these toolchains is dropped, SG_HAS_STD_FORMAT and // StringUtils::FormatString() can be removed in favor of direct usage of // std::format(). #if SG_HAS_STD_FORMAT template SG_FORCEINLINE static std::string FormatString(std::format_string fmt, Args&&... args) { return std::format(fmt, std::forward(args)...); } #else /* SG_HAS_STD_FORMAT */ template static std::string FormatString(const std::string& fmt, const Args&... args) { int32_t size = std::snprintf(nullptr, 0, fmt.c_str(), args...) + 1;// extra space for '\0' SG_ASSERT(size > 0, "Error during formatting: size must be positive."); std::unique_ptr buffer{std::make_unique(size)}; std::snprintf(buffer.get(), size, fmt.c_str(), args...); return std::string{buffer.get(), buffer.get() + size - 1};// we don't want the '\0' inside } #endif /* SG_HAS_STD_FORMAT */ /// Print the different sizes within a 2D array /// /// /// template static std::string PrintSize(const std::vector>& vect) { const std::size_t size = vect.size(); std::string res("(" + std::to_string(size) + ")["); for (std::size_t i = 0; i < size; ++i) { res += std::to_string(vect[i].size()); if (i < size - 1) { res += ", "; } } return res + std::string("]"); } static bool CopyString(const std::string& data, char* out_buffer, std::string& out_error); //Base64 Encoding - for firmware. Taken from https://github.com/tobiaslocker/base64 static const std::string& GetBase64Chars(); static std::string CharVectorToBase64(const std::vector& data); #if SG_PLATFORM_WINDOWS static std::wstring Utf8StringToWideString(const std::string& utf8String); static std::string WideStringToUtf8String(const std::wstring& wideString); #endif /* SG_PLATFORM_WINDOWS */ public: StringUtils() = delete; virtual ~StringUtils() = delete; };