summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
blob: aed16bf057c518a552a85c20cd56dedb530f5f99 (plain) (blame)
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
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$
package scala.tools.nsc.symtab.classfile;

/** Variable length byte arrays, with methods for basic pickling and unpickling.
 *  @param data: The initial buffer
 *  @param from: The first index where defined data are found
 *  @param to  : The first index where new data can be written
 */
class PickleBuffer(data: Array[byte], from: int, to: int) {

  var bytes = data;
  var readIndex = from;
  var writeIndex = to;

  /** Double bytes array */
  private def dble: unit = {
    val bytes1 = new Array[byte](bytes.length * 2);
    System.arraycopy(bytes, 0, bytes1, 0, writeIndex);
    bytes = bytes1
  }

  def ensureCapacity(capacity: int) = while (bytes.length < writeIndex + capacity) dble;

  // -- Basic output routines --------------------------------------------

  /** Write a byte of data */
  def writeByte(b: int): unit = {
    if (writeIndex == bytes.length) dble;
    bytes(writeIndex) = b.asInstanceOf[byte];
    writeIndex = writeIndex + 1
  }

  /** Write a natural number in big endian format, base 128.
   *  All but the last digits have bit 0x80 set.*/
  def writeNat(x: int): unit = {
    def writeNatPrefix(x: int): unit = {
      val y = x >>> 7;
      if (y != 0) writeNatPrefix(y);
      writeByte((x & 0x7f) | 0x80);
    }
    val y = x >>> 7;
    if (y != 0) writeNatPrefix(y);
    writeByte(x & 0x7f)
  }

  /** Write a natural number at `pos'
   *  If number is more than one byte, shift rest of array to make space. */
  def patchNat(pos: int, x: int): unit = {
    def patchNatPrefix(x: int): unit = {
      writeByte(0);
      System.arraycopy(bytes, pos, bytes, pos+1, writeIndex - (pos+1));
      bytes(pos) = ((x & 0x7f) | 0x80).asInstanceOf[byte];
      val y = x >>> 7;
      if (y != 0) patchNatPrefix(y)
    }
    bytes(pos) = (x & 0x7f).asInstanceOf[byte];
    val y = x >>> 7;
    if (y != 0) patchNatPrefix(y);
  }

  /** Write a long number in signed big endian format, base 256. */
  def writeLong(x: long): unit = {
    val y = x >> 8;
    val z = x & 0xff;
    if (-y != (z >> 7)) writeLong(y);
    writeByte(z.asInstanceOf[int]);
  }

  // -- Basic input routines --------------------------------------------

  /** Read a byte */
  def readByte(): int = {
    val x = bytes(readIndex); readIndex = readIndex + 1; x
  }

  /** Read a natural number in big endian format, base 128.
   *  All but the last digits have bit 0x80 set.*/
  def readNat(): int = {
    var b = 0;
    var x = 0;
    do {
      b = readByte();
      x = (x << 7) + (b & 0x7f);
    } while ((b & 0x80) != 0);
    x
  }

  /** Read a long number in signed big endian format, base 256. */
  def readLong(len: int): long = {
    var x = 0L;
    var i = 0;
    while (i < len) {
      x = (x << 8) + (readByte() & 0xff);
      i = i + 1
    }
    val leading = 64 - (len << 3);
    x << leading >> leading
  }

  /** Perform operation `op' until readIndex == end. Concatenate results into a list. */
  def until[T](end: int, op: () => T): List[T] =
    if (readIndex == end) List() else op() :: until(end, op);

  /** Create an index */
  def createIndex: Array[int] = {
    val index = new Array[int](readNat());
    for (val i <- Iterator.range(0, index.length)) {
      index(i) = readIndex;
      readByte();
      readIndex = readNat() + readIndex
    }
    index
  }
}