// Copyright (c) 2012, the Dart 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.

#include "vm/bitmap.h"

#include "platform/assert.h"
#include "vm/object.h"

namespace dart {

void BitmapBuilder::SetLength(intptr_t new_length) {
  // When this function is used to shorten the length, affected bits in the
  // backing store need to be cleared because the implementation assumes it.
  if (new_length < length_) {
    // Byte offset containing the first bit to be cleared.
    intptr_t byte_offset = new_length >> kBitsPerByteLog2;
    if (byte_offset < data_size_in_bytes_) {
      // First bit index (in the byte) to be cleared.
      intptr_t bit_index = new_length & (kBitsPerByte - 1);
      intptr_t mask = (1 << bit_index) - 1;
      data_[byte_offset] &= mask;
      // Clear the rest.
      ++byte_offset;
      if (byte_offset < data_size_in_bytes_) {
        memset(&data_[byte_offset], 0, data_size_in_bytes_ - byte_offset);
      }
    }
  }
  length_ = new_length;
}

bool BitmapBuilder::Get(intptr_t bit_offset) const {
  if (!InRange(bit_offset)) {
    return false;
  }
  intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
  // Bits not covered by the backing store are implicitly false.
  return (byte_offset < data_size_in_bytes_) && GetBit(bit_offset);
}

void BitmapBuilder::Set(intptr_t bit_offset, bool value) {
  if (!InRange(bit_offset)) {
    length_ = bit_offset + 1;
    // Bits not covered by the backing store are implicitly false.
    if (!value) return;
    // Grow the backing store if necessary.
    intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
    if (byte_offset >= data_size_in_bytes_) {
      uint8_t* old_data = data_;
      intptr_t old_size = data_size_in_bytes_;
      data_size_in_bytes_ =
          Utils::RoundUp(byte_offset + 1, kIncrementSizeInBytes);
      ASSERT(data_size_in_bytes_ > 0);
      data_ = Thread::Current()->zone()->Alloc<uint8_t>(data_size_in_bytes_);
      ASSERT(data_ != NULL);
      memmove(data_, old_data, old_size);
      memset(&data_[old_size], 0, (data_size_in_bytes_ - old_size));
    }
  }
  SetBit(bit_offset, value);
}

void BitmapBuilder::SetRange(intptr_t min, intptr_t max, bool value) {
  for (intptr_t i = min; i <= max; i++) {
    Set(i, value);
  }
}

void BitmapBuilder::Print() const {
  for (intptr_t i = 0; i < Length(); i++) {
    if (Get(i)) {
      OS::PrintErr("1");
    } else {
      OS::PrintErr("0");
    }
  }
}

void BitmapBuilder::AppendAsBytesTo(BaseWriteStream* stream) const {
  // Early return if there are no bits in the payload to copy.
  if (Length() == 0) return;

  const intptr_t total_size =
      Utils::RoundUp(Length(), kBitsPerByte) / kBitsPerByte;
  intptr_t payload_size;
  intptr_t extra_size;
  if (total_size > data_size_in_bytes_) {
    // A [BitmapBuilder] does not allocate storage for the trailing 0 bits in
    // the backing store, so we need to add additional empty bytes here.
    payload_size = data_size_in_bytes_;
    extra_size = total_size - data_size_in_bytes_;
  } else {
    payload_size = total_size;
    extra_size = 0;
  }
#if defined(DEBUG)
  // Make sure any bits in the payload beyond the bit length if we're not
  // appending trailing zeroes are cleared to ensure deterministic snapshots.
  if (extra_size == 0 && Length() % kBitsPerByte != 0) {
    const int8_t mask = (1 << (Length() % kBitsPerByte)) - 1;
    ASSERT_EQUAL(data_[payload_size - 1], (data_[payload_size - 1] & mask));
  }
#endif
  for (intptr_t i = 0; i < payload_size; i++) {
    stream->WriteByte(data_[i]);
  }
  for (intptr_t i = 0; i < extra_size; i++) {
    stream->WriteByte(0U);
  }
}

bool BitmapBuilder::GetBit(intptr_t bit_offset) const {
  if (!InRange(bit_offset)) {
    return false;
  }
  intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
  ASSERT(byte_offset < data_size_in_bytes_);
  intptr_t bit_remainder = bit_offset & (kBitsPerByte - 1);
  uint8_t mask = 1U << bit_remainder;
  ASSERT(data_ != NULL);
  return ((data_[byte_offset] & mask) != 0);
}

void BitmapBuilder::SetBit(intptr_t bit_offset, bool value) {
  if (!InRange(bit_offset)) {
    FATAL1(
        "Fatal error in BitmapBuilder::SetBit :"
        " invalid bit_offset, %" Pd "\n",
        bit_offset);
  }
  intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
  ASSERT(byte_offset < data_size_in_bytes_);
  intptr_t bit_remainder = bit_offset & (kBitsPerByte - 1);
  uint8_t mask = 1U << bit_remainder;
  ASSERT(data_ != NULL);
  if (value) {
    data_[byte_offset] |= mask;
  } else {
    data_[byte_offset] &= ~mask;
  }
}

}  // namespace dart
