us.ihmc.idl.IDLSequence Maven / Gradle / Ivy
/**
* Copyright 2024 Florida Institute for Human and Machine Cognition (IHMC)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package us.ihmc.idl;
import org.apache.commons.lang3.NotImplementedException;
import gnu.trove.list.array.TByteArrayList;
import gnu.trove.list.array.TCharArrayList;
import gnu.trove.list.array.TDoubleArrayList;
import gnu.trove.list.array.TFloatArrayList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.list.array.TLongArrayList;
import gnu.trove.list.array.TShortArrayList;
import us.ihmc.commons.lists.PreallocatedEnumList;
import us.ihmc.commons.lists.RecyclingArrayList;
import us.ihmc.pubsub.TopicDataType;
import java.nio.ByteBuffer;
/**
* Represents an IDL sequence.
*
* The current implementation of this class extends ArrayList. Primitive versions are provided as subclasses and extend Trove ArrayLists.
* By providing a custom interface to ArrayList we can adjust the type to more efficient storage should the need arise.
*
* @author Jesper Smith
*/
public interface IDLSequence
{
public static class Boolean extends TByteArrayList implements IDLSequence
{
public static final byte True = 1;
public static final byte False = 0;
private final int maxSize;
public Boolean(int maxSize, String typeCode)
{
super(maxSize);
if (!typeCode.equals("type_7"))
{
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
public void add(boolean value)
{
add(value ? True : False);
}
public boolean getBoolean(int offset)
{
return get(offset) == True;
}
public void set(int offset, boolean b)
{
set(offset, b?True : False);
}
@Override
public void readElement(int i, CDR cdr)
{
add(cdr.read_type_7());
}
@Override
public void writeElement(int i, CDR cdr)
{
cdr.write_type_7(getBoolean(i));
}
public void set(Boolean other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(getBoolean(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Byte implements IDLSequence
{
/**
* The backing buffer as a heap array.
* We only use the position and capacity. We do not use the limit or mark.
* The position is used as the size and capacity is the max message size
* and is final after construction.
*/
private final ByteBuffer buffer;
public Byte(int maxSize, String typeCode)
{
if (!typeCode.equals("type_9"))
{
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
buffer = ByteBuffer.allocate(maxSize);
}
@Override
public void readElement(int i, CDR cdr)
{
// unused for faster copy method
}
@Override
public void writeElement(int i, CDR cdr)
{
// unused for faster copy method
}
public void set(Byte other)
{
buffer.position(other.buffer.position());
System.arraycopy(other.buffer.array(), 0, buffer.array(), 0, other.size());
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(buffer.get(i));
}
builder.append("]");
return builder.toString();
}
public void add(byte value)
{
buffer.put(value);
}
public void add(byte[] values)
{
buffer.put(values);
}
public void add(byte[] src, int offset, int length)
{
buffer.put(src, offset, length);
}
public void set(int index, byte value)
{
buffer.put(index, value);
}
public byte get(int i)
{
return buffer.get(i);
}
/**
* For accessing the putDouble, getDouble, etc. fancy methods.
* Only use put and get methods. Do not mess with the mark or limit.
*/
public ByteBuffer getBuffer()
{
return buffer;
}
public byte[] copyArray()
{
byte[] copy = new byte[size()];
System.arraycopy(buffer.array(), 0, copy, 0, copy.length);
return copy;
}
public ByteBuffer copyByteBuffer()
{
return ByteBuffer.wrap(copyArray());
}
@Override
public void resetQuick()
{
buffer.position(0);
}
@Override
public int size()
{
return buffer.position();
}
@Override
public int capacity()
{
return buffer.capacity();
}
public boolean isEmpty()
{
return size() == 0;
}
@Override
public boolean equals(java.lang.Object other)
{
if (other == this)
{
return true;
}
else if (other instanceof IDLSequence.Byte otherSequence)
{
if (otherSequence.size() != this.size())
return false;
else
{
for (int i = size(); i-- > 0; )
{
if (buffer.get(i) != otherSequence.buffer.get(i))
{
return false;
}
}
return true;
}
}
else
return false;
}
}
public static class Char extends TCharArrayList implements IDLSequence
{
private final int type;
private final int maxSize;
public Char(int maxSize, String typeCode)
{
super(maxSize);
switch (typeCode)
{
case "type_8":
type = 8;
break;
case "type_14":
type = 14;
break;
default:
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
switch (type)
{
case 8:
add(cdr.read_type_8());
break;
case 14:
add(cdr.read_type_14());
break;
}
}
@Override
public void writeElement(int i, CDR cdr)
{
switch (type)
{
case 8:
cdr.write_type_8(get(i));
break;
case 14:
cdr.write_type_14(get(i));
break;
}
}
public void set(Char other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Short extends TShortArrayList implements IDLSequence
{
private final int maxSize;
public Short(int maxSize, String typeCode)
{
super(maxSize);
if (!typeCode.equals("type_1"))
{
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
add(cdr.read_type_1());
}
@Override
public void writeElement(int i, CDR cdr)
{
cdr.write_type_1(get(i));
}
public void set(Short other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Integer extends TIntArrayList implements IDLSequence
{
private final int type;
private final int maxSize;
public Integer(int maxSize, String typeCode)
{
super(maxSize);
switch (typeCode)
{
case "type_2":
type = 2;
break;
case "type_3":
type = 3;
break;
default:
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
switch (type)
{
case 2:
add(cdr.read_type_2());
break;
case 3:
add(cdr.read_type_3());
break;
}
}
@Override
public void writeElement(int i, CDR cdr)
{
switch (type)
{
case 2:
cdr.write_type_2(get(i));
break;
case 3:
cdr.write_type_3(get(i));
break;
}
}
public void set(Integer other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Long extends TLongArrayList implements IDLSequence
{
private final int type;
private final int maxSize;
public Long(int maxSize, String typeCode)
{
super(maxSize);
switch (typeCode)
{
case "type_11":
type = 11;
break;
case "type_12":
type = 12;
break;
case "type_4":
type = 4;
break;
default:
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
switch (type)
{
case 11:
add(cdr.read_type_11());
break;
case 12:
add(cdr.read_type_12());
break;
case 4:
add(cdr.read_type_4());
break;
}
}
@Override
public void writeElement(int i, CDR cdr)
{
switch (type)
{
case 11:
cdr.write_type_11(get(i));
break;
case 12:
cdr.write_type_12(get(i));
break;
case 4:
cdr.write_type_4(get(i));
break;
}
}
public void set(Long other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Float extends TFloatArrayList implements IDLSequence
{
private final int maxSize;
public Float(int maxSize, String typeCode)
{
super(maxSize);
if (!typeCode.equals("type_5"))
{
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
add(cdr.read_type_5());
}
@Override
public void writeElement(int i, CDR cdr)
{
cdr.write_type_5(get(i));
}
public void set(Float other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class Double extends TDoubleArrayList implements IDLSequence
{
private final int maxSize;
public Double(int maxSize, String typeCode)
{
super(maxSize);
if (!typeCode.equals("type_6"))
{
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
this.maxSize = maxSize;
}
@Override
public void readElement(int i, CDR cdr)
{
add(cdr.read_type_6());
}
@Override
public void writeElement(int i, CDR cdr)
{
cdr.write_type_6(get(i));
}
public void set(Double other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public int capacity()
{
return maxSize;
}
}
public static class StringBuilderHolder extends RecyclingArrayList implements IDLSequence
{
private final int type;
/**
* @param maxSize Preallocate elements
* @param typeCode Can be "type_d" (idl type string) or "type_15" (idl type wstring)
*/
public StringBuilderHolder(int maxSize, String typeCode)
{
super(maxSize, StringBuilder::new);
switch (typeCode)
{
case "type_d":
type = 0xd;
break;
case "type_15":
type = 0x15;
break;
default:
throw new NotImplementedException(typeCode + " is not implemented for Sequence");
}
}
@Override
public void resetQuick()
{
clear();
}
@Override
public int capacity()
{
return java.lang.Integer.MAX_VALUE;
}
@Override
public void readElement(int i, CDR cdr)
{
StringBuilder res = add();
switch (type)
{
case 0xd:
cdr.read_type_d(res);
break;
case 0x15:
cdr.read_type_15(res);
break;
}
}
@Override
public void writeElement(int i, CDR cdr)
{
switch (type)
{
case 0xd:
cdr.write_type_d(get(i));
break;
case 0x15:
cdr.write_type_15(get(i));
break;
}
}
/**
* Directly add a string value.
*
* @param string
*/
public void add(String string)
{
StringBuilder elem = add();
elem.setLength(0);
elem.append(string);
}
/**
* Get value at index i as string
*
* @param i index
* @return string value corresponding to index i
*/
public String getString(int i)
{
return get(i).toString();
}
public void set(StringBuilderHolder other)
{
resetQuick();
for(int i = 0; i < other.size(); i++)
{
StringBuilder add = add();
add.delete(0, add.length());
add.append(other.get(i));
}
}
/**
* Create a new string array with all elements in this sequence.
*
* @return string array
*/
public String[] toStringArray()
{
String[] dest = new String[size()];
toArray(dest);
return dest;
}
/**
* Copy the data into a string array
*
* @param dest string array of length > size()
*/
public void toArray(String[] dest)
{
if(dest.length < size())
{
throw new IndexOutOfBoundsException("Cannot copy data in destination array, insufficient space.");
}
for(int i = 0; i < size(); i++)
{
dest[i] = getString(i);
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
@Override
public boolean equals(java.lang.Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
StringBuilderHolder other = (StringBuilderHolder) obj;
if(size() != other.size())
return false;
for(int i = 0; i < size(); i++)
{
if(!IDLTools.equals(get(i), other.get(i)))
return false;
}
return true;
}
}
/**
* Generic enum type for IDL sequences.
*
* @param Element type
* @author Jesper Smith
*/
@SuppressWarnings("rawtypes")
public static class Enum extends PreallocatedEnumList implements IDLSequence
{
/**
*
* @param maxSize Maximum size of this sequence
* @param clazz Class to store
* @param constants Enum constants
*/
public Enum(int maxSize, Class clazz, T[] constants)
{
super(clazz, constants, maxSize);
}
@SuppressWarnings("unchecked")
@Override
public void readElement(int i, CDR cdr)
{
add((T) getEnumConstants()[cdr.read_type_c()]);
}
@Override
public void writeElement(int i, CDR cdr)
{
cdr.write_type_c(((java.lang.Enum) get(i)).ordinal());
}
public void set(Enum other)
{
clear();
for(int i = 0; i < other.size(); i++)
{
add(other.get(i));
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
}
/**
* Generic object for IDL sequences.
*
* @author Jesper Smith
*
* @param Element type
*/
public static class Object extends RecyclingArrayList implements IDLSequence
{
private final TopicDataType topicDataType;
/**
* @deprecated Use {@link IDLSequence(int, TopicDataType)} instead.
*
* @param maxSize Maximum size of this sequence
* @param clazz Class to store
* @param topicDataType TopicDataType to preallocate data if desired
*/
public Object(int maxSize, Class clazz, TopicDataType topicDataType)
{
this(maxSize, topicDataType);
}
/**
*
* @param maxSize Maximum size of this sequence
* @param topicDataType TopicDataType to preallocate data if desired
*/
public Object(int maxSize, TopicDataType topicDataType)
{
super(maxSize, topicDataType::createData);
this.topicDataType = topicDataType;
}
@Override
public void resetQuick()
{
clear();
}
@Override
public int capacity()
{
return java.lang.Integer.MAX_VALUE;
}
@Override
public void readElement(int i, CDR cdr)
{
T val = add();
topicDataType.deserialize(val, cdr);
}
@Override
public void writeElement(int i, CDR cdr)
{
topicDataType.serialize(get(i), cdr);
}
public void set(Object other)
{
clear();
for (int i = 0; i < other.size(); i++)
{
T val = add();
topicDataType.copy(other.get(i), val);
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
for(int i = 0; i < size(); i++)
{
if(i > 0)
{
builder.append(", ");
}
builder.append(get(i));
}
builder.append("]");
return builder.toString();
}
public TopicDataType getTopicDataType()
{
return topicDataType;
}
}
/**
* Set the current position to zero.
*
* The internal elements will not get reset to their default values.
* Newly added elements will retain values from the old elements.
*
*
*/
public void resetQuick();
/**
*
* @return the current number of elements in this sequence
*/
public int size();
/**
*
* @return the maximum number of elements in this sequence
*/
public int capacity();
/**
*
* @return the remaining space in this sequence (capacity() - size())
*/
default int remaining()
{
return capacity() - size();
}
/**
* Internal function to deserialize
*
* @param i
* @param cdr
*/
public void readElement(int i, CDR cdr);
/**
* Internal function to serialize
*
* @param i
* @param cdr
*/
public void writeElement(int i, CDR cdr);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy