Announcement

Collapse
No announcement yet.

Building a universal ArrayRotate procedure

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Building a universal ArrayRotate procedure

    I wrote a little piece of code to rotate array elements.

    The problem is of course, how to pass ANY type of array.
    My array's are useally types.

    This is the code i would like to use: (doesn't work of course)

    Code:
    Function ArrayRotate( ArrayToRot() As ANY, ElementToRot As Long ) As Long
     
        Dim a As Long
        Dim T As String
     
        a = Ubound( ArrayToRot )
        If a < 0 Then Exit Function
     
        T = String$( Len( ArrayToRot( a ) ), Chr$( 0 )
     
        POKE$ StrPtr( T ), PEEK$ VarPtr( ArrayToRot( ElementToRot ) ), Len ( T )
     
        ARRAY DELETE ArrayToRot(), ElementToRot
     
        ReDim Preserve ArrayToRot( LBound( ArrayToRot ) To a )
     
        POKE$ VarPtr( ArrayToRot( a ) ), PEEK$ StrPtr( T ), Len ( T )
     
    End Function

  • #2
    There is no native way to determine the type of array from the array descriptor. It would easiest to just pass a value to tell your function which type of array is being passed.

    For example, in psuedocode:
    Code:
    %PBARRAY_INT = 1
    %PBARRAY_LONG = 2
    %PBARRAY_STRING = 3
    ...etc
    FUNCTION RotateArray(PBArray AS ANY, Element AS LONG, ArrayType AS LONG) AS LONG
    DIM pArray_Int AS INTEGER PTR
    DIM pArray_Long AS LONG PTR
    ..etc
    SELECT CASE ArrayType
      CASE %PBARRAY_INT
        ...
      CASE %PBARRAY_LONG
        ...
      CASE ...


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    Lance
    mailto:[email protected]

    Comment


    • #3
      It might not be necessary to determine the array type... Maybe you could use LBOUND and UBOUND to find the min and max element numbers, then use VARPTR to find the memory locations of the first and last elements, and from that you could infer the size of each element (1 byte, 4 bytes, 100 bytes, etc.) Then you could use PEEK$ and POKE$ on that area of memory to move things around, instead of using the ARRAY functions. It wouldn't matter whether the array was LONGs, DWORDs, or strings, for example, because they all use 4-byte elements in the array. (Assuming that string descriptors contain "absolute" information not "relative" information, and that they would not be adversely affected by being moved.)

      I haven't tried it... Just a suggestion.

      Even if it works (using ARRAY or POKE$), moving that much data around is going to be very time-consuming unless the array is quite small. Would a system of offsets, where you treat the array as a circular buffer, work better for you? It would certainly be faster.

      -- Eric

      ------------------
      Perfect Sync: Perfect Sync Development Tools
      Email: mailto:[email protected][email protected]</A>

      "Not my circus, not my monkeys."

      Comment


      • #4
        But how to determine lbound etc..?

        I know i can provide dimensions and then shift the data as a complete memory block but then i wouldn't use PB's ARRAY delete wich (i hope) is more optimized than my brainless code

        It's not that important but i would like to see this as a new PB feature (already mentioned it.)
        A stuppid question but can't i use SHIFT (bytes * 8) or so..?



        ------------------

        Comment


        • #5
          > But how to determine lbound etc..?

          Ah, after trying it I see what you mean.

          All the more reason to treat the array like a circular buffer.

          SHIFT won't work because it only operates on integer variables, not arrays of variables.

          -- Eric

          ------------------
          Perfect Sync: Perfect Sync Development Tools
          Email: mailto:[email protected][email protected]</A>



          [This message has been edited by Eric Pearson (edited June 01, 2000).]
          "Not my circus, not my monkeys."

          Comment


          • #6
            E.B. --

            Put this code in a DLL called (for example) ARRAY.DLL:

            Code:
            FUNCTION Bounds ALIAS "Bounds" (bArray() AS BYTE) EXPORT AS LONG
                MSGBOX FORMAT$(LBOUND(bArray()))
                MSGBOX FORMAT$(UBOUND(bArray()))
            END FUNCTION
            Then declare it this way in a PB/CC or PB/DLL program:

            Code:
            DECLARE FUNCTION Bounds LIB "ARRAY.DLL" ALIAS "Bounds" (bArray() AS ANY) AS LONG
            Then you can pass any type of array to the Bounds function like this...

            Code:
            DIM Array1(999) AS LOCAL LONG
            CALL Bounds(Array1())
             
            DIM Array2(7:12345) AS LOCAL STRING
            CALL Bounds(Array2())
            ...and you will see message boxes with the lower and upper bounds that you specified, regardless of the array type. It works! Does that help?

            Of course, PB Support may need to comment on whether or not this technique is likely to work with future versions of the compilers, if the internal array descriptor format is changed.

            Hmmm... I wonder if this technique could be adapted to provide a universal save/load array function? It wouldn't work with string arrays, but...?

            -- Eric

            ------------------
            Perfect Sync: Perfect Sync Development Tools
            Email: mailto:[email protected][email protected]</A>



            [This message has been edited by Eric Pearson (edited June 01, 2000).]
            "Not my circus, not my monkeys."

            Comment


            • #7
              Edwin,

              Here are a pair of functions that should do what you are after, I have
              only tested them on a LONG array but they should work on and numeric data
              size. The only real trick was to get the array data into a more convenient
              format so that the byte rotation could be performed with the standard
              basic string functions then converted back again.

              They can be made faster if it is a problem but the performance should be
              OK as they are.

              Regards,

              [email protected]

              Code:
                ' Prototypes
                ' ~~~~~~~~~~
                DECLARE FUNCTION RAR(ByVal src as LONG, ByVal Elements as LONG, _
                                     ByVal DataSize as LONG, ByVal Rot as LONG) as LONG
                
                DECLARE FUNCTION RAL(ByVal src as LONG, ByVal Elements as LONG, _
                                     ByVal DataSize as LONG, ByVal Rot as LONG) as LONG
                
                The parameters for both are,
                
                    1. src is the address of the first array element.
                
                    2. Elements is the 1 based count for the array.
                
                    3. DataSize is the byte count for the data size, 1, 2, 4, 8.
                
                    4. Rot is the number of elements to rotate. This must be less than
                       the Elements count.
                
                
                
                ' Example
                ' ~~~~~~~
                            LOCAL lpArr as LONG
                
                            redim aLong(9) as LONG
                
                            aLong(0) = 1
                            aLong(1) = 2
                            aLong(2) = 3
                            aLong(3) = 4
                            aLong(4) = 5
                            aLong(5) = 6
                            aLong(6) = 7
                            aLong(7) = 8
                            aLong(8) = 9
                            aLong(9) = 10
                
                            lpArr = VarPtr(aLong(0))
                
                            RAR lpArr, 10, 4, 9 ' rotate array right by 9 elements
                            RAL lpArr, 10, 4, 9 ' rotate array left by 9 elements
                
                            MessageBox hWin,ByCopy str$(aLong(0)), _
                                       "Result",%MB_OK
                
                
                ' ###########################################################################
                
                FUNCTION MemCopyD(ByVal src as LONG, _
                                  ByVal dst as LONG, _
                                  ByVal ln as LONG) as LONG
                
                    #REGISTER NONE
                
                      ! cld
                
                      ! mov esi, src
                      ! mov edi, dst
                      ! mov ecx, ln
                
                      ! shr ecx, 2
                      ! rep movsd
                
                      ! mov ecx, ln
                      ! and ecx, 3
                      ! rep movsb
                
                    FUNCTION = 0
                
                END FUNCTION
                
                ' ###########################################################################
                
                FUNCTION RAR(ByVal src as LONG, ByVal Elements as LONG, _
                             ByVal DataSize as LONG, ByVal Rot as LONG) as LONG
                
                    #REGISTER NONE
                
                    LOCAL ln  as LONG
                    LOCAL dst as LONG
                    LOCAL rta as LONG
                
                    ln  = Elements * DataSize   ' byte length of array
                    rta = DataSize * Rot        ' byte length to rotate
                
                    a$  = space$(ln)            ' allocate string memory
                    dst = StrPtr(a$)            ' get its address
                
                    MemCopyD src,dst,ln
                
                    b$  = right$(a$,rta)
                    c$  = left$(a$,ln - rta)
                
                    a$  = b$ + c$
                    dst = StrPtr(a$)
                
                    MemCopyD dst,src,ln
                
                    FUNCTION = 0
                
                END FUNCTION
                
                ' ###########################################################################
                
                FUNCTION RAL(ByVal src as LONG, ByVal Elements as LONG, _
                             ByVal DataSize as LONG, ByVal Rot as LONG) as LONG
                
                    #REGISTER NONE
                
                    LOCAL ln  as LONG
                    LOCAL dst as LONG
                    LOCAL rta as LONG
                
                    ln  = Elements * DataSize   ' byte length of array
                    rta = DataSize * Rot        ' byte length to rotate
                
                    a$  = space$(ln)            ' allocate string memory
                    dst = StrPtr(a$)            ' get its address
                
                    MemCopyD src,dst,ln
                
                    b$ = right$(a$,ln - rta)
                    c$  = left$(a$,rta)
                
                    a$  = b$ + c$
                    dst = StrPtr(a$)
                
                    MemCopyD dst,src,ln
                
                    FUNCTION = 0
                
                END FUNCTION
                
                ' ###########################################################################

              [This message has been edited by Steve Hutchesson (edited June 01, 2000).]
              hutch at movsd dot com
              The MASM Forum

              www.masm32.com

              Comment


              • #8
                It's all great fellas!

                You, i thought about that ANY declaration but didn't think it over..

                I'm gonna try this out soon.

                Thanks,


                ------------------

                Comment


                • #9
                  Well, i have got my descriptor!

                  I saw this was meant using a DLL but i put my brain to work

                  By using assembly i could make use of the ANY declaration directly.
                  The following is a working example:

                  Code:
                   
                  DECLARE FUNCTION Bounds (bArray() AS ANY) AS LONG
                   
                  FUNCTION MyBounds( bArray() AS Byte ) EXPORT AS LONG
                   
                      MSGBOX FORMAT$(LBOUND(bArray()))
                      MSGBOX FORMAT$(UBOUND(bArray()))
                   
                  END FUNCTION
                   
                  Function PBMain()
                   
                      Dim Array1(999) AS LOCAL LONG
                      Dim Array2(7:12345) AS LOCAL STRING
                      Dim DWW As DWORD
                      LOCAL RetVal as LONG
                      Dim lp As Long
                   
                      DWW = CodePtr( MyBounds )
                   
                      lp = VarPtr( Array1() )
                   
                      ! push lp
                      ! call dww
                      ! mov  RetVal, eax
                   
                      lp = VarPtr( Array2() )
                   
                      ! push lp
                      ! call dww
                      ! mov  RetVal, eax
                   
                  End Function
                  Cool!

                  Now to figure out it's length's etc..



                  ------------------

                  Comment


                  • #10
                    E.B. --

                    Nice work! But...

                    In the past, PowerBASIC has consistently said that the format of the array descriptor was subject to change at any time. While it's interesting to do it your way, it would probably be more "robust" to use the LBOUND, UBOUND, etc. functions to get the information you need. That way, if the descriptor is changed your code will continue to work. (I'm not even sure that the descriptor hasn't changed in the past, so your code may or may not work with older versions of the compilers.) All of the information you're getting can be obtained with UBOUND, LBOUND, VARPTR, and some math.

                    Also, it is possible (IMO) that future versions of the compiler will not accept a DECLARE that is different from the actual function in the same program -- such as using ANY in one and BYTE in another -- so it might be safer (again, for the future) to place the function in a DLL.

                    [added later]

                    Please disregard my second comment. You fooled me when that code compiled without errors! Bounds and MyBounds in the code above are not the same function, so my point is pointless. The DECLARE isn't doing anything at all, and the compiler already rejects data-type-differences like that.

                    -- Eric

                    ------------------
                    Perfect Sync: Perfect Sync Development Tools
                    Email: mailto:[email protected][email protected]</A>



                    [This message has been edited by Eric Pearson (edited June 02, 2000).]
                    "Not my circus, not my monkeys."

                    Comment


                    • #11
                      > I can't imagine a failure on the
                      > procedure you were talking about.

                      Sorry I wasn't clear. When I said that your code would be broken if the PB array descriptor format was changed, I was talking about your Source Code forum post, to which you had posted a link and which is now shown in this thread. It requires a specific-format array descriptor, which PowerBASIC has said they do not guarantee.

                      You're right, the first code you posted (CODEPTR etc.) is not descriptor-format-specific and I don't see a problem. I can see where that technique would have a lot of uses!

                      -- Eric

                      ------------------
                      Perfect Sync: Perfect Sync Development Tools
                      Email: mailto:[email protected][email protected]</A>



                      [This message has been edited by Eric Pearson (edited June 02, 2000).]
                      "Not my circus, not my monkeys."

                      Comment


                      • #12
                        E B:

                        Your messages were placed on hold by a forum administrator in order to determine whether the posting of undocumented PowerBASIC internal design is a topic suited to our forums.

                        The conclusion was, in this case, the posting was unacceptable.

                        I would like to emphasize that the internal design of the compilers is subject to change at any time, which is why this sort of information isn't documented to begin with. Using undocumented internal information, such as the format of the array descriptors, will make your code less portable and less reliable with future (and past) versions of PowerBASIC.

                        Use at your own risk!

                        ------------------
                        Tom Hanlin
                        PowerBASIC Staff

                        Comment


                        • #13
                          Tom,
                          I hope you'll inform me by mail or sort of, i was a bit angry.

                          And i find it weird, this looks like some sort of code discrimination.
                          Don't take it to hard, i hadn't a good translation yet.

                          My point is, i can do with the compiler i like (except changing it).
                          PB approves the MKCON util too, something wich is much more to worrie about than my simple code.
                          Maybe i didn't understand you completely.
                          I'm not gonna provoke a complete discussion, i just hope i get informed sooner to discuss this on the spot.
                          Thanks,

                          Eric,

                          If you have seen the shortcut code from Semen, or the generated code from Jazzage, i can see a good future to make these kind of code smaller..

                          Btw, in PB2 Call DWORD with result was allowed, who knows why it's removed in PB6?
                          (Without 'using')

                          The assembly version is as flexible as needed.??



                          ------------------

                          Comment


                          • #14
                            > in PB2 Call DWORD with result was allowed,
                            > who knows why it's removed in PB6?
                            > (Without 'using')

                            The USING clause in the CALL DWORD syntax tells PB what kind of result value to return... LONG, STRING, etc. Without it, the compiler wouldn't know what your program was expecting to get as a return value, because all it has to go on is the memory location of a function. If an older version of PB worked without the USING clause, it must have used a default return value type or something like that. It seems to me that as the PB compilers have matured over the years, more and more "loose ends" like that have been removed.

                            -- Eric

                            ------------------
                            Perfect Sync: Perfect Sync Development Tools
                            Email: mailto:[email protected][email protected]</A>



                            [This message has been edited by Eric Pearson (edited June 02, 2000).]
                            "Not my circus, not my monkeys."

                            Comment


                            • #15
                              Erwin, there is no need to get angry because your messages were deleted - they were deemed inappropriate and PowerBASIC has always reserved the right to prune messages.

                              Here is a clipping from the "BBS RULES", and everyone here has agreed to these conditions:
                              This Message Board is owned and operated by PowerBASIC, Inc. All messages are the property of PowerBASIC, Inc.
                              ...snip... PowerBASIC, Inc. reserves the right to remove any message deemed inappropriate.


                              ------------------
                              Lance
                              PowerBASIC Support
                              mailto:[email protected][email protected]</A>
                              Lance
                              mailto:[email protected]

                              Comment

                              Working...
                              X