omni/kit/Wildcard.h

File members: omni/kit/Wildcard.h

// Copyright (c) 2020-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 <regex>
#include <string>
#include <unordered_set>

namespace omni
{
namespace kit
{

class Wildcard
{
public:
    void setPatternString(const char* pattern)
    {
        // Special regex character
        static const std::unordered_set<char> kSpecialCharacters = { '.', '^', '$', '|', '(', ')', '[',
                                                                     ']', '{', '}', '*', '+', '?', '\\' };

        std::string expression = "^.*";

        size_t len = strlen(pattern);
        char prev_char = ' ';
        for (size_t i = 0; i < len; i++)
        {
            const char character = pattern[i];
            switch (character)
            {
                case '?':
                    expression += '.';
                    break;
                case ' ':
                    expression += ' ';
                    break;
                case '*':
                    if (i == 0 || prev_char != '*')
                    {
                        // make sure we don't have continuous * which will make std::regex_search super heavy, leading
                        // to crash
                        expression += ".*";
                    }
                    break;
                default:
                    if (kSpecialCharacters.find(character) != kSpecialCharacters.end())
                    {
                        // Escape special regex characters
                        expression += '\\';
                    }
                    expression += character;
            }
            prev_char = character;
        }

        expression += ".*$";
        m_expression = expression;
        buildRegex();
    }

    bool isMatching(const char* str) const
    {
        return std::regex_search(str, m_wildcardRegex);
    }

    void setCaseSensitive(bool sensitive)
    {
        if (m_caseSensitive != sensitive)
        {
            m_caseSensitive = sensitive;
            buildRegex();
        }
    }

private:
    void buildRegex()
    {
        if (m_expression.length())
        {
            auto flags = std::regex_constants::optimize;
            if (!m_caseSensitive)
            {
                flags |= std::regex_constants::icase;
            }
            m_wildcardRegex = std::regex(m_expression, flags);
        }
    }

    std::string m_expression;
    std::regex m_wildcardRegex;
    bool m_caseSensitive = false;
};

} // namespace kit
} // namespace omni