@@ -28,7 +28,11 @@ class AddressRange {
28
28
uint64_t start () const { return Start; }
29
29
uint64_t end () const { return End; }
30
30
uint64_t size () const { return End - Start; }
31
+ uint64_t empty () const { return size () == 0 ; }
31
32
bool contains (uint64_t Addr) const { return Start <= Addr && Addr < End; }
33
+ bool contains (const AddressRange &R) const {
34
+ return Start <= R.Start && R.End <= End;
35
+ }
32
36
bool intersects (const AddressRange &R) const {
33
37
return Start < R.End && R.Start < End;
34
38
}
@@ -45,101 +49,163 @@ class AddressRange {
45
49
uint64_t End = 0 ;
46
50
};
47
51
48
- // / The AddressRanges class helps normalize address range collections.
49
- // / This class keeps a sorted vector of AddressRange objects and can perform
50
- // / insertions and searches efficiently. The address ranges are always sorted
51
- // / and never contain any invalid or empty address ranges.
52
- // / Intersecting([100,200), [150,300)) and adjacent([100,200), [200,300))
53
- // / address ranges are combined during insertion.
54
- class AddressRanges {
52
+ // / The AddressRangesBase class presents the base functionality for the
53
+ // / normalized address ranges collection. This class keeps a sorted vector
54
+ // / of AddressRange-like objects and can perform searches efficiently.
55
+ // / The address ranges are always sorted and never contain any invalid,
56
+ // / empty or intersected address ranges.
57
+
58
+ template < typename T> class AddressRangesBase {
55
59
protected:
56
- using Collection = SmallVector<AddressRange >;
60
+ using Collection = SmallVector<T >;
57
61
Collection Ranges;
58
62
59
63
public:
60
64
void clear () { Ranges.clear (); }
61
65
bool empty () const { return Ranges.empty (); }
62
- bool contains (uint64_t Addr) const { return find (Addr) != Ranges.end (); }
66
+ bool contains (uint64_t Addr) const {
67
+ return find (Addr, Addr + 1 ) != Ranges.end ();
68
+ }
63
69
bool contains (AddressRange Range) const {
64
- return find (Range) != Ranges.end ();
70
+ return find (Range. start (), Range. end () ) != Ranges.end ();
65
71
}
66
- std::optional<AddressRange> getRangeThatContains (uint64_t Addr) const {
67
- Collection::const_iterator It = find (Addr);
72
+ void reserve (size_t Capacity) { Ranges.reserve (Capacity); }
73
+ size_t size () const { return Ranges.size (); }
74
+
75
+ std::optional<T> getRangeThatContains (uint64_t Addr) const {
76
+ typename Collection::const_iterator It = find (Addr, Addr + 1 );
68
77
if (It == Ranges.end ())
69
78
return std::nullopt;
70
79
71
80
return *It;
72
81
}
73
- Collection::const_iterator insert (AddressRange Range);
74
- void reserve (size_t Capacity) { Ranges.reserve (Capacity); }
75
- size_t size () const { return Ranges.size (); }
76
- bool operator ==(const AddressRanges &RHS) const {
77
- return Ranges == RHS.Ranges ;
78
- }
79
- const AddressRange &operator [](size_t i) const {
82
+
83
+ typename Collection::const_iterator begin () const { return Ranges.begin (); }
84
+ typename Collection::const_iterator end () const { return Ranges.end (); }
85
+
86
+ const T &operator [](size_t i) const {
80
87
assert (i < Ranges.size ());
81
88
return Ranges[i];
82
89
}
83
- Collection::const_iterator begin () const { return Ranges.begin (); }
84
- Collection::const_iterator end () const { return Ranges.end (); }
90
+
91
+ bool operator ==(const AddressRangesBase<T> &RHS) const {
92
+ return Ranges == RHS.Ranges ;
93
+ }
85
94
86
95
protected:
87
- Collection::const_iterator find (uint64_t Addr) const ;
88
- Collection::const_iterator find (AddressRange Range) const ;
96
+ typename Collection::const_iterator find (uint64_t Start, uint64_t End) const {
97
+ if (Start >= End)
98
+ return Ranges.end ();
99
+
100
+ auto It =
101
+ std::partition_point (Ranges.begin (), Ranges.end (), [=](const T &R) {
102
+ return AddressRange (R).start () <= Start;
103
+ });
104
+
105
+ if (It == Ranges.begin ())
106
+ return Ranges.end ();
107
+
108
+ --It;
109
+ if (End > AddressRange (*It).end ())
110
+ return Ranges.end ();
111
+
112
+ return It;
113
+ }
89
114
};
90
115
91
- // / AddressRangesMap class maps values to the address ranges.
92
- // / It keeps address ranges and corresponding values. If ranges
93
- // / are combined during insertion, then combined range keeps
94
- // / newly inserted value.
95
- template <typename T> class AddressRangesMap : protected AddressRanges {
116
+ // / The AddressRanges class helps normalize address range collections.
117
+ // / This class keeps a sorted vector of AddressRange objects and can perform
118
+ // / insertions and searches efficiently. Intersecting([100,200), [150,300))
119
+ // / and adjacent([100,200), [200,300)) address ranges are combined during
120
+ // / insertion.
121
+ class AddressRanges : public AddressRangesBase <AddressRange> {
96
122
public:
97
- void clear () {
98
- Ranges.clear ();
99
- Values.clear ();
123
+ Collection::const_iterator insert (AddressRange Range) {
124
+ if (Range.empty ())
125
+ return Ranges.end ();
126
+
127
+ auto It = llvm::upper_bound (Ranges, Range);
128
+ auto It2 = It;
129
+ while (It2 != Ranges.end () && It2->start () <= Range.end ())
130
+ ++It2;
131
+ if (It != It2) {
132
+ Range = {Range.start (), std::max (Range.end (), std::prev (It2)->end ())};
133
+ It = Ranges.erase (It, It2);
134
+ }
135
+ if (It != Ranges.begin () && Range.start () <= std::prev (It)->end ()) {
136
+ --It;
137
+ *It = {It->start (), std::max (It->end (), Range.end ())};
138
+ return It;
139
+ }
140
+
141
+ return Ranges.insert (It, Range);
100
142
}
101
- bool empty () const { return AddressRanges::empty (); }
102
- bool contains (uint64_t Addr) const { return AddressRanges::contains (Addr); }
103
- bool contains (AddressRange Range) const {
104
- return AddressRanges::contains (Range);
105
- }
106
- void insert (AddressRange Range, T Value) {
107
- size_t InputSize = Ranges.size ();
108
- Collection::const_iterator RangesIt = AddressRanges::insert (Range);
109
- if (RangesIt == Ranges.end ())
110
- return ;
143
+ };
111
144
112
- // make Values match to Ranges.
113
- size_t Idx = RangesIt - Ranges.begin ();
114
- typename ValuesCollection::iterator ValuesIt = Values.begin () + Idx;
115
- if (InputSize < Ranges.size ())
116
- Values.insert (ValuesIt, T ());
117
- else if (InputSize > Ranges.size ())
118
- Values.erase (ValuesIt, ValuesIt + InputSize - Ranges.size ());
119
- assert (Ranges.size () == Values.size ());
120
-
121
- // set value to the inserted or combined range.
122
- Values[Idx] = Value;
123
- }
124
- size_t size () const {
125
- assert (Ranges.size () == Values.size ());
126
- return AddressRanges::size ();
127
- }
128
- std::optional<std::pair<AddressRange, T>>
129
- getRangeValueThatContains (uint64_t Addr) const {
130
- Collection::const_iterator It = find (Addr);
131
- if (It == Ranges.end ())
132
- return std::nullopt;
145
+ class AddressRangeValuePair {
146
+ public:
147
+ operator AddressRange () const { return Range; }
133
148
134
- return std::make_pair (*It, Values[It - Ranges.begin ()]);
135
- }
136
- std::pair<AddressRange, T> operator [](size_t Idx) const {
137
- return std::make_pair (Ranges[Idx], Values[Idx]);
138
- }
149
+ AddressRange Range;
150
+ int64_t Value = 0 ;
151
+ };
139
152
140
- protected:
141
- using ValuesCollection = SmallVector<T>;
142
- ValuesCollection Values;
153
+ inline bool operator ==(const AddressRangeValuePair &LHS,
154
+ const AddressRangeValuePair &RHS) {
155
+ return LHS.Range == RHS.Range && LHS.Value == RHS.Value ;
156
+ }
157
+
158
+ // / AddressRangesMap class maps values to the address ranges.
159
+ // / It keeps normalized address ranges and corresponding values.
160
+ // / This class keeps a sorted vector of AddressRangeValuePair objects
161
+ // / and can perform insertions and searches efficiently.
162
+ // / Intersecting([100,200), [150,300)) ranges splitted into non-conflicting
163
+ // / parts([100,200), [200,300)). Adjacent([100,200), [200,300)) address
164
+ // / ranges are not combined during insertion.
165
+ class AddressRangesMap : public AddressRangesBase <AddressRangeValuePair> {
166
+ public:
167
+ void insert (AddressRange Range, int64_t Value) {
168
+ if (Range.empty ())
169
+ return ;
170
+
171
+ // Search for range which is less than or equal incoming Range.
172
+ auto It = std::partition_point (Ranges.begin (), Ranges.end (),
173
+ [=](const AddressRangeValuePair &R) {
174
+ return R.Range .start () <= Range.start ();
175
+ });
176
+
177
+ if (It != Ranges.begin ())
178
+ It--;
179
+
180
+ while (!Range.empty ()) {
181
+ // Inserted range does not overlap with any range.
182
+ // Store it into the Ranges collection.
183
+ if (It == Ranges.end () || Range.end () <= It->Range .start ()) {
184
+ Ranges.insert (It, {Range, Value});
185
+ return ;
186
+ }
187
+
188
+ // Inserted range partially overlaps with current range.
189
+ // Store not overlapped part of inserted range.
190
+ if (Range.start () < It->Range .start ()) {
191
+ It = Ranges.insert (It, {{Range.start (), It->Range .start ()}, Value});
192
+ It++;
193
+ Range = {It->Range .start (), Range.end ()};
194
+ continue ;
195
+ }
196
+
197
+ // Inserted range fully overlaps with current range.
198
+ if (Range.end () <= It->Range .end ())
199
+ return ;
200
+
201
+ // Inserted range partially overlaps with current range.
202
+ // Remove overlapped part from the inserted range.
203
+ if (Range.start () < It->Range .end ())
204
+ Range = {It->Range .end (), Range.end ()};
205
+
206
+ It++;
207
+ }
208
+ }
143
209
};
144
210
145
211
} // namespace llvm
0 commit comments