jspurefix 5.9.1 → 5.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/BACKPORT_PLAN.md +20 -7
  2. package/WORKLOG.md +119 -0
  3. package/dist/benchmark/bench-report.d.ts +5 -0
  4. package/dist/benchmark/bench-report.js +91 -0
  5. package/dist/benchmark/bench-report.js.map +1 -0
  6. package/dist/benchmark/bench-runner.d.ts +12 -0
  7. package/dist/benchmark/bench-runner.js +193 -0
  8. package/dist/benchmark/bench-runner.js.map +1 -0
  9. package/dist/benchmark/bench-stats.d.ts +10 -0
  10. package/dist/benchmark/bench-stats.js +56 -0
  11. package/dist/benchmark/bench-stats.js.map +1 -0
  12. package/dist/benchmark/bench-types.d.ts +74 -0
  13. package/dist/benchmark/bench-types.js +3 -0
  14. package/dist/benchmark/bench-types.js.map +1 -0
  15. package/dist/benchmark/gc-probe.d.ts +18 -0
  16. package/dist/benchmark/gc-probe.js +103 -0
  17. package/dist/benchmark/gc-probe.js.map +1 -0
  18. package/dist/benchmark/index.d.ts +6 -0
  19. package/dist/benchmark/index.js +23 -0
  20. package/dist/benchmark/index.js.map +1 -0
  21. package/dist/benchmark/parse-bench.d.ts +28 -0
  22. package/dist/benchmark/parse-bench.js +85 -0
  23. package/dist/benchmark/parse-bench.js.map +1 -0
  24. package/dist/buffer/ascii/ascii-parser.d.ts +1 -0
  25. package/dist/buffer/ascii/ascii-parser.js +4 -1
  26. package/dist/buffer/ascii/ascii-parser.js.map +1 -1
  27. package/dist/buffer/ascii/ascii-segment-parser.js +3 -2
  28. package/dist/buffer/ascii/ascii-segment-parser.js.map +1 -1
  29. package/dist/buffer/ascii/tag-index.js.map +1 -1
  30. package/dist/buffer/msg-view.d.ts +1 -0
  31. package/dist/buffer/msg-view.js +25 -19
  32. package/dist/buffer/msg-view.js.map +1 -1
  33. package/dist/dictionary/parser/quickfix/dictionary-validator.d.ts +1 -1
  34. package/dist/dictionary/parser/quickfix/dictionary-validator.js.map +1 -1
  35. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.d.ts +1 -1
  36. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js +1 -2
  37. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js.map +1 -1
  38. package/dist/dictionary/parser/quickfix/validation-error.d.ts +2 -2
  39. package/dist/dictionary/parser/quickfix/validation-error.js.map +1 -1
  40. package/dist/jsfix-bench.d.ts +1 -0
  41. package/dist/jsfix-bench.js +213 -0
  42. package/dist/jsfix-bench.js.map +1 -0
  43. package/dist/store/file-session-store.js +1 -1
  44. package/dist/store/file-session-store.js.map +1 -1
  45. package/dist/store/file-session-stream-provider.d.ts +1 -0
  46. package/dist/store/file-session-stream-provider.js +13 -13
  47. package/dist/store/file-session-stream-provider.js.map +1 -1
  48. package/dist/store/fix-session-store-factory.d.ts +1 -1
  49. package/dist/store/fix-session-store-factory.js.map +1 -1
  50. package/dist/store/fix-session-store.d.ts +11 -11
  51. package/dist/store/fix-session-store.js.map +1 -1
  52. package/dist/store/memory-session-store.js.map +1 -1
  53. package/dist/store/session-stream-provider.d.ts +13 -13
  54. package/dist/store/session-stream-provider.js.map +1 -1
  55. package/dist/transport/session/fix-clock.d.ts +1 -1
  56. package/dist/transport/session/fix-clock.js.map +1 -1
  57. package/dist/transport/session/resend-request-manager.d.ts +2 -2
  58. package/dist/transport/session/resend-request-manager.js.map +1 -1
  59. package/dist/transport/session/session-sequence-coordinator.d.ts +1 -1
  60. package/dist/transport/session/session-sequence-coordinator.js.map +1 -1
  61. package/dist/transport/session/session-sequence-store.d.ts +3 -3
  62. package/dist/transport/session/session-sequence-store.js.map +1 -1
  63. package/dist/transport/tcp/tcp-initiator.js.map +1 -1
  64. package/docs/benchmarking.md +117 -0
  65. package/eslint.config.mjs +15 -1
  66. package/jsfix.test_client.txt +62 -62
  67. package/jsfix.test_server.txt +72 -72
  68. package/package.json +9 -1
  69. package/src/benchmark/bench-report.ts +101 -0
  70. package/src/benchmark/bench-runner.ts +196 -0
  71. package/src/benchmark/bench-stats.ts +86 -0
  72. package/src/benchmark/bench-types.ts +110 -0
  73. package/src/benchmark/gc-probe.ts +145 -0
  74. package/src/benchmark/index.ts +6 -0
  75. package/src/benchmark/parse-bench.ts +144 -0
  76. package/src/buffer/ascii/ascii-parser.ts +16 -1
  77. package/src/buffer/ascii/ascii-segment-parser.ts +9 -6
  78. package/src/buffer/ascii/tag-index.ts +3 -3
  79. package/src/buffer/msg-view.ts +35 -18
  80. package/src/dictionary/parser/quickfix/dictionary-validator.ts +1 -1
  81. package/src/dictionary/parser/quickfix/quick-fix-graph-parser.ts +2 -3
  82. package/src/dictionary/parser/quickfix/validation-error.ts +1 -1
  83. package/src/jsfix-bench.ts +204 -0
  84. package/src/store/file-session-store.ts +2 -2
  85. package/src/store/file-session-stream-provider.ts +17 -11
  86. package/src/store/fix-session-store-factory.ts +1 -1
  87. package/src/store/fix-session-store.ts +11 -11
  88. package/src/store/memory-session-store.ts +1 -1
  89. package/src/store/session-stream-provider.ts +13 -13
  90. package/src/transport/session/fix-clock.ts +1 -1
  91. package/src/transport/session/resend-request-manager.ts +4 -4
  92. package/src/transport/session/session-sequence-coordinator.ts +1 -1
  93. package/src/transport/session/session-sequence-store.ts +3 -3
  94. package/src/transport/tcp/tcp-initiator.ts +1 -1
@@ -0,0 +1,74 @@
1
+ export interface IBenchCase {
2
+ readonly name: string;
3
+ readonly description?: string;
4
+ setup?: () => void;
5
+ run: (operations: number) => number;
6
+ teardown?: () => void;
7
+ }
8
+ export interface IBenchOptions {
9
+ readonly warmupOperations: number;
10
+ readonly rounds: number;
11
+ readonly operationsPerRound: number;
12
+ readonly gcBetweenRounds: boolean;
13
+ }
14
+ export interface ISampleStats {
15
+ readonly samples: number;
16
+ readonly min: number;
17
+ readonly max: number;
18
+ readonly mean: number;
19
+ readonly median: number;
20
+ readonly p95: number;
21
+ readonly p99: number;
22
+ readonly stdDev: number;
23
+ readonly coefficientOfVariation: number;
24
+ }
25
+ export interface IGcTotals {
26
+ readonly minor: number;
27
+ readonly major: number;
28
+ readonly incremental: number;
29
+ readonly weakCallback: number;
30
+ readonly total: number;
31
+ readonly totalPauseMs: number;
32
+ readonly longestPauseMs: number;
33
+ }
34
+ export interface IMemoryResult {
35
+ readonly operations: number;
36
+ readonly retainedHeapBytes: number;
37
+ readonly retainedBytesPerOperation: number;
38
+ readonly heapAtEndOfPassBytes: number;
39
+ readonly gc: IGcTotals;
40
+ readonly minorGcPerMillionOperations: number;
41
+ readonly majorGcPerMillionOperations: number;
42
+ readonly gcPauseMsPerMillionOperations: number;
43
+ readonly forcedGcAvailable: boolean;
44
+ }
45
+ export interface IRoundResult {
46
+ readonly round: number;
47
+ readonly operations: number;
48
+ readonly elapsedNanos: number;
49
+ readonly nanosPerOperation: number;
50
+ }
51
+ export interface IEnvironment {
52
+ readonly node: string;
53
+ readonly v8: string;
54
+ readonly platform: string;
55
+ readonly arch: string;
56
+ readonly cpu: string;
57
+ readonly cpuCount: number;
58
+ readonly forcedGcAvailable: boolean;
59
+ }
60
+ export interface IBenchResult {
61
+ readonly name: string;
62
+ readonly description?: string;
63
+ readonly options: IBenchOptions;
64
+ readonly rounds: IRoundResult[];
65
+ readonly timing: ISampleStats;
66
+ readonly operationsPerSecond: number;
67
+ readonly memory: IMemoryResult;
68
+ }
69
+ export interface IBenchSuiteResult {
70
+ readonly label: string;
71
+ readonly capturedAt: string;
72
+ readonly environment: IEnvironment;
73
+ readonly results: IBenchResult[];
74
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=bench-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bench-types.js","sourceRoot":"","sources":["../../src/benchmark/bench-types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A unit of work the runner can drive. run is handed the number of operations\n * to perform and returns how many it actually completed, which the runner\n * checks - a case that silently does less work than asked would otherwise look\n * like a large improvement.\n */\nexport interface IBenchCase {\n readonly name: string\n readonly description?: string\n /** called once before warmup, outside all timing */\n setup?: () => void\n run: (operations: number) => number\n teardown?: () => void\n}\n\nexport interface IBenchOptions {\n /** operations run and discarded before measuring, to let v8 tier the code up */\n readonly warmupOperations: number\n /** measured rounds - each contributes one sample */\n readonly rounds: number\n readonly operationsPerRound: number\n /** collect between rounds so one round's garbage is not charged to the next */\n readonly gcBetweenRounds: boolean\n}\n\nexport interface ISampleStats {\n readonly samples: number\n readonly min: number\n readonly max: number\n readonly mean: number\n readonly median: number\n readonly p95: number\n readonly p99: number\n readonly stdDev: number\n /** stdDev as a fraction of the mean - the run to run noise floor */\n readonly coefficientOfVariation: number\n}\n\nexport interface IGcTotals {\n readonly minor: number\n readonly major: number\n readonly incremental: number\n readonly weakCallback: number\n readonly total: number\n readonly totalPauseMs: number\n readonly longestPauseMs: number\n}\n\nexport interface IMemoryResult {\n /** operations in the diagnostics pass these figures were taken over */\n readonly operations: number\n /**\n * heapUsed after a forced collection, less the same reading taken before the\n * measured rounds - what the work left behind rather than what it churned\n */\n readonly retainedHeapBytes: number\n readonly retainedBytesPerOperation: number\n /**\n * heapUsed sampled the instant the pass finished. Not a high water mark -\n * it is wherever the sawtooth happened to be - so read it as a rough sense of\n * the working set, not as a peak.\n */\n readonly heapAtEndOfPassBytes: number\n readonly gc: IGcTotals\n /**\n * collections per million operations. allocation volume is not directly\n * observable from node, so this is the comparable proxy for it - the same\n * work triggering fewer scavenges is the same work allocating less.\n */\n readonly minorGcPerMillionOperations: number\n readonly majorGcPerMillionOperations: number\n readonly gcPauseMsPerMillionOperations: number\n /** false when the process was started without --expose-gc */\n readonly forcedGcAvailable: boolean\n}\n\nexport interface IRoundResult {\n readonly round: number\n readonly operations: number\n readonly elapsedNanos: number\n readonly nanosPerOperation: number\n}\n\nexport interface IEnvironment {\n readonly node: string\n readonly v8: string\n readonly platform: string\n readonly arch: string\n readonly cpu: string\n readonly cpuCount: number\n readonly forcedGcAvailable: boolean\n}\n\nexport interface IBenchResult {\n readonly name: string\n readonly description?: string\n readonly options: IBenchOptions\n readonly rounds: IRoundResult[]\n /** statistics over the per round nanosPerOperation samples */\n readonly timing: ISampleStats\n readonly operationsPerSecond: number\n readonly memory: IMemoryResult\n}\n\nexport interface IBenchSuiteResult {\n readonly label: string\n readonly capturedAt: string\n readonly environment: IEnvironment\n readonly results: IBenchResult[]\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { IGcTotals } from './bench-types';
2
+ export declare class GcProbe {
3
+ private observer;
4
+ private minor;
5
+ private major;
6
+ private incremental;
7
+ private weakCallback;
8
+ private totalPauseMs;
9
+ private longestPauseMs;
10
+ static forcedGcAvailable(): boolean;
11
+ static forceGc(): void;
12
+ seen(): number;
13
+ start(): void;
14
+ stop(): IGcTotals;
15
+ private reset;
16
+ private record;
17
+ private totals;
18
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GcProbe = void 0;
4
+ const perf_hooks_1 = require("perf_hooks");
5
+ const emptyTotals = {
6
+ minor: 0,
7
+ major: 0,
8
+ incremental: 0,
9
+ weakCallback: 0,
10
+ total: 0,
11
+ totalPauseMs: 0,
12
+ longestPauseMs: 0
13
+ };
14
+ class GcProbe {
15
+ constructor() {
16
+ this.observer = null;
17
+ this.minor = 0;
18
+ this.major = 0;
19
+ this.incremental = 0;
20
+ this.weakCallback = 0;
21
+ this.totalPauseMs = 0;
22
+ this.longestPauseMs = 0;
23
+ }
24
+ static forcedGcAvailable() {
25
+ return typeof global.gc === 'function';
26
+ }
27
+ static forceGc() {
28
+ const gc = global.gc;
29
+ if (typeof gc !== 'function')
30
+ return;
31
+ gc();
32
+ gc();
33
+ }
34
+ seen() {
35
+ return this.minor + this.major + this.incremental + this.weakCallback;
36
+ }
37
+ start() {
38
+ this.reset();
39
+ const observer = new perf_hooks_1.PerformanceObserver((list) => {
40
+ var _a, _b;
41
+ for (const entry of list.getEntries()) {
42
+ const gcEntry = entry;
43
+ this.record(gcEntry.duration, (_b = (_a = gcEntry.detail) === null || _a === void 0 ? void 0 : _a.kind) !== null && _b !== void 0 ? _b : 0);
44
+ }
45
+ });
46
+ observer.observe({ entryTypes: ['gc'], buffered: true });
47
+ this.observer = observer;
48
+ }
49
+ stop() {
50
+ var _a, _b;
51
+ const observer = this.observer;
52
+ if (!observer)
53
+ return emptyTotals;
54
+ for (const entry of observer.takeRecords()) {
55
+ const gcEntry = entry;
56
+ this.record(gcEntry.duration, (_b = (_a = gcEntry.detail) === null || _a === void 0 ? void 0 : _a.kind) !== null && _b !== void 0 ? _b : 0);
57
+ }
58
+ observer.disconnect();
59
+ this.observer = null;
60
+ return this.totals();
61
+ }
62
+ reset() {
63
+ this.minor = 0;
64
+ this.major = 0;
65
+ this.incremental = 0;
66
+ this.weakCallback = 0;
67
+ this.totalPauseMs = 0;
68
+ this.longestPauseMs = 0;
69
+ }
70
+ record(durationMs, kind) {
71
+ this.totalPauseMs += durationMs;
72
+ this.longestPauseMs = Math.max(this.longestPauseMs, durationMs);
73
+ switch (kind) {
74
+ case perf_hooks_1.constants.NODE_PERFORMANCE_GC_MINOR:
75
+ ++this.minor;
76
+ break;
77
+ case perf_hooks_1.constants.NODE_PERFORMANCE_GC_MAJOR:
78
+ ++this.major;
79
+ break;
80
+ case perf_hooks_1.constants.NODE_PERFORMANCE_GC_INCREMENTAL:
81
+ ++this.incremental;
82
+ break;
83
+ case perf_hooks_1.constants.NODE_PERFORMANCE_GC_WEAKCB:
84
+ ++this.weakCallback;
85
+ break;
86
+ default:
87
+ break;
88
+ }
89
+ }
90
+ totals() {
91
+ return {
92
+ minor: this.minor,
93
+ major: this.major,
94
+ incremental: this.incremental,
95
+ weakCallback: this.weakCallback,
96
+ total: this.minor + this.major + this.incremental + this.weakCallback,
97
+ totalPauseMs: this.totalPauseMs,
98
+ longestPauseMs: this.longestPauseMs
99
+ };
100
+ }
101
+ }
102
+ exports.GcProbe = GcProbe;
103
+ //# sourceMappingURL=gc-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc-probe.js","sourceRoot":"","sources":["../../src/benchmark/gc-probe.ts"],"names":[],"mappings":"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","sourcesContent":["import { PerformanceObserver, constants } from 'perf_hooks'\nimport { IGcTotals } from './bench-types'\n\ninterface IGcDetail {\n kind: number\n flags: number\n}\n\n/**\n * a gc performance entry. detail is not on the PerformanceEntry the node types\n * describe, it is only present on entries of this type\n */\ninterface IGcEntry {\n duration: number\n detail?: IGcDetail\n}\n\nconst emptyTotals: IGcTotals = {\n minor: 0,\n major: 0,\n incremental: 0,\n weakCallback: 0,\n total: 0,\n totalPauseMs: 0,\n longestPauseMs: 0\n}\n\n/**\n * Counts collections and the pause they cost while a benchmark runs.\n *\n * Node does not expose how many bytes a stretch of code allocated, so the\n * number of scavenges is the practical stand in - the same work provoking\n * fewer minor collections is the same work producing less garbage, and that\n * is the number worth moving for a drop copy engine where the cost of\n * allocation is felt as pause rather than as throughput.\n */\nexport class GcProbe {\n private observer: PerformanceObserver | null = null\n private minor: number = 0\n private major: number = 0\n private incremental: number = 0\n private weakCallback: number = 0\n private totalPauseMs: number = 0\n private longestPauseMs: number = 0\n\n /** whether the process was started with --expose-gc */\n public static forcedGcAvailable (): boolean {\n return typeof global.gc === 'function'\n }\n\n /**\n * Collect until the heap settles, so a reading taken afterwards reflects what\n * is genuinely retained. Two passes because the first can promote survivors\n * into the old space that the second is then able to reclaim. A no-op without\n * --expose-gc, in which case retained figures are indicative only.\n */\n public static forceGc (): void {\n const gc = global.gc\n if (typeof gc !== 'function') return\n gc()\n gc()\n }\n\n /** entries recorded so far - lets a caller wait for delivery to go quiet */\n public seen (): number {\n return this.minor + this.major + this.incremental + this.weakCallback\n }\n\n public start (): void {\n this.reset()\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n const gcEntry = entry as unknown as IGcEntry\n this.record(gcEntry.duration, gcEntry.detail?.kind ?? 0)\n }\n })\n // buffered so collections are not missed while the loop is busy - the\n // callback cannot run until the measured work yields\n observer.observe({ entryTypes: ['gc'], buffered: true })\n this.observer = observer\n }\n\n /**\n * Stop observing and return what was seen. Any entries still queued are\n * drained first - the observer callback is a macrotask and the benchmark\n * loop never yields, so without this every collection would be lost.\n */\n public stop (): IGcTotals {\n const observer = this.observer\n if (!observer) return emptyTotals\n for (const entry of observer.takeRecords()) {\n const gcEntry = entry as unknown as IGcEntry\n this.record(gcEntry.duration, gcEntry.detail?.kind ?? 0)\n }\n observer.disconnect()\n this.observer = null\n return this.totals()\n }\n\n private reset (): void {\n this.minor = 0\n this.major = 0\n this.incremental = 0\n this.weakCallback = 0\n this.totalPauseMs = 0\n this.longestPauseMs = 0\n }\n\n private record (durationMs: number, kind: number): void {\n this.totalPauseMs += durationMs\n this.longestPauseMs = Math.max(this.longestPauseMs, durationMs)\n switch (kind) {\n case constants.NODE_PERFORMANCE_GC_MINOR:\n ++this.minor\n break\n\n case constants.NODE_PERFORMANCE_GC_MAJOR:\n ++this.major\n break\n\n case constants.NODE_PERFORMANCE_GC_INCREMENTAL:\n ++this.incremental\n break\n\n case constants.NODE_PERFORMANCE_GC_WEAKCB:\n ++this.weakCallback\n break\n\n default:\n break\n }\n }\n\n private totals (): IGcTotals {\n return {\n minor: this.minor,\n major: this.major,\n incremental: this.incremental,\n weakCallback: this.weakCallback,\n total: this.minor + this.major + this.incremental + this.weakCallback,\n totalPauseMs: this.totalPauseMs,\n longestPauseMs: this.longestPauseMs\n }\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export * from './bench-types';
2
+ export * from './bench-stats';
3
+ export * from './bench-runner';
4
+ export * from './bench-report';
5
+ export * from './gc-probe';
6
+ export * from './parse-bench';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./bench-types"), exports);
18
+ __exportStar(require("./bench-stats"), exports);
19
+ __exportStar(require("./bench-runner"), exports);
20
+ __exportStar(require("./bench-report"), exports);
21
+ __exportStar(require("./gc-probe"), exports);
22
+ __exportStar(require("./parse-bench"), exports);
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/benchmark/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA6B;AAC7B,gDAA6B;AAC7B,iDAA8B;AAC9B,iDAA8B;AAC9B,6CAA0B;AAC1B,gDAA6B","sourcesContent":["export * from './bench-types'\nexport * from './bench-stats'\nexport * from './bench-runner'\nexport * from './bench-report'\nexport * from './gc-probe'\nexport * from './parse-bench'\n"]}
@@ -0,0 +1,28 @@
1
+ import { IJsFixConfig } from '../config/js-fix-config';
2
+ import { IBenchCase } from './bench-types';
3
+ export declare enum ParseDepth {
4
+ View = "view",
5
+ Object = "object"
6
+ }
7
+ export interface IParseCaseOptions {
8
+ readonly config: IJsFixConfig;
9
+ readonly contents: string;
10
+ readonly depth: ParseDepth;
11
+ }
12
+ export declare class ParseCase implements IBenchCase {
13
+ readonly name: string;
14
+ readonly description: string;
15
+ readonly operationsPerInvocation: number;
16
+ private readonly source;
17
+ private readonly depth;
18
+ private readonly options;
19
+ private parser;
20
+ private decoded;
21
+ constructor(name: string, options: IParseCaseOptions);
22
+ alignOperations(requested: number): number;
23
+ setup(): void;
24
+ teardown(): void;
25
+ run(operations: number): number;
26
+ private makeParser;
27
+ private countMessages;
28
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ParseCase = exports.ParseDepth = void 0;
4
+ const ascii_parser_1 = require("../buffer/ascii/ascii-parser");
5
+ const di_tokens_1 = require("../runtime/di-tokens");
6
+ const session_scope_1 = require("../runtime/session-scope");
7
+ var ParseDepth;
8
+ (function (ParseDepth) {
9
+ ParseDepth["View"] = "view";
10
+ ParseDepth["Object"] = "object";
11
+ })(ParseDepth || (exports.ParseDepth = ParseDepth = {}));
12
+ class ParseCase {
13
+ constructor(name, options) {
14
+ this.parser = null;
15
+ this.decoded = 0;
16
+ this.name = name;
17
+ this.options = options;
18
+ this.depth = options.depth;
19
+ this.source = Buffer.from(options.contents);
20
+ this.description = options.depth === ParseDepth.Object
21
+ ? 'tokenise, discover structure, build view, materialise object'
22
+ : 'tokenise, discover structure, build view';
23
+ this.operationsPerInvocation = this.countMessages();
24
+ if (this.operationsPerInvocation === 0) {
25
+ throw new Error(`${name}: input yielded no messages, check the dictionary and the delimiter`);
26
+ }
27
+ }
28
+ alignOperations(requested) {
29
+ const per = this.operationsPerInvocation;
30
+ return Math.max(per, Math.ceil(requested / per) * per);
31
+ }
32
+ setup() {
33
+ this.parser = this.makeParser(true);
34
+ }
35
+ teardown() {
36
+ var _a;
37
+ (_a = this.parser) === null || _a === void 0 ? void 0 : _a.removeAllListeners();
38
+ this.parser = null;
39
+ }
40
+ run(operations) {
41
+ const parser = this.parser;
42
+ if (!parser) {
43
+ throw new Error(`${this.name}: run called before setup`);
44
+ }
45
+ const source = this.source;
46
+ const passes = operations / this.operationsPerInvocation;
47
+ if (!Number.isInteger(passes)) {
48
+ throw new Error(`${this.name}: ${operations} operations is not a whole number of passes over the input`);
49
+ }
50
+ this.decoded = 0;
51
+ for (let i = 0; i < passes; ++i) {
52
+ parser.parseBuffer(source);
53
+ }
54
+ return this.decoded;
55
+ }
56
+ makeParser(subscribe) {
57
+ const scoped = (0, session_scope_1.makeSessionScope)(this.options.config);
58
+ const container = scoped.sessionContainer;
59
+ const buffer = container.resolve(di_tokens_1.DITokens.ParseBuffer);
60
+ const maxMessageLen = container.resolve(di_tokens_1.DITokens.maxMessageLen);
61
+ const parser = new ascii_parser_1.AsciiParser(scoped, null, buffer, maxMessageLen);
62
+ const object = subscribe && this.depth === ParseDepth.Object;
63
+ parser.on('msg', (_, view) => {
64
+ ++this.decoded;
65
+ if (object) {
66
+ const materialised = view.toObject();
67
+ if (materialised === null) {
68
+ throw new Error('view produced no object');
69
+ }
70
+ }
71
+ });
72
+ return parser;
73
+ }
74
+ countMessages() {
75
+ const parser = this.makeParser(false);
76
+ this.decoded = 0;
77
+ parser.parseBuffer(this.source);
78
+ parser.removeAllListeners();
79
+ const count = this.decoded;
80
+ this.decoded = 0;
81
+ return count;
82
+ }
83
+ }
84
+ exports.ParseCase = ParseCase;
85
+ //# sourceMappingURL=parse-bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-bench.js","sourceRoot":"","sources":["../../src/benchmark/parse-bench.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsciiParser } from '../buffer/ascii/ascii-parser'\nimport { ElasticBuffer } from '../buffer/elastic-buffer'\nimport { MsgView } from '../buffer/msg-view'\nimport { IJsFixConfig } from '../config/js-fix-config'\nimport { DITokens } from '../runtime/di-tokens'\nimport { makeSessionScope } from '../runtime/session-scope'\nimport { IBenchCase } from './bench-types'\n\n/**\n * what a decoded message is taken through once the parser has produced a view\n */\nexport enum ParseDepth {\n /** stop at the MsgView - tokenise, discover the structure, build the view */\n View = 'view',\n /** materialise the whole object graph, which is what most consumers do */\n Object = 'object'\n}\n\nexport interface IParseCaseOptions {\n readonly config: IJsFixConfig\n /** the raw text of a fix log, one or more complete messages */\n readonly contents: string\n readonly depth: ParseDepth\n}\n\n/**\n * Drives fix bytes through the real parser and counts messages out of it.\n *\n * The bytes are fed as one buffer per invocation, the same way a socket read\n * reaches parse, rather than by concatenating the file thousands of times into\n * one enormous string. That concatenation is itself a large allocation, and\n * doing it before the timer starts leaves a heap that no memory reading taken\n * afterwards can be trusted through.\n */\nexport class ParseCase implements IBenchCase {\n public readonly name: string\n public readonly description: string\n /** messages produced by one pass over the input */\n public readonly operationsPerInvocation: number\n\n private readonly source: Buffer\n private readonly depth: ParseDepth\n private readonly options: IParseCaseOptions\n private parser: AsciiParser | null = null\n private decoded: number = 0\n\n constructor (name: string, options: IParseCaseOptions) {\n this.name = name\n this.options = options\n this.depth = options.depth\n this.source = Buffer.from(options.contents)\n this.description = options.depth === ParseDepth.Object\n ? 'tokenise, discover structure, build view, materialise object'\n : 'tokenise, discover structure, build view'\n this.operationsPerInvocation = this.countMessages()\n if (this.operationsPerInvocation === 0) {\n throw new Error(`${name}: input yielded no messages, check the dictionary and the delimiter`)\n }\n }\n\n /**\n * Round a requested round size up to a whole number of passes over the input.\n * A pass cannot be stopped part way, so asking for a count that is not a\n * multiple of it would silently measure more work than it reported.\n */\n public alignOperations (requested: number): number {\n const per = this.operationsPerInvocation\n return Math.max(per, Math.ceil(requested / per) * per)\n }\n\n public setup (): void {\n this.parser = this.makeParser(true)\n }\n\n public teardown (): void {\n this.parser?.removeAllListeners()\n this.parser = null\n }\n\n public run (operations: number): number {\n const parser = this.parser\n if (!parser) {\n throw new Error(`${this.name}: run called before setup`)\n }\n const source = this.source\n const passes = operations / this.operationsPerInvocation\n if (!Number.isInteger(passes)) {\n throw new Error(`${this.name}: ${operations} operations is not a whole number of passes over the input`)\n }\n this.decoded = 0\n for (let i = 0; i < passes; ++i) {\n parser.parseBuffer(source)\n }\n return this.decoded\n }\n\n /**\n * A parser on a session scope of its own.\n *\n * It has to be a scope rather than a hand built AsciiParser: AsciiParserState\n * takes the ParseBuffer from the container, so a parser handed some other\n * buffer writes bytes the state never reads and the parse walks off into\n * nonsense. The scope re-registers the buffer and hands the same instance to\n * both, which is the same thing an accepted connection gets.\n */\n private makeParser (subscribe: boolean): AsciiParser {\n const scoped = makeSessionScope(this.options.config)\n const container = scoped.sessionContainer\n // constructed rather than resolved: DITokens.readStream has no registration\n // outside a live transport, and there is no stream here - the harness hands\n // the parser its bytes. Everything else comes from the scope, so the buffer\n // below is the same instance AsciiParserState will be injected with.\n const buffer = container.resolve<ElasticBuffer>(DITokens.ParseBuffer)\n const maxMessageLen = container.resolve<number>(DITokens.maxMessageLen)\n const parser = new AsciiParser(scoped, null, buffer, maxMessageLen)\n const object = subscribe && this.depth === ParseDepth.Object\n parser.on('msg', (_: string, view: MsgView) => {\n ++this.decoded\n if (object) {\n // read the result back so the materialisation cannot be treated as\n // dead and folded away\n const materialised = view.toObject()\n if (materialised === null) {\n throw new Error('view produced no object')\n }\n }\n })\n return parser\n }\n\n /**\n * How many messages one pass over the input yields. Counted on a throwaway\n * parser during construction so the measured run never has to ask.\n */\n private countMessages (): number {\n const parser = this.makeParser(false)\n this.decoded = 0\n parser.parseBuffer(this.source)\n parser.removeAllListeners()\n const count = this.decoded\n this.decoded = 0\n return count\n }\n}\n"]}
@@ -19,6 +19,7 @@ export declare class AsciiParser extends MsgParser {
19
19
  reset(): void;
20
20
  private msg;
21
21
  parseText(text: string): void;
22
+ parseBuffer(buff: Buffer, end?: number): void;
22
23
  private parse;
23
24
  private getView;
24
25
  }
@@ -41,7 +41,7 @@ let AsciiParser = AsciiParser_1 = class AsciiParser extends msg_parser_1.MsgPars
41
41
  this.id = AsciiParser_1.nextId++;
42
42
  this.segmentParser = config.sessionContainer.resolve(ascii_segment_parser_1.AsciiSegmentParser);
43
43
  this.state = config.sessionContainer.resolve(ascii_parser_state_1.AsciiParserState);
44
- this.state.locations = new tags_1.Tags(this.receivingBuffer.size / 10, this.maxMessageLen);
44
+ this.state.locations = new tags_1.Tags(Math.floor(this.receivingBuffer.size / 10), this.maxMessageLen);
45
45
  this.state.definitions = this.config.definitions;
46
46
  this.state.beginMessage();
47
47
  if (readStream !== null) {
@@ -92,6 +92,9 @@ let AsciiParser = AsciiParser_1 = class AsciiParser extends msg_parser_1.MsgPars
92
92
  const buff = Buffer.from(text);
93
93
  this.parse(buff, buff.length);
94
94
  }
95
+ parseBuffer(buff, end = buff.length) {
96
+ this.parse(buff, end);
97
+ }
95
98
  parse(readBuffer, end) {
96
99
  const state = this.state;
97
100
  const eq = ascii_chars_1.AsciiChars.Eq;
@@ -1 +1 @@
1
- {"version":3,"file":"ascii-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsciiChars } from './ascii-chars'\nimport { AsciiView } from './ascii-view'\nimport { AsciiSegmentParser } from './ascii-segment-parser'\nimport { AsciiParserState } from './ascii-parser-state'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport { MsgParser } from '../msg-parser'\nimport { MsgView } from '../msg-view'\nimport { Readable } from 'stream'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { SegmentDescription } from '../segment/segment-description'\nimport { ParseState } from './parse-state'\nimport { IJsFixConfig } from '../../config/js-fix-config'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\n\n@injectable()\nexport class AsciiParser extends MsgParser {\n private static nextId: number = 0\n public readonly id: number\n public readonly state: AsciiParserState\n private readonly segmentParser: AsciiSegmentParser\n public readonly delimiter: number\n public readonly writeDelimiter: number\n\n // allocate enough in receive buffer so buffer does not constant resize back after large messages\n // want to keep one slice of memory and constantly reuse it\n\n constructor (@inject(DITokens.IJsFixConfig) public readonly config: IJsFixConfig,\n @inject(DITokens.readStream) public readonly readStream: Readable | null,\n @inject(DITokens.ParseBuffer) protected readonly receivingBuffer: ElasticBuffer,\n @inject(DITokens.maxMessageLen) public readonly maxMessageLen: number = 160 * 1024) {\n super()\n\n this.delimiter = config.delimiter ?? AsciiChars.Soh\n this.writeDelimiter = config.logDelimiter ?? AsciiChars.Pipe\n this.id = AsciiParser.nextId++\n this.segmentParser = config.sessionContainer.resolve<AsciiSegmentParser>(AsciiSegmentParser)\n this.state = config.sessionContainer.resolve<AsciiParserState>(AsciiParserState)\n this.state.locations = new Tags(this.receivingBuffer.size / 10, this.maxMessageLen)\n this.state.definitions = this.config.definitions\n this.state.beginMessage()\n if (readStream !== null) {\n this.subscribe()\n }\n }\n\n private subscribe (): void {\n const inst: AsciiParser = this\n const Writable = require('stream').Writable\n const stream = this.readStream\n\n const receiver = new Writable({\n write: (data: Buffer, _: any, done: Function) => {\n try {\n inst.parse(data, data.length)\n done()\n } catch (e) {\n done(e)\n }\n }\n })\n receiver.on('error', (e: Error) => {\n this.emit('error', e)\n })\n\n // receive from say a socket or file and pipe to parser which discovers messages\n stream?.pipe(receiver).on('finish', () => {\n this.emit('done')\n })\n stream?.on('error', (e) => {\n this.emit('error', e)\n })\n stream?.on('end', () => {\n this.emit('end')\n })\n }\n\n public reset (): void {\n this.state.beginMessage()\n }\n\n private msg (ptr: number): void {\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const state = this.state\n if (this.listeners('decoded')) {\n this.emit('decoded', state.msgType, receivingBuffer, ptr)\n }\n this.emit('msg', state.msgType, this.getView(ptr))\n state.beginMessage()\n }\n\n /**\n * useful helper for testing where characters are parsed as if from the transport\n * @param text to be parsed\n */\n public parseText (text: string): void {\n const buff = Buffer.from(text)\n this.parse(buff, buff.length)\n }\n\n private parse (readBuffer: Buffer, end: number): void {\n const state = this.state\n const eq: number = AsciiChars.Eq\n const zero: number = AsciiChars.Zero\n const nine: number = AsciiChars.Nine\n const delimiter: number = this.delimiter\n const writeDelimiter: number = this.writeDelimiter\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const switchDelimiter = writeDelimiter !== delimiter\n let readPtr: number = 0\n\n while (readPtr < end) {\n const charAtPos: number = readBuffer[readPtr]\n\n const writePtr = receivingBuffer.saveChar(charAtPos) - 1\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(writePtr)\n continue\n }\n\n case ParseState.BeginField: {\n const atDigit: boolean = charAtPos >= zero && charAtPos <= nine\n if (atDigit) {\n state.beginTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingTag: {\n const isEquals: boolean = charAtPos === eq\n if (isEquals) {\n state.endTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingRawData: {\n // keep skipping until length read, regardless of delimiter or not\n if (state.incRaw()) {\n // having consumed the declared raw data length, expect delimiter.\n // if not found (e.g. replayed messages with pretty-printed XML where\n // the stored length undershoots), keep scanning forward to the actual\n // delimiter rather than throwing.\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n } else if (charAtPos === delimiter) {\n // hit delimiter before declared length exhausted — store what we have\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n case ParseState.ParsingRawDataLength:\n case ParseState.ParsingValue: {\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n default: {\n const st = state.parseState\n throw new Error(`fix parser in unknown state ${st}`)\n }\n }\n readPtr++\n }\n\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(receivingBuffer.getPos())\n break\n }\n }\n }\n\n private getView (ptr: number): MsgView | null {\n const state = this.state\n const locations = state.locations\n const source = this.receivingBuffer\n const delimiter = this.delimiter\n const definitions = this.config.definitions\n const replace = this.writeDelimiter\n const msgType = state.msgType ?? null\n if (!msgType) return null\n if (state.message) {\n try {\n const structure: Structure | null = this.segmentParser.parse(msgType, locations,\n locations.nextTagPos - 1)\n if (!structure) return null\n return new AsciiView(definitions, structure.msg(),\n source,\n structure,\n ptr,\n delimiter,\n replace)\n } catch (error) {\n if (error instanceof AsciiParserError) {\n error.summary.buffer = source.toString()\n this.emit('error', error)\n }\n throw error\n }\n }\n\n const structure = new Structure(locations, [])\n const segment = new SegmentDescription('unknown', locations.tagPos[0].tag, null, 0, 1, SegmentType.Unknown)\n segment.endPosition = locations.nextTagPos - 1\n return new AsciiView(this.config.definitions, segment, source, structure, ptr, delimiter, replace)\n }\n}\n"]}
1
+ {"version":3,"file":"ascii-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsciiChars } from './ascii-chars'\nimport { AsciiView } from './ascii-view'\nimport { AsciiSegmentParser } from './ascii-segment-parser'\nimport { AsciiParserState } from './ascii-parser-state'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport { MsgParser } from '../msg-parser'\nimport { MsgView } from '../msg-view'\nimport { Readable } from 'stream'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { SegmentDescription } from '../segment/segment-description'\nimport { ParseState } from './parse-state'\nimport { IJsFixConfig } from '../../config/js-fix-config'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\n\n@injectable()\nexport class AsciiParser extends MsgParser {\n private static nextId: number = 0\n public readonly id: number\n public readonly state: AsciiParserState\n private readonly segmentParser: AsciiSegmentParser\n public readonly delimiter: number\n public readonly writeDelimiter: number\n\n // allocate enough in receive buffer so buffer does not constant resize back after large messages\n // want to keep one slice of memory and constantly reuse it\n\n constructor (@inject(DITokens.IJsFixConfig) public readonly config: IJsFixConfig,\n @inject(DITokens.readStream) public readonly readStream: Readable | null,\n @inject(DITokens.ParseBuffer) protected readonly receivingBuffer: ElasticBuffer,\n @inject(DITokens.maxMessageLen) public readonly maxMessageLen: number = 160 * 1024) {\n super()\n\n this.delimiter = config.delimiter ?? AsciiChars.Soh\n this.writeDelimiter = config.logDelimiter ?? AsciiChars.Pipe\n this.id = AsciiParser.nextId++\n this.segmentParser = config.sessionContainer.resolve<AsciiSegmentParser>(AsciiSegmentParser)\n this.state = config.sessionContainer.resolve<AsciiParserState>(AsciiParserState)\n // floored - Tags hands the starting length to new Array, which rejects a\n // fraction, so any buffer size not divisible by 10 threw from here\n this.state.locations = new Tags(Math.floor(this.receivingBuffer.size / 10), this.maxMessageLen)\n this.state.definitions = this.config.definitions\n this.state.beginMessage()\n if (readStream !== null) {\n this.subscribe()\n }\n }\n\n private subscribe (): void {\n const inst: AsciiParser = this\n const Writable = require('stream').Writable\n const stream = this.readStream\n\n const receiver = new Writable({\n write: (data: Buffer, _: any, done: Function) => {\n try {\n inst.parse(data, data.length)\n done()\n } catch (e) {\n done(e)\n }\n }\n })\n receiver.on('error', (e: Error) => {\n this.emit('error', e)\n })\n\n // receive from say a socket or file and pipe to parser which discovers messages\n stream?.pipe(receiver).on('finish', () => {\n this.emit('done')\n })\n stream?.on('error', (e) => {\n this.emit('error', e)\n })\n stream?.on('end', () => {\n this.emit('end')\n })\n }\n\n public reset (): void {\n this.state.beginMessage()\n }\n\n private msg (ptr: number): void {\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const state = this.state\n if (this.listeners('decoded')) {\n this.emit('decoded', state.msgType, receivingBuffer, ptr)\n }\n this.emit('msg', state.msgType, this.getView(ptr))\n state.beginMessage()\n }\n\n /**\n * useful helper for testing where characters are parsed as if from the transport\n * @param text to be parsed\n */\n public parseText (text: string): void {\n const buff = Buffer.from(text)\n this.parse(buff, buff.length)\n }\n\n /**\n * feed bytes as though they had arrived from the transport. This is the path\n * the socket takes - subscribe hands each chunk it receives straight to parse -\n * so a caller driving the parser directly, a benchmark or a replay harness,\n * measures the real thing rather than a copy of it.\n *\n * @param buff bytes to parse\n * @param end how much of buff to consume, all of it by default\n */\n public parseBuffer (buff: Buffer, end: number = buff.length): void {\n this.parse(buff, end)\n }\n\n private parse (readBuffer: Buffer, end: number): void {\n const state = this.state\n const eq: number = AsciiChars.Eq\n const zero: number = AsciiChars.Zero\n const nine: number = AsciiChars.Nine\n const delimiter: number = this.delimiter\n const writeDelimiter: number = this.writeDelimiter\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const switchDelimiter = writeDelimiter !== delimiter\n let readPtr: number = 0\n\n while (readPtr < end) {\n const charAtPos: number = readBuffer[readPtr]\n\n const writePtr = receivingBuffer.saveChar(charAtPos) - 1\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(writePtr)\n continue\n }\n\n case ParseState.BeginField: {\n const atDigit: boolean = charAtPos >= zero && charAtPos <= nine\n if (atDigit) {\n state.beginTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingTag: {\n const isEquals: boolean = charAtPos === eq\n if (isEquals) {\n state.endTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingRawData: {\n // keep skipping until length read, regardless of delimiter or not\n if (state.incRaw()) {\n // having consumed the declared raw data length, expect delimiter.\n // if not found (e.g. replayed messages with pretty-printed XML where\n // the stored length undershoots), keep scanning forward to the actual\n // delimiter rather than throwing.\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n } else if (charAtPos === delimiter) {\n // hit delimiter before declared length exhausted — store what we have\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n case ParseState.ParsingRawDataLength:\n case ParseState.ParsingValue: {\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n default: {\n const st = state.parseState\n throw new Error(`fix parser in unknown state ${st}`)\n }\n }\n readPtr++\n }\n\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(receivingBuffer.getPos())\n break\n }\n }\n }\n\n private getView (ptr: number): MsgView | null {\n const state = this.state\n const locations = state.locations\n const source = this.receivingBuffer\n const delimiter = this.delimiter\n const definitions = this.config.definitions\n const replace = this.writeDelimiter\n const msgType = state.msgType ?? null\n if (!msgType) return null\n if (state.message) {\n try {\n const structure: Structure | null = this.segmentParser.parse(msgType, locations,\n locations.nextTagPos - 1)\n if (!structure) return null\n return new AsciiView(definitions, structure.msg(),\n source,\n structure,\n ptr,\n delimiter,\n replace)\n } catch (error) {\n if (error instanceof AsciiParserError) {\n error.summary.buffer = source.toString()\n this.emit('error', error)\n }\n throw error\n }\n }\n\n const structure = new Structure(locations, [])\n const segment = new SegmentDescription('unknown', locations.tagPos[0].tag, null, 0, 1, SegmentType.Unknown)\n segment.endPosition = locations.nextTagPos - 1\n return new AsciiView(this.config.definitions, segment, source, structure, ptr, delimiter, replace)\n }\n}\n"]}
@@ -28,10 +28,11 @@ let AsciiSegmentParser = class AsciiSegmentParser {
28
28
  }
29
29
  parse(msgType, tags, last) {
30
30
  const segments = [];
31
- const msgDefinition = this.definitions.message.get(msgType);
32
- if (!msgDefinition) {
31
+ const resolved = this.definitions.message.get(msgType);
32
+ if (!resolved) {
33
33
  return null;
34
34
  }
35
+ const msgDefinition = resolved;
35
36
  const structureStack = [];
36
37
  let currentTagPosition = 0;
37
38
  let peek;
@@ -1 +1 @@
1
- {"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\nimport { TagIndex } from './tag-index'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const msgDefinition: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!msgDefinition) {\n return null\n }\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // track depth-1 components that have been exited for fragmentation detection\n const exitedDepth1Components: Set<string> = new Set()\n const fragmentedComponents: Set<string> = new Set()\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n\n // track when we exit depth-1 components for fragmentation detection\n if (done.depth === 1 && done.name) {\n exitedDepth1Components.add(done.name)\n }\n\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n // detect fragmentation: re-entering a depth-1 component we already exited\n if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {\n fragmentedComponents.add(cf.name)\n }\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n function fragments (): void {\n // only build SegmentViews for components detected as fragmented during discover\n // non-fragmented components use their position ranges directly (zero overhead)\n if (fragmentedComponents.size === 0) return\n const ti = new TagIndex(msgDefinition!, tags, last + 1)\n const seen: Set<string> = new Set()\n for (let i = 1; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (seg.depth !== 1) continue\n if (!seg.name) continue\n if (seg.segmentView) continue\n if (seen.has(seg.name)) continue\n if (!fragmentedComponents.has(seg.name)) continue\n if (ti.isComponentGroupWrapper(seg.name)) continue\n const v = ti.getInstance(seg.name)\n if (!v) continue\n seen.add(seg.name)\n seg.addSegmentView(v)\n }\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n fragments()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
1
+ {"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\nimport { TagIndex } from './tag-index'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const resolved: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!resolved) {\n return null\n }\n // narrowing of resolved is not visible inside the hoisted helpers below, so\n // carry the definition on a const the compiler already sees as non-optional\n const msgDefinition: MessageDefinition = resolved\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // track depth-1 components that have been exited for fragmentation detection\n const exitedDepth1Components = new Set<string>()\n const fragmentedComponents = new Set<string>()\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n\n // track when we exit depth-1 components for fragmentation detection\n if (done.depth === 1 && done.name) {\n exitedDepth1Components.add(done.name)\n }\n\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n // detect fragmentation: re-entering a depth-1 component we already exited\n if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {\n fragmentedComponents.add(cf.name)\n }\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n function fragments (): void {\n // only build SegmentViews for components detected as fragmented during discover\n // non-fragmented components use their position ranges directly (zero overhead)\n if (fragmentedComponents.size === 0) return\n const ti = new TagIndex(msgDefinition, tags, last + 1)\n const seen = new Set<string>()\n for (let i = 1; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (seg.depth !== 1) continue\n if (!seg.name) continue\n if (seg.segmentView) continue\n if (seen.has(seg.name)) continue\n if (!fragmentedComponents.has(seg.name)) continue\n if (ti.isComponentGroupWrapper(seg.name)) continue\n const v = ti.getInstance(seg.name)\n if (!v) continue\n seen.add(seg.name)\n seg.addSegmentView(v)\n }\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n fragments()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tag-index.js","sourceRoot":"","sources":["../../../src/buffer/ascii/tag-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { IContainedSet } from '../../dictionary/contained'\nimport { SegmentView } from '../segment/segment-view'\nimport { TagPos } from '../tag/tag-pos'\nimport { Tags } from '../tag/tags'\n\nexport interface TagSpan {\n start: number\n end: number\n}\n\nexport class TagIndex {\n private readonly sortedTagPos: TagPos[]\n private readonly tagSpans: Map<number, TagSpan> = new Map()\n private readonly componentGroupWrappers: Set<string> = new Set()\n private readonly cache: Map<string, SegmentView | null> = new Map()\n\n constructor (\n public readonly set: IContainedSet,\n tags: Tags,\n count: number) {\n this.sortedTagPos = new Array(count)\n for (let i = 0; i < count; i++) {\n this.sortedTagPos[i] = tags.tagPos[i]\n }\n this.sortedTagPos.sort(TagPos.compare)\n this.populateTagSpans()\n this.calcGroups(tags, count)\n }\n\n private populateTagSpans (): void {\n for (let i = 0; i < this.sortedTagPos.length; i++) {\n const t = this.sortedTagPos[i]\n const existing = this.tagSpans.get(t.tag)\n if (existing) {\n existing.end = i\n } else {\n this.tagSpans.set(t.tag, { start: i, end: i })\n }\n }\n }\n\n private calcGroups (tags: Tags, count: number): void {\n for (let i = 0; i < count; i++) {\n const tag = tags.tagPos[i]\n const field = this.set.tagToField[tag.tag]\n if (!field) continue\n // detect component group wrappers (single-field components containing a group)\n const component = this.findParentComponent(tag.tag)\n if (component) {\n const componentSet = this.set.components.get(component)\n if (componentSet && componentSet.fields.length === 1) {\n this.componentGroupWrappers.add(component)\n }\n }\n }\n }\n\n private findParentComponent (tag: number): string | null {\n for (const [name, componentSet] of this.set.components) {\n if (componentSet.containedTag[tag]) {\n return name\n }\n }\n return null\n }\n\n public getInstance (name: string): SegmentView | null {\n const cached = this.cache.get(name)\n if (cached !== undefined) {\n return cached\n }\n\n const componentSet = this.set.components.get(name)\n if (!componentSet) {\n this.cache.set(name, null)\n return null\n }\n\n const view = new SegmentView(name, componentSet)\n const flatTags = componentSet.flattenedTag\n for (let x = 0; x < flatTags.length; x++) {\n const t = flatTags[x]\n const span = this.tagSpans.get(t)\n if (!span) continue\n if (span.start === span.end) {\n view.add(this.sortedTagPos[span.start])\n } else {\n for (let j = span.start; j <= span.end; j++) {\n view.add(this.sortedTagPos[j])\n }\n }\n }\n\n this.cache.set(name, view)\n return view\n }\n\n public isComponentGroupWrapper (name: string): boolean {\n return this.componentGroupWrappers.has(name)\n }\n}\n"]}
1
+ {"version":3,"file":"tag-index.js","sourceRoot":"","sources":["../../../src/buffer/ascii/tag-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { IContainedSet } from '../../dictionary/contained'\nimport { SegmentView } from '../segment/segment-view'\nimport { TagPos } from '../tag/tag-pos'\nimport { Tags } from '../tag/tags'\n\nexport interface TagSpan {\n start: number\n end: number\n}\n\nexport class TagIndex {\n private readonly sortedTagPos: TagPos[]\n private readonly tagSpans = new Map<number, TagSpan>()\n private readonly componentGroupWrappers = new Set<string>()\n private readonly cache = new Map<string, SegmentView | null>()\n\n constructor (\n public readonly set: IContainedSet,\n tags: Tags,\n count: number) {\n this.sortedTagPos = new Array(count)\n for (let i = 0; i < count; i++) {\n this.sortedTagPos[i] = tags.tagPos[i]\n }\n this.sortedTagPos.sort(TagPos.compare)\n this.populateTagSpans()\n this.calcGroups(tags, count)\n }\n\n private populateTagSpans (): void {\n for (let i = 0; i < this.sortedTagPos.length; i++) {\n const t = this.sortedTagPos[i]\n const existing = this.tagSpans.get(t.tag)\n if (existing) {\n existing.end = i\n } else {\n this.tagSpans.set(t.tag, { start: i, end: i })\n }\n }\n }\n\n private calcGroups (tags: Tags, count: number): void {\n for (let i = 0; i < count; i++) {\n const tag = tags.tagPos[i]\n const field = this.set.tagToField[tag.tag]\n if (!field) continue\n // detect component group wrappers (single-field components containing a group)\n const component = this.findParentComponent(tag.tag)\n if (component) {\n const componentSet = this.set.components.get(component)\n if (componentSet && componentSet.fields.length === 1) {\n this.componentGroupWrappers.add(component)\n }\n }\n }\n }\n\n private findParentComponent (tag: number): string | null {\n for (const [name, componentSet] of this.set.components) {\n if (componentSet.containedTag[tag]) {\n return name\n }\n }\n return null\n }\n\n public getInstance (name: string): SegmentView | null {\n const cached = this.cache.get(name)\n if (cached !== undefined) {\n return cached\n }\n\n const componentSet = this.set.components.get(name)\n if (!componentSet) {\n this.cache.set(name, null)\n return null\n }\n\n const view = new SegmentView(name, componentSet)\n const flatTags = componentSet.flattenedTag\n for (let x = 0; x < flatTags.length; x++) {\n const t = flatTags[x]\n const span = this.tagSpans.get(t)\n if (!span) continue\n if (span.start === span.end) {\n view.add(this.sortedTagPos[span.start])\n } else {\n for (let j = span.start; j <= span.end; j++) {\n view.add(this.sortedTagPos[j])\n }\n }\n }\n\n this.cache.set(name, view)\n return view\n }\n\n public isComponentGroupWrapper (name: string): boolean {\n return this.componentGroupWrappers.has(name)\n }\n}\n"]}