mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +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