File size: 3,361 Bytes
5641073
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 * @author jdiaz5513
 */

import initTrace from "debug";

import { decodeUtf8, encodeUtf8 } from "../../util";
import { ListElementSize } from "../list-element-size";
import { List, initList } from "./list";
import { Pointer, validate, isNull, getContent, erase } from "./pointer";
import { PointerType } from "./pointer-type";

const trace = initTrace("capnp:text");
trace("load");

export class Text extends List<string> {
  static fromPointer(pointer: Pointer): Text {
    validate(PointerType.LIST, pointer, ListElementSize.BYTE);

    return textFromPointerUnchecked(pointer);
  }

  /**
   * Read a utf-8 encoded string value from this pointer.
   *
   * @param {number} [index] The index at which to start reading; defaults to zero.
   * @returns {string} The string value.
   */

  get(index = 0): string {
    if (index !== 0) {
      trace("Called get() on %s with a strange index (%d).", this, index);
    }

    if (isNull(this)) return "";

    const c = getContent(this);

    // Remember to exclude the NUL byte.

    return decodeUtf8(
      new Uint8Array(
        c.segment.buffer,
        c.byteOffset + index,
        this.getLength() - index
      )
    );
  }

  /**
   * Get the number of utf-8 encoded bytes in this text. This does **not** include the NUL byte.
   *
   * @returns {number} The number of bytes allocated for the text.
   */

  getLength(): number {
    return super.getLength() - 1;
  }

  /**
   * Write a utf-8 encoded string value starting at the specified index.
   *
   * @param {number} index The index at which to start copying the string. Note that if this is not zero the bytes
   * before `index` will be left as-is. All bytes after `index` will be overwritten.
   * @param {string} value The string value to set.
   * @returns {void}
   */

  set(index: number, value: string): void {
    if (index !== 0) {
      trace("Called set() on %s with a strange index (%d).", this, index);
    }

    const src = encodeUtf8(value);
    const dstLength = src.byteLength + index;
    let c: Pointer;
    let original: Uint8Array | undefined;

    // TODO: Consider reusing existing space if list is already initialized and there's enough room for the value.

    if (!isNull(this)) {
      c = getContent(this);

      // Only copy bytes that will remain after copying. Everything after `index` should end up truncated.

      let originalLength = this.getLength();

      if (originalLength >= index) {
        originalLength = index;
      } else {
        trace(
          "%d byte gap exists between original text and new text in %s.",
          index - originalLength,
          this
        );
      }

      original = new Uint8Array(
        c.segment.buffer.slice(
          c.byteOffset,
          c.byteOffset + Math.min(originalLength, index)
        )
      );

      erase(this);
    }

    // Always allocate an extra byte for the NUL byte.

    initList(ListElementSize.BYTE, dstLength + 1, this);

    c = getContent(this);
    const dst = new Uint8Array(c.segment.buffer, c.byteOffset, dstLength);

    if (original) dst.set(original);

    dst.set(src, index);
  }

  toString(): string {
    return `Text_${super.toString()}`;
  }
}

function textFromPointerUnchecked(pointer: Pointer): Text {
  return new Text(
    pointer.segment,
    pointer.byteOffset,
    pointer._capnp.depthLimit
  );
}