Edit

kc3-lang/angle/src/common/vector_utils.h

Branch :

  • Show log

    Commit

  • Author : Rafael Cintron
    Date : 2018-06-20 18:08:04
    Hash : 05a449a7
    Message : Replace reinterpret_cast with safer or no cast When casting types to one another in C++, the weaker the cast, the better. This change replaces instances of reinterpret_cast with static_cast or no cast where it safe and correct to do so. BUG=angleproject:2683 Change-Id: I99c9033614a65282ae1d78cf0f4b80fabd75877a Reviewed-on: https://chromium-review.googlesource.com/1109396 Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/common/vector_utils.h
  • //
    // Copyright 2016 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.
    //
    // vector_utils.h: Utility classes implementing various vector operations
    
    #ifndef COMMON_VECTOR_UTILS_H_
    #define COMMON_VECTOR_UTILS_H_
    
    #include <cmath>
    #include <cstddef>
    #include <ostream>
    #include <type_traits>
    
    namespace angle
    {
    
    template <size_t Dimension, typename Type>
    class Vector;
    
    using Vector2 = Vector<2, float>;
    using Vector3 = Vector<3, float>;
    using Vector4 = Vector<4, float>;
    
    using Vector2I = Vector<2, int>;
    using Vector3I = Vector<3, int>;
    using Vector4I = Vector<4, int>;
    
    using Vector2U = Vector<2, unsigned int>;
    using Vector3U = Vector<3, unsigned int>;
    using Vector4U = Vector<4, unsigned int>;
    
    template <size_t Dimension, typename Type>
    class VectorBase
    {
      public:
        using VectorN = Vector<Dimension, Type>;
    
        // Constructors
        VectorBase() = default;
        explicit VectorBase(Type element);
    
        template <typename Type2>
        VectorBase(const VectorBase<Dimension, Type2> &other);
    
        template <typename Arg1, typename Arg2, typename... Args>
        VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args);
    
        // Access the vector backing storage directly
        const Type *data() const { return mData; }
        Type *data() { return mData; }
        constexpr size_t size() const { return Dimension; }
    
        // Load or store the pointer from / to raw data
        static VectorN Load(const Type *source);
        static void Store(const VectorN &source, Type *destination);
    
        // Index the vector
        Type &operator[](size_t i) { return mData[i]; }
        const Type &operator[](size_t i) const { return mData[i]; }
    
        // Basic arithmetic operations
        VectorN operator+() const;
        VectorN operator-() const;
        VectorN operator+(const VectorN &other) const;
        VectorN operator-(const VectorN &other) const;
        VectorN operator*(const VectorN &other) const;
        VectorN operator/(const VectorN &other) const;
        VectorN operator*(Type other) const;
        VectorN operator/(Type other) const;
        friend VectorN operator*(Type a, const VectorN &b) { return b * a; }
    
        // Compound arithmetic operations
        VectorN &operator+=(const VectorN &other);
        VectorN &operator-=(const VectorN &other);
        VectorN &operator*=(const VectorN &other);
        VectorN &operator/=(const VectorN &other);
        VectorN &operator*=(Type other);
        VectorN &operator/=(Type other);
    
        // Comparison operators
        bool operator==(const VectorN &other) const;
        bool operator!=(const VectorN &other) const;
    
        // Other arithmetic operations
        Type length() const;
        Type lengthSquared() const;
        Type dot(const VectorBase<Dimension, Type> &other) const;
        VectorN normalized() const;
    
      protected:
        template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
        void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &... args);
    
        // Some old compilers consider this function an alternative for initWithList(Vector)
        // when the variant above is more precise. Use SFINAE on the return value to hide
        // this variant for non-arithmetic types. The return value is still void.
        template <size_t CurrentIndex, typename OtherType, typename... Args>
        typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList(
            OtherType arg1,
            const Args &... args);
    
        template <size_t CurrentIndex>
        void initWithList() const;
    
        template <size_t Dimension2, typename Type2>
        friend class VectorBase;
    
        Type mData[Dimension];
    };
    
    template <size_t Dimension, typename Type>
    std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector);
    
    template <typename Type>
    class Vector<2, Type> : public VectorBase<2, Type>
    {
      public:
        // Import the constructors defined in VectorBase
        using VectorBase<2, Type>::VectorBase;
    
        // Element shorthands
        Type &x() { return this->mData[0]; }
        Type &y() { return this->mData[1]; }
    
        const Type &x() const { return this->mData[0]; }
        const Type &y() const { return this->mData[1]; }
    };
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector);
    
    template <typename Type>
    class Vector<3, Type> : public VectorBase<3, Type>
    {
      public:
        // Import the constructors defined in VectorBase
        using VectorBase<3, Type>::VectorBase;
    
        // Additional operations
        Vector<3, Type> cross(const Vector<3, Type> &other) const;
    
        // Element shorthands
        Type &x() { return this->mData[0]; }
        Type &y() { return this->mData[1]; }
        Type &z() { return this->mData[2]; }
    
        const Type &x() const { return this->mData[0]; }
        const Type &y() const { return this->mData[1]; }
        const Type &z() const { return this->mData[2]; }
    };
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector);
    
    template <typename Type>
    class Vector<4, Type> : public VectorBase<4, Type>
    {
      public:
        // Import the constructors defined in VectorBase
        using VectorBase<4, Type>::VectorBase;
    
        // Element shorthands
        Type &x() { return this->mData[0]; }
        Type &y() { return this->mData[1]; }
        Type &z() { return this->mData[2]; }
        Type &w() { return this->mData[3]; }
    
        const Type &x() const { return this->mData[0]; }
        const Type &y() const { return this->mData[1]; }
        const Type &z() const { return this->mData[2]; }
        const Type &w() const { return this->mData[3]; }
    };
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector);
    
    // Implementation of constructors and misc operations
    
    template <size_t Dimension, typename Type>
    VectorBase<Dimension, Type>::VectorBase(Type element)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] = element;
        }
    }
    
    template <size_t Dimension, typename Type>
    template <typename Type2>
    VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] = static_cast<Type>(other.mData[i]);
        }
    }
    
    // Ideally we would like to have only two constructors:
    //  - a scalar constructor that takes Type as a parameter
    //  - a compound constructor
    // However if we define the compound constructor for when it has a single arguments, then calling
    // Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound
    // constructor with a single argument, which is the copy constructor. We end up with three
    // constructors:
    //  - the scalar constructor
    //  - the copy constructor
    //  - the compound constructor for two or more arguments, hence the arg1, and arg2 here.
    template <size_t Dimension, typename Type>
    template <typename Arg1, typename Arg2, typename... Args>
    VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &... args)
    {
        initWithList<0>(arg1, arg2, args...);
    }
    
    template <size_t Dimension, typename Type>
    template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
    void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1,
                                                   const Args &... args)
    {
        static_assert(CurrentIndex + OtherDimension <= Dimension,
                      "Too much data in the vector constructor.");
        for (size_t i = 0; i < OtherDimension; ++i)
        {
            mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]);
        }
        initWithList<CurrentIndex + OtherDimension>(args...);
    }
    
    template <size_t Dimension, typename Type>
    template <size_t CurrentIndex, typename OtherType, typename... Args>
    typename std::enable_if<std::is_arithmetic<OtherType>::value>::type
    VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &... args)
    {
        static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor.");
        mData[CurrentIndex] = static_cast<Type>(arg1);
        initWithList<CurrentIndex + 1>(args...);
    }
    
    template <size_t Dimension, typename Type>
    template <size_t CurrentIndex>
    void VectorBase<Dimension, Type>::initWithList() const
    {
        static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor.");
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source)
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = source[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            destination[i] = source.mData[i];
        }
    }
    
    // Implementation of basic arithmetic operations
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = +mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = -mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+(
        const Vector<Dimension, Type> &other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] + other.mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-(
        const Vector<Dimension, Type> &other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] - other.mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(
        const Vector<Dimension, Type> &other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] * other.mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(
        const Vector<Dimension, Type> &other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] / other.mData[i];
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] * other;
        }
        return result;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const
    {
        Vector<Dimension, Type> result;
        for (size_t i = 0; i < Dimension; ++i)
        {
            result.mData[i] = mData[i] / other;
        }
        return result;
    }
    
    // Implementation of compound arithmetic operations
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=(
        const Vector<Dimension, Type> &other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] += other.mData[i];
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=(
        const Vector<Dimension, Type> &other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] -= other.mData[i];
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(
        const Vector<Dimension, Type> &other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] *= other.mData[i];
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(
        const Vector<Dimension, Type> &other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] /= other.mData[i];
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] *= other;
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other)
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            mData[i] /= other;
        }
        return *static_cast<Vector<Dimension, Type> *>(this);
    }
    
    // Implementation of comparison operators
    template <size_t Dimension, typename Type>
    bool VectorBase<Dimension, Type>::operator==(const Vector<Dimension, Type> &other) const
    {
        for (size_t i = 0; i < Dimension; ++i)
        {
            if (mData[i] != other.mData[i])
            {
                return false;
            }
        }
        return true;
    }
    
    template <size_t Dimension, typename Type>
    bool VectorBase<Dimension, Type>::operator!=(const Vector<Dimension, Type> &other) const
    {
        return !(*this == other);
    }
    
    // Implementation of other arithmetic operations
    template <size_t Dimension, typename Type>
    Type VectorBase<Dimension, Type>::length() const
    {
        static_assert(std::is_floating_point<Type>::value,
                      "VectorN::length is only defined for floating point vectors");
        return std::sqrt(lengthSquared());
    }
    
    template <size_t Dimension, typename Type>
    Type VectorBase<Dimension, Type>::lengthSquared() const
    {
        return dot(*this);
    }
    
    template <size_t Dimension, typename Type>
    Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const
    {
        Type sum = Type();
        for (size_t i = 0; i < Dimension; ++i)
        {
            sum += mData[i] * other.mData[i];
        }
        return sum;
    }
    
    template <size_t Dimension, typename Type>
    std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector)
    {
        ostream << "[ ";
        for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++)
        {
            if (elementIdx > 0)
            {
                ostream << ", ";
            }
            ostream << vector.data()[elementIdx];
        }
        ostream << " ]";
        return ostream;
    }
    
    template <size_t Dimension, typename Type>
    Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const
    {
        static_assert(std::is_floating_point<Type>::value,
                      "VectorN::normalized is only defined for floating point vectors");
        return *this / length();
    }
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector)
    {
        return ostream << static_cast<const VectorBase<2, Type> &>(vector);
    }
    
    template <typename Type>
    Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const
    {
        return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(),
                               x() * other.y() - y() * other.x());
    }
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector)
    {
        return ostream << static_cast<const VectorBase<3, Type> &>(vector);
    }
    
    template <typename Type>
    std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector)
    {
        return ostream << static_cast<const VectorBase<4, Type> &>(vector);
    }
    
    }  // namespace angle
    
    #endif  // COMMON_VECTOR_UTILS_H_