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