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:
mumpf 2022-11-12 11:23:04 +01:00 committed by GitHub
parent eef3a85b18
commit b51c5950c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 24 deletions

View File

@ -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 i = (low + high) / 2;
uint16_t asap_i = getASAP(i);
if (asap_i == asap)
{
// 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);
}
return getTSAP(i);
if(asap_i > asap)
high = i - 1;
else
low = i + 1 ;
}
#else
for (uint16_t i = 0; i < entries; i++)
}
else
{
// 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)

View File

@ -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;
};