Type FixLenStr (fixed size String Type)

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
MrSwiss
Posts: 3609
Joined: Jun 02, 2013 9:27
Location: Switzerland

Type FixLenStr (fixed size String Type)

Postby MrSwiss » Dec 17, 2018 13:51

Hi all,
after reading some recent posts, as well as seeing some ideas/attemps,
I've decided to do it, "straight and narrow".
Which means to say: use var-len String, as a prototype ...

The Type can be used in the conventional way: with Dim
-- or --
with the use of Pointers (New / Delete):

Code: Select all

' FixLenStr_Type.bas -- 2018-12-15, MrSwiss

' ----- Type FixLenStr -----
Type FixLenStr
  Public:
    ' default & customized ctor / dtor (default)
    Declare Constructor()               ' default constructor
    Declare Constructor(ByRef As String, ByVal As UInteger) ' custom ctor
    Declare Destructor()                ' default destructor
    ' setter for a different string (or non pointer use)
    Declare Sub         SetStr(ByRef As String, ByVal As UInteger)
    ' different getter's
    Declare Function    GetStr() As String
    Declare Function    GetLen() As UInteger
    Declare Function    GetMem() As UInteger
  Private:
    ' similar to var-len string (same informations)
    As ZString Ptr      psz
    As UInteger         lens, mems
End Type

Constructor FixLenStr()                 ' does nothing! default ctor
End Constructor

Constructor FixLenStr( _                ' cstom constructor
    ByRef strg  As String, _            ' string to store (max. len. below)
    ByVal size  As UInteger _           ' sizes stored strings length
    )
    If size > 0 Then                    ' throw ERROR if size = 0
        With This                       ' Callocate: clears alloc'ed mem.
        .psz = Callocate(size + 1)      ' length + terminator = Chr(0)
        .mems = size + 1                ' store memory size allocated
        If Len(strg) > size Then        ' if sting is to long, chop it
            *(.psz) = Left(strg, size)  ' chop string to size
            .lens = size                ' whole alloc'ed memory used
        Else                            ' string fits alloc'ed mem.
            *(.psz) = strg              ' len(strg) <= size 
            .lens = Len(strg)           ' store real string's length
        End If
        End With
    Else
        Print "ERROR: size = 0 !"       ' ERROR message (then quit)
    End If
End Constructor

Destructor FixLenStr()                  ' default destructor (prevent mem. leaks)
    With This
    If .psz > 0 Then DeAllocate(.psz)   ' free alloc. mem. (if any allocated)
    .psz = 0 : .lens = 0 : .mems = 0    ' reset all (= uninit. type)
    End With
End Destructor

Sub FixLenStr.SetStr( _
    ByRef strg  As String, _
    ByVal size  As UInteger _
    )
    If size > 0 Then
        With This
        If .psz > 0 Then DeAllocate(.psz)   ' conditional free alloc. mem.
        .psz = Callocate(size + 1)      ' below code, see: custom ctor above
        .mems = size + 1
        If Len(strg) > size Then
            *(.psz) = Left(strg, size) : .lens = size
        Else
            *(.psz) = strg : .lens = Len(strg)
        End If
        End With
    Else
        Print "ERROR: size = 0 !"
    End If
End Sub

Function FixLenStr.GetStr() As String
    Return *(This.psz)
End Function

Function FixLenStr.GetLen() As UInteger
    Return This.lens
End Function

Function FixLenStr.GetMem() As UInteger
    Return This.mems
End Function
' ----- End-Type -----

' ===== DEMO =====
Dim As String   test1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", _
                test2 = "0123456789012345678901234567890123456789"

Print "predefined source Strings ..."
Print test1,, Str(Len(test1))
Print test2, Str(Len(test2))
Print String(50, "-") : Print


' common init (no pointers)
Dim As FixLenStr    FS = FixLenStr("TESTING", 7), _ ' custom ctor call
                    FS1                 ' default ctor (uninit. type)
' below: use without pointers
Print FS.GetStr,, "len: "; FS.GetLen; _ ' output initialized type
      "    mem: "; FS.GetMem

FS1.SetStr("Welcome to FreeBASIC!", 31) ' assign uninit. type (more mem. than used)
Print FS1.GetStr, "len: "; FS1.GetLen; "   mem: "; FS1.GetMem

FS1.SetStr("-+-+-+-+-+-+-+-+-+-+-", 21) ' assign again (just needed length)
Print FS1.GetStr, "len: "; FS1.GetLen; "   mem: "; FS1.GetMem
Print

FS.SetStr("err test", 0)                ' force error (test only!)
Print : Print


' using pointers ... (usually with custom constructor)
Var tst1 = New FixLenStr(test1, 16)     ' chops string off (constructor call)
Print tst1->GetStr, _                   ' show stored FixLenStr _
      "len: "; tst1->GetLen; _          ' and other stored data (len / mem)
      "   mem: "; tst1->GetMem
Delete(tst1)                            ' destructor call (indirect)
' use above again (in a different way)
tst1 = New FixLenStr(test1, Len(test1)) ' whole string (just enough memory!)
Print tst1->GetStr, "len: "; tst1->GetLen; "   mem: "; tst1->GetMem
Print

Var tst2 = New FixLenStr(test2, 10)     ' first 10 char's (of 40 in string)
Print tst2->GetStr,, "len: "; tst2->GetLen; "   mem: "; tst2->GetMem

tst2->SetStr(test2, 20)                 ' reassign with first 20 char's
Print tst2->GetStr, "len: "; tst2->GetLen; "   mem: "; tst2->GetMem
Print

tst2->SetStr("err test", 0)             ' force error (test only!)
Print : Print
Print "press a key to EXIT ... ";

' clean up: free memory used
Delete(tst1) : Delete(tst2)

Sleep
' ===== End-DEMO =====  ' ----- EOF ------
Demo code uses both methods ...
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: Type FixLenStr (fixed size String Type)

Postby sancho3 » Dec 18, 2018 2:46

I recommend overloading at least the Cast/String so that one could use simply:
? myfixlenstr

I would also add the &, Let, and any other that are available to the built in fixed length string.
MrSwiss
Posts: 3609
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Type FixLenStr (fixed size String Type)

Postby MrSwiss » Dec 18, 2018 21:01

sancho3 wrote:I recommend overloading at least the Cast/String ...

Added:
    Let & Cast operators ...
    GetPsz() function (for calling C proc's.)

The whole type in a .bi file, "FixLenStr.bi":

Code: Select all

' FixLenStr.bi -- 2018-12-20, MrSwiss (operators Cast/Let & GetPsz() added)
' -------------------------------------------------------------------------
' fixed Let Operator (allow uninit. type, too)
' avoid uneeded memory DeAlloc./Calloc. call's in SetStr() (if same size)
' -------------------------------------------------------------------------

#Pragma Once            ' include guard (FB style)

' ----- Type FixLenStr -----
Type FixLenStr
  Public:
    ' default & customized ctor / dtor (default)
    Declare Constructor()               ' default constructor
    Declare Constructor(ByRef As String, ByVal As UInteger) ' custom ctor
    Declare Destructor()                ' default destructor
    ' operators (ease of use and assign a pre-sized new string)
    Declare Operator    Let(ByRef rhs As String) ' new string (same size/new size)
    Declare Operator    Cast() As String    ' not for ptr use (use GetPsz/GetStr)
    ' setter for a new/different size of string (otherwise use Let)
    Declare Sub         SetStr(ByRef As String, ByVal As UInteger)
    ' different getter's
    Declare Function    GetPsz() ByRef As Const ZString Ptr ' for calling C proc's.
    Declare Function    GetStr() As String  ' for FB use (dereferenced ptr!)
    Declare Function    GetLen() As UInteger' length of string
    Declare Function    GetMem() As UInteger' size of allocated memory
  Private:
    ' similar to var-len string (same informations)
    As ZString Ptr      psz
    As UInteger         lens, mems
End Type

Constructor FixLenStr()                 ' does nothing! default ctor
End Constructor

Constructor FixLenStr( _                ' cstom constructor
    ByRef strg  As String, _            ' string to store (max. len. below)
    ByVal size  As UInteger _           ' sizes stored strings length
    )
    If size > 0 Then                    ' throw ERROR if size = 0
        With This                       ' Callocate: clears alloc'ed mem.
        .psz = Callocate(size + 1)      ' length + terminator = Chr(0)
        .mems = size + 1                ' store memory size allocated
        If Len(strg) > size Then        ' if sting is to long, chop it
            *(.psz) = Left(strg, size)  ' chop string to size
            .lens = size                ' whole alloc'ed memory used
        Else                            ' string fits alloc'ed mem.
            *(.psz) = strg              ' len(strg) <= size 
            .lens = Len(strg)           ' store real string's length
        End If
        End With
    Else
        Print "ERROR: size = 0 !"       ' ERROR message (then quit)
    End If
End Constructor

Destructor FixLenStr()                  ' default destructor (prevent mem. leaks)
    With This
    If .psz > 0 Then DeAllocate(.psz)   ' free alloc. mem. (if any allocated)
    .psz = 0 : .lens = 0 : .mems = 0    ' reset all (= uninit. type)
    End With
End Destructor

Operator FixLenStr.Cast() As String     ' just for: 'ease of use'
    Return *(This.psz)
End Operator

Operator FixLenStr.Let(ByRef rhs As String) ' assign new string (same size or new)
    With This
    If .psz = 0 Then                    ' only if: uninit. type
        .psz = Callocate(Len(rhs) + 1)  ' allocate memory
        .lens = Len(rhs)                ' store strings length
        .mems = .lens + 1               ' store allcated size
        *(.psz) = rhs                   ' copy string
        Exit Operator                   ' done --> get out
    End If
    Var t = .mems - 1                   ' t = max. string-len
    If  Len(rhs) > t Then               ' string to long?
        *(.psz) = Left(rhs, t) : .lens = t  ' chop it down, to mem.-size given _
    Else                                ' store max. length
        *(.psz) = rhs : .lens = Len(rhs)' smaller/equal size: assign | store _
    End If                              ' real length
    End With
End Operator

Sub FixLenStr.SetStr( _                 ' assign new string, with new size
    ByRef strg  As String, _            ' source string
    ByVal size  As UInteger _           ' size of memory (to be alloc'ed for string)
    )
    If size > 0 Then                    ' throw ERROR if size = 0
        With This
        If size <> .mems - 1 Then       ' no unneeded DeAllocate/Callocate
            If .psz > 0 Then DeAllocate(.psz) ' conditional free alloc. mem.
            .psz = Callocate(size + 1)  ' below code, see: custom ctor above
            .mems = size + 1            ' only needed, if new size
        End If
        If Len(strg) > size Then
            *(.psz) = Left(strg, size) : .lens = size
        Else
            *(.psz) = strg : .lens = Len(strg)
        End If
        End With
    Else
        Print "ERROR: size = 0 !"
    End If
End Sub

Function FixLenStr.GetPsz() ByRef As Const ZString Ptr
    Return This.psz
End Function

Function FixLenStr.GetStr() As String
    Return *(This.psz)
End Function

Function FixLenStr.GetLen() As UInteger
    Return This.lens
End Function

Function FixLenStr.GetMem() As UInteger
    Return This.mems
End Function
' ----- End-Type -----  ' ----- EOF -----

Reworked DEMO code, "FixLenStr_Type.bas" (uses above .bi!):

Code: Select all

' FixLenStr_Type.bas -- 2018-12-18, MrSwiss (updated demo code)

#Include "FixLenStr.bi"

' ===== DEMO =====
Dim As String   test1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", _
                test2 = "0123456789012345678901234567890123456789"

Print "predefined source Strings ..."
Print test1,, Str(Len(test1))
Print test2, Str(Len(test2))
Print String(50, "-") : Print

' common init (no pointers)
Dim As FixLenStr    FS = FixLenStr("TESTING", 9), _ ' custom ctor call
                    FS1                 ' default ctor (uninit. type)
' below: use without pointers
Print FS,, "len: "; FS.GetLen; _        ' output initialized type _
      "    mem: "; FS.GetMem            ' uses Cast operator

