1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16class IndexRange { 17 readonly start: number; // inclusive 18 readonly end: number; // exclusive 19 20 constructor(start: number, end: number) { 21 this.start = start; 22 this.end = end; 23 if (this.start > this.end) { 24 throw new Error('Invalid range'); 25 } 26 } 27 28 get length(): number { 29 return this.end - this.start; 30 } 31 32 toSet(target?: Set<number>): Set<number> { 33 const set = target ?? new Set<number>(); 34 for (let i = this.start; i < this.end; ++i) { 35 set.add(i); 36 } 37 return set; 38 } 39 40 contains(value: IndexRange | number): boolean { 41 if (typeof value === 'object') { 42 return this.start <= value.start && value.end <= this.end; 43 } else { 44 return this.start <= value && value < this.end; 45 } 46 } 47 48 subtract(other: IndexRange): IndexRangeArray { 49 const result = new IndexRangeArray(); 50 if (other.start > this.start) { 51 result.push(new IndexRange(this.start, Math.min(this.end, other.start))); 52 } 53 if (other.end < this.end) { 54 result.push(new IndexRange(Math.max(other.end, this.start), this.end)); 55 } 56 return result; 57 } 58 59 // Expand the range to contain another. 60 // When `this` and `other` intersect, this is a union. 61 expandedWith(other: IndexRange): IndexRange { 62 return new IndexRange(Math.min(this.start, other.start), Math.max(this.end, other.end)); 63 } 64 65 forEachIndex(callback: (index: number) => void): void { 66 for (let i = this.start; i < this.end; ++i) { 67 callback(i); 68 } 69 } 70 71 equals(other: IndexRange): boolean { 72 return this.start === other.start && this.end === other.end; 73 } 74 75 toString(): string { 76 return `[${this.start}, ${this.end})`; 77 } 78} 79 80class IndexRangeArray extends Array<IndexRange> { 81 forEachIndex(callback: (index: number) => void): void { 82 this.forEach((range) => { 83 range.forEachIndex(callback); 84 }); 85 } 86 87 toSet(): Set<number> { 88 const set = new Set<number>(); 89 this.forEach((range) => { 90 range.toSet(set); 91 }); 92 return set; 93 } 94} 95