mirror of
https://github.com/aziascreations/PB-MessagePack.git
synced 2026-11-03 17:01:24 +01:00
209 lines
6.9 KiB
Plaintext
209 lines
6.9 KiB
Plaintext
;{- Code Header
|
|
; ==- Basic Info -================================
|
|
; Name: _Allocators.pbi
|
|
; Version: 0.0.1
|
|
; Author: Herwin Bozet (NibblePoker)
|
|
;
|
|
; ==- Compatibility -=============================
|
|
; Tested compiler version:
|
|
; * PureBasic 5.73 LTS (x86/x64)
|
|
; * PureBasic 6.21 (x86/x64)
|
|
; * PureBasic 6.21 C Backend (x86/x64/arm64)
|
|
;
|
|
; ==- Links & License -===========================
|
|
; License: CC0 1.0 Universal (Public Domain)
|
|
; GitHub: https://github.com/aziascreations/PB-MessagePack
|
|
;}
|
|
|
|
|
|
; ------------------------------------------------------------------------------
|
|
;- Compiler directive
|
|
|
|
XIncludeFile "./_Commons.pbi"
|
|
|
|
|
|
|
|
; ------------------------------------------------------------------------------
|
|
;- Procedures
|
|
|
|
;-> Thingies
|
|
|
|
Procedure.i MsgPackCreate(InitialSize.i, GrowthIncrement.i = 1)
|
|
Protected *ReturnedValue.MsgPackData = #Null
|
|
|
|
If InitialSize <= 0
|
|
DebuggerWarning("Returning #Null, requested size was zero or negative")
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
If GrowthIncrement <= 0
|
|
DebuggerWarning("Returning #Null, growth increment was zero or negative")
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
*ReturnedValue = AllocateStructure(MsgPackData)
|
|
|
|
If *ReturnedValue <> #Null
|
|
*ReturnedValue\BufferOffset = 0
|
|
*ReturnedValue\BufferSize = InitialSize
|
|
*ReturnedValue\BufferGrowthIncrement = GrowthIncrement
|
|
*ReturnedValue\DataFlags = #_MsgPack_DefaultDataFlags
|
|
|
|
*ReturnedValue\Buffer = AllocateMemory(InitialSize)
|
|
If Not *ReturnedValue\Buffer
|
|
Debug("Failed to allocate memory for buffer !")
|
|
FreeStructure(*ReturnedValue)
|
|
*ReturnedValue = #Null
|
|
EndIf
|
|
EndIf
|
|
|
|
ProcedureReturn *ReturnedValue
|
|
EndProcedure
|
|
|
|
; Wraps an existing buffer into an internal structure without copying it.
|
|
; If `GiveOwnership` is `#False`, the buffer stays owned by the caller: it will never
|
|
; be grown or freed by this include, and the caller must free it themselves.
|
|
; If `GiveOwnership` is `#True`, `*Buffer` MUST come from `AllocateMemory()`, since it
|
|
; may be reallocated when growing, and it can be freed through `MsgPackFree()`.
|
|
Procedure.i MsgPackWrapMsgBuffer(*Buffer, BufferSize.i, GiveOwnership.b = #False, GrowthIncrement.i = 1)
|
|
Protected *ReturnedValue.MsgPackData = #Null
|
|
|
|
If *Buffer = #Null Or BufferSize <= 0
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
If GrowthIncrement <= 0
|
|
DebuggerWarning("Returning #Null, growth increment was zero or negative")
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
*ReturnedValue = AllocateStructure(MsgPackData)
|
|
If *ReturnedValue = #Null
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
*ReturnedValue\BufferOffset = 0
|
|
*ReturnedValue\BufferSize = BufferSize
|
|
*ReturnedValue\BufferGrowthIncrement = GrowthIncrement
|
|
*ReturnedValue\DataFlags = #_MsgPack_DefaultDataFlags
|
|
*ReturnedValue\Buffer = *Buffer
|
|
|
|
If Not GiveOwnership
|
|
*ReturnedValue\DataFlags = *ReturnedValue\DataFlags | #MsgPack_DataFlags_CannotGrow | #MsgPack_DataFlags_NoBufferFree
|
|
EndIf
|
|
|
|
ProcedureReturn *ReturnedValue
|
|
EndProcedure
|
|
|
|
; Frees a structure, and its buffer too if `FreeDataBuffer` is `#True`.
|
|
; `FreeDataBuffer` has no default on purpose: forgetting it either leaks the buffer or frees one that's still in use.
|
|
Procedure.b MsgPackFree(*MsgPackData.MsgPackData, FreeDataBuffer.b)
|
|
If Not *MsgPackData
|
|
ProcedureReturn #False
|
|
EndIf
|
|
|
|
If FreeDataBuffer And _MsgPackHasFlag(*MsgPackData, #MsgPack_DataFlags_NoBufferFree)
|
|
DebuggerError("Cannot free a buffer that is still owned by the caller !")
|
|
ProcedureReturn #False
|
|
EndIf
|
|
|
|
If *MsgPackData\Buffer <> #Null And FreeDataBuffer
|
|
FreeMemory(*MsgPackData\Buffer)
|
|
EndIf
|
|
FreeStructure(*MsgPackData)
|
|
|
|
ProcedureReturn #True
|
|
EndProcedure
|
|
|
|
; Frees a given internal structure and returns its buffer, shrunk to the number of bytes
|
|
; written so far (`BufferOffset`), whose size can be obtained with `MemorySize()`.
|
|
; The caller takes ownership of the returned buffer and must free it with `FreeMemory()`.
|
|
; Returns `#Null` on errors, in which case `*MsgPackData` and its buffer are left untouched.
|
|
Procedure.i MsgPackFinalize(*MsgPackData.MsgPackData)
|
|
Protected *FinalBuffer
|
|
|
|
If Not *MsgPackData
|
|
DebuggerError("A #Null MsgPackData pointer was passed !")
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
If _MsgPackHasFlag(*MsgPackData, #MsgPack_DataFlags_NoBufferFree)
|
|
DebuggerError("Cannot finalize a buffer that is still owned by the caller !")
|
|
*MsgPackData\LastError = #MsgPack_Error_InvalidValue
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
If *MsgPackData\BufferOffset <= 0
|
|
DebuggerError("Cannot finalize an empty buffer !")
|
|
*MsgPackData\LastError = #MsgPack_Error_InvalidValue
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
*FinalBuffer = ReAllocateMemory(*MsgPackData\Buffer, *MsgPackData\BufferOffset, #PB_Memory_NoClear)
|
|
If Not *FinalBuffer
|
|
Debug("Failed to shrink memory for buffer !")
|
|
*MsgPackData\LastError = #MsgPack_Error_FailedToGrowBuffer
|
|
ProcedureReturn #Null
|
|
EndIf
|
|
|
|
FreeStructure(*MsgPackData)
|
|
|
|
ProcedureReturn *FinalBuffer
|
|
EndProcedure
|
|
|
|
|
|
; TODO: Add callback in the structure, maybe ?
|
|
Procedure.MsgPack_ErrorCode MsgPackGrow(*MsgPackData.MsgPackData, DesiredSizeIncrease.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
|
|
|
|
NewSize = *MsgPackData\BufferSize + DesiredSizeIncrease
|
|
|
|
; Rounding up to the next multiple of `BufferGrowthIncrement`.
|
|
If *MsgPackData\BufferGrowthIncrement > 1
|
|
NewSize = ((NewSize + *MsgPackData\BufferGrowthIncrement - 1) / *MsgPackData\BufferGrowthIncrement) * *MsgPackData\BufferGrowthIncrement
|
|
EndIf
|
|
|
|
; `DesiredSizeIncrease` is positive, so a new size that isn't bigger can only come from an overflow.
|
|
; Sizes that don't fit in a `.i` would also be truncated by `ReAllocateMemory()` on x86.
|
|
If NewSize <= *MsgPackData\BufferSize Or NewSize > #_MsgPack_MaxIntegerValue
|
|
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
|
|
Debug("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
|