summaryrefslogtreecommitdiff
path: root/Source/WTF/wtf/text/StringView.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WTF/wtf/text/StringView.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WTF/wtf/text/StringView.cpp')
-rw-r--r--Source/WTF/wtf/text/StringView.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/Source/WTF/wtf/text/StringView.cpp b/Source/WTF/wtf/text/StringView.cpp
new file mode 100644
index 000000000..580799765
--- /dev/null
+++ b/Source/WTF/wtf/text/StringView.cpp
@@ -0,0 +1,285 @@
+/*
+
+Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "config.h"
+#include "StringView.h"
+
+#include <mutex>
+#include <unicode/ubrk.h>
+#include <wtf/HashMap.h>
+#include <wtf/Lock.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Optional.h>
+#include <wtf/text/TextBreakIterator.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);
+}
+
+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);
+}
+
+void StringView::SplitResult::Iterator::findNextSubstring()
+{
+ for (size_t separatorPosition; (separatorPosition = m_result.m_string.find(m_result.m_separator, m_position)) != notFound; ++m_position) {
+ if (separatorPosition > m_position) {
+ m_length = separatorPosition - m_position;
+ return;
+ }
+ }
+ m_length = m_result.m_string.length() - m_position;
+}
+
+auto StringView::SplitResult::Iterator::operator++() -> Iterator&
+{
+ ASSERT(m_position < m_result.m_string.length());
+ m_position += m_length;
+ if (m_position < m_result.m_string.length()) {
+ ++m_position;
+ findNextSubstring();
+ }
+ return *this;
+}
+
+class StringView::GraphemeClusters::Iterator::Impl {
+public:
+ Impl(const StringView& stringView, std::optional<NonSharedCharacterBreakIterator>&& iterator, unsigned index)
+ : m_stringView(stringView)
+ , m_iterator(WTFMove(iterator))
+ , m_index(index)
+ , m_indexEnd(computeIndexEnd())
+ {
+ }
+
+ void operator++()
+ {
+ ASSERT(m_indexEnd > m_index);
+ m_index = m_indexEnd;
+ m_indexEnd = computeIndexEnd();
+ }
+
+ StringView operator*() const
+ {
+ if (m_stringView.is8Bit())
+ return StringView(m_stringView.characters8() + m_index, m_indexEnd - m_index);
+ return StringView(m_stringView.characters16() + m_index, m_indexEnd - m_index);
+ }
+
+ bool operator==(const Impl& other) const
+ {
+ ASSERT(&m_stringView == &other.m_stringView);
+ auto result = m_index == other.m_index;
+ ASSERT(!result || m_indexEnd == other.m_indexEnd);
+ return result;
+ }
+
+ unsigned computeIndexEnd()
+ {
+ if (!m_iterator)
+ return 0;
+ if (m_index == m_stringView.length())
+ return m_index;
+ return ubrk_following(m_iterator.value(), m_index);
+ }
+
+private:
+ const StringView& m_stringView;
+ std::optional<NonSharedCharacterBreakIterator> m_iterator;
+ unsigned m_index;
+ unsigned m_indexEnd;
+};
+
+StringView::GraphemeClusters::Iterator::Iterator(const StringView& stringView, unsigned index)
+ : m_impl(std::make_unique<Impl>(stringView, stringView.isNull() ? std::nullopt : std::optional<NonSharedCharacterBreakIterator>(NonSharedCharacterBreakIterator(stringView)), index))
+{
+}
+
+StringView::GraphemeClusters::Iterator::~Iterator()
+{
+}
+
+StringView::GraphemeClusters::Iterator::Iterator(Iterator&& other)
+ : m_impl(WTFMove(other.m_impl))
+{
+}
+
+auto StringView::GraphemeClusters::Iterator::operator++() -> Iterator&
+{
+ ++(*m_impl);
+ return *this;
+}
+
+StringView StringView::GraphemeClusters::Iterator::operator*() const
+{
+ return **m_impl;
+}
+
+bool StringView::GraphemeClusters::Iterator::operator==(const Iterator& other) const
+{
+ return *m_impl == *(other.m_impl);
+}
+
+bool StringView::GraphemeClusters::Iterator::operator!=(const Iterator& other) const
+{
+ return !(*this == other);
+}
+
+#if CHECK_STRINGVIEW_LIFETIME
+
+// Manage reference count manually so UnderlyingString does not need to be defined in the header.
+
+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 StaticLock underlyingStringsMutex;
+
+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<StaticLock> 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) {
+ std::lock_guard<StaticLock> lock(underlyingStringsMutex);
+ if (!--m_underlyingString->refCount) {
+ if (m_underlyingString->isValid) {
+ 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<StaticLock> 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& otherString)
+{
+ UnderlyingString* underlyingString = otherString.m_underlyingString;
+ if (underlyingString)
+ ++underlyingString->refCount;
+ adoptUnderlyingString(underlyingString);
+}
+
+#endif // CHECK_STRINGVIEW_LIFETIME
+
+} // namespace WTF