From cb2b4b330b87a5fb548aea2a614e482aab8ce54e Mon Sep 17 00:00:00 2001 From: Bart Jablonski Date: Mon, 2 Feb 2026 14:11:35 +0100 Subject: [PATCH] The DFA package [ver. 0.5.9] The DFA package [ver. 0.5.9] Package regenerated with SAS Packages Framework, version 20250202. No functional changes, documentation cleaned up. --- README.md | 2 +- dfa.md | 14 +- dfa.zip | Bin 48977 -> 49267 bytes hist/0.5.9/dfa.md | 1701 ++++++++++++++++++++++++++++++++++++++++++++ hist/0.5.9/dfa.zip | Bin 0 -> 49267 bytes 5 files changed, 1709 insertions(+), 8 deletions(-) create mode 100644 hist/0.5.9/dfa.md create mode 100644 hist/0.5.9/dfa.zip diff --git a/README.md b/README.md index fe3e1ab..4df8691 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a pr Run `%helpPackage(DFA,createDFArray)` to find examples. -SHA256 digest for the latest version of `DFA`: F*643FBE2B7AE1425FC0240139813B93AE2C6BCFFDF6A0CFAEBEC11F83D3548E57 +SHA256 digest for the latest version of `DFA`: F*17C88537F5FA9BCFAA1AC4803D0F1EF47665C8446A44C82B5558A08315DF0C49 [**Documentation for DFA**](./dfa.md "Documentation for DFA") diff --git a/dfa.md b/dfa.md index b7b38be..df4a6cd 100644 --- a/dfa.md +++ b/dfa.md @@ -9,22 +9,22 @@ ### Version information: - Package: DFA -- Version: 0.5.8 -- Generated: 2026-01-26T15:19:02 +- Version: 0.5.9 +- Generated: 2026-02-02T13:54:19 - Author(s): Bartosz Jablonski (yabwon@gmail.com) - Maintainer(s): Bartosz Jablonski (yabwon@gmail.com) - License: MIT -- File SHA256: `F*643FBE2B7AE1425FC0240139813B93AE2C6BCFFDF6A0CFAEBEC11F83D3548E57` for this version -- Content SHA256: `C*E2E883D8F8A7F7FCB97C2B7240FD5E70A8A6F2A6B3F0F75119F47886338C6B0C` for this version +- File SHA256: `F*17C88537F5FA9BCFAA1AC4803D0F1EF47665C8446A44C82B5558A08315DF0C49` for this version +- Content SHA256: `C*1818B4D524F779F2FB3A242D9E5BEEB592074A92D68135E18A660E594B214401` for this version --- -# The `DFA` package, version: `0.5.8`; +# The `DFA` package, version: `0.5.9`; --- -# The DFA package [ver. 0.5.8] ############################################### +# The DFA package [ver. 0.5.9] ############################################### The **DFA** (a.k.a. *Dynamic Function Array*) package implements: - dynamic numeric and character arrays, @@ -56,7 +56,7 @@ Required SAS Components: --------------------------------------------------------------------- -*SAS package generated by SAS Package Framework, version `20260125`,* +*SAS package generated by SAS Package Framework, version `20260202`,* *under `WIN`(`X64_10PRO`) operating system,* *using SAS release: `9.04.01M9P06042025`.* diff --git a/dfa.zip b/dfa.zip index 25452b067bf100d4719486a09a1000d28f67d3ce..2b6cc222341576007e26b542988bf73a00103219 100644 GIT binary patch delta 10579 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 OIFU|PSa8!H68{56Tq&&p diff --git a/hist/0.5.9/dfa.md b/hist/0.5.9/dfa.md new file mode 100644 index 0000000..df4a6cd --- /dev/null +++ b/hist/0.5.9/dfa.md @@ -0,0 +1,1701 @@ +# Documentation for the `DFA` package. + +---------------------------------------------------------------- + + *Dynamic function arrays and other useful data structures* + +---------------------------------------------------------------- + +### Version information: + +- Package: DFA +- Version: 0.5.9 +- Generated: 2026-02-02T13:54:19 +- Author(s): Bartosz Jablonski (yabwon@gmail.com) +- Maintainer(s): Bartosz Jablonski (yabwon@gmail.com) +- License: MIT +- File SHA256: `F*17C88537F5FA9BCFAA1AC4803D0F1EF47665C8446A44C82B5558A08315DF0C49` for this version +- Content SHA256: `C*1818B4D524F779F2FB3A242D9E5BEEB592074A92D68135E18A660E594B214401` for this version + +--- + +# The `DFA` package, version: `0.5.9`; + +--- + + +# The DFA package [ver. 0.5.9] ############################################### + +The **DFA** (a.k.a. *Dynamic Function Array*) package implements: + - dynamic numeric and character arrays, + - dynamic stacks (filo), + - dynamic queues (fifo), + - dynamic ordered stacks, + - priority queues, + - bitmap. + +The package provides a set of *macros*, +which allows to *generate* `call routines` +simulating data structures mentioned above. + +Few exemplary functions are also generated. +See particular macro help for further details. + +--- + +--- + + +--- + +Required SAS Components: + - Base SAS Software + +--- + + +--------------------------------------------------------------------- + +*SAS package generated by SAS Package Framework, version `20260202`,* +*under `WIN`(`X64_10PRO`) operating system,* +*using SAS release: `9.04.01M9P06042025`.* + +--------------------------------------------------------------------- + +# The `DFA` package content +The `DFA` package consists of the following content: + +1. [`%createdfarray()` macro ](#createdfarray-macro-1 ) +2. [`%createdharray()` macro ](#createdharray-macro-2 ) +3. [`%createdhfifo()` macro ](#createdhfifo-macro-3 ) +4. [`%createdhordstack()` macro ](#createdhordstack-macro-4 ) +5. [`%createdhprtqueue()` macro ](#createdhprtqueue-macro-5 ) +6. [`%createdhstack()` macro ](#createdhstack-macro-6 ) +7. [`bit64andprotodfa()` proto ](#bit64andprotodfa-proto-7 ) +8. [`bit64orprotodfa()` proto ](#bit64orprotodfa-proto-8 ) +9. [`bit64anddfa()` function ](#bit64anddfa-functions-9 ) +10. [`bit64ordfa()` function ](#bit64ordfa-functions-10 ) +11. [`%createdfbitmap()` macro ](#createdfbitmap-macro-11 ) +12. [`generatearrays` exec ](#generatearrays-exec-12 ) +13. [`generatearrays` clean ](#generatearrays-clean-13 ) + + +14. [License note](#license) + +--- + +## `%createdfarray()` macro ###### + +## >>> `%createDFArray()` macro: <<< ####################### + +The `%createDFArray()` macro allows to generate +a `dynamic function array` which is a FCMP based +approach to create *dynamically* allocated **numeric** +array with possible values searching and `WHICHN()` +function emulation. + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDFArray( + arrayName + <,debug=0> + <,simple=0> + <,resizeFactor=0> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayName` - *Required*, creates a FCMP call subroutine which is also + an array name. In the data step it is used in form of + a call subroutine, e.g. `call arrayName("Allocate", -3, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `simple=` - *Optional*, the default value is `0`. A *simple* dynamic + function array is one which is not searchable and does not + allows to use `which()` functionality. + If set to `1` then it disables `SEARCH` and `WHICH` functionality. + See examples below for details. + +* `resizeFactor=` - *Optional*, the default value is `0`. If set to `0` then + the dynamic array size is not changeable(mutable) after initial + size allocation. + If set not to `0` then arrays dimensions are mutable after allocation, + i.e. even if an array is allocated for ten elements (like `A[1:10]`) + you can do `A[17] = 42` and it will resize itself dynamically. + *Hint!* Set to, e.g. 4999, for faster allocation process. + See examples below for details. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &arrayName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `R`, `Return` - to get the data from an array, + - `I`, `Input` - to insert the data into an array, + - `+`, `Add` - to increment given position by a value, + - `C`, `Clear` - to reduce an array to a single empty cell, + - `A`, `Allocate` - to reserve space for array width and set starting values, + - `D`, `Dimension` - to return minimal and maximal index of an array, + - `F`, `Find`, `Exist` - to find out if a given value exist in an array, + - `W`, `Which` - to search the first position of data in array, `WHICHN()` function emulator, + - `Sum` - to return the sum of non-missing elements of an array, + - `Nonmiss` - to return the number of non-missing elements of an array, + - `Avg`, `Mean`, `Average` - to return the average of non-missing elements of an array, + - `Min`, `Minimum` - to return the minimum of non-missing elements of an array, + - `Max`, `Maximum` - to return the maximum of non-missing elements of an array. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return`/ `I`, `Input`/ `+`, `Add` it takes + an arrays index from (into) which data is get (put), + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` sets the value of the minposition, i.e. the minimal position of the array index, + - for `D`, `Dimension` it returns value of the minposition, + - for `Sum`, `Nonmiss`, `Avg`, `Mean`, `Average`, `Min`, `Minimum`, `Max`, and `Maximum` is ignored, + - for `F`, `Find`, `Exist` it returns number of occurrences of a given value in an array, + - for `W`, `Which` it returns position the first occurrence of a given value in an array. + +.3 `value` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return` it holds value retrieved from an array on a given position, + - for `I`, `Input` it holds the value inserted into an array on a given position, + - for `+`, `Add` it holds the value that is used to increment an array value at a given position, + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` it sets the value of the maxposition, i.e. maximal position of the array index, + - for `D`, `Dimension` it returns value of the maxposition + - for `Sum`, `Nonmiss`, `Avg`, `Mean`, `Average`, `Min`, `Minimum`, `Max`, and `Maximum` it returns + the calculated summary value, + - for `F`, `Find`, `Exist`, `W`, `Which` is the value to be searched in an array. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Searchable, and Immutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSI); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + call ArrDSI("Allocate", 1, 10); + L = 0; H = 0; + call ArrDSI("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H; + call ArrDSI("Input", i, i**2); + end; + + * searchability allows to find number of occurrences of value in the array ; + F = .; + call ArrDSI("Find", F, 16); + put "Value 16 occurs " F "times"; + call ArrDSI("Find", F, 17); + put "Value 17 occurs " F "times"; + + * increase value of cell 4 by 1, and verify at WHICH position is 17 (by searchability); + call ArrDSI("+", 4, 1); + call ArrDSI("Which", F, 17); + put "Value 17 occurred for the first time at position " F; + + * get values from the array ; + Value = .; + do i = L to H; + call ArrDSI("Output", i, Value); + put i= Value=; + end; + + * some basic statistics ; + call ArrDSI("Sum", ., STAT); put "sum = " STAT; + call ArrDSI("Avg", ., STAT); put "avg = " STAT; + call ArrDSI("Min", ., STAT); put "min = " STAT; + call ArrDSI("Max", ., STAT); put "max = " STAT; + call ArrDSI("Cnt", ., STAT); put "cnt = " STAT; + + * immutability does _not_ allow to increase dimensions automatically; + * this line returns an error ; + call ArrDSI("Input", 42, -1); + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Searchable, and Mutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSM, resizefactor=17); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + call ArrDSM("Allocate", -2, 2); + + do i = -2 to 2; + call ArrDSM("Input", i, 2**i); + end; + + L = .; H = .; + call ArrDSM("Dim", L, H); + put L= H=; + + * mutability allows to increase dimensions automatically + * create index 3 and -3; + call ArrDSM("+", 3, 8); + call ArrDSM("+",-3, 0.125); + call ArrDSM("Dim", L, H); + put L= H=; + + Value = .; + do i = L to H; + call ArrDSM("O", i, Value); + put i= Value=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Dynamic, non-searchable (a.k.a. SiMPle), and Immutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSMPLI, simple=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example3; + call ArrDSMPLI("Allocate", -2, 2); + + do i = -2 to 2; + call ArrDSMPLI("Input", i, 2**i); + end; + + * non-searchable array (a.k.a. simple) does not allow ; + * to find number of occurrences of value in the array ; + * and verify what is the first position of a value ; + * this lines return a warning ; + call ArrDSMPLI("Exist", i, 1); + call ArrDSMPLI("Which", i, 1); + run; + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Dynamic, non-searchable (a.k.a. SiMPle), and Mutable array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFArray(ArrDSMPLM, simple=1, resizefactor=42); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example4; + call ArrDSMPLM("Allocate", 1, 1); + + * mutability allows to increase dimensions automatically ; + do i = -12 to 12; + call ArrDSMPLM("Input", i, i*2); + end; + + * non-searchable array (a.k.a. simple) does not allow ; + * to find number of occurrences of value in the array ; + * and verify what is the first position of a value ; + * this lines return a warning ; + i = .; + call ArrDSMPLM("Exist", i, -24); + put "Exist " i=; + call ArrDSMPLM("Which", i, 24); + put "Which " i=; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdharray()` macro ###### + +## >>> `%createDHArray()` macro: <<< ####################### + +The `%createDHArray()` macro allows to generate +a `dynamic hash array` which is a FCMP based approach +to create *dynamically* allocated **numeric** +or **character** array + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHArray( + arrayName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayName` - *Required*, creates a FCMP call subroutine which is also + an array name. In the data step it is used in form of + a call subroutine, e.g. `call arrayName("Allocate", -3, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &arrayName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `R`, `Return` - to get the data from an array, + - `I`, `Input` - to insert the data into an array, + - `C`, `Clear` - to reduce an array to a single empty cell, + - `L`, `Low`, `Lower`, `Lbound` - to return minimal position of index, + - `H`, `High`, `Higher`, `Hbound` - to return maximal position of index. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `R`, `Return`/ `I`, and `Input` it is an array + index from (into) which data is get (put), + - for `C` it is ignored, + - for `L`, `Low`, `Lower`, and `Lbound` it returns the first position of an index, + - for `H`, `High`, `Higher`, and `Hbound` it returns the last position of an index, + - otherwise is not modified. + +3. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `R`, and `Return` it holds value retrieved from an array from a given position, + - for `I`, `Input` it holds the value inserted into an array into a given position, + - for `C` is ignored, + - for `L`, `Low`, `Lower`, and `Lbound` returns first value of index, + - for `H`, `High`, `Higher`, and `Hbound` returns last value of index, + - otherwise is not modified. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHArray(ArrDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); + do _I_ = -1e&zeros. to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call ArrDHC("Input", _I_, _X_); + end; + t = time() - t; + put t= / _X_= /; + + * get the size info ; + LB = 0; HB = 0; + drop LB HB; + call ArrDHC('Lbound', LB, _X_); + call ArrDHC('Hbound', HB, _X_); + put LB= HB= /; + + t = time(); + do _I_ = HB + 1 to LB - 1 by -1; + call ArrDHC('Output', _I_, _X_); + output; + end; + t = time() - t; + put t= / _X_= /; + + * clear for further reuse ; + call ArrDHC('C', ., ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric array: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHArray(ArrDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do i = -2 to 2; + call ArrDHN("Input", i, 2**i); + end; + + do i = -2 to 2; + call ArrDHN("+", i, -10); + end; + + v = .; + do i = -2 to 2; + call ArrDHN("Output", i, v); + put i= v=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdhfifo()` macro ###### + +## >>> `%createDHFifo()` macro: <<< ####################### + +The `%createDHFifo()` macro allows to generate +a `dynamic hash fifo` which is a FCMP based approach +to create dynamically allocated numeric or character +"first in first out" [queue](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) + +Interesting reading about implementing a fifo via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHFifo( + fifoName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `fifoName` - *Required*, creates a FCMP call subroutine which is also + a fifo name. In the data step it is used in form of + a call subroutine, e.g. `call fifoName("Enqueue", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &fifoName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `D`, `Dequeue`, `R`, `Return` - to get the data from a fifo (and remove it from the fifo) + - `I`, `Input`, `E`, `Enqueue`, and `Insert` - to insert the data into a fifo + - `C`, `Clear` - to reduce a fifo to an empty one + - `P`, `Peek`, `T`, and `Tail` - to peek the data from a fifo (and NOT remove it from the fifo) + - `H`, `Head` - to peek the data from a fifo head (and NOT remove it from the fifo) + - `Sum` - returns sum of nonmissing numeric elements of a stack + - `Avg`, `Mean`, `Average` - returns average of nonmissing numeric elements of a stack + - `Nonmiss`, `Cnt` - returns number of nonmissing elements of a stack + - `Height` - returns height a stack + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` it holds the value popped from the fifo, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds the value to be pushed into the fifo, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` holds the value peeked from the fifo, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, and `Height` it returns calculated summary value. + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character fifo: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHFifo(FifoDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); drop t; + do _I_ = 1 to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call FifoDHC("Enqueue", _X_); + end; + t = time() - t; + + call FifoDHC("Height", _X_); + put t= / _X_=; + + t = time(); + do _I_ = 1 to 1e&zeros. + 3; + call FifoDHC('Dequeue', _X_); + output; + end; + t = time() - t; + + call FifoDHC("Height", _X_); + put t= / _X_=; + + %* clear for further reuse *; + call FifoDHC('Clear', ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric fifo: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHFifo(FifoDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _I_ = 1,.,2,.,3,.,4,.,5,.,6; + call FifoDHN("E", _I_); + end; + + call FifoDHN("Sum", _I_); + put "Sum " _I_=; + + call FifoDHN("Avg", _I_); + put "Avg " _I_=; + + call FifoDHN("Cnt", _I_); + put "Cnt " _I_=; + + call FifoDHN("Height", _I_); + put "Height " _I_=; + + call FifoDHN("Tail", _I_); + put "Tail of fifo is " _I_=; + + call FifoDHN("Height", _I_); + put "Height after Tail " _I_=; + + call FifoDHN("Head", _I_); + put "Head of fifo is " _I_=; + + call FifoDHN("Height", _I_); + put "Height after Head" _I_=; + + _X_ = 0; + do _I_ = 1 to _I_; + call FifoDHN('D', _X_); + output; + end; + + call FifoDHN("Height", _I_); + put "Height " _I_=; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdhordstack()` macro ###### + +## >>> `%createDHOrdStack()` macro: <<< ####################### + +The `%createDHOrdStack()` macro allows to generate +a `dynamic ORDERED hash stack` which is a FCMP based approach +to create dynamically allocated numeric or character +*ordered* [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) + +Interesting reading about implementing a stack via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHOrdStack( + fifoName + <,debug=0> + <,type=8> + <,order=A> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `stackName` - *Required*, creates a FCMP call subroutine which is also + a stack name. In the data step it is used in form of + a call subroutine, e.g. `call stackName("Push", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `order=` - *Optional*, the default value is `A`. + Indicates a method of ordering of the stack, + allowed values are: `A` for ascending and `D` for descending. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &stackName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` - to get the data from a stack (and remove it from the top), + - `I`, `Input`, `Push`, `Put`, `Insert` - to insert the data into a stack, + - `C`, `Clear` - to reduce a stack to an empty one, + - `P`, `Peek` - to peek the data from a stack (and NOT remove it from the top), + - `Sum` - returns sum of non-missing numeric elements of a stack, + - `Avg`, `Mean`, `Average` - returns average of non-missing numeric elements of a stack, + - `Nonmiss`, `Cnt`, `Nnm` - returns number of non-missing elements of a stack, + - `Height` - returns height a stack, + - `Min`, `Minimum` - returns minimum of non-missing elements of a stack, + - `Max`, `Maximum` - returns maximum of non-missing elements of a stack. + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` it holds a value popped from a stack, + - for `I`, `Input`, `Push`, `Put`, `Insert` it holds a value to be pushed into a stack, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` it holds a value peeked from a stack, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height`, `Min`, `Minimum`, `Max`, and `Maximum` + it returns calculated summary value, + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character Descending Ordered stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHOrdStack(DescStackC, type = $ 12, order=D); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + + do _X_ = "A","B"," ","C","A"," ","B","C"; + call DescStackC("Push", _X_); + end; + + length S $ 12; + call DescStackC('Height', S); + put 'Height ' S; + + do until(strip(S) = "0"); + call DescStackC('Get', _X_); + call DescStackC('Height', S); + put S= _X_=; + output; + end; + + %* clear for further reuse *; + call DescStackC('Clear',''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric Ascending Ordered stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHOrdStack(DescStackN, order=A); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + call missing(Sum, Avg, Min, Max, Cnt, Hgt, Peek); + do _X_ = 1,6,2,.,5,3,4; + call DescStackN("Put", _X_); + call DescStackN('Sum', Sum); + call DescStackN('Avg', Avg); + call DescStackN('Min', Min); + call DescStackN('Max', Max); + call DescStackN('Cnt', Cnt); + call DescStackN('Height', Hgt); + put (_ALL_) (=); + end; + + call DescStackN('Peek', Peek); + put Peek=; + + do _I_ = 1 to Hgt; + call DescStackN('Output', _X_); + keep _X_; + if _X_ > .z then output; + end; + + call DescStackN('Peek', Peek); + put Peek=; + + %* clear for further reuse *; + call DescStackN('Clear',.); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdhprtqueue()` macro ###### + +## >>> `%createDHPrtQueue()` macro: <<< ####################### + + +The `%createDHPrtQueue()` macro allows to generate +a `dynamic PRIORITY hash queue` which is a FCMP based approach +to create dynamically allocated numeric or character +[priority queue](https://en.wikipedia.org/wiki/Priority_queue) + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHPrtQueue( + fifoName + <,debug=0> + <,type=8> + <,newOnTop=+> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `queueName` - *Required*, creates a FCMP call subroutine which is also + a queue name. In the data step it is used in form of + a call subroutine, e.g. `call queueName("Bottom", 1, 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `newOnTop=` - *Optional*, the default value is `+`. + Indicates how to keep order in the same priority group, + allowed values are `+` or `-`. Plus(`+`) sets new elements + at the top of the group, minus(`-`) at the bottom. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &queueName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `D`, `Dequeue`, `R`, `Return` - it pops/gets/outputs the data from the queue head (high priority), + - `B`, `Bottom` - it pops/gets/outputs the data from the queue tail (low priority), + - `I`, `Input`, `E`, `Enqueue`, `Insert` - it push/puts/inserts the data into the queue, + - `C`, `Clear` - it reduces a queue to an empty one, + - `H`, `Head` - it peeks the data from the queue head and NOT removes it, + - `T`, `Tail` - it peeks the data from the queue tail and NOT removes it, + - `Sum` - it returns sum of non-missing *numeric* elements of the queue, + - `Avg`, `Mean`, `Average` - it returns average of non-missing *numeric* elements of the queue, + - `Nonmiss`, `Cnt` - it returns number of non-missing elements of the queue, + - `Height` - it returns height of the queue. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` and `B`, `Bottom`, or `H`, `Head`, `T`, `Tail` + it holds a priority level of value popped from the queue, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds a priority level of value to be pushed into the queue, + - for `C` ignored, + - for *numeric* queue and `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` returns calculated summary value. + +3. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `D`, `Dequeue`, `R`, `Return` and `B`, `Bottom` or `H`, `Head`, `T`, `Tail` + it holds a value popped from the queue, + - for `I`, `Input`, `E`, `Enqueue`, `Insert` it holds a value to be pushed into the queue, + - for `C` ignored, + - for *numeric* queue and `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` returns calculated summary value, + - otherwise does not modify value. + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character Priority queue: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHPrtQueue(PriorityQueuePC, type = $ 12, newOnTop=+); + %createDHPrtQueue(PriorityQueueNC, type = $ 12, newOnTop=-); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + + _I_ = .; + length _X_ _Y_ $ 3; + do _X_ = "AAA","BBB","CCC","AA","BB","CC","A","B","C"; + _I_ + 1; + call PriorityQueuePC("I", mod(_I_, 3), _X_); + call PriorityQueueNC("I", mod(_I_, 3), _X_); + end; + + Height = .; + call PriorityQueuePC('Height', Height, ''); + put Height=; + + do until(Height = 0); + call PriorityQueuePC('Dequeue', _I_, _X_); + call PriorityQueueNC("Dequeue", _I_, _Y_); + call PriorityQueueNC('Height', Height, ''); + put (_ALL_) (=); + output; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric Priority queue: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHPrtQueue(PriorityQueueN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _X_ = -5 to 5; + call PriorityQueueN("Enqueue", abs(_X_), _X_); + end; + + call missing(Sum, Avg, Cnt, Hgt); + call PriorityQueueN('Sum', ., Sum); + call PriorityQueueN('Avg', ., Avg); + call PriorityQueueN('Cnt', ., Cnt); + call PriorityQueueN('Height', ., Hgt); + put (_ALL_) (=); + + do _N_ = 1 to Hgt; + call PriorityQueueN("Dequeue", _X_, _Y_); + put _X_= _Y_=; + end; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdhstack()` macro ###### + +## >>> `%createDHStack()` macro: <<< ####################### + +The `%createDHStack()` macro allows to generate +a `dynamic hash stack` which is a FCMP based approach +to create dynamically allocated numeric or character +[stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) + +Interesting reading about implementing a stack via hash table +can be found in *chapter 10.4* of the: +*"Data Management Solutions Using SAS Hash Table Operations: + A Business Intelligence Case Study"* book +by Paul Dorfman and Don Henderson. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDHStack( + fifoName + <,debug=0> + <,type=8> + <,outlib=work.DFAfcmp.package> + <,hashexp=13> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `stackName` - *Required*, creates a FCMP call subroutine which is also + a stack name. In the data step it is used in form of + a call subroutine, e.g. `call stackName("Push", 3)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `type=` - *Optional*, the default value is `8`. + Indicates what *type* (numeric/character) and *length* + are data portion of generated array. Should be in line + with the LENGTH statement, e.g. `8`, `$ 30`, etc. + Determines if the `value` argument is numeric or character. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `hashexp=` - *Optional*, the default value is `13`. It is the default `hashexp=` + value for internal hash table used by the function. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &stackName.(IO, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` - to get the data from a stack (and remove it from the top), + - `I`, `Input`, `Push`, `Put`, `Insert` - to insert the data into a stack, + - `C`, `Clear` - to reduce a stack to an empty one, + - `P`, `Peek` - to peek the data from a stack (and NOT remove it from the top), + - `Sum` - returns sum of non-missing numeric elements of a stack, + - `Avg`, `Mean`, `Average` - returns average of non-missing numeric elements of a stack, + - `Nonmiss`, `Cnt`, `Nnm` - returns number of non-missing elements of a stack, + - `Height` - returns height a stack, + +2. `value` - is a *numeric* or *character* argument (determined by the `type=`) + and depends on the `IO` value. Behaves in the following way: + - for `O`, `Output`, `Pop`, `G`, `Get`, `R`, `Return` it holds a value popped from a stack, + - for `I`, `Input`, `Push`, `Put`, `Insert` it holds a value to be pushed into a stack, + - for `C`, `Clear` it is ignored, + - for `P`, `Peek` it holds a value peeked from a stack, + - for `Sum`, `Nonmiss`, `Cnt`, `Avg`, `Mean`, `Average`, `Height` it returns calculated summary value, + +The `value` argument is **outarg**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Dynamic, Hash-based, and Character stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHStack(StackDHC, type = $ 12); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + + %let zeros = 6; *[to test bigger sizes]; + data Example1; + + t = time(); drop t; + do _I_ = 1 to 1e&zeros.; + _X_ = put(_I_*10, z12.); + call StackDHC("Put", _X_); + end; + t = time() - t; + + call StackDHC("Height", _X_); + put t= / _X_=; + + t = time(); + do _I_ = 1 to 1e&zeros. + 3; + call StackDHC('Pop', _X_); + output; + end; + t = time() - t; + + call StackDHC("Height", _X_); + put t= / _X_=; + + %* clear for further reuse *; + call StackDHC('Clear', ''); + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Dynamic, Hash-based, and Numeric stack: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDHStack(StackDHN); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + + do _I_ = 1,.,2,.,3,.,4,.,5,.,6; + call StackDHN("Put", _I_); + end; + + call StackDHN("Sum", _I_); + put "Sum " _I_=; + + call StackDHN("Avg", _I_); + put "Avg " _I_=; + + call StackDHN("Cnt", _I_); + put "Cnt " _I_=; + + call StackDHN("Height", _I_); + put "Height " _I_=; + + _X_ = 0; + do _I_ = 1 to _I_; + call StackDHN('Pop', _X_); + output; + end; + + call StackDHN("Height", _I_); + put "Height " _I_=; + + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `bit64andprotodfa()` proto ###### + +## >>> `bit64andPROTOdfa()` proto function: <<< ####################### + +The **bit64andPROTOdfa()** is external *C* function, +this is the implementation of the *bitwise AND* operation +on doubles. A double is returned. + +**Caution!** For SAS numeric values *only* operations on first 53 bits are valid! + +The function is used **internally** by functions in the *DFA* package. + +### SYNTAX: ################################################################### + +The basic syntax is the following: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64andPROTOdfa(i, j) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `i` - A double numeric argument. + +2. `j` - A double numeric argument. + +--- + + +--- + +## `bit64orprotodfa()` proto ###### + +## >>> `bit64orPROTOdfa()` proto function: <<< ####################### + +The **bit64orPROTOdfa()** is external *C* function, +this is the implementation of the *bitwise OR* operation +on doubles. A double is returned. + +**Caution!** For SAS numeric values *only* operations on first 53 bits are valid! + +The function is used **internally** by functions in the *DFA* package. + +### SYNTAX: ################################################################### + +The basic syntax is the following: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64orPROTOdfa(i, j) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `i` - A double numeric argument. + +2. `j` - A double numeric argument. + +--- + + +--- + +## `bit64anddfa()` function ###### + +## >>> `bit64andDFA()` subroutine: <<< ####################### + +The **bit64andDFA()** function is an alternative to +the 32 bit bitwise `BAND()` function working on SAS numerics. +Allows to work on *up to* 53 bits of SAS numeric value. + +The `bit64andDFA()` is an *internal* function of the `DFA` package. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64andDFA(a, b) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `a` - Argument is a SAS numeric values. + +2. `B` - Argument is a SAS numeric values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Basic test of `bit64orDFA()` and `bit64andDFA()` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options ls = max ps = max; + %let M = 53 ; %* 53 is maximum valid value; + data _null_; + array bitmask [ 0: &M] _temporary_ ; + do P = 1 to &M ; + bitmask[P] = 2**(P-1) ; + put bitmask[P] = binary54. @; + put bitmask[P] = best32.; + end ; + bitmask[0] = bitmask[&M.] ; + put bitmask[0] = best32. /; + + a=0; + put a = binary54.; + do P = 1 to &M ; + a = BIT64ORDFA (a, bitmask[P]) ; + put a = binary54.; + end; + put; + + b = 0; + put b = binary54./; + do P = 1 to &M ; + b + (BIT64ANDDFA (a, bitmask[P]) ne .) ; + put b = best32.; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `bit64ordfa()` function ###### + +## >>> `bit64orDFA()` subroutine: <<< ####################### + +The **bit64orDFA()** function is an alternative to +the 32 bit bitwise `BOR()` function working on SAS numerics. +Allows to work on *up to* 53 bits of SAS numeric value. + +The `bit64orDFA()` is an *internal* function of the `DFA` package. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +bit64orDFA(a, b) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `a` - Argument is a SAS numeric values. + +2. `B` - Argument is a SAS numeric values. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Basic test of `bit64orDFA()` and `bit64andDFA()` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + options ls = max ps = max; + %let M = 53 ; %* 53 is maximum valid value; + data _null_; + array bitmask [ 0: &M] _temporary_ ; + do P = 1 to &M ; + bitmask[P] = 2**(P-1) ; + put bitmask[P] = binary54. @; + put bitmask[P] = best32.; + end ; + bitmask[0] = bitmask[&M.] ; + put bitmask[0] = best32. /; + + a=0; + put a = binary54.; + do P = 1 to &M ; + a = BIT64ORDFA (a, bitmask[P]) ; + put a = binary54.; + end; + put; + + b = 0; + put b = binary54./; + do P = 1 to &M ; + b + (BIT64ANDDFA (a, bitmask[P]) ne .) ; + put b = best32.; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%createdfbitmap()` macro ###### + +## >>> `%createDFBitmap()` macro: <<< ####################### + +The `%createDFBitmap()` macro allows to generate +a `dynamic function bitmap` which is a FCMP based +approach to create *dynamically* allocated **numeric** +bitmnap. + +*Note:* Arrays provided by the macro are *one dimensional* arrays. + +The idea of a SAS bitmap is based on: +1. SGF Paper 3101-2019 + titeled **Re-Mapping A Bitmap** by *Paul M. Dorfman* and *Lessia S. Shajenko* + [https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2019/3101-2019.pdf](https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2019/3101-2019.pdf) +2. SUGI Paper 8-26 + titeled **Table Look-Up by Direct Addressing: Key-Indexing -- Bitmapping -- Hashing** by *Paul M. Dorfman* + [https://support.sas.com/resources/papers/proceedings/proceedings/sugi26/p008-26.pdf](https://support.sas.com/resources/papers/proceedings/proceedings/sugi26/p008-26.pdf) + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%createDFBitmap( + bitmapName + <,debug=0> + <,outlib=work.DFAfcmp.package> + <,type=32> + <,header=1> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `bitmapName` - *Required*, creates a FCMP call subroutine which is also + a bitmap name. In the data step it is used in form of + a call subroutine, e.g. `call bitmapName("Allocate", 3000)`. + Has to satisfy FCMP function naming requirements, but with + maximum of 24 characters. + +* `debug=` - *Optional*, the default value is `0`. + If set to `1` then it turns on a debugging mode. + +* `outlib=` - *Optional*, the default value is `work.DFAfcmp.package`. + It points the default location for new generated dynamic + function arrays compiled by FCMP. + *Hint!* Keep it as it is. + +* `type=` - *Optional*, the default value is `32`. Sets the type of + bitwise operations executed internaly on the bitmap. + The only valid values are `32` or `52`, + With 32 the `BOR()` and `BAND()` SAS functions are used + and with 52 the `bit64orDFA()` and `bit64and DFA()` FCMP + functions are used. + +* `header=` - *Optional*, the default value is `1`. Indicates if + the `proc fcmp outlib = &outlib.;` header is added to + the executed code. If not 1 then no header is added. + +**Created function arguments description**: + +A function generated by the macro is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +call &bitmapName.(IO, position, value) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +and accepts the following list of arguments and values: + +1. `IO` - is a *character* steering argument, possible + values and behaviour they call are the following: + - `Check`, `Test`, `T` - to get information if a bit is set to 1 (on) or not, + - `On`, `1` - to set a selected bit to 1, + - `Off`, `0` - to set a selected bit to 0, + - `C`, `Clear` - to reduce a bitmat to a single empty cell, + - `A`, `Allocate` - to reserve space for a bitmap and set all bits to 0, + - `A0`, `Allocate0` - to reserve space for a bitmap and set all bits to 0, + - `A1`, `Allocate1` - to reserve space for a bitmap and set all bits to 1, + - `D`, `Dim`, `Dimension` - to returns minimal and maximal index of the bitmap. + +2. `position` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `On`, `Off`, `1`, `0`/ `Check`, `Test`, `T` it is a bitmap index, + - for `C`, `Clear` is ignored, + - for `A`, `Allocate` sets the value of the minposition, i.e. the minimal position of the bitmap index, + - for `D`, `Dimension` it returns value of the minposition, + +.3 `value` - is a *numeric* argument and depends on the `IO` value. + Behaves in the following way: + - for `Check`, `Test`, `T` it holds value retrieved from a bitmap on a given position, + - for `On`, `Off`, `1`, `0`, `C`, `Clear` is ignored, + - for `A`, `Allocate` it sets the value of the maxposition, i.e. maximal position of the array index, + - for `D`, `Dimension` it returns value of the maxposition + +The `position` and the `value` arguments are **outargs**, i.e. can be changed by the function. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Bitmap of type 32: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBitmap32,type=32,debug=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example1; + call MyBitmap32("Allocate", -10, 100); + L = 0; H = 0; + call MyBitmap32("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H by 2; + put i @; + call MyBitmap32("1", i, .); + end; + put; + + * get values from the array ; + Value = .; + do i = L to H; + call MyBitmap32("T", i, Value); + put i= Value=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 2.** Bitmap of type 52: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBitmap52,type=52,debug=1); + options APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example2; + call MyBitmap52("Allocate", -10, 100); + L = 0; H = 0; + call MyBitmap52("Dim", L, H); + put L= H=; + + * populate array with data ; + do i = L to H by 2; + put i @; + call MyBitmap52("1", i, .); + end; + put; + + * get values from the array ; + Value = .; + do i = L to H; + call MyBitmap52("T", i, Value); + put i= Value=; + end; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 3.** Execution time test for type 52: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBigBitmap52,type=52,debug=0); + options FULLSTIMER APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example3; + call MyBigBitmap52("Allocate", -10, 2000000001); + L = 0; H = 0; + call MyBigBitmap52("Dim", L, H); + put L= H=; + + * populate bitmap with data ; + t = time(); + do i = L to H by 17; + call MyBigBitmap52("1", i, .); + x + 1; + end; + t = time() - t; + put "populate:" t= x=; + + * get values from the bitmap ; + t = time(); + Value = .; + do i = L to H; + call MyBigBitmap52("T", i, Value); + x + (-Value); + end; + t = time() - t; + put "search:" t= x=; + run; + +%* +L=-10 H=2000000001 +populate:t=55.902999878 x=117647060 +search:t=654.12900019 x=0 +NOTE: The data set WORK.EXAMPLE3 has 1 observations and 6 variables. +NOTE: DATA statement used (Total process time): + real time 11:50.42 + user cpu time 11:46.40 + system cpu time 0.45 seconds + memory 301791.12k + OS Memory 326332.00k +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 4.** Execution time test for type 32: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %createDFBitmap(MyBigBitmap32,type=32,debug=0); + options FULLSTIMER APPEND=(cmplib = WORK.DFAfcmp) ; + + data Example4; + call MyBigBitmap32("Allocate", -10, 2000000001); + L = 0; H = 0; + call MyBigBitmap32("Dim", L, H); + put L= H=; + + * populate bitmap with data ; + t = time(); + do i = L to H by 17; + call MyBigBitmap32("1", i, .); + x + 1; + end; + t = time() - t; + put "populate:" t= x=; + + * get values from the bitmap ; + t = time(); + Value = .; + do i = L to H; + call MyBigBitmap32("T", i, Value); + x + (-Value); + end; + t = time() - t; + put "populate:" t= x=; + run; + +%* +L=-10 H=2000000001 +populate:t=50.417999983 x=117647060 +populate:t=611.13600016 x=0 +NOTE: The data set WORK.EXAMPLE4 has 1 observations and 6 variables. +NOTE: DATA statement used (Total process time): + real time 11:02.07 + user cpu time 10:59.07 + system cpu time 1.46 seconds + memory 489583.90k + OS Memory 513876.00k +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `generatearrays` exec ###### + +## >>> `generateArrays` exec: <<< ####################### + +The generateArrays exec file provides a **list of automatically generated examples** of functions +emulating data structures. + +The list of provided examples is the following: +- `SmpArray` - Simple Immutable Dynamic Function Array +- `SmpMtbArray` - Simple Mutable Dynamic Function Array +- `SrchArray` - Searchable Immutable Dynamic Function Array +- `SrchMtbArray` - Searchable Mutable Dynamic Function Array +- `DynArrayC` - Dynamic Hash-based Character Function Array (length 256 bytes) +- `StackC` - Dynamic Hash-based Character Stack (length 256 bytes) +- `StackN` - Dynamic Hash-based Numeric Stack +- `FifoC` - Dynamic Hash-based Character Fifo (length 256 bytes) +- `FifoN` - Dynamic Hash-based Character Fifo +- `DescStackC` - Dynamic Hash-based Character Descending Ordered Stack (length 256 bytes) +- `AscStackC` - Dynamic Hash-based Character Ascending Ordered Stack (length 256 bytes) +- `DescStackN` - Dynamic Hash-based Numeric Descending Ordered Stack +- `AscStackN` - Dynamic Hash-based Numeric Ascending Ordered Stack +- `PrtQueueNTC` - Dynamic Hash-based Character Priority Queue with *New on Top* (length 256 bytes) +- `PrtQueueNBC` - Dynamic Hash-based Character Priority Queue with *New on Bottom* (length 256 bytes) +- `PrtQueueNTN` - Dynamic Hash-based Numeric Priority Queue with *New on Top* +- `PrtQueueNBN` - Dynamic Hash-based Numeric Priority Queue with *New on Bottom* +- `Bitmap32` - Dynamic Function Bitmap on 32 bit +- `Bitmap52` - Dynamic Function Bitmap on 52 bit + +The `outlib=` option is set to `work.DFAfcmp.package`. The `cmplib=` option is updated automatically. + +--- + + +--- + +## `generatearrays` clean ###### + +## >>> `generateArrays` clean: <<< ####################### + +The generateArrays clean file clears the list of automatically generated examples of functions +emulating data structures provided in the `generatearrays.sas` exec file. + +The `cmplib=` option is updated automatically. + +--- + + +--- + + +--- + +# License ###### + +Copyright (c) 2019 - 2026 Bartosz Jablonski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + diff --git a/hist/0.5.9/dfa.zip b/hist/0.5.9/dfa.zip new file mode 100644 index 0000000000000000000000000000000000000000..2b6cc222341576007e26b542988bf73a00103219 GIT binary patch literal 49267 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 literal 0 HcmV?d00001