/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2012-2019 Danny Robson */ #pragma once #include "fwd.hpp" #include "ops.hpp" #include "init.hpp" #include "traits.hpp" #include "../maths.hpp" #include #include #include #include namespace cruft::coord { ///////////////////////////////////////////////////////////////////////// // the base class for all coordinate-like types. // // SelfT should not be exposed as a template template directly because // some types (eg, XYZ colours) do not conform to the same template // parameters are others (eg, vector2f). ie, it does not make sense to // allow redim, or type changing on some types so they just aren't exposed. template < std::size_t S, typename T, typename SelfT > struct base : public init { static_assert (S > 0); static_assert (std::is_arithmetic::value); static_assert (sizeof (init) == S * sizeof (T)); using self_t = SelfT; using value_type = T; static constexpr std::size_t dimension = S; static constexpr std::size_t elements = S; /// returns the number of elements we contain static constexpr auto size (void) { return S; } // constructors using init::init; /// constructs, but does not initialise, the data. /// /// used to avoid unnecessary initialisation in many situations where /// we have arrays of these types that are about to be overwritten. it /// is a very important performance optimisation. base () = default; /// constructs an instance where all elements are initialised to `val'. constexpr base (T fill) { for (decltype(S) i = 0; i < S; ++i) this->data[i] = fill; } constexpr base (const base &rhs) = default; base& operator= (const base &rhs)& = default; base& operator= (const T t)& { for (auto &v: *this) v = t; return *this; } // element accessors template constexpr T& operator[] (IdxT i)& noexcept { return this->data[i]; } template constexpr const T& operator[] (IdxT i) const& noexcept { return this->data[i]; } auto cbegin (void) const { return std::cbegin (this->data); } auto cend (void) const { return std::cend (this->data); } auto begin (void) const { return std::begin (this->data); } auto end (void) const { return std::end (this->data); } auto begin (void) { return std::begin (this->data); } auto end (void) { return std::end (this->data); } const T& front (void) const { return this->data[0]; } T& front (void) { return this->data[0]; } const T& back (void) const { return this->data[S-1]; } T& back (void) { return this->data[S-1]; } /////////////////////////////////////////////////////////////////////// // conversions template