<commit_before>/**
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package parquet.io.api;

import static parquet.bytes.BytesUtils.UTF8;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;

import parquet.bytes.BytesUtils;

abstract public class Binary {

  public static final Binary EMPTY = fromByteArray(new byte[0]);

  public static Binary fromByteArray(
      final byte[] value,
      final int offset,
      final int length) {

    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return UTF8.decode(ByteBuffer.wrap(value, offset, length)).toString();
        // TODO: figure out why the following line was much slower
        // return new String(value, offset, length, BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return length;
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(value, offset, length);
      }

      @Override
      public byte[] getBytes() {
        return Arrays.copyOfRange(value, offset, offset + length);
      }

      @Override
      public int hashCode() {
        return Binary.hashCode(value, offset, length);
      }

      @Override
      boolean equals(Binary other) {
        return other.equals(value, offset, length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        return Binary.equals(value, offset, length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return ByteBuffer.wrap(value, offset, length);
      }

    };
  }

  public static Binary fromByteArray(final byte[] value) {
    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return new String(value, BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return value.length;
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(value);
      }

      @Override
      public byte[] getBytes() {
        return value;
      }

      @Override
      public int hashCode() {
        return Binary.hashCode(value, 0, value.length);
      }

      @Override
      boolean equals(Binary other) {
        return other.equals(value, 0, value.length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        return Binary.equals(value, 0, value.length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return ByteBuffer.wrap(value);
      }
    };
  }

  public static Binary fromByteBuffer(final ByteBuffer value) {
    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return new String(getBytes(), BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return value.remaining();
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(getBytes());
      }

      @Override
      public byte[] getBytes() {
        byte[] bytes = new byte[value.remaining()];
        value.get(bytes);
        return bytes;
      }

      @Override
      public int hashCode() {
        byte[] bytes = getBytes();
        return Binary.hashCode(bytes, 0, bytes.length);
      }

      @Override
      boolean equals(Binary other) {
        byte[] bytes = getBytes();
        return other.equals(bytes, 0, bytes.length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        byte[] bytes = getBytes();
        return Binary.equals(bytes, 0, bytes.length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return value;
      }
    };
  }

  public static Binary fromString(final String value) {
    return fromByteArray(value.getBytes(BytesUtils.UTF8));
  }

  /**
   * @see {@link Arrays#hashCode(byte[])}
   * @param array
   * @param offset<commit_msg>Avoid copying bytes if ByteBuffer is array-based.<commit_after>/**
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package parquet.io.api;

import static parquet.bytes.BytesUtils.UTF8;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;

import parquet.bytes.BytesUtils;

abstract public class Binary {

  public static final Binary EMPTY = fromByteArray(new byte[0]);

  public static Binary fromByteArray(
      final byte[] value,
      final int offset,
      final int length) {

    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return UTF8.decode(ByteBuffer.wrap(value, offset, length)).toString();
        // TODO: figure out why the following line was much slower
        // return new String(value, offset, length, BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return length;
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(value, offset, length);
      }

      @Override
      public byte[] getBytes() {
        return Arrays.copyOfRange(value, offset, offset + length);
      }

      @Override
      public int hashCode() {
        return Binary.hashCode(value, offset, length);
      }

      @Override
      boolean equals(Binary other) {
        return other.equals(value, offset, length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        return Binary.equals(value, offset, length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return ByteBuffer.wrap(value, offset, length);
      }

    };
  }

  public static Binary fromByteArray(final byte[] value) {
    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return new String(value, BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return value.length;
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(value);
      }

      @Override
      public byte[] getBytes() {
        return value;
      }

      @Override
      public int hashCode() {
        return Binary.hashCode(value, 0, value.length);
      }

      @Override
      boolean equals(Binary other) {
        return other.equals(value, 0, value.length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        return Binary.equals(value, 0, value.length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return ByteBuffer.wrap(value);
      }
    };
  }

  public static Binary fromByteBuffer(final ByteBuffer value) {
    return new Binary() {
      @Override
      public String toStringUsingUTF8() {
        return new String(getBytes(), BytesUtils.UTF8);
      }

      @Override
      public int length() {
        return value.remaining();
      }

      @Override
      public void writeTo(OutputStream out) throws IOException {
        out.write(getBytes());
      }

      @Override
      public byte[] getBytes() {
        byte[] bytes = new byte[value.remaining()];
        value.get(bytes);
        return bytes;
      }

      @Override
      public int hashCode() {
        if (value.hasArray()) {
          return Binary.hashCode(value.array(), value.arrayOffset() + value.position(),
              value.arrayOffset() + value.remaining());
        }
        byte[] bytes = getBytes();
        return Binary.hashCode(bytes, 0, bytes.length);
      }

      @Override
      boolean equals(Binary other) {
        if (value.hasArray()) {
          return other.equals(value.array(), value.arrayOffset() + value.position(),
              value.arrayOffset() + value.remaining());
        }
        byte[] bytes = getBytes();
        return other.equals(bytes, 0, bytes.length);
      }

      @Override
      boolean equals(byte[] other, int otherOffset, int otherLength) {
        if (value.hasArray()) {
          return Binary.equals(value.array(), value.arrayOffset() + value.position(),
              value.arrayOffset() + value.remaining(), other, otherOffset, otherLength);
        }
        byte[] bytes = getBytes();
        return Binary.equals(bytes, 0, bytes.length, other, otherOffset, otherLength);
      }

      @Override
      public ByteBuffer toByteBuffer() {
        return value;
      }
    };
  }

  public static Binary fromString(final String value) {
    return fromByteArray(value.getBytes(BytesUtils.UTF8));
  }

  /**
   * @see {@link Arrays#hashCode(byte[])}
   * @param array
   * @param offset
{'fraction_non_alphanumeric': 0.10143608414239483, 'fraction_numerical': 0.0048543689320388345, 'mean_word_length': 2.427729636048527, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2010282', 'n_tokens_mistral': 2726, 'n_tokens_neox': 2618, 'n_words': 812}