VList: Difference between revisions

86,644 bytes added ,  3 months ago
m
→‎{{header|Wren}}: Changed to Wren S/H
m (→‎{{header|Perl 6}}: copy & paste on Windows, sigh)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(31 intermediate revisions by 12 users not shown)
Line 15:
The task is to demonstrate creation of a VList and how to perform the primary operations.
 
=={{header|Applesoft BASIC}}==
<syntaxhighlight lang="gwbasic"> 0 DEF FN CDR(X) = V(X):Q$ = CHR$ (34)
1 FOR A = 6 TO 1 STEP - 1:A$ = STR$ (A): PRINT "CONS "A$": ";: GOSUB 10: GOSUB 50: NEXT A
2 GOSUB 30: PRINT "LENGTH: "L
3 PRINT "CDR: ";:V = FN CDR(V): GOSUB 50
4 GOSUB 30: PRINT "LENGTH: "L
5 I = 3: PRINT "ITEM "I": ";: GOSUB 20: GOSUB 90:I = 8: PRINT "ITEM "I": ";: GOSUB 20: GOSUB 90
6 END
 
REM CONS given A$ return V
10 N = N + 1:V(N) = V:V$(N) = A$:V = N: RETURN
 
REM GET ITEM given I return A
20 FOR N = 1 TO I:A = V:V = V(V): NEXT N: PRINT MID$ ("",1,0 ^ V((A = 0) * 32767));: RETURN
 
REM GET LENGTH OF LIST given V return L
30 A = V: FOR L = 1 TO 1E9: IF V(A) THEN A = V(A): NEXT L
40 RETURN
 
REM PRINT STRUCTURE given V
50 C$ = "": FOR P = V TO 0 STEP 0: IF V THEN PRINT C$;: GOSUB 70:C$ = ", ":P = V(P): NEXT P
60 PRINT : RETURN
 
REM PRINT ELEMENT given P
70 IF P THEN PRINT Q$V$(P)Q$;: RETURN
80 PRINT "NULL";: RETURN
 
REM PRINT ELEMENT WITH NEWLINE given A
90 P = A: GOSUB 70: PRINT : RETURN</syntaxhighlight>
{{out}}
<pre>
CONS 6: "6"
CONS 5: "5", "6"
CONS 4: "4", "5", "6"
CONS 3: "3", "4", "5", "6"
CONS 2: "2", "3", "4", "5", "6"
CONS 1: "1", "2", "3", "4", "5", "6"
LENGTH: 6
CDR: "2", "3", "4", "5", "6"
LENGTH: 5
ITEM 3: "4"
ITEM 8:
?BAD SUBSCRIPT ERROR IN 20
</pre>
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
 
Line 138 ⟶ 182:
v_del(v);
return 0;
}</langsyntaxhighlight>
 
=={{header|C++}}==
{{trans|Go}}
<syntaxhighlight lang="c">
<lang c>
#include <iostream>
#include <vector>
Line 306 ⟶ 350:
return 0;
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 331 ⟶ 375:
[ 6 ]
 
</pre>
=={{header|Component Pascal}}==
BlackBox Component Builder
 
