Skip to content

Commit 84f83d7

Browse files
authored
Merge pull request #2541 from jacomago/pvaUnionArray
Adding the PVAAnyArray,
2 parents 8fcfbb2 + 3bff846 commit 84f83d7

File tree

5 files changed

+343
-2
lines changed

5 files changed

+343
-2
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 European Spallation Source ERIC.
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18+
*/
19+
20+
package org.epics.pva.data;
21+
22+
import java.nio.ByteBuffer;
23+
import java.util.Arrays;
24+
import java.util.BitSet;
25+
import java.util.logging.Level;
26+
27+
import static org.epics.pva.PVASettings.logger;
28+
29+
/** PV Access structure
30+
*
31+
* <p>Holds one or more {@link PVAny} elements.
32+
*/
33+
public class PVAAnyArray extends PVADataWithID implements PVAArray{
34+
35+
/**
36+
* Empty array constructor
37+
* @param name Name
38+
*/
39+
public PVAAnyArray(String name) {
40+
super(name);
41+
}
42+
43+
/** Basic constructor
44+
*
45+
* @param name Name
46+
* @param elements Initial elements
47+
*/
48+
public PVAAnyArray(String name, final PVAny... elements) {
49+
super(name);
50+
this.elements = elements;
51+
}
52+
53+
/** Unmodifiable list of elements.
54+
*
55+
* <p>The value of each element may be updated, but
56+
* no elements can be added, removed, replaced.
57+
*/
58+
private volatile PVAny[] elements;
59+
60+
@Override
61+
public void setValue(Object new_value) throws Exception {
62+
63+
// Cannot set array, only individual elements
64+
throw new Exception("Cannot set " + getType() + " " + name + " to " + new_value);
65+
}
66+
67+
/** @return Current value */
68+
public PVAny[] get()
69+
{
70+
return elements;
71+
}
72+
73+
@Override
74+
public PVAData cloneType(String name) {
75+
return new PVAAnyArray(name);
76+
}
77+
78+
@Override
79+
public PVAAnyArray cloneData() {
80+
final PVAny[] safe = elements;
81+
final PVAny[] copy = new PVAny[safe.length];
82+
// Deep copy
83+
for (int i=0; i<copy.length; ++i)
84+
copy[i] = safe[i].cloneData();
85+
return new PVAAnyArray(name, copy);
86+
}
87+
88+
@Override
89+
public void encodeType(ByteBuffer buffer, BitSet described) throws Exception {
90+
final short type_id = getTypeID();
91+
if (type_id != 0) {
92+
final int u_type_id = Short.toUnsignedInt(type_id);
93+
if (described.get(u_type_id))
94+
{ // Refer to existing definition
95+
buffer.put(PVAFieldDesc.ONLY_ID_TYPE_CODE);
96+
buffer.putShort(type_id);
97+
// Done!
98+
return;
99+
}
100+
else
101+
{ // (Re-)define this type
102+
buffer.put(PVAFieldDesc.FULL_WITH_ID_TYPE_CODE);
103+
buffer.putShort(type_id);
104+
described.set(u_type_id);
105+
}
106+
}
107+
108+
// Encode 'any array'
109+
buffer.put((byte) (PVAComplex.FIELD_DESC_TYPE | PVAFieldDesc.Array.VARIABLE_SIZE.mask | PVAComplex.VARIANT_UNION));
110+
}
111+
112+
@Override
113+
public void decode(PVATypeRegistry types, ByteBuffer buffer) throws Exception {
114+
115+
final int count = PVASize.decodeSize(buffer);
116+
// Try to re-use elements
117+
PVAny[] new_elements = elements;
118+
if (new_elements == null || new_elements.length != count)
119+
new_elements = new PVAny[count];
120+
for (int i=0; i<count; ++i)
121+
{ // Is this element non-null?
122+
final boolean non_null = PVABool.decodeBoolean(buffer);
123+
if (non_null)
124+
{ // Try to update existing element
125+
PVAny element = new_elements[i];
126+
if (element == null)
127+
element = new PVAny("any");
128+
element.decode(types, buffer);
129+
new_elements[i] = element;
130+
}
131+
else
132+
new_elements[i] = null;
133+
}
134+
elements = new_elements;
135+
logger.log(Level.FINER, () -> "Decoded any[] element: " + elements);
136+
}
137+
138+
@Override
139+
public void encode(ByteBuffer buffer) throws Exception {
140+
141+
final PVAny[] copy = elements;
142+
PVASize.encodeSize(copy.length, buffer);
143+
for (PVAny pvAny : copy) {
144+
if (pvAny == null)
145+
PVABool.encodeBoolean(false, buffer);
146+
else {
147+
PVABool.encodeBoolean(true, buffer);
148+
pvAny.encode(buffer);
149+
}
150+
}
151+
}
152+
153+
@Override
154+
protected int update(int index, PVAData new_value, BitSet changes) throws Exception {
155+
156+
if (new_value instanceof PVAAnyArray)
157+
{
158+
final PVAAnyArray other = (PVAAnyArray) new_value;
159+
if (! Arrays.equals(other.elements, elements))
160+
{
161+
// Deep copy
162+
final PVAny[] copy = new PVAny[other.elements.length];
163+
for (int i=0; i<copy.length; ++i)
164+
copy[i] = other.elements[i].cloneData();
165+
this.elements = copy;
166+
changes.set(index);
167+
}
168+
}
169+
return index + 1;
170+
}
171+
172+
@Override
173+
protected void format(int level, StringBuilder buffer) {
174+
175+
indent(level, buffer);
176+
buffer.append(getType());
177+
buffer.append(name);
178+
for (PVAData element : elements)
179+
{
180+
buffer.append("\n");
181+
element.format(level+1, buffer);
182+
}
183+
}
184+
185+
@Override
186+
public String getType() {
187+
return "any[]";
188+
}
189+
190+
@Override
191+
public boolean equals(Object obj) {
192+
if (! (obj instanceof PVAAnyArray))
193+
return false;
194+
final PVAAnyArray other = (PVAAnyArray) obj;
195+
return Arrays.equals(other.elements, elements);
196+
}
197+
}

core/pva/src/main/java/org/epics/pva/data/PVAComplex.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ else if (cplx == VARIANT_UNION)
3737
{
3838
if (array == PVAFieldDesc.Array.SCALAR)
3939
return new PVAny(name);
40-
throw new Exception("Cannot handle " + array + " any '" + name + "'");
40+
else if (array == PVAFieldDesc.Array.VARIABLE_SIZE)
41+
return new PVAAnyArray(name);
42+
throw new Exception("Cannot handle " + array + " any '" + name + "'"); //
4143
}
4244
else if (cplx == UNION)
4345
{

core/pva/src/main/java/org/epics/pva/data/PVAStructureArray.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ protected int update(final int index, final PVAData new_value, final BitSet chan
184184
final PVAStructure[] copy = new PVAStructure[other.elements.length];
185185
for (int i=0; i<copy.length; ++i)
186186
copy[i] = other.elements[i].cloneData();
187+
this.elements = copy;
187188
changes.set(index);
188189
}
189190
}
@@ -230,6 +231,6 @@ public boolean equals(final Object obj)
230231
if (! (obj instanceof PVAStructureArray))
231232
return false;
232233
final PVAStructureArray other = (PVAStructureArray) obj;
233-
return other.elements.equals(elements);
234+
return Arrays.equals(other.elements, elements);
234235
}
235236
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 European Spallation Source ERIC.
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18+
*/
19+
20+
package org.epics.pva.data;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import java.nio.ByteBuffer;
25+
import java.util.BitSet;
26+
27+
import static org.junit.jupiter.api.Assertions.*;
28+
29+
class PVAAnyArrayTest {
30+
31+
@Test
32+
void decodeType() throws Exception {
33+
PVAAnyArray pvaAnyArray = new PVAAnyArray("name");
34+
ByteBuffer buffer = ByteBuffer.allocate(200);
35+
pvaAnyArray.encodeType(buffer, new BitSet());
36+
buffer.flip();
37+
PVATypeRegistry registry = new PVATypeRegistry();
38+
PVAData data = registry.decodeType("name", buffer);
39+
assertEquals(data.getClass(), pvaAnyArray.getClass());
40+
}
41+
42+
@Test
43+
void cloneType() {
44+
PVAAnyArray pvaAnyArray = new PVAAnyArray("name");
45+
PVAData data = pvaAnyArray.cloneType("name2");
46+
assertEquals(data.getClass(), pvaAnyArray.getClass());
47+
48+
}
49+
50+
@Test
51+
void decode() throws Exception {
52+
PVAny[] anys = new PVAny[2];
53+
anys[0] = new PVAny("any0", new PVAString("string0", "stringValue0"));
54+
anys[1] = new PVAny("any1", new PVAInt("int1", 1));
55+
PVAAnyArray pvaAnyArray = new PVAAnyArray("variantArray", anys);
56+
57+
58+
ByteBuffer buffer = ByteBuffer.allocate(200);
59+
pvaAnyArray.encode(buffer);
60+
buffer.flip();
61+
62+
PVAAnyArray newArray = new PVAAnyArray("variantArray");
63+
newArray.decode(new PVATypeRegistry(), buffer);
64+
65+
assertEquals(newArray, pvaAnyArray);
66+
}
67+
68+
@Test
69+
void format() {
70+
PVAny[] anys = new PVAny[2];
71+
anys[0] = new PVAny("any0", new PVAString("string0", "stringValue0"));
72+
anys[1] = new PVAny("any1", new PVAInt("int1", 1));
73+
PVAAnyArray pvaAnyArray = new PVAAnyArray("variantArray", anys);
74+
75+
System.out.println(pvaAnyArray);
76+
assertFalse(pvaAnyArray.format().isEmpty());
77+
78+
}
79+
80+
@Test
81+
void update() throws Exception {
82+
PVAny[] anys = new PVAny[2];
83+
PVAStructure structure = new PVAStructure("structure0", "struct 0", new PVAString("element0", "element0value"));
84+
anys[0] = new PVAny("any s", structure);
85+
anys[1] = new PVAny("any string", new PVAString("element1", "valueElement1"));
86+
PVAAnyArray anyArray = new PVAAnyArray("anyArray", anys );
87+
88+
PVAAnyArray cloneArray = anyArray.cloneData();
89+
cloneArray.get()[1].get().setValue(new PVAString("element1", "newElement2"));
90+
91+
anyArray.update(0, cloneArray, new BitSet());
92+
93+
assertEquals(cloneArray, anyArray);
94+
}
95+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 European Spallation Source ERIC.
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18+
*/
19+
20+
package org.epics.pva.data;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import java.util.BitSet;
25+
26+
import static org.junit.jupiter.api.Assertions.*;
27+
28+
class PVAStructureArrayTest {
29+
30+
@Test
31+
void update() throws Exception {
32+
PVAStructure[] structures = new PVAStructure[2];
33+
structures[0] = new PVAStructure("structure0", "struct 0", new PVAString("element0", "element0value"));
34+
PVAStructure second = structures[0].cloneType("structure1");
35+
second.get("element0").setValue(new PVAString("element0", "newElement1"));
36+
structures[1] = second;
37+
PVAStructureArray structureArray = new PVAStructureArray("structureArray", structures[0].cloneType("stype"),structures );
38+
39+
PVAStructureArray cloneArray = structureArray.cloneData();
40+
cloneArray.get()[0].get("element0").setValue(new PVAString("element0", "newElement2"));
41+
42+
structureArray.update(0, cloneArray, new BitSet());
43+
44+
assertEquals(cloneArray, structureArray);
45+
}
46+
}

0 commit comments

Comments
 (0)