| //===-- RangeMap.h ----------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef liblldb_RangeMap_h_ |
| #define liblldb_RangeMap_h_ |
| |
| #include "lldb/lldb-private.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| // Uncomment to make sure all Range objects are sorted when needed |
| //#define ASSERT_RANGEMAP_ARE_SORTED |
| |
| namespace lldb_private { |
| |
| |
| //---------------------------------------------------------------------- |
| // Templatized classes for dealing with generic ranges and also |
| // collections of ranges, or collections of ranges that have associated |
| // data. |
| //---------------------------------------------------------------------- |
| |
| //---------------------------------------------------------------------- |
| // A simple range class where you get to define the type of the range |
| // base "B", and the type used for the range byte size "S". |
| //---------------------------------------------------------------------- |
| template <typename B, typename S> |
| struct Range |
| { |
| typedef B BaseType; |
| typedef S SizeType; |
| |
| BaseType base; |
| SizeType size; |
| |
| Range () : |
| base (0), |
| size (0) |
| { |
| } |
| |
| Range (BaseType b, SizeType s) : |
| base (b), |
| size (s) |
| { |
| } |
| |
| void |
| Clear (BaseType b = 0) |
| { |
| base = b; |
| size = 0; |
| } |
| |
| // Set the start value for the range, and keep the same size |
| BaseType |
| GetRangeBase () const |
| { |
| return base; |
| } |
| |
| void |
| SetRangeBase (BaseType b) |
| { |
| base = b; |
| } |
| |
| void |
| Slide (BaseType slide) |
| { |
| base += slide; |
| } |
| |
| BaseType |
| GetRangeEnd () const |
| { |
| return base + size; |
| } |
| |
| void |
| SetRangeEnd (BaseType end) |
| { |
| if (end > base) |
| size = end - base; |
| else |
| size = 0; |
| } |
| |
| SizeType |
| GetByteSize () const |
| { |
| return size; |
| } |
| |
| void |
| SetByteSize (SizeType s) |
| { |
| size = s; |
| } |
| |
| bool |
| IsValid() const |
| { |
| return size > 0; |
| } |
| |
| bool |
| Contains (BaseType r) const |
| { |
| return (GetRangeBase() <= r) && (r < GetRangeEnd()); |
| } |
| |
| bool |
| ContainsEndInclusive (BaseType r) const |
| { |
| return (GetRangeBase() <= r) && (r <= GetRangeEnd()); |
| } |
| |
| bool |
| Contains (const Range& range) const |
| { |
| return Contains(range.GetRangeBase()) && ContainsEndInclusive(range.GetRangeEnd()); |
| } |
| |
| bool |
| Overlap (const Range &rhs) const |
| { |
| const BaseType lhs_base = this->GetRangeBase(); |
| const BaseType rhs_base = rhs.GetRangeBase(); |
| const BaseType lhs_end = this->GetRangeEnd(); |
| const BaseType rhs_end = rhs.GetRangeEnd(); |
| bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base); |
| return result; |
| } |
| |
| bool |
| operator < (const Range &rhs) const |
| { |
| if (base == rhs.base) |
| return size < rhs.size; |
| return base < rhs.base; |
| } |
| |
| bool |
| operator == (const Range &rhs) const |
| { |
| return base == rhs.base && size == rhs.size; |
| } |
| |
| bool |
| operator != (const Range &rhs) const |
| { |
| return base != rhs.base || size != rhs.size; |
| } |
| }; |
| |
| //---------------------------------------------------------------------- |
| // A range array class where you get to define the type of the ranges |
| // that the collection contains. |
| //---------------------------------------------------------------------- |
| |
| template <typename B, typename S, unsigned N> |
| class RangeArray |
| { |
| public: |
| typedef B BaseType; |
| typedef S SizeType; |
| typedef Range<B,S> Entry; |
| //typedef std::vector<Entry> Collection; |
| typedef llvm::SmallVector<Entry, N> Collection; |
| |
| RangeArray () : |
| m_entries () |
| { |
| } |
| |
| ~RangeArray() |
| { |
| } |
| |
| void |
| Append (const Entry &entry) |
| { |
| m_entries.push_back (entry); |
| } |
| |
| bool |
| RemoveEntrtAtIndex (uint32_t idx) |
| { |
| if (idx < m_entries.size()) |
| { |
| m_entries.erase (m_entries.begin() + idx); |
| return true; |
| } |
| return false; |
| } |
| |
| void |
| Sort () |
| { |
| if (m_entries.size() > 1) |
| std::stable_sort (m_entries.begin(), m_entries.end()); |
| } |
| |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| bool |
| IsSorted () const |
| { |
| typename Collection::const_iterator pos, end, prev; |
| // First we determine if we can combine any of the Entry objects so we |
| // don't end up allocating and making a new collection for no reason |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && *pos < *prev) |
| return false; |
| } |
| return true; |
| } |
| #endif |
| void |
| CombineConsecutiveRanges () |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| // Can't combine if ranges if we have zero or one range |
| if (m_entries.size() > 1) |
| { |
| // The list should be sorted prior to calling this function |
| typename Collection::iterator pos; |
| typename Collection::iterator end; |
| typename Collection::iterator prev; |
| bool can_combine = false; |
| // First we determine if we can combine any of the Entry objects so we |
| // don't end up allocating and making a new collection for no reason |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && prev->Overlap(*pos)) |
| { |
| can_combine = true; |
| break; |
| } |
| } |
| |
| // We we can combine at least one entry, then we make a new collection |
| // and populate it accordingly, and then swap it into place. |
| if (can_combine) |
| { |
| Collection minimal_ranges; |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && prev->Overlap(*pos)) |
| minimal_ranges.back().SetRangeEnd (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd())); |
| else |
| minimal_ranges.push_back (*pos); |
| } |
| // Use the swap technique in case our new vector is much smaller. |
| // We must swap when using the STL because std::vector objects never |
| // release or reduce the memory once it has been allocated/reserved. |
| m_entries.swap (minimal_ranges); |
| } |
| } |
| } |
| |
| |
| BaseType |
| GetMinRangeBase (BaseType fail_value) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if (m_entries.empty()) |
| return fail_value; |
| // m_entries must be sorted, so if we aren't empty, we grab the |
| // first range's base |
| return m_entries.front().GetRangeBase(); |
| } |
| |
| BaseType |
| GetMaxRangeEnd (BaseType fail_value) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if (m_entries.empty()) |
| return fail_value; |
| // m_entries must be sorted, so if we aren't empty, we grab the |
| // last range's end |
| return m_entries.back().GetRangeEnd(); |
| } |
| |
| void |
| Slide (BaseType slide) |
| { |
| typename Collection::iterator pos, end; |
| for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos) |
| pos->Slide (slide); |
| } |
| |
| void |
| Clear () |
| { |
| m_entries.clear(); |
| } |
| |
| bool |
| IsEmpty () const |
| { |
| return m_entries.empty(); |
| } |
| |
| size_t |
| GetSize () const |
| { |
| return m_entries.size(); |
| } |
| |
| const Entry * |
| GetEntryAtIndex (size_t i) const |
| { |
| if (i<m_entries.size()) |
| return &m_entries[i]; |
| return NULL; |
| } |
| |
| // Clients must ensure that "i" is a valid index prior to calling this function |
| const Entry & |
| GetEntryRef (size_t i) const |
| { |
| return m_entries[i]; |
| } |
| |
| Entry * |
| Back() |
| { |
| if (m_entries.empty()) |
| return NULL; |
| return &m_entries.back(); |
| } |
| |
| const Entry * |
| Back() const |
| { |
| if (m_entries.empty()) |
| return NULL; |
| return &m_entries.back(); |
| } |
| |
| static bool |
| BaseLessThan (const Entry& lhs, const Entry& rhs) |
| { |
| return lhs.GetRangeBase() < rhs.GetRangeBase(); |
| } |
| |
| uint32_t |
| FindEntryIndexThatContains (B addr) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if (!m_entries.empty()) |
| { |
| Entry entry (addr, 1); |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end && pos->Contains(addr)) |
| { |
| return std::distance (begin, pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(addr)) |
| return std::distance (begin, pos); |
| } |
| } |
| return UINT32_MAX; |
| } |
| |
| const Entry * |
| FindEntryThatContains (B addr) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if (!m_entries.empty()) |
| { |
| Entry entry (addr, 1); |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end && pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| const Entry * |
| FindEntryThatContains (const Entry &range) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if (!m_entries.empty()) |
| { |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan); |
| |
| if (pos != end && pos->Contains(range)) |
| { |
| return &(*pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(range)) |
| { |
| return &(*pos); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| protected: |
| Collection m_entries; |
| }; |
| |
| //---------------------------------------------------------------------- |
| // A simple range with data class where you get to define the type of |
| // the range base "B", the type used for the range byte size "S", and |
| // the type for the associated data "T". |
| //---------------------------------------------------------------------- |
| template <typename B, typename S, typename T> |
| struct RangeData : public Range<B,S> |
| { |
| typedef T DataType; |
| |
| DataType data; |
| |
| RangeData () : |
| Range<B,S> (), |
| data () |
| { |
| } |
| |
| RangeData (B base, S size, DataType d) : |
| Range<B,S> (base, size), |
| data (d) |
| { |
| } |
| |
| bool |
| operator < (const RangeData &rhs) const |
| { |
| if (this->base == rhs.base) |
| { |
| if (this->size == rhs.size) |
| return this->data < rhs.data; |
| else |
| return this->size < rhs.size; |
| } |
| return this->base < rhs.base; |
| } |
| |
| bool |
| operator == (const RangeData &rhs) const |
| { |
| return this->GetRangeBase() == rhs.GetRangeBase() && |
| this->GetByteSize() == rhs.GetByteSize() && |
| this->data == rhs.data; |
| } |
| |
| bool |
| operator != (const RangeData &rhs) const |
| { |
| return this->GetRangeBase() != rhs.GetRangeBase() || |
| this->GetByteSize() != rhs.GetByteSize() || |
| this->data != rhs.data; |
| } |
| }; |
| |
| template <typename B, typename S, typename T, unsigned N> |
| class RangeDataArray |
| { |
| public: |
| typedef RangeData<B,S,T> Entry; |
| //typedef std::vector<Entry> Collection; |
| typedef llvm::SmallVector<Entry, N> Collection; |
| |
| |
| RangeDataArray () |
| { |
| } |
| |
| ~RangeDataArray() |
| { |
| } |
| |
| void |
| Append (const Entry &entry) |
| { |
| m_entries.push_back (entry); |
| } |
| |
| void |
| Sort () |
| { |
| if (m_entries.size() > 1) |
| std::stable_sort (m_entries.begin(), m_entries.end()); |
| } |
| |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| bool |
| IsSorted () const |
| { |
| typename Collection::const_iterator pos, end, prev; |
| // First we determine if we can combine any of the Entry objects so we |
| // don't end up allocating and making a new collection for no reason |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && *pos < *prev) |
| return false; |
| } |
| return true; |
| } |
| #endif |
| |
| void |
| CombineConsecutiveEntriesWithEqualData () |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| typename Collection::iterator pos; |
| typename Collection::iterator end; |
| typename Collection::iterator prev; |
| bool can_combine = false; |
| // First we determine if we can combine any of the Entry objects so we |
| // don't end up allocating and making a new collection for no reason |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && prev->data == pos->data) |
| { |
| can_combine = true; |
| break; |
| } |
| } |
| |
| // We we can combine at least one entry, then we make a new collection |
| // and populate it accordingly, and then swap it into place. |
| if (can_combine) |
| { |
| Collection minimal_ranges; |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && prev->data == pos->data) |
| minimal_ranges.back().SetRangeEnd (pos->GetRangeEnd()); |
| else |
| minimal_ranges.push_back (*pos); |
| } |
| // Use the swap technique in case our new vector is much smaller. |
| // We must swap when using the STL because std::vector objects never |
| // release or reduce the memory once it has been allocated/reserved. |
| m_entries.swap (minimal_ranges); |
| } |
| } |
| |
| void |
| Clear () |
| { |
| m_entries.clear(); |
| } |
| |
| bool |
| IsEmpty () const |
| { |
| return m_entries.empty(); |
| } |
| |
| size_t |
| GetSize () const |
| { |
| return m_entries.size(); |
| } |
| |
| const Entry * |
| GetEntryAtIndex (size_t i) const |
| { |
| if (i<m_entries.size()) |
| return &m_entries[i]; |
| return NULL; |
| } |
| |
| // Clients must ensure that "i" is a valid index prior to calling this function |
| const Entry & |
| GetEntryRef (size_t i) const |
| { |
| return m_entries[i]; |
| } |
| |
| static bool |
| BaseLessThan (const Entry& lhs, const Entry& rhs) |
| { |
| return lhs.GetRangeBase() < rhs.GetRangeBase(); |
| } |
| |
| uint32_t |
| FindEntryIndexThatContains (B addr) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if ( !m_entries.empty() ) |
| { |
| Entry entry (addr, 1); |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end && pos->Contains(addr)) |
| { |
| return std::distance (begin, pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(addr)) |
| return std::distance (begin, pos); |
| } |
| } |
| return UINT32_MAX; |
| } |
| |
| Entry * |
| FindEntryThatContains (B addr) |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if ( !m_entries.empty() ) |
| { |
| Entry entry; |
| entry.SetRangeBase(addr); |
| entry.SetByteSize(1); |
| typename Collection::iterator begin = m_entries.begin(); |
| typename Collection::iterator end = m_entries.end(); |
| typename Collection::iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end && pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| } |
| } |
| return NULL; |
| } |
| const Entry * |
| FindEntryThatContains (B addr) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if ( !m_entries.empty() ) |
| { |
| Entry entry; |
| entry.SetRangeBase(addr); |
| entry.SetByteSize(1); |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end && pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(addr)) |
| { |
| return &(*pos); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| const Entry * |
| FindEntryThatContains (const Entry &range) const |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if ( !m_entries.empty() ) |
| { |
| typename Collection::const_iterator begin = m_entries.begin(); |
| typename Collection::const_iterator end = m_entries.end(); |
| typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan); |
| |
| if (pos != end && pos->Contains(range)) |
| { |
| return &(*pos); |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if (pos->Contains(range)) |
| { |
| return &(*pos); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| Entry * |
| Back() |
| { |
| if (!m_entries.empty()) |
| return &m_entries.back(); |
| return NULL; |
| } |
| |
| const Entry * |
| Back() const |
| { |
| if (!m_entries.empty()) |
| return &m_entries.back(); |
| return NULL; |
| } |
| |
| protected: |
| Collection m_entries; |
| }; |
| |
| |
| //---------------------------------------------------------------------- |
| // A simple range with data class where you get to define the type of |
| // the range base "B", the type used for the range byte size "S", and |
| // the type for the associated data "T". |
| //---------------------------------------------------------------------- |
| template <typename B, typename T> |
| struct AddressData |
| { |
| typedef B BaseType; |
| typedef T DataType; |
| |
| BaseType addr; |
| DataType data; |
| |
| AddressData () : |
| addr (), |
| data () |
| { |
| } |
| |
| AddressData (B a, DataType d) : |
| addr (a), |
| data (d) |
| { |
| } |
| |
| bool |
| operator < (const AddressData &rhs) const |
| { |
| if (this->addr == rhs.addr) |
| return this->data < rhs.data; |
| return this->addr < rhs.addr; |
| } |
| |
| bool |
| operator == (const AddressData &rhs) const |
| { |
| return this->addr == rhs.addr && |
| this->data == rhs.data; |
| } |
| |
| bool |
| operator != (const AddressData &rhs) const |
| { |
| return this->addr != rhs.addr || |
| this->data == rhs.data; |
| } |
| }; |
| |
| |
| template <typename B, typename T, unsigned N> |
| class AddressDataArray |
| { |
| public: |
| typedef AddressData<B,T> Entry; |
| //typedef std::vector<Entry> Collection; |
| typedef llvm::SmallVector<Entry, N> Collection; |
| |
| |
| AddressDataArray () |
| { |
| } |
| |
| ~AddressDataArray() |
| { |
| } |
| |
| void |
| Append (const Entry &entry) |
| { |
| m_entries.push_back (entry); |
| } |
| |
| void |
| Sort () |
| { |
| if (m_entries.size() > 1) |
| std::stable_sort (m_entries.begin(), m_entries.end()); |
| } |
| |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| bool |
| IsSorted () const |
| { |
| typename Collection::const_iterator pos, end, prev; |
| // First we determine if we can combine any of the Entry objects so we |
| // don't end up allocating and making a new collection for no reason |
| for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++) |
| { |
| if (prev != end && *pos < *prev) |
| return false; |
| } |
| return true; |
| } |
| #endif |
| |
| void |
| Clear () |
| { |
| m_entries.clear(); |
| } |
| |
| bool |
| IsEmpty () const |
| { |
| return m_entries.empty(); |
| } |
| |
| size_t |
| GetSize () const |
| { |
| return m_entries.size(); |
| } |
| |
| const Entry * |
| GetEntryAtIndex (size_t i) const |
| { |
| if (i<m_entries.size()) |
| return &m_entries[i]; |
| return NULL; |
| } |
| |
| // Clients must ensure that "i" is a valid index prior to calling this function |
| const Entry & |
| GetEntryRef (size_t i) const |
| { |
| return m_entries[i]; |
| } |
| |
| static bool |
| BaseLessThan (const Entry& lhs, const Entry& rhs) |
| { |
| return lhs.addr < rhs.addr; |
| } |
| |
| Entry * |
| FindEntry (B addr, bool exact_match_only) |
| { |
| #ifdef ASSERT_RANGEMAP_ARE_SORTED |
| assert (IsSorted()); |
| #endif |
| if ( !m_entries.empty() ) |
| { |
| Entry entry; |
| entry.addr = addr; |
| typename Collection::iterator begin = m_entries.begin(); |
| typename Collection::iterator end = m_entries.end(); |
| typename Collection::iterator pos = std::lower_bound (begin, end, entry, BaseLessThan); |
| |
| if (pos != end) |
| { |
| if (pos->addr == addr || !exact_match_only) |
| return &(*pos); |
| } |
| } |
| return NULL; |
| } |
| |
| const Entry * |
| FindNextEntry (const Entry *entry) |
| { |
| if (entry >= &*m_entries.begin() && entry + 1 < &*m_entries.end()) |
| return entry + 1; |
| return NULL; |
| } |
| |
| Entry * |
| Back() |
| { |
| if (!m_entries.empty()) |
| return &m_entries.back(); |
| return NULL; |
| } |
| |
| const Entry * |
| Back() const |
| { |
| if (!m_entries.empty()) |
| return &m_entries.back(); |
| return NULL; |
| } |
| |
| protected: |
| Collection m_entries; |
| }; |
| |
| } // namespace lldb_private |
| |
| #endif // liblldb_RangeMap_h_ |