Skip to content

Instantly share code, notes, and snippets.

@RealKC
Created November 22, 2019 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RealKC/4bbf675ccef49db75ba8fc3fadc82189 to your computer and use it in GitHub Desktop.
Save RealKC/4bbf675ccef49db75ba8fc3fadc82189 to your computer and use it in GitHub Desktop.
#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