// 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.

#ifndef RUNTIME_VM_BIT_VECTOR_H_
#define RUNTIME_VM_BIT_VECTOR_H_

#include "vm/allocation.h"
#include "vm/isolate.h"
#include "vm/zone.h"

namespace dart {

// Bit vector implementation.
class BitVector : public ZoneObject {
 public:
  // Iterator for the elements of this BitVector.
  class Iterator : public ValueObject {
   public:
    explicit Iterator(BitVector* target)
        : target_(target),
          bit_index_(-1),
          word_index_(0),
          current_word_(target->data_[0]) {
      ASSERT(target->data_length_ > 0);
      Advance();
    }
    ~Iterator() {}

    bool Done() const { return word_index_ >= target_->data_length_; }
    void Advance();

    intptr_t Current() const {
      ASSERT(!Done());
      return bit_index_;
    }

   private:
    BitVector* target_;
    intptr_t bit_index_;
    intptr_t word_index_;
    uword current_word_;

    friend class BitVector;
  };

  BitVector(Zone* zone, intptr_t length)
      : length_(length),
        data_length_(SizeFor(length)),
        data_(zone->Alloc<uword>(data_length_)) {
    Clear();
  }

  void CopyFrom(const BitVector* other);

  static intptr_t SizeFor(intptr_t length) {
    return 1 + ((length - 1) / kBitsPerWord);
  }

  void Add(intptr_t i) {
    ASSERT(i >= 0 && i < length());
    data_[i / kBitsPerWord] |= (static_cast<uword>(1) << (i % kBitsPerWord));
  }

  void Remove(intptr_t i) {
    ASSERT(i >= 0 && i < length());
    data_[i / kBitsPerWord] &= ~(static_cast<uword>(1) << (i % kBitsPerWord));
  }

  void Set(intptr_t i, bool value) { value ? Add(i) : Remove(i); }

  bool Equals(const BitVector& other) const;

  // Add all elements that are in the bitvector from.
  bool AddAll(const BitVector* from);

  // Remove all elements that are in the bitvector from.
  bool RemoveAll(const BitVector* from);

  // From the bitvector gen add those elements that are not in the
  // bitvector kill.
  bool KillAndAdd(BitVector* kill, BitVector* gen);

  void Intersect(const BitVector* other);

  bool IsEmpty() const;

  bool Contains(intptr_t i) const {
    ASSERT(i >= 0 && i < length());
    uword block = data_[i / kBitsPerWord];
    return (block & (static_cast<uword>(1) << (i % kBitsPerWord))) != 0;
  }

  bool SubsetOf(const BitVector& other) {
    ASSERT(length_ == other.length_);
    for (intptr_t i = 0; i < data_length_; ++i) {
      if ((data_[i] & other.data_[i]) != data_[i]) return false;
    }
    return true;
  }

  void Clear() {
    for (intptr_t i = 0; i < data_length_; i++) {
      data_[i] = 0;
    }
  }

  void SetAll() {
    for (intptr_t i = 0; i < data_length_; i++) {
      data_[i] = static_cast<uword>(-1);
    }
  }

  intptr_t length() const { return length_; }

  void Print() const;

 private:
  intptr_t length_;
  intptr_t data_length_;
  uword* data_;

  DISALLOW_COPY_AND_ASSIGN(BitVector);
};

}  // namespace dart

#endif  // RUNTIME_VM_BIT_VECTOR_H_
