<commit_before>/**
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module Shumway.Tools {
  import clamp = NumberUtilities.clamp;
  import createEmptyObject = ObjectUtilities.createEmptyObject;

  /**
   * Inspired by the Chrome flame chart and others.
   */

  export class TimelineFrame {
    public children: TimelineFrame [];
    public total: number;
    constructor (
      public parent: TimelineFrame,
      public kind: number,
      public startTime: number,
      public endTime: number) {
      // ...
    }

    public getChildIndex(time: number) {
      var children = this.children;
      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        if (child.endTime > time) {
          return i;
        }
      }
      return 0;
    }

    public getChildRange(s: number, e: number) {
      var children = this.children;
      var j = -1, k = -1;
      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        var l = child.startTime, r = child.endTime;
        if (l <= e && s <= r) { // Segments Overlap
          if (j < 0) {
            j = i;
          }
          k = i;
        }
      }
      return [j, k];
    }

    public query(time: number) {
      if (time < this.startTime || time > this.endTime) {
        return null;
      }
      var children = this.children;
      if (children) {
        for (var i = 0; i < children.length; i++) {
          var child = children[i];
          if (time >= child.startTime && time <= child.endTime) {
            return child.query(time);
          }
        }
      }
      return this;
    }

    public getDepth(): number {
      var depth = 0;
      var self = this;
      while (self) {
        depth ++;
        self = self.parent;
      }
      return depth;
    }
  }

  export class TimelineBuffer {
    static ENTER = 0xBEEF0000 | 0;
    static LEAVE = 0xDEAD0000 | 0;

    private _depth: number;
    private _kindCount: number;
    public marks: Shumway.CircularBuffer;
    public times: Shumway.CircularBuffer;
    public kinds: Shumway.Map<number>;
    public kindNames: Shumway.Map<string>;

    constructor() {
      this.marks = new Shumway.CircularBuffer(Int32Array, 20);
      this.times = new Shumway.CircularBuffer(Float64Array, 20);
      this.kinds = createEmptyObject();
      this.kindNames = createEmptyObject();
      this._depth = 0;
      this._kindCount = 0;
    }

    getKindName(kind: number): string {
      return this.kindNames[kind];
    }

    getKind(name: string): number {
      if (this.kinds[name] === undefined) {
        var kind = this._kindCount ++;
        this.kinds[name] = kind;
        this.kindNames[kind] = name;
      }
      return this.kinds[name];
    }

    enter(name: string, time?: number) {
      this._depth++;
      this.marks.write(TimelineBuffer.ENTER | this.getKind(name));
      this.times.write(time || performance.now());
    }

    leave(name: string, time?: number) {
      this.marks.write(TimelineBuffer.LEAVE | this.getKind(name));
      this.times.write(time || performance.now());
      this._depth--;
    }

    gatherRange(count: number): TimelineFrame {
      var range = new TimelineFrame(null, 0, NaN, NaN);
      var stack: TimelineFrame [] = [range];
      var times = this.times;
      var topLevelFrameCount = 0;
      this.marks.forEachInReverse(function (mark, i) {
        var time = times.get(i);
        if ((mark & 0xFFFF0000) === TimelineBuffer.LEAVE) {
          if (stack.length === 1) {
            topLevelFrameCount ++;
            if (topLevelFrameCount > count) {
              return true;
            }<commit_msg>Some comments.<commit_after>/**
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
module Shumway.Tools {
  import clamp = NumberUtilities.clamp;
  import createEmptyObject = ObjectUtilities.createEmptyObject;

  /**
   * Inspired by the Chrome flame chart and others.
   */

  /**
   * Represents a single timeline frame range and makes it easier to work with the compacted
   * timeline buffer data.
   */
  export class TimelineFrame {
    public children: TimelineFrame [];
    public total: number;
    constructor (
      public parent: TimelineFrame,
      public kind: number,
      public startTime: number,
      public endTime: number) {
      // ...
    }

    /**
     * Gets the child index of the first child to overlap the specified time.
     */
    public getChildIndex(time: number): number {
      var children = this.children;
      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        if (child.endTime > time) {
          return i;
        }
      }
      return 0;
    }

    /**
     * Gets the high and low index of the children that intersect the specified time range.
     *
     * TODO: This uses a dumb linear algorithm, we can do much better here by doing a binary search.
     */
    public getChildRange(s: number, e: number): number [] {
      var children = this.children;
      var j = -1, k = -1;
      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        var l = child.startTime, r = child.endTime;
        if (l <= e && s <= r) { // Segments Overlap
          if (j < 0) {
            j = i;
          }
          k = i;
        }
      }
      return [j, k];
    }

    /**
     * Finds the deepest child that intersects with the specified time.
     */
    public query(time: number): TimelineFrame {
      if (time < this.startTime || time > this.endTime) {
        return null;
      }
      var children = this.children;
      if (children) {
        for (var i = 0; i < children.length; i++) {
          var child = children[i];
          if (time >= child.startTime && time <= child.endTime) {
            return child.query(time);
          }
        }
      }
      return this;
    }

    /**
     * Gets this frame's distance to the root.
     */
    public getDepth(): number {
      var depth = 0;
      var self = this;
      while (self) {
        depth ++;
        self = self.parent;
      }
      return depth;
    }
  }

  /**
   * Records enter / leave events in two circular buffers. The goal here is to be able to handle
   * large ammounts of data.
   */
  export class TimelineBuffer {
    static ENTER = 0xBEEF0000 | 0;
    static LEAVE = 0xDEAD0000 | 0;

    private _depth: number;
    private _kindCount: number;
    public marks: Shumway.CircularBuffer;
    public times: Shumway.CircularBuffer;
    public kinds: Shumway.Map<number>;
    public kindNames: Shumway.Map<string>;

    constructor() {
      this.marks = new Shumway.CircularBuffer(Int32Array, 20);
      this.times = new Shumway.CircularBuffer(Float64Array, 20);
      this.kinds = createEmptyObject();
      this.kindNames = createEmptyObject();
      this._depth = 0;
      this._kindCount = 0;
    }

    getKindName(kind: number): string {
      return this.kindNames[kind];
    }

    getKind(name: string): number {
      if (this.kinds[name] === undefined) {
        var kind = this._kindCount ++;
        this.kinds[name] = kind;
        this.kindNames[kind] = name;
      }
      return this.kinds[name];
    }

    enter(name: string, time?: number) {
      this._depth++;
      this.marks.write(TimelineBuffer.ENTER | this.getKind(name));
      this.times.write(time || performance.now());
    }

    leave(name: string, time?: number) {
      this.marks.write(TimelineBuffer.LEAVE | this.getKind(name));
      this.times.write(time || performance.now());
      this._depth--;
    }

    /**
     * Constructs an easier to work with TimelineFrame data structure.
     */
    gatherRange(count: number): TimelineFrame {
      var range = new TimelineFrame(null, 0, NaN, NaN);
      var stack: TimelineFrame [] = [range];
      var times = this.times;
      var topLevelFrameCount = 0;
      this.marks.forEachInReverse(function (mark, i) {
        var time = times.get(i);
        if ((mark & 0xFFFF0000) === TimelineBuffer.LEAVE) {
          if (stack.length === 1) {
            topLevelFrameCount ++;
            if (topLevelFrameCount > count) {
              return true;
            }
{'fraction_non_alphanumeric': 0.11195404790289368, 'fraction_numerical': 0.009970738051370977, 'mean_word_length': 2.1667810569663692, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4075513', 'n_tokens_mistral': 2800, 'n_tokens_neox': 2682, 'n_words': 839}