tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vector_utils.h (15908B)


      1 //
      2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // vector_utils.h: Utility classes implementing various vector operations
      7 
      8 #ifndef COMMON_VECTOR_UTILS_H_
      9 #define COMMON_VECTOR_UTILS_H_
     10 
     11 #include <cmath>
     12 #include <cstddef>
     13 #include <ostream>
     14 #include <type_traits>
     15 
     16 namespace angle
     17 {
     18 
     19 template <size_t Dimension, typename Type>
     20 class Vector;
     21 
     22 using Vector2 = Vector<2, float>;
     23 using Vector3 = Vector<3, float>;
     24 using Vector4 = Vector<4, float>;
     25 
     26 using Vector2I = Vector<2, int>;
     27 using Vector3I = Vector<3, int>;
     28 using Vector4I = Vector<4, int>;
     29 
     30 using Vector2U = Vector<2, unsigned int>;
     31 using Vector3U = Vector<3, unsigned int>;
     32 using Vector4U = Vector<4, unsigned int>;
     33 
     34 template <size_t Dimension, typename Type>
     35 class VectorBase
     36 {
     37  public:
     38    using VectorN = Vector<Dimension, Type>;
     39 
     40    // Constructors
     41    VectorBase() = default;
     42    explicit VectorBase(Type element);
     43 
     44    template <typename Type2>
     45    VectorBase(const VectorBase<Dimension, Type2> &other);
     46 
     47    template <typename Arg1, typename Arg2, typename... Args>
     48    VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args);
     49 
     50    // Access the vector backing storage directly
     51    const Type *data() const { return mData; }
     52    Type *data() { return mData; }
     53    constexpr size_t size() const { return Dimension; }
     54 
     55    // Load or store the pointer from / to raw data
     56    static VectorN Load(const Type *source);
     57    static void Store(const VectorN &source, Type *destination);
     58 
     59    // Index the vector
     60    Type &operator[](size_t i) { return mData[i]; }
     61    const Type &operator[](size_t i) const { return mData[i]; }
     62 
     63    // Basic arithmetic operations
     64    VectorN operator+() const;
     65    VectorN operator-() const;
     66    VectorN operator+(const VectorN &other) const;
     67    VectorN operator-(const VectorN &other) const;
     68    VectorN operator*(const VectorN &other) const;
     69    VectorN operator/(const VectorN &other) const;
     70    VectorN operator*(Type other) const;
     71    VectorN operator/(Type other) const;
     72    friend VectorN operator*(Type a, const VectorN &b) { return b * a; }
     73 
     74    // Compound arithmetic operations
     75    VectorN &operator+=(const VectorN &other);
     76    VectorN &operator-=(const VectorN &other);
     77    VectorN &operator*=(const VectorN &other);
     78    VectorN &operator/=(const VectorN &other);
     79    VectorN &operator*=(Type other);
     80    VectorN &operator/=(Type other);
     81 
     82    // Comparison operators
     83    bool operator==(const VectorBase<Dimension, Type> &other) const;
     84    bool operator!=(const VectorBase<Dimension, Type> &other) const;
     85 
     86    // Other arithmetic operations
     87    Type length() const;
     88    Type lengthSquared() const;
     89    Type dot(const VectorBase<Dimension, Type> &other) const;
     90    VectorN normalized() const;
     91 
     92  protected:
     93    template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
     94    void initWithList(const Vector<OtherDimension, OtherType> &arg1, const Args &...args);
     95 
     96    // Some old compilers consider this function an alternative for initWithList(Vector)
     97    // when the variant above is more precise. Use SFINAE on the return value to hide
     98    // this variant for non-arithmetic types. The return value is still void.
     99    template <size_t CurrentIndex, typename OtherType, typename... Args>
    100    typename std::enable_if<std::is_arithmetic<OtherType>::value>::type initWithList(
    101        OtherType arg1,
    102        const Args &...args);
    103 
    104    template <size_t CurrentIndex>
    105    void initWithList() const;
    106 
    107    template <size_t Dimension2, typename Type2>
    108    friend class VectorBase;
    109 
    110    Type mData[Dimension];
    111 };
    112 
    113 template <size_t Dimension, typename Type>
    114 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector);
    115 
    116 template <typename Type>
    117 class Vector<2, Type> : public VectorBase<2, Type>
    118 {
    119  public:
    120    // Import the constructors defined in VectorBase
    121    using VectorBase<2, Type>::VectorBase;
    122 
    123    // Element shorthands
    124    Type &x() { return this->mData[0]; }
    125    Type &y() { return this->mData[1]; }
    126 
    127    const Type &x() const { return this->mData[0]; }
    128    const Type &y() const { return this->mData[1]; }
    129 };
    130 
    131 template <typename Type>
    132 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector);
    133 
    134 template <typename Type>
    135 class Vector<3, Type> : public VectorBase<3, Type>
    136 {
    137  public:
    138    // Import the constructors defined in VectorBase
    139    using VectorBase<3, Type>::VectorBase;
    140 
    141    // Additional operations
    142    Vector<3, Type> cross(const Vector<3, Type> &other) const;
    143 
    144    // Element shorthands
    145    Type &x() { return this->mData[0]; }
    146    Type &y() { return this->mData[1]; }
    147    Type &z() { return this->mData[2]; }
    148 
    149    const Type &x() const { return this->mData[0]; }
    150    const Type &y() const { return this->mData[1]; }
    151    const Type &z() const { return this->mData[2]; }
    152 };
    153 
    154 template <typename Type>
    155 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector);
    156 
    157 template <typename Type>
    158 class Vector<4, Type> : public VectorBase<4, Type>
    159 {
    160  public:
    161    // Import the constructors defined in VectorBase
    162    using VectorBase<4, Type>::VectorBase;
    163 
    164    // Element shorthands
    165    Type &x() { return this->mData[0]; }
    166    Type &y() { return this->mData[1]; }
    167    Type &z() { return this->mData[2]; }
    168    Type &w() { return this->mData[3]; }
    169 
    170    const Type &x() const { return this->mData[0]; }
    171    const Type &y() const { return this->mData[1]; }
    172    const Type &z() const { return this->mData[2]; }
    173    const Type &w() const { return this->mData[3]; }
    174 };
    175 
    176 template <typename Type>
    177 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector);
    178 
    179 // Implementation of constructors and misc operations
    180 
    181 template <size_t Dimension, typename Type>
    182 VectorBase<Dimension, Type>::VectorBase(Type element)
    183 {
    184    for (size_t i = 0; i < Dimension; ++i)
    185    {
    186        mData[i] = element;
    187    }
    188 }
    189 
    190 template <size_t Dimension, typename Type>
    191 template <typename Type2>
    192 VectorBase<Dimension, Type>::VectorBase(const VectorBase<Dimension, Type2> &other)
    193 {
    194    for (size_t i = 0; i < Dimension; ++i)
    195    {
    196        mData[i] = static_cast<Type>(other.mData[i]);
    197    }
    198 }
    199 
    200 // Ideally we would like to have only two constructors:
    201 //  - a scalar constructor that takes Type as a parameter
    202 //  - a compound constructor
    203 // However if we define the compound constructor for when it has a single arguments, then calling
    204 // Vector2(0.0) will be ambiguous. To solve this we take advantage of there being a single compound
    205 // constructor with a single argument, which is the copy constructor. We end up with three
    206 // constructors:
    207 //  - the scalar constructor
    208 //  - the copy constructor
    209 //  - the compound constructor for two or more arguments, hence the arg1, and arg2 here.
    210 template <size_t Dimension, typename Type>
    211 template <typename Arg1, typename Arg2, typename... Args>
    212 VectorBase<Dimension, Type>::VectorBase(const Arg1 &arg1, const Arg2 &arg2, const Args &...args)
    213 {
    214    initWithList<0>(arg1, arg2, args...);
    215 }
    216 
    217 template <size_t Dimension, typename Type>
    218 template <size_t CurrentIndex, size_t OtherDimension, typename OtherType, typename... Args>
    219 void VectorBase<Dimension, Type>::initWithList(const Vector<OtherDimension, OtherType> &arg1,
    220                                               const Args &...args)
    221 {
    222    static_assert(CurrentIndex + OtherDimension <= Dimension,
    223                  "Too much data in the vector constructor.");
    224    for (size_t i = 0; i < OtherDimension; ++i)
    225    {
    226        mData[CurrentIndex + i] = static_cast<Type>(arg1.mData[i]);
    227    }
    228    initWithList<CurrentIndex + OtherDimension>(args...);
    229 }
    230 
    231 template <size_t Dimension, typename Type>
    232 template <size_t CurrentIndex, typename OtherType, typename... Args>
    233 typename std::enable_if<std::is_arithmetic<OtherType>::value>::type
    234 VectorBase<Dimension, Type>::initWithList(OtherType arg1, const Args &...args)
    235 {
    236    static_assert(CurrentIndex + 1 <= Dimension, "Too much data in the vector constructor.");
    237    mData[CurrentIndex] = static_cast<Type>(arg1);
    238    initWithList<CurrentIndex + 1>(args...);
    239 }
    240 
    241 template <size_t Dimension, typename Type>
    242 template <size_t CurrentIndex>
    243 void VectorBase<Dimension, Type>::initWithList() const
    244 {
    245    static_assert(CurrentIndex == Dimension, "Not enough data in the vector constructor.");
    246 }
    247 
    248 template <size_t Dimension, typename Type>
    249 Vector<Dimension, Type> VectorBase<Dimension, Type>::Load(const Type *source)
    250 {
    251    Vector<Dimension, Type> result;
    252    for (size_t i = 0; i < Dimension; ++i)
    253    {
    254        result.mData[i] = source[i];
    255    }
    256    return result;
    257 }
    258 
    259 template <size_t Dimension, typename Type>
    260 void VectorBase<Dimension, Type>::Store(const Vector<Dimension, Type> &source, Type *destination)
    261 {
    262    for (size_t i = 0; i < Dimension; ++i)
    263    {
    264        destination[i] = source.mData[i];
    265    }
    266 }
    267 
    268 // Implementation of basic arithmetic operations
    269 template <size_t Dimension, typename Type>
    270 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+() const
    271 {
    272    Vector<Dimension, Type> result;
    273    for (size_t i = 0; i < Dimension; ++i)
    274    {
    275        result.mData[i] = +mData[i];
    276    }
    277    return result;
    278 }
    279 
    280 template <size_t Dimension, typename Type>
    281 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-() const
    282 {
    283    Vector<Dimension, Type> result;
    284    for (size_t i = 0; i < Dimension; ++i)
    285    {
    286        result.mData[i] = -mData[i];
    287    }
    288    return result;
    289 }
    290 
    291 template <size_t Dimension, typename Type>
    292 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator+(
    293    const Vector<Dimension, Type> &other) const
    294 {
    295    Vector<Dimension, Type> result;
    296    for (size_t i = 0; i < Dimension; ++i)
    297    {
    298        result.mData[i] = mData[i] + other.mData[i];
    299    }
    300    return result;
    301 }
    302 
    303 template <size_t Dimension, typename Type>
    304 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator-(
    305    const Vector<Dimension, Type> &other) const
    306 {
    307    Vector<Dimension, Type> result;
    308    for (size_t i = 0; i < Dimension; ++i)
    309    {
    310        result.mData[i] = mData[i] - other.mData[i];
    311    }
    312    return result;
    313 }
    314 
    315 template <size_t Dimension, typename Type>
    316 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(
    317    const Vector<Dimension, Type> &other) const
    318 {
    319    Vector<Dimension, Type> result;
    320    for (size_t i = 0; i < Dimension; ++i)
    321    {
    322        result.mData[i] = mData[i] * other.mData[i];
    323    }
    324    return result;
    325 }
    326 
    327 template <size_t Dimension, typename Type>
    328 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(
    329    const Vector<Dimension, Type> &other) const
    330 {
    331    Vector<Dimension, Type> result;
    332    for (size_t i = 0; i < Dimension; ++i)
    333    {
    334        result.mData[i] = mData[i] / other.mData[i];
    335    }
    336    return result;
    337 }
    338 
    339 template <size_t Dimension, typename Type>
    340 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator*(Type other) const
    341 {
    342    Vector<Dimension, Type> result;
    343    for (size_t i = 0; i < Dimension; ++i)
    344    {
    345        result.mData[i] = mData[i] * other;
    346    }
    347    return result;
    348 }
    349 
    350 template <size_t Dimension, typename Type>
    351 Vector<Dimension, Type> VectorBase<Dimension, Type>::operator/(Type other) const
    352 {
    353    Vector<Dimension, Type> result;
    354    for (size_t i = 0; i < Dimension; ++i)
    355    {
    356        result.mData[i] = mData[i] / other;
    357    }
    358    return result;
    359 }
    360 
    361 // Implementation of compound arithmetic operations
    362 template <size_t Dimension, typename Type>
    363 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator+=(
    364    const Vector<Dimension, Type> &other)
    365 {
    366    for (size_t i = 0; i < Dimension; ++i)
    367    {
    368        mData[i] += other.mData[i];
    369    }
    370    return *static_cast<Vector<Dimension, Type> *>(this);
    371 }
    372 
    373 template <size_t Dimension, typename Type>
    374 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator-=(
    375    const Vector<Dimension, Type> &other)
    376 {
    377    for (size_t i = 0; i < Dimension; ++i)
    378    {
    379        mData[i] -= other.mData[i];
    380    }
    381    return *static_cast<Vector<Dimension, Type> *>(this);
    382 }
    383 
    384 template <size_t Dimension, typename Type>
    385 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(
    386    const Vector<Dimension, Type> &other)
    387 {
    388    for (size_t i = 0; i < Dimension; ++i)
    389    {
    390        mData[i] *= other.mData[i];
    391    }
    392    return *static_cast<Vector<Dimension, Type> *>(this);
    393 }
    394 
    395 template <size_t Dimension, typename Type>
    396 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(
    397    const Vector<Dimension, Type> &other)
    398 {
    399    for (size_t i = 0; i < Dimension; ++i)
    400    {
    401        mData[i] /= other.mData[i];
    402    }
    403    return *static_cast<Vector<Dimension, Type> *>(this);
    404 }
    405 
    406 template <size_t Dimension, typename Type>
    407 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator*=(Type other)
    408 {
    409    for (size_t i = 0; i < Dimension; ++i)
    410    {
    411        mData[i] *= other;
    412    }
    413    return *static_cast<Vector<Dimension, Type> *>(this);
    414 }
    415 
    416 template <size_t Dimension, typename Type>
    417 Vector<Dimension, Type> &VectorBase<Dimension, Type>::operator/=(Type other)
    418 {
    419    for (size_t i = 0; i < Dimension; ++i)
    420    {
    421        mData[i] /= other;
    422    }
    423    return *static_cast<Vector<Dimension, Type> *>(this);
    424 }
    425 
    426 // Implementation of comparison operators
    427 template <size_t Dimension, typename Type>
    428 bool VectorBase<Dimension, Type>::operator==(const VectorBase<Dimension, Type> &other) const
    429 {
    430    for (size_t i = 0; i < Dimension; ++i)
    431    {
    432        if (mData[i] != other.mData[i])
    433        {
    434            return false;
    435        }
    436    }
    437    return true;
    438 }
    439 
    440 template <size_t Dimension, typename Type>
    441 bool VectorBase<Dimension, Type>::operator!=(const VectorBase<Dimension, Type> &other) const
    442 {
    443    return !(*this == other);
    444 }
    445 
    446 // Implementation of other arithmetic operations
    447 template <size_t Dimension, typename Type>
    448 Type VectorBase<Dimension, Type>::length() const
    449 {
    450    static_assert(std::is_floating_point<Type>::value,
    451                  "VectorN::length is only defined for floating point vectors");
    452    return std::sqrt(lengthSquared());
    453 }
    454 
    455 template <size_t Dimension, typename Type>
    456 Type VectorBase<Dimension, Type>::lengthSquared() const
    457 {
    458    return dot(*this);
    459 }
    460 
    461 template <size_t Dimension, typename Type>
    462 Type VectorBase<Dimension, Type>::dot(const VectorBase<Dimension, Type> &other) const
    463 {
    464    Type sum = Type();
    465    for (size_t i = 0; i < Dimension; ++i)
    466    {
    467        sum += mData[i] * other.mData[i];
    468    }
    469    return sum;
    470 }
    471 
    472 template <size_t Dimension, typename Type>
    473 std::ostream &operator<<(std::ostream &ostream, const VectorBase<Dimension, Type> &vector)
    474 {
    475    ostream << "[ ";
    476    for (size_t elementIdx = 0; elementIdx < Dimension; elementIdx++)
    477    {
    478        if (elementIdx > 0)
    479        {
    480            ostream << ", ";
    481        }
    482        ostream << vector.data()[elementIdx];
    483    }
    484    ostream << " ]";
    485    return ostream;
    486 }
    487 
    488 template <size_t Dimension, typename Type>
    489 Vector<Dimension, Type> VectorBase<Dimension, Type>::normalized() const
    490 {
    491    static_assert(std::is_floating_point<Type>::value,
    492                  "VectorN::normalized is only defined for floating point vectors");
    493    return *this / length();
    494 }
    495 
    496 template <typename Type>
    497 std::ostream &operator<<(std::ostream &ostream, const Vector<2, Type> &vector)
    498 {
    499    return ostream << static_cast<const VectorBase<2, Type> &>(vector);
    500 }
    501 
    502 template <typename Type>
    503 Vector<3, Type> Vector<3, Type>::cross(const Vector<3, Type> &other) const
    504 {
    505    return Vector<3, Type>(y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(),
    506                           x() * other.y() - y() * other.x());
    507 }
    508 
    509 template <typename Type>
    510 std::ostream &operator<<(std::ostream &ostream, const Vector<3, Type> &vector)
    511 {
    512    return ostream << static_cast<const VectorBase<3, Type> &>(vector);
    513 }
    514 
    515 template <typename Type>
    516 std::ostream &operator<<(std::ostream &ostream, const Vector<4, Type> &vector)
    517 {
    518    return ostream << static_cast<const VectorBase<4, Type> &>(vector);
    519 }
    520 
    521 }  // namespace angle
    522 
    523 #endif  // COMMON_VECTOR_UTILS_H_