//===--- BlotSetVector.h ----------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_BLOTSETVECTOR_H #define SWIFT_BASIC_BLOTSETVECTOR_H #include "swift/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include namespace swift { /// This is a set container with the following properties: /// /// 1. Fast insertion-order iteration. /// /// 2. Stable index offsets for all values after all operations including /// erase. /// /// This contrasts with SetVector where index offsets are not stable due to /// usage of std::vector::erase(). In contrast, BlotSetVector uses the `blot /// operation' (a) which trades memory for runtime and index offset stability. /// /// 3. Fast replacement of a value v1 with a second value v2 guaranteeing that /// v2 is placed into the same array index as v1, just deleting v1 if v2 is /// already in the array. /// /// This is important if one has other data structures referring to v1 via v1's /// index in the vector that one wishes to now refer to v2. /// /// 4. Fast deletion via the 'blot' operation. /// /// 5. Fast insertion. /// /// (a) The `blot operation' is leaving the value in the set vector, but marking /// the value as being dead. template >, typename MapT = llvm::DenseMap> class BlotSetVector { VectorT Vector; MapT Map; public: /// \brief Construct an empty BlotSetVector. BlotSetVector() {} bool empty() const { return Vector.empty(); } unsigned size() const { return Vector.size(); } using iterator = typename VectorT::iterator; using const_iterator = typename VectorT::const_iterator; iterator begin() { return Vector.begin(); } iterator end() { return Vector.end(); } const_iterator begin() const { return Vector.begin(); } const_iterator end() const { return Vector.end(); } llvm::iterator_range getRange() const { return {begin(), end()}; } using const_reverse_iterator = typename VectorT::const_reverse_iterator; const_reverse_iterator rbegin() const { return Vector.rbegin(); } const_reverse_iterator rend() const { return Vector.rend(); } llvm::iterator_range getReverseRange() const { return {rbegin(), rend()}; } const Optional &operator[](unsigned n) const { assert(n < Vector.size() && "Out of range!"); return Vector[n]; } /// Insert \p V into the SetVector if it is not in the array and return the /// index of \p V in the Set Vector. If \p V is already in the SetVector, just /// return its index in the array. unsigned insert(const ValueT &V) { auto Iter = Map.find(V); if (Iter != Map.end()) return Iter->second; unsigned Index = Vector.size(); Map[V] = Index; Vector.push_back(V); return Index; } /// Replace \p V1 with \p V2 placing \p V2 into the position in the array /// where V1 used to be. If \p V2 is already in the set, this just erases \p /// V1. void replace(const ValueT &V1, const ValueT &V2) { auto Iter1 = Map.find(V1); assert(Iter1 != Map.end() && "Cannot replace value that is not in set"); unsigned V1Index = Iter1->second; Map.erase(V1); auto Iter2 = Map.find(V2); if (Iter2 != Map.end()) { Vector[V1Index] = None; return; } Map[V2] = V1Index; Vector[V1Index] = V2; } /// Erase the value \p V if it is in the set. Returns true if V was /// successfully erased and false otherwise. bool erase(const ValueT &V) { auto Iter = Map.find(V); if (Iter == Map.end()) return false; unsigned Index = Iter->second; Map.erase(V); Vector[Index] = None; return true; } /// Attempt to lookup the index of \p V. Returns None upon failure and the /// value on success. Optional getIndex(const ValueT &V) { auto Iter = Map.find(V); if (Iter == Map.end()) return None; return Iter->second; } }; template , N>, typename MapT = llvm::SmallDenseMap> class SmallBlotSetVector : public BlotSetVector { public: SmallBlotSetVector() {} }; } // end swift namespace #endif // SWIFT_BASIC_BLOTSETVECTOR_H