| author | wenzelm | 
| Sun, 23 Feb 2014 21:30:35 +0100 | |
| changeset 55695 | c05d3e22adaf | 
| parent 55618 | 995162143ef4 | 
| child 60833 | d201996f72a8 | 
| permissions | -rw-r--r-- | 
| 54439 | 1  | 
/* Title: Pure/General/bytes.scala  | 
2  | 
Module: PIDE  | 
|
3  | 
Author: Makarius  | 
|
4  | 
||
5  | 
Immutable byte vectors versus UTF8 strings.  | 
|
6  | 
*/  | 
|
7  | 
||
8  | 
package isabelle  | 
|
9  | 
||
10  | 
||
| 54440 | 11  | 
import java.io.{File => JFile, OutputStream, FileInputStream}
 | 
12  | 
||
13  | 
||
| 54439 | 14  | 
object Bytes  | 
15  | 
{
 | 
|
16  | 
val empty: Bytes = new Bytes(Array[Byte](), 0, 0)  | 
|
17  | 
||
18  | 
def apply(s: CharSequence): Bytes =  | 
|
19  | 
  {
 | 
|
20  | 
val str = s.toString  | 
|
21  | 
if (str.isEmpty) empty  | 
|
22  | 
    else {
 | 
|
| 
54442
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
23  | 
val b = str.getBytes(UTF8.charset)  | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
24  | 
new Bytes(b, 0, b.length)  | 
| 54439 | 25  | 
}  | 
26  | 
}  | 
|
| 54440 | 27  | 
|
| 
54442
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
28  | 
def apply(a: Array[Byte], offset: Int, length: Int): Bytes =  | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
29  | 
if (length == 0) empty  | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
30  | 
    else {
 | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
31  | 
val b = new Array[Byte](length)  | 
| 55618 | 32  | 
System.arraycopy(a, offset, b, 0, length)  | 
| 
54442
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
33  | 
new Bytes(b, 0, b.length)  | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
34  | 
}  | 
| 
 
c39972ddd672
more specific Protocol_Output: empty message.body, main content via bytes/text;
 
wenzelm 
parents: 
54440 
diff
changeset
 | 
35  | 
|
| 54440 | 36  | 
|
37  | 
/* read */  | 
|
38  | 
||
39  | 
def read(file: JFile): Bytes =  | 
|
40  | 
  {
 | 
|
41  | 
var i = 0  | 
|
42  | 
var m = 0  | 
|
43  | 
val n = file.length.toInt  | 
|
44  | 
val bytes = new Array[Byte](n)  | 
|
45  | 
||
46  | 
val stream = new FileInputStream(file)  | 
|
47  | 
    try {
 | 
|
48  | 
      do {
 | 
|
49  | 
m = stream.read(bytes, i, n - i)  | 
|
50  | 
if (m != -1) i += m  | 
|
51  | 
} while (m != -1 && n > i)  | 
|
52  | 
}  | 
|
53  | 
    finally { stream.close }
 | 
|
54  | 
||
55  | 
new Bytes(bytes, 0, bytes.length)  | 
|
56  | 
}  | 
|
| 54439 | 57  | 
}  | 
58  | 
||
59  | 
final class Bytes private(  | 
|
60  | 
protected val bytes: Array[Byte],  | 
|
61  | 
protected val offset: Int,  | 
|
62  | 
val length: Int)  | 
|
63  | 
{
 | 
|
64  | 
/* equality */  | 
|
65  | 
||
| 54440 | 66  | 
override def equals(that: Any): Boolean =  | 
67  | 
  {
 | 
|
68  | 
    that match {
 | 
|
69  | 
case other: Bytes =>  | 
|
70  | 
if (this eq other) true  | 
|
71  | 
else if (length != other.length) false  | 
|
72  | 
else (0 until length).forall(i => bytes(offset + i) == other.bytes(other.offset + i))  | 
|
73  | 
case _ => false  | 
|
74  | 
}  | 
|
75  | 
}  | 
|
76  | 
||
| 54439 | 77  | 
private lazy val hash: Int =  | 
78  | 
  {
 | 
|
79  | 
var h = 0  | 
|
80  | 
    for (i <- offset until offset + length) {
 | 
|
81  | 
val b = bytes(i).asInstanceOf[Int] & 0xFF  | 
|
82  | 
h = 31 * h + b  | 
|
83  | 
}  | 
|
84  | 
h  | 
|
85  | 
}  | 
|
86  | 
||
87  | 
override def hashCode(): Int = hash  | 
|
88  | 
||
89  | 
||
90  | 
/* content */  | 
|
91  | 
||
| 54512 | 92  | 
lazy val sha1_digest: SHA1.Digest = SHA1.digest(bytes)  | 
| 54440 | 93  | 
|
| 54444 | 94  | 
override def toString: String =  | 
95  | 
UTF8.decode_chars(s => s, bytes, offset, offset + length).toString  | 
|
| 54439 | 96  | 
|
| 54440 | 97  | 
def isEmpty: Boolean = length == 0  | 
| 54439 | 98  | 
|
99  | 
def +(other: Bytes): Bytes =  | 
|
| 54440 | 100  | 
if (other.isEmpty) this  | 
101  | 
else if (isEmpty) other  | 
|
| 54439 | 102  | 
    else {
 | 
103  | 
val new_bytes = new Array[Byte](length + other.length)  | 
|
| 55618 | 104  | 
System.arraycopy(bytes, offset, new_bytes, 0, length)  | 
105  | 
System.arraycopy(other.bytes, other.offset, new_bytes, length, other.length)  | 
|
| 54439 | 106  | 
new Bytes(new_bytes, 0, new_bytes.length)  | 
107  | 
}  | 
|
| 54440 | 108  | 
|
109  | 
||
110  | 
/* write */  | 
|
111  | 
||
112  | 
def write(stream: OutputStream): Unit = stream.write(bytes, offset, length)  | 
|
| 54439 | 113  | 
}  | 
114  |