Skip to content

Commit 8718d09

Browse files
committed
Merge '0.6.x' into 'master'.
2 parents 62d352e + c72bf67 commit 8718d09

37 files changed

+1447
-677
lines changed

javalib/src/main/scala/java/net/URI.scala

Lines changed: 78 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ final class URI(origStr: String) extends Serializable with Comparable[URI] {
5454
private val _authority = fld(AbsAuthority, RelAuthority).filter(_ != "")
5555
private val _userInfo = fld(AbsUserInfo, RelUserInfo)
5656
private val _host = fld(AbsHost, RelHost)
57-
private val _port = fld(AbsPort, RelPort).fold(-1)(_.toInt)
57+
private val _port = fld(AbsPort, RelPort).map(_.toInt)
5858

5959
private val _path = {
6060
val useNetPath = fld(AbsAuthority, RelAuthority).isDefined
@@ -101,41 +101,56 @@ final class URI(origStr: String) extends Serializable with Comparable[URI] {
101101
*/
102102
@inline
103103
private def internalCompare(that: URI)(cmp: (String, String) => Int): Int = {
104-
@inline def cmpOpt(x: js.UndefOr[String], y: js.UndefOr[String]): Int = {
104+
@inline
105+
def cmpOpt[T](x: js.UndefOr[T], y: js.UndefOr[T])(comparator: (T, T) => Int): Int = {
105106
if (x == y) 0
106107
// Undefined components are considered less than defined components
107-
else x.fold(-1)(s1 => y.fold(1)(s2 => cmp(s1, s2)))
108+
else x.fold(-1)(s1 => y.fold(1)(s2 => comparator(s1, s2)))
109+
}
110+
def comparePathQueryFragement(): Int = {
111+
val cmpPath = cmpOpt(this._path, that._path)(cmp)
112+
if (cmpPath != 0) {
113+
cmpPath
114+
} else {
115+
val cmpQuery = cmpOpt(this._query, that._query)(cmp)
116+
if (cmpQuery != 0) cmpQuery
117+
else cmpOpt(this._fragment, that._fragment)(cmp)
118+
}
108119
}
109120

110-
if (this._scheme != that._scheme)
111-
this._scheme.fold(-1)(s1 => that._scheme.fold(1)(s1.compareToIgnoreCase))
112-
else if (this._isOpaque != that._isOpaque)
113-
// A hierarchical URI is less than an opaque URI
114-
if (this._isOpaque) 1 else -1
115-
else if (_isOpaque) {
116-
val ssp = cmp(this._schemeSpecificPart, that._schemeSpecificPart)
117-
if (ssp != 0) ssp
118-
else cmpOpt(this._fragment, that._fragment)
119-
} else if (this._authority != that._authority) {
120-
if (this._host.isDefined && that._host.isDefined) {
121-
val ui = cmpOpt(this._userInfo, that._userInfo)
122-
if (ui != 0) ui
123-
else {
124-
val hst = this._host.get.compareToIgnoreCase(that._host.get)
125-
if (hst != 0) hst
126-
else if (this._port == that._port) 0
127-
else if (this._port == -1) -1
128-
else if (that._port == -1) 1
129-
else this._port - that._port
121+
val cmpScheme = cmpOpt(this._scheme, that._scheme)(_.compareToIgnoreCase(_))
122+
if (cmpScheme != 0) {
123+
cmpScheme
124+
} else {
125+
val cmpIsOpaque = this.isOpaque.compareTo(that.isOpaque) // A hierarchical URI is less than an opaque URI
126+
if (cmpIsOpaque != 0) {
127+
cmpIsOpaque
128+
} else {
129+
if (this.isOpaque()) {
130+
val cmpSchemeSpecificPart = cmp(this._schemeSpecificPart, that._schemeSpecificPart)
131+
if (cmpSchemeSpecificPart != 0) cmpSchemeSpecificPart
132+
else comparePathQueryFragement()
133+
} else if (this._host.isDefined && that._host.isDefined) {
134+
val cmpUserInfo = cmpOpt(this._userInfo, that._userInfo)(cmp)
135+
if (cmpUserInfo != 0) {
136+
cmpUserInfo
137+
} else {
138+
val cmpHost = cmpOpt(this._host, that._host)(_.compareToIgnoreCase(_))
139+
if (cmpHost != 0) {
140+
cmpHost
141+
} else {
142+
val cmpPort = cmpOpt(this._port, that._port)(_ - _)
143+
if (cmpPort != 0) cmpPort
144+
else comparePathQueryFragement()
145+
}
146+
}
147+
} else {
148+
val cmpAuthority = cmpOpt(this._authority, that._authority)(cmp)
149+
if (cmpAuthority != 0) cmpAuthority
150+
else comparePathQueryFragement()
130151
}
131-
} else
132-
cmpOpt(this._authority, that._authority)
133-
} else if (this._path != that._path)
134-
cmpOpt(this._path, that._path)
135-
else if (this._query != that._query)
136-
cmpOpt(this._query, that._query)
137-
else
138-
cmpOpt(this._fragment, that._fragment)
152+
}
153+
}
139154
}
140155

141156
def compareTo(that: URI): Int = internalCompare(that)(_.compareTo(_))
@@ -149,7 +164,7 @@ final class URI(origStr: String) extends Serializable with Comparable[URI] {
149164
def getFragment(): String = _fragment.map(decodeComponent).orNull
150165
def getHost(): String = _host.orNull
151166
def getPath(): String = _path.map(decodeComponent).orNull
152-
def getPort(): Int = _port
167+
def getPort(): Int = _port.getOrElse(-1)
153168
def getQuery(): String = _query.map(decodeComponent).orNull
154169
def getRawAuthority(): String = _authority.orNull
155170
def getRawFragment(): String = _fragment.orNull
@@ -166,10 +181,19 @@ final class URI(origStr: String) extends Serializable with Comparable[URI] {
166181
import URI.normalizeEscapes
167182

168183
var acc = URI.uriSeed
169-
acc = mix(acc, _scheme.##) // scheme may not contain escapes
170-
acc = mix(acc, normalizeEscapes(_schemeSpecificPart).##)
171-
acc = mixLast(acc, _fragment.map(normalizeEscapes).##)
172-
184+
acc = mix(acc, _scheme.map(_.toLowerCase).##) // scheme may not contain escapes
185+
if (this.isOpaque()) {
186+
acc = mix(acc, normalizeEscapes(this._schemeSpecificPart).##)
187+
} else if (this._host.isDefined) {
188+
acc = mix(acc, normalizeEscapes(this._userInfo).##)
189+
acc = mix(acc, this._host.map(_.toLowerCase).##)
190+
acc = mix(acc, this._port.##)
191+
} else {
192+
acc = mix(acc, normalizeEscapes(this._authority).##)
193+
}
194+
acc = mix(acc, normalizeEscapes(this._path).##)
195+
acc = mix(acc, normalizeEscapes(this._query).##)
196+
acc = mixLast(acc, normalizeEscapes(this._fragment).##)
173197
finalizeHash(acc, 3)
174198
}
175199

@@ -334,7 +358,10 @@ object URI {
334358
}
335359

336360
// IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
337-
private final val ipv4address = "[0-9]{1,3}(?:\\.[0-9]{1,3}){3}"
361+
private final val ipv4address = {
362+
val digit = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
363+
s"(?:$digit\\.){3}$digit"
364+
}
338365

339366
private final val ipv6address = {
340367
// http://stackoverflow.com/a/17871737/1149944
@@ -800,21 +827,22 @@ object URI {
800827
}
801828

802829
/** Upper-cases all URI escape sequences in `str`. Used for hashing */
803-
private def normalizeEscapes(str: String): String = {
804-
var i = 0
805-
var res = ""
806-
while (i < str.length) {
807-
if (str.charAt(i) == '%') {
808-
assert(str.length > i + 2, "Invalid escape in URI")
809-
res += str.substring(i, i+3).toUpperCase()
810-
i += 3
811-
} else {
812-
res += str.substring(i, i+1)
813-
i += 1
830+
private def normalizeEscapes(maybeStr: js.UndefOr[String]): js.UndefOr[String] = {
831+
maybeStr.map { str =>
832+
var i = 0
833+
var res = ""
834+
while (i < str.length) {
835+
if (str.charAt(i) == '%') {
836+
assert(str.length > i + 2, "Invalid escape in URI")
837+
res += str.substring(i, i+3).toUpperCase()
838+
i += 3
839+
} else {
840+
res += str.substring(i, i+1)
841+
i += 1
842+
}
814843
}
844+
res
815845
}
816-
817-
res
818846
}
819847

820848
private final val uriSeed = 53722356
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Scala.js (https://www.scala-js.org/)
3+
*
4+
* Copyright EPFL.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (https://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package java.util
14+
15+
/** A universal `Comparator` using the *natural ordering* of the elements.
16+
*
17+
* A number of JDK APIs accept a possibly-null `Comparator`, and use the
18+
* *natural ordering* of elements when it is `null`. This universal comparator
19+
* can be used internally instead of systematically testing for `null`,
20+
* simplifying code paths.
21+
*
22+
* The `compare()` method of this comparator throws `ClassCastException`s when
23+
* used with values that cannot be compared using natural ordering, assuming
24+
* Scala.js is configured with compliant `asInstanceOf`s. The behavior is
25+
* otherwise undefined.
26+
*/
27+
private[util] object NaturalComparator extends Comparator[Any] {
28+
def compare(o1: Any, o2: Any): Int =
29+
o1.asInstanceOf[Comparable[Any]].compareTo(o2)
30+
31+
/** Selects the given comparator if it is non-null, otherwise the natural
32+
* comparator.
33+
*/
34+
def select[A](comparator: Comparator[A]): Comparator[_ >: A] =
35+
if (comparator eq null) this
36+
else comparator
37+
38+
/** Unselects the given comparator, returning `null` if it was the natural
39+
* comparator.
40+
*
41+
* This method is useful to re-expose to a public API an internal comparator
42+
* that was obtained with `select()`.
43+
*/
44+
def unselect[A](comparator: Comparator[A]): Comparator[A] =
45+
if (comparator eq this) null
46+
else comparator
47+
}

0 commit comments

Comments
 (0)