mirror of
https://github.com/BlackMATov/vmath.hpp.git
synced 2025-12-15 04:35:25 +07:00
basic vector type
This commit is contained in:
@@ -6,6 +6,239 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
struct uninit_t {};
|
||||
inline constexpr uninit_t uninit;
|
||||
}
|
||||
|
||||
namespace vmath_hpp::detail
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
class vec_base;
|
||||
|
||||
template < typename T >
|
||||
class vec_base<T, 2> {
|
||||
public:
|
||||
T x, y;
|
||||
public:
|
||||
constexpr vec_base() : x{}, y{} {}
|
||||
constexpr explicit vec_base(uninit_t) {}
|
||||
|
||||
constexpr explicit vec_base(const T& v)
|
||||
: x{v}, y{v} {}
|
||||
|
||||
constexpr vec_base(T x, T y)
|
||||
: x{std::move(x)}, y{std::move(y)} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 3>&& xy)
|
||||
: x{std::move(xy.x)} , y{std::move(xy.y)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 3>& xy)
|
||||
: x{xy.x} , y{xy.y} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 4>&& xy)
|
||||
: x{std::move(xy.x)} , y{std::move(xy.y)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 4>& xy)
|
||||
: x{xy.x} , y{xy.y} {}
|
||||
|
||||
constexpr T* data() noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
|
||||
constexpr const T* data() const noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
class vec_base<T, 3> {
|
||||
public:
|
||||
T x, y, z;
|
||||
public:
|
||||
constexpr vec_base() : x{}, y{}, z{} {}
|
||||
constexpr explicit vec_base(uninit_t) {}
|
||||
|
||||
constexpr explicit vec_base(const T& v)
|
||||
: x{v}, y{v}, z{v} {}
|
||||
|
||||
constexpr vec_base(T x, T y, T z)
|
||||
: x{std::move(x)}, y{std::move(y)}, z{std::move(z)} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 2>&& xy, T z)
|
||||
: x{std::move(xy.x)} , y{std::move(xy.y)} , z{std::move(z)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 2>& xy, T z)
|
||||
: x{xy.x} , y{xy.y} , z{std::move(z)} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 4>&& xyz)
|
||||
: x{std::move(xyz.x)} , y{std::move(xyz.y)} , z{std::move(xyz.z)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 4>& xyz)
|
||||
: x{xyz.x} , y{xyz.y} , z{xyz.z} {}
|
||||
|
||||
constexpr T* data() noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
|
||||
constexpr const T* data() const noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
class vec_base<T, 4> {
|
||||
public:
|
||||
T x, y, z, w;
|
||||
public:
|
||||
constexpr vec_base() : x{}, y{}, z{}, w{} {}
|
||||
constexpr explicit vec_base(uninit_t) {}
|
||||
|
||||
constexpr explicit vec_base(const T& v)
|
||||
: x{v}, y{v}, z{v}, w{v} {}
|
||||
|
||||
constexpr vec_base(T x, T y, T z, T w)
|
||||
: x{std::move(x)}, y{std::move(y)}, z{std::move(z)}, w{std::move(w)} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 2>&& xy, T z, T w)
|
||||
: x{std::move(xy.x)} , y{std::move(xy.y)} , z{std::move(z)} , w{std::move(w)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 2>& xy, T z, T w)
|
||||
: x{xy.x} , y{xy.y} , z{std::move(z)} , w{std::move(w)} {}
|
||||
|
||||
constexpr explicit vec_base(vec_base<T, 3>&& xyz, T w)
|
||||
: x{std::move(xyz.x)} , y{std::move(xyz.y)} , z{std::move(xyz.z)} , w{std::move(w)} {}
|
||||
constexpr explicit vec_base(const vec_base<T, 3>& xyz, T w)
|
||||
: x{xyz.x} , y{xyz.y} , z{xyz.z} , w{std::move(w)} {}
|
||||
|
||||
constexpr T* data() noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
|
||||
constexpr const T* data() const noexcept {
|
||||
return std::addressof(x);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
class vec final : public detail::vec_base<T, Size> {
|
||||
public:
|
||||
using self_type = vec;
|
||||
using value_type = T;
|
||||
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
public:
|
||||
using detail::vec_base<T, Size>::data;
|
||||
using detail::vec_base<T, Size>::vec_base;
|
||||
|
||||
vec(vec&&) = default;
|
||||
vec& operator=(vec&&) = default;
|
||||
|
||||
vec(const vec&) = default;
|
||||
vec& operator=(const vec&) = default;
|
||||
|
||||
void fill(const value_type& v) {
|
||||
std::fill_n(begin(), size(), v);
|
||||
}
|
||||
|
||||
void swap(vec& other) noexcept(std::is_nothrow_swappable_v<T>) {
|
||||
std::swap_ranges(begin(), end(), other.begin());
|
||||
}
|
||||
|
||||
constexpr iterator begin() noexcept { return iterator(data()); }
|
||||
constexpr const_iterator begin() const noexcept { return const_iterator(data()); }
|
||||
constexpr const_iterator cbegin() const noexcept { return const_iterator(data()); }
|
||||
|
||||
constexpr iterator end() noexcept { return iterator(data() + size()); }
|
||||
constexpr const_iterator end() const noexcept { return const_iterator(data() + size()); }
|
||||
constexpr const_iterator cend() const noexcept { return const_iterator(data() + size()); }
|
||||
|
||||
constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
|
||||
constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
|
||||
constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
|
||||
|
||||
constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
|
||||
constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
|
||||
constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
|
||||
|
||||
constexpr size_type size() const noexcept { return Size; }
|
||||
constexpr size_type max_size() const noexcept { return Size; }
|
||||
constexpr bool empty() const noexcept { return !Size; }
|
||||
|
||||
constexpr reference operator[](size_type index) noexcept { return data()[index]; }
|
||||
constexpr const_reference operator[](size_type index) const noexcept { return data()[index]; }
|
||||
|
||||
constexpr reference at(size_type index) {
|
||||
if ( index >= size() ) {
|
||||
throw std::out_of_range("vec::at");
|
||||
}
|
||||
return data()[index];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type index) const {
|
||||
if ( index >= size() ) {
|
||||
throw std::out_of_range("vec::at");
|
||||
}
|
||||
return data()[index];
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
void swap(vec<T, Size>& l, vec<T, Size>& r) noexcept(noexcept(l.swap(r))) {
|
||||
l.swap(r);
|
||||
}
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
bool operator==(const vec<T, Size>& l, const vec<T, Size>& r) {
|
||||
return std::equal(l.begin(), l.end(), r.begin());
|
||||
}
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
bool operator!=(const vec<T, Size>& l, const vec<T, Size>& r) {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
bool operator<(const vec<T, Size>& l, const vec<T, Size>& r) {
|
||||
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||
}
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
using vec2i = vec<int, 2>;
|
||||
using vec3i = vec<int, 3>;
|
||||
using vec4i = vec<int, 4>;
|
||||
|
||||
using vec2b = vec<bool, 2>;
|
||||
using vec3b = vec<bool, 3>;
|
||||
using vec4b = vec<bool, 4>;
|
||||
|
||||
using vec2f = vec<float, 2>;
|
||||
using vec3f = vec<float, 3>;
|
||||
using vec4f = vec<float, 4>;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,184 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("vmath") {
|
||||
REQUIRE(true);
|
||||
TEST_CASE("vmath/vec") {
|
||||
using namespace vmath_hpp;
|
||||
|
||||
SECTION("sizeof") {
|
||||
STATIC_REQUIRE(sizeof(vec2i{}) == sizeof(int) * 2);
|
||||
STATIC_REQUIRE(sizeof(vec3i{}) == sizeof(int) * 3);
|
||||
STATIC_REQUIRE(sizeof(vec4i{}) == sizeof(int) * 4);
|
||||
}
|
||||
|
||||
SECTION("ctors") {
|
||||
{
|
||||
REQUIRE(vec2i().x == 0);
|
||||
REQUIRE(vec2i().y == 0);
|
||||
|
||||
REQUIRE(vec2i(1).x == 1);
|
||||
REQUIRE(vec2i(1).y == 1);
|
||||
|
||||
REQUIRE(vec2i(1,2).x == 1);
|
||||
REQUIRE(vec2i(1,2).y == 2);
|
||||
}
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i v2 = v;
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i v2 = std::move(v);
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
{
|
||||
REQUIRE(vec2i(vec3i(1,2,3)) == vec2i(1,2));
|
||||
REQUIRE(vec2i(vec4i(1,2,3,4)) == vec2i(1,2));
|
||||
|
||||
REQUIRE(vec3i(vec2i(1,2),3) == vec3i(1,2,3));
|
||||
REQUIRE(vec3i(vec4i(1,2,3,4)) == vec3i(1,2,3));
|
||||
|
||||
REQUIRE(vec4i(vec2i(1,2),3,4) == vec4i(1,2,3,4));
|
||||
REQUIRE(vec4i(vec3i(1,2,3),4) == vec4i(1,2,3,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator=") {
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i v2;
|
||||
v2 = v;
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i v2;
|
||||
v2 = std::move(v);
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("fill") {
|
||||
vec2i v(1,2);
|
||||
v.fill(4);
|
||||
REQUIRE(v == vec2i(4));
|
||||
}
|
||||
|
||||
SECTION("swap") {
|
||||
{
|
||||
vec2i v1(1,2);
|
||||
vec2i v2(4,5);
|
||||
v1.swap(v2);
|
||||
REQUIRE(v1 == vec2i(4,5));
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
{
|
||||
vec2i v1(1,2);
|
||||
vec2i v2(4,5);
|
||||
swap(v1, v2);
|
||||
REQUIRE(v1 == vec2i(4,5));
|
||||
REQUIRE(v2 == vec2i(1,2));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("data") {
|
||||
vec2i v(1,2);
|
||||
REQUIRE(v.data() == &v.x);
|
||||
REQUIRE(std::as_const(v).data() == &v.x);
|
||||
}
|
||||
|
||||
SECTION("iter") {
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i::iterator i = v.begin();
|
||||
REQUIRE(*i++ == 1);
|
||||
REQUIRE(*i++ == 2);
|
||||
REQUIRE(v.end() == i);
|
||||
}
|
||||
{
|
||||
const vec2i v(1,2);
|
||||
vec2i::const_iterator i = v.begin();
|
||||
REQUIRE(*i++ == 1);
|
||||
REQUIRE(*i++ == 2);
|
||||
REQUIRE(v.end() == i);
|
||||
}
|
||||
{
|
||||
vec2i v(1,2);
|
||||
for ( auto i = v.begin(); i < v.end(); ++i ) {
|
||||
*i = *i * 2;
|
||||
}
|
||||
REQUIRE(v == vec2i(2,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("riter") {
|
||||
{
|
||||
vec2i v(1,2);
|
||||
vec2i::reverse_iterator i = v.rbegin();
|
||||
REQUIRE(*i++ == 2);
|
||||
REQUIRE(*i++ == 1);
|
||||
REQUIRE(v.rend() == i);
|
||||
for ( auto j = v.rbegin(); j < v.rend(); ++j ) {
|
||||
*j = *j * 2;
|
||||
}
|
||||
REQUIRE(v == vec2i(2,4));
|
||||
}
|
||||
{
|
||||
const vec2i v(1,2);
|
||||
vec2i::const_reverse_iterator i = v.rbegin();
|
||||
REQUIRE(*i++ == 2);
|
||||
REQUIRE(*i++ == 1);
|
||||
REQUIRE(v.rend() == i);
|
||||
}
|
||||
{
|
||||
vec2i v(1,2);
|
||||
for ( auto i = v.rbegin(); i < v.rend(); ++i ) {
|
||||
*i = *i * 2;
|
||||
}
|
||||
REQUIRE(v == vec2i(2,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("size/max_size/empty") {
|
||||
STATIC_REQUIRE(vec<int, 2>().size() == 2);
|
||||
STATIC_REQUIRE(vec<int, 2>().max_size() == 2);
|
||||
STATIC_REQUIRE_FALSE(vec<int, 2>().empty());
|
||||
|
||||
STATIC_REQUIRE(vec<int, 3>().size() == 3);
|
||||
STATIC_REQUIRE(vec<int, 3>().max_size() == 3);
|
||||
STATIC_REQUIRE_FALSE(vec<int, 3>().empty());
|
||||
}
|
||||
|
||||
SECTION("operator[]") {
|
||||
REQUIRE(vec2i(1,2).x == 1);
|
||||
REQUIRE(vec2i(1,2).y == 2);
|
||||
REQUIRE(vec2i(1,2)[0] == 1);
|
||||
REQUIRE(vec2i(1,2)[1] == 2);
|
||||
}
|
||||
|
||||
SECTION("at") {
|
||||
REQUIRE(vec2i(1,2).at(0) == 1);
|
||||
REQUIRE(vec2i(1,2).at(1) == 2);
|
||||
REQUIRE_THROWS_AS(vec2i(1,2).at(2), std::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("operator==/operator!=") {
|
||||
REQUIRE(vec2i(1,2) == vec2i(1,2));
|
||||
REQUIRE_FALSE(vec2i(1,2) == vec2i(2,2));
|
||||
REQUIRE_FALSE(vec2i(1,2) == vec2i(1,3));
|
||||
|
||||
REQUIRE_FALSE(vec2i(1,2) != vec2i(1,2));
|
||||
REQUIRE(vec2i(1,2) != vec2i(2,2));
|
||||
REQUIRE(vec2i(1,2) != vec2i(1,3));
|
||||
}
|
||||
|
||||
SECTION("operator<") {
|
||||
REQUIRE_FALSE(vec2i(1,2) < vec2i(1,2));
|
||||
|
||||
REQUIRE(vec2i(1,1) < vec2i(1,2));
|
||||
REQUIRE_FALSE(vec2i(1,2) < vec2i(1,1));
|
||||
|
||||
REQUIRE(vec2i(0,3) < vec2i(1,2));
|
||||
REQUIRE_FALSE(vec2i(1,2) < vec2i(0,3));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user