comments
Uses FileMap2.inc.
This is an UDT file memory manager.
Takes care of allocating file space and storing UDTs in a file.
Storage is allocated form 4 to 1024 bytes; in 4 byte increments.
Allocating a 7 byte UDT will take 8 bytes in file.
An allocation request returns a handle.
Thereafter, you use the handle to access the UDT.
You access the UDT, in the file, with a pointer.
FMem_Get(tMem, handle) returns a memory address for the stored UDT.
You use the pointer to Get/Set the UDT’s members.
Modifications to the pointer reflect through to the file.
File Mapping is used, so you’re reading/writing at full memory speed.
You don’t have to worry about where UDTs are stored in the file, all taken care of.
If UDT is freed, the freed file memory block added to a freed stack for reuse.
Uses FileMap2.inc.
This is an UDT file memory manager.
Takes care of allocating file space and storing UDTs in a file.
Storage is allocated form 4 to 1024 bytes; in 4 byte increments.
Allocating a 7 byte UDT will take 8 bytes in file.
An allocation request returns a handle.
Thereafter, you use the handle to access the UDT.
You access the UDT, in the file, with a pointer.
FMem_Get(tMem, handle) returns a memory address for the stored UDT.
You use the pointer to Get/Set the UDT’s members.
Modifications to the pointer reflect through to the file.
File Mapping is used, so you’re reading/writing at full memory speed.
You don’t have to worry about where UDTs are stored in the file, all taken care of.
If UDT is freed, the freed file memory block added to a freed stack for reuse.
Code:
'PB 5/9 'FileMemMang2.inc ' UDT File Memory Manager Module ' ' - automatic storage of UDTs in file ' - access in-file UDT at full memory speed ' ' works like system memory allocation ' hMem = FMem_Alloc(tMem, 16) 'allocate 16 bytes to hold UDT ' ' pMyUDT = FMem_Get(tMem, hMem) 'set UDT pointer ' @pMyUDT.price = 99.99 ' ' changing a pointer to a UDT reflects through to file ' ' Important! ' it's best to use wrapper procedures to Set/Get UDT values ' reestablish pointer memory address in each procedure ' this will slow things down, but; ' any allocation request might cause the file to have to grow ' file mapping has to be closed to change the size of the file ' a pointer address may be invalid after a file resize ' depends on where Window's establishes new file mapping view address ' #If Not %Def(%WINAPI) #Include Once "WIN32API.INC" #EndIf '''#Include Once "C:\PB9\FileMapping\GlobalMem.inc" #Include Once "C:\PB9\FileMapping\FileMap2.inc" ' $FMem_Validation = Guid$("{65B4C69F-FFE9-484B-AAFD-1396C9D4FFBA}") ' %FMem_PageSize = 2048 %FMem_UserMax = 200 %FMem_BlockMax = 1024 %FMem_BlockIncr = 4 %FMem_BlockVariations = 256 ' $FMem_Err_NullPtr = "File Memory Manager: null pointer" $FMem_Err_NullHandle = "File Memory Manager: null memory block handle" $FMem_Err_InvalidFile = "File Memory Manager: invalid file" $FMem_Err_FileNotOpen = "File Memory Manager: file not open" $FMem_Err_IndexOutOfBounds = "File Memory Manager: index out of bounds" $FMem_Err_InvalidBlockSize = "File Memory Manager: invalid block size" $FMem_Err_InvalidPageNo = "File Memory Manager: invalid page number" $FMem_Err_BlockOutOfFileBounds = "File Memory Manager: block out of file bounds" $FMem_Err_BlockOutOfPageBounds = "File Memory Manager: block out of page bounds" $FMem_Err_InvalidBlockPos = "File Memory Manager: invalid block position" $FMem_Err_BadBlockHandle = "File Memory Manager: bad block handle" ' Macro FMem_ExitFalse(test, procedure, msg) If test Then Else #Debug Print FuncName$ +": "+ msg t.isErr = %TRUE t.errMsg = msg Exit procedure End If End Macro Macro FMem_ExitTrue(test, procedure, msg) If test Then #Debug Print FuncName$ +": "+ msg t.isErr = %TRUE t.errMsg = msg Exit procedure End If End Macro Macro FMem_GoFalse(test, MARKER, msg) If test Then Else #Debug Print FuncName$ +": "+ msg t.isErr = %TRUE t.errMsg = msg GoTo MARKER End If End Macro Macro FMem_GoTrue(test, MARKER, msg) If test Then #Debug Print FuncName$ +": "+ msg t.isErr = %TRUE t.errMsg = msg GoTo MARKER End If End Macro ' Macro McFMem_BlockSize(blockSize) = ((Int(blockSize / %FMem_BlockIncr)) * %FMem_BlockIncr) + IIf&(blockSize Mod %FMem_BlockIncr, %FMem_BlockIncr, 0) '12345|12345|12345 Macro McFMem_PageFilePosition(pageNo) = (pageNo * %FMem_PageSize) - %FMem_PageSize + 1 Macro McFMem_BlockIndex(blockSize) = blockSize / %FMem_BlockIncr Macro McFMem_PageCount = (FMap_LOF(t.map) / %FMem_PageSize) Macro McFMem_BlocksPerPage(blockSize) = Int(%FMem_PageSize / blockSize) Macro McFMem_MemAddr(hBlock) = t.map.hView + hBlock - 1 ' ' ' Type FMem_FreeT nextFree As Long End Type Type FMem_HdrT validate As Guid freeBlock(1 To %FMem_BlockVariations) As Long userArr(1 To %FMem_UserMax) As Long End Type Type FMemT hdr As FMem_HdrT map As FMapT isOpen As Long isErr As Long errMsg As Asciiz * 256 End Type ' ' ' Function FMem_Create(t As FMemT, ByVal file As String) As Long 'create new file - open for use - True/False success Local i As Long Local pHdr As FMem_HdrT Ptr ' t.isErr = %FALSE t.isOpen = %FALSE FMem_ExitFalse(FMap_Create(t.map, file, %FMem_PageSize), Function, t.map.errMsg) t.hdr.validate = $FMem_Validation For i = 1 To %FMem_BlockVariations t.hdr.freeBlock(i) = %NULL Next i For i = 1 To %FMem_UserMax t.hdr.userArr(i) = %NULL Next i pHdr = FMap_MemStart(t.map) : FMem_GoFalse(pHdr, CLOSE_FILE_MAP, $FMem_Err_NullPtr) @pHdr = t.hdr 'store header in file t.isOpen = %TRUE Function = %TRUE ' Exit Function ' CLOSE_FILE_MAP: FMap_Close t.map End Function ' Function FMem_Open(t As FMemT, ByVal file As String) As Long 'open existing file - True/False success ' file must have been created by FMem_Create() Local pHdr As FMem_HdrT Ptr ' t.isErr = %FALSE t.isOpen = %FALSE FMem_ExitFalse(FMap_Open(t.map, file), Function, t.map.errMsg) FMem_GoTrue(FMap_LOF(t.map) < %FMem_PageSize, CLOSE_FILE_MAP, $FMem_Err_InvalidFile) pHdr = FMap_MemStart(t.map) : FMem_GoFalse(pHdr, CLOSE_FILE_MAP, $FMem_Err_NullPtr) t.hdr = @pHdr 'get header from file FMem_GoFalse(t.hdr.validate = $FMem_Validation, CLOSE_FILE_MAP, $FMem_Err_InvalidFile) t.isOpen = %TRUE Function = %TRUE ' Exit Function ' CLOSE_FILE_MAP: FMap_Close t.map End Function ' Sub FMem_Close(t As FMemT) 'close file Local pHdr As FMem_HdrT Ptr ' t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Sub, $FMem_Err_FileNotOpen) pHdr = FMap_MemStart(t.map) : FMem_GoFalse(pHdr, CLOSE_FILE_MAP, $FMem_Err_NullPtr) @pHdr = t.hdr 'save header in file ' CLOSE_FILE_MAP: FMap_Close t.map t.isOpen = %FALSE End Sub ' Sub FMem_Clear(t As FMemT) 'delete all data ' file header cleared ' 200 user slots cleared ' file reduced to one page - holds header Local i As Long Local pHdr As FMem_HdrT Ptr ' t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Sub, $FMem_Err_FileNotOpen) FMap_Resize t.map, %FMem_PageSize FMem_ExitTrue(t.map.isErr, Sub, t.map.errMsg) For i = 1 To %FMem_BlockVariations t.hdr.freeBlock(i) = %NULL Next i For i = 1 To %FMem_UserMax t.hdr.userArr(i) = %NULL Next i pHdr = FMap_MemStart(t.map) : FMem_ExitFalse(pHdr, Sub, $FMem_Err_NullPtr) @pHdr = t.hdr End Sub ' Function FMem_Alloc(t As FMemT, ByVal blockSize As Long) As Long 'allocate block of memory in file - return handle ' this returns a handle to an allocated memory block in the file ' use FMem_Get() to get a memory address to work with allocated block ' p = FMem_Get(tFMem, h) : @p.count = 99 'changes reflected in file Local i, hBlock, pageNo, blockCount As Long ' t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Function, $FMem_Err_FileNotOpen) FMem_ExitTrue(blockSize < 1 Or blockSize > %FMem_BlockMax, Function, $FMem_Err_InvalidBlockSize) ' blockSize = McFMem_BlockSize(blockSize) hBlock = FMem_GetFreeBlock(t, blockSize) If hBlock Then Function = hBlock Else FMap_Resize t.map, FMap_LOF(t.map) + %FMem_PageSize pageNo = McFMem_PageCount : FMem_ExitFalse(pageNo, Function, $FMem_Err_InvalidPageNo) hBlock = McFMem_PageFilePosition(pageNo) blockCount = McFMem_BlocksPerPage(blockSize) 'push all blocks on free stack For i = 1 To blockCount FMem_Free t, hBlock, blockSize hBlock += blockSize Next i hBlock = FMem_GetFreeBlock(t, blockSize) FMem_ExitFalse(hBlock, Function, $FMem_Err_NullHandle) Function = hBlock End If End Function Function FMem_Get(t As FMemT, ByVal hBlock As Long) As Long 'get pointer memory address for hBlock ' this returns the memory address within the File Mapping, File View; for hBlock ' use this memory address to set a pointer to the structure that hBlock was allocated for ' p = FMem_Get(tFMem, hBlock) ' you can now use the pointer to Get/Set values ' INCR @p.count : x = @p.count ' modifications automatically reflect threw to file t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Function, $FMem_Err_FileNotOpen) FMem_ExitFalse(hBlock, Function, $FMem_Err_NullHandle) Function = McFMem_MemAddr(hBlock) End Function ' Sub FMem_Free(t As FMemT, ByVal hBlock As Long, ByVal blockSize As Long) 'free an allocated file memory block - block pushed on stack for reuse Local index As Long Local pFree As FMem_FreeT Ptr ' t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Sub, $FMem_Err_FileNotOpen) FMem_ExitFalse(hBlock, Sub, $FMem_Err_NullHandle) FMem_ExitTrue(blockSize < 1 Or blockSize > %FMem_BlockMax, Sub, $FMem_Err_InvalidBlockSize) ' blockSize = McFMem_BlockSize(blockSize) ' index = McFMem_BlockIndex(blockSize) : FMem_ExitTrue(index < 1 Or index > %FMem_BlockVariations, Sub, $FMem_Err_IndexOutOfBounds) pFree = FMem_Get(t, hBlock) : FMem_ExitFalse(pFree, Sub, $FMem_Err_NullHandle) 'null memory Poke$ pFree, Nul$(blockSize) @pFree.nextFree = t.hdr.freeBlock(index) t.hdr.freeBlock(index) = hBlock End Sub ' Function FMem_IsErr(t As FMemT) As Long 'True/False if last operation caused an error Function = t.isErr End Function ' Function FMem_ErrMsg(t As FMemT) As String 'get error message If t.isErr Then Function = t.errMsg End Function ' Sub FMem_SetUser(t As FMemT, ByVal index As Long, ByVal value As Long) 'set one of the 200 LONG user slots available ' value will be permanently stored in file header ' erased by FMem_Clear() t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Sub, $FMem_Err_FileNotOpen) FMem_ExitTrue(index < 1 Or index > %FMem_UserMax, Sub, $FMem_Err_IndexOutOfBounds) t.hdr.userArr(index) = value End Sub ' Function FMem_GetUser(t As FMemT, ByVal index As Long) As Long 'get one of the 200 LONG user slots available ' user values are permanently stored in file header ' erased by FMem_Clear() t.isErr = %FALSE FMem_ExitFalse(t.isOpen, Function, $FMem_Err_FileNotOpen) FMem_ExitTrue(index < 1 Or index > %FMem_UserMax, Function, $FMem_Err_IndexOutOfBounds) Function = t.hdr.userArr(index) End Function ' ' ----------------------------------- ' internal ' ----------------------------------- ' Function FMem_GetFreeBlock(t As FMemT, ByVal blockSize As Long) As Long 'get freed block from stack Local index, hBlock As Long Local pFree As FMem_FreeT Ptr ' t.isErr = %FALSE index = McFMem_BlockIndex(blockSize) : FMem_ExitTrue(index < 1 Or index > %FMem_BlockVariations, Function, $FMem_Err_IndexOutOfBounds) hBlock = t.hdr.freeBlock(index) If hBlock Then pFree = McFMem_MemAddr(hBlock) : FMem_ExitFalse(pFree, Function, $FMem_Err_NullPtr) t.hdr.freeBlock(index) = @pFree.nextFree Function = hBlock End If End Function '
Comment