I have taken a look of your examples. In other languages we pass a comparison function as a parameter of the sorting function. This is not (or it is?) possible using ST language.
A way to do it may be to create an ABSTRACT FUNCTION_BLOCK FB_Sort with a private Compare and final Sort method. Then in your code you have to create your own FB_Sort_blablabla (example: FB_Sort_REAL) which derivate (EXTENDS) from the abstract FB_Sort. Then you override the Compare method to fit your needs (like comparing REAL, LREAL, INT, FB_Biscuit, FB_Something, etcβ¦).
You don't have to override the method Sort, it is the same for all your data types.
You don't need to implement anything in the body of your FB_Sort_blablabla.
To sort your array, simply call FB_Sort_blablabla.Sort(insert_all_parameters_as_described).
OPEN POINT
Since the function Sort uses an internal array of byte to be able to perform a variable swap, if your data type exceed the length of the array, the Sort method will return FALSE and your array will not be sorted. Maybe we should also pass as parameter the location of the temp variable to ensure that the swap will always be possible?
Or should we also add a method "Swap" which also need to be overriden?
We also can call the operator __NEW() with the needed byte count...
What are your thougt about it?
Back to the code
See code below (I have attached 2 FB's in PLCopenXML format):
The Abstract function block FB_Sort with abstract method Compare and final method Sort:
FUNCTION_BLOCK ABSTRACT FB_Sort(** Purpose: Run an optimized version of insertion sort with specified order* Author: NothinRandom* v1.0 September 16, 2020* Note:*)VAR_INPUTEND_VAR
// No code in the body, the sort algorithm is done using the Sort method// We could fill the body of this FB with the code of the Sort method// but then we cannot prevent someone to override it (or it will cause inatended behaviour)
Compare method:
(* Please override this method so it returns:* 0 : a == b*-1 : a < b* 1 : a > b* which a and b are the ADDRESS of the 2 elements you want to compare*)METHODABSTRACTCompare:DINTVAR_INPUTa:PVOID;b:PVOID;END_VAR
// No code here since it is an abstract method !!!
Sort method:
METHOD FINAL Sort : BOOLVAR_INPUT pbBuffer : POINTER TO BYTE; // pointer to buffer diElements : DINT; // array length uiDataSize : UINT; // use it like this : uiDataType := SIZEOF(MyDataType) // where MyDataType is the type your currently want to compare bDescending : BOOL := FALSE; // default ascendingEND_VARVAR _diIndex : DINT; // loop index _diMinIndex : DINT; // loop lowest index tested _diMaxIndex : DINT; // loop highest index tested _diCurrentIndex : DINT; // loop current tested element index _abTemp : ARRAY [1..8] OF BYTE; // store temp value _pbElement1 : PVOID; // pointer operator, current element _pbElement2 : PVOID; // pointer operator, insert element _pCurrent : PVOID;END_VAR
Ok ... that's for the base of all your future sort function block... Let see an example that can be used to sort REAL type:
First create a new FB which EXTENDS from FB_Sort like this (the FINAL keyword is not necessary):
FUNCTION_BLOCK FINAL FB_Sort_Real EXTENDS FB_SortVAR_INPUTEND_VARVAR_OUTPUTEND_VARVAREND_VAR
// Leave the body empty
Then, simply override the Compare method:
(* Please override this method so it returns:* 0 : a == b*-1 : a < b* 1 : a > b* which a and b are the ADDRESS of the 2 elements you want to compare*)METHODCompare:DINTVAR_INPUTa:PVOID;b:PVOID;END_VARVAR_a:REAL;//_b:REAL;END_VAR
About the MEMCMP/cast in the Compare function: Yes of course a byte per byte comparison is stupid for REAL and also on other types. I was so excited that I forget to remove this commented line of code of my example... shame on me.
We aren't far enough π ... insertion sort is not that bad but merge sort or quick sort will be really more effective. I am looking to adapt the sort provided in the OSCAT lib to run using a pointer (PVOID) instead of a POINTER TO ARRAY[1..32000] OF REAL. I have some issue with left and right boundaries and/or with the pivot start position. But I will find out soon I hope π
My end goal is really to provide a Sort "function" (or class) that can Sort anything using a given compare function. So it will be easy to sort some FB_Biscuit by area size to know which one will get the more chocolate on it π
Last edit: gised-link 2021-11-25
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You're right. I forgot π
A workaround for this can be:
Hi everyone,
I have taken a look of your examples. In other languages we pass a comparison function as a parameter of the sorting function. This is not (or it is?) possible using ST language.
A way to do it may be to create an ABSTRACT FUNCTION_BLOCK FB_Sort with a private Compare and final Sort method. Then in your code you have to create your own FB_Sort_blablabla (example: FB_Sort_REAL) which derivate (EXTENDS) from the abstract FB_Sort. Then you override the Compare method to fit your needs (like comparing REAL, LREAL, INT, FB_Biscuit, FB_Something, etcβ¦).
You don't have to override the method Sort, it is the same for all your data types.
You don't need to implement anything in the body of your FB_Sort_blablabla.
To sort your array, simply call FB_Sort_blablabla.Sort(insert_all_parameters_as_described).
OPEN POINT
Since the function Sort uses an internal array of byte to be able to perform a variable swap, if your data type exceed the length of the array, the Sort method will return FALSE and your array will not be sorted. Maybe we should also pass as parameter the location of the temp variable to ensure that the swap will always be possible?
Or should we also add a method "Swap" which also need to be overriden?
We also can call the operator __NEW() with the needed byte count...
What are your thougt about it?
Back to the code
See code below (I have attached 2 FB's in PLCopenXML format):
The Abstract function block FB_Sort with abstract method Compare and final method Sort:
Compare method:
// No code here since it is an abstract method !!!
Sort method:
Ok ... that's for the base of all your future sort function block... Let see an example that can be used to sort REAL type:
First create a new FB which EXTENDS from FB_Sort like this (the FINAL keyword is not necessary):
// Leave the body empty
Then, simply override the Compare method:
And I use the code like it somewhere inside my project:
Last edit: gised-link 2021-11-24
I was worried we went a little too far on this topic, but you clearly went a step further.
Just about the real comparaison, real values are stored as IEEE format (see : https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:binary32 ). That's a good exemple why you need to type cast and compare values knowing the datatype you are comparing.
great input π
Edit : Typo
Last edit: dFx 2021-11-25
About the MEMCMP/cast in the Compare function: Yes of course a byte per byte comparison is stupid for REAL and also on other types. I was so excited that I forget to remove this commented line of code of my example... shame on me.
We aren't far enough π ... insertion sort is not that bad but merge sort or quick sort will be really more effective. I am looking to adapt the sort provided in the OSCAT lib to run using a pointer (PVOID) instead of a POINTER TO ARRAY[1..32000] OF REAL. I have some issue with left and right boundaries and/or with the pivot start position. But I will find out soon I hope π
My end goal is really to provide a Sort "function" (or class) that can Sort anything using a given compare function. So it will be easy to sort some FB_Biscuit by area size to know which one will get the more chocolate on it π
Last edit: gised-link 2021-11-25
(for the future me: DO NOT SPAM THE POST BUTTON)
Last edit: gised-link 2021-11-25