xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/orc/interval_map.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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