All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.wjybxx.dson.io.DsonOutputs Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
/*
 * Copyright 2023-2024 wjybxx([email protected])
 *
 * 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 cn.wjybxx.dson.io;

import cn.wjybxx.base.io.ByteBufferUtils;
import cn.wjybxx.dson.internal.CodedUtils;
import cn.wjybxx.dson.internal.Utf8Util;

/**
 * 核心包去除了对Protobuf的支持,如果期望使用protobuf和netty读取数据,可引入相应的扩展包。
 *
 * @author wjybxx
 * date - 2023/4/22
 */
public class DsonOutputs {

    public static DsonOutput newInstance(byte[] buffer) {
        return new ArrayOutput(buffer, 0, buffer.length);
    }

    public static DsonOutput newInstance(byte[] buffer, int offset, int length) {
        return new ArrayOutput(buffer, offset, length);
    }

    static class ArrayOutput implements DsonOutput {

        private final byte[] buffer;
        private final int rawOffset;
        private final int rawLimit;

        private int bufferPos;
        private int bufferPosLimit;

        ArrayOutput(byte[] buffer, int offset, int length) {
            ByteBufferUtils.checkBuffer(buffer, offset, length);
            this.buffer = buffer;
            this.rawOffset = offset;
            this.rawLimit = offset + length;

            this.bufferPos = offset;
            this.bufferPosLimit = offset + length;
        }

        //region check

        private int CheckNewBufferPos(int newBufferPos) {
            if (newBufferPos < rawOffset || newBufferPos > bufferPosLimit) {
                throw new DsonIOException("BytesLimited, LimitPos: %d, position: %d, newPosition: %d"
                        .formatted(bufferPosLimit, bufferPos, newBufferPos));
            }
            return newBufferPos;
        }

        //endregion

        //region basic

        @Override
        public void writeRawByte(int value) {
            CheckNewBufferPos(bufferPos + 1);
            buffer[bufferPos++] = (byte) value;
        }

        @Override
        public void writeRawByte(byte value) {
            CheckNewBufferPos(bufferPos + 1);
            buffer[bufferPos++] = value;
        }

        @Override
        public void writeInt32(int value) {
            try {
                int newPos = CodedUtils.writeInt32(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeUint32(int value) {
            try {
                int newPos = CodedUtils.writeUint32(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeSint32(int value) {
            try {
                int newPos = CodedUtils.writeSint32(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeFixed32(int value) {
            try {
                int newPos = CodedUtils.writeFixed32(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeInt64(long value) {
            try {
                int newPos = CodedUtils.writeInt64(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeUint64(long value) {
            try {
                int newPos = CodedUtils.writeUint64(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeSint64(long value) {
            try {
                int newPos = CodedUtils.writeSint64(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeFixed64(long value) {
            try {
                int newPos = CodedUtils.writeFixed64(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeFloat(float value) {
            try {
                int newPos = CodedUtils.writeFloat(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeDouble(double value) {
            try {
                int newPos = CodedUtils.writeDouble(buffer, bufferPos, value);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeBool(boolean value) {
            try {
                int newPos = CodedUtils.writeUint32(buffer, bufferPos, value ? 1 : 0);
                bufferPos = CheckNewBufferPos(newPos);
            } catch (Exception e) {
                throw DsonIOException.wrap(e, "buffer overflow");
            }
        }

        @Override
        public void writeString(String value) {
            try {
                long maxByteCount = (value.length() * 3L);
                int maxByteCountVarIntSize = CodedUtils.computeRawVarInt64Size(maxByteCount);
                int minByteCountVarIntSize = CodedUtils.computeRawVarInt32Size(value.length());
                if (maxByteCountVarIntSize == minByteCountVarIntSize) {
                    // len占用的字节数是可提前确定的,因此无需额外的字节数计算,可直接编码
                    int newPos = bufferPos + minByteCountVarIntSize;
                    int byteCount = Utf8Util.utf8Encode(value, buffer, newPos, bufferPosLimit - newPos);
                    CodedUtils.writeUint32(buffer, bufferPos, byteCount);
                    bufferPos = CheckNewBufferPos(newPos + byteCount);
                } else {
                    // 注意,这里写的编码后的字节长度;而不是字符串长度 -- 提前计算UTF8的长度是很有用的方法
                    int byteCount = Utf8Util.utf8Length(value);
                    int newPos = CodedUtils.writeUint32(buffer, bufferPos, byteCount);
                    if (byteCount > 0) {
                        CheckNewBufferPos(newPos + byteCount);
                        Utf8Util.utf8Encode(value, buffer, newPos, bufferPosLimit - newPos);
                    }
                    bufferPos = (newPos + byteCount);
                }
            } catch (Exception e) {
                throw DsonIOException.wrap(e);
            }
        }

        @Override
        public void writeRawBytes(byte[] data, int offset, int length) {
            ByteBufferUtils.checkBuffer(data, offset, length);
            CheckNewBufferPos(bufferPos + length);

            System.arraycopy(data, offset, buffer, bufferPos, length);
            bufferPos += length;
        }
        // endregion

        // region sp

        @Override
        public int spaceLeft() {
            return bufferPosLimit - bufferPos;
        }

        @Override
        public int getPosition() {
            return bufferPos - rawOffset;
        }

        @Override
        public void setPosition(int value) {
            ByteBufferUtils.checkBuffer(rawLimit - rawOffset, value);
            bufferPos = rawOffset + value;
        }

        @Override
        public void setByte(int pos, byte value) {
            ByteBufferUtils.checkBuffer(rawLimit - rawOffset, pos, 1);
            int bufferPos = rawOffset + pos;
            buffer[bufferPos] = value;
        }

        @Override
        public void setFixedInt32(int pos, int value) {
            ByteBufferUtils.checkBuffer(rawLimit - rawOffset, pos, 4);
            int bufferPos = rawOffset + pos;
            ByteBufferUtils.setInt32LE(buffer, bufferPos, value);
        }
        // endregion

        @Override
        public void flush() {

        }

        @Override
        public void close() {

        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy