content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * 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.
   */
  
  package com.taobao.android.dx.dex.code;
  
  import com.taobao.android.dx.rop.code.SourcePosition;
  import com.taobao.android.dx.util.FixedSizeList;
  
  /**
   * List of source position entries. This class includes a utility
   * method to extract an instance out of a {@link DalvInsnList}.
   */
  public final class PositionList extends FixedSizeList {
      /** {@code non-null;} empty instance */
      public static final PositionList EMPTY = new PositionList(0);
  
      /**
       * constant for {@link #make} to indicate that no actual position
       * information should be returned
       */
      public static final int NONE = 1;
  
      /**
       * constant for {@link #make} to indicate that only line number
       * transitions should be returned
       */
      public static final int LINES = 2;
  
      /**
       * constant for {@link #make} to indicate that only "important" position
       * information should be returned. This includes block starts and
       * instructions that might throw.
       */
      public static final int IMPORTANT = 3;
  
      /**
       * Extracts and returns the source position information out of an
       * instruction list.
       *
       * @param insns {@code non-null;} instructions to convert
       * @param howMuch how much information should be included; one of the
       * static constants defined by this class
       * @return {@code non-null;} the positions list
       */
      public static PositionList make(DalvInsnList insns, int howMuch) {
          switch (howMuch) {
              case NONE: {
                  return EMPTY;
              }
              case LINES:
              case IMPORTANT: {
                  // Valid.
                  break;
              }
              default: {
                  throw new IllegalArgumentException("bogus howMuch");
              }
          }
  
          SourcePosition noInfo = SourcePosition.NO_INFO;
          SourcePosition cur = noInfo;
          int sz = insns.size();
          Entry[] arr = new Entry[sz];
          boolean lastWasTarget = false;
          int at = 0;
  
          for (int i = 0; i < sz; i++) {
              DalvInsn insn = insns.get(i);
  
              if (insn instanceof CodeAddress) {
                  lastWasTarget = true;;
                  continue;
              }
  
              SourcePosition pos = insn.getPosition();
  
              if (pos.equals(noInfo) || pos.sameLine(cur)) {
                  continue;
              }
  
              if ((howMuch == IMPORTANT) && !lastWasTarget) {
                  continue;
              }
  
              cur = pos;
              arr[at] = new Entry(insn.getAddress(), pos);
              at++;
  
              lastWasTarget = false;
          }
  
          PositionList result = new PositionList(at);
          for (int i = 0; i < at; i++) {
              result.set(i, arr[i]);
          }
  
          result.setImmutable();
          return result;
      }
  
      /**
       * Constructs an instance. All indices initially contain {@code null}.
       *
       * @param size {@code >= 0;} the size of the list
       */
      public PositionList(int size) {
          super(size);
      }
  
      /**
       * Gets the element at the given index. It is an error to call
       * this with the index for an element which was never set; if you
       * do that, this will throw {@code NullPointerException}.
       *
       * @param n {@code >= 0, < size();} which index
       * @return {@code non-null;} element at that index
       */
      public Entry get(int n) {
          return (Entry) get0(n);
      }
  
      /**
       * Sets the entry at the given index.
       *
       * @param n {@code >= 0, < size();} which index
       * @param entry {@code non-null;} the entry to set at {@code n}
       */
      public void set(int n, Entry entry) {
          set0(n, entry);
      }
  
      /**
       * Entry in a position list.
       */
      public static class Entry {
          /** {@code >= 0;} address of this entry */
          private final int address;
  
          /** {@code non-null;} corresponding source position information */
          private final SourcePosition position;
  
          /**
           * Constructs an instance.
           *
           * @param address {@code >= 0;} address of this entry
           * @param position {@code non-null;} corresponding source position information
           */
          public Entry (int address, SourcePosition position) {
              if (address < 0) {
                  throw new IllegalArgumentException("address < 0");
              }
  
              if (position == null) {
                  throw new NullPointerException("position == null");
              }
  
              this.address = address;
              this.position = position;
          }
  
          /**
           * Gets the address.
           *
           * @return {@code >= 0;} the address
           */
          public int getAddress() {
              return address;
          }
  
          /**
           * Gets the source position information.
           *
           * @return {@code non-null;} the position information
           */
          public SourcePosition getPosition() {
              return position;
          }
      }
  }
  