LILAC
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
example_type.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 #pragma once
18 #ifndef EXAMPLE_TYPE_HPP
19 #define EXAMPLE_TYPE_HPP
20 #include <cmath>
21 #include <ostream>
22 #include "type_operators.hpp"
23 //This class is an example of how to make a custom type fo use in the integrators
25  double val1;
26  //This prevents val1 and val2 from being next to each other in memory, meaning
27  //we can't just overwrite this classe's memory with values to fill them
28  //
29  //This is an extremely contrived example, but it is possible that there may be something
30  //that is different, and whose memory layout can't be changed (other code assumes a certain layout,
31  //the function has internally calculated values, etc). Really, as long as there are values other than
32  //the dimension values, you would have to write a custom getter anyways to prevent various operations
33  //from stomping over the other parts of memory.
35  double val2;
36  public:
38  example_type(double v1, double v2): val1(v1), val2(v2){}
39  //This class should break the rule of seperating into cpp and h files
40  //even though it isn't a template. This allows the operator calls
41  //to be inlined, and will provide a giant boost to performance
42  inline example_type operator + (const example_type& inval) const{
43  return example_type(val1+inval.val1, val2+inval.val2);
44  }
45  inline example_type operator - (const example_type& inval) const{
46  return example_type(val1-inval.val1, val2-inval.val2);
47  }
48  inline example_type operator + (double inval) const{
49  return example_type(val1+inval, val2+inval);
50  }
51  inline example_type operator - (double inval) const{
52  return example_type(val1-inval, val2-inval);
53  }
54  inline example_type operator * (const example_type& inval) const{
55  return example_type(val1*inval.val1, val2*inval.val2);
56  }
57  inline example_type operator / (const example_type& inval) const{
58  return example_type(val1/inval.val1, val2/inval.val2);
59  }
60  inline example_type operator * (double inval) const{
61  return example_type(val1*inval, val2*inval);
62  }
63  inline example_type operator / (double inval) const{
64  return example_type(val1/inval, val2/inval);
65  }
66  friend struct get<example_type, 1>;
67  friend struct get<example_type, 2>;
68  friend double abs(const example_type& inval);
69  friend std::ostream& operator <<(std::ostream& out, const example_type& dat);
70 };
71 inline double abs(const example_type& inval){
72  return std::sqrt(inval.val1*inval.val1 + inval.val2*inval.val2);
73 }
74 //These allow for operators that go both ways (double * example_type) and (example_type * double)
75 inline example_type operator +(double val, const example_type & in){
76  return in + val;
77 }
78 inline example_type operator *(double val, const example_type & in){
79  return in * val;
80 }
81 inline example_type operator -(double val, const example_type & in){
82  return (-1*in) + val;
83 }
84 //note the lack of a double/example_type operator-this might not always make since.
85 //
86 //If there is a constructor for examply_type that took a single double, hten this would implictly make sense
87 //However, this is not the case here and regardless it isn't needed
88 //
89 
90 inline std::ostream& operator <<(std::ostream& out, const example_type& dat){
91  out << "(" << dat.val1 << ", " << dat.val2 << ")";
92  return out;
93 }
94 
95 //This template specialization is used by the engine to determine what the
96 //underlying floating point type of the class should be
97 //in this case, it would be double since the class uses doubles
99 /*
100  * This class defines the float_traits for example_type. Since the underlying values are
101  * double, the type is double. Since the dimension is two, the dim variable is 2.
102  */
103 template<>
105  static constexpr bool cast_to_double=false;
106  typedef double type;
107  constexpr static size_t dim=2;
108 };
109 //The next set of functions define the getter functions for example
110 //type. Since example type has 2 dimension, we must do two template specializations.
111 //The first one is for the first dimension, which is val1. The second returns val2,
112 //and any others return zero. However, the other dimensions will also cause errors to throw.
113 //Having a valid return type and function reduces compile errors.
114 //
115 //
116 //Why is this done at compile time, with template specialization? If we were to create a function that
117 //took a dimension at runtime and returned a value, that would require runtime decisions. However,
118 //the compile time decision allows the compiler to replace calls to get::pull
119 //directly with example_type.val1, etc. THis means no effeciency lost and no dependency on data layout.
120 
122 template<>
123 struct get<example_type, 1>{
124  static inline double& pull(example_type& inval){
125  return inval.val1;
126  }
127 };
128 
130 template<>
131 struct get<example_type, 2>{
132  static inline double& pull(example_type& inval){
133  return inval.val2;
134  }
135 };
136 
138 template<size_t dim>
139 struct get<example_type, dim>{
140  //one of these will trip
141  static_assert(dim > 2, "get created for example_type with a dimension greater than 2");
142  static_assert(dim < 1, "get created for example_type with a dimension less than 1");
143  static inline double pull(example_type& inval){
144  return 0;
145  }
146 };
147 #endif