/**
   * Get a table from PV
   *
   * <p>Ideally, the PV holds a {@link VTable}, and the returned data is then the table's data.
   *
   * <p>If the PV is a scalar, a table with a single cell is returned.
   *
   * <p>If the PV is an array, a table with one column is returned.
   *
   * @param value Value of a PV
   * @return List of rows, where each row contains either String or Number cells
   */
  @SuppressWarnings("rawtypes")
  public static List<List<Object>> getTable(final VType value) {
    final List<List<Object>> data = new ArrayList<>();
    if (value instanceof VTable) {
      final VTable table = (VTable) value;
      final int rows = table.getRowCount();
      final int cols = table.getColumnCount();
      // Extract 2D string matrix for data
      for (int r = 0; r < rows; ++r) {
        final List<Object> row = new ArrayList<>(cols);
        for (int c = 0; c < cols; ++c) {
          final Object col_data = table.getColumnData(c);
          if (col_data instanceof List) row.add(Objects.toString(((List) col_data).get(r)));
          else if (col_data instanceof ListDouble) row.add(((ListDouble) col_data).getDouble(r));
          else if (col_data instanceof ListNumber) row.add(((ListNumber) col_data).getLong(r));
          else row.add(Objects.toString(col_data));
        }
        data.add(row);
      }
    } else if (value instanceof VNumberArray) {
      final ListNumber numbers = ((VNumberArray) value).getData();
      final int num = numbers.size();
      for (int i = 0; i < num; ++i) data.add(Arrays.asList(numbers.getDouble(i)));
    } else if (value instanceof VNumber) data.add(Arrays.asList(((VNumber) value).getValue()));
    else data.add(Arrays.asList(Objects.toString(value)));

    return data;
  }
 /**
  * Get a table cell from PV
  *
  * <p>PV must hold a VTable
  *
  * @param value Value of a PV
  * @param row Row index, 0..
  * @param column Column index, 0..
  * @return Either String or Number for the cell's value, null if invalid row/column
  */
 @SuppressWarnings("rawtypes")
 public static Object getTableCell(final VType value, final int row, final int column) {
   if (value instanceof VTable) {
     final VTable table = (VTable) value;
     if (column >= table.getColumnCount() || row >= table.getRowCount()) return null;
     final Object col_data = table.getColumnData(column);
     if (col_data instanceof List) return Objects.toString(((List) col_data).get(row));
     else if (col_data instanceof ListDouble) return ((ListDouble) col_data).getDouble(row);
     else if (col_data instanceof ListNumber) return ((ListNumber) col_data).getLong(row);
     else return Objects.toString(col_data);
   } else return Objects.toString(value);
 }
 /**
  * Get labels for a {@link VEnum} value, or headers for a {@link VTable}.
  *
  * @param value Value of a PV
  * @return Enum labels or empty array if not enum nor table
  */
 public static String[] getLabels(final VType value) {
   if (value instanceof VEnum) {
     final List<String> labels = ((VEnum) value).getLabels();
     return labels.toArray(new String[labels.size()]);
   }
   if (value instanceof VTable) {
     final VTable table = (VTable) value;
     final int num = table.getColumnCount();
     final String[] headers = new String[num];
     for (int i = 0; i < num; ++i) headers[i] = table.getColumnName(i);
     return headers;
   }
   return new String[0];
 }