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