1 /** 2 Copyright: Copyright (c) 2020, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.backend.analyze.utility; 11 12 import dextool.plugin.mutate.backend.analyze.ast : Interval; 13 14 struct Stack(T) { 15 import std.typecons : Tuple; 16 import automem; 17 18 alias Element = Tuple!(T, "data", uint, "depth"); 19 Vector!(Element) stack; 20 21 alias stack this; 22 23 // trusted: as long as arr do not escape the instance 24 void put(T a, uint depth) @trusted { 25 stack.put(Element(a, depth)); 26 } 27 28 // trusted: as long as arr do not escape the instance 29 void pop() @trusted { 30 stack.popBack; 31 } 32 33 /** 34 * It is important that it removes up to and including the specified depth 35 * because the stack is used when doing depth first search. Each call to 36 * popUntil is expected to remove a layer. New nodes are then added to the 37 * parent which is the first one from the previous layer. 38 * 39 * Returns: the removed elements. 40 */ 41 auto popUntil(uint depth) @trusted { 42 Vector!T rval; 43 while (!stack.empty && stack[$ - 1].depth >= depth) { 44 rval.put(stack[$ - 1].data); 45 stack.popBack; 46 } 47 return rval; 48 } 49 50 T back() { 51 return stack[$ - 1].data; 52 } 53 54 bool empty() @safe pure nothrow const @nogc { 55 return stack.empty; 56 } 57 58 /// Returns: the depth (1+) if any of the parent nodes is `k`, zero otherwise. 59 uint isInside(K)(K k) { 60 import std.algorithm : filter; 61 62 foreach (a; stack.range.filter!(a => a.data.kind == k)) { 63 return a.depth; 64 } 65 return 0; 66 } 67 } 68 69 /** An index that can be queries to see if an interval overlap any of those 70 * that are in it. Create an index of all intervals that then can be queried to 71 * see if a Cursor or Interval overlap a macro. 72 */ 73 struct Index(KeyT) { 74 Interval[][KeyT] index; 75 76 this(Interval[][KeyT] index) { 77 this.index = index; 78 } 79 80 void put(KeyT k, Interval i) { 81 if (auto v = k in index) { 82 (*v) ~= i; 83 } else { 84 index[k] = [i]; 85 } 86 } 87 88 /** Check if `i` is inside any of the intervals for `key`. 89 * 90 * Returns: true if `i` is inside a macro interval. 91 */ 92 bool inside(const KeyT key, const Interval i) { 93 static bool test(Interval i, uint p) { 94 return p >= i.begin && p <= i.end; 95 } 96 97 if (auto intervals = key in index) { 98 foreach (a; *intervals) { 99 if (test(a, i.begin) || test(a, i.end)) { 100 return true; 101 } 102 } 103 } 104 105 return false; 106 } 107 }