// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.lightir;

import it.unimi.dsi.fastutil.bytes.ByteIterator;
import java.util.Iterator;

/**
 * Basic iterator over the light IR.
 *
 * <p>This iterator is internally a zero-allocation parser with the "elements" as a view onto the
 * current state.
 */
public class LirIterator implements Iterator<LirInstructionView>, LirInstructionView {

  private final ByteIterator iterator;

  // State of the byte offsets into the iterator.
  private int currentByteIndex = 0;
  private int endOfCurrentInstruction = 0;

  // State of the instruction interpretation.
  private int currentInstructionIndex = -1;
  private int currentOpcode = -1;

  public LirIterator(ByteIterator iterator) {
    this.iterator = iterator;
  }

  private void skipRemainingOperands() {
    if (hasMoreOperands()) {
      skip(getRemainingOperandSizeInBytes());
    }
  }

  @Override
  public boolean hasNext() {
    skipRemainingOperands();
    return iterator.hasNext();
  }

  @Override
  public LirInstructionView next() {
    skipRemainingOperands();
    ++currentInstructionIndex;
    currentOpcode = u1();
    if (LirOpcodes.isOneByteInstruction(currentOpcode)) {
      endOfCurrentInstruction = currentByteIndex;
    } else {
      // Any instruction that is not a single byte has a two-byte header. The second byte is the
      // size of the variable width operand payload.
      int operandSize = u1();
      if (operandSize == 0) {
        // Zero is used to indicate the operand size is larger than a u1 encoded value.
        operandSize = u4();
      }
      endOfCurrentInstruction = currentByteIndex + operandSize;
    }
    return this;
  }

  @Override
  public void accept(LirInstructionCallback eventCallback) {
    eventCallback.onInstructionView(this);
  }

  @Override
  public int getInstructionIndex() {
    return currentInstructionIndex;
  }

  @Override
  public int getOpcode() {
    return currentOpcode;
  }

  @Override
  public int getRemainingOperandSizeInBytes() {
    return endOfCurrentInstruction - currentByteIndex;
  }

  @Override
  public boolean hasMoreOperands() {
    return currentByteIndex < endOfCurrentInstruction;
  }

  @Override
  public int getNextIntegerOperand() {
    assert hasMoreOperands();
    return u4();
  }

  @Override
  public long getNextLongOperand() {
    assert hasMoreOperands();
    return u8();
  }

  @Override
  public int getNextConstantOperand() {
    return getNextIntegerOperand();
  }

  @Override
  public int getNextValueOperand() {
    return getNextIntegerOperand();
  }

  @Override
  public int getNextBlockOperand() {
    return getNextIntegerOperand();
  }

  private void skip(int i) {
    currentByteIndex += i;
    iterator.skip(i);
  }

  private int u1() {
    ++currentByteIndex;
    return ByteUtils.fromU1(iterator.nextByte());
  }

  private int u4() {
    currentByteIndex += 4;
    return ByteUtils.readEncodedInt(iterator);
  }

  private long u8() {
    currentByteIndex += 8;
    return ByteUtils.readEncodedLong(iterator);
  }
}
