libcruft-util/coord/traits.hpp
Danny Robson d3f434b523 coord: make template parameters more flexible
The coordinate system was unable to support types that prohibited
redim or retype operations. Additionally, the `tags' type used for
providing named data parameters was unwiedly.

We remove much of the dependance on template template parameters in the
defined operations and instead define these in terms of a template
specialisation of is_coord.

The tag types were replaced with direct specialisation of the `store'
struct by the primary type, and passing this type through use of the
CRTP.
2017-11-22 17:03:00 +11:00

171 lines
6.5 KiB
C++

/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_COORD_TRAITS_HPP
#define CRUFT_UTIL_COORD_TRAITS_HPP
#include "fwd.hpp"
#include <cstddef>
#include <type_traits>
namespace util {
///////////////////////////////////////////////////////////////////////
// operation traits
template <typename, typename>
struct result { };
//-------------------------------------------------------------------------
template <std::size_t S, typename T> struct result<srgba<S,T>,srgba<S,T>> { using type = srgba<S,T>; };
template <std::size_t S, typename T> struct result<srgba<S,T>,vector<S,T>> { using type = srgba<S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,srgba<S,T>> { using type = srgba<S,T>; };
template <std::size_t S, typename T> struct result<extent<S,T>,extent<S,T>> { using type = extent<S,T>; };
template <std::size_t S, typename T> struct result<extent<S,T>,vector<S,T>> { using type = extent<S,T>; };
template <std::size_t S, typename T> struct result<point<S,T>,extent<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<point<S,T>,vector<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,point<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,vector<S,T>> { using type = vector<S,T>; };
template <
typename A, typename B
>
using result_t = typename result<A,B>::type;
//---------------------------------------------------------------------
template <typename>
struct has_norm : public std::false_type { };
template <std::size_t S, typename T> struct has_norm<vector<S,T>> : public std::true_type { };
template <typename T>
constexpr auto has_norm_v = has_norm<T>::value;
//---------------------------------------------------------------------
template <typename T>
struct has_scalar_op : public std::false_type { };
template <std::size_t S, typename T> struct has_scalar_op<srgba<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<extent<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<point<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<vector<S,T>> : public std::true_type { };
template <typename T>
constexpr auto has_scalar_op_v = has_scalar_op<T>::value;
template <class> struct is_coord : std::false_type { };
template <typename T> struct is_coord<const T> : is_coord<T> {};
template <typename T> struct is_coord<T&> : is_coord<T> {};
template <std::size_t S, typename T> struct is_coord<point<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<srgba<S,T>> : std::true_type { };
template <class K>
constexpr bool
is_coord_v = is_coord<K>::value;
///////////////////////////////////////////////////////////////////////////
template <typename T> struct has_redim : std::false_type {};
//---------------------------------------------------------------------
template <std::size_t S, typename T> struct has_redim< point<S,T>> : public std::true_type {};
template <std::size_t S, typename T> struct has_redim<vector<S,T>> : public std::true_type {};
template <std::size_t S, typename T> struct has_redim<extent<S,T>> : public std::true_type {};
//---------------------------------------------------------------------
template <typename T> constexpr auto has_redim_v = has_redim<T>::value;
///////////////////////////////////////////////////////////////////////////
template <typename> struct redim_type {};
//---------------------------------------------------------------------
template <std::size_t S, typename T> struct redim_type<point<S,T>>
{ template <std::size_t _S> using type = point<_S,T>; };
template <std::size_t S, typename T> struct redim_type<vector<S,T>>
{ template <std::size_t _S> using type = vector<_S,T>; };
template <std::size_t S, typename T> struct redim_type<extent<S,T>>
{ template <std::size_t _S> using type = extent<_S,T>; };
//---------------------------------------------------------------------
template <
typename Self,
std::size_t S
>
using redim_t = typename redim_type<Self>::template type<S>;
///////////////////////////////////////////////////////////////////////////
template <typename> struct revalue_type {};
//-------------------------------------------------------------------------
template <std::size_t S, typename T>
struct revalue_type<point<S,T>> {
template <typename _T> using type = point<S,_T>;
};
template <std::size_t S, typename T>
struct revalue_type<vector<S,T>> {
template <typename _T> using type = vector<S,_T>;
};
template <std::size_t S, typename T>
struct revalue_type<extent<S,T>> {
template <typename _T> using type = extent<S,_T>;
};
//-------------------------------------------------------------------------
template <typename Self, typename T>
using revalue_t = typename revalue_type<Self>::template type<T>;
///////////////////////////////////////////////////////////////////////////
template <typename,typename=void> struct arity {};
template <typename T>
struct arity<T,std::enable_if_t<std::is_arithmetic_v<T>,void>
> :std::integral_constant<std::size_t, 1>
{ };
template <typename T>
struct arity<
T,std::enable_if_t<is_coord_v<T>,void>
> :std::integral_constant<std::size_t,T::elements>
{ };
///////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr auto arity_v = arity<T>::value;
}
#endif