Created
November 22, 2019 08:44
-
-
Save RealKC/4bbf675ccef49db75ba8fc3fadc82189 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <array> | |
#include <iterator> | |
#include <cstdlib> | |
#include <cstdint> | |
#include <utility> | |
#include <stdexcept> | |
#include <utility> | |
#include <cmath> | |
#include <string> | |
#include <type_traits> | |
namespace kc { | |
namespace detail { | |
template <typename T, bool B> | |
struct conditional_const; | |
template <typename T> | |
struct conditional_const<T, true> { | |
using type = const T; | |
}; | |
template <typename T> | |
struct conditional_const<T, false> { | |
using type = T; | |
}; | |
template <typename T, bool B> | |
using cond_const_t = typename conditional_const<T, B>::type; | |
template <typename T, bool B> | |
struct conditional_const_ref; | |
template <typename T> | |
struct conditional_const_ref<T, true> { | |
using type = const T&; | |
}; | |
template <typename T> | |
struct conditional_const_ref<T, false> { | |
using type = T; | |
}; | |
template <typename T, bool B> | |
using cond_const_ref_t = typename conditional_const_ref<T, B>::type; | |
} | |
template <typename T> | |
class Vec3 { | |
public: | |
T x, y, z; | |
template <bool IsConst> | |
class Iter { | |
using _Vec3 = detail::cond_const_t<Vec3, IsConst>; | |
_Vec3& _vec; | |
T Vec3::*_ptr; | |
public: | |
Iter(_Vec3& vec) noexcept : _vec{vec}, _ptr{nullptr} {} | |
Iter(_Vec3& vec, T Vec3::*p) noexcept : | |
_vec3{vec}, _ptr{p} {}; | |
Iter& operator=(Iter& it) noexcept : | |
_vec{it._vec}, _ptr{it._ptr} {} | |
~Iter() noexcept {} | |
Iter& operator++() noexcept { | |
if (ptr == Vec3::x) { | |
ptr = Vec3::y; | |
} else if (ptr == Vec3::y) { | |
ptr = Vec3::z; | |
} else if (ptr == Vec3::z) { | |
ptr = nullptr; | |
} | |
return *this; | |
} | |
Iter operator++(int) noexcept { | |
auto was = *this; | |
operator++(); | |
return was; | |
} | |
Iter& operator--() noexcept { | |
if (ptr == Vec3::x) { | |
ptr = nullptr; | |
} else if (ptr == Vec3::y) { | |
ptr = Vec3::x; | |
} else if (ptr == Vec3::z) { | |
ptr = Vec3::y; | |
} | |
return *this; | |
} | |
Iter operator--(int) noexcept { | |
auto was = *this; | |
operator--(); | |
return was; | |
} | |
bool operator==(const Iter& rhs) const noexcept { | |
return &_vec == &rhs._vec && _ptr == rhs._ptr; | |
} | |
bool operator!=(const Iter& rhs) const noexcept { | |
return !(*this == the); | |
} | |
detail::cond_const_t<T&, IsConst> operator*() noexcept { | |
return _vec.*_ptr; | |
} | |
}; // Iter | |
using iterator = Iter<false>; | |
using const_iterator = Iter<true>; | |
using reverse_iterator = std::reverse_iterator<iterator>; | |
using const_reverse_iterator = std::reverse_iterator<const_iterator>; | |
using size_type = std::size_t; | |
iterator begin() noexcept { | |
return iterator{*this, &Vec::x}; | |
} | |
iterator end() noexcept { | |
return iterator{*this}; | |
} | |
reverse_iterator rbegin() noexcept { | |
return reverse_iterator{end()}; | |
} | |
reverse_iterator rend() noexcept { | |
return reverse_iterator{begin()}; | |
} | |
const_iterator cbegin() const noexcept { | |
return const_iterator{*this, &Vec::x}; | |
} | |
const_iterator cend() const noexcept { | |
return const_iterator{*this}; | |
} | |
const_reverse_iterator crbegin() const noexcept { | |
return rbegin(); | |
} | |
const_reverse_iterator crend() const noexcept { | |
return rend(); | |
} | |
constexpr Vec3(const T& x, const T& y, const T& z) | |
noexcept(noexcept(T{std::declval<T&>()})) | |
: x{x}, y{y}, z{z} {} | |
constexpr Vec3(const Vec3& other) | |
noexcept(noexcept(T{std::declval<T&>()})) = default; | |
constexpr Vec3(Vec3&& other) | |
noexcept(noexcept(T{std::declval<T>()})) = default; | |
constexpr Vec3& operator=(const Vec3& other) noexcept = default; | |
constexpr Vec3& operator=(Vec3&& other) noexcept = default; | |
~Vec3() noexcept = default; | |
_ret_t operator[](size_type i) noexcept { | |
return _at<false>(i); | |
} | |
constexpr T operator[](size_type i) const noexcept { | |
return _at<true>(i); | |
} | |
_ret_t at(size_type i) { | |
if (i > 2) { | |
_throw_oob(i); | |
} | |
return _at<false>(i); | |
} | |
T at(size_type i) const { | |
if (i > 2) { | |
_throw_oob(i); | |
} | |
return _at<true>(i); | |
} | |
void swap(Vec3& other) { | |
using std::swap; | |
swap(x, other.x); | |
swap(y, other.y); | |
swap(z, other.z); | |
} | |
// Operations | |
T magnitude() const { | |
using std::sqrt; | |
return sqrt(x*x + y*y + z*z); | |
} | |
Vec3& operator+=(const Vec3& rhs) noexcept { | |
x += rhs.x; | |
y += rhs.y; | |
z += rhs.z; | |
return *this; | |
} | |
Vec3& operator-=(const Vec3& rhs) noexcept { | |
x -= rhs.x; | |
y -= rhs.y; | |
z -= rhs.z; | |
return *this; | |
} | |
Vec3& operator*=() | |
constexpr std::array<T, 3> as_arr() const { | |
return std::array{x, y, z}; | |
} | |
private: | |
template<bool IsConst> | |
detail::cond_const_t<T&, IsConst> _at(size_type i) noexcept { | |
if (i == 0) { | |
return x; | |
} | |
if (i == 1) { | |
return y; | |
} | |
return z; | |
} | |
using _ret_t = detail::cond_const_ref_t<T, std::is_trivial_v<T>>; | |
void _throw_oob(size_type idx) const { | |
throw std::out_of_range { | |
"A kc::Vec3 has exactly 3 elements(indexes 0, 1, 2) while your index was: " | |
+ std::to_string(idx) | |
}; | |
} | |
}; | |
template<typename T> | |
bool operator==(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; | |
} | |
template<typename T> | |
bool operator!=(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return !(lhs == rhs); | |
} | |
template <typename T> | |
bool operator<(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return lhs.magnitude() < rhs.magnitute(); | |
} | |
template <typename T> | |
bool operator>(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return rhs < lhs; | |
} | |
template <typename T> | |
bool operator>=(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return !(lhs < rhs); | |
} | |
template <typename T> | |
bool operator<=(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept { | |
return !(lhs > rhs); | |
} | |
template<typename T> | |
Vec3<T> operator+(Vec3<T> lhs, const Vec3<T>& rhs) noexcept { | |
lhs += rhs; | |
return lhs; | |
} | |
template<typename T> | |
Vec3<T> operator-(Vec3<T> lhs, const Vec3<T>& rhs) noexcept { | |
lhs -= rhs; | |
return lhs; | |
} | |
template <typename T> | |
void swap(Vec3<T>& lhs, Vec3<T>& rhs) { | |
lhs.swap(rhs); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment