Skip to content

Commit 4710bba

Browse files
committed
Added FlexIntType
1 parent 85017c4 commit 4710bba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1673
-322
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ A lot of data, especially data designed to be used in many different languages,
2020
- Use when there is a lot of repetition in the data. If you don't have any arrays, sets, or maps, you can't really benefit from the cutdown on redundancy.
2121

2222
## Differences from Protocol Buffers
23+
- Types have binary serializations, not just values. (Protocol Buffers requires both the sender and receiver to have `.proto` definition files, which are not designed to be transmitted like values.) This makes storage of complex types much more compact and allows for sending values of types the receiver has not yet seen.
2324
- Types are generated programmatically rather than by reading `.proto` files. This allows for functionality like a function which turns a type into another type that either contains an error message or an instance of the original type.
2425
- This project is designed with downloading data of known types from servers over HTTP in mind. If the client has already received data of the same type, the server only sends the value and the client reads it using its cached type. If the client doesn't know what the type looks like, the server sends it in byte form along with the value and the client caches the type. This way, the type does not need to be specified in the client-side JavaScript and repeated requests are very efficient.
2526
- `structure-bytes` provides a larger set of primitive and recursive types.
@@ -31,12 +32,13 @@ A lot of data, especially data designed to be used in many different languages,
3132
- `Int` (4-byte signed integer)
3233
- `Long` (8-byte signed integer)
3334
- `BigInt` (a signed integer with arbitrary precision)
35+
- `FlexInt` (a signed integer from `-(2 ** 52)` to `2 ** 52` with a variable-length representation)
3436
- `UnsignedByte` (1-byte unsigned integer)
3537
- `UnsignedShort` (2-byte unsigned integer)
3638
- `UnsignedInt` (4-byte unsigned integer)
3739
- `UnsignedLong` (8-byte unsigned integer)
3840
- `BigUnsignedInt` (an unsigned integer with arbitrary precision)
39-
- `FlexUnsignedInt` (an unsigned integer below `2^53` with a variable-length representation)
41+
- `FlexUnsignedInt` (an unsigned integer below `2 ** 53` with a variable-length representation)
4042
- `Date` (8-byte unsigned integer representing number of milliseconds since Jan 1, 1970)
4143
- `Day` (3-byte unsigned integer representing a specific day in history)
4244
- `Time` (4-byte unsigned integer representing a specific time of day)
@@ -474,6 +476,7 @@ In the following definitions, `type` means the binary type format.
474476
- `IntType`: identifier `0x03`
475477
- `LongType`: identifier `0x04`
476478
- `BigIntType`: identifier `0x05`
479+
- `FlexIntType`: identifier `0x07`
477480
- `UnsignedByteType`: identifier `0x11`
478481
- `UnsignedShortType`: identifier `0x12`
479482
- `UnsignedIntType`: identifier `0x13`
@@ -541,6 +544,7 @@ In the following definitions, `type` means the binary type format.
541544
- `BigIntType`:
542545
- `byteCount` - `flexInt`
543546
- `number` - `byteCount`-byte integer
547+
- `FlexIntType`: `flexInt` of `value * 2` if `value` is non-negative, `-2 * value - 1` if `value` is negative
544548
- `UnsignedByteType`: 1-byte unsigned integer
545549
- `UnsignedShortType`: 2-byte unsigned integer
546550
- `UnsignedIntType`: 4-byte unsigned integer

compiled/download.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiled/upload-download.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiled/upload.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* - [[IntType]]
2525
* - [[LongType]]
2626
* - [[BigIntType]]
27+
* - [[FlexIntType]]
2728
* - Unsigned integer types
2829
* - [[UnsignedByteType]]
2930
* - [[UnsignedShortType]]

dist/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* - [[IntType]]
2626
* - [[LongType]]
2727
* - [[BigIntType]]
28+
* - [[FlexIntType]]
2829
* - Unsigned integer types
2930
* - [[UnsignedByteType]]
3031
* - [[UnsignedShortType]]

dist/lib/assert.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function integer(instance) {
5050
*/
5151
function between(lower, value, upper, message) {
5252
if (value < lower || value >= upper) {
53-
const outOfBoundsMessage = util_inspect_1.inspect(value) +
53+
const outOfBoundsMessage = String(value) +
5454
' is not in [' +
5555
String(lower) +
5656
',' +

dist/lib/flex-int.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@ const UPPER_BOUNDS = new Map(); //mapping of numbers of bytes to the exclusive u
1313
{
1414
let cumulativeValues = 0;
1515
let bytes = 1;
16-
while (true) {
16+
while (cumulativeValues <= Number.MAX_SAFE_INTEGER) {
1717
cumulativeValues += possibleValueCount(bytes);
1818
UPPER_BOUNDS.set(bytes, cumulativeValues);
19-
if (cumulativeValues > Number.MAX_SAFE_INTEGER)
20-
break;
2119
bytes++;
2220
}
2321
}
@@ -51,19 +49,18 @@ function makeValueBuffer(value) {
5149
throw new Error('Cannot represent ' + String(value)); //should never occur
5250
})();
5351
const writeValue = value - (UPPER_BOUNDS.get(bytes - 1) || 0);
54-
const buffer = new ArrayBuffer(bytes);
55-
const castBuffer = new Uint8Array(buffer);
52+
const buffer = new Uint8Array(bytes);
5653
{
5754
let shiftedValue = writeValue;
5855
for (let writeByte = bytes - 1; writeByte >= 0; writeByte--) {
59-
castBuffer[writeByte] = shiftedValue & 0xFF; //write least significant byte
56+
buffer[writeByte] = shiftedValue & 0xFF; //write least significant byte
6057
//Move next least significant byte to least significant byte
6158
//Can't use bitwise math here because number may not fit in 32 bits
6259
shiftedValue = Math.floor(shiftedValue / 0x100);
6360
}
6461
}
65-
castBuffer[0] |= BYTE_MASKS.get(bytes);
66-
return buffer;
62+
buffer[0] |= BYTE_MASKS.get(bytes);
63+
return buffer.buffer;
6764
}
6865
exports.makeValueBuffer = makeValueBuffer;
6966
/**

dist/read.js

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const util_inspect_1 = require("./lib/util-inspect");
1313
const recursiveRegistry = require("./recursive-registry");
1414
const t = require("./types");
1515
const abstract_1 = require("./types/abstract");
16+
const flex_int_1 = require("./types/flex-int");
1617
const NOT_LONG_ENOUGH = 'Buffer is not long enough';
1718
function readFlexInt(buffer, offset) {
1819
assert_1.default(buffer.byteLength > offset, NOT_LONG_ENOUGH);
@@ -24,29 +25,17 @@ function readFlexInt(buffer, offset) {
2425
};
2526
}
2627
//Types whose type bytes are only 1 byte long (the type byte)
27-
const SINGLE_BYTE_TYPES = new Set([
28-
t.ByteType,
29-
t.ShortType,
30-
t.IntType,
31-
t.LongType,
32-
t.BigIntType,
33-
t.UnsignedByteType,
34-
t.UnsignedShortType,
35-
t.UnsignedIntType,
36-
t.UnsignedLongType,
37-
t.BigUnsignedIntType,
38-
t.FlexUnsignedIntType,
39-
t.DateType,
40-
t.DayType,
41-
t.TimeType,
42-
t.FloatType,
43-
t.DoubleType,
44-
t.BooleanType,
45-
t.BooleanArrayType,
46-
t.CharType,
47-
t.StringType,
48-
t.OctetsType
49-
]);
28+
const SINGLE_BYTE_TYPES = new Set();
29+
{
30+
const defaultAddToBuffer = abstract_1.default.prototype.addToBuffer;
31+
const tTypes = t;
32+
//tslint:disable-next-line:forin
33+
for (const typeName in tTypes) {
34+
const testType = tTypes[typeName];
35+
if (testType.prototype.addToBuffer === defaultAddToBuffer)
36+
SINGLE_BYTE_TYPES.add(testType);
37+
}
38+
}
5039
//Mapping of type bytes to the corresponding types
5140
const SINGLE_BYTE_TYPE_BYTES = new Map();
5241
for (const singleByteType of SINGLE_BYTE_TYPES) {
@@ -180,6 +169,11 @@ function consumeValue({ buffer, offset, type: readType, baseValue }) {
180169
length += bytes;
181170
break;
182171
}
172+
case t.FlexIntType: {
173+
({ value: readValue, length } = readFlexInt(buffer, offset));
174+
readValue = flex_int_1.fromUnsigned(readValue);
175+
break;
176+
}
183177
case t.UnsignedByteType: {
184178
length = 1;
185179
assert_1.default(buffer.byteLength > offset, NOT_LONG_ENOUGH);

dist/types/flex-int.d.ts

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,36 @@
11
import AppendableBuffer from '../lib/appendable';
2-
import UnsignedType from './unsigned';
2+
import IntegerType from './integer';
33
/**
4-
* A type storing any unsigned integer
5-
* that can be represented precisely in a double
6-
* (from `0` to `9007199254740991` (`2 ** 53 - 1`)).
7-
* Rather than having a fixed-length value representation,
8-
* more bytes are needed to represent larger values.
9-
* This is inspired by the UTF-8 format:
10-
* large values can be stored, but since most values
11-
* are small, fewer bytes are used in the typical case.
12-
* If values are uniformly distributed rather than
13-
* concentrated among smaller values, you will likely get
14-
* more efficient serializations from a fixed-width integer.
15-
* For example, when writing outputs of a 32-bit hash function,
16-
* you should use [[UnsignedIntType]] instead.
17-
*
18-
* The number of bytes required for numbers are as follows:
19-
* <table>
20-
* <thead>
21-
* <tr>
22-
* <th>Min</th>
23-
* <th>Max</th>
24-
* <th>Bytes</th>
25-
* </tr>
26-
* </thead>
27-
* <tbody>
28-
* <tr><td>0</td><td>127</td><td>1</td></tr>
29-
* <tr><td>128</td><td>16511</td><td>2</td></tr>
30-
* <tr><td>16512</td><td>2113663</td><td>3</td></tr>
31-
* <tr><td>2113664</td><td>270549119</td><td>4</td></tr>
32-
* <tr><td>270549120</td><td>34630287487</td><td>5</td></tr>
33-
* <tr><td>34630287488</td><td>4432676798591</td><td>6</td></tr>
34-
* <tr><td>4432676798592</td><td>567382630219903</td><td>7</td></tr>
35-
* <tr><td>567382630219904</td><td>9007199254740991</td><td>8</td></tr>
36-
* </tbody>
37-
* </table>
4+
* Converts an unsigned integer value
5+
* to a unique signed integer value.
6+
* The inverse of [[toUnsigned]].
7+
* @param signed The unsigned integer value
8+
*/
9+
export declare function fromUnsigned(unsigned: number): number;
10+
/**
11+
* Works like [[FlexUnsignedIntType]],
12+
* but allows for negative values as well.
13+
* Less efficient for storing positive values
14+
* than [[FlexUnsignedIntType]], so use that
15+
* instead if not storing negative values.
16+
* Also limited to values between
17+
* `-(2 ** 52)` and `2 ** 52 - 1`.
18+
* (Encodes `value` as approximately `2 * abs(value)`.)
3819
*
3920
* Example:
4021
* ````javascript
41-
* let type = new sb.FlexUnsignedIntType
22+
* let type = new sb.FlexIntType
4223
* ````
4324
*/
44-
export default class FlexUnsignedIntType extends UnsignedType<number | string> {
25+
export default class FlexIntType extends IntegerType<number | string> {
4526
static readonly _value: number;
4627
/**
4728
* Appends value bytes to an [[AppendableBuffer]] according to the type
4829
*
4930
* Example:
5031
* ````javascript
5132
* //Takes 4 bytes
52-
* type.writeValue(buffer, 2113664) //or '2113664'
33+
* type.writeValue(buffer, -2113664) //or '-2113664'
5334
* ````
5435
* @param buffer The buffer to which to append
5536
* @param value The value to write

0 commit comments

Comments
 (0)