/*
 * Copyright (C) 2013 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.
 */

#ifndef ART_RUNTIME_MAPPING_TABLE_H_
#define ART_RUNTIME_MAPPING_TABLE_H_

#include "base/logging.h"
#include "leb128.h"

namespace art {

// A utility for processing the raw uleb128 encoded mapping table created by the quick compiler.
class MappingTable {
 public:
  explicit MappingTable(const uint8_t* encoded_map) : encoded_table_(encoded_map) {
  }

  uint32_t TotalSize() const PURE {
    const uint8_t* table = encoded_table_;
    if (table == NULL) {
      return 0;
    } else {
      return DecodeUnsignedLeb128(&table);
    }
  }

  uint32_t DexToPcSize() const PURE {
    const uint8_t* table = encoded_table_;
    if (table == NULL) {
      return 0;
    } else {
      uint32_t total_size = DecodeUnsignedLeb128(&table);
      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
      return total_size - pc_to_dex_size;
    }
  }

  const uint8_t* FirstDexToPcPtr() const {
    const uint8_t* table = encoded_table_;
    if (table != NULL) {
      DecodeUnsignedLeb128(&table);  // Total_size, unused.
      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
      for (uint32_t i = 0; i < pc_to_dex_size; ++i) {
        DecodeUnsignedLeb128(&table);  // Move ptr past native PC.
        DecodeUnsignedLeb128(&table);  // Move ptr past dex PC.
      }
    }
    return table;
  }

  class DexToPcIterator {
   public:
    DexToPcIterator(const MappingTable* table, uint32_t element) :
        table_(table), element_(element), end_(table_->DexToPcSize()), encoded_table_ptr_(NULL),
        native_pc_offset_(0), dex_pc_(0) {
      if (element == 0) {
        encoded_table_ptr_ = table_->FirstDexToPcPtr();
        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
      } else {
        DCHECK_EQ(table_->DexToPcSize(), element);
      }
    }
    uint32_t NativePcOffset() const {
      return native_pc_offset_;
    }
    uint32_t DexPc() const {
      return dex_pc_;
    }
    void operator++() {
      ++element_;
      if (element_ != end_) {  // Avoid reading beyond the end of the table.
        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
      }
    }
    bool operator==(const DexToPcIterator& rhs) const {
      CHECK(table_ == rhs.table_);
      return element_ == rhs.element_;
    }
    bool operator!=(const DexToPcIterator& rhs) const {
      CHECK(table_ == rhs.table_);
      return element_ != rhs.element_;
    }

   private:
    const MappingTable* const table_;  // The original table.
    uint32_t element_;  // A value in the range 0 to end_.
    const uint32_t end_;  // Equal to table_->DexToPcSize().
    const uint8_t* encoded_table_ptr_;  // Either NULL or points to encoded data after this entry.
    uint32_t native_pc_offset_;  // The current value of native pc offset.
    uint32_t dex_pc_;  // The current value of dex pc.
  };

  DexToPcIterator DexToPcBegin() const {
    return DexToPcIterator(this, 0);
  }

  DexToPcIterator DexToPcEnd() const {
    uint32_t size = DexToPcSize();
    return DexToPcIterator(this, size);
  }

  uint32_t PcToDexSize() const PURE {
    const uint8_t* table = encoded_table_;
    if (table == NULL) {
      return 0;
    } else {
      DecodeUnsignedLeb128(&table);  // Total_size, unused.
      uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
      return pc_to_dex_size;
    }
  }

  const uint8_t* FirstPcToDexPtr() const {
    const uint8_t* table = encoded_table_;
    if (table != NULL) {
      DecodeUnsignedLeb128(&table);  // Total_size, unused.
      DecodeUnsignedLeb128(&table);  // PC to Dex size, unused.
    }
    return table;
  }

  class PcToDexIterator {
   public:
    PcToDexIterator(const MappingTable* table, uint32_t element) :
        table_(table), element_(element), end_(table_->PcToDexSize()), encoded_table_ptr_(NULL),
        native_pc_offset_(0), dex_pc_(0) {
      if (element == 0) {
        encoded_table_ptr_ = table_->FirstPcToDexPtr();
        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
      } else {
        DCHECK_EQ(table_->PcToDexSize(), element);
      }
    }
    uint32_t NativePcOffset() const {
      return native_pc_offset_;
    }
    uint32_t DexPc() const {
      return dex_pc_;
    }
    void operator++() {
      ++element_;
      if (element_ != end_) {  // Avoid reading beyond the end of the table.
        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
      }
    }
    bool operator==(const PcToDexIterator& rhs) const {
      CHECK(table_ == rhs.table_);
      return element_ == rhs.element_;
    }
    bool operator!=(const PcToDexIterator& rhs) const {
      CHECK(table_ == rhs.table_);
      return element_ != rhs.element_;
    }

   private:
    const MappingTable* const table_;  // The original table.
    uint32_t element_;  // A value in the range 0 to PcToDexSize.
    const uint32_t end_;  // Equal to table_->PcToDexSize().
    const uint8_t* encoded_table_ptr_;  // Either NULL or points to encoded data after this entry.
    uint32_t native_pc_offset_;  // The current value of native pc offset.
    uint32_t dex_pc_;  // The current value of dex pc.
  };

  PcToDexIterator PcToDexBegin() const {
    return PcToDexIterator(this, 0);
  }

  PcToDexIterator PcToDexEnd() const {
    uint32_t size = PcToDexSize();
    return PcToDexIterator(this, size);
  }

 private:
  const uint8_t* const encoded_table_;
};

}  // namespace art

#endif  // ART_RUNTIME_MAPPING_TABLE_H_
