Improved buffer growth mechanism, Added tests for it some still missing

This commit is contained in:
2026-10-22 22:31:19 +02:00
parent 00143b5b65
commit 4f97cafd1b
8 changed files with 124 additions and 70 deletions
+59 -2
View File
@@ -41,7 +41,7 @@ Procedure.i MsgPackCreate(InitialSize.i)
If *ReturnedValue <> #Null
*ReturnedValue\BufferOffset = 0
*ReturnedValue\BufferSize = InitialSize
*ReturnedValue\BufferGrowthIncrements = InitialSize
*ReturnedValue\BufferGrowthIncrement = InitialSize
*ReturnedValue\DataFlags = 0
*ReturnedValue\Buffer = AllocateMemory(InitialSize)
@@ -72,7 +72,7 @@ Procedure.i MsgPackWrapMsgBuffer(*Buffer, BufferSize.i)
*ReturnedValue\BufferOffset = 0
*ReturnedValue\BufferSize = BufferSize
*ReturnedValue\BufferGrowthIncrements = 0
*ReturnedValue\BufferGrowthIncrement = 0
*ReturnedValue\DataFlags = 0
*ReturnedValue\Buffer = *Buffer
@@ -93,3 +93,60 @@ Procedure.b MsgPackFree(*MsgPackData.MsgPackData, FreeDataBuffer.b = #False)
ProcedureReturn #True
EndProcedure
; TODO: Add callback in the structure, maybe ?
; FIXME: Use a .q for the size !!!!
Procedure.MsgPack_ErrorCode MsgPackGrow(*MsgPackData.MsgPackData, DesiredSizeIncrease.i)
Protected GrowthSize.q
Protected NewSize.q
Protected *NewBuffer
CompilerIf Not #MsgPack_DisableNullChecks
If Not *MsgPackData
DebuggerError("A #Null MsgPackData pointer was passed !")
ProcedureReturn #MsgPack_Error_NullPointerGiven
EndIf
CompilerEndIf
If _MsgPackHasFlag(*MsgPackData, #MsgPack_DataFlags_CannotGrow)
*MsgPackData\LastError = #MsgPack_Error_CannotGrowBufferDueToConfig
ProcedureReturn #MsgPack_Error_CannotGrowBufferDueToConfig
EndIf
If DesiredSizeIncrease <= 0
DebuggerError("Negative growth value was passed !")
*MsgPackData\LastError = #MsgPack_Error_InvalidValue
ProcedureReturn #MsgPack_Error_InvalidValue
EndIf
If *MsgPackData\BufferGrowthIncrement <= 1
GrowthSize = DesiredSizeIncrease
NewSize = *MsgPackData\BufferSize + GrowthSize
Else
GrowthSize = (DesiredSizeIncrease % *MsgPackData\BufferGrowthIncrement) + DesiredSizeIncrease
NewSize = ((*MsgPackData\BufferSize + GrowthSize) % *MsgPackData\BufferGrowthIncrement) + (*MsgPackData\BufferSize + GrowthSize)
EndIf
If (GrowthSize < 0) Or (*MsgPackData\BufferSize + GrowthSize < 0) Or (NewSize < 0) Or (NewSize < *MsgPackData\BufferSize)
DebuggerError("We had an overflow in one of the growth values, the calculation is messed up !")
*MsgPackData\LastError = #MsgPack_Error_ValueOverflow
ProcedureReturn #MsgPack_Error_ValueOverflow
EndIf
*NewBuffer = ReAllocateMemory(*MsgPackData\Buffer, NewSize)
If Not *NewBuffer
DebuggerError("Failed to reallocate memory for buffer !")
*MsgPackData\LastError = #MsgPack_Error_FailedToGrowBuffer
ProcedureReturn #MsgPack_Error_FailedToGrowBuffer
EndIf
*MsgPackData\Buffer = *NewBuffer
*MsgPackData\BufferSize = NewSize
; Often set by the callers, but programmers are likely to use this
; function directly, so I'm leaving it here.
*MsgPackData\LastError = #MsgPack_Error_Success
ProcedureReturn #MsgPack_Error_Success
EndProcedure
+1
View File
@@ -30,6 +30,7 @@ CompilerIf #PB_Compiler_IsMainFile
CompilerEndIf
XIncludeFile "./_Commons.pbi"
XIncludeFile "./_Allocators.pbi"
+18 -60
View File
@@ -138,12 +138,14 @@ Enumeration _MsgPack_ErrorCodes
; Common errors
#MsgPack_Error_NullPointerGiven = 1
#MsgPack_Error_BufferTooSmall = 2
#MsgPack_Error_InvalidValue = 3
#MsgPack_Error_ValueOverflow = 4
; Shouldn't re-use it.
#MsgPack_Error_FailedToGrowBuffer = 3
#MsgPack_Error_AtOrPastTheEndOfBuffer = 4
#MsgPack_Error_ReadPastEndOfBuffer = 5
#MsgPack_Error_InvalidFormatCode = 6
#MsgPack_Error_FailedToGrowBuffer = 10
#MsgPack_Error_AtOrPastTheEndOfBuffer = 11
#MsgPack_Error_ReadPastEndOfBuffer = 12
#MsgPack_Error_InvalidFormatCode = 13
; 5x - Binary
#MsgPack_Error_BinaryDataSizeIsNegative = 50
@@ -154,15 +156,14 @@ Enumeration _MsgPack_ErrorCodes
EndEnumeration
EnumerationBinary _MsgPack_DataFlags
; Not implemented
; FIXME: Not implemented
#MsgPack_DataFlags_IsReadOnly = %0000000000000001
; FIXME: Not implemented
; Prevents a `MsgPackData` structure from auto-growing its buffer when needed.
; It may make some functions return `#`
; It may make some functions return `#MsgPack_Error_CannotGrowBufferDueToConfig`.
#MsgPack_DataFlags_CannotGrow = %0000000000000010
; Not implemented
; FIXME: Not implemented
#MsgPack_DataFlags_NoBufferFree = %0000000000000100
; Indicates a given `MsgPackData` should increment its buffer offset after
@@ -173,11 +174,12 @@ EnumerationBinary _MsgPack_DataFlags
; writing a value using the standard procedures.
#MsgPack_DataFlags_MoveOffsetAfterWrite = %0000000000010000
; FIXME: Not implemented
; Indicates a given `MsgPackData` is made to be iterated on.
; And it implies it represents a Map or Array.
#MsgPack_DataFlags_Iterator = %0000000000001000
#MsgPack_DataFlags_CanProvideKeys = %0000000000010000
#MsgPack_DataFlags_CanProvideVals = %0000000000100000
#MsgPack_DataFlags_Iterator = %0000000000100000
#MsgPack_DataFlags_CanProvideKeys = %0000000001000000
#MsgPack_DataFlags_CanProvideVals = %0000000010000000
EndEnumeration
EnumerationBinary _MsgPack_ExaminationOptions
@@ -212,8 +214,11 @@ Structure MsgPackData
; Used in place of `MemorySize()` to reduce syscalls.
BufferSize.i
; Temp mechanism for buffer growth.
BufferGrowthIncrements.i
; Multiple of which any buffer size increase should match.
; Also applies to its initial size. (FIXME)
; If the requested size doesn't match one, we'll use the nearest next multiple.
; If set to `1` or lower, we'll ignore this mechanism.
BufferGrowthIncrement.i
; IteratorSizeLeft, or snoething like this.
@@ -260,53 +265,6 @@ Procedure.MsgPack_ErrorCode MsgPackLastError(*MsgPackData.MsgPackData)
EndProcedure
; Should be moved to allocators.
; But it would fuck up the splitting of responsibility.
; TODO: Add callback in the structure, maybe ?
; FIXME: Use a .q for the size !!!!
Procedure.MsgPack_ErrorCode MsgPackGrow(*MsgPackData.MsgPackData, MinimalGrowthSize.i = -1)
Protected GrowthSize.i
Protected *NewBuffer
CompilerIf Not #MsgPack_DisableNullChecks
If Not *MsgPackData
DebuggerError("A #Null MsgPackData pointer was passed !")
ProcedureReturn #MsgPack_Error_NullPointerGiven
EndIf
CompilerEndIf
; Often set by the callers, but programmers are likely to use it too,
; so I'm leaving it here.
*MsgPackData\LastError = #MsgPack_Error_Success
If *MsgPackData\BufferGrowthIncrements <= 0
DebuggerError("Cannot grow a buffer with no growth increments !")
*MsgPackData\LastError = #MsgPack_Error_CannotGrowBufferDueToConfig
ProcedureReturn #MsgPack_Error_CannotGrowBufferDueToConfig
EndIf
; TODO: Improve logic later, i can't be bothered now
GrowthSize = *MsgPackData\BufferGrowthIncrements
If MinimalGrowthSize > GrowthSize
GrowthSize = ((MinimalGrowthSize + GrowthSize - 1) / GrowthSize) * GrowthSize
EndIf
*NewBuffer = ReAllocateMemory(*MsgPackData\Buffer, *MsgPackData\BufferSize + GrowthSize)
If Not *NewBuffer
DebuggerError("Failed to reallocate memory for buffer !")
*MsgPackData\LastError = #MsgPack_Error_FailedToGrowBuffer
ProcedureReturn #MsgPack_Error_FailedToGrowBuffer
EndIf
*MsgPackData\Buffer = *NewBuffer
*MsgPackData\BufferSize + GrowthSize
ProcedureReturn #MsgPack_Error_Success
EndProcedure
; ------------------------------------------------------------------------------
;- Debugging
+1
View File
@@ -24,6 +24,7 @@ CompilerIf #PB_Compiler_IsMainFile
CompilerEndIf
XIncludeFile "./_Commons.pbi"
XIncludeFile "./_Allocators.pbi"
+1
View File
@@ -25,6 +25,7 @@ CompilerEndIf
; Includes the required "Endianness.pbi"
XIncludeFile "./_Commons.pbi"
XIncludeFile "./_Allocators.pbi"
+1
View File
@@ -20,6 +20,7 @@
;- Compiler directive
XIncludeFile "./_Commons.pbi"
XIncludeFile "./_Allocators.pbi"
@@ -1,8 +0,0 @@
EnableExplicit
XIncludeFile "../_UnitTesting.pbi"
XIncludeFile "../../Includes/MessagePack.pbi"
; ???
@@ -0,0 +1,43 @@
EnableExplicit
XIncludeFile "../_UnitTesting.pbi"
XIncludeFile "../../Includes/MessagePack.pbi"
; Setup
Define *BufferHolder.MsgPackData = MsgPackCreate(1)
Define LastMeasuredSize.q = MemorySize(*BufferHolder\Buffer)
; Checking defaults, should be able to grow
AssertIsFalse(Bool(_MsgPackHasFlag(*BufferHolder, #MsgPack_DataFlags_CannotGrow)), "The `#MsgPack_DataFlags_CannotGrow` flag isn't set by default.")
; Testing null
AssertEquals(MsgPackGrow(#Null, 64), #MsgPack_Error_NullPointerGiven, "Passing #Null is rejected properly")
; Testing negative growth
AssertEquals(MsgPackGrow(*BufferHolder, -1), #MsgPack_Error_InvalidValue, "Negative growth is blocked.")
AssertEquals(*BufferHolder\LastError, #MsgPack_Error_InvalidValue, "Negative growth's error is set in structure.")
; Testing blocked growth
*BufferHolder\DataFlags = *BufferHolder\DataFlags | #MsgPack_DataFlags_CannotGrow
AssertIsTrue(Bool(_MsgPackHasFlag(*BufferHolder, #MsgPack_DataFlags_CannotGrow)), "The `#MsgPack_DataFlags_CannotGrow` flag is now set.")
AssertEquals(MsgPackGrow(*BufferHolder, 64), #MsgPack_Error_CannotGrowBufferDueToConfig, "Testing disabled growth.")
AssertEquals(*BufferHolder\LastError, #MsgPack_Error_CannotGrowBufferDueToConfig, "Blocked growth's error is set in structure.")
AssertEquals(*BufferHolder\BufferSize, LastMeasuredSize, "Buffer's length is untouched. (1)")
AssertEquals(MemorySize(*BufferHolder\Buffer), LastMeasuredSize, "Buffer's length is untouched. (2)")
If FailedUnitTests
End 1
EndIf
Debug "Done !"
End 0