#include "config.h"
#include "StringView.h"
#include <mutex>
#include <wtf/HashMap.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/unicode/UTF8.h>
namespace WTF {
using namespace Unicode;
bool StringView::containsIgnoringASCIICase(const StringView& matchString) const
{
return findIgnoringASCIICase(matchString) != notFound;
}
bool StringView::containsIgnoringASCIICase(const StringView& matchString, unsigned startOffset) const
{
return findIgnoringASCIICase(matchString, startOffset) != notFound;
}
size_t StringView::findIgnoringASCIICase(const StringView& matchString) const
{
return ::WTF::findIgnoringASCIICase(*this, matchString, 0);
}
size_t StringView::findIgnoringASCIICase(const StringView& matchString, unsigned startOffset) const
{
return ::WTF::findIgnoringASCIICase(*this, matchString, startOffset);
}
bool StringView::startsWith(const StringView& prefix) const
{
return ::WTF::startsWith(*this, prefix);
}
bool StringView::startsWithIgnoringASCIICase(const StringView& prefix) const
{
return ::WTF::startsWithIgnoringASCIICase(*this, prefix);
}
bool StringView::endsWith(const StringView& suffix) const
{
return ::WTF::endsWith(*this, suffix);
}
bool StringView::endsWithIgnoringASCIICase(const StringView& suffix) const
{
return ::WTF::endsWithIgnoringASCIICase(*this, suffix);
}
bool equalIgnoringASCIICase(StringView a, const char* b, unsigned bLength)
{
if (bLength != a.length())
return false;
if (a.is8Bit())
return equalIgnoringASCIICase(a.characters8(), b, bLength);
return equalIgnoringASCIICase(a.characters16(), b, bLength);
}
CString StringView::utf8(ConversionMode mode) const
{
if (isNull())
return CString("", 0);
if (is8Bit())
return StringImpl::utf8ForCharacters(characters8(), length());
return StringImpl::utf8ForCharacters(characters16(), length(), mode);
}
size_t StringView::find(StringView matchString, unsigned start) const
{
return findCommon(*this, matchString, start);
}
#if CHECK_STRINGVIEW_LIFETIME
struct StringView::UnderlyingString {
std::atomic_uint refCount { 1u };
bool isValid { true };
const StringImpl& string;
explicit UnderlyingString(const StringImpl&);
};
StringView::UnderlyingString::UnderlyingString(const StringImpl& string)
: string(string)
{
}
static std::mutex& underlyingStringsMutex()
{
static NeverDestroyed<std::mutex> mutex;
return mutex;
}
static HashMap<const StringImpl*, StringView::UnderlyingString*>& underlyingStrings()
{
static NeverDestroyed<HashMap<const StringImpl*, StringView::UnderlyingString*>> map;
return map;
}
void StringView::invalidate(const StringImpl& stringToBeDestroyed)
{
UnderlyingString* underlyingString;
{
std::lock_guard<std::mutex> lock(underlyingStringsMutex());
underlyingString = underlyingStrings().take(&stringToBeDestroyed);
if (!underlyingString)
return;
}
ASSERT(underlyingString->isValid);
underlyingString->isValid = false;
}
bool StringView::underlyingStringIsValid() const
{
return !m_underlyingString || m_underlyingString->isValid;
}
void StringView::adoptUnderlyingString(UnderlyingString* underlyingString)
{
if (m_underlyingString) {
if (!--m_underlyingString->refCount) {
if (m_underlyingString->isValid) {
std::lock_guard<std::mutex> lock(underlyingStringsMutex());
underlyingStrings().remove(&m_underlyingString->string);
}
delete m_underlyingString;
}
}
m_underlyingString = underlyingString;
}
void StringView::setUnderlyingString(const StringImpl* string)
{
UnderlyingString* underlyingString;
if (!string)
underlyingString = nullptr;
else {
std::lock_guard<std::mutex> lock(underlyingStringsMutex());
auto result = underlyingStrings().add(string, nullptr);
if (result.isNewEntry)
result.iterator->value = new UnderlyingString(*string);
else
++result.iterator->value->refCount;
underlyingString = result.iterator->value;
}
adoptUnderlyingString(underlyingString);
}
void StringView::setUnderlyingString(const StringView& string)
{
UnderlyingString* underlyingString = string.m_underlyingString;
if (underlyingString)
++underlyingString->refCount;
adoptUnderlyingString(underlyingString);
}
#endif // CHECK_STRINGVIEW_LIFETIME
}