| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_ZONE_ZONE_HANDLE_SET_H_ |
| #define V8_ZONE_ZONE_HANDLE_SET_H_ |
| |
| #include "src/handles.h" |
| #include "src/zone/zone-containers.h" |
| #include "src/zone/zone.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| template <typename T> |
| class ZoneHandleSet final { |
| public: |
| ZoneHandleSet() : data_(kEmptyTag) {} |
| explicit ZoneHandleSet(Handle<T> handle) |
| : data_(bit_cast<intptr_t>(handle.address()) | kSingletonTag) { |
| DCHECK(IsAligned(bit_cast<intptr_t>(handle.address()), kPointerAlignment)); |
| } |
| |
| bool is_empty() const { return data_ == kEmptyTag; } |
| |
| size_t size() const { |
| if ((data_ & kTagMask) == kEmptyTag) return 0; |
| if ((data_ & kTagMask) == kSingletonTag) return 1; |
| return list()->size(); |
| } |
| |
| Handle<T> at(size_t i) const { |
| DCHECK_NE(kEmptyTag, data_ & kTagMask); |
| if ((data_ & kTagMask) == kSingletonTag) { |
| DCHECK_EQ(0u, i); |
| return Handle<T>(singleton()); |
| } |
| return Handle<T>(list()->at(static_cast<int>(i))); |
| } |
| |
| Handle<T> operator[](size_t i) const { return at(i); } |
| |
| void insert(Handle<T> handle, Zone* zone) { |
| T** const value = bit_cast<T**>(handle.address()); |
| DCHECK(IsAligned(bit_cast<intptr_t>(value), kPointerAlignment)); |
| if ((data_ & kTagMask) == kEmptyTag) { |
| data_ = bit_cast<intptr_t>(value) | kSingletonTag; |
| } else if ((data_ & kTagMask) == kSingletonTag) { |
| if (singleton() == value) return; |
| List* list = new (zone->New(sizeof(List))) List(zone); |
| if (singleton() < value) { |
| list->push_back(singleton()); |
| list->push_back(value); |
| } else { |
| list->push_back(value); |
| list->push_back(singleton()); |
| } |
| DCHECK(IsAligned(bit_cast<intptr_t>(list), kPointerAlignment)); |
| data_ = bit_cast<intptr_t>(list) | kListTag; |
| } else { |
| DCHECK_EQ(kListTag, data_ & kTagMask); |
| List const* const old_list = list(); |
| for (size_t i = 0; i < old_list->size(); ++i) { |
| if (old_list->at(i) == value) return; |
| if (old_list->at(i) > value) break; |
| } |
| List* new_list = new (zone->New(sizeof(List))) List(zone); |
| new_list->reserve(old_list->size() + 1); |
| size_t i = 0; |
| for (; i < old_list->size(); ++i) { |
| if (old_list->at(i) > value) break; |
| new_list->push_back(old_list->at(i)); |
| } |
| new_list->push_back(value); |
| for (; i < old_list->size(); ++i) { |
| new_list->push_back(old_list->at(i)); |
| } |
| DCHECK_EQ(old_list->size() + 1, new_list->size()); |
| DCHECK(IsAligned(bit_cast<intptr_t>(new_list), kPointerAlignment)); |
| data_ = bit_cast<intptr_t>(new_list) | kListTag; |
| } |
| } |
| |
| bool contains(ZoneHandleSet<T> const& other) const { |
| if (data_ == other.data_) return true; |
| if (data_ == kEmptyTag) return false; |
| if (other.data_ == kEmptyTag) return true; |
| if ((data_ & kTagMask) == kSingletonTag) return false; |
| DCHECK_EQ(kListTag, data_ & kTagMask); |
| List const* cached_list = list(); |
| if ((other.data_ & kTagMask) == kSingletonTag) { |
| return std::find(cached_list->begin(), cached_list->end(), |
| other.singleton()) != cached_list->end(); |
| } |
| DCHECK_EQ(kListTag, other.data_ & kTagMask); |
| // TODO(bmeurer): Optimize this case. |
| for (size_t i = 0; i < other.list()->size(); ++i) { |
| if (std::find(cached_list->begin(), cached_list->end(), |
| other.list()->at(i)) == cached_list->end()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool contains(Handle<T> other) const { |
| if (data_ == kEmptyTag) return false; |
| if ((data_ & kTagMask) == kSingletonTag) { |
| return singleton() == bit_cast<T**>(other.address()); |
| } |
| DCHECK_EQ(kListTag, data_ & kTagMask); |
| return std::find(list()->begin(), list()->end(), |
| bit_cast<T**>(other.address())) != list()->end(); |
| } |
| |
| void remove(Handle<T> handle, Zone* zone) { |
| // TODO(bmeurer): Optimize this case. |
| ZoneHandleSet<T> that; |
| for (size_t i = 0; i < size(); ++i) { |
| Handle<T> value = at(i); |
| if (value.address() != handle.address()) { |
| that.insert(value, zone); |
| } |
| } |
| std::swap(*this, that); |
| } |
| |
| friend bool operator==(ZoneHandleSet<T> const& lhs, |
| ZoneHandleSet<T> const& rhs) { |
| if (lhs.data_ == rhs.data_) return true; |
| if ((lhs.data_ & kTagMask) == kListTag && |
| (rhs.data_ & kTagMask) == kListTag) { |
| List const* const lhs_list = lhs.list(); |
| List const* const rhs_list = rhs.list(); |
| if (lhs_list->size() == rhs_list->size()) { |
| for (size_t i = 0; i < lhs_list->size(); ++i) { |
| if (lhs_list->at(i) != rhs_list->at(i)) return false; |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| friend bool operator!=(ZoneHandleSet<T> const& lhs, |
| ZoneHandleSet<T> const& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| friend size_t hash_value(ZoneHandleSet<T> const& set) { |
| return static_cast<size_t>(set.data_); |
| } |
| |
| class const_iterator; |
| inline const_iterator begin() const; |
| inline const_iterator end() const; |
| |
| private: |
| typedef ZoneVector<T**> List; |
| |
| List const* list() const { |
| DCHECK_EQ(kListTag, data_ & kTagMask); |
| return bit_cast<List const*>(data_ - kListTag); |
| } |
| |
| T** singleton() const { |
| DCHECK_EQ(kSingletonTag, data_ & kTagMask); |
| return bit_cast<T**>(data_ - kSingletonTag); |
| } |
| |
| enum Tag : intptr_t { |
| kSingletonTag = 0, |
| kEmptyTag = 1, |
| kListTag = 2, |
| kTagMask = 3 |
| }; |
| |
| STATIC_ASSERT(kTagMask < kPointerAlignment); |
| |
| intptr_t data_; |
| }; |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, ZoneHandleSet<T> set) { |
| for (size_t i = 0; i < set.size(); ++i) { |
| if (i > 0) os << ", "; |
| os << set.at(i); |
| } |
| return os; |
| } |
| |
| template <typename T> |
| class ZoneHandleSet<T>::const_iterator { |
| public: |
| typedef std::forward_iterator_tag iterator_category; |
| typedef std::ptrdiff_t difference_type; |
| typedef Handle<T> value_type; |
| |
| const_iterator(const const_iterator& other) |
| : set_(other.set_), current_(other.current_) {} |
| |
| Handle<T> operator*() const { return (*set_)[current_]; } |
| bool operator==(const const_iterator& other) const { |
| return set_ == other.set_ && current_ == other.current_; |
| } |
| bool operator!=(const const_iterator& other) const { |
| return !(*this == other); |
| } |
| const_iterator& operator++() { |
| DCHECK(current_ < set_->size()); |
| current_ += 1; |
| return *this; |
| } |
| const_iterator operator++(int); |
| |
| private: |
| friend class ZoneHandleSet<T>; |
| |
| explicit const_iterator(const ZoneHandleSet<T>* set, size_t current) |
| : set_(set), current_(current) {} |
| |
| const ZoneHandleSet<T>* set_; |
| size_t current_; |
| }; |
| |
| template <typename T> |
| typename ZoneHandleSet<T>::const_iterator ZoneHandleSet<T>::begin() const { |
| return ZoneHandleSet<T>::const_iterator(this, 0); |
| } |
| |
| template <typename T> |
| typename ZoneHandleSet<T>::const_iterator ZoneHandleSet<T>::end() const { |
| return ZoneHandleSet<T>::const_iterator(this, size()); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_ZONE_ZONE_HANDLE_SET_H_ |