148 lines
4.9 KiBLFS
C++
148 lines
4.9 KiBLFS
C++
/**
|
|
* @file
|
|
*
|
|
* @author Mamadou Babaei <mamadou@senseglove.com>
|
|
*
|
|
* @section LICENSE
|
|
*
|
|
* Copyright (c) 2020 - 2026 SenseGlove
|
|
*
|
|
* @section DESCRIPTION
|
|
*
|
|
* String conversion, parsing and other utility stuff. Much more prominent in
|
|
* C++.
|
|
*/
|
|
|
|
|
|
#pragma once
|
|
|
|
#include <SenseGlove/Common/Platform.hpp>
|
|
|
|
#include <charconv>
|
|
#include <concepts>
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
|
|
#if SG_HAS_STD_FORMAT
|
|
#include <format>
|
|
#endif /* SG_HAS_STD_FORMAT */
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <system_error>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
namespace SGCommon
|
|
{
|
|
/// <summary> Utility class to convert strings into usable values. </summary>
|
|
class SGCOMMON_API StringUtils;
|
|
}// namespace SGCommon
|
|
|
|
/// <summary> Utility class to convert strings into usable values. </summary>
|
|
class SGCOMMON_API SGCommon::StringUtils
|
|
{
|
|
public:
|
|
static std::string QuickSplit(const std::string& input, char delimiter, int32_t getIndex);
|
|
|
|
/// <summary> Split a std::string into a vector of std::strings by a delimiter </summary>
|
|
static std::vector<std::string> Split(const std::string& str, char delimiter);
|
|
|
|
static bool Contains(const std::string& haystack, const std::string& needle);
|
|
|
|
/// <summary> Replace all occurrences of a character with another one. </summary>
|
|
static std::string ReplaceChars(const std::string& str, char from, char to);
|
|
|
|
/// <summary> Convert a string into an integer value. </summary>
|
|
static int32_t ToInt(const std::string& str, int32_t fallback = 0);
|
|
|
|
static uint64_t ToUint64(const std::string& str, uint64_t fallback = 0);
|
|
|
|
/// <summary> Convert a string into a decimal value. </summary>
|
|
static float ToFloat(const std::string& str, float fallback = 0.0f);
|
|
|
|
#if SG_TOOLCHAIN_ANDROID_NDK_R25B
|
|
template<typename T>
|
|
requires (
|
|
std::is_floating_point_v<T>
|
|
|| std::is_integral_v<T>
|
|
)
|
|
#else /* SG_TOOLCHAIN_ANDROID_NDK_R25B */
|
|
template<typename T>
|
|
requires (
|
|
std::floating_point<T>
|
|
|| std::integral<T>
|
|
)
|
|
#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 <format> 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<typename... Args>
|
|
SG_FORCEINLINE static std::string FormatString(std::format_string<Args...> fmt, Args&&... args)
|
|
{
|
|
return std::format(fmt, std::forward<Args>(args)...);
|
|
}
|
|
#else /* SG_HAS_STD_FORMAT */
|
|
template<typename... Args>
|
|
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<char[]> buffer{std::make_unique<char[]>(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 */
|
|
|
|
/// <summary> Print the different sizes within a 2D array </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="vect"></param>
|
|
/// <returns></returns>
|
|
template<typename T>
|
|
static std::string PrintSize(const std::vector<std::vector<T>>& 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<char>& 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;
|
|
};
|