Two modules are provided - one for implementing and one for using VLists
<syntaxhighlight lang="oberon2">
MODULE RosettaVLists;
(** In 2002, Phil Bagwell published "Fast Functional Lists" which introduced VLists as alternatives to Functional Programming's
ubiquitous linked lists and described Visp (a dialect of Common Lisp) using VLists, but including a "foldr" function,
optimized to use VLists. VLists have the same properties as immutable functional linked lists (including full persistence); but,
unlike a linked list, with O(1) random access time. The VLists implemented here is based on section 2.1 of that article but has been
modified to retain the safety features of Component Pascal.
 
VLists are referenced through 2 fields: "base" and "offset". A third field "length" reduces the time to determine its length to O(1).
 
Methods provided for manipulating VLists are named after their corresponding Visp functions, but follow Component Pascal's case conventions. **)
 
TYPE
Element* = CHAR; (** "Element" could be defined as a generic type.
To demonstrate strings, it is defined as a character. **)
 
Accum* = ABSTRACT RECORD END; (** For use in "FoldR" **)
 
Out* = ABSTRACT RECORD END; (** For use in "Exp" **)
 
Link = RECORD base: Base; offset: INTEGER END;
 
Base = POINTER TO RECORD
link: Link;
lastUsed: INTEGER;
block: POINTER TO ARRAY OF Element
END;
 
List* = RECORD
link: Link;
length-: INTEGER (** the length of the list **)
END;
(* The field "length" (read-only outside this module) has been added to "List".
This reduces the time to determine the VList's length to O(1). *)
(* primary operation #4: the length of the VList. *)
 
VAR
nilBase: Base;
 
(** Used for processing an element in "FoldR" **)
PROCEDURE (VAR a: Accum) Do- (e: Element), NEW, ABSTRACT;
 
(** Process the elements of "l" in reverse **)
PROCEDURE (IN l: List) FoldR* (VAR a: Accum), NEW;
(* Uses only O(log n) storage for pointers *)
 
PROCEDURE Aux (IN k: Link; len: INTEGER);
VAR i: INTEGER;
BEGIN
IF len = 0 THEN RETURN END;
Aux(k.base.link, len - k.offset - 1);
FOR i := 0 TO k.offset DO
a.Do(k.base.block[i])
END
END Aux;
 
BEGIN
Aux(l.link, l.length)
END FoldR;
 
(** Returns the first element of "l". It is an error for "l" be empty. **)
PROCEDURE (IN l: List) Car* (): Element, NEW;
(* An indirect load via the list "link". *)
BEGIN
ASSERT(l.length > 0);
RETURN l.link.base.block[l.link.offset]
END Car;
 
(** Returns the "n"th element of "l". It is an error for "n" to be negative or at least
"l.length". **)
PROCEDURE (IN l: List) Nth* (n: INTEGER): Element, NEW;
(* primary operation #1 *)
VAR k: Link;
BEGIN
ASSERT(0 <= n); ASSERT(n < l.length);
k := l.link;
WHILE n > k.offset DO
DEC(n, k.offset + 1);
k := k.base.link
END;
RETURN k.base.block[k.offset - n]
END Nth;
 
PROCEDURE (b: Base) NewBlock (size: INTEGER; e: Element), NEW;
BEGIN
b.lastUsed := 0; NEW(b.block, size); b.block[0] := e
END NewBlock;
 
(** Prefix "e" to "l". **)
PROCEDURE (VAR l: List) Cons* (e: Element), NEW;
(* primary operation #2 *)
 
PROCEDURE NewBase (size: INTEGER);
VAR b: Base;
BEGIN
NEW(b); b.link := l.link; b.NewBlock(size, e);
l.link.base := b; l.link.offset := 0
END NewBase;
 
BEGIN
INC(l.length);
IF l.link.base = NIL THEN
ASSERT(l.length = 1); NewBase(1)
ELSIF l.link.offset + 1 = LEN(l.link.base.block) THEN
(* If there is no room in "block" then a new "Base", with its length doubled in
size, is added and the new entry made. *)
NewBase(2 * LEN(l.link.base.block))
ELSIF l.link.offset = l.link.base.lastUsed THEN
(* "offset" is compared with "lastUsed". If they are the same and there is still
room in "block", they are simply both incremented and the new entry made. *)
INC(l.link.offset); (* Increment "offset". *)
INC(l.link.base.lastUsed); (* Increment "lastUsed". *)
l.link.base.block[l.link.offset] := e (* New entry. *)
ELSIF l.link.base.block[l.link.offset + 1] = e THEN
(* If the next location happens to contain an element identical to the new element.
only "offset" is incremented *)
INC(l.link.offset) (* Increment "offset". *)
ELSE
(* If "offset" is less than "lastUsed", "Cons" is being applied to the tail of a
longer vlist. In this case a new "Base" must be allocated and its "link" set to the
tail contained in the original list with "offset" being set to the point in this tail
and the new entry made. The two lists now share a common tail, as would have
been the case with a linked list implementation. *)
NewBase(1)
END
END Cons;
 
(** Remove the first element of "l". Unlike Common Lisp it is an error for "l" be empty. **)
PROCEDURE (VAR l: List) Cdr* (), NEW;
(* primary operation #3 *)
(* Follow "link" to the next "Base" if "offset" of "link" is 0 else decrement
"offset" of "link" *)
BEGIN
ASSERT(l.length > 0); DEC(l.length);
IF l.link.offset = 0 THEN
l.link := l.link.base.link (* Follow "link" to the next "Base". *)
ELSE
DEC(l.link.offset) (* Decrement "offset" of "link". *)
END
END Cdr;
 
(** Remove the first "n" elements of "l". It is an error for "n" to be negative or at
least "l.length". Except for performance, equivalent to performing "n" "Cdr"s **)
PROCEDURE (VAR l: List) NthCdr* (n: INTEGER), NEW;
VAR k: Link;
BEGIN
ASSERT(0 <= n); ASSERT(n < l.length); DEC(l.length, n);
k := l.link;
WHILE n > k.offset DO
DEC(n, k.offset + 1);
k := k.base.link
END;
l.link.base := k.base; l.link.offset := k.offset - n;
END NthCdr;
(** initialise "l" to the empty list **)
PROCEDURE (VAR l: List) Init*, NEW;
BEGIN
l.link.base := nilBase; l.link.offset := -1;
l.length := 0
END Init;
 
(** Used for outputting in "Exp" **)
PROCEDURE (IN o: Out) Char- (e: Element), NEW, ABSTRACT;
 
(** "Expose" exposes the structure of "l" by outputting it, separating the blocks
with '┃' characters **)
PROCEDURE (IN l: List) Expose* (IN o: Out), NEW;
VAR k: Link; len, i: INTEGER;
BEGIN
k := l.link; len := l.length;
IF len = 0 THEN RETURN END;
LOOP
FOR i := k.offset TO 0 BY -1 DO
o.Char(k.base.block[i])
END;
DEC(len, k.offset+1);
IF len = 0 THEN RETURN END;
o.Char('┃');
k := k.base.link
END
END Expose;
 
BEGIN
NEW(nilBase); nilBase.NewBlock(1, '*')
END RosettaVLists.
</syntaxhighlight>
Interface extracted from implementation:
<syntaxhighlight lang="oberon2">
DEFINITION RosettaVLists;
 
TYPE
Accum = ABSTRACT RECORD
(VAR a: Accum) Do- (e: Element), NEW, ABSTRACT
END;
 
Element = CHAR;
 
List = RECORD
length-: INTEGER;
(IN l: List) Car (): Element, NEW;
(VAR l: List) Cdr, NEW;
(VAR l: List) Cons (e: Element), NEW;
(IN l: List) Expose (IN o: Out), NEW;
(IN l: List) FoldR (VAR a: Accum), NEW;
(VAR l: List) Init, NEW;
(IN l: List) Nth (n: INTEGER): Element, NEW;
(VAR l: List) NthCdr (n: INTEGER), NEW
END;
 
Out = ABSTRACT RECORD
(IN o: Out) Char- (e: Element), NEW, ABSTRACT
END;
 
END RosettaVLists.</syntaxhighlight>
Module that uses previous module:
<syntaxhighlight lang="oberon2">
MODULE RosettaVListsUse;
 
IMPORT Out, VLists := RosettaVLists;
 
TYPE
Char = VLists.Element;
String = VLists.List;
Log = RECORD (VLists.Out) END; (* Used for outputting in "Exp" *)
App = RECORD (VLists.Accum) s: String END;
 
(* Used for appending in "FoldR" *)
PROCEDURE (VAR a: App) Do (c: Char);
BEGIN
a.s.Cons(c)
END Do;
 
(* Uses "FoldR" to concatenate "f" onto "r". *)
PROCEDURE Append (IN f: String; VAR r: String);
VAR a: App;
BEGIN
a.s := r; f.FoldR(a); r := a.s
END Append;
 
(* Concatenate "f" onto "r". *)
PROCEDURE Prefix (f: ARRAY OF CHAR; VAR r: String);
VAR i: INTEGER;
BEGIN
FOR i := LEN(f$) - 1 TO 0 BY -1 DO r.Cons(f[i]) END
END Prefix;
 
PROCEDURE Output (s: String);
VAR i: INTEGER;
BEGIN
FOR i := 0 TO s.length - 1 DO Out.Char(s.Nth(i)) END;
END Output;
 
(* Used for outputting in "Expose" *)
PROCEDURE (IN o: Log) Char- (c: Char);
BEGIN
Out.Char(c)
END Char;
 
PROCEDURE Display (IN name: ARRAY OF CHAR; s: String);
VAR o: Log;
BEGIN
Out.String(name + ' = "'); Output(s);
Out.String('"; length = '); Out.Int(s.length, 0);
Out.String('; stored as "'); s.Expose(o); Out.Char('"');
Out.Ln
END Display;
 
PROCEDURE Use*; (* Examples to demonstrate persistence *)
VAR nu, no, e, d, b: String;
BEGIN
nu.Init; Prefix("numerator", nu); Display("nu", nu);
no := nu; Display("no", no);
no.NthCdr(5); Display("no", no);
Prefix("nomin", no); Display("no", no);
e := nu; e.Cons('e'); Display("e", e);
Display("no", no); Display("nu", nu);
d.Init; Prefix("data", d); Display("d", d);
b.Init; Prefix("base", b); Display("b", b);
Append(d, b); Display("d", d); Display("b", b);
END Use;
 
END RosettaVListsUse.
</syntaxhighlight>
Execute: ^Q RosettaVListsUse.Use
{{out}}
<pre>
nu = "numerator"; length = 9; stored as "nu┃mera┃to┃r"
no = "numerator"; length = 9; stored as "nu┃mera┃to┃r"
no = "ator"; length = 4; stored as "a┃to┃r"
no = "nominator"; length = 9; stored as "no┃mi┃n┃a┃to┃r"
e = "enumerator"; length = 10; stored as "enu┃mera┃to┃r"
no = "nominator"; length = 9; stored as "no┃mi┃n┃a┃to┃r"
nu = "numerator"; length = 9; stored as "nu┃mera┃to┃r"
d = "data"; length = 4; stored as "d┃at┃a"
b = "base"; length = 4; stored as "b┃as┃e"
d = "data"; length = 4; stored as "d┃at┃a"
b = "database"; length = 8; stored as "d┃atab┃as┃e"
</pre>
 
=={{header|D}}==
{{trans|C}}
<langsyntaxhighlight lang="d">import core.stdc.stdio: fprintf, stderr;
import core.stdc.stdlib: malloc, free, abort;
 
Line 470 ⟶ 817:
 
v.free;
}</langsyntaxhighlight>
{{out}}
<pre>v.length = 10
Line 493 ⟶ 840:
popHead: 1
popHead: 0</pre>
 
 
=={{header|FreeBASIC}}==
VList.inc
<syntaxhighlight lang="vbnet">'********************************************************************
' FBVLIST, Virtual ListBox custom control for FreeBasic
'********************************************************************
' Public Domain by Borje Hagsten, December 2000
'
' Modified for Freebasic by James Klutho
'--------------------------------------------------------------------
' VL_REFRESH - to refresh control with new array data
' wParam = Not used, should be 0.
' lParam = Not used, should be 0.
' Returns: Nothing, 0
' Example: SendMessage hWndCtrl, VLB_REFRESH, 0, 0
'--------------------------------------------------------------------
' VL_SIZEHANDLER - internal, for handling resizing and memory DC's etc.
' wParam = Not used, should be 0.
' lParam = Not used, should be 0.
' Returns: Nothing, 0
' Example: SendMessage hWndCtrl, VLB_SIZEHANDLER, 0, 0
'--------------------------------------------------------------------
' VL_GETSELECTED - returns selected line number ((array item)
' wParam = not used, should be 0.
' lParam = not used, should be 0.
' Returns: Index of selected line.
' Example: index = SendMessage(hWndCtrl, VLB_GETSELECTED, 0, 0)
'--------------------------------------------------------------------
' VL_SETSELECTED - sets selected line number ((array item)
' wParam = Line to select.
' lParam = Redraw flag. TRUE to redraw, FALSE to ignore
' Returns: Index of selected line, or -1 if no selection could be made.
' Example: index = SendMessage(hWndCtrl, VLB_SETSELECTED, SelectLine, TRUE)
'--------------------------------------------------------------------
' VL_GETTOPLINE - returns first visible line in control
' wParam = not used, should be 0.
' lParam = not used, should be 0.
' Returns: Index of control's top (first visible) line.
' Example: index = SendMessage(hWndCtrl, VLB_GETTOPLINE, 0, 0)
'--------------------------------------------------------------------
' VL_SETTOPLINE - sets first visible line in control
' wParam = Line to show as top (first visible) line.
' lParam = Redraw flag. TRUE to redraw, FALSE to ignore
' Returns: Index of top line, or -1 if no items are available.
' Example: index = SendMessage(hWndCtrl, VLB_SETTOPLINE, TopLine, TRUE)
'--------------------------------------------------------------------
' VLN_RETURN
' Notification sent to parent's WM_COMMAND when Enter key has been pressed
'--------------------------------------------------------------------
' VLN_SPACE
' Notification sent to parent's WM_COMMAND when Space bar has been pressed
'--------------------------------------------------------------------
' VLN_DELETE
' Notification sent to parent's WM_COMMAND when Delete key has been pressed
 
'********************************************************************
' Declares
'********************************************************************
 
Declare Sub SetSBar(Myhwnd As HWND, Byval vhPage As Long, Byval vhMax As Long, Byval vhPos As Long, Byval vhBar As Long)
 
'VList messages and Notifications
#define VL_SETARRAY WM_USER + 1
#define VL_REFRESH WM_USER + 2
#define VL_GETSELECTED WM_USER + 3
#define VL_SETSELECTED WM_USER + 4
#define VL_GETTOPLINE WM_USER + 5
#define VL_SETTOPLINE WM_USER + 6
#define VL_SIZEHANDLER WM_USER + 7
#define VL_GETCURSEL WM_USER + 8
#define VL_SETCURSEL WM_USER + 9
 
#define VLN_RETURN WM_USER + 200
#define VLN_SPACE WM_USER + 201
#define VLN_DELETE WM_USER + 202
 
#define FBVLISTSTYLES WS_VISIBLE OR WS_CHILD OR WS_VSCROLL OR WS_TABSTOP OR WS_DLGFRAME OR WS_HSCROLL
 
#define VL_WSTRINGLEN 50 'Change to any desired fixed length Wstring you desire
#define USEWSTR 1 'Change to zero to use ANSI strings - non zero for Wstrings
 
Type MyNotify
NMHeader As NMHDR
Param1 As Long
Param2 As Long
Param3 As Long
Param4 As Long
End Type
 
Type vListData 'Type variable to hold private ListBox data
hParent As HWND 'Can be freely customized to meet extended needs
hInst As HINSTANCE
id As Long
cyChar As Long
wMaxHeight As Long
wFirstLine As Long
wLastLine As Long
tLineCount As Long
charWidth As Long
wMaxWidth As Long
iHscrollMax As Long
iHscrollPos As Long
xPos As Long
hBit As hGDIOBJ
memDC As hDC
SelLine As Long
hFont As hFont
st As String Ptr
ws As WSTRING Ptr
End Type
 
 
Function VLSendNotifyMessage(Byval hWnd As hWnd, Byval hCtrl As hWnd, Byval CtrlID As Long, Byval NCode As Long,Byval MyParam1 As Long, Byval MyParam2 As Long, Byval MyParam3 As Long, Byval MyParam4 As Long) As Long
Dim NMG As MyNotify
NMG.NMHeader.hwndFrom=hCtrl
NMG.NMHeader.idFrom=CtrlID
NMG.NMHeader.code=NCode
NMG.Param1=MyParam1
NMG.Param2=MyParam2
NMG.Param3=MyParam3
NMG.Param4=MyParam4
Return SendMessage(hWnd, WM_NOTIFY,Cast(wParam,CtrlID), Cast(lParam,Varptr(NMG)))
End Function
 
'********************************************************************
' Set Scroll bars
'********************************************************************
Sub SetSBar( myhwnd As HWND, Byval vhPage As Long, Byval vhMax As Long,Byval vhPos As Long, Byval vhBar As Long)
Dim si As SCROLLINFO
si.cbSize = Sizeof(si)
si.fMask = SIF_ALL Or SIF_DISABLENOSCROLL
si.nMin = 0
si.nMax = MAX(0, vhMax)
si.nPage = vhPage
si.nPos = vhPos
SetScrollInfo myhwnd, vhBar, @si, -1
End Sub
 
'********************************************************************
' Main control procedure
'********************************************************************
Function VL_Proc (hWnd As Hwnd, wMsg As UINT, _
wParam As WPARAM, lParam As LPARAM) As LRESULT
Dim tm As TEXTMETRIC, rc As RECT, wRect As RECT
Dim ps As PAINTSTRUCT,_
si As SCROLLINFO, lp As Point, _
hdc As hDC, hPen As hGDIOBJ, hBrush As hGDIOBJ, _
tSel As Long, bkBrush As hGDIOBJ, hBrushSel As hGDIOBJ, _
y As Long, i As Long, iVscrollInc As Long, hScrlInc As Long
Dim MyWStr As wstring * 50
'Note: v is declared as DIM, but stored globally via DIMAlloc and
' a pointer to the returned handle is stored in the extra bytes
' of the control's private window class (in cbWndExtra), so each
' control still can hold its own private data.
Dim v As VlistData Ptr
If wMsg <> WM_CREATE Then v = GetProp(hWnd,"VlistData")
Select Case wMsg
Case WM_CREATE 'Allocate storage for the vListData structure.
v = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Sizeof(VlistData))
'print v
If v Then
SetProp hWnd, "VlistData", Cast(HANDLE,v)
Else
MessageBox hWnd, "Could not allocate memory for Virtual Listbox" & Chr$(0), _
"FBLIST32 message" & Chr$(0), MB_OK
Function = -1 : Exit Function 'Return -1 to break the action
End If
v->hParent = GetParent(hWnd)
v->id = GetWindowLong(hWnd, GWL_ID)
v->hInst = Cast(hInstance, GetWindowLongPtr(hWnd, GWLP_HINSTANCE))
v->SelLine = -1 : v->tLineCount = -1
SendMessage hWnd, VL_SIZEHANDLER, 0, 0
Case WM_DESTROY
If v Then
If v->hbit Then DeleteObject SelectObject(v->memDC, v->hbit)
If v->memDC Then DeleteDC Cast(hDC, v->memDC)
HeapFree(GetProcessHeap(), 0, Byval v)
RemoveProp hWnd,"VlistData"
End If
Case WM_SETFONT
If wParam <> v->hFont Then
v->hFont = Cast(hFont, wParam)
SelectObject v->memDC, v->hFont
GetTextMetrics (v->memDC, @tm) 'Get font parameters
v->cyChar = tm.tmHeight + tm.tmExternalLeading 'Line spacing
v->charWidth = tm.tmAveCharWidth 'Average character width
GetWindowRect(hWnd, @wRect) 'Adjust height to avoid partial lines
v->wMaxHeight = (wRect.Bottom - wRect.Top) \ v->cyChar
v->wMaxWidth = MAX(1, ((wRect.Right - wRect.Left) / 2) / (v->charWidth - 1)) 'Get window size in characters
SetWindowPos hWnd, 0, 0, 0, wRect.Right - wRect.Left,v->wMaxHeight * v->cyChar + 4,SWP_NOMOVE Or SWP_NOZORDER
SendMessage hWnd, VL_SIZEHANDLER, 0, 0
End If
Case WM_SIZE
If Hiword(lParam) Then
v->wMaxHeight = Hiword(lParam) / v->cyChar
SendMessage hWnd, VL_SIZEHANDLER, 0, 0
End If
Case VL_SIZEHANDLER 'create a virtual window that fits current window size
If v->hbit Then DeleteObject SelectObject(v->memDC,v->hbit)
If v->memDC Then DeleteDC v->memDC
hDC = GetDC(hWnd)
GetClientRect(hWnd, @wRect)
v->memDC = CreateCompatibleDC(hDC)
v->hbit = CreateCompatibleBitmap(hDC, wRect.Right, wRect.Bottom)
v->hbit = SelectObject(v->memDC, v->hbit)
hbrush = GetStockObject( WHITE_BRUSH)
If hbrush Then SelectObject v->memDC, hbrush
If v->hFont = 0 Then v->hFont = GetStockObject(ANSI_VAR_FONT)
If v->hFont Then SelectObject v->memDC, v->hFont
PatBlt v->memDC, 0, 0, wRect.Right, wRect.Bottom, PATCOPY
GetTextMetrics (v->memDC, @tm) 'Get font parameters
v->cyChar = tm.tmHeight + tm.tmExternalLeading 'Line spacing
v->charWidth = tm.tmAveCharWidth 'Average character width
ReleaseDC (hWnd, hdc)
v->wMaxHeight = wRect.Bottom / v->cyChar
v->wMaxWidth = MAX(1, (wRect.Right / 2) / (v->charWidth - 1) ) 'Get window size in characters
v->iHscrollMax = MAX (0, 1024 - v->wMaxWidth) '1024, max number of characters..
v->iHscrollPos = MIN (v->iHscrollPos, v->iHscrollMax)
v->xPos = v->charWidth * (- v->iHscrollPos)
SetSBar hwnd, v->wMaxWidth, v->iHscrollMax, v->iHscrollPos, SB_HORZ
v->wMaxHeight = wRect.Bottom / v->cyChar
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case WM_VSCROLL
If v->tLineCount < 0 Then Exit Select
Select Case Loword(wParam)
Case SB_TOP : iVscrollInc = -v->wFirstLine
Case SB_BOTTOM : iVscrollInc = v->tLineCount - v->wMaxHeight
Case SB_LINEUP : iVscrollInc = -1
Case SB_LINEDOWN : If v->wFirstLine < v->tLineCount - v->wMaxHeight + 1 Then iVscrollInc = 1
Case SB_PAGEUP : iVscrollInc = MIN(-1, v->wMaxHeight)
Case SB_PAGEDOWN : iVscrollInc = MAX(1, v->wMaxHeight)
Case SB_THUMBTRACK ' getScrollInfo enables 32-bit scroll positions
si.cbSize = Sizeof(si)
si.fMask = SIF_TRACKPOS
GetScrollInfo hWnd, SB_VERT, @si
iVscrollInc = si.nTrackPos - v->wFirstLine
Case Else : iVscrollInc = 0
End Select
iVscrollInc = MAX(-v->wFirstLine, MIN(iVscrollInc, v->tLineCount - v->wMaxHeight + 1))
If iVscrollInc <> 0 And v->wFirstLine <= v->tLineCount - v->wMaxHeight + 1 Then
v->wFirstLine = MIN(v->wFirstLine + iVscrollInc, v->tLineCount - v->wMaxHeight + 1)
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
End If
Case WM_HSCROLL
Select Case Loword(wParam)
Case SB_LINELEFT : hScrlInc = -1
Case SB_LINERIGHT : hScrlInc = 1
Case SB_PAGELEFT : hScrlInc = -v->wMaxWidth
Case SB_PAGERIGHT : hScrlInc = v->wMaxWidth
Case SB_THUMBTRACK : hScrlInc = Hiword(wParam) - v->iHscrollPos
Case Else : hScrlInc = 0
End Select
hScrlInc = MAX(-v->iHscrollPos, MIN(hScrlInc, v->iHscrollMax - v->iHscrollPos))
If hScrlInc <> 0 Then
v->iHscrollPos = v->iHscrollPos + hScrlInc
v->xPos = v->charWidth * (- v->iHscrollPos)
SetSBar hwnd, v->wMaxWidth, v->iHscrollMax, v->iHscrollPos, SB_HORZ
InvalidateRect hwnd, Byval NULL, 0 : UpdateWindow hwnd
End If
Case WM_GETDLGCODE ' Ensure that the control processes all keys (except tab and escape) by itself
Dim iMsg As UINT, pMsg As TAGMSG Ptr
pMsg = Cast(TAGMSG Ptr, lParam)
If pMsg > 0 Then iMsg = pMsg->Message
If iMsg = WM_KEYDOWN Or iMsg = WM_CHAR Then
Select Case pMsg->wParam
Case VK_TAB, VK_ESCAPE 'let system handle these
Function = DefWindowProc(hWnd, wMsg, wParam, lParam)
Case Else
Function = DLGC_WANTALLKEYS
End Select
End If
Case WM_CHAR
#If(USEWSTR = 0)
' mimic standard listbox's search on keypress
For i = v->SelLine + 1 To v->tLineCount ' look for next item that starts like pressed key
If Ucase(Chr(wParam)) = Ucase(Chr(Asc(v->st[i]))) Then ' on success, set sel and exit
SendMessage hWnd, VL_SETCURSEL, i, 1
Exit Function
End If
Next
'if no success and SelLine is > first item, scan from array start to SelLine - 1
If v->SelLine > 0 Then
For i = 0 To v->SelLine - 1
If Ucase(Chr(wParam)) = Ucase(Chr(Asc(v->st[i]))) Then
SendMessage hWnd, VL_SETCURSEL, i, 1
Exit Function
End If
Next
End If
#Else
For i = v->SelLine + 1 To v->tLineCount ' look for next item that starts like pressed key
If Ucase(Chr(wParam)) = Ucase(Chr(Asc(v->ws[i * VL_WSTRINGLEN]))) Then ' on success, set sel and exit
SendMessage hWnd, VL_SETCURSEL, i, 1
Exit Function
End If
Next
'if no success and SelLine is > first item, scan from array start to SelLine - 1
If v->SelLine > 0 Then
For i = 0 To v->SelLine - 1
If Ucase(Chr(wParam)) = Ucase(Chr(Asc(v->ws[i * VL_WSTRINGLEN]))) Then
SendMessage hWnd, VL_SETCURSEL, i, 1
Exit Function
End If
Next
End If
#endif
Case WM_KEYDOWN
If v->tLineCount < 0 And wParam <> VK_TAB Then Exit Select
Select Case (wParam)
Case VK_UP, VK_LEFT
If v->SelLine = -1 Then v->SelLine = v->wFirstLine + 1
v->SelLine = MAX&(v->SelLine - 1, 0)
If v->SelLine < v->wFirstLine Or v->SelLine > v->wLastLine Then
v->wFirstLine = MIN&(v->SelLine, v->tLineCount - v->wMaxHeight + 1)
SetSBar hwnd, v->wMaxHeight, MAX&(0, v->tLineCount), v->wFirstLine, SB_VERT
End If
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VK_DOWN, VK_RIGHT
If v->SelLine = -1 Then v->SelLine = v->wFirstLine - 1
v->SelLine = MIN(v->SelLine + 1, v->tLineCount)
'print v->wMaxHeight
If v->SelLine > v->wLastLine Or v->SelLine < v->wFirstLine Then
v->wFirstLine = MIN(v->SelLine, v->tLineCount) - v->wMaxHeight + 1
'print v->wFirstLine
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
End If
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VK_PRIOR 'PgUp
If v->SelLine = v->wFirstLine Then
v->SelLine = MAX(v->SelLine - v->wMaxHeight + 1, 0)
Else
v->SelLine = v->wFirstLine
End If
If v->SelLine < v->wFirstLine + 1 Then
v->wFirstLine = v->SelLine
SetScrollPos (hWnd, SB_VERT, v->wFirstLine, TRUE)
End If
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VK_NEXT 'PgDn
If v->SelLine = v->wLastLine Then
v->SelLine = MIN(v->SelLine + v->wMaxHeight - 1, v->tLineCount)
Else
v->SelLine = v->wLastLine
End If
If v->SelLine > v->wLastLine Then
v->wFirstLine = MIN&(v->SelLine, v->tLineCount) - v->wMaxHeight + 1
SetScrollPos (hWnd, SB_VERT, v->wFirstLine, TRUE)
End If
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VK_SPACE 'Space bar pressed
VLSendNotifyMessage v->hParent,hWnd,v->id,VLN_SPACE,0,0,0,0
Case VK_RETURN 'Enter key pressed
VLSendNotifyMessage v->hParent,hWnd,v->id,VLN_RETURN,0,0,0,0
Case VK_DELETE 'Delete key pressed
VLSendNotifyMessage v->hParent,hWnd,v->id,VLN_DELETE,0,0,0,0
Case VK_HOME
v->SelLine = 0 : v->wFirstLine = 0
SetScrollPos (hWnd, SB_VERT, v->wFirstLine, TRUE)
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VK_END
v->SelLine = v->tLineCount
v->wFirstLine = v->tLineCount - v->wMaxHeight + 1
SetScrollPos (hWnd, SB_VERT, v->wFirstLine, TRUE)
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case Else
End Select
Case WM_MOUSEMOVE
If v->tLineCount < 0 Then Exit Select
If wParam = MK_LBUTTON Then
GetCursorPos @lp : GetWindowRect hWnd, @wRect
If lp.y < wRect.Top + 3 Then
tSel = v->wFirstLine - ((wRect.Top - lp.y) \ v->cyChar + 1)
Else
tSel = v->wFirstLine + Hiword(lParam) \ v->cyChar
End If
If tSel < 0 Then tSel = 0
If tSel > v->tLineCount Then tSel = v->tLineCount
If v->SelLine = tSel Then Exit Select 'no need to repeat ourselves..
If tSel > v->wLastLine Then v->wFirstLine = tSel - v->wMaxHeight + 1
If tSel < v->wFirstLine Then v->wFirstLine = tSel
v->SelLine = tSel
If v->tLineCount > v->wMaxHeight - 1 Then
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
End If
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
End If
Case WM_LBUTTONDBLCLK
If v->tLineCount < 0 Then Exit Select
v->SelLine = MAX(0, v->wFirstLine + Hiword(lParam) \ v->cyChar)
If v->SelLine <= v->tLineCount Then
SendMessage v->hParent, WM_COMMAND, MAKELONG(v->id, LBN_DBLCLK), Cast(lparam,hwnd)
End If
Case WM_LBUTTONDOWN
If v->tLineCount < 0 Then Exit Select
SetCapture hWnd
v->SelLine = v->wFirstLine + Hiword(lParam) \ v->cyChar
If v->SelLine < 0 Then v->SelLine = 0
If v->SelLine > v->tLineCount Then v->SelLine = v->tLineCount
SetFocus hWnd
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case WM_LBUTTONUP
If v->tLineCount < 0 Then Exit Select
ReleaseCapture
Case WM_KILLFOCUS, WM_SETFOCUS ' Must process these if line is selected
If v->SelLine > - 1 Then
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Else
GetClientRect hWnd, @wRect
rc.Left = 0 : rc.Top = 0 : rc.Right = wRect.Right : rc.Bottom = v->cyChar
hdc = GetDc(hWnd)
DrawFocusRect hDC, @rc
ReleaseDc hWnd, hdc
End If
If wMsg = WM_KILLFOCUS Then 'Send notifications to parent
SendMessage v->hParent, WM_COMMAND, MAKELONG(v->id, LBN_KILLFOCUS), Cast(lparam,hwnd)
Else
SendMessage v->hParent, WM_COMMAND, MAKELONG(v->id, LBN_SETFOCUS), Cast(lparam,hwnd)
End If
Case WM_PAINT 'Draw only the list items that needs to be shown
'Send WM_CTLCOLORLISTBOX to parent, to get eventual brush for bg color
bkBrush = Cast(hGDIOBJ,SendMessage(v->hParent, WM_CTLCOLORLISTBOX, Cast(wParam,v->memDC), Cast(lparam,hwnd)) )
If bkBrush Then SelectObject v->memDC, bkBrush
hdc = BeginPaint(hWnd, @ps)
GetClientRect(hWnd, @wRect)
v->wFirstLine = MAX(0, v->wFirstLine)
v->wLastLine = MIN(v->tLineCount, v->wFirstLine + v->wMaxHeight - 1)
PatBlt v->memDC, 0, 0, wRect.Right, wRect.Bottom, PATCOPY
If v->tLineCount > -1 Then ' DRAW TEXT (ARRAY)
For i = v->wFirstLine To v->wLastLine
y = v->cyChar * (-v->wFirstLine + i)
#If(USEWSTR = 0)
TabbedTextOut v->memDC, v->xPos, y,Byval Strptr(v->st[i]), Len(v->st[i]),0, Byval NULL, 0
#Else
MyWStr = v->ws[i * VL_WSTRINGLEN] '"Jimmy " + WSTR(i)
TabbedTextOutW v->memDC, v->xPos, y,Byval Varptr(MyWstr), Len(MyWStr),0, Byval NULL, 0
#endif
Next
End If
'DRAW SELECTION
If v->SelLine >= v->wFirstLine Then
If v->SelLine > v->tLineCount Then v->SelLine = v->tLineCount
rc.Left = 0 : rc.Top = v->cyChar * (v->SelLine - v->wFirstLine)
rc.Right = wRect.right : rc.Bottom = rc.Top + v->cyChar
'=== Draw Selection rectangle, plus focus rectangle ===
If GetFocus = hWnd Then
hBrushSel = GetSysColorBrush( COLOR_HIGHLIGHT)
Else
hBrushSel = GetSysColorBrush( COLOR_INACTIVECAPTION)
End If
hBrushSel = SelectObject(v->memDC, hBrushSel)
hPen = CreatePen( PS_DOT, 1, GetSysColor( COLOR_HIGHLIGHTTEXT))
hPen = SelectObject(v->memDC, hPen)
SetROP2(v->memDC, R2_MERGEPENNOT)
Rectangle(v->memDC, rc.Left - 1, rc.Top - 1, rc.Right + 1, rc.Bottom + 1)
If GetFocus() = hWnd Then DrawFocusRect(v->memDC, @rc)
SelectObject v->memDC, hBrushSel
DeleteObject SelectObject(v->memDC, hPen)
SendMessage v->hParent, WM_COMMAND, MAKELONG(v->id, LBN_SELCHANGE), Cast(lparam,hwnd)
Elseif v->SelLine = -1 And GetFocus = hWnd Then
rc.Left = 0 : rc.Top = 0 : rc.Right = wRect.right : rc.Bottom = v->cyChar
DrawFocusRect v->memDC, @rc
End If
BitBlt hDC, wRect.top, wRect.left, wRect.right, wRect.bottom, v->memDC, 0, 0, SRCCOPY
EndPaint(hWnd, @ps)
Case WM_ERASEBKGND 'Prevent erasing background
Function = 1
Case LB_SETHORIZONTALEXTENT
GetClientRect(hWnd, @wRect)
v->iHscrollMax = MAX (0, wParam - wRect.Right)
SetSBar hwnd, v->wMaxWidth, v->iHscrollMax, v->iHscrollPos, SB_HORZ
Case VL_SETARRAY
#If(USEWSTR = 0)
v->st = Cast(Any Ptr,wParam)
#Else
v->ws = Cast(Any Ptr,wParam)
#endif
v->SelLine = -1
v->tLineCount = lParam
v->wFirstLine = 0
Case VL_REFRESH
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Case VL_GETSELECTED
Function = v->SelLine
Case VL_GETCURSEL
Function = v->SelLine
Case VL_SETSELECTED
If wParam < 0 Then
v->SelLine = -1
Else
v->SelLine = MIN(wParam, v->tLineCount)
End If
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
If lParam Then 'Refresh control
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
End If
Function = v->SelLine
Case VL_SETCURSEL
If wParam < 0 Then
v->SelLine = -1
Else
v->SelLine = MIN(wParam, v->tLineCount)
If v->SelLine < v->wFirstLine Then
v->wFirstLine = v->SelLine
Elseif v->SelLine > v->wFirstLine + v->wMaxHeight - 1 Then
v->wFirstLine = MIN(v->SelLine - v->wMaxHeight + 1, v->tLineCount - v->wMaxHeight + 1)
End If
End If
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
Function = v->SelLine
Case VL_GETTOPLINE
Function = v->wFirstLine
Case VL_SETTOPLINE
If wParam < 0 Then
v->wFirstLine = 0
Else
v->wFirstLine = MIN(wParam, v->tLineCount - v->wMaxHeight + 1)
End If
SetSBar hwnd, v->wMaxHeight, MAX(0, v->tLineCount), v->wFirstLine, SB_VERT
If lParam Then 'Refresh control
InvalidateRect hWnd, Byval NULL, 0 : UpdateWindow hwnd
End If
Function = v->wFirstLine
Case Else ' Process all other messages
Function = DefWindowProc(hWnd, wMsg, wParam, lParam)
 
End Select
End Function
 
Sub VL_INT()
Dim wc As WNDCLASSEX
Dim As String szClassName = "FBVLIST"
If GetClassInfoEx(GetModuleHandle(Byval NULL), Strptr(szClassName), @wc) <> 0 Then
' 'It is already registered
Exit Sub
End If
wc.cbSize = Sizeof(wc)
wc.style = CS_DBLCLKS
wc.lpfnWndProc = @VL_Proc
wc.cbWndExtra = 4 '4 extra bytes for pointer to UDT
wc.hInstance = GetModuleHandle(Byval NULL)
wc.hCursor = LoadCursor(NULL, Byval IDC_ARROW)
wc.lpszClassName = Strptr(szClassName)
RegisterClassEx @wc
End Sub</syntaxhighlight>
 
Code test
<syntaxhighlight lang="vbnet">'Programmed for Freebasic by James Klutho
'--------------------------------------------------------------------
 
#include once "windows.bi"
#INCLUDE ONCE "VList.inc"
 
Dim Shared hVList1 As hwnd
Dim Shared hLBox As hwnd
Dim Shared hButExit As hwnd
Dim Shared hButChange As hwnd
 
 
Const IDC_VLIST = 101
Const IDC_LBOX = 102
Const IDC_MYEXIT = 103
Const IDC_MYCHANGE = 104
 
'To switch between ANSI and Wstrings, make these changes in the VList.inc file
 
'define VL_WSTRINGLEN 50 'Change to any desired fixed length Wstring you desire
'define USEWSTR 1 'Change to zero to use dynamic ANSI strings
 
Dim Shared ss(50) As String 'ANSI dynamic string
Dim Shared ww(50) As Wstring * VL_WSTRINGLEN 'Fixed length Wstring
 
 
Sub AddNote(hMyLBox As hwnd, s As String)
Dim MyMsg As ZString * 256
Static COUNT As Long
Dim s5 As zSTRING * 5
COUNT = COUNT +1
s5 = Str(COUNT)
MyMsg="Notification # "& s5 & ":" & s
SendMessage(hMyLBox,LB_INSERTSTRING,0,Cast(lparam,Varptr(MyMsg)))
End Sub
 
Declare Function WinMain (Byval hInstance As HINSTANCE, _
Byval hPrevInstance As HINSTANCE, _
Byval szCmdLine As zstring Ptr, _
Byval iCmdShow As Integer) As Integer
End WinMain(GetModuleHandle(null), null, Command(), SW_NORMAL)
 
'':::::
Function WndProc (Byval hWnd As HWND, Byval wMsg As UINT, _
Byval wParam As WPARAM, Byval lParam As LPARAM) As LRESULT
Dim MyNptr As MyNotify Ptr
Function = 0
Select Case(wMsg)
Case WM_CREATE
Exit Function
Case WM_COMMAND
If GETFOCUS = hVList1 Then Exit Function
Select Case Loword(wParam)
Case IDC_MYEXIT
' // close the application sending an WM_CLOSE message
If Hiword(wParam) = BN_CLICKED Then
SendMessageW hwnd, WM_CLOSE, 0, 0
Exit Function
End If
Case IDC_MYCHANGE
' // Display the message
If Hiword(wParam) = BN_CLICKED Then
#If(USEWSTR = 0)
ss(10) = "Changed"
#Else
ww(10) = "Changed"
#endif
SendMessageW hVList1, VL_REFRESH, 0, 0
End If
End Select
Case WM_NOTIFY
MyNptr = Cast(MyNotify Ptr,lParam)
If MyNptr->NMHeader.idFrom = IDC_VLIST Then
Select Case MyNptr->NMHeader.code
Case VLN_RETURN
AddNote hLBox, "RETURN "
Case VLN_SPACE
AddNote hLBox, "SPACE "
Case VLN_DELETE
AddNote hLBox, "DELETE "
End Select
End If
Case WM_PAINT
Dim rct As RECT
Dim pnt As PAINTSTRUCT
Dim hDC As HDC
hDC = BeginPaint(hWnd, @pnt)
EndPaint(hWnd, @pnt)
Exit Function
Case WM_KEYDOWN
Case WM_DESTROY
PostQuitMessage(0)
Exit Function
End Select
Function = DefWindowProc(hWnd, wMsg, wParam, lParam)
End Function
 
'':::::
Function WinMain (Byval hInstance As HINSTANCE, _
Byval hPrevInstance As HINSTANCE, _
Byval szCmdLine As zstring Ptr, _
Byval iCmdShow As Integer) As Integer
Dim wMsg As MSG
Dim wcls As WNDCLASS
Dim hWnd As HWND
Dim x As Long
Function = 0
With wcls
.style = CS_HREDRAW Or CS_VREDRAW
.lpfnWndProc = @WndProc
.cbClsExtra = 0
.cbWndExtra = 0
.hInstance = hInstance
.hIcon = LoadIcon(NULL, IDI_APPLICATION)
.hCursor = LoadCursor(NULL, IDC_ARROW)
.hbrBackground = GetStockObject(WHITE_BRUSH)
.lpszMenuName = NULL
.lpszClassName = @"FBListTest"
End With
If(RegisterClass(@wcls) = FALSE) Then
MessageBox(null, "Failed to register wcls", "Error", MB_ICONERROR)
Exit Function
End If
hWnd = CreateWindowEx(0, _
@"FBListTest", _
"The Hello Program", _
WS_OVERLAPPEDWINDOW, _
4, 4, 500, 500, _
NULL, _
NULL, _
hInstance, _
NULL)
VL_Int
hVList1 = CreateWindow ("FBVLIST",_ 'window class name
Byval NULL,_ 'window caption
FBVLISTSTYLES,_ 'window style
4,4,300,300,_ 'initial Position
hWnd,_ 'parent window handle
Cast(hMENU,IDC_VLIST),_ 'window menu handle
hInstance,_ 'program instance handle
Byval NULL)
hLBox = CreateWindow ("listbox",_ 'window class name
Byval NULL,_ 'window caption
LBS_NOTIFY Or WS_CHILDWINDOW Or WS_BORDER Or WS_VSCROLL Or WS_VISIBLE, _
4,_ 'initial x position
325,_ 'initial y position
480,_ 'initial x size
100,_ 'initial y
HWND,_ 'parent window handle
Cast(hMENU,IDC_LBOX),_
hInstance,_ 'program instance handle
Byval NULL)
hButExit = CreateWindow ("button",_ 'window class name
"Exit",_ 'window caption
WS_CHILDWINDOW Or WS_BORDER Or WS_VISIBLE, _
325,_ 'initial x position
50,_ 'initial y position
50,_ 'initial x size
30,_ 'initial y
HWND,_ 'parent window handle
Cast(hMENU,IDC_MYEXIT),_
hInstance,_ 'program instance handle
Byval NULL)
hButChange = CreateWindow ("button",_ 'window class name
"Change",_ 'window caption
WS_CHILDWINDOW Or WS_BORDER Or WS_VISIBLE, _
325,_ 'initial x position
125,_ 'initial y position
75,_ 'initial x size
30,_ 'initial y
HWND,_ 'parent window handle
Cast(hMENU,IDC_MYCHANGE),_
hInstance,_ 'program instance handle
Byval NULL)
SendMessage hVList1,WM_SETFONT,Cast(wParam,GetStockObject(SYSTEM_FIXED_FONT)),MAKELONG(TRUE,0)
AddNote hLBox,"Ready"
For x = Lbound(ww) To Ubound(ww)
ww(x) = "FreeBasic Wide String " & Wstr(x)
Next x
For x = Lbound(ss) To Ubound(ss)
ss(x) = "FreeBasic " & Str(x)
Next x
#If(USEWSTR = 0)
SendMessage hVList1,VL_SETARRAY,Cast(wparam,Varptr(ss(0))),Cast(lparam,Ubound(ss))
#Else
SendMessage hVList1,VL_SETARRAY,Cast(wparam,Varptr(ww(0))),Cast(lparam,Ubound(ww))
#endif
SendMessage hVList1,VL_REFRESH,0,0
ShowWindow(hWnd, iCmdShow)
UpdateWindow(hWnd)
While(GetMessage(@wMsg, NULL, 0, 0) <> FALSE)
TranslateMessage(@wMsg)
DispatchMessage(@wMsg)
Wend
Function = wMsg.wParam
End Function</syntaxhighlight>
 
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 618 ⟶ 1,830:
fmt.Println("show cdr releasing segment. 2 elements removed:", v)
v.printStructure()
}</langsyntaxhighlight>
{{out}}
<pre>
Line 649 ⟶ 1,861:
{{omit from|Openscad}}
{{omit from|Tcl|You wouldn't do such a low-level data structure directly in Tcl normally}}
 
=={{header|J}}==
 
A vlist preallocates storage in increasing powers of 2. The "head" of the vlist is in the last (largest) storage block. Here we define a class with methods <code>unshift</code> (which adds to the "head" of the vlist), <code>shift</code> (which removes from the "head" of the vlist), <code>size</code> (which tells us how many elements the vlist currently contains), and <code>get</code> (which retrieves the nth element from the vlist):
 
<syntaxhighlight lang="j">coclass 'vlist'
 
off=: 0
lastsz=: 1
(current=: 'b1')=: 0
 
size=: {{ lastsz+off-1 }}
 
get=: {{
assert. y>:0 ['negative index not supported'
assert. y<size 'index too large'
bi=. #:y+1 NB. work with binary representation of origin 1 index
b=. #.(#bi){.1 NB. most significant bit (the reason for origin 1)
i=. #.}.bi NB. rest of index
i{do 'b',":b
}}"0
 
unshift=: {{
(current)=: y off} do current
off=: 1+off
if. off=lastsz do.
off=: 0
lastsz=: 2*lastsz
current=: 'b',":lastsz
(current)=: lastsz#0
end.
y
}}"0
 
shift=: {{
assert. 0<size 'vlist empty'
off=: off-1
if. 0>off do.
erase current
lastsz=: <.-:lastsz
off=: lastsz-1
current=: 'b',":lastsz
end.
r=. off{do current
}}</syntaxhighlight>
 
Example use:
 
<syntaxhighlight lang="j"> L=: conew'vlist'
size__L''
0
unshift__L 100
100
unshift__L 200 303 404 555
200 303 404 555
size__L''
5
get__L 0 1 2
100 200 303
shift__L''
555
size__L''
4</syntaxhighlight>
 
Caution: this is an accurate model of the vlist data structure but should not be used if performance is critical.
 
If performance is critical use J's native operations and make sure that there's only the named reference to the list when adding or removing the last item from the list. For example, given <code>L=:100 200 303 404</code>, use <code>L=: L,555</code> to append to the list, and and after using <code>{:L</code> to extract the final element from L, use <code>L=: }:L</code> to discard the final element from the list. (And, of course, <code>#L</code> will report the size of the list.) J's implementation uses techniques which are in some ways similar in character to vlists for these operations (but uses copy on write if there's other references to the list).
 
=={{header|Julia}}==
{{trans|Go}}
Benchmarking suggests that the `cons routine` as given is not truly O(1), perhaps because of allocations. Other VList methods
may well be O(1). In addition, benchmarking the native Vector or Array{Char, 1} type shows this to be superior in every timing
benchmark over the VList implementation, except for the copy from second element, and that copy is only slower because of the
time for making such a copy. Importantly, Julia has a `view` macro which is a similar copy-saving trick to that used by VList,
only much faster, and also O(1). So, from the linked list form available to me, it seems use of VList may primarily be for
languages with slower arrays.
 
<syntaxhighlight lang="ruby">""" Rosetta Code task rosettacode.org/wiki/VList """
 
import Base.length, Base.string
 
using BenchmarkTools
 
abstract type VNode end
 
struct VNil <: VNode end
const nil = VNil()
 
mutable struct VSeg{T} <: VNode
next::VNode
ele::Vector{T}
end
 
mutable struct VList
base::VNode
offset::Int
VList(b = nil, o = 0) = new(b, o)
end
 
""" primary operation 1: locate the kth element. """
function index(v, i)
i < 0 && error("index out of range")
i += v.offset
sg = v.base
while sg !== nil
i < length(sg.ele) && return sg.ele[i + 1]
i -= length(sg.ele)
sg = sg.next
end
end
 
""" primary operation 2: add an element to the front of the VList. """
function cons(v::VList, a)
v.base === nil && return VList(VSeg(nil, [a]), 0)
if v.offset == 0
newlen = length(v.base.ele) * 2
ele = Vector{typeof(a)}(undef, newlen)
ele[newlen] = a
return VList(VSeg(v.base, ele), newlen - 1)
end
v.base.ele[v.offset] = a
v.offset -= 1
return v
end
 
""" primary operation 3: obtain new array beginning at second element of old array """
function cdr(v)
v.base === nil && error("cdr on empty VList")
v.offset += 1
return v.offset < length(v.base.ele) ? v : VList(v.base.next, 0)
end
 
""" primary operation 4: compute the length of the list. (It's O(1).) """
Base.length(v::VList) = (v.base === nil) ? 0 : length(v.base.ele) * 2 - v.offset - 1
 
""" A handy method: satisfy string interface for easy output. """
function Base.string(v::VList)
v.base === nil && return "[]"
r = "[" * string(v.base.ele[v.offset+1])
sg, sl = v.base, v.base.ele[v.offset+2:end]
while true
r *= " " * join(sl, " ")
sg = sg.next
sg === nil && break
sl = sg.ele
end
return r * "]"
end
 
""" Basic print for VList """
Base.print(io::IO, v::VList) = print(io, string(v))
 
""" One more method for demonstration purposes """
function print_structure(v::VList)
println("offset: ", v.offset)
sg = v.base
while sg !== nil
println(" $(sg.ele)") # illustrates the string type
sg = sg.next
end
println()
end
 
""" demonstration program using the WP example data """
function testVList()
v = VList()
println("zero value for type. empty VList: $v")
print_structure(v)
 
for a in '6':-1:'1'
v = cons(v, a)
end
println("demonstrate cons. 6 elements added: $v")
print_structure(v)
 
v = cdr(v)
println("demonstrate cdr. 1 element removed: $v")
print_structure(v)
 
println("demonstrate length. length = ", length(v), "\n")
 
println("demonstrate element access. v[3] = ", index(v, 3), "\n")
 
v = v |> cdr |> cdr
println("show cdr releasing segment. 2 elements removed: $v")
print_structure(v)
 
# Timings for n = 10, 100, 1000, 1000 sized structures
 
for i in 1:4
v = VList()
c = Char[]
for a in 10^i:-1:1
v = cons(v, a)
push!(c, a)
end
println("Testing index for VList of size ", 10^i)
arr = rand(1:10^i-1, 100)
@btime let
n = 0
for k in $arr
n = index($v, k)
end
end
println("Testing index for vector of size ", 10^i)
@btime let n = 0
for k in $arr
n = $c[k]
end
end
println("Testing adding an element for VList of size ", 10^i)
@btime let n = cons($v, 0) end
println("Testing adding an element for vector of size ", 10^i)
@btime let n = push!($c, '\0') end
 
println("Testing new array beginning at second element for VList of size ", 10^i)
@btime let m = cdr($v) end
println("Testing new vector with copy beginning at second element for vector of size ", 10^i)
@btime let m = popfirst!(copy($c)) end
println("Testing new vector using a view beginning at second element for vector of size ", 10^i)
@btime let m = @view $c[2:end] end
 
println("Testing length for VList of size ", 10^i)
@btime let n = length($v) end
println("Testing length for vector of size ", 10^i)
@btime let n = length($c) end
end
end
 
testVList()
</syntaxhighlight>{{out}}
<pre>
zero value for type. empty VList: []
offset: 0
 
demonstrate cons. 6 elements added: [1 2 3 4 5 6]
offset: 1
['\x0b\x54\x2e\xa0', '1', '2', '3']
['4', '5']
['6']
 
demonstrate cdr. 1 element removed: [2 3 4 5 6]
offset: 2
['\x0b\x54\x2e\xa0', '1', '2', '3']
['4', '5']
['6']
 
demonstrate length. length = 5
 
demonstrate element access. v[3] = 5
 
show cdr releasing segment. 2 elements removed: [4 5 6]
offset: 0
['4', '5']
['6']
 
Testing index for VList of size 10
28.100 μs (0 allocations: 0 bytes)
Testing index for vector of size 10
49.141 ns (0 allocations: 0 bytes)
Testing adding an element for VList of size 10
457.839 ns (3 allocations: 256 bytes)
Testing adding an element for vector of size 10
6.600 ns (0 allocations: 0 bytes)
Testing new array beginning at second element for VList of size 10
199.470 ns (2 allocations: 48 bytes)
Testing new vector with copy beginning at second element for vector of size 10
6.738 ms (2 allocations: 40.06 MiB)
Testing new vector using a view beginning at second element for vector of size 10
2.700 ns (0 allocations: 0 bytes)
Testing length for VList of size 10
99.576 ns (3 allocations: 48 bytes)
Testing length for vector of size 10
2.200 ns (0 allocations: 0 bytes)
Testing index for VList of size 100
26.200 μs (0 allocations: 0 bytes)
Testing index for vector of size 100
49.091 ns (0 allocations: 0 bytes)
Testing adding an element for VList of size 100
476.596 ns (3 allocations: 1.12 KiB)
Testing adding an element for vector of size 100
6.700 ns (0 allocations: 0 bytes)
Testing new array beginning at second element for VList of size 100
200.000 ns (2 allocations: 48 bytes)
Testing new vector with copy beginning at second element for vector of size 100
6.851 ms (2 allocations: 40.06 MiB)
Testing new vector using a view beginning at second element for vector of size 100
2.700 ns (0 allocations: 0 bytes)
Testing length for VList of size 100
100.530 ns (3 allocations: 48 bytes)
Testing length for vector of size 100
2.200 ns (0 allocations: 0 bytes)
Testing index for VList of size 1000
27.800 μs (245 allocations: 3.83 KiB)
Testing index for vector of size 1000
49.144 ns (0 allocations: 0 bytes)
Testing adding an element for VList of size 1000
648.436 ns (6 allocations: 8.23 KiB)
Testing adding an element for vector of size 1000
8.600 ns (0 allocations: 0 bytes)
Testing new array beginning at second element for VList of size 1000
205.900 ns (3 allocations: 64 bytes)
Testing new vector with copy beginning at second element for vector of size 1000
6.769 ms (2 allocations: 40.06 MiB)
Testing new vector using a view beginning at second element for vector of size 1000
2.700 ns (0 allocations: 0 bytes)
Testing length for VList of size 1000
109.892 ns (5 allocations: 80 bytes)
Testing length for vector of size 1000
2.300 ns (0 allocations: 0 bytes)
Testing index for VList of size 10000
33.600 μs (716 allocations: 11.19 KiB)
Testing index for vector of size 10000
49.190 ns (0 allocations: 0 bytes)
Testing adding an element for VList of size 10000
1.954 μs (7 allocations: 128.16 KiB)
Testing adding an element for vector of size 10000
6.700 ns (0 allocations: 0 bytes)
Testing new array beginning at second element for VList of size 10000
205.612 ns (3 allocations: 64 bytes)
Testing new vector with copy beginning at second element for vector of size 10000
6.876 ms (2 allocations: 40.09 MiB)
Testing new vector using a view beginning at second element for vector of size 10000
2.700 ns (0 allocations: 0 bytes)
Testing length for VList of size 10000
109.903 ns (5 allocations: 80 bytes)
Testing length for vector of size 10000
2.200 ns (0 allocations: 0 bytes)
</pre>
 
=={{header|Kotlin}}==
{{trans|Go}}
<langsyntaxhighlight lang="scala">// version 1.1.3
 
class VList<T : Any?> {
Line 767 ⟶ 2,308:
println("Demonstrating cdr method again, 2 more elements removed: $v")
v.printStructure()
}</langsyntaxhighlight>
 
{{out}}
Line 794 ⟶ 2,335:
[4, 5]
[6]
</pre>
 
=={{header|Nim}}==
{{trans|Go}}
<syntaxhighlight lang="nim">type
 
VSeg[T] = ref object
next: VSeg[T]
elems: seq[T]
 
VList[T] = ref object
base: VSeg[T]
offset: int
 
 
func newVList[T](): VList[T] = new(VList[T])
 
 
func `[]`[T](v: VList[T]; k: int): T =
## Primary operation 1: locate the kth element.
if k >= 0:
var i = k + v.offset
var sg = v.base
while not sg.isNil:
if i < sg.elems.len:
return sg.elems[i]
dec i, sg.elems.len
sg = sg.next
raise newException(IndexDefect, "index out of range; got " & $k)
 
 
func cons[T](v: VList[T]; a: T): VList[T] =
## Primary operation 2: add an element to the front of the VList.
if v.base.isNil:
return VList[T](base: VSeg[T](elems: @[a]))
 
if v.offset == 0:
let l2 = v.base.elems.len * 2
var elems = newSeq[T](l2)
elems[l2 - 1] = a
return VList[T](base: VSeg[T](next: v.base, elems: move(elems)), offset: l2 - 1)
 
dec v.offset
v.base.elems[v.offset] = a
result = v
 
 
func cdr[T](v: VList[T]): VList[T] =
## Primary operation 3: obtain a new array beginning at the second element of an old array.
if v.base.isNil:
raise newException(NilAccessDefect, "cdr on empty list")
 
if v.offset + 1 < v.base.elems.len:
inc v.offset
return v
result = VList[T](base: v.base.next, offset: 0)
 
 
func len[T](v: VList[T]): Natural =
## Primary operation 4: compute the length of the list.
if v.base.isNil: return 0
result = v.base.elems.len * 2 - v.offset - 1
 
 
func `$`[T](v: VList[T]): string =
if v.base.isNil: return "[]"
result = '[' & $v.base.elems[v.offset]
var sg = v.base
var sl = v.base.elems[v.offset+1..^1]
while true:
for e in sl: result.add ' ' & $e
sg = sg.next
if sg.isNil: break
sl = sg.elems
result.add ']'
 
 
proc printStructure[T](v: VList[T]) =
echo "offset: ", v.offset
var sg = v.base
while not sg.isNil:
echo " ", sg.elems
sg = sg.next
echo()
 
 
when isMainModule:
 
var v = newVList[string]()
 
echo "Zero value for type. Empty vList:", v
v.printStructure()
 
for a in countdown('6', '1'): v = v.cons($a)
echo "Demonstrate cons. Six elements added:", v
v.printStructure()
 
v = v.cdr()
echo "Demonstrate cdr. One element removed:", v
v.printStructure()
 
echo "Demonstrate length. Length = ", v.len()
echo()
 
echo "Demonstrate element access. v[3] = ", v[3]
echo()
 
v = v.cdr().cdr()
echo "Show cdr releasing segment. Two elements removed: ", v
v.printStructure()</syntaxhighlight>
 
{{out}}
<pre>Zero value for type. Empty vList:[]
offset: 0
 
Demonstrate cons. Six elements added:[1 2 3 4 5 6]
offset: 1
@["", "1", "2", "3"]
@["4", "5"]
@["6"]
 
Demonstrate cdr. One element removed:[2 3 4 5 6]
offset: 2
@["", "1", "2", "3"]
@["4", "5"]
@["6"]
 
Demonstrate length. Length = 5
 
Demonstrate element access. v[3] = 5
 
Show cdr releasing segment. Two elements removed: [4 5 6]
offset: 0
@["4", "5"]
@["6"]</pre>
 
=={{header|Objeck}}==
{{trans|Kotlin}}
 
<syntaxhighlight lang="objeck">class vList<T:Stringify> {
@base : vSeg<T>;
@offset : Int;
 
New() {}
 
New(base : vSeg<T>, offset : Int) {
@base := base;
@offset := offset;
}
 
New(base : vSeg<T>) {
@base := base;
}
 
method : public : GetBase() ~ vSeg<T> {
return @base;
}
 
method : public : GetOffset() ~ Int {
return @offset;
}
 
method : public : Cons(a : T) ~ vList<T> {
if(@base = Nil) {
return vList->New(vSeg->New(a)<T>)<T>;
}
else if(@offset = 0) {
l2 := @base->GetEle()->Size() * 2;
ele := T->New[l2];
ele[l2 - 1] := a;
return vList->New(vSeg->New(@base, ele)<T>, l2 - 1)<T>;
}
else {
@offset -= 1;
ele := @base->GetEle();
ele[@offset] := a;
return @self;
};
}
 
method : public : Cdr() ~ vList<T> {
if(@base = Nil) {
return Nil;
};
 
@offset += 1;
if(@offset < @base->GetEle()->Size()) {
return @self;
}
else {
return vList->New(@base->GetNext(), 0)<T>;
};
}
 
method : public : Index(i : Int) ~ T {
if(i >= 0) {
i += @offset;
for(sg := @base; sg <> Nil; sg := sg->GetNext();) {
ele := sg->GetEle();
if(i < ele->Size()) {
return ele[i];
};
i -= ele->Size();
};
};
 
return Nil;
}
 
method : public : Size() ~ Int {
if(@base = Nil) {
return 0;
};
 
return @base->GetEle()->Size() * 2 - @offset - 1;
}
 
method : public : ToString() ~ String {
if(@base = Nil) {
return "[]";
};
 
r := "[";
ele := @base->GetEle();
r += ele[@offset]->ToString();
r += ' ';
 
sg := @base;
offset := @offset + 1;
done := false;
while(<>done) {
for(i := offset; i < ele->Size(); i += 1;) {
r += ele[i]->ToString();
r += ' ';
};
 
sg := sg->GetNext();
if(sg <> Nil) {
ele := sg->GetEle();
offset := 0;
}
else {
done := true;
};
};
r += ']';
 
return r;
}
 
method : public : PrintStructure() ~ Nil {
offset := @offset;
" offset: {$offset}"->PrintLine();
for(sg := @base; sg <> Nil; sg := sg->GetNext();) {
values := sg->GetEle();
" ["->Print();
each(i : values) {
value := values[i];
if(value <> Nil) {
"{$value}"->Print();
}
else {
"{Nil}"->Print();
};
 
if(i + 1 < values->Size()) {
", "->Print();
};
};
"]"->PrintLine();
};
""->PrintLine();
}
}
class vSeg<T:Stringify> {
@next : vSeg<T>;
@ele : T[];
 
New(next : vSeg<T>, ele : T[]) {
@next := next;
@ele := ele;
}
 
New(s : T) {
@ele := T->New[1];
@ele[0] := s;
}
 
method : public : GetNext() ~ vSeg<T> {
return @next;
}
 
method : public : GetEle() ~ T[] {
return @ele;
}
}
 
class Test {
function : Main(args : String[]) ~ Nil {
v := vList->New()<String>;
"Zero value for type. empty vList: {$v}"->PrintLine();
v->PrintStructure();
 
for(a := '6'; a >= '1'; a -=1;) {
v := v->Cons("{$a}")<String>;
};
"Demonstrate cons. 6 elements added: {$v}"->PrintLine();
v->PrintStructure();
 
v := v->Cdr()<String>;
Runtime->Assert(v <> Nil);
"Demonstrate cdr. 1 element removed: {$v}"->PrintLine();
v->PrintStructure();
 
size := v->Size();
"Demonstrating size property, size = {$size}"->PrintLine();
 
e := v->Index(3);
Runtime->Assert(e <> Nil);
"Demonstrate element access. v[3] = {$e}"->PrintLine();
 
v := v->Cdr()->Cdr()<String>;
Runtime->Assert(v <> Nil);
"Demonstrate cdr. 2 elements removed: {$v}"->PrintLine();
v->PrintStructure();
}
}</syntaxhighlight>
 
{{output}}
<pre>
Zero value for type. empty vList: []
offset: 0
 
Demonstrate cons. 6 elements added: [1 2 3 4 5 6 ]
offset: 1
[{Nil}, 1, 2, 3]
[4, 5]
[6]
 
Demonstrate cdr. 1 element removed: [2 3 4 5 6 ]
offset: 2
[{Nil}, 1, 2, 3]
[4, 5]
[6]
 
Demonstrating size property, size = 5
Demonstrate element access. v[3] = 5
Demonstrate cdr. 2 elements removed: [4 5 6 ]
offset: 0
[4, 5]
[6]
</pre>
 
Line 799 ⟶ 2,696:
The ooRexx queue class is a vlist implementation.
Here are some examples of usage:
<syntaxhighlight lang="oorexx">
<lang ooRexx>
-- show how to use the queue class
q = .queue~of(1, 2, 3, 4)
Line 820 ⟶ 2,717:
say q[1] q[2] q[4]
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 829 ⟶ 2,726:
</pre>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- (first spare slot [0=none])</span>
<span style="color: #000000;">SEGMENTS</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">new_vlist</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,{}}</span> <span style="color: #000080;font-style:italic;">-- offset of 0, no segments</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">get_vlist</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- locate kth element</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">sg</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">vsg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">sg</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;"><=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vsg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">vsg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">-=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vsg</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">sg</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">throw</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"index out of range"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cons</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- add an element to the front of v</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">])=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">}}}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">offset</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])*</span><span style="color: #000000;">2</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">],</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">offset</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cdr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- remove first element of v</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">])=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">throw</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"cdr invoked on empty VList"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">offset</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">offset</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">vlist_size</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- compute the size of v</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">])=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])*</span><span style="color: #000000;">2</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">flatten</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">])[</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Offset: %d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">OFFSET</span><span style="color: #0000FF;">])</span>
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">[</span><span style="color: #000000;">SEGMENTS</span><span style="color: #0000FF;">],{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_vlist</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Before adding any elements, empty VList: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cons</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating cons method, 6 elements added: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cdr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating cdr method, 1 element removed: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating size property, size = %d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">vlist_size</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">))</span>
<span style="color: #000080;font-style:italic;">-- (note this is 1-based indexing)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating element access, v[3] = %d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">get_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cdr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cdr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cdr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)))</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating cdr method again, 3 more elements removed: %s, size = %d\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">),</span><span style="color: #000000;">vlist_size</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">=</span><span style="color: #000000;">7</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cons</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span> <span style="color: #000080;font-style:italic;">-- (this time not by -1; {9 8 7 5 6} is expected)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Demonstrating cons method, 3 more elements added: %s, size = %d\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">sprint_vlist</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">),</span><span style="color: #000000;">vlist_size</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">print_vlist_structure</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Before adding any elements, empty VList: ""
Offset: 0
{}
Demonstrating cons method, 6 elements added: {1,2,3,4,5,6}
Offset: 1
{{0,1,2,3},
{4,5},
{6}}
Demonstrating cdr method, 1 element removed: {2,3,4,5,6}
Offset: 2
{{0,1,2,3},
{4,5},
{6}}
Demonstrating size property, size = 5
Demonstrating element access, v[3] = 4
Demonstrating cdr method again, 3 more elements removed: {5,6}, size = 2
Offset: 1
{{4,5},
{6}}
Demonstrating cons method, 3 more elements added: {9,8,7,5,6}, size = 5
Offset: 2
{{0,0,9,8},
{7,5},
{6}}
</pre>
 
=={{header|Racket}}==
See https://github.com/takikawa/tr-pfds/blob/master/pfds/vlist.rkt
for an implementation of VLists.
 
=={{header|Raku}}==
(formerly Perl 6)
{{trans|Go}}
{{trans|Kotlin}}
<syntaxhighlight lang="raku" line>class vList {
<lang perl6>#!/usr/bin/env perl6
 
class vList {
 
subset vEle of Any; # or Str
Line 843 ⟶ 2,871:
}
 
has vSeg $.base is rw is default(vSeg.new(ele=>()));
has Int $.offset is rw is default(0) ;
 
submethod BUILD () { self.base = vSeg.new(ele=>()) } # default() this as well?
 
method Index(Int $i is copy --> vEle) { # method to locate the kth element
if $i ≥ 0 {
loop ( $i += self.offset, $_ = self.base; $_.defined; $_ := $_.next) {
loop ($i < my $_len = self.base;ele.elems) ?? return $_.defined;ele[$i] !! $_i :-= $_.next) {len
return .ele[$i] if $i < .ele.elems;
$i -= .ele.elems
}
}
Line 860 ⟶ 2,884:
 
method cons(vEle \a --> vList) { # method to add an element to the front
if not self.base.ele.elemsBool =={ 0 { # probably faster than .elems ?
self.base.ele.push: a ;
return self;
} elsif self.offset == 0 {
my \L2offset = (self.base.ele.elems * 2) - 1 ;
my \s = vSeg.new(next => self.base, ele => flat Nil xx L2offset, a);
return vList.new(base => s, offset => L2offset )
}
if self.base.ele[--self.offset] == 0 {a;
my \l2 = self.base.ele.elems * 2 ;
my vEle @ele = Nil xx l2 ;
@ele[l2-1] = a ;
my \v = vList.new;
my \s = vSeg.new;
s.next = self.base;
s.ele = @ele;
v.base = s;
v.offset = l2 - 1 ;
return v
}
self.offset--;
self.base.ele[self.offset] = a;
return self
}
Line 884 ⟶ 2,899:
method cdr(--> vList) {
die "cdr on empty vList" unless self.base.defined;
return self.offset if ++self.offset < self.base.ele.elems;
return self if selfvList.offsetnew(base <=> self.base.ele.elems;next)
my \v = vList.new();
v.base = self.base.next;
return v
}
 
Line 897 ⟶ 2,909:
 
method gist { # (mis)used to create output similar to Go/Kotlin
return '[]' unless self.base.definedele.Bool;
my $r@sl = "[" ~ self.base.ele[self.offset .. *]; # warning
myloop ($sg :_= self.base.next; $_.defined; $_:=$_.next) { @sl.append: .ele }
myreturn "[" ~ @sl := self.base.ele[self.offset+1Str ..~ *"];"
loop {
{ $r ~= " $_".Str } for @sl;
$sg := $sg.next;
last unless $sg.defined;
@sl := $sg.ele
}
return $r ~ "]"
}
 
Line 934 ⟶ 2,939:
$v := $v.cdr.cdr;
say "show cdr releasing segment. 2 elements removed: ", $v;
$v.printStructure;</langsyntaxhighlight>
{{out}}
<pre>zero value for type. empty vList: []
Line 961 ⟶ 2,966:
[6]
</pre>
 
=={{header|Phix}}==
<lang Phix>enum OFFSET, -- (first spare slot [0=none])
SEGMENTS
 
function new_vlist()
return {0,{}} -- offset of 0, no segments
end function
 
function get_vlist(sequence v, integer k)
-- locate kth element
if k>0 then
k += v[OFFSET]
integer sg = 1
while sg<=length(v[SEGMENTS]) do
sequence vsg = v[SEGMENTS][sg]
if k<= length(vsg) then return vsg[k] end if
k -= length(vsg)
sg += 1
end while
end if
throw("index out of range")
end function
function cons(sequence v, object a)
-- add an element to the front of v
if length(v[SEGMENTS])=0 then
return {0,{{a}}}
end if
integer offset = v[OFFSET]
if offset=0 then
offset = length(v[SEGMENTS][1])*2
v[SEGMENTS] = prepend(v[SEGMENTS],repeat(0,offset))
end if
v[SEGMENTS][1][offset] = a
v[OFFSET] = offset-1
return v
end function
function cdr(sequence v)
-- remove first element of v
if length(v[SEGMENTS])=0 then
throw("cdr invoked on empty VList")
end if
integer offset = v[OFFSET]+1
if offset>length(v[SEGMENTS][1]) then
v[SEGMENTS] = v[SEGMENTS][2..$]
v[OFFSET] = 1
else
v[OFFSET] = offset
end if
return v
end function
function vlist_size(sequence v)
-- compute the size of v
if length(v[SEGMENTS])=0 then return 0 end if
return length(v[SEGMENTS][1])*2 -v[OFFSET] -1
end function
 
function sprint_vlist(sequence v)
return sprint(flatten(v[SEGMENTS])[v[OFFSET]+1..$])
end function
 
procedure print_vlist_structure(sequence v)
printf(1,"Offset: %d\n",v[OFFSET])
pp(v[SEGMENTS],{pp_Nest,1})
end procedure
procedure main()
sequence v = new_vlist()
printf(1,"Before adding any elements, empty VList: %s\n",{sprint_vlist(v)})
print_vlist_structure(v)
for a=6 to 1 by -1 do v = cons(v,a) end for
printf(1,"Demonstrating cons method, 6 elements added: %s\n",{sprint_vlist(v)})
print_vlist_structure(v)
v = cdr(v)
printf(1,"Demonstrating cdr method, 1 element removed: %s\n",{sprint_vlist(v)})
print_vlist_structure(v)
printf(1,"Demonstrating size property, size = %d\n",vlist_size(v))
-- (note this is 1-based indexing)
printf(1,"Demonstrating element access, v[3] = %d\n",get_vlist(v,3))
v = cdr(cdr(cdr(v)))
printf(1,"Demonstrating cdr method again, 3 more elements removed: %s, size = %d\n",
{sprint_vlist(v),vlist_size(v)})
print_vlist_structure(v)
 
for a=7 to 9 do v = cons(v,a) end for -- (this time not by -1; {9 8 7 5 6} is expected)
printf(1,"Demonstrating cons method, 3 more elements added: %s, size = %d\n",
{sprint_vlist(v),vlist_size(v)})
print_vlist_structure(v)
 
end procedure
main()</lang>
{{out}}
<pre>
Before adding any elements, empty VList: ""
Offset: 0
{}
Demonstrating cons method, 6 elements added: {1,2,3,4,5,6}
Offset: 1
{{0,1,2,3},
{4,5},
{6}}
Demonstrating cdr method, 1 element removed: {2,3,4,5,6}
Offset: 2
{{0,1,2,3},
{4,5},
{6}}
Demonstrating size property, size = 5
Demonstrating element access, v[3] = 4
Demonstrating cdr method again, 3 more elements removed: {5,6}, size = 2
Offset: 1
{{4,5},
{6}}
Demonstrating cons method, 3 more elements added: {9,8,7,5,6}, size = 5
Offset: 2
{{0,0,9,8},
{7,5},
{6}}
</pre>
 
=={{header|Racket}}==
See https://github.com/takikawa/tr-pfds/blob/master/pfds/vlist.rkt
for an implementation of VLists.
 
=={{header|REXX}}==
Line 1,142 ⟶ 3,018:
║ used. I.E.: 63.01 63.5 63.63 63.9 ║
╚════════════════════════════════════════════════════════════════════╝
<langsyntaxhighlight lang="rexx">/*REXX program demonstrates VList operations: add, update, delete, insert, show. */
/*could use instead: q = 1 2 3 4 */
call q 0, 1 2 3 4 /*populate the list with values 1 ── ►4*/
Line 1,177 ⟶ 3,053:
if j==ni then $=$ ! /*handle the "insert". */
end /*j*/
q=space($); return q /*elide superfluous blanks. */</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 1,194 ⟶ 3,070:
The Scala implementation shares a common root with the Clojure implementation, but is certainly not a port of it.</blockquote>
A quote of Martin Odersky, his co-worker Phil Bagwell† invented the VList.
<langsyntaxhighlight Scalalang="scala">object VList extends App {
 
val emptyVlist1 = Vector.empty[Int]
Line 1,211 ⟶ 3,087:
assert(addedVlist1(3) == 10, "Wrong element accesed.")
println("Successfully completed without errors.")
}</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
<syntaxhighlight lang="wren">class VSeg_ {
construct new() {
_next = null
_ele = []
}
 
next { _next }
next=(n) { _next = n}
ele { _ele }
ele=(e) { _ele = e }
}
 
class VList {
construct new() {
_base = null
_offset = 0
}
 
base { _base }
base=(b) { _base = b}
offset { _offset }
offset=(o) { _offset = o }
 
/* locate kth element */
[k] {
var i = k
if (i >= 0) {
i = i + _offset
var sg = _base
while (sg) {
if (i < sg.ele.count) return sg.ele[i]
i = i - sg.ele.count
sg = sg.next
}
}
Fiber.abort("Index out of range.")
}
 
/* add an element to the front of VList */
cons(a) {
if (!_base) {
var v = VList.new()
var s = VSeg_.new()
s.ele = [a]
v.base = s
return v
}
if (_offset == 0) {
var l2 = _base.ele.count * 2
var ele = List.filled(l2, null)
ele[l2 - 1] = a
var v = VList.new()
var s = VSeg_.new()
s.next = _base
s.ele = ele
v.base = s
v.offset = l2 - 1
return v
}
_offset = _offset - 1
_base.ele[_offset] = a
return this
}
 
/* obtain a new VList beginning at the second element of an old VList */
cdr() {
if (!_base) Fiber.abort("cdr invoked on empty VList")
_offset = _offset + 1
if (offset < _base.ele.count) return this
var v = VList.new()
v.base = _base.next
return v
}
 
/* compute the size of the VList */
size {
if (!_base) return 0
return _base.ele.count * 2 - _offset - 1
}
 
toString {
if (!_base) return "[]"
var r = "[%(_base.ele[_offset])"
var sg = _base
var sl = _base.ele[_offset + 1..-1]
while (true) {
for (e in sl) r = r + " %(e)"
sg = sg.next
if (!sg) break
sl = sg.ele
}
return r + "]"
}
 
printStructure() {
System.print("Offset: %(_offset)")
var sg = _base
while (sg) {
System.print(sg.ele)
sg = sg.next
}
System.print()
}
}
 
var v = VList.new()
System.print("Before adding any elements, empty VList: %(v)")
v.printStructure()
 
for (a in 6..1) v = v.cons(a)
System.print("Demonstrating cons method, 6 elements added: %(v)")
v.printStructure()
 
v = v.cdr()
System.print("Demonstrating cdr method, 1 element removed: %(v)")
v.printStructure()
 
System.print("Demonstrating size property, size = %(v.size)\n")
System.print("Demonstrating element access, v[3] = %(v[3])\n")
 
v = v.cdr().cdr()
System.print("Demonstrating cdr method again, 2 more elements removed: %(v)")
v.printStructure()</syntaxhighlight>
 
{{out}}
<pre>
Before adding any elements, empty VList: []
Offset: 0
 
Demonstrating cons method, 6 elements added: [1 2 3 4 5 6]
Offset: 1
[null, 1, 2, 3]
[4, 5]
[6]
 
Demonstrating cdr method, 1 element removed: [2 3 4 5 6]
Offset: 2
[null, 1, 2, 3]
[4, 5]
[6]
 
Demonstrating size property, size = 5
 
Demonstrating element access, v[3] = 5
 
Demonstrating cdr method again, 2 more elements removed: [4 5 6]
Offset: 0
[4, 5]
[6]
</pre>
9,476

edits