Main Menu

Recent posts

#61
José Roca Software / Re: DWStrList
Last post by Paul Squires - May 06, 2026, 08:07:15 PM
@Richard Kelly just an FYI, DWString and also built-in FB strings are much better at concatenations than PowerBasic's OLE strings. As José has pointed out, FB strings have a built in extra buffer that allows for better concatenation performance. That is why things like PB's StringBuilder is not overly worthwhile. I built a StringBuilder for FB during my early FB days and it essentially turned out to be a waste of time and actually performed slightly worse than simply adding strings together.
#62
José Roca Software / Re: DWStrList
Last post by José Roca - May 06, 2026, 07:42:44 PM
Not sure I fully understand what you intend to do, but here are the key points.

DWSTRING already uses a string‑builder strategy internally, so repeated concatenations like:

sString = sString + sNewString

are not expensive when done through DWSTRING. The class minimizes reallocations: as long as there is enough capacity in the internal buffer, it simply appends using wmemmove, which is extremely fast.

When the buffer runs out of space, DWSTRING allocates a new buffer with double the previous capacity. This amortizes the cost of growth.

If you know the approximate maximum size of the final string, you can eliminate reallocations entirely by setting the Capacity property:

DIM dws AS DWSTRING
dws.Capacity = 100000   ' // Set the initial capacity to 100000 characters
dws += "New string"
dws += "New string 2"
' ...

If your goal is to store strings for later reuse, you don't need DWStrList or linked lists. A simple array of DWSTRING is more efficient and more in line with modern memory behavior:

DIM rg(100) AS DWSTRING
rg(0) = "string 1"
rg(1) = "string 2"
' ...
DIM dws AS DWSTRING
dws += rg(0)
dws += rg(1)
-- or: dws += rg(0) + " " + rg(1)
print dws

Linked lists are a 1950s solution to a 1950s hardware problem. On modern CPUs, with deep caches and wide memory buses, they are usually worse than contiguous arrays because they destroy locality of reference.

Your best options today are:

DSafeArray, which is already optimized for unicode strings and variants.

DSafeArray.CreateVector, which allocates a single contiguous block and is the most efficient when you know the number of elements in advance.

#63
José Roca Software / DWStrList
Last post by Richard Kelly - May 06, 2026, 03:48:01 PM
This old PowerBasic project I'm porting over involves creating a bunch of strings that get added together like:

sString = sString + sNewString

This can happen many times.

Would it be efficient to store each string in DWStrList and, when I need to full string, pull them from DWStrList one at a time and build the final DWSTRING?

My idea was to keep track of the total length of all the strings added and then use:

DWSTRING (BYVAL nChars AS LONG, BYREF wszFill AS CONST WSTRING)

to allocate a buffer one time to hold all the strings in DWStrList.
#64
José Roca Software / Re: CDicObj
Last post by José Roca - May 05, 2026, 10:06:49 AM
I have made mine indexed, allowing to work as if they were arrays.

' // Retrieve and print the results
FOR i AS LONG = 1 TO List->Count
   PRINT List->Item(i)
NEXT

Therefore, First, Last, Next, Previous and For Each aren't needed.

Although DVarList can be used with any data type, because it uses variants, DWStrList is optimized to work with DWSTRING and it is much faster when you only need to use strings.

I also have safe arrays, both dynamic and fixed size (vectors).

https://github.com/JoseRoca/AfxNova/blob/main/docs/COM%20/DSAFEARRAY%20Class.md
#65
José Roca Software / Re: CDicObj
Last post by Richard Kelly - May 05, 2026, 12:52:54 AM
Quote from: José Roca on May 03, 2026, 06:40:57 PMI have DWstrList and DVarList:

https://github.com/JoseRoca/AfxNova/blob/main/docs/String%20Management%20/Linked%20Lists.md



PB supports:

ILinkListCollection.ADD method adds am item to the end of the LinkListCollection.
ILinkListCollection.CLEAR method removes all items from the LinkListCollection.
ILinkListCollection.COUNT method returns the number of items currently in the LinkListCollection.
ILinkListCollection.FIRST method sets the current index for the LinkListCollection to one (1) and returns the previous value.
ILinkListCollection.INDEX method sets the current index for the LinkListCollection to the specified value and returns the previous value.
ILinkListCollection.INSERT method adds the specified item to the specified index position..
ILinkListCollection.ITEM method returns the item from the specified index position.
ILinkListCollection.LAST method sets the index value to the last item and returns the previous value.
ILinkListCollection.NEXT method returns the next item in the LinkListCollection.
ILinkListCollection.PREVIOUS method returns the previous item in the LinkListCollection.
ILinkListCollection.REMOVE method removes the item at the specified position from the LinkListCollection.
ILinkListCollection.REPLACE method replaces the item at the specified position with a new item in the LinkListCollection.

This old PB code I'm looking at uses:

Count, Clear, Item, Replace, Add

I think I'll move forward with DVarList and DWStrList



#66
José Roca Software / Re: CDicObj
Last post by Richard Kelly - May 03, 2026, 11:21:20 PM
Thank you Jose. I'll certainly look into all of them as I progress with porting this PowerBasic project from 15 years ago.

I have the first piece done, a class that defines all the fonts. See attached.

Code I used to check it out...Got some sleeps in there so you have to press a key to get through it. I did that so I could see each section.

#cmdline "-s console"   ' console application
#DEFINE UNICODE
#DEFINE _WIN32_WINNT &h0602
#INCLUDE ONCE "crInc\cPDF\cPDFFonts.bi"
USING AfxNova

Type FontDescriptor
    FontName                As WSTRING * 30
    FontID                  As Long
    FontStyle               As Long
    FontReferenced          As Long
    FontAscent              As Long
    FontCapHeight           As Long
    FontDescent             As Long
    FontFlags               As Long
    FontRectLeft            As Long
    FontRectTop             As Long
    FontRectRight           As Long
    FontRectBottom          As Long
    FontItalicAngle         As Double
    FontStemV               As Long
    FontWeight              As Long
    FontUnderlineThickness  As Long
    FontUnderlinePosition   As Long
    FontObject              As Long
    FontWidthObject         As Long
    FontDescriptorObject    As Long
 End Type
 
DIM oPDFFonts  AS cPDFFonts
DIM sFontID    AS DWSTRING
DIM dvFont     AS DVARIANT
DIM sWidth     AS DWSTRING
DIM uDescriptor     AS FontDescriptor

print  "Total Defined Fonts=" + str(oPDFFonts.TotalFonts)
print ""
SLEEP
oPDFFonts.GetFont(1, sFontID, dvFont, sWidth)
dvFont.ToBuffer(@uDescriptor, SIZEOF(uDescriptor))
print "Font Descriptor"
print ""
print uDescriptor.FontName
print str(uDescriptor.FontID)
print str(uDescriptor.FontStyle)
print str(uDescriptor.FontReferenced)
print str(uDescriptor.FontAscent)
print str(uDescriptor.FontCapHeight)
print str(uDescriptor.FontDescent)
print str(uDescriptor.FontFlags)
print str(uDescriptor.FontRectLeft)
print str(uDescriptor.FontRectTop)
print str(uDescriptor.FontRectRight)
print str(uDescriptor.FontRectBottom)
print str(uDescriptor.FontItalicAngle)
print str(uDescriptor.FontStemV)
print str(uDescriptor.FontWeight)
print str(uDescriptor.FontUnderlineThickness)
print str(uDescriptor.FontUnderlinePosition)
SLEEP
print ""
print "Font Widths"
print ""
print sWidth
SLEEP

In case your curious about the comma delimited list of font widths, they will eventually get parsed out using AfxArrays and AfxStr with code like this:

DIM nStart          AS LONG = 1
DIM arWidths()   AS LONG
WHILE nStart < LEN(sWidthList)
       sWidth = AfxStrExtract(nStart,sWidthList,",",",")
       AppendElementToArray (arWidths, CLNG(sWidth))
       nStart = nStart + LEN(sWidth) + 1
   WEND
#67
José Roca Software / Re: CDicObj
Last post by José Roca - May 03, 2026, 07:05:27 PM
I also have stacks (CStack) and queues (CQueue):

See: https://github.com/JoseRoca/AfxNova/blob/main/docs/COM%20/Stacks%20and%20Queues.md

This completes the PowerCollection.
#69
José Roca Software / Re: CDicObj
Last post by Richard Kelly - May 03, 2026, 02:44:28 PM
Oh wow! Updated my code to follow your example and, of course, it works perfectly.

Type FontDescriptor
    FontName                As WSTRING * 30
    FontID                  As Long
    FontStyle               As Long
    FontReferenced          As Long
    FontAscent              As Long
    FontCapHeight           As Long
    FontDescent             As Long
    FontFlags               As Long
    FontRectLeft            As Long
    FontRectTop             As Long
    FontRectRight           As Long
    FontRectBottom          As Long
    FontItalicAngle         As Double
    FontStemV               As Long
    FontWeight              As Long
    FontUnderlineThickness  As Long
    FontUnderlinePosition   As Long
    FontObject              As Long
    FontWidthObject         As Long
    FontDescriptorObject    As Long
 End Type

DIM uDescriptor     AS FontDescriptor
DIM uDescriptor1    AS FontDescriptor
DIM oDicObj         AS CDicObj
DIM dv              AS DVARIANT
 
    uDescriptor.FontName = "Arial"
    uDescriptor.FontID = 1
    uDescriptor.FontStyle = 1
    uDescriptor.FontReferenced = 0
    uDescriptor.FontAscent = 905
    uDescriptor.FontCapHeight = 728
    uDescriptor.FontDescent = -210
    uDescriptor.FontFlags = 32
    uDescriptor.FontRectLeft = -666
    uDescriptor.FontRectTop = -210
    uDescriptor.FontRectRight = 2000
    uDescriptor.FontRectBottom = 728
    uDescriptor.FontItalicAngle = 0
    uDescriptor.FontStemV = 44
    uDescriptor.FontWeight = 400
    uDescriptor.FontUnderlineThickness = 73
    uDescriptor.FontUnderlinePosition = -106
   
    dv.PutBuffer(@uDescriptor, SIZEOF(uDescriptor))
    oDicObj.Add "F1", dv
    dv = oDicObj.Item("F1")
    dv.ToBuffer(@uDescriptor1, SIZEOF(uDescriptor1))
   
    print uDescriptor1.FontName
    print str(uDescriptor1.FontID)
    print str(uDescriptor1.FontStyle)
    print str(uDescriptor1.FontReferenced)
    print str(uDescriptor1.FontAscent)
    print str(uDescriptor1.FontCapHeight)
    print str(uDescriptor1.FontDescent)
    print str(uDescriptor1.FontFlags)
    print str(uDescriptor1.FontRectLeft)
    print str(uDescriptor1.FontRectTop)
    print str(uDescriptor1.FontRectRight)
    print str(uDescriptor1.FontRectBottom)
    print str(uDescriptor1.FontItalicAngle)
    print str(uDescriptor1.FontStemV)
    print str(uDescriptor1.FontWeight)
    print str(uDescriptor1.FontUnderlineThickness)
    print str(uDescriptor1.FontUnderlinePosition)

Time to figure out PB LinkListCollection
#70
José Roca Software / Re: CDicObj
Last post by José Roca - May 03, 2026, 07:50:57 AM
After thinking it over, this is the solution I've come up with. It stores the UDT as an array of unsigned bytes (a VT_ARRRAY OR VT_UI1 variant).. Works with ZSTRING too.

#cmdline "-s console"
#INCLUDE ONCE "AfxNova/CDicObj.inc"
USING AfxNova

TYPE Foo
  x AS long
  y as long
  b as WSTRING * 260
END type
 

' // Creates an instance of the CDicObj class
DIM pDic AS CDicObj

' // Creates an instance of the Foo type
DIM t AS Foo = (12345, 72727, "Test string")
' // Assigns it to a DVARIANT
DIM dv AS DVARIANT
dv.PutBuffer(@t, SIZEOF(t))
' // Adds the type to the dictionary
pDic.Add "Foo1", dv

' // Creates another instance of the Foo type
DIM t2 AS Foo = (111111, 22222, "Test string 2")
' // Assigns it to a DVARIANT
DIM dv2 AS DVARIANT
dv2.PutBuffer(@t2, SIZEOF(t2))
' // Adds the type to the dictionary
pDic.Add "Foo2", dv2

' // Gets Foo1 from the dictionary
DIM dvFoo1 AS DVARIANT
dvFoo1 = pDic.Item("Foo1")
' // Assigns it to a Foo structure
DIM tFoo1 AS Foo
dvFoo1.ToBuffer(@tFoo1, SIZEOF(tFoo1))
' // DIsplays the values
print tFoo1.x
print tFoo1.y
print tFoo1.b

' // Gets Foo2 from the dictionary
DIM dvFoo2 AS DVARIANT
dvFoo2 = pDic.Item("Foo2")
' // Assigns it to a Foo structure
DIM tFoo2 AS Foo
dvFoo2.ToBuffer(@tFoo2, SIZEOF(tFoo2))
' // DIsplays the values
print tFoo2.x
print tFoo2.y
print tFoo2.b

PRINT
PRINT "Press any key..."
SLEEP