FS1.SetStr("Welcome to FreeBASIC!", 31) ' assign uninit. type (more mem. than used)
Print FS1, "len: "; FS1.GetLen; "   mem: "; FS1.GetMem

FS1.SetStr("-+-+-+-+-+-+-+-+-+-+-", 21) ' assign again (just needed length)
Print FS1, "len: "; FS1.GetLen; "   mem: "; FS1.GetMem

FS = "FreeBASIC"                        ' using operator Let (fill alloc'ed mem!)
Print FS,, "len: "; FS.GetLen; "    mem: "; FS.GetMem

FS = "no news!"                         ' using operator Let (smaller than mem!)
Print FS,, "len: "; FS.GetLen; "    mem: "; FS.GetMem
Print

FS.SetStr("err test", 0)                ' force error (test only!)
Print : Print

' using pointers ... (usually with custom constructor)
Var tst1 = New FixLenStr(test1, 16)     ' chops string off (custom ctor call)
Print *(tst1->GetPsz), _                ' show stored FixLenStr _
      "len: "; tst1->GetLen; _          ' and other stored data (len / mem)
      "   mem: "; tst1->GetMem
Delete(tst1)                            ' destructor call (indirect)
' use above again (in a different way)
tst1 = New FixLenStr(test1, Len(test1)) ' whole string (just enough memory!)
Print tst1->GetStr, "len: "; tst1->GetLen; "   mem: "; tst1->GetMem

Var tst2 = New FixLenStr(test2, 10)     ' first 10 char's (of 40 in string)
Print *(tst2->GetPsz),, "len: "; tst2->GetLen; "   mem: "; tst2->GetMem

tst2->SetStr(test2, 20)                 ' reassign with first 20 char's
Print tst2->GetStr, "len: "; tst2->GetLen; "   mem: "; tst2->GetMem

tst2->SetStr(test1, 20)                 ' reassign other string (same size)
Print tst2->GetStr, "len: "; tst2->GetLen; "   mem: "; tst2->GetMem

Print

tst2->SetStr("err test", 0)             ' force error (test only!)
Print : Print
Print "press a key to EXIT ... ";

' clean up: free memory used
Delete(tst1) : Delete(tst2)

Sleep
' ===== End-DEMO =====  ' ----- EOF ------

sancho3 wrote:... any other that are available to the built in fixed length string.

There is just about "nothing", in the default 'fixed length string' it's static.
String * n / ZString * (n+1)
Unlike the FixLenStr Type which can be resized, any time needed/wanted ...
Last edited by MrSwiss on Dec 20, 2018 17:05, edited 1 time in total.
MrSwiss
Posts: 3609
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Type FixLenStr (fixed size String Type)

Postby MrSwiss » Dec 20, 2018 17:04

After doing some more tests, I've had to extend code in Let Operator,
to let it deal with a uninitialized Type, also ...
Since the initial version of SetStr always DeAllocated/Callocated memory,
the recoded version only does it, when new size <> old size ...

Updated code, in above post, the .bi file is the recoded version now.
(2018-12-20)

New test code: specifically, for Let op. testing ... :

Code: Select all

' FixLenStr_Test2.bas -- 2018-12-20, MrSwiss

#Include "FixLenStr.bi"

' ===== DEMO =====
Dim As String   test1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", _
                test2 = "abcdefghijklmnopqrstuvwxyz", _
                test3 = "01234567890"

' common init (no pointers)
Dim As FixLenStr    FS1, FS2, FS3, FS4  ' default ctor (uninit. type)

' below: testing the recoded: Let Operator ... (uninit. type handling)
FS1 = test1 : FS2 = test2 : FS3 = test3 ' simple assignment
FS4 = FS1 & FS2 & FS3                   ' doesn't work with '+' !!! _
' however, they're FIXED size, after all (use FB string's otherwise!)

Print FS1, FS1.GetLen, FS1.GetMem
Print FS2, FS2.GetLen, FS2.GetMem
Print FS3,, FS3.GetLen, FS3.GetMem      ' two tab's needed ...
Print FS4, FS4.GetLen, FS4.GetMem

Sleep

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 3 guests