<commit_before>/*
 *  Copyright (C) 2011-2017 Cojen.org
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cojen.tupl.io;

import java.nio.Buffer;
import java.nio.ByteBuffer;

/**
 * Backdoor access to DirectByteBuffer.
 *
 * @author <NAME>
 */
public class DirectAccess {
    private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.tryObtain();

    private static final Class<?> cDirectByteBufferClass;
    private static final long cDirectAddressOffset;
    private static final long cDirectCapacityOffset;
    private static final ThreadLocal<ByteBuffer> cLocalBuffer;
    private static final ThreadLocal<ByteBuffer> cLocalBuffer2;

    static {
        Class<?> clazz;
        long addrOffset, capOffset;
        ThreadLocal<ByteBuffer> local;
        ThreadLocal<ByteBuffer> local2;

        try {
            clazz = Class.forName("java.nio.DirectByteBuffer");

            addrOffset = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address"));
            capOffset = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("capacity"));

            local = new ThreadLocal<>();
            local2 = new ThreadLocal<>();
        } catch (Throwable e) {
            clazz = null;
            addrOffset = 0;
            capOffset = 0;
            local = null;
            local2 = null;
        }

        cDirectByteBufferClass = clazz;
        cDirectAddressOffset = addrOffset;
        cDirectCapacityOffset = capOffset;
        cLocalBuffer = local;
        cLocalBuffer2 = local2;
    }

    private final ThreadLocal<ByteBuffer> mLocalBuffer;

    /**
     * @throws UnsupportedOperationException if not supported
     */
    public DirectAccess() {
        if (!isSupported()) {
            throw new UnsupportedOperationException();
        }
        mLocalBuffer = new ThreadLocal<>();
    }

    /**
     * Returns an instance-specific thread-local ByteBuffer which references any memory
     * address. The position is set to zero, the limit and capacity are set to the given
     * length.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public ByteBuffer prepare(long ptr, int length) {
        return ref(mLocalBuffer, ptr, length);
    }

    public static boolean isSupported() {
        return cLocalBuffer2 != null;
    }

    /**
     * Returns a thread-local ByteBuffer which references any memory address. The position is
     * set to zero, the limit and capacity are set to the given length.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public static ByteBuffer ref(long ptr, int length) {
        return ref(cLocalBuffer, ptr, length);
    }

    /**
     * Returns a second independent thread-local ByteBuffer.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public static ByteBuffer ref2(long ptr, int length) {
        return ref(cLocalBuffer2, ptr, length);
    }

    public static long getAddress(Buffer buf) {
        if (!buf.isDirect()) {
            throw new IllegalArgumentException("Not a direct buffer");
        }
        try {
            return UNSAFE.getLong(buf, cDirectAddressOffset);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }
    }

    private static ByteBuffer ref(ThreadLocal<ByteBuffer> local, long ptr, int length) {
        if (local == null) {
            throw new UnsupportedOperationException();
        }

        ByteBuffer bb = local.get();

        try {
            if (bb == null) {
                bb = (ByteBuffer) UNSAFE.allocateInstance(cDirectByteBufferClass);
                bb.clear();
                local.set(bb);
            }
            UNSAFE.putLong(bb, cDirectAddressOffset, ptr);
            UNSAFE.putInt(bb, cDirectCapacityOffset, length);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }

        bb.position(0).limit(length);

        return bb;
    }

    /**
     * Optionally unreference a buffer. The garbage collector does not attempt to free memory
     * referenced by a ByteBuffer created by this class.
     */
    public static void unref(ByteBuffer bb) {
        bb.position(0).limit(0);
        try {
            UNSAFE.putInt(bb, cDirectCapacityOffset, 0);
            UNSAFE.putLong(bb, cDirectAddressOffset, 0);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }
    }
}
<commit_msg>Expose the allocDirect method for other package-private classes to use later.<commit_after>/*
 *  Copyright (C) 2011-2017 Cojen.org
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cojen.tupl.io;

import java.nio.Buffer;
import java.nio.ByteBuffer;

/**
 * Backdoor access to DirectByteBuffer.
 *
 * @author <NAME>
 */
