basic vector type

This commit is contained in:
BlackMATov
2020-11-20 22:24:15 +07:00
parent c1200d8747
commit 98b11af392
2 changed files with 413 additions and 2 deletions

View File

@@ -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>;
}

View File

@@ -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));
}
}