skipUpTo helpfully falls back from skip invocations which return zero to invoke a read into a buffer.

The current implementation has two inefficiencies which cause unexpected performance degradation in tight loops, especially when a small number of bytes are requested:

1. In many cases skipSafely is able to skip all the requested bytes, there's no need to allocate a read buffer
2. The caller only requests a few bytes are skipped. Calling `ByteStreams.skipFully(stream, 32)` always allocates a 8192 byte buffer.

Proposed solution:
Defer buffer allocation until it is needed, using the minimum of the requested size and BUFFER_SIZE. This reduces allocation pressure in all cases of small skip values, as well as streams that report nonzero bytes available (assuming skip returns a positive value).
* This value is intended to be large enough to make the overhead of system calls negligible,
   * without being so large that it causes problems for systems with atypical memory management if
   * approaches 2 or 3 are used.
   */
  private static final int ZERO_COPY_CHUNK_SIZE = 512 * 1024;
  private ByteStreams() {}
  /**
   * Copies all bytes from the input stream to the output stream. Does not close or flush either
   * stream.
   *
   * @param from the input stream to read from
   * @param to the output stream to write to
   * @return the number of bytes copied
   * @throws IOException if an I/O error occurs
   */
  @CanIgnoreReturnValue
  public static long copy(InputStream from, OutputStream to) throws IOException {
    checkNotNull(from);
    checkNotNull(to);
    byte[] buf = createBuffer();
    long total = 0;
    while (true) {
      int r = from.read(buf);
      if (r == -1) {
        break;
      }
      to.write(buf, 0, r);
      total += r;
    }
    return total;