Jump to content
Sign in to follow this  
Jefrey

Buffer/stack with Arrays (limiting array size) UDF

Recommended Posts

At my work I was creating a music player (truly the project is bigger than it but it doesn't come to the case right now) and, given some conditions, it should start playing songs randomly. I've used Random() function to sort any song from the list, but the "random wasn't so random" sometimes, and some songs used to repeat multiple times, although the song list wasn't so small. So I needed to keep a list of all the played songs. However, I couldn't feed up an array forever as this system I'm working on is meant to work 24/7 with no pause and the array could really reach huge values, while just the latest X values would really be used (to check if a random song was played recently before playing it).

So I managed to create this simple stack/buffer/heap script. It works just like Assembly stacks (although the target is totally different). You'll have an array, you can define its max size and start adding items into it. Once the array limit is reached, the first added item is automatically removed, all the other items are reindexed and your new item will then be added.

You can also change the array (stack) limit at any time, reset it as well as pull/remove or read the last added item. In the best Assembly stack way, you shouldn't be able to read all the items, except the last added item. But, well, we are talking about AutoIt arrays. It's just a list, where the 0 index brings the actual items count. This means you can easily create loops and read the array as you want (just be very careful if you want to modify the array without _Buffer* functions).

It's also useful if you want to generate random values with Random() with repeating values, but they're repeating more than you want (instead of "1-2-2-2-3-1-2-3-4" you would have "1-3-2-4-3-1-2-4" - the values would only start repeating after it's too long since they were generated in last).

Here's an example:

#inclcude 'buffer.au3' ; the lib
#include <Array.au3> ; needed only to do _ArrayDisplay

; Example 1
$aBuffer = _BufferCreate(3)
_BufferPush($aBuffer, 12)
_BufferPush($aBuffer, 23)
_BufferPush($aBuffer, 34)
_BufferPush($aBuffer, 45)
MsgBox(0, '', _BufferPull($aBuffer)) ; 45 (and remove it)
_BufferPush($aBuffer, 56)
_BufferPush($aBuffer, 67)
_ArrayDisplay($aBuffer)

; Example 2
$aBuffer = _BufferCreate(3)
_BufferPush($aBuffer, 12)
_BufferPush($aBuffer, 23)
_BufferPush($aBuffer, 34)
_BufferPush($aBuffer, 45)
_BufferChangeLimit($aBuffer, 6)
_BufferPush($aBuffer, 56)
_BufferPush($aBuffer, 67)
_ArrayDisplay($aBuffer)
MsgBox(0, "", "Buffer items count: " & _BufferItemsCount($aBuffer) & @CRLF & "Buffer max size: " & _BufferLimit($aBuffer) & @CRLF & "Last item (without pulling/removing it): " & _BufferGetLastItem($aBuffer))

; Example 3
$aBuffer = _BufferCreate(3)
_BufferPush($aBuffer, 'ab')
_BufferPush($aBuffer, 'cd')
_BufferPush($aBuffer, 'ef')
_BufferPush($aBuffer, 'gh')
_ArrayDisplay($aBuffer)
_BufferReset($aBuffer)
_ArrayDisplay($aBuffer)

; Example 4
$aBuffer = _BufferCreate(2)
_BufferPush($aBuffer, 'Song 1')
_BufferPush($aBuffer, 'Music 2')
_BufferPush($aBuffer, 'Hit 3')
If _BufferCheckValue($aBuffer, 'Song 1') Then ; False
   MsgBox(0, "", "Song 1 was played too recently.")
EndIf
If _BufferCheckValue($aBuffer, 'Music 2') Then ; True
   MsgBox(0, "", "Music 2 was played too recently.")
EndIf

The lib source code:

#include-once

#cs
   Buffer/stack/heap UDF
   made by Jefrey <jefrey[at]jefrey.ml>
   Licensed under WTFPL: http://www.wtfpl.net/txt/copying/
#ce

; Creates a new buffer
; Arguments: $iSize - size of the buffer (limit)
Func _BufferCreate($iSize)
   Local $aBuffer[$iSize+1]
   $aBuffer[0] = 0
   Return $aBuffer
EndFunc

; Adds an item to the buffer
; If the buffer limit was reached, then the first item will be removed.
; Arguments: $aBuffer - buffer to change (reference) / $mItem - item to add
Func _BufferPush(ByRef $aBuffer, $mItem)
   If $aBuffer[0]+1 > UBound($aBuffer)-1 Then
      ; remove first item and reindex
      $aBuffer[1] = Null
      For $i = 2 To $aBuffer[0]
         $aBuffer[$i - 1] = $aBuffer[$i]
      Next
   Else
      $aBuffer[0] += 1
   EndIf
   $aBuffer[$aBuffer[0]] = $mItem
   Return $aBuffer
EndFunc

; Removes the last added item of the buffer and returns its value
; Arguments: $aBuffer - buffer to change (reference)
Func _BufferPull(ByRef $aBuffer)
   If $aBuffer[0] = 0 Then Return
   $mReturn = $aBuffer[$aBuffer[0]]
   $aBuffer[$aBuffer[0]] = Null
   $aBuffer[0] -= 1
   Return $mReturn
EndFunc

; Returns the actual items count (how many items were added to the buffer, and not its limit)
; Arguments: $aBuffer - the buffer
Func _BufferItemsCount($aBuffer)
   Return $aBuffer[0]
EndFunc

; Returns the actual items count (how many items were added to the buffer, and not its limit)
; Arguments: $aBuffer - the buffer
Func _BufferGetLastItem($aBuffer)
   Return $aBuffer[$aBuffer[0]]
EndFunc

; Returns the buffer limits (that were set by you)
; Arguments: $aBuffer - the buffer
Func _BufferLimit($aBuffer)
   Return UBound($aBuffer)-1
EndFunc

; Changes a buffer limit
; Arguments: $aBuffer - the buffer to change / $iSize - new buffer size
Func _BufferChangeLimit(ByRef $aBuffer, $iSize)
   ReDim $aBuffer[$iSize + 1]
   Return $aBuffer
EndFunc

; Resets a buffer (removes all items)
; Arguments: $aBuffer - the buffer to change
Func _BufferReset(ByRef $aBuffer)
   Local $j = UBound($aBuffer)-1
   For $i = 1 To $j
      $aBuffer[$i] = Null
   Next
   $aBuffer[0] = 0
EndFunc

; Checks if a value exists in a buffer
; Returns: 0 if not found or index (>0) of where it was found
Func _BufferCheckValue($aBuffer, $mValue)
   If Not $aBuffer[0] Then Return 0
   For $i = 1 To $aBuffer[0]
      If $aBuffer[$i] = $mValue Then Return $i
   Next
   Return 0
EndFunc

 

Edited by Jefrey
_BufferCheckValue added

My stuff

Spoiler

My UDFs  _AuThread multithreading emulation for AutoIt · _ExtInputBox an inputbox with multiple inputs and more features · forceUTF8 fix strings encoding without knowing its original charset · JSONgen JSON generator · _TCPServer UDF multi-client and multi-task (run on background) event-based TCP server easy to do · _TCPClient_UDF multi-server and multi-task (runs on background) event-based TCP client easy to do · ParseURL and ParseStr functions ported from PHP · _CmdLine UDF easily parse command line parameters, keys or flags · AutoPHP Create documents (bills, incomes) from HTML by sending variables/arrays from AutoIt to PHP · (Un)Serialize Convert arrays and data into a storable string (PHP compatible) · RTTL Plays and exports to MP3 Nokia-format monophonic ringtones (for very old cellphones) · I18n library Simple and easy to use localization library · Scripting.Dictionary OOP and OOP-like approach · Buffer/stack limit arrays to N items by removing the last one once the limit is reached · NGBioAPI UDF to work with Nitgen fingerprint readers · Serial/Licensing system require license key based on unique machine ID from your users · HTTP a simple WinHTTP library that allows GET, POST and file uploads · Thread true AutoIt threads (under-dev) · RC4 RC4 encryption compatible with PHP and JS ·  storage.au3 localStorage and sessionStorage for AutoIt Classes _WKHtmlToX uses wkhtmlto* to convert HTML files and webpages into PDF or images (jpg, bmp, gif, png...) Snippets _Word_DocFindReplaceByLongText replace strings using Word UDF with strings longer than 255 characters (MSWord limit) rangeparser parser for printing-like pages interval (e.g.: "1,2,3-5") EnvParser parse strings/paths with environment variables and get full path Random stuff Super Mario beep sound your ears will hurt

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Colduction
      Hi dear friends!, i'm sorry for creating a new thread (a new problem), i have over than 9 lists that i want to combine them to be this (in this example, there are 3 test files):


      I've written a little code for splitting main information, but i really confused how to make results as "Output.txt", here is that code:
       
      $sRegex_1 = StringRegExp(FileRead("1.txt"), '(?s:(?<=\=\=\r\n)(.*?)(?=\r\n\=\=))', 3) $sRegex_2 = StringRegExp(FileRead("2.txt"), '(?s:(?<=\=\=\r\n)(.*?)(?=\r\n\=\=))', 3) $sRegex_3 = StringRegExp(FileRead("3.txt"), '(?s:(?<=\=\=\r\n)(.*?)(?=\r\n\=\=))', 3) For $i = 0 To UBound($sRegex_1) - 1 ConsoleWrite($sRegex_1[$i] & @CRLF) For $j = 0 To UBound($sRegex_2) - 1 ConsoleWrite($sRegex_2[$j] & @CRLF) For $k = 0 To UBound($sRegex_3) - 1 ConsoleWrite($sRegex_3[$k] & @CRLF) Next Next Next  
    • By Colduction
      Hi guys!, i have a problem to convert Python code to AutoIt code, in fact i had not coded with Python yet!, this code is about permutation a string's case, i will be happy with your comments :)❤;

      Python code:
       
      # Python code to print all permutations # with respect to cases # Function to generate permutations def permute(inp): n = len(inp) # Number of permutations is 2^n mx = 1 << n # Converting string to lower case inp = inp.lower() # Using all subsequences and permuting them for i in range(mx): # If j-th bit is set, we convert it to upper case combination = [k for k in inp] for j in range(n): if (((i >> j) & 1) == 1): combination[j] = inp[j].upper() temp = "" # Printing current combination for i in combination: temp += i print(temp), # Driver code permute("Hello") # This code is contributed by Sachin Bisht
      My code in AutoIt:
      ; https://www.geeksforgeeks.org/permute-string-changing-case/ _PermuteCase("ABC") Func _PermuteCase($sText) If StringRegExp($sText, "^[A-Za-z]{1,}$") Then Local $iLength = StringLen($sText) ; Get length of the text. Local $iMaxPerm = 2 ^ $iLength ; Number of permutations is 2^n Local $sLow_Text = StringLower($sText) ; Converting string to lower case Local $asChrs = StringToASCIIArray($sLow_Text) ; Split the text into array of chars. For $i = 1 To $iMaxPerm Step 1 For $j = 0 To $asChrs[0] ;................................................... Next Next Else Return SetError(-1, 0, "Error: Input is incorrect!") EndIf EndFunc ;==>_PermuteCase  
       
       
       
       
       
      ====================== SOLUTION by @TheXman ======================
       
    • By TheAutomator
      I'm working on a script that needs to work with a huge database inside a combobox.
      I'm looking for the best way to link a multidimensional array to that data to load that data on to textfields.

      example:
      combo item 0 = "A", data = [index linked to combo item 0] [1,0,5,4,87,9,"xyz"]
      combo item 1 = "B", data = [index linked to combo item 1] [1,6,5,4,87,9,"zzz"]
      combo item 3 = "A", data = [index linked to combo item 3] [1,6,4,4,87,9,"aaa"] ; yes also double items!
      Would also like to be able to delete and add items on the fly btw..
      Local $INDEX[0][10] ; ubound wil be resized like a stack while loading from a textfile ;inside gui: local $Combo = GUICtrlCreateCombo('...', 10, 10, 290, 25) ;gui loop: While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $Combo display() ; how do i link my array index to the combo labels to know what to show in the textfields? ; NOTE: (there are duplicate items in the combobox!) EndSwitch WEnd Any toughs are welcome.
      I was thinking about using _GUICtrlComboBox_GetCurSel($Combo) and use that integer to refer to the index (dimension 1) of the array 
      Thanks, TheAutomator
       
    • By nacerbaaziz
      good morning all.
      first lit me give you all a thinks to your help
      you're help me allot thank you all.
      sirs today i've a new problem
      it's not a problem but thing i want to add it to blind accessability.
      the ListBox can send a notification when the user send a double click on it items
      but as we know that the blind users can't use the mouse for that they use the keybord to navigate.
      as we know that the enter replace the double click on the keybord
      for that i need when the user send a inter above any listBox item the list send a double click notification.
      i know some of you tell me that i can use the  GUISetAccelerators function
      but the enter has a other tasks such as leav a blanc line on edits and activate the defaultButton and other tasks.
      that what i need and i hope that you can help me
      this is a simple example.
      #include <GUIConstantsEx.au3> #include <StructureConstants.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> #include <ListBoxConstants.au3> Example() Func Example() Local $sMESSAGE = "The following buttons have been clicked" GUICreate("My GUI list") ; will create a dialog box that when displayed is centered Local $idButton_Add = GUICtrlCreateButton("Add", 64, 32, 75, 25) Local $idButton_Clear = GUICtrlCreateButton("Clear", 64, 72, 75, 25) global $idMylist = GUICtrlCreateList("buttons that have been clicked", 176, 32, 121, 97) GUICtrlSetLimit(-1, 200) ; to limit horizontal scrolling GUICtrlSetData(-1, $sMESSAGE) global $DummyList = GUICtrlCreateDummy() GUICtrlSendToDummy($DummyList, 1) Local $idButton_Close = GUICtrlCreateButton("my closing button", 64, 160, 175, 25) GUIRegisterMsg($WM_command, "WM_command") GUISetState(@SW_SHOW) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idButton_Add GUICtrlSetData($idMylist, "You clicked button No1|") Case $idButton_Clear GUICtrlSetData($idMylist, "") Case $idButton_Close MsgBox($MB_SYSTEMMODAL, "", "the closing button has been clicked", 2) Exit case $DummyList $g_iTemp = GUICtrlRead($DummyList) if $g_iTemp = $LBN_DBLCLK then ;$LBN_DBLCLK then msgBox(64, "", "") endIf GUICtrlSendToDummy($DummyList, 0) EndSwitch WEnd EndFunc ;==>Example Func WM_command($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) $hWndFrom = $lParam $iCode = BitShift($wParam, 16) ; Hi Word Switch $hWndFrom Case GUICtrlGetHandle($idMylist) Switch $iCode Case $LBN_SELCHANGE, $LBN_DBLCLK, $LBN_SELCANCEL, $LBN_SETFOCUS GUICtrlSendToDummy($DummyList, $iCode) case else ;GUICtrlSendToDummy($DummyTreeview, 1) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc  
    • By kneze
      Hi
      script read path to pst files from registry and write this informations to txt file. Unfortunately there are stored not needed lines: path  to ost file, other line has string IndexAvailableBodyand first line is blank. How can i remove anything from txt file exept path to pst files ? 
      Thanks in advance!
      #include <ButtonConstants.au3> #include <ComboConstants.au3> #include <DateTimeConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <array.au3> #include <IE.au3> #include <WinAPIFiles.au3> #include <FileConstants.au3> #include <File.au3> #include <GUIListBox.au3> #include <Date.au3> $Form2 = GUICreate("Form1", 405, 294, 633, 264) $Button1 = GUICtrlCreateButton("Button1", 72, 48, 113, 33) GUISetState(@SW_SHOW) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button1 _searchPSTFiles() EndSwitch WEnd FUNC _searchPSTFiles() Global $aLines ;$sFileName = @ScriptDir & "\Pst.txt" $sFileNameTMP = @ScriptDir & "\Psttmp.txt" ;IF FileExists ($sFileName) then FileDelete ($sFileName) IF FileExists ($sFileNameTMP) then FileDelete ($sFileNameTMP) ;$logpathpst = FileOpen($sFileName, $FO_OVERWRITE) $logpathpsttmp = FileOpen($sFileNameTMP, $FO_OVERWRITE) Local $Outlookpst[30] For $i = 1 To 30 $Outlookpst[$i] = RegEnumVal("HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Search\", $i) If @error <> 0 Then ExitLoop If $Outlookpst = "" Then ContinueLoop EndIf FileWrite($logpathpstTMP, @CRLF & $Outlookpst[$i]) Next ;FileClose ($sFileName) FileClose ($sFileNameTMP) EndFunc  
×
×
  • Create New...