mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
Refactor ParamEntry look-up allowing "contained by" discovery
This commit is contained in:
parent
ef12c20829
commit
12d3da029b
13 changed files with 690 additions and 286 deletions
|
@ -14,28 +14,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// A container for records occupying (possibly overlapping)
|
||||
// intervals. I.e. a map from a linear ordered domain to
|
||||
// (multiple) records.
|
||||
// recordtype is the type of a record
|
||||
// must support
|
||||
// constructor(first,last)
|
||||
// getFirst() beginning of range
|
||||
// getLast() end of range (inclusive)
|
||||
// getSubsort()
|
||||
// initialize() initialization with inittype object
|
||||
// must define types
|
||||
// linetype
|
||||
// subsorttype
|
||||
// inittype
|
||||
// linetype is the type of elements in the linear domain
|
||||
// must support <,<=,==,!=, +(integer) -(integer)
|
||||
// subsorttype - overlapping intervals can be subsorted
|
||||
// must suport <
|
||||
// null or false initialization produces minimal value
|
||||
// true initialization produces maximal value
|
||||
// copy constructor
|
||||
// inittype is extra initialization data for the recordtype
|
||||
/// \file rangemap.hh
|
||||
/// \brief Templates to define interval map containers
|
||||
|
||||
#ifndef __RANGEMAP__
|
||||
#define __RANGEMAP__
|
||||
|
@ -43,102 +23,160 @@
|
|||
#include <set>
|
||||
#include <list>
|
||||
|
||||
/// \brief An interval map container
|
||||
///
|
||||
/// A container for records occupying (possibly overlapping)
|
||||
/// intervals. I.e. a map from a linear ordered domain to
|
||||
/// (multiple) records.
|
||||
/// The \b recordtype is the main object in the container, it must support:
|
||||
/// - recordtype() a constructor taking no parameters
|
||||
/// - getFirst() beginning of range
|
||||
/// - getLast() end of range (inclusive)
|
||||
/// - getSubsort() retrieve the subsorttype object (see below)
|
||||
/// - initialize(inittype,linetype,linetype) an initializer routine
|
||||
///
|
||||
/// The \b recordtype must define data-types:
|
||||
/// - linetype
|
||||
/// - subsorttype
|
||||
/// - inittype
|
||||
///
|
||||
/// \b linetype is the data-type of elements in the linear domain. It
|
||||
/// must support:
|
||||
/// - <,<= Comparisons
|
||||
/// - ==,!= Equality
|
||||
/// - + \<constant> Addition of integers
|
||||
/// - - \<constant> Subtraction of integers
|
||||
///
|
||||
/// \b subsorttype describes how overlapping intervals can be sub-sorted. It
|
||||
/// must support:
|
||||
/// - <
|
||||
/// - subsorttype(\b false) constructor with \b false produces a minimal value
|
||||
/// - subsorttype(\b true) constructor with \b true produces a maximal value
|
||||
/// - copy constructor
|
||||
///
|
||||
/// \b inittype is extra initialization data for the \b recordtype
|
||||
///
|
||||
/// The main interval map is implemented as a \e multiset of disjoint sub-ranges mapping
|
||||
/// to the \b recordtype objects. After deduping the sub-ranges form the common refinement
|
||||
/// of all the possibly overlapping \b recordtype ranges. A sub-range is duplicated for each
|
||||
/// distinct \b recordtype that overlaps that sub-range. The sub-range multiset is updated
|
||||
/// with every insertion or deletion of \b recordtype objects into the container, which
|
||||
/// may insert new or delete existing boundary points separating the disjoint subranges.
|
||||
template<typename _recordtype>
|
||||
class rangemap {
|
||||
// A class for describing a disjoint partition
|
||||
public:
|
||||
typedef typename _recordtype::linetype linetype;
|
||||
typedef typename _recordtype::subsorttype subsorttype;
|
||||
typedef typename _recordtype::inittype inittype;
|
||||
typedef typename _recordtype::linetype linetype; ///< Integer data-type defining the linear domain
|
||||
typedef typename _recordtype::subsorttype subsorttype; ///< The data-type used for subsorting
|
||||
typedef typename _recordtype::inittype inittype; ///< The data-type containing initialization data for records
|
||||
private:
|
||||
/// \brief The internal \e sub-range object for the interval map
|
||||
///
|
||||
/// It defines a disjoint range within the common refinement of all ranges
|
||||
/// in the container. It also knows about its containing range and \b recordtype.
|
||||
class AddrRange {
|
||||
friend class rangemap<_recordtype>;
|
||||
friend class PartIterator;
|
||||
mutable linetype first; // Part of range contained in partition
|
||||
linetype last;
|
||||
mutable linetype a,b; // Range occupied by the entire record
|
||||
mutable subsorttype subsort;
|
||||
AddrRange(linetype l) : subsort(false) { last = l; }
|
||||
AddrRange(linetype l,const subsorttype &s) : subsort(s) { last = l; }
|
||||
mutable linetype first; ///< Start of the disjoint sub-range
|
||||
linetype last; ///< End of the disjoint sub-range
|
||||
mutable linetype a; ///< Start of full range occupied by the entire \b recordtype
|
||||
mutable linetype b; ///< End of full range occupied by the entire \b recordtype
|
||||
mutable subsorttype subsort; ///< How \b this should be sub-sorted
|
||||
mutable typename std::list<_recordtype>::iterator value; ///< Iterator pointing at the actual \b recordtype
|
||||
AddrRange(linetype l) : subsort(false) { last = l; } ///< (Partial) constructor
|
||||
AddrRange(linetype l,const subsorttype &s) : subsort(s) { last = l; } ///< (Partial) constructor given a subsort
|
||||
public:
|
||||
mutable typename std::list<_recordtype>::iterator value;
|
||||
bool operator<(const AddrRange &op2) const {
|
||||
if (last != op2.last) return (last < op2.last);
|
||||
return (subsort < op2.subsort);
|
||||
}
|
||||
typename std::list<_recordtype>::iterator getValue(void) const { return value; }
|
||||
} ///< Comparison method based on ending boundary point
|
||||
typename std::list<_recordtype>::iterator getValue(void) const { return value; } ///< Retrieve the \b recordtype
|
||||
};
|
||||
public:
|
||||
class PartIterator { // Iterator over partitions
|
||||
typename std::multiset<AddrRange>::const_iterator iter;
|
||||
/// \brief An iterator into the interval map container
|
||||
///
|
||||
/// This is really an iterator to the underlying multiset, but dereferencing it returns the
|
||||
/// \b recordtype. Iteration occurs over the disjoint sub-ranges, thus the same \b recordtype
|
||||
/// may be visited multiple times by the iterator, depending on how much it overlaps other
|
||||
/// \b recordtypes. The sub-ranges are sorted in linear order, then depending on the \b subsorttype.
|
||||
class PartIterator {
|
||||
typename std::multiset<AddrRange>::const_iterator iter; ///< The underlying multiset iterator
|
||||
public:
|
||||
PartIterator(void) {}
|
||||
PartIterator(typename std::multiset<AddrRange>::const_iterator i) { iter=i; }
|
||||
_recordtype &operator*(void) { return *(*iter).value; }
|
||||
PartIterator &operator++(void) { ++iter; return *this; }
|
||||
PartIterator(void) {} ///< Constructor
|
||||
PartIterator(typename std::multiset<AddrRange>::const_iterator i) { iter=i; } ///< Construct given iterator
|
||||
_recordtype &operator*(void) { return *(*iter).value; } ///< Dereference to the \b recordtype object
|
||||
PartIterator &operator++(void) { ++iter; return *this; } ///< Pre-increment the iterator
|
||||
PartIterator operator++(int i) {
|
||||
PartIterator orig(iter); ++iter; return orig; }
|
||||
PartIterator &operator--(void) { --iter; return *this; }
|
||||
PartIterator orig(iter); ++iter; return orig; } ///< Post-increment the iterator
|
||||
PartIterator &operator--(void) { --iter; return *this; } ///< Pre-decrement the iterator
|
||||
PartIterator operator--(int i) {
|
||||
PartIterator orig(iter); --iter; return orig; }
|
||||
PartIterator orig(iter); --iter; return orig; } ///< Post-decrement the iterator
|
||||
PartIterator &operator=(const PartIterator &op2) {
|
||||
iter = op2.iter; return *this;
|
||||
}
|
||||
} ///< Assign to the iterator
|
||||
bool operator==(const PartIterator &op2) const {
|
||||
return (iter==op2.iter);
|
||||
}
|
||||
} ///< Test equality of iterators
|
||||
bool operator!=(const PartIterator &op2) const {
|
||||
return (iter!=op2.iter);
|
||||
}
|
||||
typename std::list<_recordtype>::iterator getValueIter(void) const { return (*iter).getValue(); }
|
||||
} ///< Test inequality of iterators
|
||||
typename std::list<_recordtype>::iterator getValueIter(void) const {
|
||||
return (*iter).getValue(); } ///< Get the \b recordtype iterator
|
||||
};
|
||||
|
||||
typedef PartIterator const_iterator;
|
||||
typedef PartIterator const_iterator; ///< The main sub-range iterator data-type
|
||||
|
||||
private:
|
||||
std::multiset<AddrRange> tree;
|
||||
std::list<_recordtype> record;
|
||||
std::multiset<AddrRange> tree; ///< The underlying multiset of sub-ranges
|
||||
std::list<_recordtype> record; ///< Storage for the actual record objects
|
||||
|
||||
void zip(linetype i,typename std::multiset<AddrRange>::iterator iter);
|
||||
void unzip(linetype i,typename std::multiset<AddrRange>::iterator iter);
|
||||
void zip(linetype i,typename std::multiset<AddrRange>::iterator iter); ///< Remove the given partition boundary
|
||||
void unzip(linetype i,typename std::multiset<AddrRange>::iterator iter); ///< Insert the given partition boundary
|
||||
public:
|
||||
bool empty(void) const { return record.empty(); }
|
||||
void clear(void) { tree.clear(); record.clear(); }
|
||||
typename std::list<_recordtype>::const_iterator begin_list(void) const { return record.begin(); }
|
||||
typename std::list<_recordtype>::const_iterator end_list(void) const { return record.end(); }
|
||||
typename std::list<_recordtype>::iterator begin_list(void) { return record.begin(); }
|
||||
typename std::list<_recordtype>::iterator end_list(void) { return record.end(); }
|
||||
bool empty(void) const { return record.empty(); } ///< Return \b true if the container is empty
|
||||
void clear(void) { tree.clear(); record.clear(); } ///< Clear all records from the container
|
||||
typename std::list<_recordtype>::const_iterator begin_list(void) const { return record.begin(); } ///< Beginning of records
|
||||
typename std::list<_recordtype>::const_iterator end_list(void) const { return record.end(); } ///< End of records
|
||||
typename std::list<_recordtype>::iterator begin_list(void) { return record.begin(); } ///< Beginning of records
|
||||
typename std::list<_recordtype>::iterator end_list(void) { return record.end(); } ///< End of records
|
||||
|
||||
const_iterator begin(void) const { return PartIterator(tree.begin()); }
|
||||
const_iterator end(void) const { return PartIterator(tree.end()); }
|
||||
const_iterator begin(void) const { return PartIterator(tree.begin()); } ///< Beginning of sub-ranges
|
||||
const_iterator end(void) const { return PartIterator(tree.end()); } ///< Ending of sub-ranges
|
||||
|
||||
// Find range of intervals intersecting a
|
||||
/// \brief Find sub-ranges intersecting the given boundary point
|
||||
std::pair<const_iterator,const_iterator> find(linetype a) const;
|
||||
|
||||
// Find range of intervals intersecting a, with subsort
|
||||
// between (subsort1,subsort2)
|
||||
/// \brief Find sub-ranges intersecting given boundary point, and between given \e subsorts
|
||||
std::pair<const_iterator,const_iterator>
|
||||
find(linetype a,const subsorttype &subsort1,const subsorttype &subsort2) const;
|
||||
|
||||
// Find first interval after point, that does not intersect it
|
||||
const_iterator find_firstafter(linetype point) const;
|
||||
/// \brief Find beginning of sub-ranges that contain the given boundary point
|
||||
const_iterator find_begin(linetype point) const;
|
||||
|
||||
// Find last interval after point, that does not intersect it
|
||||
const_iterator find_lastbefore(linetype point) const;
|
||||
/// \brief Find ending of sub-ranges that contain the given boundary point
|
||||
const_iterator find_end(linetype point) const;
|
||||
|
||||
// Find first interval overlapping given interval
|
||||
/// \brief Find first record overlapping given interval
|
||||
const_iterator find_overlap(linetype point,linetype end) const;
|
||||
|
||||
/// \brief Insert a new record into the container
|
||||
typename std::list<_recordtype>::iterator insert(const inittype &data,linetype a,linetype b);
|
||||
|
||||
/// \brief Erase a given record from the container
|
||||
void erase(typename std::list<_recordtype>::iterator v);
|
||||
|
||||
/// \brief Erase a record given an iterator
|
||||
void erase(const_iterator iter) { erase( iter.getValueIter() ); }
|
||||
};
|
||||
|
||||
/// All sub-ranges that end with the given boundary point are deleted, and all sub-ranges
|
||||
/// that begin with the given boundary point (+1) are extended to cover the deleted sub-range.
|
||||
/// This should run in O(k).
|
||||
/// \param i is the given boundary point
|
||||
/// \param iter points to the first sub-range that ends with the given boundary point
|
||||
template<typename _recordtype>
|
||||
void rangemap<_recordtype>::zip(linetype i,typename std::multiset<AddrRange>::iterator iter)
|
||||
|
||||
{ // Remove the partition boundary occurring right after i
|
||||
// This should run in O(k)
|
||||
{
|
||||
linetype f = (*iter).first;
|
||||
while((*iter).last == i)
|
||||
tree.erase(iter++);
|
||||
|
@ -149,13 +187,15 @@ void rangemap<_recordtype>::zip(linetype i,typename std::multiset<AddrRange>::it
|
|||
}
|
||||
}
|
||||
|
||||
/// All sub-ranges that contain the boundary point will be split into a sub-range
|
||||
/// that ends at the boundary point and a sub-range that begins with the boundary point (+1).
|
||||
/// This should run in O(k), where k is the number of intervals intersecting the boundary point.
|
||||
/// \param i is the given boundary point
|
||||
/// \param iter points to the first sub-range containing the boundary point
|
||||
template<typename _recordtype>
|
||||
void rangemap<_recordtype>::unzip(linetype i,typename std::multiset<AddrRange>::iterator iter)
|
||||
|
||||
{ // Create a new partition boundary right after i
|
||||
// This should run in O(k), where k is the number
|
||||
// of intervals intersecting the point i
|
||||
// iter should be the first interval containing i
|
||||
{
|
||||
typename std::multiset<AddrRange>::iterator hint = iter;
|
||||
if ((*iter).last == i) return; // Can't split size 1 (i.e. split already present)
|
||||
linetype f;
|
||||
|
@ -174,11 +214,15 @@ void rangemap<_recordtype>::unzip(linetype i,typename std::multiset<AddrRange>::
|
|||
}
|
||||
}
|
||||
|
||||
/// \param data is other initialization data for the new record
|
||||
/// \param a is the start of the range occupied by the new record
|
||||
/// \param b is the (inclusive) end of the range
|
||||
/// \return an iterator to the new record
|
||||
template<typename _recordtype>
|
||||
typename std::list<_recordtype>::iterator
|
||||
rangemap<_recordtype>::insert(const inittype &data,linetype a,linetype b)
|
||||
|
||||
{ // Insert a new record into the container at inclusive range [a,b]
|
||||
{
|
||||
linetype f=a;
|
||||
typename std::list<_recordtype>::iterator liter;
|
||||
typename std::multiset<AddrRange>::iterator low = tree.lower_bound(AddrRange(f));
|
||||
|
@ -188,8 +232,8 @@ rangemap<_recordtype>::insert(const inittype &data,linetype a,linetype b)
|
|||
unzip(f-1,low); // If so do the refinement
|
||||
}
|
||||
|
||||
record.push_front( _recordtype(a,b) );
|
||||
record.front().initialize( data );
|
||||
record.push_front( _recordtype() );
|
||||
record.front().initialize( data, a, b );
|
||||
liter = record.begin();
|
||||
|
||||
AddrRange addrrange(b,(*liter).getSubsort());
|
||||
|
@ -233,6 +277,7 @@ rangemap<_recordtype>::insert(const inittype &data,linetype a,linetype b)
|
|||
return liter;
|
||||
}
|
||||
|
||||
/// \param v is the iterator to the record to be erased
|
||||
template<typename _recordtype>
|
||||
void rangemap<_recordtype>::erase(typename std::list<_recordtype>::iterator v)
|
||||
|
||||
|
@ -281,11 +326,13 @@ void rangemap<_recordtype>::erase(typename std::list<_recordtype>::iterator v)
|
|||
record.erase(v);
|
||||
}
|
||||
|
||||
/// \param point is the given boundary point
|
||||
/// \return begin/end iterators over all intersecting sub-ranges
|
||||
template<typename _recordtype>
|
||||
std::pair<typename rangemap<_recordtype>::const_iterator,typename rangemap<_recordtype>::const_iterator>
|
||||
rangemap<_recordtype>::find(linetype point) const
|
||||
|
||||
{ // Get range of intervals which intersect point
|
||||
{
|
||||
AddrRange addrrange(point);
|
||||
typename std::multiset<AddrRange>::const_iterator iter1,iter2;
|
||||
|
||||
|
@ -300,6 +347,10 @@ rangemap<_recordtype>::find(linetype point) const
|
|||
return std::pair<PartIterator,PartIterator>(PartIterator(iter1),PartIterator(iter2));
|
||||
}
|
||||
|
||||
/// \param point is the given boundary point
|
||||
/// \param sub1 is the starting subsort
|
||||
/// \param sub2 is the ending subsort
|
||||
/// \return begin/end iterators over all intersecting and bounded sub-ranges
|
||||
template<typename _recordtype>
|
||||
std::pair<typename rangemap<_recordtype>::const_iterator,typename rangemap<_recordtype>::const_iterator>
|
||||
rangemap<_recordtype>::find(linetype point,const subsorttype &sub1,const subsorttype &sub2) const
|
||||
|
@ -318,39 +369,44 @@ rangemap<_recordtype>::find(linetype point,const subsorttype &sub1,const subsort
|
|||
return std::pair<PartIterator,PartIterator>(PartIterator(iter1),PartIterator(iter2));
|
||||
}
|
||||
|
||||
/// \param point is the given boundary point
|
||||
/// \return iterator to first sub-range of intersects the boundary point
|
||||
template<typename _recordtype>
|
||||
typename rangemap<_recordtype>::const_iterator
|
||||
rangemap<_recordtype>::find_lastbefore(linetype point) const
|
||||
rangemap<_recordtype>::find_begin(linetype point) const
|
||||
|
||||
{
|
||||
AddrRange addrrange(point);
|
||||
typename std::multiset<AddrRange>::const_iterator iter;
|
||||
|
||||
// First interval with last >= point
|
||||
|
||||
iter = tree.lower_bound(addrrange);
|
||||
if (iter==tree.begin())
|
||||
return tree.end();
|
||||
--iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
/// \param point is the given boundary point
|
||||
/// \return iterator to first sub-range after that does not intersect the boundary point
|
||||
template<typename _recordtype>
|
||||
typename rangemap<_recordtype>::const_iterator
|
||||
rangemap<_recordtype>::find_firstafter(linetype point) const
|
||||
rangemap<_recordtype>::find_end(linetype point) const
|
||||
|
||||
{
|
||||
AddrRange addrrange(point,subsorttype(true));
|
||||
AddrRange addrend(point,subsorttype(true));
|
||||
typename std::multiset<AddrRange>::const_iterator iter;
|
||||
|
||||
iter = tree.upper_bound(addrrange);
|
||||
while(iter != tree.end()) {
|
||||
if (point < (*iter).a)
|
||||
return iter;
|
||||
++iter;
|
||||
}
|
||||
return tree.end();
|
||||
iter = tree.upper_bound(addrend);
|
||||
if ((iter==tree.end())||(point < (*iter).first))
|
||||
return iter;
|
||||
|
||||
// If we reach here, (*iter).last is bigger than point (as per upper_bound) but
|
||||
// point >= than (*iter).first, i.e. point is contained in the sub-range.
|
||||
// So we have to do one more search for first sub-range after the containing sub-range.
|
||||
AddrRange addrbeyond((*iter).last,subsorttype(true));
|
||||
return tree.upper_bound(addrbeyond);
|
||||
}
|
||||
|
||||
/// \param point is the start of interval to test
|
||||
/// \param end is the end of the interval to test
|
||||
/// \return iterator to first sub-range of an intersecting record (or \b end)
|
||||
template<typename _recordtype>
|
||||
typename rangemap<_recordtype>::const_iterator
|
||||
rangemap<_recordtype>::find_overlap(linetype point,linetype end) const
|
||||
|
@ -362,7 +418,7 @@ rangemap<_recordtype>::find_overlap(linetype point,linetype end) const
|
|||
// First range where right boundary is equal to or past point
|
||||
iter = tree.lower_bound(addrrange);
|
||||
if (iter==tree.end()) return iter;
|
||||
if (((*iter).first <= point)||((*iter).first<=end))
|
||||
if ((*iter).first<=end)
|
||||
return iter;
|
||||
return tree.end();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue