omni/extras/StringHelpers.h

File members: omni/extras/StringHelpers.h

// Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include "../../carb/Types.h"

#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <cctype>

namespace omni
{
namespace extras
{

#pragma push_macro("max")
#undef max

inline std::vector<std::string> split(const std::string& s, char d, size_t count = std::numeric_limits<size_t>::max())
{
    std::vector<std::string> res;
    std::stringstream ss(s);
    size_t i = 0;
    while (ss.good() && i < count)
    {
        std::string tmp;
        if (i == count - 1)
        {
            std::getline(ss, tmp, (char)0);
        }
        else
        {
            std::getline(ss, tmp, d);
        }

        if (!tmp.empty())
        {
            res.push_back(tmp);
        }
        i++;
    }
    return res;
}

#pragma pop_macro("max")

inline bool endsWith(const std::string& str, const std::string& ending)
{
    if (ending.size() > str.size())
    {
        return false;
    }
    return std::equal(ending.rbegin(), ending.rend(), str.rbegin());
}

inline bool startsWith(const std::string& str, const std::string& prefix)
{
    return (str.length() >= prefix.length() && str.compare(0, prefix.size(), prefix) == 0);
}

inline void toLower(std::string& str)
{
    std::transform(str.begin(), str.end(), str.begin(), [](char c) { return (char)std::tolower(c); });
}

inline bool stringToInteger(const std::string& str, int32_t& outResult)
{
    char* numericEnd;

    uint32_t val = (int32_t)strtoll(str.c_str(), &numericEnd, 0);
    if (*numericEnd == '\0')
    {
        outResult = val;
        return true;
    }

    double fVal = strtod(str.c_str(), &numericEnd);
    if (*numericEnd == '\0')
    {
        outResult = static_cast<int32_t>(fVal);
        return true;
    }

    return false;
}

constexpr char kInt2Delimiters[] = ",x";

inline bool stringToInt2(const std::string& str, carb::Int2& outResult, const char* delims = kInt2Delimiters)
{
    // try splitting by different delimiters

    for (int delimIndex = 0; delims[delimIndex] != 0; delimIndex++)
    {
        auto delim = delims[delimIndex];
        auto pathAndOther = split(str, delim);

        if (pathAndOther.size() == 2)
        {
            int32_t x, y;

            if (extras::stringToInteger(pathAndOther[0], x) && extras::stringToInteger(pathAndOther[1], y))
            {
                outResult = { x, y };
                return true;
            }
        }
    }

    return false;
}

constexpr char kTrimCharsDefault[] = " \t\n\r\f\v";

inline std::string& rtrim(std::string& s, const char* t = kTrimCharsDefault)
{
    s.erase(s.find_last_not_of(t) + 1);
    return s;
}

inline std::string& ltrim(std::string& s, const char* t = kTrimCharsDefault)
{
    s.erase(0, s.find_first_not_of(t));
    return s;
}

inline std::string& trim(std::string& s, const char* t = kTrimCharsDefault)
{
    return ltrim(rtrim(s, t), t);
}

inline std::string trimCopy(std::string s, const char* t = kTrimCharsDefault)
{
    trim(s, t);
    return s;
}

inline void replaceAll(std::string& str, const std::string& subStr, const std::string& replaceWith)
{
    size_t pos = str.find(subStr);
    while (pos != std::string::npos)
    {
        str.replace(pos, subStr.size(), replaceWith);
        pos = str.find(subStr, pos + replaceWith.size());
    }
}

inline bool stringCompareCaseInsensitive(const std::string& str1, const std::string& str2)
{
    return ((str1.size() == str2.size()) && std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
                return std::tolower(a) == std::tolower(b);
            }));
}

inline bool isPathEqual(const std::string& strLeft, const std::string& strRight)
{
#if CARB_PLATFORM_WINDOWS
    if (strLeft.size() != strRight.size())
    {
        return false;
    }

    return stringCompareCaseInsensitive(strLeft, strRight);
#else
    return (strLeft == strRight);
#endif
}

} // namespace extras
} // namespace omni