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]);
|
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)
|
const uint8_t* AssociationTableObject::restore(const uint8_t* buffer)
|
||||||
{
|
{
|
||||||
buffer = TableObject::restore(buffer);
|
buffer = TableObject::restore(buffer);
|
||||||
_tableData = (uint16_t*)data();
|
_tableData = (uint16_t*)data();
|
||||||
|
prepareBinarySearch();
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return type is int32 so that we can return uint16 and -1
|
// return type is int32 so that we can return uint16 and -1
|
||||||
int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
||||||
{
|
{
|
||||||
uint16_t entries = entryCount();
|
// sortedEntryCount is determined in prepareBinarySearch()
|
||||||
#ifdef USE_BINSEARCH
|
// if ETS provides strictly increasing numbers for ASAP
|
||||||
uint16_t low,high,i;
|
// represents the size of the array to search
|
||||||
low = 0;
|
if (sortedEntryCount)
|
||||||
high = entries-1;
|
{
|
||||||
|
uint16_t low = 0;
|
||||||
|
uint16_t high = sortedEntryCount - 1;
|
||||||
|
|
||||||
while(low <= high)
|
while(low <= high)
|
||||||
{
|
|
||||||
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,
|
uint16_t i = (low + high) / 2;
|
||||||
// search downwards to return the first occurence in the table
|
uint16_t asap_i = getASAP(i);
|
||||||
while(getASAP(--i) == asap)
|
if (asap_i == asap)
|
||||||
;
|
return getTSAP(i);
|
||||||
return getTSAP(i+1);
|
if(asap_i > asap)
|
||||||
|
high = i - 1;
|
||||||
|
else
|
||||||
|
low = i + 1 ;
|
||||||
}
|
}
|
||||||
if(asap_i > asap)
|
|
||||||
high = i - 1;
|
|
||||||
else
|
|
||||||
low = i + 1 ;
|
|
||||||
}
|
}
|
||||||
#else
|
else
|
||||||
for (uint16_t i = 0; i < entries; i++)
|
|
||||||
{
|
{
|
||||||
if (getASAP(i) == asap)
|
// if ASAP numbers are not strictly increasing linear seach is used
|
||||||
return getTSAP(i);
|
for (uint16_t i = 0; i < entryCount(); i++)
|
||||||
|
if (getASAP(i) == asap)
|
||||||
|
return getTSAP(i);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +140,7 @@ void AssociationTableObject::beforeStateChange(LoadState& newState)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_tableData = (uint16_t*)data();
|
_tableData = (uint16_t*)data();
|
||||||
|
prepareBinarySearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx)
|
int32_t AssociationTableObject::nextAsap(uint16_t tsap, uint16_t& startIdx)
|
||||||
|
@ -19,5 +19,7 @@ class AssociationTableObject : public TableObject
|
|||||||
uint16_t entryCount();
|
uint16_t entryCount();
|
||||||
uint16_t getTSAP(uint16_t idx);
|
uint16_t getTSAP(uint16_t idx);
|
||||||
uint16_t getASAP(uint16_t idx);
|
uint16_t getASAP(uint16_t idx);
|
||||||
|
void prepareBinarySearch();
|
||||||
uint16_t* _tableData = 0;
|
uint16_t* _tableData = 0;
|
||||||
|
uint16_t sortedEntryCount;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user