MemPrint and MemInput
#5
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.

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
Reply


Messages In This Thread
MemPrint and MemInput - by SMcNeill - 08-22-2022, 12:59 AM
RE: MemPrint and MemInput - by OldMoses - 08-22-2022, 01:56 AM
RE: MemPrint and MemInput - by SMcNeill - 08-22-2022, 02:04 AM
RE: MemPrint and MemInput - by SMcNeill - 08-22-2022, 10:01 AM
RE: MemPrint and MemInput - by justsomeguy - 08-22-2022, 11:09 AM
RE: MemPrint and MemInput - by SMcNeill - 08-22-2022, 11:14 AM
RE: MemPrint and MemInput - by SMcNeill - 08-22-2022, 03:03 PM
RE: MemPrint and MemInput - by justsomeguy - 08-22-2022, 08:59 PM



Users browsing this thread: 1 Guest(s)