Edit

kc3-lang/angle/src/libANGLE/BinaryStream.h

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2021-01-18 14:21:46
    Hash : 2e0490ee
    Message : Capture/Replay: Serialize float states properly. Previously we were always casting to int. Instead add a float serialization helper function. Bug: angleproject:5530 Change-Id: Ifc80e1dbad9da8a04b3b013c3a3ffa60444f6d26 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2634829 Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Tim Van Patten <timvp@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/BinaryStream.h
  • //
    // Copyright 2012 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // BinaryStream.h: Provides binary serialization of simple types.
    
    #ifndef LIBANGLE_BINARYSTREAM_H_
    #define LIBANGLE_BINARYSTREAM_H_
    
    #include <stdint.h>
    #include <cstddef>
    #include <string>
    #include <vector>
    
    #include "common/angleutils.h"
    #include "common/mathutil.h"
    
    namespace gl
    {
    template <typename IntT>
    struct PromotedIntegerType
    {
        using type = typename std::conditional<
            std::is_signed<IntT>::value,
            typename std::conditional<sizeof(IntT) <= 4, int32_t, int64_t>::type,
            typename std::conditional<sizeof(IntT) <= 4, uint32_t, uint64_t>::type>::type;
    };
    
    class BinaryInputStream : angle::NonCopyable
    {
      public:
        BinaryInputStream(const void *data, size_t length)
        {
            mError  = false;
            mOffset = 0;
            mData   = static_cast<const uint8_t *>(data);
            mLength = length;
        }
    
        // readInt will generate an error for bool types
        template <class IntT>
        IntT readInt()
        {
            static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use readBool");
            using PromotedIntT = typename PromotedIntegerType<IntT>::type;
            PromotedIntT value = 0;
            read(&value);
            ASSERT(angle::IsValueInRangeForNumericType<IntT>(value));
            return static_cast<IntT>(value);
        }
    
        template <class IntT>
        void readInt(IntT *outValue)
        {
            *outValue = readInt<IntT>();
        }
    
        template <class IntT, class VectorElementT>
        void readIntVector(std::vector<VectorElementT> *param)
        {
            size_t size = readInt<size_t>();
            for (size_t index = 0; index < size; ++index)
            {
                param->push_back(readInt<IntT>());
            }
        }
    
        template <class EnumT>
        EnumT readEnum()
        {
            using UnderlyingType = typename std::underlying_type<EnumT>::type;
            return static_cast<EnumT>(readInt<UnderlyingType>());
        }
    
        template <class EnumT>
        void readEnum(EnumT *outValue)
        {
            *outValue = readEnum<EnumT>();
        }
    
        bool readBool()
        {
            int value = 0;
            read(&value);
            return (value > 0);
        }
    
        void readBool(bool *outValue) { *outValue = readBool(); }
    
        void readBytes(unsigned char outArray[], size_t count) { read<unsigned char>(outArray, count); }
    
        std::string readString()
        {
            std::string outString;
            readString(&outString);
            return outString;
        }
    
        void readString(std::string *v)
        {
            size_t length;
            readInt(&length);
    
            if (mError)
            {
                return;
            }
    
            angle::CheckedNumeric<size_t> checkedOffset(mOffset);
            checkedOffset += length;
    
            if (!checkedOffset.IsValid() || mOffset + length > mLength)
            {
                mError = true;
                return;
            }
    
            v->assign(reinterpret_cast<const char *>(mData) + mOffset, length);
            mOffset = checkedOffset.ValueOrDie();
        }
    
        float readFloat()
        {
            float f;
            read(&f, 1);
            return f;
        }
    
        void skip(size_t length)
        {
            angle::CheckedNumeric<size_t> checkedOffset(mOffset);
            checkedOffset += length;
    
            if (!checkedOffset.IsValid() || mOffset + length > mLength)
            {
                mError = true;
                return;
            }
    
            mOffset = checkedOffset.ValueOrDie();
        }
    
        size_t offset() const { return mOffset; }
        size_t remainingSize() const
        {
            ASSERT(mLength >= mOffset);
            return mLength - mOffset;
        }
    
        bool error() const { return mError; }
    
        bool endOfStream() const { return mOffset == mLength; }
    
        const uint8_t *data() { return mData; }
    
      private:
        bool mError;
        size_t mOffset;
        const uint8_t *mData;
        size_t mLength;
    
        template <typename T>
        void read(T *v, size_t num)
        {
            static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
    
            angle::CheckedNumeric<size_t> checkedLength(num);
            checkedLength *= sizeof(T);
            if (!checkedLength.IsValid())
            {
                mError = true;
                return;
            }
    
            angle::CheckedNumeric<size_t> checkedOffset(mOffset);
            checkedOffset += checkedLength;
    
            if (!checkedOffset.IsValid() || checkedOffset.ValueOrDie() > mLength)
            {
                mError = true;
                return;
            }
    
            memcpy(v, mData + mOffset, checkedLength.ValueOrDie());
            mOffset = checkedOffset.ValueOrDie();
        }
    
        template <typename T>
        void read(T *v)
        {
            read(v, 1);
        }
    };
    
    class BinaryOutputStream : angle::NonCopyable
    {
      public:
        BinaryOutputStream();
        ~BinaryOutputStream();
    
        // writeInt also handles bool types
        template <class IntT>
        void writeInt(IntT param)
        {
            static_assert(std::is_integral<IntT>::value, "Not an integral type");
            static_assert(!std::is_same<bool, std::remove_cv<IntT>()>(), "Use writeBool");
            using PromotedIntT = typename PromotedIntegerType<IntT>::type;
            ASSERT(angle::IsValueInRangeForNumericType<PromotedIntT>(param));
            PromotedIntT intValue = static_cast<PromotedIntT>(param);
            write(&intValue, 1);
        }
    
        // Specialized writeInt for values that can also be exactly -1.
        template <class UintT>
        void writeIntOrNegOne(UintT param)
        {
            if (param == static_cast<UintT>(-1))
            {
                writeInt(-1);
            }
            else
            {
                writeInt(param);
            }
        }
    
        template <class IntT>
        void writeIntVector(const std::vector<IntT> &param)
        {
            writeInt(param.size());
            for (IntT element : param)
            {
                writeIntOrNegOne(element);
            }
        }
    
        template <class EnumT>
        void writeEnum(EnumT param)
        {
            using UnderlyingType = typename std::underlying_type<EnumT>::type;
            writeInt<UnderlyingType>(static_cast<UnderlyingType>(param));
        }
    
        void writeString(const std::string &v)
        {
            writeInt(v.length());
            write(v.c_str(), v.length());
        }
    
        void writeBytes(const unsigned char *bytes, size_t count) { write(bytes, count); }
    
        void writeBool(bool value)
        {
            int intValue = value ? 1 : 0;
            write(&intValue, 1);
        }
    
        void writeFloat(float value) { write(&value, 1); }
    
        size_t length() const { return mData.size(); }
    
        const void *data() const { return mData.size() ? &mData[0] : nullptr; }
    
        const std::vector<uint8_t> &getData() const { return mData; }
    
      private:
        template <typename T>
        void write(const T *v, size_t num)
        {
            static_assert(std::is_fundamental<T>::value, "T must be a fundamental type.");
            const char *asBytes = reinterpret_cast<const char *>(v);
            mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
        }
    
        std::vector<uint8_t> mData;
    };
    
    inline BinaryOutputStream::BinaryOutputStream() {}
    
    inline BinaryOutputStream::~BinaryOutputStream() = default;
    
    }  // namespace gl
    
    #endif  // LIBANGLE_BINARYSTREAM_H_