08-22-2022, 11:09 AM
Nice work!
I've been playing around _MEM functions as well. My main focus has been around string manipulation, just to see if I can squeeze a little more speed out string commands.
I have also been testing large text files and found that the fastest loading for me was to use the following method. It loads the entire file to a string. You can then follow up with _MEM functions.
The whole project seems to be an overall failure as most ideas just ended up being a bit slower, but I learned a lot. If anyone wants to take a look then here is the full listing.
I've been playing around _MEM functions as well. My main focus has been around string manipulation, just to see if I can squeeze a little more speed out string commands.
I have also been testing large text files and found that the fastest loading for me was to use the following method. It loads the entire file to a string. You can then follow up with _MEM functions.
Code: (Select All)
SUB loadFileFast (file AS STRING, filetext AS STRING)
DIM AS LONG fileHandle, fileSize
IF _FILEEXISTS(file) THEN
fileHandle = FREEFILE
filetext = ""
' Open file just to retrieve its length
OPEN file FOR INPUT AS #fileHandle
fileSize = LOF(fileHandle)
CLOSE #fileHandle
' Now open it for real
OPEN file FOR RANDOM AS #fileHandle LEN = fileSize
FIELD #fileHandle, fileSize AS filetext
GET #fileHandle, 1
CLOSE #fileHandle
ELSE
PRINT "File '"; file; "' does not exist."
END
END IF
END SUB
The whole project seems to be an overall failure as most ideas just ended up being a bit slower, but I learned a lot. If anyone wants to take a look then here is the full listing.
Code: (Select All)
'--------------------------------------------------------------
' Experimentation with _MEM commands and Strings
' by justsome guy
' 8/22/22
'-------------------------------------------------------------
OPTION _EXPLICIT
_TITLE "MEM Strings"
'--------------------------------------------------------------
' FPS setup
'--------------------------------------------------------------
DIM SHARED AS LONG fpsCount, fpsCurrent
DIM time AS LONG: time = _FREETIMER
ON TIMER(time, 1) fps
TIMER(time) ON
'--------------------------------------------------------------
' CONSTANTS
'--------------------------------------------------------------
CONST cMAXSTRINGLENGTH = 6000000
CONST cMAXBIGSTRINGLENGTH = 600000
CONST cTRUE = -1
CONST cFALSE = 0
'--------------------------------------------------------------
' ENTRY POINT
'--------------------------------------------------------------
Main
SUB ______Main_LOOP (): END SUB
SUB Main
DIM ti AS STRING * cMAXSTRINGLENGTH
loadFileFast _CWD$ + "/466544 Word List.txt", ti
DIM fpsStr AS STRING * cMAXSTRINGLENGTH
DIM pg AS STRING * cMAXSTRINGLENGTH
DIM ca1 AS STRING * cMAXSTRINGLENGTH
DIM ca2 AS STRING * cMAXSTRINGLENGTH
pg = "_mem console output."
ca1 = STRING$(cMAXSTRINGLENGTH, &H19) ' color and attribute info
ca2 = STRING$(cMAXSTRINGLENGTH, &H1A) ' color and attribute info
DO
' memConsolePrint can only accept fixed length strings, so
' you cannot just use 'memConsolePrint 1, "Hello",""' because
' "Hello" is not a fixed length string.
memConsolePrint 10, pg, ""
fpsStr = "fps:" + STR$(fpsCurrent)
memConsolePrint 60, fpsStr, ca1
memConsolePrint 160, memLeft$(ti, 1860), ca2
fpsCount = fpsCount + 1
LOOP UNTIL _KEYHIT = 27
END SUB
SUB ______CONSOLE_RELATED_SUBS (): END SUB
SUB memConsolePrint (position AS LONG, strng AS STRING * CMAXSTRINGLENGTH, attrib AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM consoleMem, strngMEM, attribMEM
DIM AS _UNSIGNED _BYTE b
DIM AS _UNSIGNED INTEGER m
' just set the default to white foreground and black back ground
IF attrib = "" THEN attrib = STRING$(cMAXSTRINGLENGTH, &H0F)
consoleMem = _MEMIMAGE
strngMEM = _MEM(strng)
attribMEM = _MEM(attrib)
DIM AS LONG strLen, attribLen, iter
$CHECKING:OFF
strLen = memLENFast(strng)
attribLen = memLENFast(attrib)
position = _SHL(position, 1)
IF position >= 0 AND position <= (consoleMem.SIZE - strLen) THEN
FOR iter = 0 TO strLen - 1
b = _MEMGET(strngMEM, strngMEM.OFFSET + iter, _UNSIGNED _BYTE)
IF b < 32 OR b > 127 THEN b = 32
m = b OR _SHL(_MEMGET(attribMEM, attribMEM.OFFSET + iter, _UNSIGNED _BYTE), 8)
_MEMPUT consoleMem, consoleMem.OFFSET + _SHL((iter), 1) + position, m AS _UNSIGNED INTEGER
NEXT
END IF
$CHECKING:ON
_MEMFREE consoleMem
_MEMFREE strngMEM
END SUB
SUB ______MEM_STRING_RELATED_SUBS (): END SUB
FUNCTION memLEN& (strng AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM inStringMEM
DIM AS _OFFSET iter, iterEnd
DIM AS LONG length
inStringMEM = _MEM(strng)
iterEnd = inStringMEM.OFFSET
iter = inStringMEM.OFFSET + inStringMEM.SIZE - 1
length = cMAXSTRINGLENGTH
$CHECKING:OFF
DO WHILE (_MEMGET(inStringMEM, iter, _UNSIGNED _BYTE) = 32 OR _MEMGET(inStringMEM, iter, _UNSIGNED _BYTE) = 0) AND iter > iterEnd
iter = iter - 1
length = length - 1
LOOP
$CHECKING:ON
memLEN = length
_MEMFREE inStringMEM
END FUNCTION
FUNCTION memLENFast& (strng AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM inStringMEM
DIM AS _OFFSET iter, iterEnd
DIM AS LONG length
DIM AS _UNSIGNED _INTEGER64 mem
DIM AS _UNSIGNED _BYTE mm
inStringMEM = _MEM(strng)
iterEnd = inStringMEM.OFFSET
iter = inStringMEM.OFFSET + inStringMEM.SIZE - 1
length = cMAXSTRINGLENGTH
$CHECKING:OFF
' Take off the big chunks
DO
mem = _MEMGET(inStringMEM, iter, _UNSIGNED _INTEGER64)
IF (mem = &H20 OR mem = &H0) AND iter > iterEnd THEN
iter = iter - 8
length = length - 8
ELSE
EXIT DO
END IF
LOOP
' Nibble at the rest
DO
mm = _MEMGET(inStringMEM, iter, _UNSIGNED _BYTE)
IF (mm = &H20 OR mm = &H0) AND iter > iterEnd THEN
iter = iter - 1
length = length - 1
ELSE
EXIT DO
END IF
LOOP
$CHECKING:ON
memLENFast = length
_MEMFREE inStringMEM
END FUNCTION
FUNCTION memConCat$ (strng1 AS STRING * CMAXSTRINGLENGTH, strng2 AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM inString1MEM, inString2MEM, outstringMEM
DIM AS LONG stringLENGTH1, stringLENGTH2
DIM AS _OFFSET stringSize1, stringSize2
DIM outString AS STRING * cMAXSTRINGLENGTH
inString1MEM = _MEM(strng1)
inString2MEM = _MEM(strng2)
outstringMEM = _MEM(outString)
stringSize1 = inString1MEM.SIZE
stringSize2 = inString2MEM.SIZE
stringLENGTH1 = memLEN(strng1)
stringLENGTH2 = memLEN(strng2)
IF stringLENGTH1 + stringLENGTH2 < cMAXSTRINGLENGTH THEN
_MEMCOPY inString1MEM, inString1MEM.OFFSET, stringLENGTH1 TO outstringMEM, outstringMEM.OFFSET
_MEMCOPY inString2MEM, inString2MEM.OFFSET, stringLENGTH2 TO outstringMEM, outstringMEM.OFFSET + stringLENGTH1
memConCat$ = outString
END IF
_MEMFREE inString1MEM
_MEMFREE inString2MEM
_MEMFREE outstringMEM
END FUNCTION
FUNCTION memMID$ (strng AS STRING * CMAXSTRINGLENGTH, start AS LONG, count AS LONG)
DIM outString AS STRING * cMAXSTRINGLENGTH
DIM AS _MEM inStringMEM, outStringMEM
inStringMEM = _MEM(strng)
outStringMEM = _MEM(outString)
IF start >= 1 AND start <= inStringMEM.SIZE AND count > 0 AND count <= inStringMEM.SIZE THEN
_MEMCOPY inStringMEM, inStringMEM.OFFSET + start - 1, count TO outStringMEM, outStringMEM.OFFSET
END IF
memMID$ = outString
_MEMFREE inStringMEM
_MEMFREE outStringMEM
END FUNCTION
FUNCTION memLeft$ (strng AS STRING * CMAXSTRINGLENGTH, count AS LONG)
memLeft$ = memMID$(strng, 1, count)
END FUNCTION
FUNCTION memRight$ (strng AS STRING * CMAXSTRINGLENGTH, count AS LONG)
DIM AS LONG ln: ln = memLEN(strng)
memRight$ = memMID$(strng, ln - count + 1, count)
END FUNCTION
FUNCTION memInsert$ (mainString AS STRING * CMAXSTRINGLENGTH, substring AS STRING * CMAXSTRINGLENGTH, position AS LONG)
DIM outString AS STRING * cMAXSTRINGLENGTH
DIM AS _MEM outStringMEM
DIM AS LONG ln
outStringMEM = _MEM(outString)
ln = memLEN(mainString)
outString = memConCat(memLeft(mainString, position), substring)
outString = memConCat(outString, memMID(mainString, position + 1, ln))
memInsert = outString
_MEMFREE outStringMEM
END FUNCTION
FUNCTION memInstr (start AS LONG, mainString AS STRING * CMAXSTRINGLENGTH, subString AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM mainMEM, subMEM
DIM AS LONG mainPos, subPos, mainLEN, subLEN, mainOffset
DIM AS _BYTE passFlag
mainMEM = _MEM(mainString)
subMEM = _MEM(subString)
mainLEN = memLEN(mainString)
subLEN = memLEN(subString)
IF start < 1 THEN start = 1
IF start > mainLEN THEN start = mainLEN
$CHECKING:OFF
FOR mainPos = start TO mainLEN - 1
passFlag = cTRUE
FOR subPos = 0 TO subLEN - 1
mainOffset = mainPos + subPos - 1
IF mainOffset >= mainMEM.SIZE OR subPos >= subMEM.SIZE THEN
passFlag = cFALSE
EXIT FOR
END IF
IF _MEMGET(mainMEM, mainMEM.OFFSET + mainOffset, _UNSIGNED _BYTE) <> _MEMGET(subMEM, subMEM.OFFSET + subPos, _UNSIGNED _BYTE) THEN
passFlag = cFALSE
EXIT FOR
END IF
NEXT
IF passFlag = cTRUE THEN
memInstr = mainPos
EXIT FUNCTION
END IF
NEXT
$CHECKING:ON
memInstr = 0
_MEMFREE mainMEM
_MEMFREE subMEM
END FUNCTION
SUB ______FPS_RELATED_SUBS (): END SUB
SUB fps ()
fpsCurrent = fpsCount
fpsCount = 0
END SUB
SUB ______FILE_RELATED_SUBS (): END SUB
SUB loadFileFast (file AS STRING, filetext AS STRING)
DIM AS LONG fileHandle, fileSize
IF _FILEEXISTS(file) THEN
fileHandle = FREEFILE
filetext = ""
' Open file just to retrieve its length
OPEN file FOR INPUT AS #fileHandle
fileSize = LOF(fileHandle)
CLOSE #fileHandle
' Now open it for real
OPEN file FOR RANDOM AS #fileHandle LEN = fileSize
FIELD #fileHandle, fileSize AS filetext
GET #fileHandle, 1
CLOSE #fileHandle
ELSE
PRINT "File '"; file; "' does not exist."
END
END IF
END SUB
SUB loadFile (file AS STRING, filetext AS STRING * CMAXSTRINGLENGTH)
DIM AS LONG fileHandle, position
DIM AS _MEM filetextMEM
DIM AS _UNSIGNED _BYTE ch
IF _FILEEXISTS(file) THEN
filetextMEM = _MEM(filetext)
fileHandle = FREEFILE
filetext = ""
position = 0
OPEN file FOR BINARY AS #fileHandle
DO UNTIL EOF(fileHandle)
GET #fileHandle, , ch
_MEMPUT filetextMEM, filetextMEM.OFFSET + position, ch
position = position + 1
LOOP
CLOSE #fileHandle
ELSE
PRINT "File or path '"; file; "' does not exist."
END
END IF
_MEMFREE filetextMEM
END SUB
' Do not use.
' Experimental stuff that doesn't quite work
SUB ______Experimental_SUBS (): END SUB
FUNCTION memStringImage (strng AS STRING * CMAXSTRINGLENGTH)
DIM AS _MEM strngMEM, strngIMGMEM
DIM AS LONG strngLEN, strngIMG
strngLEN = memLEN(strng)
strngMEM = _MEM(strng)
strngIMG = _NEWIMAGE(cMAXSTRINGLENGTH - 1, 1, 8)
strngIMGMEM = _MEMIMAGE(strngIMG)
_MEMCOPY strngMEM, strngMEM.OFFSET, strngLEN TO strngIMGMEM, strngIMGMEM.OFFSET
memStringImage = strngIMG
_MEMFREE strngIMGMEM
_MEMFREE strngMEM
END FUNCTION
SUB memPrintEx (position AS LONG, strngImg AS LONG)
DIM AS _MEM consoleMem, strngMEM
consoleMem = _MEMIMAGE(0)
strngMEM = _MEMIMAGE(strngImg)
DIM AS LONG strLen, iter
$CHECKING:OFF
strLen = memLENEX(strngImg)
position = _SHL(position, 1)
IF position >= 0 AND position <= (consoleMem.SIZE - strLen) THEN
FOR iter = 0 TO strLen - 1
_MEMPUT consoleMem, consoleMem.OFFSET + _SHL((iter), 1) + position, _MEMGET(strngMEM, strngMEM.OFFSET + iter, _UNSIGNED _BYTE) AS _UNSIGNED _BYTE
NEXT
END IF
$CHECKING:ON
_MEMFREE consoleMem
_MEMFREE strngMEM
END SUB
FUNCTION memLENEX~& (strng AS LONG)
DIM AS _MEM inStringMEM
DIM AS _OFFSET iter, iterEnd
DIM AS LONG length
inStringMEM = _MEMIMAGE(strng)
iterEnd = inStringMEM.OFFSET
iter = inStringMEM.OFFSET + inStringMEM.SIZE - 1
length = cMAXSTRINGLENGTH
$CHECKING:OFF
DO WHILE (_MEMGET(inStringMEM, iter, _UNSIGNED _BYTE) = 32 OR _MEMGET(inStringMEM, iter, _UNSIGNED _BYTE) = 0) AND iter > iterEnd
iter = iter - 1
length = length - 1
LOOP
PRINT
$CHECKING:ON
memLENEX = length
' PRINT "Length:"; length
_MEMFREE inStringMEM
END FUNCTION