@SuppressWarnings("BetaApi") // BaseEncoding is stable in Guava 20.0 @Override public String toString() { StringBuilder sb = new StringBuilder("Metadata("); for (int i = 0; i < size; i++) { if (i != 0) { sb.append(','); } String headerName = new String(name(i), US_ASCII); sb.append(headerName).append('='); if (headerName.endsWith(BINARY_HEADER_SUFFIX)) { sb.append(BASE64_ENCODING_OMIT_PADDING.encode(value(i))); } else { String headerValue = new String(value(i), US_ASCII); sb.append(headerValue); } } return sb.append(')').toString(); }
@SuppressWarnings("BetaApi") // BaseEncoding is stable in Guava 20.0 @Override public String toString() { StringBuilder sb = new StringBuilder("Metadata("); for (int i = 0; i < size; i++) { if (i != 0) { sb.append(','); } String headerName = new String(name(i), US_ASCII); sb.append(headerName).append('='); if (headerName.endsWith(BINARY_HEADER_SUFFIX)) { sb.append(BaseEncoding.base64().encode(value(i))); } else { String headerValue = new String(value(i), US_ASCII); sb.append(headerValue); } } return sb.append(')').toString(); }
/** * Merge values from the given set of keys into this set of metadata. If a key is present in keys, * then all of the associated values will be copied over. * * @param other The source of the new key values. * @param keys The subset of matching key we want to copy, if they exist in the source. */ public void merge(Metadata other, Set<Key<?>> keys) { Preconditions.checkNotNull(other, "other"); // Use ByteBuffer for equals and hashCode. Map<ByteBuffer, Key<?>> asciiKeys = new HashMap<ByteBuffer, Key<?>>(keys.size()); for (Key<?> key : keys) { asciiKeys.put(ByteBuffer.wrap(key.asciiName()), key); } for (int i = 0; i < other.size; i++) { ByteBuffer wrappedNamed = ByteBuffer.wrap(other.name(i)); if (asciiKeys.containsKey(wrappedNamed)) { maybeExpand(); name(size, other.name(i)); value(size, other.value(i)); size++; } } }
/** * Adds the {@code key, value} pair. If {@code key} already has values, {@code value} is added to * the end. Duplicate values for the same key are permitted. * * @throws NullPointerException if key or value is null */ public <T> void put(Key<T> key, T value) { Preconditions.checkNotNull(key, "key"); Preconditions.checkNotNull(value, "value"); maybeExpand(); name(size, key.asciiName()); value(size, key.toBytes(value)); size++; }
/** * Merge values from the given set of keys into this set of metadata. If a key is present in keys, * then all of the associated values will be copied over. * * @param other The source of the new key values. * @param keys The subset of matching key we want to copy, if they exist in the source. */ public void merge(Metadata other, Set<Key<?>> keys) { Preconditions.checkNotNull(other, "other"); // Use ByteBuffer for equals and hashCode. Map<ByteBuffer, Key<?>> asciiKeys = new HashMap<ByteBuffer, Key<?>>(keys.size()); for (Key<?> key : keys) { asciiKeys.put(ByteBuffer.wrap(key.asciiName()), key); } for (int i = 0; i < other.size; i++) { ByteBuffer wrappedNamed = ByteBuffer.wrap(other.name(i)); if (asciiKeys.containsKey(wrappedNamed)) { maybeExpand(); name(size, other.name(i)); value(size, other.value(i)); size++; } } }
/** Remove all values for the given key. If there were no values, {@code null} is returned. */ public <T> Iterable<T> removeAll(Key<T> key) { if (isEmpty()) { return null; } int writeIdx = 0; int readIdx = 0; List<T> ret = null; for (; readIdx < size; readIdx++) { if (bytesEqual(key.asciiName(), name(readIdx))) { ret = ret != null ? ret : new ArrayList<T>(); ret.add(key.parseBytes(value(readIdx))); continue; } name(writeIdx, name(readIdx)); value(writeIdx, value(readIdx)); writeIdx++; } int newSize = writeIdx; // Multiply by two since namesAndValues is interleaved. Arrays.fill(namesAndValues, writeIdx * 2, len(), null); size = newSize; return ret; }
/** * Returns the last metadata entry added with the name 'name' parsed as T. * * @return the parsed metadata entry or null if there are none. */ @Nullable public <T> T get(Key<T> key) { for (int i = size - 1; i >= 0; i--) { if (bytesEqual(key.asciiName(), name(i))) { return key.parseBytes(value(i)); } } return null; }
/** Remove all values for the given key. If there were no values, {@code null} is returned. */ public <T> Iterable<T> removeAll(Key<T> key) { if (isEmpty()) { return null; } int writeIdx = 0; int readIdx = 0; List<T> ret = null; for (; readIdx < size; readIdx++) { if (bytesEqual(key.asciiName(), name(readIdx))) { ret = ret != null ? ret : new ArrayList<T>(); ret.add(key.parseBytes(value(readIdx))); continue; } name(writeIdx, name(readIdx)); value(writeIdx, value(readIdx)); writeIdx++; } int newSize = writeIdx; // Multiply by two since namesAndValues is interleaved. Arrays.fill(namesAndValues, writeIdx * 2, len(), null); size = newSize; return ret; }
/** * Returns the last metadata entry added with the name 'name' parsed as T. * * @return the parsed metadata entry or null if there are none. */ @Nullable public <T> T get(Key<T> key) { for (int i = size - 1; i >= 0; i--) { if (bytesEqual(key.asciiName(), name(i))) { return key.parseBytes(value(i)); } } return null; }
/** * Remove all values for the given key without returning them. This is a minor performance * optimization if you do not need the previous values. */ @ExperimentalApi public <T> void discardAll(Key<T> key) { if (isEmpty()) { return; } int writeIdx = 0; int readIdx = 0; for (; readIdx < size; readIdx++) { if (bytesEqual(key.asciiName(), name(readIdx))) { continue; } name(writeIdx, name(readIdx)); value(writeIdx, value(readIdx)); writeIdx++; } int newSize = writeIdx; // Multiply by two since namesAndValues is interleaved. Arrays.fill(namesAndValues, writeIdx * 2, len(), null); size = newSize; }
/** * Remove all values for the given key without returning them. This is a minor performance * optimization if you do not need the previous values. */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4691") public <T> void discardAll(Key<T> key) { if (isEmpty()) { return; } int writeIdx = 0; int readIdx = 0; for (; readIdx < size; readIdx++) { if (bytesEqual(key.asciiName(), name(readIdx))) { continue; } name(writeIdx, name(readIdx)); value(writeIdx, value(readIdx)); writeIdx++; } int newSize = writeIdx; // Multiply by two since namesAndValues is interleaved. Arrays.fill(namesAndValues, writeIdx * 2, len(), null); size = newSize; }
/** * Adds the {@code key, value} pair. If {@code key} already has values, {@code value} is added to * the end. Duplicate values for the same key are permitted. * * @throws NullPointerException if key or value is null */ public <T> void put(Key<T> key, T value) { Preconditions.checkNotNull(key, "key"); Preconditions.checkNotNull(value, "value"); maybeExpand(); name(size, key.asciiName()); value(size, key.toBytes(value)); size++; }