123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- "use strict";
- const assert = require("assert"),
- CodePathSegment = require("./code-path-segment");
- function isReachable(segment) {
- return segment.reachable;
- }
- function createSegments(context, startIndex, endIndex, create) {
-
- const list = context.segmentsList;
-
- const normalizedBegin = startIndex >= 0 ? startIndex : list.length + startIndex;
- const normalizedEnd = endIndex >= 0 ? endIndex : list.length + endIndex;
-
- const segments = [];
- for (let i = 0; i < context.count; ++i) {
-
- const allPrevSegments = [];
- for (let j = normalizedBegin; j <= normalizedEnd; ++j) {
- allPrevSegments.push(list[j][i]);
- }
-
- segments.push(create(context.idGenerator.next(), allPrevSegments));
- }
- return segments;
- }
- function mergeExtraSegments(context, segments) {
- let currentSegments = segments;
-
- while (currentSegments.length > context.count) {
- const merged = [];
-
- for (let i = 0, length = Math.floor(currentSegments.length / 2); i < length; ++i) {
- merged.push(CodePathSegment.newNext(
- context.idGenerator.next(),
- [currentSegments[i], currentSegments[i + length]]
- ));
- }
-
- currentSegments = merged;
- }
- return currentSegments;
- }
- class ForkContext {
-
- constructor(idGenerator, upper, count) {
-
- this.idGenerator = idGenerator;
-
- this.upper = upper;
-
- this.count = count;
-
- this.segmentsList = [];
- }
-
- get head() {
- const list = this.segmentsList;
- return list.length === 0 ? [] : list[list.length - 1];
- }
-
- get empty() {
- return this.segmentsList.length === 0;
- }
-
- get reachable() {
- const segments = this.head;
- return segments.length > 0 && segments.some(isReachable);
- }
-
- makeNext(startIndex, endIndex) {
- return createSegments(this, startIndex, endIndex, CodePathSegment.newNext);
- }
-
- makeUnreachable(startIndex, endIndex) {
- return createSegments(this, startIndex, endIndex, CodePathSegment.newUnreachable);
- }
-
- makeDisconnected(startIndex, endIndex) {
- return createSegments(this, startIndex, endIndex, CodePathSegment.newDisconnected);
- }
-
- add(segments) {
- assert(segments.length >= this.count, `${segments.length} >= ${this.count}`);
- this.segmentsList.push(mergeExtraSegments(this, segments));
- }
-
- replaceHead(replacementHeadSegments) {
- assert(
- replacementHeadSegments.length >= this.count,
- `${replacementHeadSegments.length} >= ${this.count}`
- );
- this.segmentsList.splice(-1, 1, mergeExtraSegments(this, replacementHeadSegments));
- }
-
- addAll(otherForkContext) {
- assert(otherForkContext.count === this.count);
- this.segmentsList.push(...otherForkContext.segmentsList);
- }
-
- clear() {
- this.segmentsList = [];
- }
-
- static newRoot(idGenerator) {
- const context = new ForkContext(idGenerator, null, 1);
- context.add([CodePathSegment.newRoot(idGenerator.next())]);
- return context;
- }
-
- static newEmpty(parentContext, shouldForkLeavingPath) {
- return new ForkContext(
- parentContext.idGenerator,
- parentContext,
- (shouldForkLeavingPath ? 2 : 1) * parentContext.count
- );
- }
- }
- module.exports = ForkContext;
|