001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.util.struct;
006
007import java.util.Map;
008
009/** Raw struct dynamic field descriptor. */
010public class StructFieldDescriptor {
011  private static int toBitWidth(int size, int bitWidth) {
012    if (bitWidth == 0) {
013      return size * 8;
014    } else {
015      return bitWidth;
016    }
017  }
018
019  private static long toBitMask(int size, int bitWidth) {
020    if (size == 0) {
021      return 0;
022    } else {
023      return -1L >>> (64 - toBitWidth(size, bitWidth));
024    }
025  }
026
027  // does not fill in offset, shift
028  StructFieldDescriptor(
029      StructDescriptor parent,
030      String name,
031      StructFieldType type,
032      int size,
033      int arraySize,
034      int bitWidth,
035      Map<String, Long> enumValues,
036      StructDescriptor structDesc) {
037    m_parent = parent;
038    m_name = name;
039    m_size = size;
040    m_arraySize = arraySize;
041    m_enum = enumValues;
042    m_struct = structDesc;
043    m_bitMask = toBitMask(size, bitWidth);
044    m_type = type;
045    m_bitWidth = toBitWidth(size, bitWidth);
046  }
047
048  /**
049   * Gets the dynamic struct this field is contained in.
050   *
051   * @return struct descriptor
052   */
053  public StructDescriptor getParent() {
054    return m_parent;
055  }
056
057  /**
058   * Gets the field name.
059   *
060   * @return field name
061   */
062  public String getName() {
063    return m_name;
064  }
065
066  /**
067   * Gets the field type.
068   *
069   * @return field type
070   */
071  public StructFieldType getType() {
072    return m_type;
073  }
074
075  /**
076   * Returns whether the field type is a signed integer.
077   *
078   * @return true if signed integer, false otherwise
079   */
080  public boolean isInt() {
081    return m_type.isInt;
082  }
083
084  /**
085   * Returns whether the field type is an unsigned integer.
086   *
087   * @return true if unsigned integer, false otherwise
088   */
089  public boolean isUint() {
090    return m_type.isUint;
091  }
092
093  /**
094   * Gets the underlying storage size of the field, in bytes.
095   *
096   * @return number of bytes
097   */
098  public int getSize() {
099    return m_size;
100  }
101
102  /**
103   * Gets the storage offset of the field, in bytes.
104   *
105   * @return number of bytes from the start of the struct
106   */
107  public int getOffset() {
108    return m_offset;
109  }
110
111  /**
112   * Gets the bit width of the field, in bits.
113   *
114   * @return number of bits
115   */
116  public int getBitWidth() {
117    return m_bitWidth == 0 ? m_size * 8 : m_bitWidth;
118  }
119
120  /**
121   * Gets the bit mask for the field. The mask is always the least significant bits (it is not
122   * shifted).
123   *
124   * @return bit mask
125   */
126  public long getBitMask() {
127    return m_bitMask;
128  }
129
130  /**
131   * Gets the bit shift for the field (LSB=0).
132   *
133   * @return number of bits
134   */
135  public int getBitShift() {
136    return m_bitShift;
137  }
138
139  /**
140   * Returns whether the field is an array.
141   *
142   * @return true if array
143   */
144  public boolean isArray() {
145    return m_arraySize > 1;
146  }
147
148  /**
149   * Gets the array size. Returns 1 if non-array.
150   *
151   * @return number of elements
152   */
153  public int getArraySize() {
154    return m_arraySize;
155  }
156
157  /**
158   * Returns whether the field has enumerated values.
159   *
160   * @return true if there are enumerated values
161   */
162  public boolean hasEnum() {
163    return m_enum != null;
164  }
165
166  /**
167   * Gets the enumerated values.
168   *
169   * @return set of enumerated values
170   */
171  public Map<String, Long> getEnumValues() {
172    return m_enum;
173  }
174
175  /**
176   * Gets the struct descriptor for a struct data type.
177   *
178   * @return struct descriptor; returns null for non-struct
179   */
180  public StructDescriptor getStruct() {
181    return m_struct;
182  }
183
184  /**
185   * Gets the minimum unsigned integer value that can be stored in this field.
186   *
187   * @return minimum value
188   */
189  public long getUintMin() {
190    return 0;
191  }
192
193  /**
194   * Gets the maximum unsigned integer value that can be stored in this field. Note this is not the
195   * actual maximum for uint64 (due to Java lacking support for 64-bit unsigned integers).
196   *
197   * @return maximum value
198   */
199  public long getUintMax() {
200    return m_bitMask;
201  }
202
203  /**
204   * Gets the minimum signed integer value that can be stored in this field.
205   *
206   * @return minimum value
207   */
208  public long getIntMin() {
209    return (-(m_bitMask >> 1)) - 1;
210  }
211
212  /**
213   * Gets the maximum signed integer value that can be stored in this field.
214   *
215   * @return maximum value
216   */
217  public long getIntMax() {
218    return m_bitMask >> 1;
219  }
220
221  /**
222   * Returns whether the field is a bitfield.
223   *
224   * @return true if bitfield
225   */
226  public boolean isBitField() {
227    return m_bitShift != 0 || m_bitWidth != (m_size * 8);
228  }
229
230  private final StructDescriptor m_parent;
231  private final String m_name;
232  int m_size;
233  int m_offset;
234  final int m_arraySize; // 1 for non-arrays
235  private final Map<String, Long> m_enum;
236  private final StructDescriptor m_struct; // null for non-structs
237  private final long m_bitMask;
238  private final StructFieldType m_type;
239  private final int m_bitWidth;
240  int m_bitShift;
241}