Skip to content

Commit 8cdf983

Browse files
committed
perf: ⚡️ give another try to genProps()
1 parent d2ac305 commit 8cdf983

File tree

3 files changed

+261
-1
lines changed

3 files changed

+261
-1
lines changed

benchmarks/genProps.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {genProps: v4} = require('../es6/util/genProps/v4');
66
const {genProps: v5} = require('../es6/util/genProps/v5');
77
const {genProps: v6} = require('../es6/util/genProps/v6');
88
const {genProps: v7} = require('../es6/util/genProps/v7');
9+
const {genProps: v8} = require('../es6/util/genProps/v8');
910
const {parseProps} = require('../es6/util/parse');
1011

1112
const suite = new Benchmark.Suite;
@@ -39,6 +40,7 @@ run(v4);
3940
run(v5);
4041
run(v6);
4142
run(v7);
43+
run(v8);
4244

4345
suite
4446
.add(`genProps v1`, function() {
@@ -62,6 +64,9 @@ suite
6264
.add(`genProps v7`, function() {
6365
run(v7);
6466
})
67+
.add(`genProps v8`, function() {
68+
run(v8);
69+
})
6570

6671
suite
6772
.on('cycle', function(event) {

src/util/genProps/__tests__/genProps.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import {genProps as v4} from '../v4';
55
import {genProps as v5} from '../v5';
66
import {genProps as v6} from '../v6';
77
import {genProps as v7} from '../v7';
8+
import {genProps as v8} from '../v8';
89
import {parseProps} from '../../parse';
910
import { PROPERTY } from '../../../enums';
1011

11-
const generators = [v1, v2, v3, v4, v5, v6, v7];
12+
const generators = [v1, v2, v3, v4, v5, v6, v7, v8];
1213

1314
for (let i = 0; i < generators.length; i++) {
1415
const genProps = generators[i];

src/util/genProps/v8.ts

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
import { PROPERTY } from '../../enums';
2+
import {Properties} from '../../types';
3+
4+
const objectKeys = Object.keys.bind(Object);
5+
6+
export const genProps = (props: Properties): Buffer => {
7+
// Variable length integers
8+
const SubscriptionIdentifier = props[PROPERTY.SubscriptionIdentifier];
9+
10+
// Binary data
11+
const CorrelationData = props[PROPERTY.CorrelationData];
12+
const AuthenticationData = props[PROPERTY.AuthenticationData];
13+
14+
const ContentType = props[PROPERTY.ContentType];
15+
const ResponseTopic = props[PROPERTY.ResponseTopic];
16+
const AssignedClientIdentifier = props[PROPERTY.AssignedClientIdentifier];
17+
const AuthenticationMethod = props[PROPERTY.AuthenticationMethod];
18+
const ResponseInformation = props[PROPERTY.ResponseInformation];
19+
const ServerReference = props[PROPERTY.ServerReference];
20+
const ReasonString = props[PROPERTY.ReasonString];
21+
22+
// User properties
23+
const UserProperty = props[PROPERTY.UserProperty];
24+
25+
let size = 0;
26+
const keys = objectKeys(props);
27+
28+
for (const key of keys) {
29+
switch (Number(key)) {
30+
case PROPERTY.PayloadFormatIndicator:
31+
case PROPERTY.RequestProblemInformation:
32+
case PROPERTY.RequestResponseInformation:
33+
case PROPERTY.MaximumQoS:
34+
case PROPERTY.RetainAvailable:
35+
case PROPERTY.WildcardSubscriptionAvailable:
36+
case PROPERTY.SubscriptionIdentifierAvailable:
37+
case PROPERTY.SharedSubscriptionAvailable:
38+
size += 2;
39+
break;
40+
case PROPERTY.ServerKeepAlive:
41+
case PROPERTY.ReceiveMaximum:
42+
case PROPERTY.TopicAliasMaximum:
43+
case PROPERTY.TopicAlias:
44+
size += 3;
45+
break;
46+
case PROPERTY.MessageExpiryInterval:
47+
case PROPERTY.WillDelayInterval:
48+
case PROPERTY.SessionExpiryInterval:
49+
case PROPERTY.MaximumPacketSize:
50+
size += 5;
51+
break;
52+
case PROPERTY.SubscriptionIdentifier:
53+
if (SubscriptionIdentifier! < 128) size += 2;
54+
else if (SubscriptionIdentifier! < 16_384) size += 3;
55+
else if (SubscriptionIdentifier! < 2_097_152) size += 4;
56+
else size += 5;
57+
break;
58+
case PROPERTY.CorrelationData:
59+
size += 3 + CorrelationData!.length;
60+
break;
61+
case PROPERTY.AuthenticationData:
62+
size += 3 + AuthenticationData!.length;
63+
break;
64+
case PROPERTY.ContentType:
65+
case PROPERTY.ResponseTopic:
66+
case PROPERTY.AssignedClientIdentifier:
67+
case PROPERTY.AuthenticationMethod:
68+
case PROPERTY.ResponseInformation:
69+
case PROPERTY.ServerReference:
70+
case PROPERTY.ReasonString:
71+
size += 3 + Buffer.byteLength((props as any)[key]);
72+
break;
73+
}
74+
}
75+
76+
// User properties
77+
if (UserProperty) {
78+
const len = UserProperty.length;
79+
for (let i = 0; i < len; i++)
80+
size += 5 + Buffer.byteLength(UserProperty[i][0]) + Buffer.byteLength(UserProperty[i][1]);
81+
}
82+
83+
let offset: number = 0;
84+
let buf: Buffer;
85+
86+
// Write initial properties variable length integer.
87+
if (size < 128) {
88+
offset = 1;
89+
buf = Buffer.allocUnsafe(size + 1);
90+
buf.writeUInt8(size, 0);
91+
} else if (size < 16_384) {
92+
offset = 2;
93+
buf = Buffer.allocUnsafe(size + 2);
94+
buf.writeUInt16LE(((size & 0b011111110000000) << 1) | (0b10000000 | (size & 0b01111111)), 0);
95+
} else if (size < 2_097_152) {
96+
offset = 3;
97+
buf = Buffer.allocUnsafe(size + 3);
98+
buf.writeUInt16LE(((0b100000000000000 | (size & 0b011111110000000)) << 1) | (0b10000000 | (size & 0b01111111)), 0);
99+
buf.writeUInt8((size >> 14) & 0b01111111, 2);
100+
} else {
101+
offset = 4;
102+
buf = Buffer.allocUnsafe(size + 4);
103+
buf.writeUInt32LE((((((size >> 21) & 0b01111111) << 8) | (0b10000000 | ((size >> 14) & 0b01111111))) << 16) |
104+
((0b100000000000000 | (size & 0b011111110000000)) << 1) | (0b10000000 | (size & 0b01111111)), 0);
105+
}
106+
107+
for (const key of keys) {
108+
const identifier = Number(key);
109+
switch (identifier) {
110+
case PROPERTY.PayloadFormatIndicator:
111+
case PROPERTY.RequestProblemInformation:
112+
case PROPERTY.RequestResponseInformation:
113+
case PROPERTY.MaximumQoS:
114+
case PROPERTY.RetainAvailable:
115+
case PROPERTY.WildcardSubscriptionAvailable:
116+
case PROPERTY.SubscriptionIdentifierAvailable:
117+
case PROPERTY.SharedSubscriptionAvailable:
118+
buf.writeUInt8(identifier, offset++);
119+
buf.writeUInt8((props as any)[key], offset++);
120+
break;
121+
case PROPERTY.ServerKeepAlive:
122+
case PROPERTY.ReceiveMaximum:
123+
case PROPERTY.TopicAliasMaximum:
124+
case PROPERTY.TopicAlias:
125+
buf.writeUInt8(identifier, offset++);
126+
buf.writeUInt16BE((props as any)[key], offset);
127+
offset += 2;
128+
break;
129+
case PROPERTY.MessageExpiryInterval:
130+
case PROPERTY.WillDelayInterval:
131+
case PROPERTY.SessionExpiryInterval:
132+
case PROPERTY.MaximumPacketSize:
133+
buf.writeUInt8(identifier, offset++);
134+
buf.writeUInt32BE((props as any)[key], offset);
135+
offset += 4;
136+
break;
137+
}
138+
}
139+
140+
// Variable length integers
141+
if (SubscriptionIdentifier !== undefined) {
142+
buf.writeUInt8(PROPERTY.SubscriptionIdentifier, offset++);
143+
if (SubscriptionIdentifier < 128) {
144+
buf.writeUInt8(SubscriptionIdentifier, offset++);
145+
} else if (SubscriptionIdentifier < 16_384) {
146+
buf.writeUInt16LE(((SubscriptionIdentifier & 0b011111110000000) << 1) | (0b10000000 | (SubscriptionIdentifier & 0b01111111)), offset);
147+
offset += 2;
148+
} else if (SubscriptionIdentifier < 2_097_152) {
149+
buf.writeUInt16LE(((0b100000000000000 | (SubscriptionIdentifier & 0b011111110000000)) << 1) | (0b10000000 | (SubscriptionIdentifier & 0b01111111)), offset);
150+
offset += 2;
151+
buf.writeUInt8((SubscriptionIdentifier >> 14) & 0b01111111, offset);
152+
offset += 1;
153+
} else {
154+
buf.writeUInt32LE((((((SubscriptionIdentifier >> 21) & 0b01111111) << 8) | (0b10000000 | ((SubscriptionIdentifier >> 14) & 0b01111111))) << 16) |
155+
((0b100000000000000 | (SubscriptionIdentifier & 0b011111110000000)) << 1) | (0b10000000 | (SubscriptionIdentifier & 0b01111111)), offset);
156+
offset += 4;
157+
}
158+
}
159+
160+
// Binary data
161+
if (CorrelationData) {
162+
const len = CorrelationData.length;
163+
buf.writeUInt8(PROPERTY.CorrelationData, offset++);
164+
buf.writeUInt16BE(len, offset);
165+
offset += 2;
166+
CorrelationData.copy(buf, offset);
167+
offset += len;
168+
}
169+
if (AuthenticationData) {
170+
const len = AuthenticationData.length;
171+
buf.writeUInt8(PROPERTY.AuthenticationData, offset++);
172+
buf.writeUInt16BE(len, offset);
173+
offset += 2;
174+
AuthenticationData.copy(buf, offset);
175+
offset += len;
176+
}
177+
178+
// Strings
179+
if (ContentType !== undefined) {
180+
const lenContentType: number = Buffer.byteLength(ContentType);
181+
buf.writeUInt8(PROPERTY.ContentType, offset++);
182+
buf.writeUInt16BE(lenContentType, offset);
183+
offset += 2;
184+
buf.write(ContentType, offset);
185+
offset += lenContentType;
186+
}
187+
if (ResponseTopic !== undefined) {
188+
const lenResponseTopic: number = Buffer.byteLength(ResponseTopic);
189+
buf.writeUInt8(PROPERTY.ResponseTopic, offset++);
190+
buf.writeUInt16BE(lenResponseTopic, offset);
191+
offset += 2;
192+
buf.write(ResponseTopic, offset);
193+
offset += lenResponseTopic;
194+
}
195+
if (AssignedClientIdentifier !== undefined) {
196+
const lenAssignedClientIdentifier: number = Buffer.byteLength(AssignedClientIdentifier);
197+
buf.writeUInt8(PROPERTY.AssignedClientIdentifier, offset++);
198+
buf.writeUInt16BE(lenAssignedClientIdentifier, offset);
199+
offset += 2;
200+
buf.write(AssignedClientIdentifier, offset);
201+
offset += lenAssignedClientIdentifier;
202+
}
203+
if (AuthenticationMethod !== undefined) {
204+
const lenAuthenticationMethod: number = Buffer.byteLength(AuthenticationMethod);
205+
buf.writeUInt8(PROPERTY.AuthenticationMethod, offset++);
206+
buf.writeUInt16BE(lenAuthenticationMethod, offset);
207+
offset += 2;
208+
buf.write(AuthenticationMethod, offset);
209+
offset += lenAuthenticationMethod;
210+
}
211+
if (ResponseInformation !== undefined) {
212+
const lenResponseInformation: number = Buffer.byteLength(ResponseInformation);
213+
buf.writeUInt8(PROPERTY.ResponseInformation, offset++);
214+
buf.writeUInt16BE(lenResponseInformation, offset);
215+
offset += 2;
216+
buf.write(ResponseInformation, offset);
217+
offset += lenResponseInformation;
218+
}
219+
if (ServerReference !== undefined) {
220+
const lenServerReference: number = Buffer.byteLength(ServerReference);
221+
buf.writeUInt8(PROPERTY.ServerReference, offset++);
222+
buf.writeUInt16BE(lenServerReference, offset);
223+
offset += 2;
224+
buf.write(ServerReference, offset);
225+
offset += lenServerReference;
226+
}
227+
if (ReasonString !== undefined) {
228+
const lenReasonString: number = Buffer.byteLength(ReasonString);
229+
buf.writeUInt8(PROPERTY.ReasonString, offset++);
230+
buf.writeUInt16BE(lenReasonString, offset);
231+
offset += 2;
232+
buf.write(ReasonString, offset);
233+
offset += lenReasonString;
234+
}
235+
236+
if (UserProperty) {
237+
const len = UserProperty.length;
238+
for (let i = 0; i < len; i++) {
239+
const k = UserProperty[i][0];
240+
const v = UserProperty[i][1];
241+
const kLen = Buffer.byteLength(k);
242+
const vLen = Buffer.byteLength(v);
243+
buf.writeUInt8(PROPERTY.UserProperty, offset++);
244+
buf.writeUInt16BE(kLen, offset);
245+
offset += 2;
246+
buf.write(k + '__' + v, offset);
247+
offset += kLen;
248+
buf.writeUInt16BE(vLen, offset);
249+
offset += 2 + vLen;
250+
}
251+
}
252+
253+
return buf;
254+
};

0 commit comments

Comments
 (0)