/* * Copyright (C) 2015-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include namespace WTF { template struct KeyValuePair; // IndexSparseSet is an efficient set of integers that can only be valued // between zero and size() - 1. // // The implementation is using Briggs Sparse Set representation. We allocate // memory from 0 to size() - 1 to do mapping in O(1), but we never initialize // that memory. When adding/removing values to the set, they are added in a list // and the corresponding bucket is initialized to the position in the list. // // The assumption here is that we only need a sparse subset of number live at any // time. template struct DefaultIndexSparseSetTraits { typedef T EntryType; static T create(unsigned entry) { return entry; } static unsigned key(const T& entry) { return entry; } }; template struct DefaultIndexSparseSetTraits> { typedef KeyValuePair EntryType; template static EntryType create(unsigned key, PassedValueType&& value) { return EntryType(key, std::forward(value)); } static unsigned key(const EntryType& entry) { return entry.key; } }; template, typename OverflowHandler = CrashOnOverflow> class IndexSparseSet { WTF_MAKE_FAST_ALLOCATED; typedef Vector ValueList; public: explicit IndexSparseSet(unsigned size); template bool add(unsigned, Arguments&&...); template bool set(unsigned, Arguments&&...); bool remove(unsigned); void clear(); unsigned size() const; bool isEmpty() const; bool contains(unsigned) const; const EntryType* get(unsigned) const; EntryType* get(unsigned); typedef typename ValueList::const_iterator const_iterator; const_iterator begin() const; const_iterator end() const; void sort(); void validate(); const ValueList& values() const { return m_values; } private: Vector m_map; ValueList m_values; }; template inline IndexSparseSet::IndexSparseSet(unsigned size) { m_map.grow(size); } template template inline bool IndexSparseSet::add(unsigned value, Arguments&&... arguments) { if (contains(value)) return false; unsigned newPosition = m_values.size(); m_values.append(EntryTypeTraits::create(value, std::forward(arguments)...)); m_map[value] = newPosition; return true; } template template inline bool IndexSparseSet::set(unsigned value, Arguments&&... arguments) { if (EntryType* entry = get(value)) { *entry = EntryTypeTraits::create(value, std::forward(arguments)...); return false; } unsigned newPosition = m_values.size(); m_values.append(EntryTypeTraits::create(value, std::forward(arguments)...)); m_map[value] = newPosition; return true; } template inline bool IndexSparseSet::remove(unsigned value) { unsigned position = m_map[value]; if (position >= m_values.size()) return false; if (EntryTypeTraits::key(m_values[position]) == value) { EntryType lastValue = m_values.last(); m_values[position] = WTFMove(lastValue); m_map[EntryTypeTraits::key(lastValue)] = position; m_values.removeLast(); return true; } return false; } template void IndexSparseSet::clear() { m_values.shrink(0); } template unsigned IndexSparseSet::size() const { return m_values.size(); } template bool IndexSparseSet::isEmpty() const { return !size(); } template bool IndexSparseSet::contains(unsigned value) const { unsigned position = m_map[value]; if (position >= m_values.size()) return false; return EntryTypeTraits::key(m_values[position]) == value; } template auto IndexSparseSet::get(unsigned value) -> EntryType* { unsigned position = m_map[value]; if (position >= m_values.size()) return nullptr; EntryType& entry = m_values[position]; if (EntryTypeTraits::key(entry) != value) return nullptr; return &entry; } template auto IndexSparseSet::get(unsigned value) const -> const EntryType* { return const_cast(this)->get(value); } template void IndexSparseSet::sort() { std::sort( m_values.begin(), m_values.end(), [&] (const EntryType& a, const EntryType& b) { return EntryTypeTraits::key(a) < EntryTypeTraits::key(b); }); // Bring m_map back in sync with m_values for (unsigned index = 0; index < m_values.size(); ++index) { unsigned key = EntryTypeTraits::key(m_values[index]); m_map[key] = index; } #if ASSERT_ENABLED validate(); #endif } template void IndexSparseSet::validate() { RELEASE_ASSERT(m_values.size() <= m_map.size()); for (const EntryType& entry : *this) RELEASE_ASSERT(contains(EntryTypeTraits::key(entry))); } template auto IndexSparseSet::begin() const -> const_iterator { return m_values.begin(); } template auto IndexSparseSet::end() const -> const_iterator { return m_values.end(); } } // namespace WTF using WTF::DefaultIndexSparseSetTraits; using WTF::IndexSparseSet;