mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 05:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			132 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "stringrefid.hpp"
 | 
						|
#include "serializerefid.hpp"
 | 
						|
 | 
						|
#include <charconv>
 | 
						|
#include <iomanip>
 | 
						|
#include <mutex>
 | 
						|
#include <ostream>
 | 
						|
#include <sstream>
 | 
						|
#include <system_error>
 | 
						|
#include <unordered_set>
 | 
						|
 | 
						|
#include "components/misc/guarded.hpp"
 | 
						|
#include "components/misc/strings/algorithm.hpp"
 | 
						|
#include "components/misc/utf8stream.hpp"
 | 
						|
 | 
						|
namespace ESM
 | 
						|
{
 | 
						|
    namespace
 | 
						|
    {
 | 
						|
        using StringsSet = std::unordered_set<std::string, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>;
 | 
						|
 | 
						|
        const std::string emptyString;
 | 
						|
 | 
						|
        Misc::NotNullPtr<const std::string> getOrInsertString(std::string_view id)
 | 
						|
        {
 | 
						|
            static Misc::ScopeGuarded<StringsSet> refIds;
 | 
						|
            const auto locked = refIds.lock();
 | 
						|
            auto it = locked->find(id);
 | 
						|
            if (it == locked->end())
 | 
						|
                it = locked->emplace(id).first;
 | 
						|
            return &*it;
 | 
						|
        }
 | 
						|
 | 
						|
        void addHex(unsigned char value, std::string& result)
 | 
						|
        {
 | 
						|
            const std::size_t size = 2 + getHexIntegralSize(value);
 | 
						|
            const std::size_t shift = result.size();
 | 
						|
            result.resize(shift + size);
 | 
						|
            result[shift] = '\\';
 | 
						|
            result[shift + 1] = 'x';
 | 
						|
            const auto [end, ec] = std::to_chars(result.data() + shift + 2, result.data() + result.size(), value, 16);
 | 
						|
            if (ec != std::errc())
 | 
						|
                throw std::system_error(std::make_error_code(ec));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    StringRefId::StringRefId()
 | 
						|
        : mValue(&emptyString)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    StringRefId::StringRefId(std::string_view value)
 | 
						|
        : mValue(getOrInsertString(value))
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    bool StringRefId::operator==(std::string_view rhs) const noexcept
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciEqual(*mValue, rhs);
 | 
						|
    }
 | 
						|
 | 
						|
    bool StringRefId::operator<(StringRefId rhs) const noexcept
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciLess(*mValue, *rhs.mValue);
 | 
						|
    }
 | 
						|
 | 
						|
    bool operator<(StringRefId lhs, std::string_view rhs) noexcept
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciLess(*lhs.mValue, rhs);
 | 
						|
    }
 | 
						|
 | 
						|
    bool operator<(std::string_view lhs, StringRefId rhs) noexcept
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciLess(lhs, *rhs.mValue);
 | 
						|
    }
 | 
						|
 | 
						|
    std::ostream& operator<<(std::ostream& stream, StringRefId value)
 | 
						|
    {
 | 
						|
        return stream << value.toDebugString();
 | 
						|
    }
 | 
						|
 | 
						|
    std::string StringRefId::toDebugString() const
 | 
						|
    {
 | 
						|
        std::string result;
 | 
						|
        result.reserve(2 + mValue->size());
 | 
						|
        result.push_back('"');
 | 
						|
        const unsigned char* ptr = reinterpret_cast<const unsigned char*>(mValue->data());
 | 
						|
        const unsigned char* const end = reinterpret_cast<const unsigned char*>(mValue->data() + mValue->size());
 | 
						|
        while (ptr != end)
 | 
						|
        {
 | 
						|
            if (Utf8Stream::isAscii(*ptr))
 | 
						|
            {
 | 
						|
                if (std::isprint(*ptr) && *ptr != '\t' && *ptr != '\n' && *ptr != '\r')
 | 
						|
                    result.push_back(*ptr);
 | 
						|
                else
 | 
						|
                    addHex(*ptr, result);
 | 
						|
                ++ptr;
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            const auto [octets, first] = Utf8Stream::getOctetCount(*ptr);
 | 
						|
            const auto [chr, next] = Utf8Stream::decode(ptr + 1, end, first, octets);
 | 
						|
            if (chr == Utf8Stream::sBadChar())
 | 
						|
            {
 | 
						|
                while (ptr != std::min(end, ptr + octets))
 | 
						|
                {
 | 
						|
                    addHex(*ptr, result);
 | 
						|
                    ++ptr;
 | 
						|
                }
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            result.append(ptr, next);
 | 
						|
            ptr = next;
 | 
						|
        }
 | 
						|
        result.push_back('"');
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    bool StringRefId::startsWith(std::string_view prefix) const
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciStartsWith(*mValue, prefix);
 | 
						|
    }
 | 
						|
 | 
						|
    bool StringRefId::endsWith(std::string_view suffix) const
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciEndsWith(*mValue, suffix);
 | 
						|
    }
 | 
						|
 | 
						|
    bool StringRefId::contains(std::string_view subString) const
 | 
						|
    {
 | 
						|
        return Misc::StringUtils::ciFind(*mValue, subString) != std::string_view::npos;
 | 
						|
    }
 | 
						|
}
 |