RangeMap.h revision 61aca5dd78f07de66e997d41af521ab9d8c16b89
1//===-- RangeMap.h ----------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef liblldb_RangeMap_h_
11#define liblldb_RangeMap_h_
12
13#include "lldb/lldb-private.h"
14#include <vector>
15
16namespace lldb_private {
17
18    //----------------------------------------------------------------------
19    // Templatized classes for dealing with generic ranges and also
20    // collections of ranges, or collections of ranges that have associated
21    // data.
22    //----------------------------------------------------------------------
23
24    //----------------------------------------------------------------------
25    // A simple range class where you get to define the type of the range
26    // base "B", and the type used for the range byte size "S".
27    //----------------------------------------------------------------------
28    template <typename B, typename S>
29    struct Range
30    {
31        typedef B BaseType;
32        typedef S SizeType;
33
34        BaseType base;
35        SizeType size;
36
37        Range () :
38            base (0),
39            size (0)
40        {
41        }
42
43        Range (BaseType b, SizeType s) :
44            base (b),
45            size (s)
46        {
47        }
48
49        // Set the start value for the range, and keep the same size
50        BaseType
51        GetRangeBase () const
52        {
53            return base;
54        }
55
56        void
57        SetRangeBase (BaseType b)
58        {
59            base = b;
60        }
61
62        BaseType
63        GetRangeEnd () const
64        {
65            return base + size;
66        }
67
68        void
69        SetRangeEnd (BaseType end)
70        {
71            if (end > base)
72                size = end - base;
73            else
74                size = 0;
75        }
76
77        SizeType
78        GetByteSize () const
79        {
80            return size;
81        }
82
83        void
84        SetByteSize (SizeType s)
85        {
86            size = s;
87        }
88
89        bool
90        IsValid() const
91        {
92            return size > 0;
93        }
94
95        bool
96        Contains (BaseType r) const
97        {
98            return (GetRangeBase() <= r) && (r < GetRangeEnd());
99        }
100
101        bool
102        ContainsEndInclusive (BaseType r) const
103        {
104            return (GetRangeBase() <= r) && (r <= GetRangeEnd());
105        }
106
107        bool
108        Contains (const Range& range) const
109        {
110            return Contains(range.GetRangeBase()) && ContainsEndInclusive(range.GetRangeEnd());
111        }
112
113        bool
114        operator < (const Range &rhs)
115        {
116            if (base == rhs.base)
117                return size < rhs.size;
118            return base < rhs.base;
119        }
120
121        bool
122        operator == (const Range &rhs)
123        {
124            return base == rhs.base && size == rhs.size;
125        }
126
127        bool
128        operator != (const Range &rhs)
129        {
130            return  base != rhs.base || size != rhs.size;
131        }
132    };
133
134    //----------------------------------------------------------------------
135    // A range array class where you get to define the type of the ranges
136    // that the collection contains.
137    //----------------------------------------------------------------------
138
139    template <typename B, typename S>
140    class RangeArray
141    {
142        typedef Range<B,S> Entry;
143
144        RangeArray ()
145        {
146        }
147
148        ~RangeArray()
149        {
150        }
151
152        void
153        Append (const Entry &entry)
154        {
155            m_entries.push_back (entry);
156        }
157
158        void
159        Sort ()
160        {
161            if (m_entries.size() > 1)
162                std::stable_sort (m_entries.begin(), m_entries.end());
163        }
164
165        void
166        CombineConsecutiveEntriesWithEqualData ()
167        {
168            typename std::vector<Entry>::iterator pos;
169            typename std::vector<Entry>::iterator end;
170            typename std::vector<Entry>::iterator prev;
171            bool can_combine = false;
172            // First we determine if we can combine any of the Entry objects so we
173            // don't end up allocating and making a new collection for no reason
174            for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
175            {
176                if (prev != end && prev->data == pos->data)
177                {
178                    can_combine = true;
179                    break;
180                }
181            }
182
183            // We we can combine at least one entry, then we make a new collection
184            // and populate it accordingly, and then swap it into place.
185            if (can_combine)
186            {
187                std::vector<Entry> minimal_ranges;
188                for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
189                {
190                    if (prev != end && prev->data == pos->data)
191                        minimal_ranges.back().range.SetEnd (pos->range.GetRangeEnd());
192                    else
193                        minimal_ranges.push_back (*pos);
194                }
195                // Use the swap technique in case our new vector is much smaller.
196                // We must swap when using the STL because std::vector objects never
197                // release or reduce the memory once it has been allocated/reserved.
198                m_entries.swap (minimal_ranges);
199            }
200        }
201
202        void
203        Clear ()
204        {
205            m_entries.clear();
206        }
207
208        bool
209        IsEmpty () const
210        {
211            return m_entries.empty();
212        }
213
214        size_t
215        GetNumEntries () const
216        {
217            return m_entries.size();
218        }
219
220        const Entry *
221        GetEntryAtIndex (uint32_t i) const
222        {
223            if (i<m_entries.size())
224                return &m_entries[i];
225            return NULL;
226        }
227
228        static bool
229        BaseLessThan (const Entry& lhs, const Entry& rhs)
230        {
231            return lhs.GetRangeBase() < rhs.GetRangeBase();
232        }
233
234        const Entry *
235        FindEntryThatContains (B addr) const
236        {
237            if ( !m_entries.empty() )
238            {
239                Entry entry (addr, 1);
240                typename std::vector<Entry>::const_iterator begin = m_entries.begin();
241                typename std::vector<Entry>::const_iterator end = m_entries.end();
242                typename std::vector<Entry>::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
243
244                if (pos != end && pos->Contains(addr))
245                {
246                    return &(*pos);
247                }
248                else if (pos != begin)
249                {
250                    --pos;
251                    if (pos->Contains(addr))
252                    {
253                        return &(*pos);
254                    }
255                }
256            }
257            return NULL;
258        }
259
260    protected:
261        std::vector<Entry> m_entries;
262    };
263
264    //----------------------------------------------------------------------
265    // A simple range  with data class where you get to define the type of
266    // the range base "B", the type used for the range byte size "S", and
267    // the type for the associated data "T".
268    //----------------------------------------------------------------------
269    template <typename B, typename S, typename T>
270    struct RangeData : public Range<B,S>
271    {
272        typedef T DataType;
273
274        DataType data;
275
276        RangeData () :
277            Range<B,S> (),
278            data ()
279        {
280        }
281
282        RangeData (B base, S size, DataType d) :
283            Range<B,S> (base, size),
284            data (d)
285        {
286        }
287
288        bool
289        operator < (const RangeData &rhs) const
290        {
291            if (this->base == rhs.base)
292            {
293                if (this->size == rhs.size)
294                    return this->data < rhs.data;
295                else
296                    return this->size < rhs.size;
297            }
298            return this->base < rhs.base;
299        }
300
301        bool
302        operator == (const RangeData &rhs) const
303        {
304            return this->GetRangeBase() == rhs.GetRangeBase() &&
305                   this->GetByteSize() == rhs.GetByteSize() &&
306                   this->data      == rhs.data;
307        }
308
309        bool
310        operator != (const RangeData &rhs) const
311        {
312            return this->GetRangeBase() != rhs.GetRangeBase() ||
313                   this->GetByteSize() != rhs.GetByteSize() ||
314                   this->data      != rhs.data;
315        }
316    };
317
318    template <typename B, typename S, typename T>
319    class RangeDataArray
320    {
321    public:
322        typedef RangeData<B,S,T> Entry;
323
324        RangeDataArray ()
325        {
326        }
327
328        ~RangeDataArray()
329        {
330        }
331
332        void
333        Append (const Entry &entry)
334        {
335            m_entries.push_back (entry);
336        }
337
338        void
339        Sort ()
340        {
341            if (m_entries.size() > 1)
342                std::stable_sort (m_entries.begin(), m_entries.end());
343        }
344
345        void
346        CombineConsecutiveEntriesWithEqualData ()
347        {
348            typename std::vector<Entry>::iterator pos;
349            typename std::vector<Entry>::iterator end;
350            typename std::vector<Entry>::iterator prev;
351            bool can_combine = false;
352            // First we determine if we can combine any of the Entry objects so we
353            // don't end up allocating and making a new collection for no reason
354            for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
355            {
356                if (prev != end && prev->data == pos->data)
357                {
358                    can_combine = true;
359                    break;
360                }
361            }
362
363            // We we can combine at least one entry, then we make a new collection
364            // and populate it accordingly, and then swap it into place.
365            if (can_combine)
366            {
367                std::vector<Entry> minimal_ranges;
368                for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
369                {
370                    if (prev != end && prev->data == pos->data)
371                        minimal_ranges.back().SetRangeEnd (pos->GetRangeEnd());
372                    else
373                        minimal_ranges.push_back (*pos);
374                }
375                // Use the swap technique in case our new vector is much smaller.
376                // We must swap when using the STL because std::vector objects never
377                // release or reduce the memory once it has been allocated/reserved.
378                m_entries.swap (minimal_ranges);
379            }
380        }
381
382        void
383        Clear ()
384        {
385            m_entries.clear();
386        }
387
388        bool
389        IsEmpty () const
390        {
391            return m_entries.empty();
392        }
393
394        size_t
395        GetNumEntries () const
396        {
397            return m_entries.size();
398        }
399
400        const Entry *
401        GetEntryAtIndex (uint32_t i) const
402        {
403            if (i<m_entries.size())
404                return &m_entries[i];
405            return NULL;
406        }
407
408        static bool
409        BaseLessThan (const Entry& lhs, const Entry& rhs)
410        {
411            return lhs.GetRangeBase() < rhs.GetRangeBase();
412        }
413
414        const Entry *
415        FindEntryThatContains (B addr) const
416        {
417            if ( !m_entries.empty() )
418            {
419                Entry entry;
420                entry.SetRangeBase(addr);
421                entry.SetByteSize(1);
422                typename std::vector<Entry>::const_iterator begin = m_entries.begin();
423                typename std::vector<Entry>::const_iterator end = m_entries.end();
424                typename std::vector<Entry>::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
425
426                if (pos != end && pos->Contains(addr))
427                {
428                    return &(*pos);
429                }
430                else if (pos != begin)
431                {
432                    --pos;
433                    if (pos->Contains(addr))
434                    {
435                        return &(*pos);
436                    }
437                }
438            }
439            return NULL;
440        }
441
442    protected:
443        std::vector<Entry> m_entries;
444    };
445
446} // namespace lldb_private
447
448#endif  // liblldb_RangeMap_h_
449