<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[205986] trunk/Source/WebCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/205986">205986</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2016-09-15 11:12:09 -0700 (Thu, 15 Sep 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Use efficient iterators in URLParser
https://bugs.webkit.org/show_bug.cgi?id=162007
Reviewed by Tim Horton.
URLParser used to use StringView::CodePoints::Iterator, which needs to check if
the StringView is 8-bit or 16-bit every time it does anything.
I wrote a new CodePointIterator template which already knows whether it is iterating
8-bit or 16-bit characters, so it does not need to do the checks each time it gets a
code point or advances to the next code point.
No change in behavior except a performance increase.
Covered by existing tests.
* platform/URLParser.cpp:
(WebCore::CodePointIterator::CodePointIterator):
(WebCore::CodePointIterator::operator==):
(WebCore::CodePointIterator::operator!=):
(WebCore::CodePointIterator::operator=):
(WebCore::CodePointIterator::atEnd):
(WebCore::CodePointIterator<LChar>::operator):
(WebCore::CodePointIterator<UChar>::operator):
(WebCore::isWindowsDriveLetter):
(WebCore::shouldCopyFileURL):
(WebCore::isPercentEncodedDot):
(WebCore::isSingleDotPathSegment):
(WebCore::isDoubleDotPathSegment):
(WebCore::consumeSingleDotPathSegment):
(WebCore::consumeDoubleDotPathSegment):
(WebCore::URLParser::failure):
(WebCore::URLParser::parse):
(WebCore::URLParser::parseAuthority):
(WebCore::parseIPv4Number):
(WebCore::parseIPv4Host):
(WebCore::parseIPv6Host):
(WebCore::URLParser::parsePort):
(WebCore::URLParser::parseHost):
* platform/URLParser.h:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParsercpp">trunk/Source/WebCore/platform/URLParser.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformURLParserh">trunk/Source/WebCore/platform/URLParser.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (205985 => 205986)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-15 18:11:48 UTC (rev 205985)
+++ trunk/Source/WebCore/ChangeLog        2016-09-15 18:12:09 UTC (rev 205986)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2016-09-15 Alex Christensen <achristensen@webkit.org>
+
+ Use efficient iterators in URLParser
+ https://bugs.webkit.org/show_bug.cgi?id=162007
+
+ Reviewed by Tim Horton.
+
+ URLParser used to use StringView::CodePoints::Iterator, which needs to check if
+ the StringView is 8-bit or 16-bit every time it does anything.
+ I wrote a new CodePointIterator template which already knows whether it is iterating
+ 8-bit or 16-bit characters, so it does not need to do the checks each time it gets a
+ code point or advances to the next code point.
+
+ No change in behavior except a performance increase.
+ Covered by existing tests.
+
+ * platform/URLParser.cpp:
+ (WebCore::CodePointIterator::CodePointIterator):
+ (WebCore::CodePointIterator::operator==):
+ (WebCore::CodePointIterator::operator!=):
+ (WebCore::CodePointIterator::operator=):
+ (WebCore::CodePointIterator::atEnd):
+ (WebCore::CodePointIterator<LChar>::operator):
+ (WebCore::CodePointIterator<UChar>::operator):
+ (WebCore::isWindowsDriveLetter):
+ (WebCore::shouldCopyFileURL):
+ (WebCore::isPercentEncodedDot):
+ (WebCore::isSingleDotPathSegment):
+ (WebCore::isDoubleDotPathSegment):
+ (WebCore::consumeSingleDotPathSegment):
+ (WebCore::consumeDoubleDotPathSegment):
+ (WebCore::URLParser::failure):
+ (WebCore::URLParser::parse):
+ (WebCore::URLParser::parseAuthority):
+ (WebCore::parseIPv4Number):
+ (WebCore::parseIPv4Host):
+ (WebCore::parseIPv6Host):
+ (WebCore::URLParser::parsePort):
+ (WebCore::URLParser::parseHost):
+ * platform/URLParser.h:
+
</ins><span class="cx"> 2016-09-14 Antti Koivisto <antti@apple.com>
</span><span class="cx">
</span><span class="cx"> Move text decoration style computation from RenderObject to TextDecorationPainter
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.cpp (205985 => 205986)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.cpp        2016-09-15 18:11:48 UTC (rev 205985)
+++ trunk/Source/WebCore/platform/URLParser.cpp        2016-09-15 18:12:09 UTC (rev 205986)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include "Logging.h"
</span><span class="cx"> #include <array>
</span><span class="cx"> #include <unicode/uidna.h>
</span><ins>+#include <unicode/utypes.h>
</ins><span class="cx"> #include <wtf/HashMap.h>
</span><span class="cx"> #include <wtf/NeverDestroyed.h>
</span><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="lines">@@ -36,6 +37,85 @@
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><ins>+template<typename CharacterType>
+class CodePointIterator {
+public:
+ CodePointIterator() { }
+ CodePointIterator(const CharacterType* begin, const CharacterType* end)
+ : m_begin(begin)
+ , m_end(end)
+ {
+ }
+
+ CodePointIterator(const CodePointIterator& begin, const CodePointIterator& end)
+ : CodePointIterator(begin.m_begin, end.m_begin)
+ {
+ ASSERT(end.m_begin >= begin.m_begin);
+ }
+
+ UChar32 operator*() const;
+ CodePointIterator& operator++();
+
+ bool operator==(const CodePointIterator& other) const
+ {
+ return m_begin == other.m_begin
+ && m_end == other.m_end;
+ }
+ bool operator!=(const CodePointIterator& other) const { return !(*this == other); }
+
+ CodePointIterator& operator=(const CodePointIterator& other)
+ {
+ m_begin = other.m_begin;
+ m_end = other.m_end;
+ return *this;
+ }
+
+ bool atEnd() const
+ {
+ ASSERT(m_begin <= m_end);
+ return m_begin >= m_end;
+ }
+
+private:
+ const CharacterType* m_begin { nullptr };
+ const CharacterType* m_end { nullptr };
+};
+
+template<>
+UChar32 CodePointIterator<LChar>::operator*() const
+{
+ ASSERT(!atEnd());
+ return *m_begin;
+}
+
+template<>
+auto CodePointIterator<LChar>::operator++() -> CodePointIterator&
+{
+ ASSERT(!atEnd());
+ m_begin++;
+ return *this;
+}
+
+template<>
+UChar32 CodePointIterator<UChar>::operator*() const
+{
+ ASSERT(!atEnd());
+ UChar32 c;
+ U16_GET(m_begin, 0, 0, m_end - m_begin, c);
+ return c;
+}
+
+template<>
+auto CodePointIterator<UChar>::operator++() -> CodePointIterator&
+{
+ ASSERT(!atEnd());
+ if (U16_IS_LEAD(m_begin[0]) && m_begin < m_end && U16_IS_TRAIL(m_begin[1]))
+ m_begin += 2;
+ else
+ m_begin++;
+ return *this;
+}
+
</ins><span class="cx"> template<typename CharacterType> static bool isC0Control(CharacterType character) { return character <= 0x0001F; }
</span><span class="cx"> template<typename CharacterType> static bool isC0ControlOrSpace(CharacterType character) { return isC0Control(character) || character == 0x0020; }
</span><span class="cx"> template<typename CharacterType> static bool isTabOrNewline(CharacterType character) { return character == 0x0009 || character == 0x000A || character == 0x000D; }
</span><span class="lines">@@ -45,12 +125,13 @@
</span><span class="cx"> template<typename CharacterType> static bool isInvalidDomainCharacter(CharacterType character) { return character == 0x0000 || character == 0x0009 || character == 0x000A || character == 0x000D || character == 0x0020 || character == '#' || character == '%' || character == '/' || character == ':' || character == '?' || character == '@' || character == '[' || character == '\\' || character == ']'; }
</span><span class="cx"> template<typename CharacterType> static bool isPercentOrNonASCII(CharacterType character) { return !isASCII(character) || character == '%'; }
</span><span class="cx">
</span><del>-static bool isWindowsDriveLetter(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+static bool isWindowsDriveLetter(CodePointIterator<CharacterType> iterator)
</ins><span class="cx"> {
</span><del>- if (iterator == end || !isASCIIAlpha(*iterator))
</del><ins>+ if (iterator.atEnd() || !isASCIIAlpha(*iterator))
</ins><span class="cx"> return false;
</span><span class="cx"> ++iterator;
</span><del>- if (iterator == end)
</del><ins>+ if (iterator.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> return *iterator == ':' || *iterator == '|';
</span><span class="cx"> }
</span><span class="lines">@@ -62,17 +143,18 @@
</span><span class="cx"> return isASCIIAlpha(builder[index]) && (builder[index + 1] == ':' || builder[index + 1] == '|');
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool shouldCopyFileURL(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator end)
</del><ins>+template<typename CharacterType>
+static bool shouldCopyFileURL(CodePointIterator<CharacterType> iterator)
</ins><span class="cx"> {
</span><del>- if (isWindowsDriveLetter(iterator, end))
</del><ins>+ if (isWindowsDriveLetter(iterator))
</ins><span class="cx"> return true;
</span><del>- if (iterator == end)
</del><ins>+ if (iterator.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> ++iterator;
</span><del>- if (iterator == end)
</del><ins>+ if (iterator.atEnd())
</ins><span class="cx"> return true;
</span><span class="cx"> ++iterator;
</span><del>- if (iterator == end)
</del><ins>+ if (iterator.atEnd())
</ins><span class="cx"> return true;
</span><span class="cx"> return *iterator != '/' && *iterator != '\\' && *iterator != '?' && *iterator != '#';
</span><span class="cx"> }
</span><span class="lines">@@ -351,75 +433,79 @@
</span><span class="cx">
</span><span class="cx"> static const char* dotASCIICode = "2e";
</span><span class="cx">
</span><del>-static bool isPercentEncodedDot(StringView::CodePoints::Iterator c, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+static bool isPercentEncodedDot(CodePointIterator<CharacterType> c)
</ins><span class="cx"> {
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (*c != '%')
</span><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (*c != dotASCIICode[0])
</span><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> return toASCIILower(*c) == dotASCIICode[1];
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static bool isSingleDotPathSegment(StringView::CodePoints::Iterator c, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+static bool isSingleDotPathSegment(CodePointIterator<CharacterType> c)
</ins><span class="cx"> {
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (*c == '.') {
</span><span class="cx"> ++c;
</span><del>- return c == end || *c == '/' || *c == '\\' || *c == '?' || *c == '#';
</del><ins>+ return c.atEnd() || *c == '/' || *c == '\\' || *c == '?' || *c == '#';
</ins><span class="cx"> }
</span><span class="cx"> if (*c != '%')
</span><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end || *c != dotASCIICode[0])
</del><ins>+ if (c.atEnd() || *c != dotASCIICode[0])
</ins><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (toASCIILower(*c) == dotASCIICode[1]) {
</span><span class="cx"> ++c;
</span><del>- return c == end || *c == '/' || *c == '\\' || *c == '?' || *c == '#';
</del><ins>+ return c.atEnd() || *c == '/' || *c == '\\' || *c == '?' || *c == '#';
</ins><span class="cx"> }
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><del>-
-static bool isDoubleDotPathSegment(StringView::CodePoints::Iterator c, const StringView::CodePoints::Iterator& end)
</del><ins>+
+template<typename CharacterType>
+static bool isDoubleDotPathSegment(CodePointIterator<CharacterType> c)
</ins><span class="cx"> {
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (*c == '.') {
</span><span class="cx"> ++c;
</span><del>- return isSingleDotPathSegment(c, end);
</del><ins>+ return isSingleDotPathSegment(c);
</ins><span class="cx"> }
</span><span class="cx"> if (*c != '%')
</span><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end || *c != dotASCIICode[0])
</del><ins>+ if (c.atEnd() || *c != dotASCIICode[0])
</ins><span class="cx"> return false;
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (toASCIILower(*c) == dotASCIICode[1]) {
</span><span class="cx"> ++c;
</span><del>- return isSingleDotPathSegment(c, end);
</del><ins>+ return isSingleDotPathSegment(c);
</ins><span class="cx"> }
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void consumeSingleDotPathSegment(StringView::CodePoints::Iterator& c, const StringView::CodePoints::Iterator end)
</del><ins>+template<typename CharacterType>
+static void consumeSingleDotPathSegment(CodePointIterator<CharacterType>& c)
</ins><span class="cx"> {
</span><del>- ASSERT(isSingleDotPathSegment(c, end));
</del><ins>+ ASSERT(isSingleDotPathSegment(c));
</ins><span class="cx"> if (*c == '.') {
</span><span class="cx"> ++c;
</span><del>- if (c != end) {
</del><ins>+ if (!c.atEnd()) {
</ins><span class="cx"> if (*c == '/' || *c == '\\')
</span><span class="cx"> ++c;
</span><span class="cx"> else
</span><span class="lines">@@ -432,7 +518,7 @@
</span><span class="cx"> ++c;
</span><span class="cx"> ASSERT(toASCIILower(*c) == dotASCIICode[1]);
</span><span class="cx"> ++c;
</span><del>- if (c != end) {
</del><ins>+ if (!c.atEnd()) {
</ins><span class="cx"> if (*c == '/' || *c == '\\')
</span><span class="cx"> ++c;
</span><span class="cx"> else
</span><span class="lines">@@ -441,9 +527,10 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void consumeDoubleDotPathSegment(StringView::CodePoints::Iterator& c, const StringView::CodePoints::Iterator end)
</del><ins>+template<typename CharacterType>
+static void consumeDoubleDotPathSegment(CodePointIterator<CharacterType>& c)
</ins><span class="cx"> {
</span><del>- ASSERT(isDoubleDotPathSegment(c, end));
</del><ins>+ ASSERT(isDoubleDotPathSegment(c));
</ins><span class="cx"> if (*c == '.')
</span><span class="cx"> ++c;
</span><span class="cx"> else {
</span><span class="lines">@@ -454,7 +541,7 @@
</span><span class="cx"> ASSERT(toASCIILower(*c) == dotASCIICode[1]);
</span><span class="cx"> ++c;
</span><span class="cx"> }
</span><del>- consumeSingleDotPathSegment(c, end);
</del><ins>+ consumeSingleDotPathSegment(c);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void URLParser::popPath()
</span><span class="lines">@@ -470,11 +557,13 @@
</span><span class="cx"> m_buffer.resize(m_url.m_pathAfterLastSlash);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-URL URLParser::failure(const String& input)
</del><ins>+template<typename CharacterType>
+URL URLParser::failure(const CharacterType* input, unsigned length)
</ins><span class="cx"> {
</span><span class="cx"> URL url;
</span><span class="cx"> url.m_isValid = false;
</span><span class="cx"> url.m_protocolIsInHTTPFamily = false;
</span><ins>+ url.m_cannotBeABaseURL = false;
</ins><span class="cx"> url.m_schemeEnd = 0;
</span><span class="cx"> url.m_userStart = 0;
</span><span class="cx"> url.m_userEnd = 0;
</span><span class="lines">@@ -485,31 +574,37 @@
</span><span class="cx"> url.m_pathEnd = 0;
</span><span class="cx"> url.m_queryEnd = 0;
</span><span class="cx"> url.m_fragmentEnd = 0;
</span><del>- url.m_string = input;
</del><ins>+ url.m_string = String(input, length);
</ins><span class="cx"> return url;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> URL URLParser::parse(const String& input, const URL& base, const TextEncoding& encoding)
</span><span class="cx"> {
</span><del>- LOG(URLParser, "Parsing URL <%s> base <%s>", input.utf8().data(), base.string().utf8().data());
</del><ins>+ if (input.is8Bit())
+ return parse(input.characters8(), input.length(), base, encoding);
+ return parse(input.characters16(), input.length(), base, encoding);
+}
+
+template<typename CharacterType>
+URL URLParser::parse(const CharacterType* input, const unsigned length, const URL& base, const TextEncoding& encoding)
+{
+ LOG(URLParser, "Parsing URL <%s> base <%s>", String(input, length).utf8().data(), base.string().utf8().data());
</ins><span class="cx"> m_url = { };
</span><span class="cx"> m_buffer.clear();
</span><del>- m_buffer.reserveCapacity(input.length());
</del><ins>+ m_buffer.reserveCapacity(length);
</ins><span class="cx">
</span><span class="cx"> bool isUTF8Encoding = encoding == UTF8Encoding();
</span><span class="cx"> StringBuilder queryBuffer;
</span><span class="cx">
</span><del>- unsigned endIndex = input.length();
</del><ins>+ unsigned endIndex = length;
</ins><span class="cx"> while (endIndex && isC0ControlOrSpace(input[endIndex - 1]))
</span><span class="cx"> endIndex--;
</span><del>- auto codePoints = bufferView(input, 0, endIndex).codePoints();
- auto c = codePoints.begin();
- auto end = codePoints.end();
- auto authorityOrHostBegin = codePoints.begin();
- while (c != end && isC0ControlOrSpace(*c))
</del><ins>+ CodePointIterator<CharacterType> c(input, input + endIndex);
+ CodePointIterator<CharacterType> authorityOrHostBegin;
+ while (!c.atEnd() && isC0ControlOrSpace(*c))
</ins><span class="cx"> ++c;
</span><span class="cx"> auto beginAfterControlAndSpace = c;
</span><del>-
</del><ins>+
</ins><span class="cx"> enum class State : uint8_t {
</span><span class="cx"> SchemeStart,
</span><span class="cx"> Scheme,
</span><span class="lines">@@ -536,7 +631,7 @@
</span><span class="cx"> #define LOG_FINAL_STATE(x) LOG(URLParser, "Final State: %s", x)
</span><span class="cx">
</span><span class="cx"> State state = State::SchemeStart;
</span><del>- while (c != end) {
</del><ins>+ while (!c.atEnd()) {
</ins><span class="cx"> if (isTabOrNewline(*c)) {
</span><span class="cx"> ++c;
</span><span class="cx"> continue;
</span><span class="lines">@@ -582,9 +677,9 @@
</span><span class="cx"> m_url.m_portEnd = m_url.m_userStart;
</span><span class="cx"> auto maybeSlash = c;
</span><span class="cx"> ++maybeSlash;
</span><del>- while (maybeSlash != end && isTabOrNewline(*maybeSlash))
</del><ins>+ while (!maybeSlash.atEnd() && isTabOrNewline(*maybeSlash))
</ins><span class="cx"> ++maybeSlash;
</span><del>- if (maybeSlash != end && *maybeSlash == '/') {
</del><ins>+ if (!maybeSlash.atEnd() && *maybeSlash == '/') {
</ins><span class="cx"> m_buffer.append('/');
</span><span class="cx"> m_url.m_pathAfterLastSlash = m_url.m_userStart + 1;
</span><span class="cx"> state = State::PathOrAuthority;
</span><span class="lines">@@ -605,9 +700,9 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> ++c;
</span><del>- while (c != end && isTabOrNewline(*c))
</del><ins>+ while (!c.atEnd() && isTabOrNewline(*c))
</ins><span class="cx"> ++c;
</span><del>- if (c == end) {
</del><ins>+ if (c.atEnd()) {
</ins><span class="cx"> m_buffer.clear();
</span><span class="cx"> state = State::NoScheme;
</span><span class="cx"> c = beginAfterControlAndSpace;
</span><span class="lines">@@ -616,7 +711,7 @@
</span><span class="cx"> case State::NoScheme:
</span><span class="cx"> LOG_STATE("NoScheme");
</span><span class="cx"> if (base.isNull() || (base.m_cannotBeABaseURL && *c != '#'))
</span><del>- return failure(input);
</del><ins>+ return failure(input, length);
</ins><span class="cx"> if (base.m_cannotBeABaseURL && *c == '#') {
</span><span class="cx"> copyURLPartsUntil(base, URLPart::QueryEnd);
</span><span class="cx"> state = State::Fragment;
</span><span class="lines">@@ -637,10 +732,10 @@
</span><span class="cx"> if (*c == '/') {
</span><span class="cx"> m_buffer.append('/');
</span><span class="cx"> ++c;
</span><del>- while (c != end && isTabOrNewline(*c))
</del><ins>+ while (!c.atEnd() && isTabOrNewline(*c))
</ins><span class="cx"> ++c;
</span><del>- if (c == end)
- return failure(input);
</del><ins>+ if (c.atEnd())
+ return failure(input, length);
</ins><span class="cx"> if (*c == '/') {
</span><span class="cx"> m_buffer.append('/');
</span><span class="cx"> state = State::SpecialAuthorityIgnoreSlashes;
</span><span class="lines">@@ -705,10 +800,10 @@
</span><span class="cx"> m_buffer.append("//");
</span><span class="cx"> if (*c == '/' || *c == '\\') {
</span><span class="cx"> ++c;
</span><del>- while (c != end && isTabOrNewline(*c))
</del><ins>+ while (!c.atEnd() && isTabOrNewline(*c))
</ins><span class="cx"> ++c;
</span><del>- if (c == end)
- return failure(input);
</del><ins>+ if (c.atEnd())
+ return failure(input, length);
</ins><span class="cx"> if (*c == '/' || *c == '\\')
</span><span class="cx"> ++c;
</span><span class="cx"> }
</span><span class="lines">@@ -728,9 +823,9 @@
</span><span class="cx"> LOG_STATE("AuthorityOrHost");
</span><span class="cx"> {
</span><span class="cx"> if (*c == '@') {
</span><del>- parseAuthority(authorityOrHostBegin, c);
</del><ins>+ parseAuthority(CodePointIterator<CharacterType>(authorityOrHostBegin, c));
</ins><span class="cx"> ++c;
</span><del>- while (c != end && isTabOrNewline(*c))
</del><ins>+ while (!c.atEnd() && isTabOrNewline(*c))
</ins><span class="cx"> ++c;
</span><span class="cx"> authorityOrHostBegin = c;
</span><span class="cx"> state = State::Host;
</span><span class="lines">@@ -741,8 +836,8 @@
</span><span class="cx"> if (isSlash || *c == '?' || *c == '#') {
</span><span class="cx"> m_url.m_userEnd = m_buffer.length();
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><del>- if (!parseHost(authorityOrHostBegin, c))
- return failure(input);
</del><ins>+ if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
+ return failure(input, length);
</ins><span class="cx"> if (!isSlash) {
</span><span class="cx"> m_buffer.append('/');
</span><span class="cx"> m_url.m_pathAfterLastSlash = m_buffer.length();
</span><span class="lines">@@ -758,8 +853,8 @@
</span><span class="cx"> case State::Host:
</span><span class="cx"> LOG_STATE("Host");
</span><span class="cx"> if (*c == '/' || *c == '?' || *c == '#') {
</span><del>- if (!parseHost(authorityOrHostBegin, c))
- return failure(input);
</del><ins>+ if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
+ return failure(input, length);
</ins><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -806,7 +901,7 @@
</span><span class="cx"> ++c;
</span><span class="cx"> break;
</span><span class="cx"> default:
</span><del>- if (!base.isNull() && base.protocolIs("file") && shouldCopyFileURL(c, end))
</del><ins>+ if (!base.isNull() && base.protocolIs("file") && shouldCopyFileURL(c))
</ins><span class="cx"> copyURLPartsUntil(base, URLPart::PathAfterLastSlash);
</span><span class="cx"> else {
</span><span class="cx"> m_buffer.append("///");
</span><span class="lines">@@ -835,12 +930,17 @@
</span><span class="cx"> state = State::FileHost;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (!base.isNull() && base.protocol() == "file") {
</del><ins>+ if (!base.isNull() && base.protocolIs("file")) {
+ // FIXME: This String copy is unnecessary.
</ins><span class="cx"> String basePath = base.path();
</span><del>- auto basePathCodePoints = StringView(basePath).codePoints();
- if (basePath.length() >= 2 && isWindowsDriveLetter(basePathCodePoints.begin(), basePathCodePoints.end())) {
- m_buffer.append(basePath[0]);
- m_buffer.append(basePath[1]);
</del><ins>+ if (basePath.length() >= 2) {
+ bool windowsQuirk = basePath.is8Bit()
+ ? isWindowsDriveLetter(CodePointIterator<LChar>(basePath.characters8(), basePath.characters8() + basePath.length()))
+ : isWindowsDriveLetter(CodePointIterator<UChar>(basePath.characters16(), basePath.characters16() + basePath.length()));
+ if (windowsQuirk) {
+ m_buffer.append(basePath[0]);
+ m_buffer.append(basePath[1]);
+ }
</ins><span class="cx"> }
</span><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="lines">@@ -883,8 +983,8 @@
</span><span class="cx"> state = State::Path;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (!parseHost(authorityOrHostBegin, c))
- return failure(input);
</del><ins>+ if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
+ return failure(input, length);
</ins><span class="cx">
</span><span class="cx"> if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost") {
</span><span class="cx"> m_buffer.resize(m_url.m_passwordEnd);
</span><span class="lines">@@ -914,13 +1014,13 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> if (m_buffer.length() && m_buffer[m_buffer.length() - 1] == '/') {
</span><del>- if (isDoubleDotPathSegment(c, end)) {
- consumeDoubleDotPathSegment(c, end);
</del><ins>+ if (isDoubleDotPathSegment(c)) {
+ consumeDoubleDotPathSegment(c);
</ins><span class="cx"> popPath();
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (m_buffer[m_buffer.length() - 1] == '/' && isSingleDotPathSegment(c, end)) {
- consumeSingleDotPathSegment(c, end);
</del><ins>+ if (m_buffer[m_buffer.length() - 1] == '/' && isSingleDotPathSegment(c)) {
+ consumeSingleDotPathSegment(c);
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -935,7 +1035,7 @@
</span><span class="cx"> state = State::Fragment;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (isPercentEncodedDot(c, end)) {
</del><ins>+ if (isPercentEncodedDot(c)) {
</ins><span class="cx"> m_buffer.append('.');
</span><span class="cx"> ASSERT(*c == '%');
</span><span class="cx"> ++c;
</span><span class="lines">@@ -990,7 +1090,7 @@
</span><span class="cx"> LOG_FINAL_STATE("SchemeStart");
</span><span class="cx"> if (!m_buffer.length() && !base.isNull())
</span><span class="cx"> return base;
</span><del>- return failure(input);
</del><ins>+ return failure(input, length);
</ins><span class="cx"> case State::Scheme:
</span><span class="cx"> LOG_FINAL_STATE("Scheme");
</span><span class="cx"> break;
</span><span class="lines">@@ -1032,7 +1132,7 @@
</span><span class="cx"> break;
</span><span class="cx"> case State::SpecialAuthorityIgnoreSlashes:
</span><span class="cx"> LOG_FINAL_STATE("SpecialAuthorityIgnoreSlashes");
</span><del>- return failure(input);
</del><ins>+ return failure(input, length);
</ins><span class="cx"> case State::AuthorityOrHost:
</span><span class="cx"> LOG_FINAL_STATE("AuthorityOrHost");
</span><span class="cx"> m_url.m_userEnd = m_buffer.length();
</span><span class="lines">@@ -1041,8 +1141,8 @@
</span><span class="cx"> case State::Host:
</span><span class="cx"> if (state == State::Host)
</span><span class="cx"> LOG_FINAL_STATE("Host");
</span><del>- if (!parseHost(authorityOrHostBegin, end))
- return failure(input);
</del><ins>+ if (!parseHost(authorityOrHostBegin))
+ return failure(input, length);
</ins><span class="cx"> m_buffer.append('/');
</span><span class="cx"> m_url.m_pathEnd = m_url.m_portEnd + 1;
</span><span class="cx"> m_url.m_pathAfterLastSlash = m_url.m_pathEnd;
</span><span class="lines">@@ -1095,8 +1195,8 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (!parseHost(authorityOrHostBegin, c))
- return failure(input);
</del><ins>+ if (!parseHost(CodePointIterator<CharacterType>(authorityOrHostBegin, c)))
+ return failure(input, length);
</ins><span class="cx">
</span><span class="cx"> if (bufferView(m_buffer, m_url.m_passwordEnd, m_buffer.length() - m_url.m_passwordEnd) == "localhost") {
</span><span class="cx"> m_buffer.resize(m_url.m_passwordEnd);
</span><span class="lines">@@ -1143,18 +1243,19 @@
</span><span class="cx"> return m_url;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void URLParser::parseAuthority(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+void URLParser::parseAuthority(CodePointIterator<CharacterType> iterator)
</ins><span class="cx"> {
</span><del>- if (iterator == end) {
</del><ins>+ if (iterator.atEnd()) {
</ins><span class="cx"> m_url.m_userEnd = m_buffer.length();
</span><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> return;
</span><span class="cx"> }
</span><del>- for (; iterator != end; ++iterator) {
</del><ins>+ for (; !iterator.atEnd(); ++iterator) {
</ins><span class="cx"> if (*iterator == ':') {
</span><span class="cx"> ++iterator;
</span><span class="cx"> m_url.m_userEnd = m_buffer.length();
</span><del>- if (iterator == end) {
</del><ins>+ if (iterator.atEnd()) {
</ins><span class="cx"> m_url.m_passwordEnd = m_url.m_userEnd;
</span><span class="cx"> if (m_url.m_userEnd > m_url.m_userStart)
</span><span class="cx"> m_buffer.append('@');
</span><span class="lines">@@ -1165,7 +1266,7 @@
</span><span class="cx"> }
</span><span class="cx"> m_buffer.append(*iterator);
</span><span class="cx"> }
</span><del>- for (; iterator != end; ++iterator)
</del><ins>+ for (; !iterator.atEnd(); ++iterator)
</ins><span class="cx"> m_buffer.append(*iterator);
</span><span class="cx"> m_url.m_passwordEnd = m_buffer.length();
</span><span class="cx"> if (!m_url.m_userEnd)
</span><span class="lines">@@ -1252,7 +1353,8 @@
</span><span class="cx"> buffer.append(']');
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static Optional<uint32_t> parseIPv4Number(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+static Optional<uint32_t> parseIPv4Number(CodePointIterator<CharacterType>& iterator)
</ins><span class="cx"> {
</span><span class="cx"> // FIXME: Check for overflow.
</span><span class="cx"> enum class State : uint8_t {
</span><span class="lines">@@ -1264,7 +1366,7 @@
</span><span class="cx"> };
</span><span class="cx"> State state = State::UnknownBase;
</span><span class="cx"> uint32_t value = 0;
</span><del>- while (iterator != end) {
</del><ins>+ while (!iterator.atEnd()) {
</ins><span class="cx"> if (*iterator == '.') {
</span><span class="cx"> ++iterator;
</span><span class="cx"> return value;
</span><span class="lines">@@ -1319,14 +1421,15 @@
</span><span class="cx"> return values[exponent];
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static Optional<uint32_t> parseIPv4Host(StringView::CodePoints::Iterator iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+static Optional<uint32_t> parseIPv4Host(CodePointIterator<CharacterType> iterator)
</ins><span class="cx"> {
</span><span class="cx"> Vector<uint32_t, 4> items;
</span><span class="cx"> items.reserveInitialCapacity(4);
</span><del>- while (iterator != end) {
</del><ins>+ while (!iterator.atEnd()) {
</ins><span class="cx"> if (items.size() >= 4)
</span><span class="cx"> return Nullopt;
</span><del>- if (auto item = parseIPv4Number(iterator, end))
</del><ins>+ if (auto item = parseIPv4Number(iterator))
</ins><span class="cx"> items.append(item.value());
</span><span class="cx"> else
</span><span class="cx"> return Nullopt;
</span><span class="lines">@@ -1348,10 +1451,11 @@
</span><span class="cx"> ipv4 += items[counter] * pow256(3 - counter);
</span><span class="cx"> return ipv4;
</span><span class="cx"> }
</span><del>-
-static Optional<std::array<uint16_t, 8>> parseIPv6Host(StringView::CodePoints::Iterator c, StringView::CodePoints::Iterator end)
</del><ins>+
+template<typename CharacterType>
+static Optional<std::array<uint16_t, 8>> parseIPv6Host(CodePointIterator<CharacterType> c)
</ins><span class="cx"> {
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return Nullopt;
</span><span class="cx">
</span><span class="cx"> std::array<uint16_t, 8> address = {{0, 0, 0, 0, 0, 0, 0, 0}};
</span><span class="lines">@@ -1360,7 +1464,7 @@
</span><span class="cx">
</span><span class="cx"> if (*c == ':') {
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return Nullopt;
</span><span class="cx"> if (*c != ':')
</span><span class="cx"> return Nullopt;
</span><span class="lines">@@ -1369,7 +1473,7 @@
</span><span class="cx"> compressPointer = piecePointer;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- while (c != end) {
</del><ins>+ while (!c.atEnd()) {
</ins><span class="cx"> if (piecePointer == 8)
</span><span class="cx"> return Nullopt;
</span><span class="cx"> if (*c == ':') {
</span><span class="lines">@@ -1382,7 +1486,7 @@
</span><span class="cx"> }
</span><span class="cx"> uint16_t value = 0;
</span><span class="cx"> for (size_t length = 0; length < 4; length++) {
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> break;
</span><span class="cx"> if (!isASCIIHexDigit(*c))
</span><span class="cx"> break;
</span><span class="lines">@@ -1390,7 +1494,7 @@
</span><span class="cx"> ++c;
</span><span class="cx"> }
</span><span class="cx"> address[piecePointer++] = value;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> break;
</span><span class="cx"> if (*c != ':')
</span><span class="cx"> return Nullopt;
</span><span class="lines">@@ -1397,11 +1501,11 @@
</span><span class="cx"> ++c;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (c != end) {
</del><ins>+ if (!c.atEnd()) {
</ins><span class="cx"> if (piecePointer > 6)
</span><span class="cx"> return Nullopt;
</span><span class="cx"> size_t dotsSeen = 0;
</span><del>- while (c != end) {
</del><ins>+ while (!c.atEnd()) {
</ins><span class="cx"> Optional<uint16_t> value;
</span><span class="cx"> if (!isASCIIDigit(*c))
</span><span class="cx"> return Nullopt;
</span><span class="lines">@@ -1414,7 +1518,7 @@
</span><span class="cx"> else
</span><span class="cx"> value = value.value() * 10 + number;
</span><span class="cx"> ++c;
</span><del>- if (c == end)
</del><ins>+ if (c.atEnd())
</ins><span class="cx"> return Nullopt;
</span><span class="cx"> if (value.value() > 255)
</span><span class="cx"> return Nullopt;
</span><span class="lines">@@ -1424,9 +1528,9 @@
</span><span class="cx"> address[piecePointer] = address[piecePointer] * 0x100 + value.valueOr(0);
</span><span class="cx"> if (dotsSeen == 1 || dotsSeen == 3)
</span><span class="cx"> piecePointer++;
</span><del>- if (c != end)
</del><ins>+ if (!c.atEnd())
</ins><span class="cx"> ++c;
</span><del>- if (dotsSeen == 3 && c != end)
</del><ins>+ if (dotsSeen == 3 && !c.atEnd())
</ins><span class="cx"> return Nullopt;
</span><span class="cx"> dotsSeen++;
</span><span class="cx"> }
</span><span class="lines">@@ -1513,15 +1617,16 @@
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool URLParser::parsePort(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+bool URLParser::parsePort(CodePointIterator<CharacterType>& iterator)
</ins><span class="cx"> {
</span><span class="cx"> uint32_t port = 0;
</span><del>- if (iterator == end) {
</del><ins>+ if (iterator.atEnd()) {
</ins><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> m_buffer.append(':');
</span><del>- for (; iterator != end; ++iterator) {
</del><ins>+ for (; !iterator.atEnd(); ++iterator) {
</ins><span class="cx"> if (isTabOrNewline(*iterator))
</span><span class="cx"> continue;
</span><span class="cx"> if (isASCIIDigit(*iterator)) {
</span><span class="lines">@@ -1542,23 +1647,24 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool URLParser::parseHost(StringView::CodePoints::Iterator& iterator, const StringView::CodePoints::Iterator& end)
</del><ins>+template<typename CharacterType>
+bool URLParser::parseHost(CodePointIterator<CharacterType> iterator)
</ins><span class="cx"> {
</span><del>- if (iterator == end)
</del><ins>+ if (iterator.atEnd())
</ins><span class="cx"> return false;
</span><span class="cx"> if (*iterator == '[') {
</span><span class="cx"> ++iterator;
</span><span class="cx"> auto ipv6End = iterator;
</span><del>- while (ipv6End != end && *ipv6End != ']')
</del><ins>+ while (!ipv6End.atEnd() && *ipv6End != ']')
</ins><span class="cx"> ++ipv6End;
</span><del>- if (auto address = parseIPv6Host(iterator, ipv6End)) {
</del><ins>+ if (auto address = parseIPv6Host(CodePointIterator<CharacterType>(iterator, ipv6End))) {
</ins><span class="cx"> serializeIPv6(address.value(), m_buffer);
</span><span class="cx"> m_url.m_hostEnd = m_buffer.length();
</span><del>- if (ipv6End != end) {
</del><ins>+ if (!ipv6End.atEnd()) {
</ins><span class="cx"> ++ipv6End;
</span><del>- if (ipv6End != end && *ipv6End == ':') {
</del><ins>+ if (!ipv6End.atEnd() && *ipv6End == ':') {
</ins><span class="cx"> ++ipv6End;
</span><del>- return parsePort(ipv6End, end);
</del><ins>+ return parsePort(ipv6End);
</ins><span class="cx"> }
</span><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span><span class="lines">@@ -1569,21 +1675,21 @@
</span><span class="cx">
</span><span class="cx"> if (!m_hostHasPercentOrNonASCII) {
</span><span class="cx"> auto hostIterator = iterator;
</span><del>- for (; iterator != end; ++iterator) {
</del><ins>+ for (; !iterator.atEnd(); ++iterator) {
</ins><span class="cx"> if (isTabOrNewline(*iterator))
</span><span class="cx"> continue;
</span><span class="cx"> if (*iterator == ':')
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (auto address = parseIPv4Host(hostIterator, iterator)) {
</del><ins>+ if (auto address = parseIPv4Host(CodePointIterator<CharacterType>(hostIterator, iterator))) {
</ins><span class="cx"> serializeIPv4(address.value(), m_buffer);
</span><span class="cx"> m_url.m_hostEnd = m_buffer.length();
</span><del>- if (iterator == end) {
</del><ins>+ if (iterator.atEnd()) {
</ins><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> ++iterator;
</span><del>- return parsePort(iterator, end);
</del><ins>+ return parsePort(iterator);
</ins><span class="cx"> }
</span><span class="cx"> for (; hostIterator != iterator; ++hostIterator) {
</span><span class="cx"> if (!isTabOrNewline(*hostIterator))
</span><span class="lines">@@ -1590,12 +1696,12 @@
</span><span class="cx"> m_buffer.append(toASCIILower(*hostIterator));
</span><span class="cx"> }
</span><span class="cx"> m_url.m_hostEnd = m_buffer.length();
</span><del>- if (hostIterator != end) {
</del><ins>+ if (!hostIterator.atEnd()) {
</ins><span class="cx"> ASSERT(*hostIterator == ':');
</span><span class="cx"> ++hostIterator;
</span><del>- while (hostIterator != end && isTabOrNewline(*hostIterator))
</del><ins>+ while (!hostIterator.atEnd() && isTabOrNewline(*hostIterator))
</ins><span class="cx"> ++hostIterator;
</span><del>- return parsePort(hostIterator, end);
</del><ins>+ return parsePort(hostIterator);
</ins><span class="cx"> }
</span><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span><span class="lines">@@ -1603,7 +1709,7 @@
</span><span class="cx">
</span><span class="cx"> // FIXME: We probably don't need to make so many buffers and String copies.
</span><span class="cx"> StringBuilder utf8Encoded;
</span><del>- for (; iterator != end; ++iterator) {
</del><ins>+ for (; !iterator.atEnd(); ++iterator) {
</ins><span class="cx"> if (isTabOrNewline(*iterator))
</span><span class="cx"> continue;
</span><span class="cx"> if (*iterator == ':')
</span><span class="lines">@@ -1623,27 +1729,29 @@
</span><span class="cx"> auto asciiDomain = domainToASCII(domain);
</span><span class="cx"> if (!asciiDomain || hasInvalidDomainCharacter(asciiDomain.value()))
</span><span class="cx"> return false;
</span><ins>+ String& asciiDomainValue = asciiDomain.value();
+ RELEASE_ASSERT(asciiDomainValue.is8Bit());
+ const LChar* asciiDomainCharacters = asciiDomainValue.characters8();
</ins><span class="cx">
</span><del>- auto asciiDomainCodePoints = StringView(asciiDomain.value()).codePoints();
- if (auto address = parseIPv4Host(asciiDomainCodePoints.begin(), asciiDomainCodePoints.end())) {
</del><ins>+ if (auto address = parseIPv4Host(CodePointIterator<LChar>(asciiDomainCharacters, asciiDomainCharacters + asciiDomainValue.length()))) {
</ins><span class="cx"> serializeIPv4(address.value(), m_buffer);
</span><span class="cx"> m_url.m_hostEnd = m_buffer.length();
</span><del>- if (iterator == end) {
</del><ins>+ if (iterator.atEnd()) {
</ins><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> ++iterator;
</span><del>- return parsePort(iterator, end);
</del><ins>+ return parsePort(iterator);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_buffer.append(asciiDomain.value());
</span><span class="cx"> m_url.m_hostEnd = m_buffer.length();
</span><del>- if (iterator != end) {
</del><ins>+ if (!iterator.atEnd()) {
</ins><span class="cx"> ASSERT(*iterator == ':');
</span><span class="cx"> ++iterator;
</span><del>- while (iterator != end && isTabOrNewline(*iterator))
</del><ins>+ while (!iterator.atEnd() && isTabOrNewline(*iterator))
</ins><span class="cx"> ++iterator;
</span><del>- return parsePort(iterator, end);
</del><ins>+ return parsePort(iterator);
</ins><span class="cx"> }
</span><span class="cx"> m_url.m_portEnd = m_buffer.length();
</span><span class="cx"> return true;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformURLParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/URLParser.h (205985 => 205986)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/URLParser.h        2016-09-15 18:11:48 UTC (rev 205985)
+++ trunk/Source/WebCore/platform/URLParser.h        2016-09-15 18:12:09 UTC (rev 205986)
</span><span class="lines">@@ -32,6 +32,8 @@
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><ins>+template<typename CharacterType> class CodePointIterator;
+
</ins><span class="cx"> class URLParser {
</span><span class="cx"> public:
</span><span class="cx"> WEBCORE_EXPORT URL parse(const String&, const URL& = { }, const TextEncoding& = UTF8Encoding());
</span><span class="lines">@@ -49,11 +51,13 @@
</span><span class="cx"> StringBuilder m_buffer;
</span><span class="cx"> bool m_urlIsSpecial { false };
</span><span class="cx"> bool m_hostHasPercentOrNonASCII { false };
</span><del>- void parseAuthority(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
- bool parseHost(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
- bool parsePort(StringView::CodePoints::Iterator&, const StringView::CodePoints::Iterator& end);
- URL failure(const String& input);
</del><span class="cx">
</span><ins>+ template<typename CharacterType> URL parse(const CharacterType*, const unsigned length, const URL&, const TextEncoding&);
+ template<typename CharacterType> void parseAuthority(CodePointIterator<CharacterType>);
+ template<typename CharacterType> bool parseHost(CodePointIterator<CharacterType>);
+ template<typename CharacterType> bool parsePort(CodePointIterator<CharacterType>&);
+ template<typename CharacterType> URL failure(const CharacterType*, unsigned length);
+
</ins><span class="cx"> enum class URLPart;
</span><span class="cx"> void copyURLPartsUntil(const URL& base, URLPart);
</span><span class="cx"> static size_t urlLengthUntilPart(const URL&, URLPart);
</span></span></pre>
</div>
</div>
</body>
</html>