mirror of
https://github.com/thelsing/knx.git
synced 2024-12-18 19:08:18 +01:00
reimplemented binary search for translateAsap() (#220)
* reimplemented binary search for translateAsap() - new prepareBinarySearch() after association_table change - fallback to linear search if ETS does not provide sorted ASAP entries - activated with #define BIN_SEARCH * added required comments to explain algorithm Co-authored-by: Waldemar Porscha <wp@porscha.eu>
This commit is contained in:
parent
eef3a85b18
commit
b51c5950c5
@ -39,46 +39,97 @@ uint16_t AssociationTableObject::getASAP(uint16_t idx)
|
||||
return ntohs(_tableData[2 * idx + 2]);
|
||||
}
|
||||
|
||||
// after any table change the table is checked if it allows
|
||||
// binary search access. If not, sortedEntryCount stays 0,
|
||||
// otherwise sortedEntryCount represents size of bin search array
|
||||
void AssociationTableObject::prepareBinarySearch()
|
||||
{
|
||||
sortedEntryCount = 0;
|
||||
#ifdef USE_BINSEARCH
|
||||
uint16_t lastASAP = 0;
|
||||
uint16_t currentASAP = 0;
|
||||
uint16_t lookupIdx = 0;
|
||||
uint16_t lookupASAP = 0;
|
||||
// we iterate through all ASAP
|
||||
// the first n ASAP are sorted (strictly increasing number), these are assigning sending TSAP
|
||||
// the remaining ASAP have to be all repetitions, otherwise we set sortedEntryCount to 0, which forces linear search
|
||||
for (uint16_t idx = 0; idx < entryCount(); idx++)
|
||||
{
|
||||
currentASAP = getASAP(idx);
|
||||
if (sortedEntryCount)
|
||||
{
|
||||
// look if the remaining ASAP exist in the previously sorted list.
|
||||
while (lookupIdx < sortedEntryCount)
|
||||
{
|
||||
lookupASAP = getASAP(lookupIdx);
|
||||
if (currentASAP <= lookupASAP)
|
||||
break; // while
|
||||
else
|
||||
lookupIdx++;
|
||||
}
|
||||
if (currentASAP < lookupASAP || lookupIdx >= sortedEntryCount)
|
||||
{
|
||||
// a new ASAP found, we force linear search
|
||||
sortedEntryCount = 0;
|
||||
break; // for
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for strictly increasing ASAP
|
||||
if (currentASAP > lastASAP)
|
||||
lastASAP = currentASAP;
|
||||
else
|
||||
{
|
||||
sortedEntryCount = idx; // last found index indicates end of sorted list
|
||||
idx--; // current item has to be handled as remaining ASAP
|
||||
}
|
||||
}
|
||||
}
|
||||
// in case complete table is strictly increasing
|
||||
if (lookupIdx == 0 && sortedEntryCount == 0)
|
||||
sortedEntryCount = entryCount();
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint8_t* AssociationTableObject::restore(const uint8_t* buffer)
|
||||
{
|
||||
buffer = TableObject::restore(buffer);
|
||||
_tableData = (uint16_t*)data();
|
||||
prepareBinarySearch();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// return type is int32 so that we can return uint16 and -1
|
||||
int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
||||
{
|
||||
uint16_t entries = entryCount();
|
||||
#ifdef USE_BINSEARCH
|
||||
uint16_t low,high,i;
|
||||
low = 0;
|
||||
high = entries-1;
|
||||
// sortedEntryCount is determined in prepareBinarySearch()
|
||||
// if ETS provides strictly increasing numbers for ASAP
|
||||
// represents the size of the array to search
|
||||
if (sortedEntryCount)
|
||||
{
|
||||
uint16_t low = 0;
|
||||
uint16_t high = sortedEntryCount - 1;
|
||||
|
||||
while(low <= high)
|
||||
{
|
||||
i = (low+high)/2;
|
||||
uint16_t asap_i = getASAP(i);
|
||||
if (asap_i == asap)
|
||||
while(low <= high)
|
||||
{
|
||||
// as the binary search does not hit the first element in a list with identical items,
|
||||
// search downwards to return the first occurence in the table
|
||||
while(getASAP(--i) == asap)
|
||||
;
|
||||
return getTSAP(i+1);
|
||||
uint16_t i = (low + high) / 2;
|
||||
uint16_t asap_i = getASAP(i);
|
||||
if (asap_i == asap)
|
||||
return getTSAP(i);
|
||||
if(asap_i > asap)
|
||||
high = i - 1;
|
||||
else
|
||||
low = i + 1 ;
|
||||
}
|
||||
if(asap_i > asap)
|
||||
high = i - 1;
|
||||
else
|
||||
low = i + 1 ;
|
||||
}
|
||||
#else
|
||||
for (uint16_t i = 0; i < entries; i++)
|
||||
else
|
||||
{
|
||||
if (getASAP(i) == asap)
|
||||
return getTSAP(i);
|
||||
// if ASAP numbers are not strictly increasing linear seach is used
|
||||
for (uint16_t i = 0; i < entryCount(); i++)
|
||||
if (getASAP(i) == asap)
|
||||
return getTSAP(i);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -89,6 +140,7 @@ void AssociationTableObject::beforeStateChange(LoadState& newState)
|
||||
return;
|
||||
|
||||
_tableData = (uint16_t*)data();
|
||||
prepareBinarySearch();
|
||||
}
|
||||
|
||||
int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx)
|
||||
|
@ -19,5 +19,7 @@ class AssociationTableObject : public TableObject
|
||||
uint16_t entryCount();
|
||||
uint16_t getTSAP(uint16_t idx);
|
||||
uint16_t getASAP(uint16_t idx);
|
||||
void prepareBinarySearch();
|
||||
uint16_t* _tableData = 0;
|
||||
uint16_t sortedEntryCount;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user