Code-Beispiel
BIT-Feld (BitArray), viele Ein/Aus-Schalter mit Index
Lizenz: | Erster Autor: | Letzte Bearbeitung: |
k. A. | TJF | 23.05.2011 |
Dieses Beispiel betrifft BitArrays, also viele Ein/Aus-Schalter (= boolsche Werte oder boolean) in einer Feld-Variablen und ist für alle Betriebssysteme anwendbar (dos / windows / UNIX / LINUX).
BitArrays können einerseits in einer TYPE-Struktur zusammengefasst werden, z. B. durch
TYPE Schalter
AS INTEGER Rot : 1
AS INTEGER Blau : 1
END TYPE
und dann mit aussagekräftigen Namen im Quelltext verwendet werden. Andererseits eignet sich diese Lösung jedoch nur bedingt, wenn sehr viele Schalter vorhanden sind und diese in Programm-Schleifen abgefragt oder verändert werden sollen. Hier ist es vorteilhaft, die Schalter über einen Index auswählen zu können.
Der folgende Quelltext erzeugt ein UDT (= TYPE-Struktur) zur Speicherung eines beliebig großen BIT-Feldes. Er sollte unter dem Namen BitArray.bas abgespeichert werden.
' This is file BitArray.bas, a UDT for variable length arrays of bits
' (C) 2011 by Thomas[ dot ]Freiherr[ at ]gmx{ dot }net
' License LGPLv 2
'
' Note: index is zero based (allways)
#DEFINE BitArrayError(_V_) ?"BitArray error: Index out of range (" & _V_ & ")"
TYPE BitArray
DECLARE CONSTRUCTOR(BYVAL N AS UINTEGER = 0, BYVAL V AS UBYTE = 0)
DECLARE PROPERTY Bit_(BYVAL I AS UINTEGER, BYVAL B AS INTEGER)
DECLARE PROPERTY Bit_(BYVAL I AS UINTEGER) AS INTEGER
DECLARE SUB Redim_(BYVAL N AS UINTEGER = 0, BYVAL V AS UBYTE = 0)
DECLARE SUB Xor_(BYVAL I AS UINTEGER = 0)
DECLARE FUNCTION Ubound_() AS UINTEGER
Private:
AS STRING Store
AS UINTEGER Maxi, Ubo
END TYPE
CONSTRUCTOR BitArray(BYVAL N AS UINTEGER = 0, BYVAL V AS UBYTE = 0)
Ubo = N
Maxi = N SHR 3
Store = STRING(1 + Maxi, V)
END CONSTRUCTOR
PROPERTY BitArray.Bit_(BYVAL I AS UINTEGER) AS INTEGER
VAR p = I SHR 3
IF p > Maxi THEN BitArrayError(I) : RETURN 0
RETURN BIT(Store[p], I - (p SHL 3))
END PROPERTY
PROPERTY BitArray.Bit_(BYVAL I AS UINTEGER, BYVAL B AS INTEGER)
VAR p = I SHR 3, x = I - (p SHL 3)
IF p > Maxi THEN BitArrayError(I) : EXIT PROPERTY
IF B THEN Store[p] = BITSET(Store[p], x) : EXIT PROPERTY
Store[p] = BITRESET(Store[p], x)
END PROPERTY
SUB BitArray.Redim_(BYVAL N AS UINTEGER = 0, BYVAL V AS UBYTE = 0)
VAR ln = N SHR 3
IF ln > Maxi THEN
Store &= STRING(ln - Maxi, V)
ELSE
Store = LEFT(Store, ln + 1)
END IF
Ubo = N
Maxi = ln
END SUB
SUB BitArray.Xor_(BYVAL I AS UINTEGER = 0)
VAR p = I SHR 3, x = I - (p SHL 3)
IF p > Maxi THEN BitArrayError(I) : EXIT SUB
IF BIT(Store[p], x) THEN Store[p] = BITRESET(Store[p], x) : EXIT SUB
Store[p] = BITSET(Store[p], x)
END SUB
FUNCTION BitArray.Ubound_() AS UINTEGER
RETURN Ubo
END FUNCTION
Anwendung
- Ein neues BIT-Feld mit dem Namen Test wird durch VAR Test = BitArray(Az) erzeugt. Az ist die Anzahl der Einträge im BIT-Feld. Alle Werte des neuen BIT-Feldes sind zunächst AUS (= FALSE, 0).
- Der Index beginnt bei 0. Für Az = 7 werden also BITs mit dem Index 0 bis 7 erzeugt - insgesamt also 8 BITs.
- Der Zugriff auf einzelne BITs erfolgt durch Test.Bit_(BitNr).
- Einen Wert setzen: Test.Bit_(BitNr) = NeuerWert.
- Einen Wert abfragen: Ergebnis = Test.Bit_(BitNr).
- Die Größe des BIT-Feldes abgefragen: Groesse = Test.Ubound_(BitNr).
- BIT-Feld mit neuer Größe definieren: Test.Redim_(NeuAz). (BITs, deren Index kleiner oder gleich NeuAz ist, bleiben erhalten.)
- Beim Declarieren und Umdimensionieren kann ein Vorgabewert für neu erzeugte Bits angegeben werden. Die Vorgabe wird für Blöcke von jeweils 8 Bits definiert und als Parameter nach der Anzahl übergeben. Beispiel: VAR Test = BitArray(Az, &b10101010) jedes zweite BIT einschalten. Test.Redim_(NeuAz, &b11111111) ] alle neuen BITs einschalten (Vorsicht an der Grenze zwischen alten und neuen Bytes).
- BitArray kann nicht nur auf Modulebene, sondern auch (und uneingeschränkt) in anderen UDTs eingesetzt werden.
Beispiel1 (Modulebene)
' This is file BitArrayTest.bas, an example for BitArray.bas
' (C) 2011 by Thomas[ dot ]Freiherr[ at ]gmx{ dot }net
' License GPLv 3
#INCLUDE "BitArray.bas"
#IFNDEF __FB_UNIX__
SCREEN 13
#ENDIF
'#DEFINE english
' used to print out headers and values
#MACRO HEADER(_G_, _E_)
#IFDEF english
?:?_E_
#ELSE
?:?_G_
#ENDIF
#ENDMACRO
#DEFINE SHOW(_V_, _I_) PRINT #_V_ & ".Bit_(" & _I_ & ") = " & _V_##.Bit_(_I_)
HEADER("BitFeld erzeugen jeden zweiten Wert setzen", _
"Create a BitArray, set each second values")
CONST Az = 19
VAR Test = BitArray(Az, &b01010101)
FOR i AS INTEGER = 0 TO Az
SHOW(test, i)
NEXT
HEADER("Fuenf zufaellig ausgewaehlte BITs anzeigen:", _
"Show five randomly choosen values")
FOR j AS INTEGER = 0 TO 4
VAR i = INT(RND * (Az + 1))
SHOW(test, i)
NEXT
HEADER("Bei einem zu grossen Index erfolgt eine Fehlermeldung:", _
"Error message in case of out-ranged index:")
SHOW(test, Az + 8)
HEADER("Ein BIT veraendern", _
"Change a value")
' this doesn't work, since fbc cannot handle the index
' Test.Bit_(i) XOR= Test.Bit_(i)
VAR i = Az SHR 1
SHOW(test, i)
'Test.Bit_(i) = Test.Bit_(i) XOR -1
Test.Xor_(i)
SHOW(test, i)
HEADER("Eine Kopie des BitFeldes erzeugen:", _
"Create a copy of the BitArray:")
VAR neu = test
SHOW(neu, i)
HEADER("Die Groesse des neu-BitFeldes reduzieren, alle BITs anzeigen:", _
"Reduce the neu BitArray and show all values:")
neu.Redim_(7)
FOR i AS INTEGER = 0 TO neu.Ubound_()
SHOW(neu, i)
NEXT
HEADER("Die Groesse des neu-BitFeldes wieder erhoehen, alle BITs anzeigen:", _
"Increment the neu BitArray and show all values:")
neu.Redim_(11, &b11111111) ' sets all new values
FOR i AS INTEGER = 0 TO neu.Ubound_()
SHOW(neu, i)
NEXT
#IFNDEF __FB_UNIX__
SLEEP
#ENDIF
Beispiel2 (in TYPE Struktur)
' This is file BitArrayTest2.bas, an example for BitArray.bas
' (C) 2011 by Thomas[ dot ]Freiherr[ at ]gmx{ dot }net
' License GPLv 3
#INCLUDE "BitArray.bas"
'#DEFINE english
#MACRO SHOW(_V_, _G_, _E_)
#IFDEF english
?_E_
#ELSE
?_G_
#ENDIF
FOR i AS UINTEGER = 0 TO _V_.Ubound_()
?_V_.Bit_(i); " ";
NEXT : ?
#ENDMACRO
TYPE UDT
DECLARE SUB Operate()
AS BitArray Publ = BitArray(24, &b10101010) ' 24 bits, second set
Private:
AS BitArray Priv = BitArray(9, &b11111111) ' 9 bits, all set
END TYPE
SUB UDT.Operate()
CLS
SHOW(Publ, "Das öffentliche (PUBLIC) BIT-Feld (Vorgabe jedes 2. BIT ein)", _
"The public bit array (every second bit set on init)")
Publ.Redim_(Publ.Ubound_() SHR 1)
SHOW(Publ, "Verkleinere auf die Hälfte", _
"decrease the entries to half")
?
SHOW(Priv, "Das verborgene (PRIVATE) BIT-Feld (Vorgabe BITs ein)", _
"The private bit array (all bits set on init)")
Priv.Redim_(Priv.Ubound_() SHL 1, &b11111111)
SHOW(Priv, "Die Anzahl der Eintraege verdoppeln (neue BITs ein)", _
"double the entries (new bits set)")
FOR i AS INTEGER = 0 TO Priv.Ubound_() STEP 3
Priv.Xor_(i)
NEXT
SHOW(Priv, "Jedes dritte BIT umschalten", _
"switch every third bit")
?
VAR neu = Priv
SHOW(neu, "Eine Kopie des verborgenen Feldes", _
"A copy of the private bit array")
END SUB
#IFNDEF __FB_UNIX__
SCREEN 13
#ENDIF
' *** main ***
DIM AS UDT test
test.Operate()
? : ? : ?"Ein BIT ausserhalb der TYPE-Struktur / A bit outside the UDT"
VAR n = 7
?test.Publ.Bit_(n)
' Die Folgezeile kompiliert nicht (error 175: Illegal member access)
' next line doesn't compile (error 175: Illegal member access)
'?test.Priv.Bit_(n)
#IFNDEF __FB_UNIX__
SLEEP
#ENDIF
Anmerkungen
- Der Index beginnt immer bei Null. Falls eine andere Index-Basis benötigt wird, muss eine Index-Umrechnung vorgeschaltet werden.
- Es ist nur ein Index vorgesehen. Falls mehrere Indices benötigt werden, muss eine Index-Umrechnung vorgeschaltet werden.
- Die Speicherung der BITs erfolgt in Blöcken zu je 8 BIT (= Byte). Es können also ggf. mehr BITs gespeichert werden als angefordert. (Z. B. nach Dimensioniren mit Az = 8 kann auch ein Index von bis zu 15 verwendet werden.)
- Die maximale BIT-Anzahl ist das 8-fache der maximalen Länge einer STRING-Variablen. Unter DOS ist ggf. die Länge von STRING-Variablen begrenzt (Extended memory Thematik), wodurch sich hier eine Einschränkung der maximalen BIT-Anzahl ergeben kann.
English
This example is about an UDT for creating an array of boolean values (BITs) and can be used on all platforms.
BIT arrays can be done by defining a TYPE-structure like
TYPE Schalter
AS INTEGER Rot : 1
AS INTEGER Blau : 1
END TYPE
and the BITs can be used in the source by their meaningful names. But it's not sufficiant when you need to use a large number of BITs in a loop. In this case you may want to refer to the BITs by an index. Here's one way how to do so.
The first second block generates an UDT to store a variable length bit array. It should be saved as file BitArray.bas.
Usage
- To create a new BIT array named Test use VAR Test = BitArray(Az). Az is the number of entries in the BIT array. All values are set to OFF (= FALSE, 0) after initialization.
- The index is zero-based. For Az = 7 BITs with index 0 to 7 will get created -- so 8 BITs at all.
- Handle a single BIT Test.Bit_(BitNr).
- Set a BIT: Test.Bit_(BitNr) = NeuerWert.
- Get a BIT: Ergebnis = Test.Bit_(BitNr).
- Get the size of the BIT array: Groesse = Test.Ubound_(BitNr).
- Re-dimensioning the BIT array: Test.Redim_(NeuAz). (BITs with index <= NeuAz are preserved.)
- Set init values on Dim / Redim a BIT array by passing an additional parameter. The init values are given in blocks of 8 BITs. Example: VAR Test = BitArray(Az, &b10101010) set every second BIT. Test.Redim_(NeuAz, &b11111111) set all new BITs (be careful at the border between old and new bytes).
- BIT arrays can be used on modul level, as well as in UDTs without limits.
The third (Beispiel1) and fourth (Beispiel2) code blocks show examples on how to use it.
Anotations
- The index allways is zero-based. If you need the index starting at an offset, you can use an pre-conversion for the index.
- Only one index is used. If you need more indices, you can use an pre-conversion for the index.
- The BITs gets stored in blocks of 8 BITs (= Byte). You may use an index greater than required. (Ie when you require 8 BITs, you can use an index up to 15.)
- The maximum number of BITs is the maximum STRING-length times 8. Under DOS the STRING-variable length may be limited (extended memory issues) and this may cause a lower limit for the maximum number of BITs here.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|