Skip to content

Commit 784d2f3

Browse files
committed
Cross compatibility with the new collections of 2.13
Use distinct implementations of PagedSeq according to the scala version. Use JavaConverters rather than JavaConversions. Use Map#map instead of Map#transform. Use ++= instead of copyToBuffer.
1 parent 5c11019 commit 784d2f3

File tree

6 files changed

+280
-5
lines changed

6 files changed

+280
-5
lines changed

jvm/src/test/scala/scala/util/parsing/combinator/t4929.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.util.parsing.json._
22
import java.util.concurrent._
3-
import collection.JavaConversions._
3+
import collection.JavaConverters._
44

55
import org.junit.Test
66

@@ -36,6 +36,6 @@ class t4929 {
3636
thread.setDaemon(true)
3737
thread.start()
3838
}
39-
errors foreach { throw(_) }
39+
errors.asScala foreach { throw(_) }
4040
}
4141
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../scala-2.12/scala/util/parsing/input/PagedSeq.scala
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
10+
11+
package scala
12+
package util.parsing.input
13+
14+
import java.io.{File, FileReader, Reader => JReader}
15+
import scala.reflect.ClassTag
16+
17+
/** The `PagedSeq` object defines a lazy implementations of
18+
* a random access sequence.
19+
*
20+
* Provides utility methods that return instances of `PagedSeq[Char]`.
21+
* `fromIterator` and `fromIterable` provide generalised instances of `PagedSeq`
22+
*/
23+
object PagedSeq {
24+
final val UndeterminedEnd = Int.MaxValue
25+
26+
/** Constructs a paged sequence from an iterator */
27+
def fromIterator[T: ClassTag](source: Iterator[T]): PagedSeq[T] =
28+
new PagedSeq[T]((data: Array[T], start: Int, len: Int) => {
29+
var i = 0
30+
while (i < len && source.hasNext) {
31+
data(start + i) = source.next()
32+
i += 1
33+
}
34+
if (i == 0) -1 else i
35+
})
36+
37+
/** Constructs a paged sequence from an iterable */
38+
def fromIterable[T: ClassTag](source: Iterable[T]): PagedSeq[T] =
39+
fromIterator(source.iterator)
40+
41+
/** Constructs a paged character sequence from a string iterator */
42+
def fromStrings(source: Iterator[String]): PagedSeq[Char] = {
43+
var current: String = ""
44+
def more(data: Array[Char], start: Int, len: Int): Int =
45+
if (current.length != 0) {
46+
val cnt = current.length min len
47+
current.getChars(0, cnt, data, start)
48+
current = current.substring(cnt)
49+
if (cnt == len) cnt
50+
else (more(data, start + cnt, len - cnt) max 0) + cnt
51+
} else if (source.hasNext) {
52+
current = source.next()
53+
more(data, start, len)
54+
} else -1
55+
new PagedSeq(more(_: Array[Char], _: Int, _: Int))
56+
}
57+
58+
/** Constructs a paged character sequence from a string iterable */
59+
def fromStrings(source: Iterable[String]): PagedSeq[Char] =
60+
fromStrings(source.iterator)
61+
62+
/** Constructs a paged character sequence from a line iterator
63+
* Lines do not contain trailing `\n` characters; The method inserts
64+
* a line separator `\n` between any two lines in the sequence.
65+
*/
66+
def fromLines(source: Iterator[String]): PagedSeq[Char] = {
67+
var isFirst = true
68+
fromStrings(source map { line =>
69+
if (isFirst) {
70+
isFirst = false
71+
line
72+
} else "\n"+line
73+
})
74+
}
75+
76+
/** Constructs a paged character sequence from a line iterable
77+
* Lines do not contain trailing `\n` characters; The method inserts
78+
* a line separator `\n` between any two lines in the sequence.
79+
*/
80+
def fromLines(source: Iterable[String]): PagedSeq[Char] =
81+
fromLines(source.iterator)
82+
83+
/** Constructs a paged character sequence from an input reader
84+
*/
85+
def fromReader(source: JReader): PagedSeq[Char] =
86+
new PagedSeq(source.read(_: Array[Char], _: Int, _: Int))
87+
88+
/** Constructs a paged character sequence from an input file
89+
*/
90+
def fromFile(source: File): PagedSeq[Char] =
91+
fromReader(new FileReader(source))
92+
93+
/** Constructs a paged character sequence from a file with given name
94+
*/
95+
def fromFile(source: String): PagedSeq[Char] =
96+
fromFile(new File(source))
97+
98+
/** Constructs a paged character sequence from a scala.io.Source value
99+
*/
100+
def fromSource(source: scala.io.Source) =
101+
fromLines(source.getLines())
102+
}
103+
104+
105+
import PagedSeq._
106+
107+
/** An implementation of lazily computed sequences, where elements are stored
108+
* in "pages", i.e. arrays of fixed size.
109+
*
110+
* A paged sequence is constructed from a function that produces more elements when asked.
111+
* The producer function - `more`, is similar to the read method in java.io.Reader.
112+
* The `more` function takes three parameters: an array of elements, a start index, and an end index.
113+
* It should try to fill the array between start and end indices (excluding end index).
114+
* It returns the number of elements produced, or -1 if end of logical input stream was reached
115+
* before reading any element.
116+
*
117+
* @tparam T the type of the elements contained in this paged sequence, with an `ClassTag` context bound.
118+
*
119+
* @author Martin Odersky
120+
* @define Coll `PagedSeq`
121+
* @define coll paged sequence
122+
* @define mayNotTerminateInf
123+
* @define willNotTerminateInf
124+
*/
125+
class PagedSeq[T: ClassTag] protected(
126+
more: (Array[T], Int, Int) => Int,
127+
first1: Page[T],
128+
start: Int,
129+
end: Int)
130+
extends scala.collection.AbstractSeq[T]
131+
with scala.collection.IndexedSeq[T]
132+
{
133+
def this(more: (Array[T], Int, Int) => Int) = this(more, new Page[T](0), 0, UndeterminedEnd)
134+
135+
// Members declared in scala.collection.Seq
136+
def iterableFactory: collection.SeqFactory[collection.IndexedSeq] = collection.IndexedSeq
137+
138+
// Members declared in scala.collection.IterableOps
139+
protected[this] def fromSpecificIterable(coll: collection.Iterable[T]): collection.IndexedSeq[T] = iterableFactory.from(coll)
140+
protected[this] def newSpecificBuilder(): collection.mutable.Builder[T, collection.IndexedSeq[T]] = iterableFactory.newBuilder()
141+
142+
private var current: Page[T] = first1
143+
144+
private def latest = first1.latest
145+
146+
private def addMore() = latest.addMore(more)
147+
148+
private def page(absindex: Int) = {
149+
if (absindex < current.start)
150+
current = first1
151+
while (absindex >= current.end && current.next != null)
152+
current = current.next
153+
while (absindex >= current.end && !current.isLast) {
154+
current = addMore()
155+
}
156+
current
157+
}
158+
159+
/** The length of the paged sequence
160+
* @note Calling this method will force the entire sequence to be read.
161+
*/
162+
def length: Int = {
163+
while (!latest.isLast && latest.end < end) addMore()
164+
(latest.end min end) - start
165+
}
166+
167+
/** The element at position `index`.
168+
*/
169+
def apply(index: Int) =
170+
if (isDefinedAt(index)) page(index + start)(index + start)
171+
else throw new IndexOutOfBoundsException(index.toString)
172+
173+
/** Predicate method to check if an element is defined
174+
* at position `index` of the current sequence.
175+
* Unlike `length` this operation does not force reading
176+
* a lazy sequence to the end.
177+
*/
178+
override def isDefinedAt(index: Int) =
179+
index >= 0 && index < end - start && {
180+
val absidx = index + start
181+
absidx >= 0 && absidx < page(absidx).end
182+
}
183+
184+
/** The subsequence from index `start` up to `end -1` if `end`
185+
* is lesser than the length of the current sequence and up to
186+
* length of the sequence otherwise. This is limited up to the length
187+
* of the current sequence if `end` is larger than its length.
188+
*/
189+
override def slice(_start: Int, _end: Int): PagedSeq[T] = {
190+
page(start)
191+
val s = start + _start
192+
val e = if (_end == UndeterminedEnd) _end else start + _end
193+
var f = first1
194+
while (f.end <= s && !f.isLast) {
195+
if (f.next eq null) f = f.addMore(more)
196+
else f = f.next
197+
}
198+
// Warning -- not refining `more` means that slices can freely request and obtain
199+
// data outside of their slice. This is part of the design of PagedSeq
200+
// (to read pages!) but can be surprising.
201+
new PagedSeq(more, f, s, e)
202+
}
203+
204+
/** The subsequence from index `start` up to
205+
* the length of the current sequence.
206+
*/
207+
def slice(start: Int): PagedSeq[T] = slice(start, UndeterminedEnd)
208+
209+
/** Convert sequence to string */
210+
override def toString = {
211+
val buf = new StringBuilder
212+
for (ch <- PagedSeq.this.iterator) buf append ch
213+
buf.toString
214+
}
215+
}
216+
217+
218+
/** Page containing up to PageSize characters of the input sequence.
219+
*/
220+
private class Page[T: ClassTag](val num: Int) {
221+
222+
private final val PageSize = 4096
223+
224+
/** The next page in the sequence */
225+
var next : Page[T] = null
226+
227+
/** A later page in the sequence, serves a cache for pointing to last page */
228+
var later : Page[T] = this
229+
230+
/** The number of elements read into this page */
231+
var filled: Int = 0
232+
233+
/** Set true if the current page is the last in the sequence or if
234+
* the `more` function returned -1 signalling end of input. */
235+
var isLast: Boolean = false
236+
237+
/** The element array */
238+
final val data = new Array[T](PageSize)
239+
240+
/** The index of the first element in this page relative to the whole sequence */
241+
final def start = num * PageSize
242+
243+
/** The index of the element following the last element in this page relative
244+
* to the whole sequence */
245+
final def end = start + filled
246+
247+
/** The last page as currently present in the sequence; This can change as more
248+
* elements get appended to the sequence. */
249+
final def latest: Page[T] = {
250+
if (later.next != null) later = later.next.latest
251+
later
252+
}
253+
254+
/** The element at the given sequence index.
255+
* That index is relative to the whole sequence, not the page. */
256+
def apply(index: Int) = {
257+
if (index < start || index - start >= filled) throw new IndexOutOfBoundsException(index.toString)
258+
data(index - start)
259+
}
260+
261+
/** Produces more elements by calling `more` and adds them on the current page,
262+
* or fills a subsequent page if current page is full.
263+
* @note If current page is full, it is the last one in the sequence. */
264+
final def addMore(more: (Array[T], Int, Int) => Int): Page[T] =
265+
if (filled == PageSize) {
266+
next = new Page[T](num + 1)
267+
next.addMore(more)
268+
} else {
269+
val count = more(data, filled, PageSize - filled)
270+
if (count < 0) isLast = true
271+
else filled += count
272+
this
273+
}
274+
}

shared/src/main/scala/scala/util/parsing/json/JSON.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ object JSON extends Parser {
7373
* arrays. See the `parse` method for details.
7474
*/
7575
def resolveType(input: Any): Any = input match {
76-
case JSONObject(data) => data.transform {
77-
case (k,v) => resolveType(v)
76+
case JSONObject(data) => data.map {
77+
case (k,v) => k -> resolveType(v)
7878
}
7979
case JSONArray(data) => data.map(resolveType)
8080
case x => x

shared/src/test/scala/scala/util/parsing/combinator/UnitTestIO.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class UnitTestIO {
2626
val s = "Here is a test string"
2727
val f = io.Source.fromBytes(s.getBytes("utf-8"))
2828
val b = new collection.mutable.ArrayBuffer[Char]()
29-
f.copyToBuffer(b)
29+
b ++= f
3030
assertEquals(new String(b.toArray), s)
3131
}
3232
}

0 commit comments

Comments
 (0)