1 //===--------- interval_map.h - A sorted interval map -----------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Implements a coalescing interval map.
11 //===----------------------------------------------------------------------===//
13 #ifndef ORC_RT_INTERVAL_MAP_H
14 #define ORC_RT_INTERVAL_MAP_H
22 enum class IntervalCoalescing
{ Enabled
, Disabled
};
24 /// Maps intervals to keys with optional coalescing.
26 /// NOTE: The interface is kept mostly compatible with LLVM's IntervalMap
27 /// collection to make it easy to swap over in the future if we choose
29 template <typename KeyT
, typename ValT
> class IntervalMapBase
{
31 using KeyPairT
= std::pair
<KeyT
, KeyT
>;
34 using is_transparent
= std::true_type
;
35 bool operator()(const KeyPairT
&LHS
, const KeyPairT
&RHS
) const {
38 bool operator()(const KeyPairT
&LHS
, const KeyT
&RHS
) const {
39 return LHS
.first
< RHS
;
41 bool operator()(const KeyT
&LHS
, const KeyPairT
&RHS
) const {
42 return LHS
< RHS
.first
;
46 using ImplMap
= std::map
<KeyPairT
, ValT
, Compare
>;
49 using iterator
= typename
ImplMap::iterator
;
50 using const_iterator
= typename
ImplMap::const_iterator
;
51 using size_type
= typename
ImplMap::size_type
;
53 bool empty() const { return Impl
.empty(); }
55 void clear() { Impl
.clear(); }
57 iterator
begin() { return Impl
.begin(); }
58 iterator
end() { return Impl
.end(); }
60 const_iterator
begin() const { return Impl
.begin(); }
61 const_iterator
end() const { return Impl
.end(); }
63 iterator
find(KeyT K
) {
64 // Early out if the key is clearly outside the range.
65 if (empty() || K
< begin()->first
.first
||
66 K
>= std::prev(end())->first
.second
)
69 auto I
= Impl
.upper_bound(K
);
70 assert(I
!= begin() && "Should have hit early out above");
72 if (K
< I
->first
.second
)
77 const_iterator
find(KeyT K
) const {
78 return const_cast<IntervalMapBase
<KeyT
, ValT
> *>(this)->find(K
);
81 ValT
lookup(KeyT K
, ValT NotFound
= ValT()) const {
88 // Erase [KS, KE), which must be entirely containing within one existing
89 // range in the map. Removal is allowed to split the range.
90 void erase(KeyT KS
, KeyT KE
) {
94 auto J
= Impl
.upper_bound(KS
);
96 // Check previous range. Bail out if range to remove is entirely after
98 auto I
= std::prev(J
);
99 if (KS
>= I
->first
.second
)
102 // Assert that range is wholly contained.
103 assert(KE
<= I
->first
.second
);
105 auto Tmp
= std::move(*I
);
108 // Split-right -- introduce right-split range.
109 if (KE
< Tmp
.first
.second
) {
111 J
, std::make_pair(std::make_pair(KE
, Tmp
.first
.second
), Tmp
.second
));
115 // Split-left -- introduce left-split range.
116 if (KS
> Tmp
.first
.first
)
118 J
, std::make_pair(std::make_pair(Tmp
.first
.first
, KS
), Tmp
.second
));
125 template <typename KeyT
, typename ValT
, IntervalCoalescing Coalescing
>
128 template <typename KeyT
, typename ValT
>
129 class IntervalMap
<KeyT
, ValT
, IntervalCoalescing::Enabled
>
130 : public IntervalMapBase
<KeyT
, ValT
> {
132 // Coalescing insert. Requires that ValTs be equality-comparable.
133 void insert(KeyT KS
, KeyT KE
, ValT V
) {
134 auto J
= this->Impl
.upper_bound(KS
);
136 // Coalesce-right if possible. Either way, J points at our insertion
138 if (J
!= this->end() && KE
== J
->first
.first
&& J
->second
== V
) {
139 KE
= J
->first
.second
;
141 this->Impl
.erase(Tmp
);
144 // Coalesce-left if possible.
145 if (J
!= this->begin()) {
146 auto I
= std::prev(J
);
147 if (I
->first
.second
== KS
&& I
->second
== V
) {
152 this->Impl
.insert(J
, std::make_pair(std::make_pair(KS
, KE
), std::move(V
)));
156 template <typename KeyT
, typename ValT
>
157 class IntervalMap
<KeyT
, ValT
, IntervalCoalescing::Disabled
>
158 : public IntervalMapBase
<KeyT
, ValT
> {
160 // Non-coalescing insert. Does not require ValT to be equality-comparable.
161 void insert(KeyT KS
, KeyT KE
, ValT V
) {
162 this->Impl
.insert(std::make_pair(std::make_pair(KS
, KE
), std::move(V
)));
166 } // End namespace __orc_rt
168 #endif // ORC_RT_INTERVAL_MAP_H