1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {Item} from 'trace/item'; 18 19export abstract class TreeNode implements Item { 20 protected children: this[] = []; 21 22 constructor(readonly id: string, readonly name: string) {} 23 24 addOrReplaceChild(newChild: this): void { 25 const currIndex = this.children.findIndex( 26 (child) => child.id === newChild.id, 27 ); 28 if (currIndex !== -1) { 29 this.children[currIndex] = newChild; 30 } else { 31 this.children.push(newChild); 32 } 33 } 34 35 removeChild(childId: string) { 36 this.children = this.children.filter((child) => child.id !== childId); 37 } 38 39 removeAllChildren() { 40 this.children = []; 41 } 42 43 getChildByName(name: string): this | undefined { 44 return this.children.find((child) => child.name === name); 45 } 46 47 getAllChildren(): readonly this[] { 48 return this.children; 49 } 50 51 forEachNodeDfs(callback: (node: this) => void, reverseChildren = false) { 52 callback(this); 53 54 if (reverseChildren) { 55 for (let i = this.children.length - 1; i > -1; i--) { 56 this.children[i].forEachNodeDfs(callback, reverseChildren); 57 } 58 } else { 59 this.children.forEach((child) => 60 child.forEachNodeDfs(callback, reverseChildren), 61 ); 62 } 63 } 64 65 findDfs(targetNodeFilter: (node: this) => boolean): this | undefined { 66 if (targetNodeFilter(this)) { 67 return this; 68 } 69 70 for (const child of this.children.values()) { 71 const nodeFound = child.findDfs(targetNodeFilter); 72 if (nodeFound) return nodeFound; 73 } 74 75 return undefined; 76 } 77 78 filterDfs( 79 predicate: (node: this) => boolean, 80 reverseChildren = false, 81 ): this[] { 82 const result: this[] = []; 83 84 this.forEachNodeDfs((node) => { 85 if (predicate(node)) { 86 result.push(node); 87 } 88 }, reverseChildren); 89 90 return result; 91 } 92 93 abstract isRoot(): boolean; 94} 95