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

cn.wjybxx.dson.DsonReaderUtils Maven / Gradle / Ivy

The 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;

import cn.wjybxx.dson.internal.DsonInternals;
import cn.wjybxx.dson.io.DsonChunk;
import cn.wjybxx.dson.io.DsonIOException;
import cn.wjybxx.dson.io.DsonInput;
import cn.wjybxx.dson.io.DsonOutput;
import cn.wjybxx.dson.types.*;

import java.util.List;

/**
 * @author wjybxx
 * date - 2023/5/31
 */
public class DsonReaderUtils {

    /** 支持读取为bytes和直接写入bytes的数据类型 -- 这些类型不可以存储额外数据在WireType上 */
    public static final List VALUE_BYTES_TYPES = List.of(DsonType.STRING,
            DsonType.BINARY, DsonType.ARRAY, DsonType.OBJECT, DsonType.HEADER);

    // region number

    /**
     * 1.浮点数的前16位固定写入,因此只统计后16位
     * 2.wireType表示后导0对应的字节数
     * 3.该算法对于整数有很好的收益,对于小数收益较低
     * 4.由于编码依赖了上层的wireType比特位,因此不能写在Output接口中
     */
    public static int wireTypeOfFloat(float value) {
        int rawBits = Float.floatToRawIntBits(value);
        if ((rawBits & 0xFF) != 0) return 0;
        if ((rawBits & 0xFF00) != 0) return 1;
        return 2;
    }

    /** 小端编码,从末尾非0开始写入 */
    public static void writeFloat(DsonOutput output, float value, int wireType) {
        if (wireType == 0) {
            output.writeFloat(value);
            return;
        }

        int rawBits = Float.floatToRawIntBits(value);
        for (int i = 0; i < wireType; i++) {
            rawBits = rawBits >>> 8;
        }
        for (int i = wireType; i < 4; i++) {
            output.writeRawByte((byte) rawBits);
            rawBits = rawBits >>> 8;
        }
    }

    public static float readFloat(DsonInput input, int wireType) {
        if (wireType == 0) {
            return input.readFloat();
        }

        int rawBits = 0;
        for (int i = wireType; i < 4; i++) {
            rawBits |= (input.readRawByte() & 0XFF) << (8 * i);
        }
        return Float.intBitsToFloat(rawBits);
    }

    /**
     * 1.浮点数的前16位固定写入,因此只统计后48位
     * 2.wireType表示后导0对应的字节数
     * 3.该算法对于整数有很好的收益,对于小数收益较低
     */
    public static int wireTypeOfDouble(double value) {
        long rawBits = Double.doubleToRawLongBits(value);
        if ((rawBits & 0xFFL) != 0) return 0;
        if ((rawBits & 0xFF00L) != 0) return 1;
        if ((rawBits & 0xFF_0000L) != 0) return 2;
        if ((rawBits & 0xFF00_0000L) != 0) return 3;
        if ((rawBits & 0xFF_0000_0000L) != 0) return 4;
        if ((rawBits & 0xFF00_0000_0000L) != 0) return 5;
        return 6;
    }

    public static void writeDouble(DsonOutput output, double value, int wireType) {
        if (wireType == 0) {
            output.writeDouble(value);
            return;
        }

        long rawBits = Double.doubleToRawLongBits(value);
        for (int i = 0; i < wireType; i++) {
            rawBits = rawBits >>> 8;
        }
        for (int i = wireType; i < 8; i++) {
            output.writeRawByte((byte) rawBits);
            rawBits = rawBits >>> 8;
        }
    }

    public static double readDouble(DsonInput input, int wireType) {
        if (wireType == 0) {
            return input.readDouble();
        }

        long rawBits = 0;
        for (int i = wireType; i < 8; i++) {
            rawBits |= (input.readRawByte() & 0XFFL) << (8 * i);
        }
        return Double.longBitsToDouble(rawBits);
    }

    public static boolean readBool(DsonInput input, int wireTypeBits) {
        if (wireTypeBits == 1) {
            return true;
        }
        if (wireTypeBits == 0) {
            return false;
        }
        throw new DsonIOException("invalid wireType for bool, bits: " + wireTypeBits);
    }
    // endregion

    // region binary

    public static void writeBinary(DsonOutput output, Binary binary) {
        output.writeUint32(binary.length());
        output.writeRawBytes(binary.unsafeBuffer());
    }

    public static void writeBinary(DsonOutput output, DsonChunk chunk) {
        output.writeUint32(chunk.getLength());
        output.writeRawBytes(chunk.getBuffer(), chunk.getOffset(), chunk.getLength());
    }

    public static Binary readBinary(DsonInput input) {
        int size = input.readUint32();
        int oldLimit = input.pushLimit(size);
        Binary binary;
        {
            binary = Binary.unsafeWrap(input.readRawBytes(size));
        }
        input.popLimit(oldLimit);
        return binary;
    }

    // endregion

    // region 内置结构体
    public static int wireTypeOfPtr(ObjectPtr objectPtr) {
        int v = 0;
        if (objectPtr.hasNamespace()) {
            v |= ObjectPtr.MASK_NAMESPACE;
        }
        if (objectPtr.getType() != 0) {
            v |= ObjectPtr.MASK_TYPE;
        }
        if (objectPtr.getPolicy() != 0) {
            v |= ObjectPtr.MASK_POLICY;
        }
        return v;
    }

    public static void writePtr(DsonOutput output, ObjectPtr objectPtr) {
        output.writeString(objectPtr.getLocalId());
        if (objectPtr.hasNamespace()) {
            output.writeString(objectPtr.getNamespace());
        }
        if (objectPtr.getType() != 0) {
            output.writeRawByte(objectPtr.getType());
        }
        if (objectPtr.getPolicy() != 0) {
            output.writeRawByte(objectPtr.getPolicy());
        }
    }

    public static ObjectPtr readPtr(DsonInput input, int wireTypeBits) {
        String localId = input.readString();
        String namespace = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_NAMESPACE) ? input.readString() : null;
        byte type = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_TYPE) ? input.readRawByte() : (byte) 0;
        byte policy = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_POLICY) ? input.readRawByte() : (byte) 0;
        return new ObjectPtr(localId, namespace, type, policy);
    }

    public static int wireTypeOfLitePtr(ObjectLitePtr objectLitePtr) {
        int v = 0;
        if (objectLitePtr.hasNamespace()) {
            v |= ObjectPtr.MASK_NAMESPACE;
        }
        if (objectLitePtr.getType() != 0) {
            v |= ObjectPtr.MASK_TYPE;
        }
        if (objectLitePtr.getPolicy() != 0) {
            v |= ObjectPtr.MASK_POLICY;
        }
        return v;
    }

    public static void writeLitePtr(DsonOutput output, ObjectLitePtr objectLitePtr) {
        output.writeUint64(objectLitePtr.getLocalId());
        if (objectLitePtr.hasNamespace()) {
            output.writeString(objectLitePtr.getNamespace());
        }
        if (objectLitePtr.getType() != 0) {
            output.writeRawByte(objectLitePtr.getType());
        }
        if (objectLitePtr.getPolicy() != 0) {
            output.writeRawByte(objectLitePtr.getPolicy());
        }
    }

    public static ObjectLitePtr readLitePtr(DsonInput input, int wireTypeBits) {
        long localId = input.readUint64();
        String namespace = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_NAMESPACE) ? input.readString() : null;
        byte type = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_TYPE) ? input.readRawByte() : (byte) 0;
        byte policy = DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_POLICY) ? input.readRawByte() : (byte) 0;
        return new ObjectLitePtr(localId, namespace, type, policy);
    }

    public static void writeDateTime(DsonOutput output, ExtDateTime dateTime) {
        output.writeUint64(dateTime.getSeconds());
        output.writeUint32(dateTime.getNanos());
        output.writeSint32(dateTime.getOffset());
//        output.writeRawByte(dateTime.getEnables());
    }

    public static ExtDateTime readDateTime(DsonInput input, int wireTypeBits) {
        return new ExtDateTime(
                input.readUint64(),
                input.readUint32(),
                input.readSint32(),
                (byte) wireTypeBits);
    }

    public static void writeTimestamp(DsonOutput output, Timestamp Timestamp) {
        output.writeUint64(Timestamp.getSeconds());
        output.writeUint32(Timestamp.getNanos());
    }

    public static Timestamp readTimestamp(DsonInput input) {
        return new Timestamp(
                input.readUint64(),
                input.readUint32());
    }

    // endregion

    // region 特殊
    public static void writeValueBytes(DsonOutput output, DsonType dsonType, byte[] data) {
        if (dsonType == DsonType.STRING || dsonType == DsonType.BINARY) {
            output.writeUint32(data.length);
        } else {
            output.writeFixed32(data.length);
        }
        output.writeRawBytes(data);
    }

    public static byte[] readValueAsBytes(DsonInput input, DsonType dsonType) {
        int size;
        if (dsonType == DsonType.STRING || dsonType == DsonType.BINARY) {
            size = input.readUint32();
        } else {
            size = input.readFixed32();
        }
        return input.readRawBytes(size);
    }

    public static void checkReadValueAsBytes(DsonType dsonType) {
        if (!VALUE_BYTES_TYPES.contains(dsonType)) {
            throw DsonIOException.invalidDsonType(VALUE_BYTES_TYPES, dsonType);
        }
    }

    public static void checkWriteValueAsBytes(DsonType dsonType) {
        if (!VALUE_BYTES_TYPES.contains(dsonType)) {
            throw DsonIOException.invalidDsonType(VALUE_BYTES_TYPES, dsonType);
        }
    }

    public static void skipToEndOfObject(DsonInput input) {
        int size = input.getBytesUntilLimit();
        if (size > 0) {
            input.skipRawBytes(size);
        }
    }
    // endregion

    public static void skipValue(DsonInput input, DsonContextType contextType,
                                 DsonType dsonType, WireType wireType, int wireTypeBits) {
        int skip;
        switch (dsonType) {
            case FLOAT -> {
                skip = 4 - wireTypeBits;
            }
            case DOUBLE -> {
                skip = 8 - wireTypeBits;
            }
            case BOOL, NULL -> {
                return;
            }
            case INT32 -> {
                wireType.readInt32(input);
                return;
            }
            case INT64 -> {
                wireType.readInt64(input);
                return;
            }
            case STRING -> {
                skip = input.readUint32();  // string长度
            }
            case BINARY -> {
                skip = input.readUint32(); // length(data)
            }
            case POINTER -> {
                skip = input.readUint32(); // localId长度
                input.skipRawBytes(skip);

                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_NAMESPACE)) {
                    skip = input.readUint32(); // namespace长度
                    input.skipRawBytes(skip);
                }
                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_TYPE)) {
                    input.readRawByte();
                }
                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_POLICY)) {
                    input.readRawByte();
                }
                return;
            }
            case LITE_POINTER -> {
                input.readUint64(); // localId
                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_NAMESPACE)) {
                    skip = input.readUint32(); // namespace长度
                    input.skipRawBytes(skip);
                }
                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_TYPE)) {
                    input.readRawByte();
                }
                if (DsonInternals.isSet(wireTypeBits, ObjectPtr.MASK_POLICY)) {
                    input.readRawByte();
                }
                return;
            }
            case DATETIME -> {
                input.readUint64();
                input.readUint32();
                input.readSint32();
//                input.readRawByte();
                return;
            }
            case TIMESTAMP -> {
                input.readUint64();
                input.readUint32();
                return;
            }
            case HEADER -> {
                skip = input.readFixed16();
            }
            case ARRAY, OBJECT -> {
                skip = input.readFixed32();
            }
            default -> {
                throw DsonIOException.invalidDsonType(contextType, dsonType);
            }
        }
        if (skip > 0) {
            input.skipRawBytes(skip);
        }
    }

    public static DsonReaderGuide whatShouldIDo(DsonContextType contextType, DsonReaderState state) {
        if (contextType == DsonContextType.TOP_LEVEL) {
            if (state == DsonReaderState.END_OF_FILE) {
                return DsonReaderGuide.CLOSE;
            }
            if (state == DsonReaderState.VALUE) {
                return DsonReaderGuide.READ_VALUE;
            }
            return DsonReaderGuide.READ_TYPE;
        } else {
            return switch (state) {
                case TYPE -> DsonReaderGuide.READ_TYPE;
                case VALUE -> DsonReaderGuide.READ_VALUE;
                case NAME -> DsonReaderGuide.READ_NAME;
                case WAIT_START_OBJECT -> {
                    if (contextType == DsonContextType.HEADER) {
                        yield DsonReaderGuide.START_HEADER;
                    }
                    if (contextType == DsonContextType.ARRAY) {
                        yield DsonReaderGuide.START_ARRAY;
                    }
                    yield DsonReaderGuide.START_OBJECT;
                }
                case WAIT_END_OBJECT -> {
                    if (contextType == DsonContextType.HEADER) {
                        yield DsonReaderGuide.END_HEADER;
                    }
                    if (contextType == DsonContextType.ARRAY) {
                        yield DsonReaderGuide.END_ARRAY;
                    }
                    yield DsonReaderGuide.END_OBJECT;
                }
                case INITIAL, END_OF_FILE -> throw new AssertionError("invalid state " + state);
            };
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy