1*0b57cec5SDimitry Andric //===- ContinuousRangeMap.h - Map with int range as key ---------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines the ContinuousRangeMap class, which is a highly 10*0b57cec5SDimitry Andric // specialized container used by serialization. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H 15*0b57cec5SDimitry Andric #define LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 20*0b57cec5SDimitry Andric #include <algorithm> 21*0b57cec5SDimitry Andric #include <cassert> 22*0b57cec5SDimitry Andric #include <utility> 23*0b57cec5SDimitry Andric 24*0b57cec5SDimitry Andric namespace clang { 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric /// A map from continuous integer ranges to some value, with a very 27*0b57cec5SDimitry Andric /// specialized interface. 28*0b57cec5SDimitry Andric /// 29*0b57cec5SDimitry Andric /// CRM maps from integer ranges to values. The ranges are continuous, i.e. 30*0b57cec5SDimitry Andric /// where one ends, the next one begins. So if the map contains the stops I0-3, 31*0b57cec5SDimitry Andric /// the first range is from I0 to I1, the second from I1 to I2, the third from 32*0b57cec5SDimitry Andric /// I2 to I3 and the last from I3 to infinity. 33*0b57cec5SDimitry Andric /// 34*0b57cec5SDimitry Andric /// Ranges must be inserted in order. Inserting a new stop I4 into the map will 35*0b57cec5SDimitry Andric /// shrink the fourth range to I3 to I4 and add the new range I4 to inf. 36*0b57cec5SDimitry Andric template <typename Int, typename V, unsigned InitialCapacity> 37*0b57cec5SDimitry Andric class ContinuousRangeMap { 38*0b57cec5SDimitry Andric public: 39*0b57cec5SDimitry Andric using value_type = std::pair<Int, V>; 40*0b57cec5SDimitry Andric using reference = value_type &; 41*0b57cec5SDimitry Andric using const_reference = const value_type &; 42*0b57cec5SDimitry Andric using pointer = value_type *; 43*0b57cec5SDimitry Andric using const_pointer = const value_type *; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric private: 46*0b57cec5SDimitry Andric using Representation = SmallVector<value_type, InitialCapacity>; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric Representation Rep; 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric struct Compare { 51*0b57cec5SDimitry Andric bool operator ()(const_reference L, Int R) const { 52*0b57cec5SDimitry Andric return L.first < R; 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric bool operator ()(Int L, const_reference R) const { 55*0b57cec5SDimitry Andric return L < R.first; 56*0b57cec5SDimitry Andric } 57*0b57cec5SDimitry Andric bool operator ()(Int L, Int R) const { 58*0b57cec5SDimitry Andric return L < R; 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric bool operator ()(const_reference L, const_reference R) const { 61*0b57cec5SDimitry Andric return L.first < R.first; 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric }; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric public: 66*0b57cec5SDimitry Andric void insert(const value_type &Val) { 67*0b57cec5SDimitry Andric if (!Rep.empty() && Rep.back() == Val) 68*0b57cec5SDimitry Andric return; 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric assert((Rep.empty() || Rep.back().first < Val.first) && 71*0b57cec5SDimitry Andric "Must insert keys in order."); 72*0b57cec5SDimitry Andric Rep.push_back(Val); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void insertOrReplace(const value_type &Val) { 76*0b57cec5SDimitry Andric iterator I = llvm::lower_bound(Rep, Val, Compare()); 77*0b57cec5SDimitry Andric if (I != Rep.end() && I->first == Val.first) { 78*0b57cec5SDimitry Andric I->second = Val.second; 79*0b57cec5SDimitry Andric return; 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric Rep.insert(I, Val); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric using iterator = typename Representation::iterator; 86*0b57cec5SDimitry Andric using const_iterator = typename Representation::const_iterator; 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric iterator begin() { return Rep.begin(); } 89*0b57cec5SDimitry Andric iterator end() { return Rep.end(); } 90*0b57cec5SDimitry Andric const_iterator begin() const { return Rep.begin(); } 91*0b57cec5SDimitry Andric const_iterator end() const { return Rep.end(); } 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric iterator find(Int K) { 94*0b57cec5SDimitry Andric iterator I = llvm::upper_bound(Rep, K, Compare()); 95*0b57cec5SDimitry Andric // I points to the first entry with a key > K, which is the range that 96*0b57cec5SDimitry Andric // follows the one containing K. 97*0b57cec5SDimitry Andric if (I == Rep.begin()) 98*0b57cec5SDimitry Andric return Rep.end(); 99*0b57cec5SDimitry Andric --I; 100*0b57cec5SDimitry Andric return I; 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric const_iterator find(Int K) const { 103*0b57cec5SDimitry Andric return const_cast<ContinuousRangeMap*>(this)->find(K); 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric reference back() { return Rep.back(); } 107*0b57cec5SDimitry Andric const_reference back() const { return Rep.back(); } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric /// An object that helps properly build a continuous range map 110*0b57cec5SDimitry Andric /// from a set of values. 111*0b57cec5SDimitry Andric class Builder { 112*0b57cec5SDimitry Andric ContinuousRangeMap &Self; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric public: 115*0b57cec5SDimitry Andric explicit Builder(ContinuousRangeMap &Self) : Self(Self) {} 116*0b57cec5SDimitry Andric Builder(const Builder&) = delete; 117*0b57cec5SDimitry Andric Builder &operator=(const Builder&) = delete; 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric ~Builder() { 120*0b57cec5SDimitry Andric llvm::sort(Self.Rep, Compare()); 121*0b57cec5SDimitry Andric std::unique(Self.Rep.begin(), Self.Rep.end(), 122*0b57cec5SDimitry Andric [](const_reference A, const_reference B) { 123*0b57cec5SDimitry Andric // FIXME: we should not allow any duplicate keys, but there are a lot of 124*0b57cec5SDimitry Andric // duplicate 0 -> 0 mappings to remove first. 125*0b57cec5SDimitry Andric assert((A == B || A.first != B.first) && 126*0b57cec5SDimitry Andric "ContinuousRangeMap::Builder given non-unique keys"); 127*0b57cec5SDimitry Andric return A == B; 128*0b57cec5SDimitry Andric }); 129*0b57cec5SDimitry Andric } 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric void insert(const value_type &Val) { 132*0b57cec5SDimitry Andric Self.Rep.push_back(Val); 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric }; 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric friend class Builder; 137*0b57cec5SDimitry Andric }; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric } // namespace clang 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric #endif // LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H 142