content: // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
  //  This source code is licensed under both the GPLv2 (found in the
  //  COPYING file in the root directory) and Apache 2.0 License
  //  (found in the LICENSE.Apache file in the root directory).
  
  package org.rocksdb;
  
  import java.nio.ByteBuffer;
  
  /**
   * Base class for slices which will receive direct
   * ByteBuffer based access to the underlying data.
   *
   * ByteBuffer backed slices typically perform better with
   * larger keys and values. When using smaller keys and
   * values consider using @see org.rocksdb.Slice
   */
  public class DirectSlice extends AbstractSlice<ByteBuffer> {
    public final static DirectSlice NONE = new DirectSlice();
  
    /**
     * Indicates whether we have to free the memory pointed to by the Slice
     */
    private final boolean internalBuffer;
    private volatile boolean cleared = false;
    private volatile long internalBufferOffset = 0;
  
    /**
     * Called from JNI to construct a new Java DirectSlice
     * without an underlying C++ object set
     * at creation time.
     *
     * Note: You should be aware that it is intentionally marked as
     * package-private. This is so that developers cannot construct their own
     * default DirectSlice objects (at present). As developers cannot construct
     * their own DirectSlice objects through this, they are not creating
     * underlying C++ DirectSlice objects, and so there is nothing to free
     * (dispose) from Java.
     */
    DirectSlice() {
      super();
      this.internalBuffer = false;
    }
  
    /**
     * Constructs a slice
     * where the data is taken from
     * a String.
     *
     * @param str The string
     */
    public DirectSlice(final String str) {
      super(createNewSliceFromString(str));
      this.internalBuffer = true;
    }
  
    /**
     * Constructs a slice where the data is
     * read from the provided
     * ByteBuffer up to a certain length
     *
     * @param data The buffer containing the data
     * @param length The length of the data to use for the slice
     */
    public DirectSlice(final ByteBuffer data, final int length) {
      super(createNewDirectSlice0(ensureDirect(data), length));
      this.internalBuffer = false;
    }
  
    /**
     * Constructs a slice where the data is
     * read from the provided
     * ByteBuffer
     *
     * @param data The bugger containing the data
     */
    public DirectSlice(final ByteBuffer data) {
      super(createNewDirectSlice1(ensureDirect(data)));
      this.internalBuffer = false;
    }
  
    private static ByteBuffer ensureDirect(final ByteBuffer data) {
      if(!data.isDirect()) {
        throw new IllegalArgumentException("The ByteBuffer must be direct");
      }
      return data;
    }
  
    /**
     * Retrieves the byte at a specific offset
     * from the underlying data
     *
     * @param offset The (zero-based) offset of the byte to retrieve
     *
     * @return the requested byte
     */
    public byte get(final int offset) {
      return get0(getNativeHandle(), offset);
    }
  
    @Override
    public void clear() {
      clear0(getNativeHandle(), !cleared && internalBuffer, internalBufferOffset);
      cleared = true;
    }
  
    @Override
    public void removePrefix(final int n) {
      removePrefix0(getNativeHandle(), n);
      this.internalBufferOffset += n;
    }
  
    @Override
    protected void disposeInternal() {
      final long nativeHandle = getNativeHandle();
      if(!cleared && internalBuffer) {
        disposeInternalBuf(nativeHandle, internalBufferOffset);
      }
      disposeInternal(nativeHandle);
    }
  
    private native static long createNewDirectSlice0(final ByteBuffer data,
        final int length);
    private native static long createNewDirectSlice1(final ByteBuffer data);
    @Override protected final native ByteBuffer data0(long handle);
    private native byte get0(long handle, int offset);
    private native void clear0(long handle, boolean internalBuffer,
        long internalBufferOffset);
    private native void removePrefix0(long handle, int length);
    private native void disposeInternalBuf(final long handle,
        long internalBufferOffset);
  }
  