public class DirectAccess {
    private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.tryObtain();

    private static final Class<?> cDirectByteBufferClass;
    private static final long cDirectAddressOffset;
    private static final long cDirectCapacityOffset;
    private static final ThreadLocal<ByteBuffer> cLocalBuffer;
    private static final ThreadLocal<ByteBuffer> cLocalBuffer2;

    static {
        Class<?> clazz;
        long addrOffset, capOffset;
        ThreadLocal<ByteBuffer> local;
        ThreadLocal<ByteBuffer> local2;

        try {
            clazz = Class.forName("java.nio.DirectByteBuffer");

            addrOffset = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address"));
            capOffset = UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("capacity"));

            local = new ThreadLocal<>();
            local2 = new ThreadLocal<>();
        } catch (Throwable e) {
            clazz = null;
            addrOffset = 0;
            capOffset = 0;
            local = null;
            local2 = null;
        }

        cDirectByteBufferClass = clazz;
        cDirectAddressOffset = addrOffset;
        cDirectCapacityOffset = capOffset;
        cLocalBuffer = local;
        cLocalBuffer2 = local2;
    }

    private final ThreadLocal<ByteBuffer> mLocalBuffer;

    /**
     * @throws UnsupportedOperationException if not supported
     */
    public DirectAccess() {
        if (!isSupported()) {
            throw new UnsupportedOperationException();
        }
        mLocalBuffer = new ThreadLocal<>();
    }

    /**
     * Returns an instance-specific thread-local ByteBuffer which references any memory
     * address. The position is set to zero, the limit and capacity are set to the given
     * length.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public ByteBuffer prepare(long ptr, int length) {
        return ref(mLocalBuffer, ptr, length);
    }

    public static boolean isSupported() {
        return cLocalBuffer2 != null;
    }

    /**
     * Returns a thread-local ByteBuffer which references any memory address. The position is
     * set to zero, the limit and capacity are set to the given length.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public static ByteBuffer ref(long ptr, int length) {
        return ref(cLocalBuffer, ptr, length);
    }

    /**
     * Returns a second independent thread-local ByteBuffer.
     *
     * @throws UnsupportedOperationException if not supported
     */
    public static ByteBuffer ref2(long ptr, int length) {
        return ref(cLocalBuffer2, ptr, length);
    }

    public static long getAddress(Buffer buf) {
        if (!buf.isDirect()) {
            throw new IllegalArgumentException("Not a direct buffer");
        }
        try {
            return UNSAFE.getLong(buf, cDirectAddressOffset);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }
    }

    private static ByteBuffer ref(ThreadLocal<ByteBuffer> local, long ptr, int length) {
        if (local == null) {
            throw new UnsupportedOperationException();
        }
        ByteBuffer bb = local.get();
        if (bb == null) {
            bb = allocDirect();
        }
        ref(bb, ptr, length);
        return bb;
    }

    /**
     * Optionally unreference a buffer. The garbage collector does not attempt to free memory
     * referenced by a ByteBuffer created by this class.
     */
    public static void unref(ByteBuffer bb) {
        bb.position(0).limit(0);
        try {
            UNSAFE.putInt(bb, cDirectCapacityOffset, 0);
            UNSAFE.putLong(bb, cDirectAddressOffset, 0);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }
    }

    static ByteBuffer allocDirect() {
        try {
            var bb = (ByteBuffer) UNSAFE.allocateInstance(cDirectByteBufferClass);
            bb.clear();
            return bb;
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        }
    }

    static void ref(ByteBuffer bb, long ptr, int length) {
        UNSAFE.putLong(bb, cDirectAddressOffset, ptr);
        UNSAFE.putInt(bb, cDirectCapacityOffset, length);
        bb.position(0).limit(length);
    }
}

{'fraction_non_alphanumeric': 0.08356545961002786, 'fraction_numerical': 0.004802612621265969, 'mean_word_length': 2.4148901279107906, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, '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': '3394841', 'n_tokens_mistral': 2778, 'n_tokens_neox': 2695, 'n_words': 896}