mirror of https://github.com/mosra/magnum.git
6 changed files with 345 additions and 0 deletions
@ -0,0 +1,211 @@
|
||||
#ifndef Magnum_Array_h |
||||
#define Magnum_Array_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class Magnum::Array, Magnum::Array1D, Magnum::Array2D, Magnum::Array3D |
||||
*/ |
||||
|
||||
#include <cstdint> |
||||
#include <type_traits> |
||||
#include <Utility/Debug.h> |
||||
|
||||
namespace Magnum { |
||||
|
||||
/**
|
||||
@brief %Array |
||||
@tparam dimensions Dimension count |
||||
@tparam T Data type |
||||
|
||||
Similar to Math::Vector, but more suitable for storing enum values which don't |
||||
need any math operations and fuzzy comparison (e.g. enum values). Unlike |
||||
Math::Vector this class has non-explicit constructor from one value. |
||||
@see Array1D, Array2D, Array3D |
||||
*/ |
||||
template<std::uint8_t dimensions, class T> class Array { |
||||
public: |
||||
typedef T Type; /**< @brief Data type */ |
||||
const static std::uint8_t Dimensions = dimensions; /**< @brief Dimension count */ |
||||
|
||||
/**
|
||||
* @brief Default constructor |
||||
* |
||||
* Sets all components to their default-constructed values |
||||
*/ |
||||
inline constexpr Array(): _data() {} |
||||
|
||||
/**
|
||||
* @brief Initializer-list constructor |
||||
* @param first First value |
||||
* @param next Next values |
||||
*/ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
template<class ...U> inline constexpr Array(T first, T second, U... next): _data{first, second, next...} { |
||||
static_assert(sizeof...(next)+2 == dimensions, "Improper number of arguments passed to Array constructor"); |
||||
} |
||||
template<class U = T> inline constexpr Array(typename std::enable_if<std::is_same<T, U>::value && dimensions == 1, U>::type first): _data{first} {} |
||||
#else |
||||
template<class ...U> inline constexpr Array(T first, U... next); |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param value Value for all fields |
||||
*/ |
||||
template<class U, class = typename std::enable_if<std::is_same<T, U>::value && dimensions != 1, U>::type> inline Array(U value) { |
||||
for(std::uint8_t i = 0; i != dimensions; ++i) |
||||
_data[i] = value; |
||||
} |
||||
|
||||
/** @brief Equality */ |
||||
inline bool operator==(const Array<dimensions, T>& other) const { |
||||
for(std::uint8_t i = 0; i != dimensions; ++i) |
||||
if(_data[i] != other._data[i]) return false; |
||||
return true; |
||||
} |
||||
|
||||
/** @brief Non-equality */ |
||||
inline bool operator!=(const Array<dimensions, T>& other) const { |
||||
return !operator==(other); |
||||
} |
||||
|
||||
/** @brief Value at given position */ |
||||
inline T& operator[](std::uint8_t pos) { return _data[pos]; } |
||||
inline constexpr T operator[](std::uint8_t pos) const { return _data[pos]; } /**< @overload */ |
||||
|
||||
/**
|
||||
* @brief Raw data |
||||
* @return One-dimensional array of `dimensions` length |
||||
*/ |
||||
inline T* data() { return _data; } |
||||
inline constexpr const T* data() const { return _data; } /**< @overload */ |
||||
|
||||
private: |
||||
T _data[dimensions]; |
||||
}; |
||||
|
||||
/**
|
||||
@brief One-dimensional array |
||||
@tparam T Data type |
||||
*/ |
||||
template<class T> class Array1D: public Array<1, T> { |
||||
public: |
||||
/** @copydoc Array::Array() */ |
||||
inline constexpr Array1D() = default; |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param x X component |
||||
*/ |
||||
inline constexpr Array1D(T x): Array<1, T>(x) {} |
||||
|
||||
/** @brief Copy constructor */ |
||||
inline constexpr Array1D(const Array<1, T>& other): Array<1, T>(other) {} |
||||
|
||||
inline T& x() { return (*this)[0]; } /**< @brief X component */ |
||||
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ |
||||
}; |
||||
|
||||
/**
|
||||
@brief Two-dimensional array |
||||
@tparam T Data type |
||||
*/ |
||||
template<class T> class Array2D: public Array<2, T> { |
||||
public: |
||||
/** @copydoc Array::Array() */ |
||||
inline constexpr Array2D() = default; |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param x X component |
||||
* @param y Y component |
||||
*/ |
||||
inline constexpr Array2D(T x, T y): Array<2, T>(x, y) {} |
||||
|
||||
/** @copydoc Array::Array(U) */ |
||||
inline constexpr Array2D(T value): Array<2, T>(value, value) {} |
||||
|
||||
/** @brief Copy constructor */ |
||||
inline constexpr Array2D(const Array<2, T>& other): Array<2, T>(other) {} |
||||
|
||||
inline T& x() { return (*this)[0]; } /**< @brief X component */ |
||||
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ |
||||
inline T& y() { return (*this)[1]; } /**< @brief Y component */ |
||||
inline constexpr T y() const { return (*this)[1]; } /**< @overload */ |
||||
}; |
||||
|
||||
/**
|
||||
@brief Three-dimensional array |
||||
@tparam T Data type |
||||
*/ |
||||
template<class T> class Array3D: public Array<3, T> { |
||||
public: |
||||
/** @copydoc Array::Array() */ |
||||
inline constexpr Array3D() {} |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param x X component |
||||
* @param y Y component |
||||
* @param z Z component |
||||
*/ |
||||
inline constexpr Array3D(T x, T y, T z): Array<3, T>(x, y, z) {} |
||||
|
||||
/** @copydoc Array::Array(U) */ |
||||
inline constexpr Array3D(T value): Array<3, T>(value, value, value) {} |
||||
|
||||
/** @brief Copy constructor */ |
||||
inline constexpr Array3D(const Array<3, T>& other): Array<3, T>(other) {} |
||||
|
||||
inline T& x() { return (*this)[0]; } /**< @brief X component */ |
||||
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ |
||||
inline T& y() { return (*this)[1]; } /**< @brief Y component */ |
||||
inline constexpr T y() const { return (*this)[1]; } /**< @overload */ |
||||
inline T& z() { return (*this)[2]; } /**< @brief Z component */ |
||||
inline constexpr T z() const { return (*this)[2]; } /**< @overload */ |
||||
}; |
||||
|
||||
/** @debugoperator{Magnum::Array} */ |
||||
template<std::uint8_t dimensions, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Array<dimensions, T>& value) { |
||||
debug << "Array("; |
||||
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); |
||||
for(std::uint8_t i = 0; i != dimensions; ++i) { |
||||
if(i != 0) debug << ", "; |
||||
debug << value[i]; |
||||
} |
||||
debug << ')'; |
||||
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); |
||||
return debug; |
||||
} |
||||
|
||||
/** @debugoperator{Magnum::Array1D} */ |
||||
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Array1D<T>& value) { |
||||
return debug << static_cast<const Array<1, T>&>(value); |
||||
} |
||||
|
||||
/** @debugoperator{Magnum::Array2D} */ |
||||
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Array2D<T>& value) { |
||||
return debug << static_cast<const Array<2, T>&>(value); |
||||
} |
||||
|
||||
/** @debugoperator{Magnum::Array3D} */ |
||||
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Array3D<T>& value) { |
||||
return debug << static_cast<const Array<3, T>&>(value); |
||||
} |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
#include "ArrayTest.h" |
||||
|
||||
#include "Array.h" |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Test::ArrayTest) |
||||
|
||||
namespace Magnum { namespace Test { |
||||
|
||||
typedef Magnum::Array1D<int> Array1D; |
||||
typedef Magnum::Array2D<int> Array2D; |
||||
typedef Magnum::Array3D<int> Array3D; |
||||
|
||||
ArrayTest::ArrayTest() { |
||||
addTests(&ArrayTest::construct, |
||||
&ArrayTest::constexprConstruct, |
||||
&ArrayTest::equality, |
||||
&ArrayTest::access); |
||||
} |
||||
|
||||
void ArrayTest::construct() { |
||||
CORRADE_COMPARE(Array1D(5), (Array<1, int>(5))); |
||||
CORRADE_COMPARE(Array2D(5, 3), (Array<2, int>(5, 3))); |
||||
CORRADE_COMPARE(Array3D(5, 3, -2), (Array<3, int>(5, 3, -2))); |
||||
|
||||
/* Verify proper expansion */ |
||||
CORRADE_COMPARE((Array<3, int>(5)), (Array<3, int>(5, 5, 5))); |
||||
CORRADE_COMPARE(Array2D(5), (Array<2, int>(5, 5))); |
||||
CORRADE_COMPARE(Array3D(5), (Array<3, int>(5, 5, 5))); |
||||
} |
||||
|
||||
void ArrayTest::constexprConstruct() { |
||||
/* Verify that all full constructors can be called as constexpr */ |
||||
constexpr Array1D a(5); |
||||
constexpr Array2D b(5, 3); |
||||
constexpr Array2D b2(5); |
||||
constexpr Array3D c(5, 6, 7); |
||||
constexpr Array3D c2(5); |
||||
constexpr Array<3, int> d(5, 6, 7); |
||||
|
||||
CORRADE_COMPARE(a, Array1D(5)); |
||||
CORRADE_COMPARE(b, Array2D(5, 3)); |
||||
CORRADE_COMPARE(b2, Array2D(5)); |
||||
CORRADE_COMPARE(c, Array3D(5, 6, 7)); |
||||
CORRADE_COMPARE(c2, Array3D(5)); |
||||
CORRADE_COMPARE(d, (Array<3, int>(5, 6, 7))); |
||||
} |
||||
|
||||
void ArrayTest::equality() { |
||||
CORRADE_VERIFY((Array<3, int>(5, 6, 7) == Array<3, int>(5, 6, 7))); |
||||
CORRADE_VERIFY((Array<3, int>(5, 6, 7) != Array<3, int>(5, 6, 8))); |
||||
} |
||||
|
||||
void ArrayTest::access() { |
||||
Array1D a(50); |
||||
const Array1D ac(50); |
||||
Array2D b(5, 3); |
||||
const Array2D bc(5, 3); |
||||
Array3D c(-5, 6, 7); |
||||
const Array3D cc(-5, 6, 7); |
||||
|
||||
CORRADE_COMPARE(a.x(), 50); |
||||
CORRADE_COMPARE(ac.x(), 50); |
||||
|
||||
CORRADE_COMPARE(b.x(), 5); |
||||
CORRADE_COMPARE(b.y(), 3); |
||||
CORRADE_COMPARE(bc.x(), 5); |
||||
CORRADE_COMPARE(bc.y(), 3); |
||||
|
||||
CORRADE_COMPARE(c.x(), -5); |
||||
CORRADE_COMPARE(c.y(), 6); |
||||
CORRADE_COMPARE(c.z(), 7); |
||||
CORRADE_COMPARE(cc.x(), -5); |
||||
CORRADE_COMPARE(cc.y(), 6); |
||||
CORRADE_COMPARE(cc.z(), 7); |
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,34 @@
|
||||
#ifndef Magnum_Test_ArrayTest_h |
||||
#define Magnum_Test_ArrayTest_h |
||||
/*
|
||||
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
This file is part of Magnum. |
||||
|
||||
Magnum is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU Lesser General Public License version 3 |
||||
only, as published by the Free Software Foundation. |
||||
|
||||
Magnum is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU Lesser General Public License version 3 for more details. |
||||
*/ |
||||
|
||||
#include <TestSuite/Tester.h> |
||||
|
||||
namespace Magnum { namespace Test { |
||||
|
||||
class ArrayTest: public Corrade::TestSuite::Tester<ArrayTest> { |
||||
public: |
||||
ArrayTest(); |
||||
|
||||
void construct(); |
||||
void constexprConstruct(); |
||||
void equality(); |
||||
void access(); |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue