ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/partmap.hh

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