Union

Forum for discussion about the documentation project.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Union

Post by dodicat »

I think you need string * 9 and not zstring * 9 to make it work as expected.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

dodicat wrote:I think you need string * 9 and not zstring * 9 to make it work as expected.
Very weirdly, if I change zstring*9 by string*9 everywhere, I don't have any more the issue with the array boundary (I can go beyond 2^16 - 1).
But I loose all the compression advantage:

With strings:

Code: Select all

memory usage
32760
36855 '!!
get the value at index 111 back
****          o
****          0
111
get the value at index 1024 back
****          1024
****          1024
1024
With Zstrings (same data as above):

Code: Select all

memory usage
32760
7962 '<------ good
get the value at index 111 back
****          o
****          0
111
get the value at index 1024 back
****          1024
****          1024
1024
How did you come to think that Zstrings would induce something bad here? I cant see the reason at all.... And I can't really use Strings.

Edit:
Ahah! It is needed to use string*9 within the UNION, but not in the rest of the code. Then it works again... Thanks :)
I still wonder the reason under the hood. The fact that Union are said not to be quite tolerante to strings (the not fixed-len ones) it tends to lead to use zstrings rather... Silly, but true. Anyway, where the difference comes from when it is all about fixed-len stuff here?

Code: Select all

dim as uinteger n       => 18       'size of the 2 arrays used below 2^n -1
dim as uinteger upper   => 2^n - 1

union SPACESAVER
        as uinteger     value
        as string*9    zstr
        as ubyte        firstbyte
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
    declare function ConsistencyCheck(byval as uinteger) as boolean
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    select case THIS.firstbyte
    case 0
        return str(V)
    case else
        return THIS.zstr
    end select
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    THIS.zstr = Z
    ? "****", Z
    ?"****", cUint(Z)
    select case ( (cUint(Z)<>0) andAlso (cUint(Z) mod 256 = 0))
    case TRUE
        return val(Z)
    case else
        return THIS.value
    end select
end function
function SPACESAVER.ConsistencyCheck(byval ArrayIndex as uinteger) as boolean
    if not THIS.SetStringGetValue(THIS.SetValueGetString(ArrayIndex))=ArrayIndex then 
        return FALSE
    else
        return TRUE
    end if
end function

dim as SPACESAVER spsa
redim as uinteger   arrayOfUInt(1 to upper)
redim as zstring*9  arrayOfStr(1 to upper)

dim as uinteger sumUintArray
dim as uinteger sumStrArray
for i as integer = 1 to upper
    arrayOfUInt(i) = i
    arrayOfStr(i) = spsa.SetValueGetString( arrayOfUInt(i) )
    sumUintArray += len(i)
    sumStrArray += len( arrayOfStr(i) )
next i
    
? "memory usage"
? sumUintArray
? sumStrArray

? "get the value at index 111 back"
? spsa.SetStringGetValue( arrayOfStr(111) )

? "get the value at index 1024 back"
? spsa.SetStringGetValue( arrayOfStr(1024) )

getKey()

Code: Select all

memory usage
2097144
722001
get the value at index 111 back
****          o
****          0
111
get the value at index 1024 back
****          1024
****          1024
1024
Thanks again!
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

When writing a number, all bytes of number are updated.
When writing a zstring, only the useful characters (plus the terminal character) are updated (the followings are unchanged).
(for a 'string * n', all characters are always updated)

Simple workaround to your original code:

Code: Select all

function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    THIS.value = 0  '' in order to reset the zstring
    THIS.zstr = Z
    ? "****", Z
    ?"****", cUint(Z)
    select case ( (cUint(Z)<>0) andAlso (cUint(Z) mod 256 = 0))
    case TRUE
        return val(Z)
    case else
        return THIS.value
    end select
end function
Note: if you use a fix-len string, a 'string * 8' is sufficient.
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

fxm wrote:As soon as a the uinteger longint contains a not higher null ubyte, that no longer works.
Simple example:
spsa.value = 256
You have not solved everything.
As soon as the number contains any significant ubyte equal to zero, it no longer works.
For example, try the value: &h010001 or &h01000101 ...
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

KeyPgUnion → fxm [Rewording]
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

fxm wrote: Simple workaround to your original code:

Code: Select all

    THIS.value = 0  '' in order to reset the zstring
Note: if you use a fix-len string, a 'string * 8' is sufficient.
There is a lot to master in the above answers. I start from the simplest thing to my ears. How the Union buffer is filled and cleaned.
I've made this code to summarize a little:

Code: Select all

union US
    declare sub PrintContent()
        as zstring*9        zs
        as uinteger<8*8>     u
        as uinteger<8*1>      v
        as string*8         s
        type
            as ubyte     b1 : as ubyte     b2
            as ubyte     b3 : as ubyte     b4
            as ubyte     b5 : as ubyte     b6
            as ubyte     b7 : as ubyte     b8
        end type
end union
sub US.PrintContent()
    ? "zString9=",, THIS.zs
    ? "value=",, THIS.u
    ? "1 byte value=",, THIS.v
    ? "string8=",,THIS.s
    ? ,, "________"
    ? THIS.b1; ":"; : ? THIS.b2; ":";
    ? THIS.b3; ":"; : ? THIS.b4; ":";
    ? THIS.b5; ":"; : ? THIS.b6; ":";
    ? THIS.b7; ":"; : ? THIS.b8
end sub

dim as US   uuss

? "fill the buffer"
uuss.u = &h1111111111111111
uuss.PrintContent()

?
? "after a zstring assignement, things are not cleaned up enough"
uuss.zs = "hhhhh"
uuss.PrintContent()

?
? "after a string assignement it's ok"
uuss.s = "hhhhh"
uuss.PrintContent()

?
? "fill the buffer again"
uuss.u = &h1111111111111111
uuss.PrintContent()

?
? "after a 8bits (1 byte) value assignement it's not cleaned up"
uuss.v = &h44
uuss.PrintContent()

?
? "after a 64bits (8 bytes) value assignement it seems OK"
uuss.u = &h44
uuss.PrintContent()

getKey()
running: OS:WINDOWS FBC_Version =1.06.0 64bit

fill the buffer
zString9= ????????
value= 1229782938247303441
1 byte value= 17
string8= ????????
________
17:17:17:17:17:17:17:17

after a zstring assignement, things are not cleaned up enough
zString9= hhhhh
value= 1229764621677127784
1 byte value= 104
string8= hhhhh
________
104:104:104:104:104:0:17:17

after a string assignement it's ok
zString9= hhhhh
value= 448428271720
1 byte value= 104
string8= hhhhh
________
104:104:104:104:104:0:0:0

fill the buffer again
zString9= ????????
value= 1229782938247303441
1 byte value= 17
string8= ????????
________
17:17:17:17:17:17:17:17

after a 8bits (1 byte) value assignement it's not cleaned up
zString9= D???????
value= 1229782938247303492
1 byte value= 68
string8= D???????
________
68:17:17:17:17:17:17:17

after a 64bits (8 bytes) value assignement it seems OK
zString9= D
value= 68
1 byte value= 68
string8= D
________
68:0:0:0:0:0:0:0
Better seen with a pic:
Image
fxm wrote: As soon as the number contains any significant ubyte equal to zero, it no longer works.
For example, try the value: &h010001 or &h01000101 ...
I still don't get very well the other affair with zstrings and significant stuff or null terminator...
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

fxm wrote:As soon as the number contains any significant ubyte equal to zero, it no longer works.
For example, try the value: &h010001 or &h01000101 ...
Values ​​in hexadecimal, thus broken down by byte:

Code: Select all

&h|01|00|01|
      ^null byte (terminal character for a zstring)

&h|01|00|01|01|
      ^null byte (terminal character for a zstring)
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

fxm wrote: Values ​​in hexadecimal, thus broken down by byte:

Code: Select all

&h|01|00|01|
      ^null byte (terminal character for a zstring)

&h|01|00|01|01|
      ^null byte (terminal character for a zstring)
Ok I think I get it. Each time a ASCII character is written (corresponding to a ubyte say) -> if it is a null value, that's a problem for zstrings that will break down right there. So we'll have to watch each Bytes, and reject the conversion to zstring if there is a null byte around. I think it's quite feasible fortunately!!

edit:
First, to go back to the fundation:

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        as string*8         strng
        type
            as ubyte    b1, b2, b3, b4, b5, b6, b7, b8
        end type
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    return THIS.strng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    THIS.strng = Z
    return THIS.value
end function

dim as SPACESAVER spsa

scope
    dim as uinteger<64>     ui = &h11223344
    ? "numeric value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11220044
    ? "numeric value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11003344
    ? "numeric value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ?
end scope
scope
    dim as uinteger<64>     ui = &h110033005566
    ? "numeric value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ?
end scope

getKey()
numeric value: 11223344
after 1 switch: 11223344
array of byte: 443322110000
string stored: D3"◄

numeric value: 11220044
after 1 switch: 44
array of byte: 440000000
string stored: D

numeric value: 11003344
after 1 switch: 3344
array of byte: 4433000000
string stored: D3

numeric value: 110033005566
after 1 switch: 5566
array of byte: 6655000000
string stored: fU
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

Hi all,

@fxm, I've finally crafted this union below. This seems to be working after writting some tedious nested if test to avoid the null bytes that the strings seem unable to store well enough for the job asked.
Could you tell me if you see something I missed? Or anyone who have some time for this?
From my side my tests look successull.

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        as string*18         strng   'can't be exchanged outside if null char inside
        as zstring*19        zstrng  'will be truncated immediatly if null char inside
        type
            as ubyte    b1, b2, b3, b4, b5, b6, b7, b8
        end type
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        if .b8=0 then
            if .b7=0 then
                if .b6=0 then
                    if .b5=0 then
                        if .b4=0 then
                            if .b3=0 then
                                if .b2=0 then
                                    if .b1=0 then
                                        return str(.value)
                                    end if
                                end if
                            else
                                if .b2*.b1=0 then
                                    return str(.value)
                                end if
                            end if
                        else
                            if .b3*.b2*.b1=0 then
                                return str(.value)
                            end if
                        end if
                    else
                        if .b4*.b3*.b2*.b1=0 then
                            return str(.value)
                        end if
                    end if
                else
                    if .b5*.b4*.b3*.b2*.b1=0 then
                        return str(.value)
                    end if
                end if
            else
                if .b6*.b5*.b4*.b3*.b2*.b1=0 then
                    return str(.value)
                end if
            end if
        else
            if .b7*.b6*.b5*.b4*.b3*.b2*.b1=0 then
                return str(.value)
            end if
        end if
    end with    
    'if no null bytes let the union do the job
    return THIS.strng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    if (str(val(Z))=Z) then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function

dim as SPACESAVER spsa

scope
    dim as uinteger<64>     ui = &h11223344
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11220044
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11003344
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11000099000066
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "array of byte:", 
    ? hex(spsa.b1); hex(spsa.b2); hex(spsa.b3); hex(spsa.b4); hex(spsa.b5); hex(spsa.b6); hex(spsa.b7); hex(spsa.b8)
    ? "string stored:", spsa.strng
    ? "zstring stored:", spsa.zstrng
    var temp = spsa.strng
    spsa.value = 0
    ? "back to initial:", spsa.SetStringGetValue(temp)
    ?
end scope

getKey()
numeric value: 287454020
hex. num. value: 11223344
after 1 switch: 11223344
array of byte: 443322110000
string stored: D3"◄
zstring stored: D3"◄
back to initial: 287454020

numeric value: 287440964
hex. num. value: 11220044
after 1 switch: 11220044
array of byte: 3238373434303936
string stored: 287440964
zstring stored: 287440964
back to initial: 287440964

numeric value: 285225796
hex. num. value: 11003344
after 1 switch: 11003344
array of byte: 3238353232353739
string stored: 285225796
zstring stored: 285225796
back to initial: 285225796

numeric value: 4785077170995302
hex. num. value: 11000099000066
after 1 switch: 11000099000066
array of byte: 3437383530373731
string stored: 4785077170995302
zstring stored: 4785077170995302
back to initial: 4785077170995302
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

My version (raw code, little tested):

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        as zstring*(20+1)   zstrng  'UINTEGER 64bit: max=18446744073709551615
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        for i as integer = 7 to 1 step -1
            if .zstrng[i] <> 0 then
                for j as integer = i-1 to 0 step -1
                    if .zstrng[j] = 0 then
                        return str(.value)
                    end if
                next j
            end if
        next i
    end with   
    'if no null bytes let the union do the job
    return THIS.zstrng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    if (str(val(Z))=Z) then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function

dim as SPACESAVER spsa

scope
    dim as uinteger<64>     ui = &h11223344
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11220044
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11003344
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = &h11000099000066
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope

getKey()
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

fxm wrote:My version (raw code, little tested):
I've launched a first test with an array of 10000 values (1 to 10000) and I found some errors (for value = 48 to 57):
(I added a useless THIS.value=0 at line 25, it doesn't cause the error here)
8 * 10000 = 80000
size of the array data 19820
problem here string stored=0 initial value= 48
problem here string stored=1 initial value= 49
problem here string stored=2 initial value= 50
problem here string stored=3 initial value= 51
problem here string stored=4 initial value= 52
problem here string stored=5 initial value= 53
problem here string stored=6 initial value= 54
problem here string stored=7 initial value= 55
problem here string stored=8 initial value= 56
problem here string stored=9 initial value= 57

numeric value: 47
hex. num. value: 2F
after 1 switch: 2F
zstring stored: /
back to initial: 47


numeric value: 48
hex. num. value: 30
after 1 switch: 0
zstring stored: 0
back to initial: 0

end

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        as zstring*(20+1)   zstrng  'UINTEGER 64bit: max=18446744073709551615
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        for i as integer = 7 to 1 step -1
            if .zstrng[i] <> 0 then
                for j as integer = i-1 to 0 step -1
                    if .zstrng[j] = 0 then
                        return str(.value)
                    end if
                next j
            end if
        next i
    end with   
    'if no null bytes let the union do the job
    return THIS.zstrng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    THIS.value = 0
    if (str(val(Z))=Z) then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function

dim as SPACESAVER   spsa
dim as integer  sumlen
dim as string   strarray(1 to 10000)
for i as integer = 1 to 10000
    strarray(i) = spsa.SetValueGetString(i)
    sumlen += len(strarray(i))
next i

? "8 * 10000 =", 8 * 10000
? "size of the array data", sumlen
for i as integer = 1 to 10000
    dim as SPACESAVER   spsa1
    if spsa1.SetStringGetValue(strarray(i))<>i then
        ? "problem here", "string stored=";strarray(i), "initial value=";i
    end if
next i

scope
    dim as uinteger<64>     ui = 47
    ?
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope
scope
    dim as uinteger<64>     ui = 48
    ?
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    ? "back to initial:", spsa.SetStringGetValue(spsa.zstrng)
    ?
end scope

? "end"
getKey()
I will also try with my version. I don't see the cause of the issue anyway.
Same test with my code gives more errors (including those cited above):
8 * 10000 = 80000
size of the array data 19667
problem here string stored=0 initial value= 48
problem here string stored=1 initial value= 49
problem here string stored=2 initial value= 50
problem here string stored=3 initial value= 51
problem here string stored=4 initial value= 52
problem here string stored=5 initial value= 53
problem here string stored=6 initial value= 54
problem here string stored=7 initial value= 55
problem here string stored=8 initial value= 56
problem here string stored=9 initial value= 57
problem here string stored= initial value= 256
problem here string stored= initial value= 512
problem here string stored= initial value= 768
problem here string stored= initial value= 1024
problem here string stored= initial value= 1280
problem here string stored= initial value= 1536
problem here string stored= initial value= 1792
problem here string stored= initial value= 2048
problem here string stored= initial value= 2304
problem here string stored= initial value= 2560
problem here string stored= initial value= 2816
....
[Edit]
silly remark...
Last edited by Tourist Trap on Dec 12, 2018 22:21, edited 1 time in total.
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        type
            as zstring*20+1   zstrng  'UINTEGER 64bit: max=18446744073709551615
            as byte flag
        end type
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        for i as integer = 7 to 1 step -1
            if .zstrng[i] <> 0 then
                for j as integer = i-1 to 0 step -1
                    if .zstrng[j] = 0 then
                        .flag = 1
                        return str(.value)
                    end if
                next j
            end if
        next i
    end with   
    'if no null bytes let the union do the job
    THIS.flag = 0
    return THIS.zstrng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    if THIS.flag=1 then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Union

Post by Tourist Trap »

fxm wrote:
It works!

Still remaining a little issue. When I run the array test, the value returned via the function string->tovalue doesn't give the right stuff. Even if the right string is there. It's a small issue I guess.

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        type
            as zstring*20+1   zstrng  'UINTEGER 64bit: max=18446744073709551615
            as byte flag
        end type
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        for i as integer = 7 to 1 step -1
            if .zstrng[i] <> 0 then
                for j as integer = i-1 to 0 step -1
                    if .zstrng[j] = 0 then
                        .flag = 1
                        return str(.value)
                    end if
                next j
            end if
        next i
    end with   
    'if no null bytes let the union do the job
    THIS.flag = 0
    return THIS.zstrng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    if THIS.flag=1 then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function

'------------------------------------------------------test1
dim as SPACESAVER   spsa
scope
    dim as uinteger<64>     ui = 256
    ?
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    var temp = spsa.zstrng
    spsa.value = 0
    ? "back to initial:", spsa.SetStringGetValue(temp)
    ?
end scope
scope
    dim as uinteger<64>     ui = 2560
    ?
    ? "numeric value:", ui
    ? "hex. num. value:", hex(ui)
    ? "after 1 switch:", hex(spsa.SetStringGetValue(spsa.SetValueGetString( ui )))
    ? "zstring stored:", spsa.zstrng
    var temp = spsa.zstrng
    spsa.value = 0
    ? "back to initial:", spsa.SetStringGetValue(temp)
    ?
end scope

'------------------------------------------------------test2
dim as integer  sumlen
redim as string    strarray(1 to 2^12)
for i as integer = 1 to 2^12
    strarray(i) = spsa.SetValueGetString(i)
    sumlen += len(strarray(i))
next i

? "array data consummed", sumlen
for i as integer = 1 to 2^12
    dim as SPACESAVER   spsa2
    spsa2.value = 0
    if spsa2.SetStringGetValue(strarray(i))<>i then
        ? "problem here", "string stored=";strarray(i);",";spsa2.SetStringGetValue(strarray(i)), "initial value=";i
    end if
next i


? "end"

getKey()
numeric value: 2560
hex. num. value: A00
after 1 switch: A00
zstring stored: 2560
back to initial: 2560

array data consummed 7966
problem here string stored=256,3552562 initial value= 256
problem here string stored=512,3289397 initial value= 512
problem here string stored=768,3683895 initial value= 768
problem here string stored=1024,875704369 initial value= 1024
problem here string stored=1280,808989233 initial value= 1280
problem here string stored=1536,909325617 initial value= 1536
problem here string stored=1792,842610481 initial value= 1792
problem here string stored=2048,942944306 initial value= 2048
problem here string stored=2304,875574066 initial value= 2304
problem here string stored=2560,808858930 initial value= 2560
problem here string stored=2816,909195314 initial value= 2816
problem here string stored=3072,842477619 initial value= 3072
problem here string stored=3328,942814003 initial value= 3328
problem here string stored=3584,876098867 initial value= 3584
problem here string stored=3840,808728627 initial value= 3840
problem here string stored=4096,909717556 initial value= 4096
end
Do you think there is a way to get a simpler solution always with this kind of union?

Is your flag stored at the last character (n°21) of the zstring*21 (due maybe to reverse order of strings in memory?) or I 'm wrong?
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

'zstrng' and 'flag' are in a Type block, so there is no common memory between them.
'flag' is declared after 'zstrng', so no common memory with 'value'.
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Union

Post by fxm »

Last attempt for me (this strange and twisted use of Union is not very exciting):

Code: Select all

union SPACESAVER
        as uinteger<8*8>    value
        type
            as zstring*20+1   zstrng  'UINTEGER 64bit: max=18446744073709551615
            as byte flag
        end type
    declare function SetValueGetString(byval as uinteger) as string
    declare function SetStringGetValue(byref as const string) as uinteger
end union
function SPACESAVER.SetValueGetString(byval V as uinteger) as string
    THIS.value = V
    'test for null bytes
    with THIS
        for i as integer = 7 to 1 step -1
            if .zstrng[i] <> 0 then
                for j as integer = i-1 to 0 step -1
                    if .zstrng[j] = 0 then
                        .flag = 1
                        return str(.value)
                    end if
                next j
            end if
        next i
    end with   
    'if no null bytes let the union do the job
    THIS.flag = 0
    return THIS.zstrng
end function
function SPACESAVER.SetStringGetValue(byref Z as const string) as uinteger
    dim as SPACESAVER ss
    ss.SetValueGetString(valuint(Z))
    if ss.flag=1 or THIS.flag=1 then
        THIS.zstrng = Z
        return val(Z)
    else
        THIS.zstrng = Z
        return THIS.value
    end if
end function
Post Reply