Announcement

Collapse
No announcement yet.

Swap array names

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

  • Swap array names

    Is there a way of swapping the targets of two array names? In other words, if I have two arrays, aDib() and aDob() say, is there a way of making aDib refer to what was aDob and aDob refer to what was aDib.

    I guess what I’m asking for is a “shallow” SWAP: that is VARPTR(aDib()) becomes VARPTR(aDob()) and vice versa.

    Keith

  • #2
    In PBWIN10, there is MEMORY SWAP, something like:
    Code:
       MEMORY SWAP VARPTR(aDib()), VARPTR(aDob()), (UBOUND(aDib) - LBOUND(aDib)) * 4
    Where last part is size of array (in example, LONG (4 byte) array. Else I guess you also could do "normal" swap using MAT statement and a temporary array, like:
    Code:
      DIM aTmp(LBOUND(aDib) TO UBOUND(aDib)) AS LONG AT VARPTR(aDib())
      MAT aDib = aDob
      MAT aDob = aTmp

    Comment


    • #3
      Hi Borje

      The physical copying/swapping of the array data is what I was hoping to avoid. I was also hoping to avoid the “elbowroom” of introducing a temporary array to facilitate the swap

      The following seems to work (inspired by https://forum.powerbasic.com/forum/u...-string-arrays ) but I’m a little “frightened” of it.

      Code:
        LOCAL i, aPos(), aNeg() AS LONG
      
        DIM aPos(9), aNeg(9)
        FOR i = 0 TO 9
          aPos(i) = +i*i
          aNeg(i) = -i*i
        NEXT
      
        MSGBOX " Before swap: aPos(2) = " + str$(aPos(2))
      
        SwapPointers (VARPTR(aPos()), VARPTR(aNeg()))
      
        MSGBOX " After swap:  aPos(2) = " + str$(aPos(2))
      
      SUB SwapPointers (BYVAL aPtr1 AS DWORD, BYVAL aPtr2 AS DWORD)
      
        !MOV ECX, aPtr1
        !MOV EDX, aPtr2
      
        !MOV EAX, [ECX]
        !MOV EBX, [EDX]
        !MOV [ECX], EBX
        !MOV [EDX], EAX
      
      END SUB
      Keith

      Comment


      • #4

        What I would do is..

        Instead of:
        Code:
        LOCAL aDib() AS STRING
        LOCAL aDob() AS STRING
        
        DIM aDib(%ArraySize)
        DIM aDob(%ArraySize)
        
        aDib(5) = "Item 5 originally in aDib()"
        aDob(2) = "Item 2 originally in aD0b()"

        I would use..
        Code:
        LOCAL a() AS  STRING
        LOCAL DiB, DoB AS LONG
        
        DIM a(0 TO 1, %ArraySize)
        
        DiB = 0
        DoB = 1
        
        
        a(DiB,5) = "Item 5 originally in aDib()"
        a(DoB,2) = "Item 2 originally in aD0b()"
        
        'Then to swap the arrays just..
        SWAP DiB,DoB

        Comment


        • #5
          What I would do is..
          .. re-examine my program design?
          Michael Mattias
          Tal Systems Inc.
          Racine WI USA
          mmattias@talsystems.com
          http://www.talsystems.com

          Comment


          • #6
            Paul

            Yes, that is a way – essentially have a single array with two “layers”. Trouble is there is a complication in that the size of the arrays can change greatly. I’ve been amiss in not explaining the context.

            The application allows the user to enter commands into an edit pane. The commands are analysed and the results displayed in an output pane. The analysis stage can sometimes take a significant time and so I propose to run it in a separate thread. I would have two “results” data structures; call them “buffer” and “display”. Essentially the following sequence would occur.
            1. Edits are made to the commands
            2. Analysis thread writes the results into the “buffer” data structure.
            3. When complete, “buffer” is written into the “display” data structure.

            It’s a legacy program and the data structures take the form of several global arrays, including some string arrays, and some scalars. The size of the “results” can vary greatly from one analysis to the next – current the arrays are expanded as necessary with REDIM PRESERVE.

            The somewhat brute-force way of implementing step 3 above would be to simply redimension the “display” data structure to match the “buffer” and then copy the data across (eg. MAT display() = buffer()). What would be the most efficient way of doing this with respect to speed and memory elbowroom? Would there be a way of avoiding the copying altogether by essentially having a “buffer” and a “display” pointer and simply swapping them?

            Comment


            • #7
              Keith,

              Does something like this work?

              You don't actually reference the arrays directly (by their names). You use another name which you assign via DIM...AT. This way you can simply swap the names with a REDIM.

              Code:
              FUNCTION PBMAIN( )
                  DIM aDib( 4 ) AS STRING
                  DIM aDob( 4 ) AS STRING
                  aDib( 0 ) = "dib 0"
                  aDib( 1 ) = "dib 1"
                  aDib( 2 ) = "dib 2"
                  aDib( 3 ) = "dib 3"
                  aDob( 0 ) = "dob 0"
                  aDob( 1 ) = "dob 1"
                  aDob( 2 ) = "dob 2"
                  aDob( 3 ) = "dob 3"
                  DIM bDib( 3 ) AS STRING AT VARPTR( aDib( 0 ))
                  DIM bDib( 3 ) AS STRING AT VARPTR( aDob( 0 ))
                  MSGBOX "Pre swap Source: bDib(0)=" + bDib( 0 )
                  REDIM bDib( 3 ) AS STRING AT VARPTR( aDob( 0 ))
                  REDIM bDob( 3 ) AS STRING AT VARPTR( aDib( 0 ))
                  MSGBOX "Post swap Source: bDib(0)=" + bDib( 0 )
              END FUNCTION
               
              Last edited by George Bleck; 20 Mar 2017, 11:48 AM.
              <b>George W. Bleck</b>
              <img src='http://www.blecktech.com/myemail.gif'>

              Comment


              • #8
                Is it dynamic string arrays? Think you can use pointer variables and plain SWAP with any kind of array, like:
                Code:
                  LOCAL pDob, pDib AS STRING PTR
                  pDob = VARPTR(aDob())
                  pDib = VARPTR(aDib())
                  SWAP @pDob, @pDib
                Not tested, but should work... I think.
                Edit: and LONG PTR for LONG arrays, etc, but I know you know that.
                Last edited by Borje Hagsten; 20 Mar 2017, 11:51 AM.

                Comment


                • #9
                  Borje

                  It works – just tried it with both STRING and LONG arrays. But, I’m not sure I understand why it works.

                  Amazed
                  Keith

                  Comment


                  • #10
                    If the upper and lower bounds of the arrays are the same, then swapping the pointers in the array descriptors effectively exchanges the names (which don't exist at run time anyway). The data in the elements of the arrays is not moved.

                    If the bounds are not same, then those will also need to be swapped between descriptors.

                    Since I don't have the structure of the descriptors memorized, I won't do sample code. I think Borje's first idea was closest though.

                    Cheers,
                    Dale

                    Comment


                    • #11
                      Dale, you beat me to it – I was about to post just:

                      Well, not quite. The two array names now reference the data that used to belong to the other, but the array descriptors remain the same, and hence inconsistent with the size of the data. I suspect I’m going to give some thought to George’s suggestion of using REDIM AT – late afternoon brain fade at moment.

                      Comment


                      • #12
                        I seem to remember the array descriptor is proprietary and liable to change. Still, it is a pity that I can’t just swap the respective array descriptors.

                        Comment


                        • #13
                          Borje

                          As I said above, I’m not sure I understand why it (swapping pointer variables) works – it’s been bugging me.

                          As I understand it, an array of numeric type will have a contiguous block of memory that holds the actual data of the array. An array of dynamic strings will still have a contiguous block of memory but this time of STRING descriptors. In either case, the location of the start of this block is VARPTR(anArray(0)), assuming zero lower bound.

                          Now, I also understand that, VARPTR(anArray()) gives the address of the array descriptor. My hypothesis is that the first member of this descriptor is the address of the location of the array data block. In other words, this first member is a DWORD. This being so, it would seem that declaring the pointers as either LONG PTR or STRING PTR in our original code is a red-herring. What we really mean is a pointer to a pointer, ie. a DWORD PTR.

                          The following code would seem to confirm these thoughts.


                          Code:
                             LOCAL i AS LONG, aPos(), aNeg() AS STRING, pPos, pNeg AS DWORD PTR
                          
                            DIM aPos(9), aNeg(9)
                            FOR i = 0 TO 9
                              aPos(i) = str$(+i*i)
                              aNeg(i) = str$(-i*i)
                            NEXT
                          
                            pPos = VARPTR(aPos())
                            pNeg = VARPTR(aNeg())
                          
                            MSGBOX " Before swap: aPos(2)   = " + aPos(2) + $CRLF _
                                 + " @pPos, VARPTR(aPos(0)) : " + str$(@pPos) + "," + STR$(VARPTR(aPos(0)))
                          
                            SWAP @pPos, @pNeg
                          
                            MSGBOX " After swap:  aPos(2) = " + aPos(2) + $CRLF _
                                 + " @pPos, VARPTR(aNeg(0)) : " + str$(@pPos) + "," + STR$(VARPTR(aNeg(0)))
                          What do you think? It seems to me the swapping of array pointer variables in the manner discussed has a built-in assumption about the array descriptor.

                          Comment


                          • #14
                            It seems to me the swapping of array pointer variables in the manner discussed has a built-in assumption about the array descriptor.
                            No, it does not.

                            However, it DOES have a built-in assumption about the way PB stores string Array (cap A) elements.

                            MCM
                            Michael Mattias
                            Tal Systems Inc.
                            Racine WI USA
                            mmattias@talsystems.com
                            http://www.talsystems.com

                            Comment


                            • #15
                              STRING Arrays:
                              Code:
                                LOCAL i AS LONG, aPos(), aNeg() AS STRING, pPos, pNeg AS DWORD PTR
                                LOCAL sBefore, sAfter AS STRING
                              
                                DIM aPos(9), aNeg(9)
                                FOR i = 0 TO 9
                                  aPos(i) = str$(+i*i)
                                  aNeg(i) = str$(-i*i)
                                NEXT
                              
                                pPos = VARPTR(aPos())
                                pNeg = VARPTR(aNeg())
                              
                                sBefore = " Before swap: aPos(2) = " + aPos(2) + $CRLF _
                                        + " VARPTR(aPos()),  VARPTR(aNeg())  :" + str$(VARPTR(aPos())) + "," + str$(VARPTR(aNeg())) + $CRLF _
                                        + " VARPTR(aPos(0)), VARPTR(aNeg(0)) :" + str$(VARPTR(aPos(0))) + "," + str$(VARPTR(aNeg(0))) + $CRLF _
                                        + " @pPos, @pNeg                     :" + str$(@pPos) + "," + str$(@pNeg)
                              
                                SWAP @pPos, @pNeg
                              
                                sAfter  = " After swap:  aPos(2) = " + aPos(2) + $CRLF _
                                        + " VARPTR(aPos()),  VARPTR(aNeg())  :" + str$(VARPTR(aPos())) + "," + str$(VARPTR(aNeg())) + $CRLF _
                                        + " VARPTR(aPos(0)), VARPTR(aNeg(0)) :" + str$(VARPTR(aPos(0))) + "," + str$(VARPTR(aNeg(0))) + $CRLF _
                                        + " @pPos, @pNeg                     :" + str$(@pPos) + "," + str$(@pNeg)
                              
                                MSGBOX sBefore + $CRLF + $CRLF + sAfter

                              LONG Arrays:
                              Code:
                                LOCAL i AS LONG, aPos(), aNeg() AS LONG, pPos, pNeg AS DWORD PTR
                                LOCAL sBefore, sAfter AS STRING
                              
                                DIM aPos(9), aNeg(9)
                                FOR i = 0 TO 9
                                  aPos(i) = +i*i
                                  aNeg(i) = -i*i
                                NEXT
                              
                                pPos = VARPTR(aPos())
                                pNeg = VARPTR(aNeg())
                              
                                sBefore = " Before swap: aPos(2) = " + str$(aPos(2)) + $CRLF _
                                        + " VARPTR(aPos()),  VARPTR(aNeg())  :" + str$(VARPTR(aPos())) + "," + str$(VARPTR(aNeg())) + $CRLF _
                                        + " VARPTR(aPos(0)), VARPTR(aNeg(0)) :" + str$(VARPTR(aPos(0))) + "," + str$(VARPTR(aNeg(0))) + $CRLF _
                                        + " @pPos, @pNeg                     :" + str$(@pPos) + "," + str$(@pNeg)
                              
                                SWAP @pPos, @pNeg
                              
                                sAfter  = " After swap:  aPos(2) = " + str$(aPos(2)) + $CRLF _
                                        + " VARPTR(aPos()),  VARPTR(aNeg())  :" + str$(VARPTR(aPos())) + "," + str$(VARPTR(aNeg())) + $CRLF _
                                        + " VARPTR(aPos(0)), VARPTR(aNeg(0)) :" + str$(VARPTR(aPos(0))) + "," + str$(VARPTR(aNeg(0))) + $CRLF _
                                        + " @pPos, @pNeg                     :" + str$(@pPos) + "," + str$(@pNeg)
                              
                                MSGBOX sBefore + $CRLF + $CRLF + sAfter

                              To be specific, I was referring to the assumption that the first four bytes of a PB Array descriptor holds the base address of the array (small ‘a’). Are the above codes not relying on that assumption?

                              Comment

                              Working...
                              X