mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
233 lines
8.6 KiB
C++
233 lines
8.6 KiB
C++
/* ###
|
|
* IP: GHIDRA
|
|
* NOTE: very generic partition container
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/// \file partmap.hh
|
|
/// \brief The partmap<> template mapping a linear space to value objects
|
|
#ifndef __PARTMAP_HH__
|
|
#define __PARTMAP_HH__
|
|
|
|
#include <map>
|
|
|
|
namespace ghidra {
|
|
|
|
/// \brief A map from a linear space to value objects
|
|
///
|
|
/// The partmap is a template class taking:
|
|
/// - _linetype which represents an element in the linear space
|
|
/// - _valuetype which are the objects that linear space maps to
|
|
///
|
|
/// Let R be the linear space with an ordering, and let { a_i } be a finite set
|
|
/// of points in R.
|
|
/// The a_i partition R into a finite number of disjoint sets
|
|
/// { x : x < a_0 }, { x : x>=a_0 && x < a_1 }, ...
|
|
/// { x : x>=a_i && x < a_i+1 }, ...
|
|
/// { x : x>=a_n }
|
|
///
|
|
/// A partmap maps elements of this partition to _valuetype objects
|
|
/// A _valuetype is then associated with any element x in R by
|
|
/// looking up the value associated with the partition element
|
|
/// containing x.
|
|
///
|
|
/// The map is defined by starting with a \e default value object that applies
|
|
/// to the whole linear space. Then \e split points are introduced, one at a time,
|
|
/// in the linear space. At each split point, the associated value object is split
|
|
/// into two objects. At any point the value object describing some part of the linear space
|
|
/// can be changed.
|
|
template<typename _linetype,typename _valuetype>
|
|
class partmap {
|
|
public:
|
|
typedef std::map<_linetype,_valuetype> maptype; ///< Defining the map from split points to value objects
|
|
typedef typename maptype::iterator iterator; ///< A partmap iterator is an iterator into the map
|
|
typedef typename maptype::const_iterator const_iterator; ///< A constant iterator
|
|
private:
|
|
maptype database; ///< Map from linear split points to the value objects
|
|
_valuetype defaultvalue; ///< The value object \e before the first split point
|
|
public:
|
|
_valuetype &getValue(const _linetype &pnt); ///< Get the value object at a point
|
|
const _valuetype &getValue(const _linetype &pnt) const; ///< Get the value object at a point
|
|
const _valuetype &bounds(const _linetype &pnt,_linetype &before,_linetype &after,int &valid) const;
|
|
_valuetype &split(const _linetype &pnt); ///< Introduce a new split point
|
|
const _valuetype &defaultValue(void) const { return defaultvalue; } ///< Get the default value object
|
|
_valuetype &defaultValue(void) { return defaultvalue; } ///< Get the default value object
|
|
_valuetype & clearRange(const _linetype &pnt1,const _linetype &pnt2); ///< Clear a range of split points
|
|
const_iterator begin(void) const { return database.begin(); } ///< Beginning of split points
|
|
const_iterator end(void) const { return database.end(); } ///< End of split points
|
|
iterator begin(void) { return database.begin(); } ///< Beginning of split points
|
|
iterator end(void) { return database.end(); } ///< End of split points
|
|
const_iterator begin(const _linetype &pnt) const { return database.lower_bound(pnt); } ///< Get first split point after given point
|
|
iterator begin(const _linetype &pnt) { return database.lower_bound(pnt); } ///< Get first split point after given point
|
|
void clear(void) { database.clear(); } ///< Clear all split points
|
|
bool empty(void) const { return database.empty(); } ///< Return \b true if there are no split points
|
|
};
|
|
|
|
/// Look up the first split point coming before the given point
|
|
/// and return the value object it maps to. If there is no earlier split point
|
|
/// return the default value.
|
|
/// \param pnt is the given point in the linear space
|
|
/// \return the corresponding value object
|
|
template<typename _linetype,typename _valuetype>
|
|
_valuetype &partmap<_linetype,_valuetype>::
|
|
getValue(const _linetype &pnt)
|
|
|
|
{
|
|
iterator iter;
|
|
|
|
iter = database.upper_bound(pnt);
|
|
if (iter == database.begin())
|
|
return defaultvalue;
|
|
--iter;
|
|
return (*iter).second;
|
|
}
|
|
|
|
/// Look up the first split point coming before the given point
|
|
/// and return the value object it maps to. If there is no earlier split point
|
|
/// return the default value.
|
|
/// \param pnt is the given point in the linear space
|
|
/// \return the corresponding value object
|
|
template<typename _linetype,typename _valuetype>
|
|
const _valuetype &partmap<_linetype,_valuetype>::
|
|
getValue(const _linetype &pnt) const
|
|
|
|
{
|
|
const_iterator iter;
|
|
|
|
iter = database.upper_bound(pnt);
|
|
if (iter == database.begin())
|
|
return defaultvalue;
|
|
--iter;
|
|
return (*iter).second;
|
|
}
|
|
|
|
/// Add (if not already present) a point to the linear partition.
|
|
/// \param pnt is the (new) point
|
|
/// \return the (possibly) new value object for the range starting at the point
|
|
template<typename _linetype,typename _valuetype>
|
|
_valuetype &partmap<_linetype,_valuetype>::
|
|
split(const _linetype &pnt)
|
|
|
|
{
|
|
iterator iter;
|
|
|
|
iter = database.upper_bound(pnt);
|
|
if (iter != database.begin()) {
|
|
--iter;
|
|
if ((*iter).first == pnt) // point matches exactly
|
|
return (*iter).second; // Return old ref
|
|
_valuetype &newref( database[pnt] ); // Create new ref at point
|
|
newref = (*iter).second; // Copy of original partition value
|
|
return newref;
|
|
}
|
|
_valuetype &newref( database[pnt] ); // Create new ref at point
|
|
newref = defaultvalue; // Copy of defaultvalue
|
|
return newref;
|
|
}
|
|
|
|
/// Split points are introduced at the two boundary points of the given range,
|
|
/// and all split points in between are removed. The value object that was initially
|
|
/// present at the left-most boundary point becomes the value (as a copy) for the whole range.
|
|
/// \param pnt1 is the left-most boundary point of the range
|
|
/// \param pnt2 is the right-most boundary point
|
|
/// \return the value object assigned to the range
|
|
template<typename _linetype,typename _valuetype>
|
|
_valuetype &partmap<_linetype,_valuetype>::
|
|
clearRange(const _linetype &pnt1,const _linetype &pnt2)
|
|
{
|
|
split(pnt1);
|
|
split(pnt2);
|
|
iterator beg = begin(pnt1);
|
|
iterator end = begin(pnt2);
|
|
|
|
_valuetype &ref( (*beg).second );
|
|
++beg;
|
|
database.erase(beg,end);
|
|
return ref;
|
|
}
|
|
|
|
/// \brief Get the value object for a given point and return the range over which the value object applies
|
|
///
|
|
/// Pass back a \b before and \b after point defining the maximal range over which the value applies.
|
|
/// An additional validity code is passed back describing which of the bounding points apply:
|
|
/// - 0 if both bounds apply
|
|
/// - 1 if there is no lower bound
|
|
/// - 2 if there is no upper bound,
|
|
/// - 3 if there is neither a lower or upper bound
|
|
/// \param pnt is the given point around which to compute the range
|
|
/// \param before is a reference to the passed back lower bound
|
|
/// \param after is a reference to the passed back upper bound
|
|
/// \param valid is a reference to the passed back validity code
|
|
/// \return the corresponding value object
|
|
template<typename _linetype,typename _valuetype>
|
|
const _valuetype &partmap<_linetype,_valuetype>::
|
|
bounds(const _linetype &pnt,_linetype &before,_linetype &after,int &valid) const
|
|
{
|
|
if (database.empty()) {
|
|
valid = 3;
|
|
return defaultvalue;
|
|
}
|
|
const_iterator iter,enditer;
|
|
|
|
enditer = database.upper_bound(pnt);
|
|
if (enditer != database.begin()) {
|
|
iter = enditer;
|
|
--iter;
|
|
before = (*iter).first;
|
|
if (enditer == database.end())
|
|
valid = 2; // No upperbound
|
|
else {
|
|
after = (*enditer).first;
|
|
valid = 0; // Fully bounded
|
|
}
|
|
return (*iter).second;
|
|
}
|
|
valid = 1; // No lowerbound
|
|
after = (*enditer).first;
|
|
return defaultvalue;
|
|
}
|
|
|
|
} // End namespace ghidra
|
|
#endif
|
|
|
|
#if 0
|
|
|
|
#include <iostream>
|
|
using std::cout;
|
|
|
|
int main(int argc,char **argv)
|
|
|
|
{
|
|
partmap<int,unsigned int> data;
|
|
|
|
data.defaultValue() = 0;
|
|
data.split(5) = 5;
|
|
data.split(2) = 2;
|
|
data.split(3) = 4;
|
|
data.split(3) = 3;
|
|
|
|
cout << data.getValue(6) << endl;
|
|
cout << data.getValue(8) << endl;
|
|
cout << data.getValue(4) << endl;
|
|
cout << data.getValue(1) << endl;
|
|
|
|
partmap<int,unsigned int>::const_iterator iter;
|
|
|
|
iter = data.begin(3);
|
|
while(iter!=data.end()) {
|
|
cout << (*iter).second << endl;
|
|
++iter;
|
|
}
|
|
}
|
|
#endif
|
|
|