Skip to content

Commit 02a1741

Browse files
Finishd OrderedCode
1 parent eb13a86 commit 02a1741

File tree

3 files changed

+111
-2
lines changed

3 files changed

+111
-2
lines changed

packages/firestore/src/index/ordered_code_writer.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
* limitations under the License.
1616
*/
1717
import { debugAssert } from '../util/assert';
18+
<<<<<<< HEAD
19+
import { ByteString } from '../util/byte_string';
20+
=======
21+
>>>>>>> @{-1}
1822

1923
/** These constants are taken from the backend. */
2024
const MIN_SURROGATE = '\uD800';
@@ -25,6 +29,7 @@ const NULL_BYTE = 0xff; // Combined with ESCAPE1
2529
const SEPARATOR = 0x01; // Combined with ESCAPE1
2630

2731
const ESCAPE2 = 0xff;
32+
const INFINITY = 0xff; // Combined with ESCAPE2
2833
const FF_BYTE = 0x00; // Combined with ESCAPE2
2934

3035
const LONG_SIZE = 64;
@@ -110,6 +115,26 @@ export class OrderedCodeWriter {
110115
buffer = new Uint8Array(DEFAULT_BUFFER_SIZE);
111116
position = 0;
112117

118+
writeBytesAscending(value: ByteString): void {
119+
const it = value[Symbol.iterator]();
120+
let byte = it.next();
121+
while (!byte.done) {
122+
this.writeByteAscending(byte.value);
123+
byte = it.next();
124+
}
125+
this.writeSeparatorAscending();
126+
}
127+
128+
writeBytesDescending(value: ByteString): void {
129+
const it = value[Symbol.iterator]();
130+
let byte = it.next();
131+
while (!byte.done) {
132+
this.writeByteDescending(byte.value);
133+
byte = it.next();
134+
}
135+
this.writeSeparatorDescending();
136+
}
137+
113138
/** Writes utf8 bytes into this byte sequence, ascending. */
114139
writeUtf8Ascending(sequence: string): void {
115140
for (const c of sequence) {
@@ -182,6 +207,24 @@ export class OrderedCodeWriter {
182207
}
183208
}
184209

210+
/**
211+
* Writes the "infinity" byte sequence that sorts after all other byte
212+
* sequences written in ascending order.
213+
*/
214+
writeInfinityAscending(): void {
215+
this.writeEscapedByteAscending(ESCAPE2);
216+
this.writeEscapedByteAscending(INFINITY);
217+
}
218+
219+
/**
220+
* Writes the "infinity" byte sequence that sorts before all other byte
221+
* sequences written in descending order.
222+
*/
223+
writeInfinityDescending(): void {
224+
this.writeEscapedByteDescending(ESCAPE2);
225+
this.writeEscapedByteDescending(INFINITY);
226+
}
227+
185228
/**
186229
* Encodes `val` into an encoding so that the order matches the IEEE 754
187230
* floating-point comparison results with the following exceptions:
@@ -277,4 +320,10 @@ export class OrderedCodeWriter {
277320
newBuffer.set(this.buffer); // copy old data
278321
this.buffer = newBuffer;
279322
}
323+
324+
seed(encodedBytes: Uint8Array): void {
325+
this.ensureAvailable(encodedBytes.length);
326+
this.buffer.set(encodedBytes, this.position);
327+
this.position += encodedBytes.length;
328+
}
280329
}

packages/firestore/src/util/byte_string.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ export class ByteString {
4343
return new ByteString(binaryString);
4444
}
4545

46+
[Symbol.iterator](): Iterator<number> {
47+
let i = 0;
48+
return {
49+
next: () => {
50+
if (i < this.binaryString.length) {
51+
return { value: this.binaryString.charCodeAt(i++), done: false };
52+
} else {
53+
return { value: undefined, done: true };
54+
}
55+
}
56+
};
57+
}
58+
4659
toBase64(): string {
4760
return encodeBase64(this.binaryString);
4861
}

packages/firestore/test/unit/index/ordered_code_writer.test.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
numberOfLeadingZerosInByte,
2121
OrderedCodeWriter
2222
} from '../../../src/index/ordered_code_writer';
23+
import { ByteString } from '../../../src/util/byte_string';
2324

2425
class ValueTestCase<T> {
2526
constructor(
@@ -108,6 +109,23 @@ const STRING_TEST_CASES: Array<ValueTestCase<string>> = [
108109
)
109110
];
110111

112+
const BYTES_TEST_CASES: Array<ValueTestCase<Uint8Array>> = [
113+
new ValueTestCase(fromHex(''), '0001', 'fffe'),
114+
new ValueTestCase(fromHex('00'), '00ff0001', 'ff00fffe'),
115+
new ValueTestCase(fromHex('0000'), '00ff00ff0001', 'ff00ff00fffe'),
116+
new ValueTestCase(fromHex('0001'), '00ff010001', 'ff00fefffe'),
117+
new ValueTestCase(fromHex('0041'), '00ff410001', 'ff00befffe'),
118+
new ValueTestCase(fromHex('00ff'), '00ffff000001', 'ff0000fffffe'),
119+
new ValueTestCase(fromHex('01'), '010001', 'fefffe'),
120+
new ValueTestCase(fromHex('0100'), '0100ff0001', 'feff00fffe'),
121+
new ValueTestCase(fromHex('6f776c'), '6f776c0001', '908893fffe'),
122+
new ValueTestCase(fromHex('ff'), 'ff000001', '00fffffe'),
123+
new ValueTestCase(fromHex('ff00'), 'ff0000ff0001', '00ffff00fffe'),
124+
new ValueTestCase(fromHex('ff01'), 'ff00010001', '00fffefffe'),
125+
new ValueTestCase(fromHex('ffff'), 'ff00ff000001', '00ff00fffffe'),
126+
new ValueTestCase(fromHex('ffffff'), 'ff00ff00ff000001', '00ff00ff00fffffe')
127+
];
128+
111129
describe('Ordered Code Writer', () => {
112130
it('computes number of leading zeros', () => {
113131
for (let i = 0; i < 0xff; ++i) {
@@ -139,6 +157,34 @@ describe('Ordered Code Writer', () => {
139157
verifyOrdering(STRING_TEST_CASES);
140158
});
141159

160+
it('converts bytes to bits', () => {
161+
verifyEncoding(BYTES_TEST_CASES);
162+
});
163+
164+
it('orders bytes correctly', () => {
165+
verifyOrdering(BYTES_TEST_CASES);
166+
});
167+
168+
it('encodes infinity', () => {
169+
const writer = new OrderedCodeWriter();
170+
writer.writeInfinityAscending();
171+
expect(writer.encodedBytes()).to.deep.equal(fromHex("ffff"));
172+
173+
writer.reset();
174+
writer.writeInfinityDescending();
175+
expect(writer.encodedBytes()).to.deep.equal(fromHex("0000"));
176+
});
177+
178+
it('seeds bytes', () => {
179+
const writer = new OrderedCodeWriter();
180+
writer.seed(new Uint8Array([0x01]));
181+
writer.writeInfinityAscending();
182+
writer.seed(new Uint8Array([0x02]));
183+
expect(writer.encodedBytes()).to.deep.equal(
184+
fromHex("01ffff02")
185+
);
186+
});
187+
142188
function verifyEncoding(testCases: Array<ValueTestCase<unknown>>): void {
143189
for (let i = 0; i < testCases.length; ++i) {
144190
const bytes = getBytes(testCases[i].val);
@@ -202,8 +248,9 @@ function getBytes(val: unknown): { asc: Uint8Array; desc: Uint8Array } {
202248
} else if (typeof val === 'string') {
203249
ascWriter.writeUtf8Ascending(val);
204250
descWriter.writeUtf8Descending(val);
205-
} else {
206-
throw new Error('Encoding not yet supported for ' + val);
251+
} else if (val instanceof Uint8Array) {
252+
ascWriter.writeBytesAscending(ByteString.fromUint8Array(val));
253+
descWriter.writeBytesDescending(ByteString.fromUint8Array(val));
207254
}
208255
return { asc: ascWriter.encodedBytes(), desc: descWriter.encodedBytes() };
209256
}

0 commit comments

Comments
 (0)