LILAC
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
type_operators.hpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2014, Sam Schetterer, Nathan Kutz, University of Washington
3 Authors: Sam Schetterer
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 
8 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 
10 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11 
12 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13 
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 
16 */
17 #ifndef TYPE_OPERATORS_HPP
18 #define TYPE_OPERATORS_HPP
19 #include <complex>
20 #include <utility>
21 #include "float_traits.hpp"
22 //I would recommend rolling your own static assert, so there is a more specific error message as well.
23 //But dim_check will always fail when value is false
25 template<int bound, int dim>
26 struct dim_check{
27  constexpr static bool value = dim > 0 && dim <= bound;
28  static_assert(value, "Dimension is outside of bounds");
29 };
30 //Getter structs to allow for generic and effecient retrieval of various parameters
31 //If only c++ allowed partial specialization of functions...
33 template<class T, int dim>
34 struct get{
35  static_assert(dim > 0, "Dimension less than one passed to getter");
36  static_assert(std::is_floating_point<T>::value, "Non floating-point type used with standard getter");
37  static inline T& pull(T& inval){
38  return inval;
39  }
40 };
42 template<class T, int dim>
43 struct get<T[], dim>{
44  static_assert(dim > 0, "Dimension less than one passed to getter");
45  static_assert(std::is_floating_point<T>::value, "Non floating-point type used with standard getter");
46  template<size_t N>
47  static inline T& pull(T(& array)[N]){
48  static_assert(dim <= N, "Dimension higher than array dimension used");
49  return array[dim-1];
50  }
51 };
52 
54 template<class T, int dim>
55 struct get<T*, dim>{
56  static_assert(dim > 0, "Dimension less than one passed to getter");
57  static_assert(std::is_floating_point<T>::value, "Non floating-point type used with standard getter");
58  //adios bounds-checking...
59  static inline T& pull(T* inval){
60  return inval[dim-1];
61  }
62 };
63 
64 //These make it possible to extract from the complex values holding non-basic types
65 //without violating dimension rules
67 template<class T, size_t dim, bool is_first>
69  static inline typename float_traits<T>::type& pull(std::complex<T>& pullfrom){
70  T& cur = ((T*)&pullfrom)[0];
71  //is in the first value, use the current dim
72  return get<T, dim>::pull(cur);
73  }
74 };
75 
77 template<class T, size_t dim>
78 struct comp_get_helper<T, dim, false>{
79  static inline typename float_traits<T>::type& pull(std::complex<T>& pullfrom){
80  T& cur = ((T*)&pullfrom)[1];
81  //is in the second value, subtract dim of T to get proper index
82  return get<T, dim-float_traits<T>::dim>::pull(cur);
83  }
84 };
86 /*
87  * This gets a value from a complex number. This is a somewhat complex proposition, since
88  * the types can be nested (std::complex<example_type> for example).
89  *
90  * If you were to imagine the relevant floating_point values as an N dimensional array,=
91  * The pull function would return the Nth value in that array (1-indexed, since this is dimensions)
92  *
93  * For example, an std::complex<example_type> would be [{val1, val2}, i*{val1, val2}];
94  * get<2> would return val2 from the real part, while get<3> would return val1 from the imaginary part
95  */
96 template<class T, int dim>
97 struct get<std::complex<T>, dim>{
98  static_assert(dim_check<float_traits<std::complex<T>>::dim, dim>::value,
99  "Dimension used outside the range of complex values");
100  //having this function cleans up the code, and decreases the number of specializations
101  static inline typename float_traits<T>::type& pull(std::complex<T>& inval){
102  constexpr static bool is_first = dim <= float_traits<T>::dim;
104  }
105 };
106 
108 template<class T, int dim>
109 struct get_cref{
111  const static inline real_type& pull(const T& inval){
112  return get<T, dim>(const_cast<T&>(inval));
113  }
114 };
115 
117 template<class T, int dim>
118 struct get_val{
120  static inline real_type pull(const T& inval){
121  return get<T, dim>(const_cast<T&>(inval));
122  }
123 };
124 
126 template<class T, size_t dim = float_traits<T>::dim>
127 struct apply{
128  private:
130  template<class U>
131  static auto get(U& inval) -> decltype(get<U, dim>::pull(inval)){
133  }
134  public:
135  static_assert(dim >= 1, "A dimension less then one has been given to the apply structure");
136  //no dimension checking here, that should be done by the getter function
169  template<class Lambda>
170  static inline void transform(T& inval, Lambda&& func){
171  std::forward<Lambda>(func)(get(inval), dim);
172  apply<T, dim-1>::transform(inval, std::forward<Lambda>(func));
173  }
175 
198  template<template<size_t> class Lambda>
199  static inline void transform(T& inval){
200  Lambda<dim>::apply(inval);
201  apply<T, dim-1>::template transform<Lambda>(inval);
202  }
209  template<class Lambda, class Final>
210  static inline void transform(T& inval, Lambda&& func, Final&& finish){
211  apply<T, dim>::transform(inval, std::forward<Lambda>(func));
212  std::forward<Final>(finish)(inval);
213  }
214 
215  template<class Lambda, class Trans>
216  static inline void map_into(const T& inval, Lambda&& func, Trans& outval){
218  "The dimension of the Trans type is not equal to the dimension of the T type");
219  get(outval) = std::forward<Lambda>(func)(get_cref<T, dim>::pull(inval), dim);
220  apply<T, dim-1>::map_into(inval, std::forward<Lambda>(func), outval);
221  }
223  template<class Lambda, class Trans>
224  static inline Trans map(const T& inval, Lambda&& func){
225  Trans val;
226  map_into(inval, std::forward<Lambda>(func), val);
227  return val;
228  }
230  template<class Lambda, class Trans, class constr, class postop>
231  static inline Trans map(const T& inval, Lambda&& func,
232  postop&& finish, constr&& build){
233  Trans val = std::forward<constr>(build)();
234  map_into(inval, std::forward<Lambda>(func), val);
235  std::forward<postop>(finish)(val);
236  return val;
237  }
238 };
239 template<class T>
240 struct apply<T, 1>{
241  private:
242  static constexpr size_t dim=1;
243  template<class U>
244  static auto get(U& inval) -> decltype(get<U, dim>::pull(inval)){
246  }
247  public:
248  template<class Lambda>
249  static inline void transform(T& inval, Lambda&& func){
250  std::forward<Lambda>(func)(get(inval), 1);
251  }
252  template<template<size_t> class Lambda>
253  static inline void transform(T& inval){
254  Lambda<1>::apply(inval);
255  }
256  template<class Lambda, class Final>
257  static inline void transform(T& inval, Lambda&& func, Final&& finish){
258  std::forward<Lambda>(func)(get(inval), 1);
259  std::forward<Final>(finish)(inval);
260  }
261  template<class Lambda, class Trans>
262  static inline void map_into(const T& inval, Lambda&& func, Trans& outval){
263  get(outval) = std::forward<Lambda>(func)(get(inval), 1);
264  }
265 
266 };
267 #endif