-
Notifications
You must be signed in to change notification settings - Fork 145
/
Scanners.scala
143 lines (124 loc) · 4.76 KB
/
Scanners.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package better.files.benchmarks
import java.io.BufferedReader
import better.files._
/** Base interface to test */
abstract class AbstractScanner(protected[this] val reader: BufferedReader) {
def hasNext: Boolean
def next(): String
def nextInt() = next().toInt
def nextLine() = reader.readLine()
def close() = reader.close()
}
/** Based on java.util.Scanner */
class JavaScanner(reader: BufferedReader) extends AbstractScanner(reader) {
private[this] val scanner = new java.util.Scanner(reader)
override def hasNext = scanner.hasNext
override def next() = scanner.next()
override def nextInt() = scanner.nextInt()
override def nextLine() = {
scanner.nextLine()
scanner.nextLine()
}
override def close() = scanner.close()
}
/** Based on StringTokenizer + resetting the iterator */
class IterableScanner(reader: BufferedReader) extends AbstractScanner(reader) with Iterable[String] {
override def iterator =
for {
line <- Iterator.continually(reader.readLine()).takeWhile(_ != null)
tokenizer = new java.util.StringTokenizer(line)
_ <- Iterator.continually(tokenizer).takeWhile(_.hasMoreTokens)
} yield tokenizer.nextToken()
private[this] var current = iterator
override def hasNext = current.hasNext
override def next() = current.next()
override def nextLine() = {
current = iterator
super.nextLine()
}
}
/** Based on a mutating var StringTokenizer */
class IteratorScanner(reader: BufferedReader) extends AbstractScanner(reader) with Iterator[String] {
import java.util.StringTokenizer
private[this] val tokenizers =
Iterator.continually(reader.readLine()).takeWhile(_ != null).map(new StringTokenizer(_)).filter(_.hasMoreTokens)
private[this] var current: Option[StringTokenizer] = None
@inline private[this] def tokenizer(): Option[StringTokenizer] =
current.find(_.hasMoreTokens) orElse {
current = if (tokenizers.hasNext) Some(tokenizers.next()) else None
current
}
override def hasNext = tokenizer().nonEmpty
override def next() = tokenizer().get.nextToken()
override def nextLine() = {
current = None
super.nextLine()
}
}
/** Based on java.io.StreamTokenizer */
class StreamingScanner(reader: BufferedReader) extends AbstractScanner(reader) with Iterator[String] {
import java.io.StreamTokenizer
private[this] val in = new StreamTokenizer(reader)
override def hasNext = in.ttype != StreamTokenizer.TT_EOF
override def next() = {
in.nextToken()
in.sval
}
override def nextInt() = nextDouble().toInt
def nextDouble() = {
in.nextToken()
in.nval
}
}
/** Based on a reusable StringBuilder */
class StringBuilderScanner(reader: BufferedReader) extends AbstractScanner(reader) with Iterator[String] {
private[this] val chars = reader.chars.nonClosing()
private[this] val buffer = new StringBuilder()
override def next() = {
buffer.clear()
while (buffer.isEmpty && hasNext) {
chars.takeWhile(c => !c.isWhitespace).foreach(buffer += _)
}
buffer.toString()
}
override def hasNext = chars.hasNext
}
/** Scala version of the ArrayBufferScanner */
class CharBufferScanner(reader: BufferedReader) extends AbstractScanner(reader) with Iterator[String] {
private[this] val chars = reader.chars.nonClosing()
private[this] var buffer = Array.ofDim[Char](1 << 4)
override def next() = {
var pos = 0
while (pos == 0 && hasNext) {
for {
c <- chars.takeWhile(c => c != ' ' && c != '\n')
} {
if (pos == buffer.length) buffer = java.util.Arrays.copyOf(buffer, 2 * pos)
buffer(pos) = c
pos += 1
}
}
String.copyValueOf(buffer, 0, pos)
}
override def hasNext = chars.hasNext
}
/** Scanner using https://github.com/williamfiset/FastJavaIO */
class FastJavaIOScanner(reader: BufferedReader) extends AbstractScanner(reader) {
protected def is: java.io.InputStream = new org.apache.commons.io.input.ReaderInputStream(reader, DefaultCharset)
private[this] val fastReader = new fastjavaio.InputReader(is)
override def hasNext = true // TODO: https://github.com/williamfiset/FastJavaIO/issues/3
override def next() = fastReader.readStr()
override def nextInt() = fastReader.readInt()
override def nextLine() = fastReader.readLine()
}
/** Same as FastJavaIOScanner but uses better-files's Reader => InputStream */
class FastJavaIOScanner2(reader: BufferedReader) extends FastJavaIOScanner(reader) {
override def is = reader.toInputStream()
}
/** Based on the better-files implementation */
class BetterFilesScanner(reader: BufferedReader) extends AbstractScanner(reader) {
private[this] val scanner = Scanner(reader)
override def hasNext = scanner.hasNext
override def next() = scanner.next()
override def nextLine() = scanner.nextLine()
}