@@ -28,11 +28,7 @@ class AddressRange {
2828 uint64_t start () const { return Start; }
2929 uint64_t end () const { return End; }
3030 uint64_t size () const { return End - Start; }
31- uint64_t empty () const { return size () == 0 ; }
3231 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- }
3632 bool intersects (const AddressRange &R) const {
3733 return Start < R.End && R.Start < End;
3834 }
@@ -49,163 +45,101 @@ class AddressRange {
4945 uint64_t End = 0 ;
5046};
5147
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 {
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 {
5955protected:
60- using Collection = SmallVector<T >;
56+ using Collection = SmallVector<AddressRange >;
6157 Collection Ranges;
6258
6359public:
6460 void clear () { Ranges.clear (); }
6561 bool empty () const { return Ranges.empty (); }
66- bool contains (uint64_t Addr) const {
67- return find (Addr, Addr + 1 ) != Ranges.end ();
68- }
62+ bool contains (uint64_t Addr) const { return find (Addr) != Ranges.end (); }
6963 bool contains (AddressRange Range) const {
70- return find (Range. start (), Range. end () ) != Ranges.end ();
64+ return find (Range) != Ranges.end ();
7165 }
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 );
66+ std::optional<AddressRange> getRangeThatContains (uint64_t Addr) const {
67+ Collection::const_iterator It = find (Addr);
7768 if (It == Ranges.end ())
7869 return std::nullopt;
7970
8071 return *It;
8172 }
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 {
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 {
8780 assert (i < Ranges.size ());
8881 return Ranges[i];
8982 }
90-
91- bool operator ==(const AddressRangesBase<T> &RHS) const {
92- return Ranges == RHS.Ranges ;
93- }
83+ Collection::const_iterator begin () const { return Ranges.begin (); }
84+ Collection::const_iterator end () const { return Ranges.end (); }
9485
9586protected:
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- }
87+ Collection::const_iterator find (uint64_t Addr) const ;
88+ Collection::const_iterator find (AddressRange Range) const ;
11489};
11590
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> {
122- public:
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);
142- }
143- };
144-
145- class AddressRangeValuePair {
146- public:
147- operator AddressRange () const { return Range; }
148-
149- AddressRange Range;
150- int64_t Value = 0 ;
151- };
152-
153- inline bool operator ==(const AddressRangeValuePair &LHS,
154- const AddressRangeValuePair &RHS) {
155- return LHS.Range == RHS.Range && LHS.Value == RHS.Value ;
156- }
157-
15891// / 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> {
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 {
16696public:
167- void insert (AddressRange Range, int64_t Value) {
168- if (Range.empty ())
97+ void clear () {
98+ Ranges.clear ();
99+ Values.clear ();
100+ }
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 ())
169110 return ;
170111
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- }
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;
208123 }
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;
133+
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+ }
139+
140+ protected:
141+ using ValuesCollection = SmallVector<T>;
142+ ValuesCollection Values;
209143};
210144
211145} // namespace llvm
0 commit comments