OpenOffice BASIC: Create an independent copy of an array.

Shared Libraries
Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This section is not for asking questions about writing your own macros.
Post Reply
User avatar
Lupp
Volunteer
Posts: 3542
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

OpenOffice BASIC: Create an independent copy of an array.

Post by Lupp »

===Editing again 2021-12-30===
Due to a recent request I want to explicitly state that arrays being elements of an array copied the way described here should be expected to be result of an internal assignment by reference, as is standard for arrays.
In different words: The deep copy will not propagate to the elements of nested arrays.
===End Edit 2021-12-30===

Editing:
I have to apologize for insufficient verification of the code. It did not work correctly in an example "JeJe" provided.
I will replace it now with a slightly reworked version working correctly for me in LibO V6.0.3 and also in AOO V4.1.5.
Be careful, please. I cannot give any guarantee. Errors still expected!

In addition I attach a .ods file containing the test by JeJe, the reworked code, and an enhanced version for arrays up to 5 dimensions.
arrayCopyByVal_1.ods
(11.81 KiB) Downloaded 460 times
Start of the original text:[/i]

Arrays (and structures) are generally assigned to variables by reference in OpenOffice BASIC (and beyond). Hence I am only talking about arrays. I will recap in short what "by reference" means.

If the variable A is declared by A(0 To 3, 1 To 2) e.g. and you make an assignmen B = A then accessing B does exactly the same as accessing A. A(1,2) = 3 will force B(1,2) to also have the value 3. A subsequent B(1,2) = "Z" will cause A(1,2) to return "Z".

This is often the desired behaviour. Think alone of storage efficiency. It involves, however, that an array passed to a routine (Sub, Function) via a parameter specified with the ByVal clause also only can get the reference where it is not of high importance if this reference is primarily one to the varibale you access the array with or directly to the array.

On the other hand there are cases where you want to create a new array B and to only inititialize it with the contents of A while both the names actually shall give access to two arrays whose elements can be changed independently afterwards.

Since I today considered this anew and got an idea how to avoid the need of copying elments one by one explicitly in a way I not yet had seen, I want to present the solution to you and to request for your comments and criticisms. See code below.

Code: Select all

Function createArrayCopy2D(p2D)
REM Returns a reference to a newly created copy of the passed array.
REM BE CAREFUL! This is not based on profound knowledge of any specifications
REM for LibreOffice BASIC, not to speak of any knowledge of its interpreter's code.
REM This is based on speculative testing. New testers please report contradictory results.
If NOT IsArray(p2D)  Then Exit Function
If NOT (dimensionality(p2D)=2) Then Exit Function
dummy = p2D
l = Array(Lbound(dummy,1), Lbound(dummy,2)
u = Array(Ubound(dummy,1), Ubound(dummy,2)
Redim Preserve dummy(l(0) To u(0), l(1) To u(1))
REM The Redim command does not test if any dimnsion is actually changed.
REM By way of precaution it creates a copy with ReferenceCounter=1
REM and decrements the ReferenceCounter of the source by 1.
REM This way the calling position will get returned a reference to the copy
REM while the source array wherever referenced in advance will be unchanged.
createArrayCopy2D = dummy
End Function

Function dimensionality(pArray)
REM Returns the dimensionality of an array.
dim d As Long ' The code relies on the initialization with 0.
If NOT IsArray(pArray) Then Exit Function
On Local Error Goto doneExit
REM Below the Ubound() function is only used to raise an error when needed.
REM Its result, if returned, gets annulled.
Do
    d = Ubound(pArray, d+1)*0 + d + 1 
Loop 
doneExit:
dimensionality = d
End Function 
This is specialized to arrays of exactly 2 dimensions. To do it for only one or for more dimensions (up to a reasonable limit) is also feasible.
Last edited by Lupp on Thu Dec 30, 2021 2:23 pm, edited 6 times in total.
On Windows 10: LibreOffice 24.2 (new numbering) and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
JeJe
Volunteer
Posts: 2764
Joined: Wed Mar 09, 2016 2:40 pm

Re: OpenOffice BASIC: Create an independent copy of an array

Post by JeJe »

Doesn't work here - try this test code.

Code: Select all


sub tmp

dim aa(0 to 50,0 to 40)

aa(10,10) =80
dim bb(0 to 50,0 to 40)
bb = createArrayCopy2D(aa)
aa(10,10) =50
msgbox bb(10,10) 'result is 50 not 80
end sub


Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 2764
Joined: Wed Mar 09, 2016 2:40 pm

Re: OpenOffice BASIC: Create an independent copy of an array

Post by JeJe »

On Windows the CopyMemory Api function is a way of copying all the values in one array to another... but testing that, it works for a single item of an array but not the whole array. So - presumably OO array items aren't stored in contiguous memory locations.

I notice if you make an assignment array2 = array1 and then Erase array1 then array2 isn't erased. OO array variables appear to be pointers to an array and its maybe not possible to do what you want to do here. OO is alway going to be copying the pointer to the array... never making a new array.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
User avatar
Lupp
Volunteer
Posts: 3542
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

Re: OpenOffice BASIC: Create an independent copy of an array

Post by Lupp »

Hallo JeJe,

Thank yopu very much for testing - and bashful apologies for my prematurely pasting insufficiently verified code.

I do not fully understand the problem. When I wrote and tested the functions (And it worked!) there were a few more assignment of the relevant array to different variables, among them a few indexed variables (array elements). Probably this has influenced parts of the environment.

Since i don't know a documentation on which I might base further development, I could only try a solution based on guessing again. Now there is an intermediary variable inside the relevant function serving to give access to the original array over a bridge that is burnt finally when the function is left.

And now your test suggests correct working - for the example.
I would not yet rely on the method with crucial tasks.

Please see the reworked code contained in the .ods I will attach now to my first post.

Apologies again!
On Windows 10: LibreOffice 24.2 (new numbering) and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
JeJe
Volunteer
Posts: 2764
Joined: Wed Mar 09, 2016 2:40 pm

Re: OpenOffice BASIC: Create an independent copy of an array

Post by JeJe »

That works... redim preserve creates a new copy of the array - well spotted. This seems to work too...

Code: Select all


dim aa(0 to 50,0 to 40), bb(0 to 50,0 to 40)
aa(10,10) =80
bb = aa 
redim preserve bb(0 to 50,0 to 40) 'or redim preserve aa 
aa(10,10) =50
msgbox aa(10,10)
msgbox bb(10,10)
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
User avatar
Lupp
Volunteer
Posts: 3542
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

Re: OpenOffice BASIC: Create an independent copy of an array

Post by Lupp »

JeJe wrote:That works... redim preserve creates a new copy of the array - well spotted. This seems to work too...

Code: Select all

dim aa(0 to 50,0 to 40), bb(0 to 50,0 to 40)
aa(10,10) =80
bb = aa 
redim preserve bb(0 to 50,0 to 40) 'or redim preserve aa 
aa(10,10) =50
msgbox aa(10,10)
msgbox bb(10,10)
Yes. I think I chose the function approach to get a containment for calls to helper functions (from my little framework of array-related routines). Since these functions were not included here, and aren't actually in a shape to do it, the createArrayCopys?? functions may look a bit hollow. But generally a function createArrayCopy should be able to work on all kinds of Basic arrays (any dimnsionality or, say, up to 5 dimesions) and probably even on API-arrays like the .DataArray of a SheetCellRange.

Everything would be a lot simpler if an existing variable (b) having assigned a pre-existing different array variable the ByRef way was detached from the group of variables referencing the same data-container by a simple Redim Preseve b without a need to explicitly give the index ranges.
I tried this and that in a few cases in Libreoffice, but the behavior was inconsistent.
See also:
https://bugs.documentfoundation.org/sho ... ?id=134712 and
https://bugs.documentfoundation.org/sho ... ?id=134692
On Windows 10: LibreOffice 24.2 (new numbering) and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
User avatar
MrProgrammer
Moderator
Posts: 4895
Joined: Fri Jun 04, 2010 7:57 pm
Location: Wisconsin, USA

Re: OpenOffice BASIC: Create an independent copy of an array

Post by MrProgrammer »

More examples and pitfalls of copying an array are in Pitonyak's Miscellaneous Topics In Macro Programming
Mr. Programmer
AOO 4.1.7 Build 9800, MacOS 13.6.3, iMac Intel.   The locale for any menus or Calc formulas in my posts is English (USA).
User avatar
Lupp
Volunteer
Posts: 3542
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

Re: OpenOffice BASIC: Create an independent copy of an array

Post by Lupp »

Clearance regarding my previous post.

The relevant new one of the linked bugs (tdf#134692) afflicting the routine I posted in this snippets-thread only lived in a few prereleases of LibO V7.0. It is fixed and the fix verified to my satisfaction. The bug will not afflict any release version of LibO.

The other bug I reported is also treated as RESOLVED with type WONTFIX. You may read the short discussion there if interested. (A highly efficient deep copy for arrays without a Redim Preserve as is and thus without the need to know exactly the dimensionality and dimensions does therefore still not exist.)
On Windows 10: LibreOffice 24.2 (new numbering) and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
Post Reply