Skip to content

Commit 8e12bb2

Browse files
committed
add T.String and T.InternedString
1 parent 1ac162e commit 8e12bb2

File tree

8 files changed

+712
-116
lines changed

8 files changed

+712
-116
lines changed

src/builtins/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {make as makeFloat64} from "./float64";
1616

1717
import {make as makeBoolean} from "./boolean";
1818
import {make as makeString} from "./string";
19+
import {make as makeInternedString} from "./interned-string";
1920

2021

2122
export function registerBuiltins (realm: Realm): TypeRegistry {
@@ -33,6 +34,7 @@ export function registerBuiltins (realm: Realm): TypeRegistry {
3334
//registry.add(makeNumber(realm, 9));
3435
registry.add(makeBoolean(realm, 10));
3536
registry.add(makeString(realm, 11));
37+
registry.add(makeInternedString(realm, 12));
3638

3739
return registry;
3840
}

src/builtins/interned-string/index.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* @flow */
2+
3+
import type Backing from "backing";
4+
import type {Realm} from "../..";
5+
6+
import {$StringPool} from "../../symbols";
7+
import randomString from "../../random/string";
8+
9+
export function make (realm: Realm, typeId: uint32): Type<string> {
10+
const {StringType, T} = realm;
11+
const pool = realm[$StringPool];
12+
//return pool.makeInternedStringType('InternedString', typeId);
13+
14+
const RawString = T.String;
15+
16+
const InternedString = new StringType('InternedString', {
17+
id: typeId,
18+
byteLength: 8, // Pointer
19+
byteAlignment: 8,
20+
constructor (input) {
21+
if (this instanceof InternedString) {
22+
throw new TypeError(`InternedString is not a constructor.`);
23+
}
24+
else {
25+
return input == null ? '' : ''+input;
26+
}
27+
},
28+
cast (input: any): string {
29+
return input == null ? '' : ''+input;
30+
},
31+
accepts (input: any): boolean {
32+
return typeof input === 'string';
33+
},
34+
initialize (backing: Backing, pointerAddress: float64, initialInput?: string): void {
35+
if (!initialInput) {
36+
backing.setFloat64(pointerAddress, 0);
37+
}
38+
else {
39+
backing.setFloat64(pointerAddress, pool.add(initialInput));
40+
}
41+
},
42+
store (backing: Backing, pointerAddress: float64, input: string): void {
43+
const existing: float64 = backing.getFloat64(pointerAddress);
44+
if (!input) {
45+
if (existing !== 0) {
46+
pool.removeStringByPointer(pointerAddress);
47+
backing.setFloat64(pointerAddress, 0);
48+
}
49+
}
50+
else {
51+
const address: float64 = pool.add(input);
52+
if (address !== existing) {
53+
if (existing !== 0) {
54+
pool.removeStringByPointer(pointerAddress);
55+
}
56+
backing.setFloat64(pointerAddress, address);
57+
}
58+
}
59+
},
60+
load: RawString.load,
61+
clear (backing: Backing, pointerAddress: float64): string {
62+
const existing: float64 = backing.getFloat64(pointerAddress);
63+
if (existing !== 0) {
64+
pool.removeStringByPointer(pointerAddress);
65+
backing.setFloat64(pointerAddress, 0);
66+
}
67+
},
68+
randomValue: randomString,
69+
emptyValue (): string {
70+
return '';
71+
},
72+
hashValue: hashString
73+
});
74+
75+
return InternedString;
76+
}
77+
78+
79+
/**
80+
* Returns the hash for the given string.
81+
*/
82+
function hashString (input: string): uint32 {
83+
let hash = 0x811c9dc5;
84+
for (let i = 0; i < input.length; i++) {
85+
hash ^= input.charCodeAt(i);
86+
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
87+
}
88+
return hash >>> 0;
89+
}

src/builtins/interned-string/test.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
describeRealm('Builtin: InternedString', function (options) {
2+
let realm;
3+
let backing;
4+
let T;
5+
let address;
6+
7+
before(() => {
8+
realm = options.realm;
9+
backing = realm.backing;
10+
T = realm.T;
11+
address = backing.alloc(T.InternedString.byteLength);
12+
});
13+
14+
after(() => {
15+
backing.free(address);
16+
});
17+
18+
describe('Cast', function () {
19+
it('should return an empty value for empty input', function () {
20+
T.InternedString().should.equal('');
21+
});
22+
23+
});
24+
25+
it('should not create a new instance', function () {
26+
(() => new T.InternedString('wat')).should.throw(TypeError);
27+
});
28+
29+
describe('.emptyValue()', function () {
30+
it('should return an empty value', function () {
31+
T.InternedString.emptyValue().should.equal('');
32+
});
33+
});
34+
35+
describe('.randomValue()', function () {
36+
it('should return a random value', function () {
37+
const value = T.InternedString.randomValue();
38+
(typeof value).should.equal('string');
39+
});
40+
41+
it('should accept a random value', function () {
42+
T.InternedString.accepts(T.InternedString.randomValue()).should.equal(true);
43+
});
44+
});
45+
46+
describe('.initialize(), .store(), .load() and .clear()', function () {
47+
let input;
48+
before(() => {
49+
input = T.InternedString.randomValue();
50+
});
51+
52+
it('should initialize an address', function () {
53+
T.InternedString.initialize(backing, address);
54+
});
55+
56+
it('should load an empty value from a just-initialized address', function () {
57+
T.InternedString.load(backing, address).should.equal(T.InternedString.emptyValue());
58+
});
59+
60+
it('should store a value at an address', function () {
61+
T.InternedString.store(backing, address, input);
62+
});
63+
64+
it('should load a value from an address', function () {
65+
T.InternedString.load(backing, address).should.equal(input);
66+
});
67+
68+
it('should clear a value from an address', function () {
69+
T.InternedString.clear(backing, address);
70+
});
71+
72+
it('should load an empty value from a cleaned up address', function () {
73+
(T.InternedString.load(backing, address) === T.InternedString.emptyValue()).should.equal(true);
74+
});
75+
});
76+
77+
describe('.hashValue()', function () {
78+
it('should hash a value', function () {
79+
T.InternedString.hashValue('abc').should.be.above(-1);
80+
});
81+
82+
it('should hash a random value', function () {
83+
T.InternedString.hashValue(T.InternedString.randomValue()).should.be.above(-1);
84+
});
85+
86+
it('should hash an empty value', function () {
87+
T.InternedString.hashValue(T.InternedString.emptyValue()).should.be.above(-1);
88+
});
89+
});
90+
91+
describe('.Array', function () {
92+
let array;
93+
it('should create an array of items', function () {
94+
array = new T.InternedString.Array(4);
95+
});
96+
97+
it('should have the right length', function () {
98+
array.length.should.equal(4);
99+
});
100+
101+
it('every entry should be empty', function () {
102+
for (let i = 0; i < array.length; i++) {
103+
array[i].should.equal('');
104+
}
105+
});
106+
107+
it('should set an item in the middle of the array', function () {
108+
array[2] = 'hello world';
109+
});
110+
111+
it('should have stored the item', function () {
112+
array[2].should.equal('hello world');
113+
});
114+
115+
it('should overwrite the item', function () {
116+
array[2] = 'wat';
117+
});
118+
119+
it('should have overwritten the item', function () {
120+
array[2].should.equal('wat');
121+
});
122+
123+
it('should set every item in the array', function () {
124+
array[0] = 'a';
125+
array[1] = 'b';
126+
array[2] = 'c';
127+
array[3] = 'd';
128+
});
129+
130+
it('should have set every item in the array', function () {
131+
array[0].should.equal('a');
132+
array[1].should.equal('b');
133+
array[2].should.equal('c');
134+
array[3].should.equal('d');
135+
});
136+
137+
it('should clear every item in the array', function () {
138+
array[0] = '';
139+
array[1] = '';
140+
array[2] = '';
141+
array[3] = '';
142+
});
143+
144+
it('should have cleared every item in the array', function () {
145+
array[0].should.equal('');
146+
array[1].should.equal('');
147+
array[2].should.equal('');
148+
array[3].should.equal('');
149+
});
150+
151+
it('should create an array of items from a list of strings', function () {
152+
array = new T.InternedString.Array([
153+
'foo',
154+
'bar',
155+
'qux',
156+
'foobar',
157+
'hello',
158+
'world'
159+
]);
160+
});
161+
162+
it('should have the right length', function () {
163+
array.length.should.equal(6);
164+
});
165+
166+
it('should have set the contents', function () {
167+
array[0].should.equal('foo');
168+
array[1].should.equal('bar');
169+
array[2].should.equal('qux');
170+
array[3].should.equal('foobar');
171+
array[4].should.equal('hello');
172+
array[5].should.equal('world');
173+
});
174+
});
175+
});

0 commit comments

Comments
 (0)