docs: @VisibleForTesting
    static String trimFieldsAndRemoveEmptyFields(String str) {
      char[] chars = str.toCharArray();
      char[] res = new char[chars.length];
      /*
       * set when reading the first non trimmable char after a separator char (or the beginning of the string)
       * unset when reading a separator
       */
      boolean inField = false;
      boolean inQuotes = false;
      int i = 0;
      int resI = 0;
      for (; i < chars.length; i++) {
        boolean isSeparator = chars[i] == ',';
        if (!inQuotes && isSeparator) {
          // exiting field (may already be unset)
          inField = false;
          if (resI > 0) {
            resI = retroTrim(res, resI);
          }
        } else {
          boolean isTrimmed = !inQuotes && istrimmable(chars[i]);
          if (isTrimmed && !inField) {
            // we haven't meet any non trimmable char since the last separator yet
            continue;
          }
  
          boolean isEscape = isEscapeChar(chars[i]);
          if (isEscape) {
            inQuotes = !inQuotes;
          }
  
          // add separator as we already had one field
          if (!inField && resI > 0) {
            res[resI] = ',';
            resI++;
          }
  
          // register in field (may already be set)
          inField = true;
          // copy current char
          res[resI] = chars[i];
          resI++;
        }
      }
      // inQuotes can only be true at this point if quotes are unbalanced
      if (!inQuotes) {
        // trim end of str
        resI = retroTrim(res, resI);
      }
      return new String(res, 0, resI);
    }