<commit_before>package net.ihiroky.niotty.codec;

import net.ihiroky.niotty.LoadStage;
import net.ihiroky.niotty.StageContext;
import net.ihiroky.niotty.TransportStateEvent;
import net.ihiroky.niotty.buffer.Buffers;
import net.ihiroky.niotty.buffer.CodecBuffer;

/**
 * @author <NAME>
 */
public class FrameLengthRemoveDecoder implements LoadStage<CodecBuffer, CodecBuffer> {

    private int poolingFrameBytes_;
    private CodecBuffer buffer_;

    @Override
    public void load(StageContext<CodecBuffer> context, CodecBuffer input) {
        while (input.remainingBytes() > 0) {
            int frameBytes = poolingFrameBytes_;

            // load frame length
            if (frameBytes == 0) {
                CodecBuffer b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                if (b == null) {
                    return;
                }
                // int length = b.readShort() & FrameLengthPrependEncoder.MASK_TWO_BYTES;
                int length = b.readShort();
                if (length >= 0) { // length < Short.MAX_VALUE
                    frameBytes = length;
                } else {
                    length <<= FrameLengthPrependEncoder.SHIFT_TWO_BYTES;
                    b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                    if (b == null) {
                        poolingFrameBytes_ = length; // negative
                        return;
                    }
                    int upper = length & ~FrameLengthPrependEncoder.INT_FLAG;
                    int lower = b.readShort() & FrameLengthPrependEncoder.MASK_TWO_BYTES;
                    frameBytes = upper | lower;
                }
            } else if (frameBytes < 0) {
                CodecBuffer b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                if (b == null) {
                    return;
                }
                int upper = frameBytes & ~FrameLengthPrependEncoder.INT_FLAG;
                int lower = b.readShort() & FrameLengthPrependEncoder.MASK_TWO_BYTES;
                frameBytes = (upper << FrameLengthPrependEncoder.SHIFT_TWO_BYTES) | lower;
            }

            // load frame
            CodecBuffer output = readFully(input, frameBytes, false);
            if (output == null) {
                poolingFrameBytes_ = frameBytes;
                return;
            }

            poolingFrameBytes_ = 0;
            context.proceed(output);
        }
    }

    @Override
    public void load(StageContext<?> context, TransportStateEvent event) {
        context.proceed(event);
    }

    /**
     * <p>Reads data to the amount of specified {@code requiredLength}.</p>
     *
     * <p>If enough data exist in the {@code input}, then this method returns a buffer
     * which contains data at least {@code requiredLength}. Otherwise, returns null
     * and pools a content of the {@code input} to a member field.</p>
     *
     * @param input a input buffer<commit_msg>Fix comments<commit_after>package net.ihiroky.niotty.codec;

import net.ihiroky.niotty.LoadStage;
import net.ihiroky.niotty.StageContext;
import net.ihiroky.niotty.TransportStateEvent;
import net.ihiroky.niotty.buffer.Buffers;
import net.ihiroky.niotty.buffer.CodecBuffer;

/**
 * @author <NAME>
 */
public class FrameLengthRemoveDecoder implements LoadStage<CodecBuffer, CodecBuffer> {

    private int poolingFrameBytes_;
    private CodecBuffer buffer_;

    @Override
    public void load(StageContext<CodecBuffer> context, CodecBuffer input) {
        while (input.remainingBytes() > 0) {
            int frameBytes = poolingFrameBytes_;

            // load frame length
            if (frameBytes == 0) {
                CodecBuffer b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                if (b == null) {
                    return;
                }
                int length = b.readShort();
                if (length >= 0) { // it's also satisfies length <= Short.MAX_VALUE
                    frameBytes = length;
                } else {
                    length <<= FrameLengthPrependEncoder.SHIFT_TWO_BYTES;
                    b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                    if (b == null) {
                        poolingFrameBytes_ = length; // negative
                        return;
                    }
                    int upper = length & ~FrameLengthPrependEncoder.INT_FLAG;
                    int lower = b.readShort() & FrameLengthPrependEncoder.MASK_TWO_BYTES;
                    frameBytes = upper | lower;
                }
            } else if (frameBytes < 0) {
                CodecBuffer b = readFully(input, FrameLengthPrependEncoder.SHORT_BYTES, true);
                if (b == null) {
                    return;
                }
                int upper = frameBytes & ~FrameLengthPrependEncoder.INT_FLAG;
                int lower = b.readShort() & FrameLengthPrependEncoder.MASK_TWO_BYTES;
                frameBytes = (upper << FrameLengthPrependEncoder.SHIFT_TWO_BYTES) | lower;
            }

            // load frame
            CodecBuffer output = readFully(input, frameBytes, false);
            if (output == null) {
                poolingFrameBytes_ = frameBytes; // positive
                return;
            }

            poolingFrameBytes_ = 0;
            context.proceed(output);
        }
    }

    @Override
    public void load(StageContext<?> context, TransportStateEvent event) {
        context.proceed(event);
    }

    /**
     * <p>Reads data to the amount of specified {@code requiredLength}.</p>
     *
     * <p>If enough data exist in the {@code input}, then this method returns a buffer
     * which contains data at least {@code requiredLength}. Otherwise, returns null
     * and pools a content of the {@code input} to a member field.</p>
     *
     * @param input a input buffer
{'fraction_non_alphanumeric': 0.08779912369396697, 'fraction_numerical': 0.0016852039096730705, 'mean_word_length': 1.8154648956356736, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4154664', 'n_tokens_mistral': 1630, 'n_tokens_neox': 1557, 'n_words': 384}