all files / src/ fast-iterative.js

100% Statements 43/43
100% Branches 8/8
100% Functions 2/2
100% Lines 37/37
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97                                                    12×               18×   16×   16×   16× 24× 23× 16×           14×           16×                   18×          
/** ******************************************************************************************************************
 * @file Implements a near-linear time iterative dominator generator based on this
 * paper: (A Simple, Fast Dominance Algorithm)[https://www.cs.rice.edu/~keith/Embed/dom.pdf]
 * Citation:
 * Cooper, Keith & Harvey, Timothy & Kennedy, Ken. (2006). A Simple, Fast Dominance Algorithm. Rice University, CS Technical Report 06-33870
 *
 * @author Julian Jensen <jjdanois@gmail.com>
 * @since 1.0.0
 * @date 10-Dec-2017
 *********************************************************************************************************************/
"use strict";
 
const
    { DFS } = require( 'traversals' );
 
/**
 * @param {Array<Array<number>>} succs
 * @param {number} [rootIndex=0]
 * @return {Array<number>}
 */
function iterative( succs, rootIndex = 0 )
{
    const
        idoms = [];
 
    let changed = true;
 
    const nodes = [];
 
    succs.forEach( ( _succs, i ) => {
        nodes.push( { id: i, preds: [], succs: _succs, post: null } );
    } );
 
    nodes.forEach( ( n, i ) => n.succs.forEach( s => nodes[ s ].preds.push( i ) ) );
 
    nodes.forEach( () => idoms.push( null ) );
 
    idoms[ rootIndex ] = rootIndex;
 
    /**
     * @param {number} index
     */
    function find_idoms( index )
    {
        if ( index === rootIndex ) return;
 
        const b = nodes[ index ];
 
        let idom = null;
 
        b.preds.forEach( p => {
            if ( idoms[ p ] === null ) return;
            if ( idom === null )
                idom = p;
            else
            {
                let finger1 = nodes[ p ],
                    finger2 = nodes[ idom ];
 
                while ( finger1.post !== finger2.post )
                {
                    while ( finger1.post < finger2.post )
                        finger1 = nodes[ idoms[ finger1.id ] ];
                    while ( finger2.post < finger1.post )
                        finger2 = nodes[ idoms[ finger2.id ] ];
                }
 
                idom = finger1.id;
            }
        } );
 
        if ( idoms[ b.id ] !== idom )
        {
            idoms[ b.id ] = idom;
            changed = true;
        }
    }
 
    const
        cbs = {
            rpost: find_idoms,
            post: ( id, postNum ) => nodes[ id ].post = postNum
        };
 
    while ( changed )
    {
        changed = false;
        DFS( nodes.map( n => n.succs ), cbs );
        cbs.post = void 0;
    }
 
    idoms[ rootIndex ] = null;
    return idoms;
}
 
module.exports = iterative;