1*810390e3Srobert //===--------- interval_map.h - A sorted interval map -----------*- C++ -*-===// 2*810390e3Srobert // 3*810390e3Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*810390e3Srobert // See https://llvm.org/LICENSE.txt for license information. 5*810390e3Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*810390e3Srobert // 7*810390e3Srobert //===----------------------------------------------------------------------===// 8*810390e3Srobert // 9*810390e3Srobert // Implements a coalescing interval map. 10*810390e3Srobert // 11*810390e3Srobert //===----------------------------------------------------------------------===// 12*810390e3Srobert 13*810390e3Srobert #ifndef ORC_RT_INTERVAL_MAP_H 14*810390e3Srobert #define ORC_RT_INTERVAL_MAP_H 15*810390e3Srobert 16*810390e3Srobert #include "adt.h" 17*810390e3Srobert #include <cassert> 18*810390e3Srobert #include <map> 19*810390e3Srobert 20*810390e3Srobert namespace __orc_rt { 21*810390e3Srobert 22*810390e3Srobert enum class IntervalCoalescing { Enabled, Disabled }; 23*810390e3Srobert 24*810390e3Srobert /// Maps intervals to keys with optional coalescing. 25*810390e3Srobert /// 26*810390e3Srobert /// NOTE: The interface is kept mostly compatible with LLVM's IntervalMap 27*810390e3Srobert /// collection to make it easy to swap over in the future if we choose 28*810390e3Srobert /// to. 29*810390e3Srobert template <typename KeyT, typename ValT> class IntervalMapBase { 30*810390e3Srobert private: 31*810390e3Srobert using KeyPairT = std::pair<KeyT, KeyT>; 32*810390e3Srobert 33*810390e3Srobert struct Compare { 34*810390e3Srobert using is_transparent = std::true_type; operatorCompare35*810390e3Srobert bool operator()(const KeyPairT &LHS, const KeyPairT &RHS) const { 36*810390e3Srobert return LHS < RHS; 37*810390e3Srobert } operatorCompare38*810390e3Srobert bool operator()(const KeyPairT &LHS, const KeyT &RHS) const { 39*810390e3Srobert return LHS.first < RHS; 40*810390e3Srobert } operatorCompare41*810390e3Srobert bool operator()(const KeyT &LHS, const KeyPairT &RHS) const { 42*810390e3Srobert return LHS < RHS.first; 43*810390e3Srobert } 44*810390e3Srobert }; 45*810390e3Srobert 46*810390e3Srobert using ImplMap = std::map<KeyPairT, ValT, Compare>; 47*810390e3Srobert 48*810390e3Srobert public: 49*810390e3Srobert using iterator = typename ImplMap::iterator; 50*810390e3Srobert using const_iterator = typename ImplMap::const_iterator; 51*810390e3Srobert using size_type = typename ImplMap::size_type; 52*810390e3Srobert empty()53*810390e3Srobert bool empty() const { return Impl.empty(); } 54*810390e3Srobert clear()55*810390e3Srobert void clear() { Impl.clear(); } 56*810390e3Srobert begin()57*810390e3Srobert iterator begin() { return Impl.begin(); } end()58*810390e3Srobert iterator end() { return Impl.end(); } 59*810390e3Srobert begin()60*810390e3Srobert const_iterator begin() const { return Impl.begin(); } end()61*810390e3Srobert const_iterator end() const { return Impl.end(); } 62*810390e3Srobert find(KeyT K)63*810390e3Srobert iterator find(KeyT K) { 64*810390e3Srobert // Early out if the key is clearly outside the range. 65*810390e3Srobert if (empty() || K < begin()->first.first || 66*810390e3Srobert K >= std::prev(end())->first.second) 67*810390e3Srobert return end(); 68*810390e3Srobert 69*810390e3Srobert auto I = Impl.upper_bound(K); 70*810390e3Srobert assert(I != begin() && "Should have hit early out above"); 71*810390e3Srobert I = std::prev(I); 72*810390e3Srobert if (K < I->first.second) 73*810390e3Srobert return I; 74*810390e3Srobert return end(); 75*810390e3Srobert } 76*810390e3Srobert find(KeyT K)77*810390e3Srobert const_iterator find(KeyT K) const { 78*810390e3Srobert return const_cast<IntervalMapBase<KeyT, ValT> *>(this)->find(K); 79*810390e3Srobert } 80*810390e3Srobert 81*810390e3Srobert ValT lookup(KeyT K, ValT NotFound = ValT()) const { 82*810390e3Srobert auto I = find(K); 83*810390e3Srobert if (I == end()) 84*810390e3Srobert return NotFound; 85*810390e3Srobert return I->second; 86*810390e3Srobert } 87*810390e3Srobert 88*810390e3Srobert // Erase [KS, KE), which must be entirely containing within one existing 89*810390e3Srobert // range in the map. Removal is allowed to split the range. erase(KeyT KS,KeyT KE)90*810390e3Srobert void erase(KeyT KS, KeyT KE) { 91*810390e3Srobert if (empty()) 92*810390e3Srobert return; 93*810390e3Srobert 94*810390e3Srobert auto J = Impl.upper_bound(KS); 95*810390e3Srobert 96*810390e3Srobert // Check previous range. Bail out if range to remove is entirely after 97*810390e3Srobert // it. 98*810390e3Srobert auto I = std::prev(J); 99*810390e3Srobert if (KS >= I->first.second) 100*810390e3Srobert return; 101*810390e3Srobert 102*810390e3Srobert // Assert that range is wholly contained. 103*810390e3Srobert assert(KE <= I->first.second); 104*810390e3Srobert 105*810390e3Srobert auto Tmp = std::move(*I); 106*810390e3Srobert Impl.erase(I); 107*810390e3Srobert 108*810390e3Srobert // Split-right -- introduce right-split range. 109*810390e3Srobert if (KE < Tmp.first.second) { 110*810390e3Srobert Impl.insert( 111*810390e3Srobert J, std::make_pair(std::make_pair(KE, Tmp.first.second), Tmp.second)); 112*810390e3Srobert J = std::prev(J); 113*810390e3Srobert } 114*810390e3Srobert 115*810390e3Srobert // Split-left -- introduce left-split range. 116*810390e3Srobert if (KS > Tmp.first.first) 117*810390e3Srobert Impl.insert( 118*810390e3Srobert J, std::make_pair(std::make_pair(Tmp.first.first, KS), Tmp.second)); 119*810390e3Srobert } 120*810390e3Srobert 121*810390e3Srobert protected: 122*810390e3Srobert ImplMap Impl; 123*810390e3Srobert }; 124*810390e3Srobert 125*810390e3Srobert template <typename KeyT, typename ValT, IntervalCoalescing Coalescing> 126*810390e3Srobert class IntervalMap; 127*810390e3Srobert 128*810390e3Srobert template <typename KeyT, typename ValT> 129*810390e3Srobert class IntervalMap<KeyT, ValT, IntervalCoalescing::Enabled> 130*810390e3Srobert : public IntervalMapBase<KeyT, ValT> { 131*810390e3Srobert public: 132*810390e3Srobert // Coalescing insert. Requires that ValTs be equality-comparable. insert(KeyT KS,KeyT KE,ValT V)133*810390e3Srobert void insert(KeyT KS, KeyT KE, ValT V) { 134*810390e3Srobert auto J = this->Impl.upper_bound(KS); 135*810390e3Srobert 136*810390e3Srobert // Coalesce-right if possible. Either way, J points at our insertion 137*810390e3Srobert // point. 138*810390e3Srobert if (J != this->end() && KE == J->first.first && J->second == V) { 139*810390e3Srobert KE = J->first.second; 140*810390e3Srobert auto Tmp = J++; 141*810390e3Srobert this->Impl.erase(Tmp); 142*810390e3Srobert } 143*810390e3Srobert 144*810390e3Srobert // Coalesce-left if possible. 145*810390e3Srobert if (J != this->begin()) { 146*810390e3Srobert auto I = std::prev(J); 147*810390e3Srobert if (I->first.second == KS && I->second == V) { 148*810390e3Srobert KS = I->first.first; 149*810390e3Srobert this->Impl.erase(I); 150*810390e3Srobert } 151*810390e3Srobert } 152*810390e3Srobert this->Impl.insert(J, std::make_pair(std::make_pair(KS, KE), std::move(V))); 153*810390e3Srobert } 154*810390e3Srobert }; 155*810390e3Srobert 156*810390e3Srobert template <typename KeyT, typename ValT> 157*810390e3Srobert class IntervalMap<KeyT, ValT, IntervalCoalescing::Disabled> 158*810390e3Srobert : public IntervalMapBase<KeyT, ValT> { 159*810390e3Srobert public: 160*810390e3Srobert // Non-coalescing insert. Does not require ValT to be equality-comparable. insert(KeyT KS,KeyT KE,ValT V)161*810390e3Srobert void insert(KeyT KS, KeyT KE, ValT V) { 162*810390e3Srobert this->Impl.insert(std::make_pair(std::make_pair(KS, KE), std::move(V))); 163*810390e3Srobert } 164*810390e3Srobert }; 165*810390e3Srobert 166*810390e3Srobert } // End namespace __orc_rt 167*810390e3Srobert 168*810390e3Srobert #endif // ORC_RT_INTERVAL_MAP_H 169