/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #if __has_include() #include #endif #include #include #include #include #include #include #include #include namespace nostalgia::geo { template struct Vec { public: using value_type = T; using size_type = std::size_t; static constexpr auto TypeName = "net.drinkingtea.nostalgia.geo.Point"; static constexpr auto TypeVersion = 1; T x = 0; T y = 0; template struct iterator: public std::iterator { private: PtrType m_t = nullptr; size_type m_offset = 0; size_type m_max = 0; public: constexpr iterator() noexcept = default; constexpr iterator(PtrType t, size_type offset, size_type max) noexcept { m_t = t; m_offset = offset; m_max = max; } [[nodiscard]] constexpr auto offset() const noexcept { return m_offset; } constexpr iterator operator+(size_type s) const noexcept { if constexpr(reverse) { return iterator(m_t, ox::max(m_offset - s, 0), m_max); } else { return iterator(m_t, ox::min(m_offset + s, m_max), m_max); } } constexpr typename std::iterator::difference_type operator-(const iterator &other) const noexcept { if constexpr(reverse) { return m_offset + other.m_offset; } else { return m_offset - other.m_offset; } } constexpr iterator operator-(size_type s) const noexcept { if constexpr(reverse) { return iterator(m_t, ox::min(m_offset + s, m_max), m_max); } else { return iterator(m_t, ox::max(m_offset - s, 0), m_max); } } constexpr iterator &operator+=(size_type s) noexcept { if constexpr(reverse) { m_offset = ox::max(m_offset - s, 0); } else { m_offset = ox::min(m_offset + s, m_max); } return *this; } constexpr iterator &operator-=(size_type s) noexcept { if constexpr(reverse) { m_offset = ox::min(m_offset + s, m_max); } else { m_offset = ox::max(m_offset - s, 0); } return *this; } constexpr iterator &operator++() noexcept { return operator+=(1); } constexpr iterator &operator--() noexcept { return operator-=(1); } constexpr RefType operator*() const noexcept { return m_t[m_offset]; } constexpr RefType operator[](size_type s) const noexcept { return m_t[s]; } constexpr bool operator<(const iterator &other) const noexcept { return m_offset < other.m_offset; } constexpr bool operator>(const iterator &other) const noexcept { return m_offset > other.m_offset; } constexpr bool operator<=(const iterator &other) const noexcept { return m_offset <= other.m_offset; } constexpr bool operator>=(const iterator &other) const noexcept { return m_offset >= other.m_offset; } constexpr bool operator==(const iterator &other) const noexcept { return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max; } constexpr bool operator!=(const iterator &other) const noexcept { return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max; } }; constexpr Vec() noexcept = default; template constexpr Vec(T pX, T pY) noexcept: x(pX), y(pY) { } #if __has_include() explicit constexpr Vec(const ImVec2 &v) noexcept: Vec(v.x, v.y) { } explicit inline operator ImVec2() const noexcept { return {x, y}; } #endif [[nodiscard]] constexpr iterator<> begin() noexcept { return {start(), 0, size()}; } [[nodiscard]] constexpr iterator<> end() noexcept { return {start(), size(), size()}; } [[nodiscard]] constexpr iterator begin() const noexcept { return {start(), 0, size()}; } [[nodiscard]] constexpr iterator end() const noexcept { return {start(), size(), size()}; } [[nodiscard]] constexpr iterator rbegin() noexcept { return {start(), size() - 1, size()}; } [[nodiscard]] constexpr iterator rend() noexcept { return {start(), ox::MaxValue, size()}; } [[nodiscard]] constexpr iterator rbegin() const noexcept { return {start(), size() - 1, size()}; } [[nodiscard]] constexpr iterator rend() const noexcept { return {start(), ox::MaxValue, size()}; } constexpr auto &operator[](std::size_t i) noexcept { if (std::is_constant_evaluated()) { switch (i) { case 0: return x; case 1: return y; default: oxAssert(false, "Read past end of Vec2"); return y; } } else { return start()[i]; } } constexpr const auto &operator[](std::size_t i) const noexcept { if (std::is_constant_evaluated()) { switch (i) { case 0: return x; case 1: return y; default: oxAssert(false, "Read past end of Vec2"); return y; } } else { return start()[i]; } } constexpr auto operator==(const Vec &v) const noexcept { for (auto i = 0u; i < v.size(); ++i) { if ((*this)[i] != v[i]) { return false; } } return true; } constexpr auto operator!=(const Vec &v) const noexcept { return !operator==(v); } [[nodiscard]] constexpr std::size_t size() const noexcept { return 2; } protected: [[nodiscard]] constexpr T *start() noexcept { return &x; } [[nodiscard]] constexpr const T *start() const noexcept { return &x; } }; using Vec2 = Vec; oxModelBegin(Vec2) oxModelField(x) oxModelField(y) oxModelEnd() }