@@ -0,0 +1,210 | |||||
|
1 | #ifndef OPAQUE_BINOP_FUNCTION_HPP | |||
|
2 | #define OPAQUE_BINOP_FUNCTION_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "../utility.hpp" | |||
|
32 | #include <type_traits> | |||
|
33 | ||||
|
34 | namespace opaque { | |||
|
35 | namespace binop { | |||
|
36 | ||||
|
37 | /// \addtogroup miscellaneous | |||
|
38 | /// @{ | |||
|
39 | ||||
|
40 | // | |||
|
41 | // Functions implementing the ordinary operator@= variations | |||
|
42 | // | |||
|
43 | ||||
|
44 | template <typename T, typename U> | |||
|
45 | constexpr auto multiply_equal(T& l, const U& r) | |||
|
46 | noexcept(noexcept(l *= r)) | |||
|
47 | -> decltype(l *= r) { | |||
|
48 | return l *= r; } | |||
|
49 | ||||
|
50 | template <typename T, typename U> | |||
|
51 | constexpr auto divide_equal(T& l, const U& r) | |||
|
52 | noexcept(noexcept(l /= r)) | |||
|
53 | -> decltype(l /= r) { | |||
|
54 | return l /= r; } | |||
|
55 | ||||
|
56 | template <typename T, typename U> | |||
|
57 | constexpr auto modulus_equal(T& l, const U& r) | |||
|
58 | noexcept(noexcept(l %= r)) | |||
|
59 | -> decltype(l %= r) { | |||
|
60 | return l %= r; } | |||
|
61 | ||||
|
62 | template <typename T, typename U> | |||
|
63 | constexpr auto add_equal(T& l, const U& r) | |||
|
64 | noexcept(noexcept(l += r)) | |||
|
65 | -> decltype(l += r) { | |||
|
66 | return l += r; } | |||
|
67 | ||||
|
68 | template <typename T, typename U> | |||
|
69 | constexpr auto subtract_equal(T& l, const U& r) | |||
|
70 | noexcept(noexcept(l -= r)) | |||
|
71 | -> decltype(l -= r) { | |||
|
72 | return l -= r; } | |||
|
73 | ||||
|
74 | template <typename T, typename U> | |||
|
75 | constexpr auto left_shift_equal(T& l, const U& r) | |||
|
76 | noexcept(noexcept(l <<= r)) | |||
|
77 | -> decltype(l <<= r) { | |||
|
78 | return l <<= r; } | |||
|
79 | ||||
|
80 | template <typename T, typename U> | |||
|
81 | constexpr auto right_shift_equal(T& l, const U& r) | |||
|
82 | noexcept(noexcept(l >>= r)) | |||
|
83 | -> decltype(l >>= r) { | |||
|
84 | return l >>= r; } | |||
|
85 | ||||
|
86 | template <typename T, typename U> | |||
|
87 | constexpr auto bitand_equal(T& l, const U& r) | |||
|
88 | noexcept(noexcept(l &= r)) | |||
|
89 | -> decltype(l &= r) { | |||
|
90 | return l &= r; } | |||
|
91 | ||||
|
92 | template <typename T, typename U> | |||
|
93 | constexpr auto bitxor_equal(T& l, const U& r) | |||
|
94 | noexcept(noexcept(l ^= r)) | |||
|
95 | -> decltype(l ^= r) { | |||
|
96 | return l ^= r; } | |||
|
97 | ||||
|
98 | template <typename T, typename U> | |||
|
99 | constexpr auto bitor_equal(T& l, const U& r) | |||
|
100 | noexcept(noexcept(l |= r)) | |||
|
101 | -> decltype(l |= r) { | |||
|
102 | return l |= r; } | |||
|
103 | ||||
|
104 | // | |||
|
105 | // These variants accept and modify temporary objects, and return by value. | |||
|
106 | // This allows them to be used in expressions without named variables, such | |||
|
107 | // as multiply_equal(T(l),r). | |||
|
108 | // | |||
|
109 | ||||
|
110 | template <typename T, typename U, typename = typename | |||
|
111 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
112 | constexpr auto multiply_equal(T&& l, const U& r) | |||
|
113 | noexcept(noexcept(opaque::move(l *= r))) -> typename | |||
|
114 | std::decay<decltype(l *= r)>::type { | |||
|
115 | return opaque::move(l *= r); } | |||
|
116 | ||||
|
117 | template <typename T, typename U, typename = typename | |||
|
118 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
119 | constexpr auto divide_equal(T&& l, const U& r) | |||
|
120 | noexcept(noexcept(opaque::move(l /= r))) -> typename | |||
|
121 | std::decay<decltype(l /= r)>::type { | |||
|
122 | return opaque::move(l /= r); } | |||
|
123 | ||||
|
124 | template <typename T, typename U, typename = typename | |||
|
125 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
126 | constexpr auto modulus_equal(T&& l, const U& r) | |||
|
127 | noexcept(noexcept(opaque::move(l %= r))) -> typename | |||
|
128 | std::decay<decltype(l %= r)>::type { | |||
|
129 | return opaque::move(l %= r); } | |||
|
130 | ||||
|
131 | template <typename T, typename U, typename = typename | |||
|
132 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
133 | constexpr auto add_equal(T&& l, const U& r) | |||
|
134 | noexcept(noexcept(opaque::move(l += r))) -> typename | |||
|
135 | std::decay<decltype(l += r)>::type { | |||
|
136 | return opaque::move(l += r); } | |||
|
137 | ||||
|
138 | template <typename T, typename U, typename = typename | |||
|
139 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
140 | constexpr auto subtract_equal(T&& l, const U& r) | |||
|
141 | noexcept(noexcept(opaque::move(l -= r))) -> typename | |||
|
142 | std::decay<decltype(l -= r)>::type { | |||
|
143 | return opaque::move(l -= r); } | |||
|
144 | ||||
|
145 | template <typename T, typename U, typename = typename | |||
|
146 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
147 | constexpr auto left_shift_equal(T&& l, const U& r) | |||
|
148 | noexcept(noexcept(opaque::move(l <<= r))) -> typename | |||
|
149 | std::decay<decltype(l <<= r)>::type { | |||
|
150 | return opaque::move(l <<= r); } | |||
|
151 | ||||
|
152 | template <typename T, typename U, typename = typename | |||
|
153 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
154 | constexpr auto right_shift_equal(T&& l, const U& r) | |||
|
155 | noexcept(noexcept(opaque::move(l >>= r))) -> typename | |||
|
156 | std::decay<decltype(l >>= r)>::type { | |||
|
157 | return opaque::move(l >>= r); } | |||
|
158 | ||||
|
159 | template <typename T, typename U, typename = typename | |||
|
160 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
161 | constexpr auto bitand_equal(T&& l, const U& r) | |||
|
162 | noexcept(noexcept(opaque::move(l &= r))) -> typename | |||
|
163 | std::decay<decltype(l &= r)>::type { | |||
|
164 | return opaque::move(l &= r); } | |||
|
165 | ||||
|
166 | template <typename T, typename U, typename = typename | |||
|
167 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
168 | constexpr auto bitxor_equal(T&& l, const U& r) | |||
|
169 | noexcept(noexcept(opaque::move(l ^= r))) -> typename | |||
|
170 | std::decay<decltype(l ^= r)>::type { | |||
|
171 | return opaque::move(l ^= r); } | |||
|
172 | ||||
|
173 | template <typename T, typename U, typename = typename | |||
|
174 | std::enable_if<not std::is_lvalue_reference<T>::value>::type> | |||
|
175 | constexpr auto bitor_equal(T&& l, const U& r) | |||
|
176 | noexcept(noexcept(opaque::move(l |= r))) -> typename | |||
|
177 | std::decay<decltype(l |= r)>::type { | |||
|
178 | return opaque::move(l |= r); } | |||
|
179 | ||||
|
180 | // | |||
|
181 | // Functor objects that forward to the appropriate function. | |||
|
182 | // Note that the function name is qualified to inhibit ADL. | |||
|
183 | // | |||
|
184 | ||||
|
185 | #define OPAQUE_BINOP_FORWARD(F) \ | |||
|
186 | template <typename T, typename U> \ | |||
|
187 | constexpr auto operator()(T&& l, U&& r) const noexcept( \ | |||
|
188 | noexcept(opaque::binop::F(opaque::forward<T>(l), opaque::forward<U>(r)))) -> \ | |||
|
189 | decltype(opaque::binop::F(opaque::forward<T>(l), opaque::forward<U>(r))) { \ | |||
|
190 | return opaque::binop::F(opaque::forward<T>(l), opaque::forward<U>(r)); } \ | |||
|
191 | ||||
|
192 | struct multiply_equal_t { OPAQUE_BINOP_FORWARD( multiply_equal) }; | |||
|
193 | struct divide_equal_t { OPAQUE_BINOP_FORWARD( divide_equal) }; | |||
|
194 | struct modulus_equal_t { OPAQUE_BINOP_FORWARD( modulus_equal) }; | |||
|
195 | struct add_equal_t { OPAQUE_BINOP_FORWARD( add_equal) }; | |||
|
196 | struct subtract_equal_t { OPAQUE_BINOP_FORWARD( subtract_equal) }; | |||
|
197 | struct left_shift_equal_t { OPAQUE_BINOP_FORWARD( left_shift_equal) }; | |||
|
198 | struct right_shift_equal_t { OPAQUE_BINOP_FORWARD(right_shift_equal) }; | |||
|
199 | struct bitand_equal_t { OPAQUE_BINOP_FORWARD( bitand_equal) }; | |||
|
200 | struct bitxor_equal_t { OPAQUE_BINOP_FORWARD( bitxor_equal) }; | |||
|
201 | struct bitor_equal_t { OPAQUE_BINOP_FORWARD( bitor_equal) }; | |||
|
202 | ||||
|
203 | #undef OPAQUE_BINOP_FORWARD | |||
|
204 | ||||
|
205 | /// @} | |||
|
206 | ||||
|
207 | } | |||
|
208 | } | |||
|
209 | ||||
|
210 | #endif |
@@ -0,0 +1,242 | |||||
|
1 | #ifndef OPAQUE_BINOP_INHERIT_HPP | |||
|
2 | #define OPAQUE_BINOP_INHERIT_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "binop_function.hpp" | |||
|
32 | #include "binop_overload.hpp" | |||
|
33 | #include "../utility.hpp" | |||
|
34 | ||||
|
35 | namespace opaque { | |||
|
36 | namespace binop { | |||
|
37 | ||||
|
38 | /// \addtogroup miscellaneous | |||
|
39 | /// @{ | |||
|
40 | ||||
|
41 | // | |||
|
42 | // It is necessary to provide distinct overloads for every operation. | |||
|
43 | // Perfect forwarding fails because it creates operators that accept any | |||
|
44 | // type. That becomes ambiguous if there is more than one instantiation. | |||
|
45 | // | |||
|
46 | ||||
|
47 | template <typename RT, bool commutative=true, | |||
|
48 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
49 | struct multipliable { | |||
|
50 | using OP = multiply_equal_t; | |||
|
51 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
52 | friend constexpr RT operator* (const P1& p1 , const P2& p2 ) noexcept( | |||
|
53 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
54 | return binop_t::func( p1 , p2 ); } | |||
|
55 | friend constexpr RT operator* (const P1& p1 , P2&& p2 ) noexcept( | |||
|
56 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
57 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
58 | friend constexpr RT operator* ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
59 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
60 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
61 | friend constexpr RT operator* ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
62 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
63 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
64 | }; | |||
|
65 | ||||
|
66 | template <typename RT, bool commutative=false, | |||
|
67 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
68 | struct dividable { | |||
|
69 | using OP = divide_equal_t; | |||
|
70 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
71 | friend constexpr RT operator/ (const P1& p1 , const P2& p2 ) noexcept( | |||
|
72 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
73 | return binop_t::func( p1 , p2 ); } | |||
|
74 | friend constexpr RT operator/ (const P1& p1 , P2&& p2 ) noexcept( | |||
|
75 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
76 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
77 | friend constexpr RT operator/ ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
78 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
79 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
80 | friend constexpr RT operator/ ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
81 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
82 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
83 | }; | |||
|
84 | ||||
|
85 | template <typename RT, bool commutative=false, | |||
|
86 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
87 | struct modulable { | |||
|
88 | using OP = modulus_equal_t; | |||
|
89 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
90 | friend constexpr RT operator% (const P1& p1 , const P2& p2 ) noexcept( | |||
|
91 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
92 | return binop_t::func( p1 , p2 ); } | |||
|
93 | friend constexpr RT operator% (const P1& p1 , P2&& p2 ) noexcept( | |||
|
94 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
95 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
96 | friend constexpr RT operator% ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
97 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
98 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
99 | friend constexpr RT operator% ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
100 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
101 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
102 | }; | |||
|
103 | ||||
|
104 | template <typename RT, bool commutative=true, | |||
|
105 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
106 | struct addable { | |||
|
107 | using OP = add_equal_t; | |||
|
108 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
109 | friend constexpr RT operator+ (const P1& p1 , const P2& p2 ) noexcept( | |||
|
110 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
111 | return binop_t::func( p1 , p2 ); } | |||
|
112 | friend constexpr RT operator+ (const P1& p1 , P2&& p2 ) noexcept( | |||
|
113 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
114 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
115 | friend constexpr RT operator+ ( P1&& p1, const P2& p2 ) noexcept( | |||
|
116 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
117 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
118 | friend constexpr RT operator+ ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
119 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
120 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
121 | }; | |||
|
122 | ||||
|
123 | template <typename RT, bool commutative=false, | |||
|
124 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
125 | struct subtractable { | |||
|
126 | using OP = subtract_equal_t; | |||
|
127 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
128 | friend constexpr RT operator- (const P1& p1 , const P2& p2 ) noexcept( | |||
|
129 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
130 | return binop_t::func( p1 , p2 ); } | |||
|
131 | friend constexpr RT operator- (const P1& p1 , P2&& p2 ) noexcept( | |||
|
132 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
133 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
134 | friend constexpr RT operator- ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
135 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
136 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
137 | friend constexpr RT operator- ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
138 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
139 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
140 | }; | |||
|
141 | ||||
|
142 | template <typename RT, bool commutative=false, | |||
|
143 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
144 | struct left_shiftable { | |||
|
145 | using OP = left_shift_equal_t; | |||
|
146 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
147 | friend constexpr RT operator<<(const P1& p1 , const P2& p2 ) noexcept( | |||
|
148 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
149 | return binop_t::func( p1 , p2 ); } | |||
|
150 | friend constexpr RT operator<<(const P1& p1 , P2&& p2 ) noexcept( | |||
|
151 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
152 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
153 | friend constexpr RT operator<<( P1&& p1 , const P2& p2 ) noexcept( | |||
|
154 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
155 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
156 | friend constexpr RT operator<<( P1&& p1 , P2&& p2 ) noexcept( | |||
|
157 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
158 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
159 | }; | |||
|
160 | ||||
|
161 | template <typename RT, bool commutative=false, | |||
|
162 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
163 | struct right_shiftable { | |||
|
164 | using OP = right_shift_equal_t; | |||
|
165 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
166 | friend constexpr RT operator>>(const P1& p1 , const P2& p2 ) noexcept( | |||
|
167 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
168 | return binop_t::func( p1 , p2 ); } | |||
|
169 | friend constexpr RT operator>>(const P1& p1 , P2&& p2 ) noexcept( | |||
|
170 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
171 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
172 | friend constexpr RT operator>>( P1&& p1 , const P2& p2 ) noexcept( | |||
|
173 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
174 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
175 | friend constexpr RT operator>>( P1&& p1 , P2&& p2 ) noexcept( | |||
|
176 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
177 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
178 | }; | |||
|
179 | ||||
|
180 | template <typename RT, bool commutative=true, | |||
|
181 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
182 | struct bitandable { | |||
|
183 | using OP = bitand_equal_t; | |||
|
184 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
185 | friend constexpr RT operator& (const P1& p1 , const P2& p2 ) noexcept( | |||
|
186 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
187 | return binop_t::func( p1 , p2 ); } | |||
|
188 | friend constexpr RT operator& (const P1& p1 , P2&& p2 ) noexcept( | |||
|
189 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
190 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
191 | friend constexpr RT operator& ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
192 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
193 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
194 | friend constexpr RT operator& ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
195 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
196 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
197 | }; | |||
|
198 | ||||
|
199 | template <typename RT, bool commutative=true, | |||
|
200 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
201 | struct bitxorable { | |||
|
202 | using OP = bitxor_equal_t; | |||
|
203 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
204 | friend constexpr RT operator^ (const P1& p1 , const P2& p2 ) noexcept( | |||
|
205 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
206 | return binop_t::func( p1 , p2 ); } | |||
|
207 | friend constexpr RT operator^ (const P1& p1 , P2&& p2 ) noexcept( | |||
|
208 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
209 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
210 | friend constexpr RT operator^ ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
211 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
212 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
213 | friend constexpr RT operator^ ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
214 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
215 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
216 | }; | |||
|
217 | ||||
|
218 | template <typename RT, bool commutative=true, | |||
|
219 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
220 | struct bitorable { | |||
|
221 | using OP = bitor_equal_t; | |||
|
222 | using binop_t = binary_operator<OP, RT, commutative, P1, P2, I1, I2>; | |||
|
223 | friend constexpr RT operator| (const P1& p1 , const P2& p2 ) noexcept( | |||
|
224 | noexcept(binop_t::func( p1 , p2 ))) { | |||
|
225 | return binop_t::func( p1 , p2 ); } | |||
|
226 | friend constexpr RT operator| (const P1& p1 , P2&& p2 ) noexcept( | |||
|
227 | noexcept(binop_t::func( p1 , opaque::move(p2)))) { | |||
|
228 | return binop_t::func( p1 , opaque::move(p2)); } | |||
|
229 | friend constexpr RT operator| ( P1&& p1 , const P2& p2 ) noexcept( | |||
|
230 | noexcept(binop_t::func(opaque::move(p1), p2 ))) { | |||
|
231 | return binop_t::func(opaque::move(p1), p2 ); } | |||
|
232 | friend constexpr RT operator| ( P1&& p1 , P2&& p2 ) noexcept( | |||
|
233 | noexcept(binop_t::func(opaque::move(p1), opaque::move(p2)))) { | |||
|
234 | return binop_t::func(opaque::move(p1), opaque::move(p2)); } | |||
|
235 | }; | |||
|
236 | ||||
|
237 | /// @} | |||
|
238 | ||||
|
239 | } | |||
|
240 | } | |||
|
241 | ||||
|
242 | #endif |
@@ -0,0 +1,308 | |||||
|
1 | #ifndef OPAQUE_BINOP_OVERLOAD_HPP | |||
|
2 | #define OPAQUE_BINOP_OVERLOAD_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "../constexpr14.hpp" | |||
|
32 | #include "../type_traits.hpp" | |||
|
33 | #include "../utility.hpp" | |||
|
34 | #include "../convert.hpp" | |||
|
35 | #include <type_traits> | |||
|
36 | ||||
|
37 | namespace opaque { | |||
|
38 | namespace binop { | |||
|
39 | ||||
|
40 | /// \addtogroup internal | |||
|
41 | /// @{ | |||
|
42 | ||||
|
43 | /// | |||
|
44 | /// Overloads of binary operators | |||
|
45 | /// | |||
|
46 | ||||
|
47 | template <typename OP, typename RT, bool apply_commutativity=false, | |||
|
48 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2> | |||
|
49 | struct overload; | |||
|
50 | ||||
|
51 | template <typename OP, typename RT, | |||
|
52 | typename P1, typename P2, typename I1, typename I2> | |||
|
53 | struct overload<OP,RT,false,const P1& ,const P2& ,I1,I2> { | |||
|
54 | // No return type conversion - enable NRVO | |||
|
55 | template <typename R=RT> static constexpr14 | |||
|
56 | typename std::enable_if< std::is_same<RT,I1>::value, R>::type | |||
|
57 | func(const P1& p1, const P2& p2, OP op=OP{}) noexcept( | |||
|
58 | std::is_nothrow_constructible<I1,const P1&>::value and | |||
|
59 | noexcept(op(std::declval<I1>(), convert<I2>(p2)))) { | |||
|
60 | I1 temp(p1); | |||
|
61 | op(temp, convert<I2>(p2)); | |||
|
62 | return temp; | |||
|
63 | } | |||
|
64 | // Return type conversion | |||
|
65 | template <typename R=RT> static constexpr14 | |||
|
66 | typename std::enable_if<not std::is_same<RT,I1>::value, R>::type | |||
|
67 | func(const P1& p1, const P2& p2, OP op=OP{}) noexcept( | |||
|
68 | std::is_nothrow_constructible<I1,const P1&>::value and | |||
|
69 | std::is_nothrow_constructible<RT,I1&&>::value and | |||
|
70 | noexcept(op(std::declval<I1>(), convert<I2>(p2)))) { | |||
|
71 | I1 temp(p1); | |||
|
72 | op(temp, convert<I2>(p2)); | |||
|
73 | return static_cast<RT>(opaque::move(temp)); | |||
|
74 | } | |||
|
75 | }; | |||
|
76 | ||||
|
77 | template <typename OP, typename RT, | |||
|
78 | typename P1, typename P2, typename I1, typename I2> | |||
|
79 | struct overload<OP,RT,false,const P1& , P2&&,I1,I2> { | |||
|
80 | // No return type conversion - enable NRVO | |||
|
81 | template <typename R=RT> static constexpr14 | |||
|
82 | typename std::enable_if< std::is_same<RT,I1>::value, R>::type | |||
|
83 | func(const P1& p1, P2&& p2, OP op=OP{}) noexcept( | |||
|
84 | std::is_nothrow_constructible<I1,const P1&>::value and | |||
|
85 | noexcept(op(std::declval<I1>(), convert<I2>(opaque::move(p2))))) { | |||
|
86 | I1 temp(p1); | |||
|
87 | op(temp, convert<I2>(opaque::move(p2))); | |||
|
88 | return temp; | |||
|
89 | } | |||
|
90 | // Return type conversion | |||
|
91 | template <typename R=RT> static constexpr14 | |||
|
92 | typename std::enable_if<not std::is_same<RT,I1>::value, R>::type | |||
|
93 | func(const P1& p1, P2&& p2, OP op=OP{}) noexcept( | |||
|
94 | std::is_nothrow_constructible<I1,const P1&>::value and | |||
|
95 | std::is_nothrow_constructible<RT,I1&&>::value and | |||
|
96 | noexcept(op(std::declval<I1>(), convert<I2>(opaque::move(p2))))) { | |||
|
97 | I1 temp(p1); | |||
|
98 | op(temp, convert<I2>(opaque::move(p2))); | |||
|
99 | return static_cast<RT>(opaque::move(temp)); | |||
|
100 | } | |||
|
101 | }; | |||
|
102 | ||||
|
103 | template <typename OP, typename RT, | |||
|
104 | typename P1, typename P2, typename I1, typename I2> | |||
|
105 | struct overload<OP,RT,false, P1&&,const P2& ,I1,I2> { | |||
|
106 | static constexpr RT func( P1&& p1, const P2& p2, OP op=OP{}) noexcept( | |||
|
107 | noexcept(static_cast<RT>( | |||
|
108 | op(convert_mutable<I1>(opaque::move(p1)), | |||
|
109 | convert<I2>( p2 ))))) { | |||
|
110 | return static_cast<RT>( | |||
|
111 | op(convert_mutable<I1>(opaque::move(p1)), | |||
|
112 | convert<I2>( p2 ))); } | |||
|
113 | }; | |||
|
114 | ||||
|
115 | template <typename OP, typename RT, | |||
|
116 | typename P1, typename P2, typename I1, typename I2> | |||
|
117 | struct overload<OP,RT,false, P1&&, P2&&,I1,I2> { | |||
|
118 | static constexpr RT func( P1&& p1, P2&& p2, OP op=OP{}) noexcept( | |||
|
119 | noexcept(static_cast<RT>( | |||
|
120 | op(convert_mutable<I1>(opaque::move(p1)), | |||
|
121 | convert<I2>( opaque::move(p2)))))) { | |||
|
122 | return static_cast<RT>( | |||
|
123 | op(convert_mutable<I1>(opaque::move(p1)), | |||
|
124 | convert<I2>( opaque::move(p2)))); } | |||
|
125 | }; | |||
|
126 | ||||
|
127 | template <typename OP, typename RT, | |||
|
128 | typename P1, typename P2, typename I1, typename I2> | |||
|
129 | struct overload<OP,RT,true,P1,P2,I1,I2> { | |||
|
130 | using overload_t = overload<OP,RT,false,P2,P1,I2,I1>; | |||
|
131 | static constexpr RT func(P1&& p1, P2&& p2, OP op=OP{}) noexcept( | |||
|
132 | noexcept(overload_t::func( | |||
|
133 | opaque::forward<P2>(p2), opaque::forward<P1>(p1), op))) { | |||
|
134 | return overload_t::func( | |||
|
135 | opaque::forward<P2>(p2), opaque::forward<P1>(p1), op); | |||
|
136 | } | |||
|
137 | }; | |||
|
138 | ||||
|
139 | // | |||
|
140 | // Four flavors of overload are required, but we cannot inherit from the same | |||
|
141 | // base class more than once (ISO/IEC 14882 οΏ½10.1/3). Work around this by | |||
|
142 | // creating four distinct classes to inherit from. | |||
|
143 | // | |||
|
144 | ||||
|
145 | template <typename OP, typename RT, bool apply_commutativity, | |||
|
146 | typename P1, typename P2, typename I1, typename I2> | |||
|
147 | struct overload_1 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { }; | |||
|
148 | ||||
|
149 | template <typename OP, typename RT, bool apply_commutativity, | |||
|
150 | typename P1, typename P2, typename I1, typename I2> | |||
|
151 | struct overload_2 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { }; | |||
|
152 | ||||
|
153 | template <typename OP, typename RT, bool apply_commutativity, | |||
|
154 | typename P1, typename P2, typename I1, typename I2> | |||
|
155 | struct overload_3 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { }; | |||
|
156 | ||||
|
157 | template <typename OP, typename RT, bool apply_commutativity, | |||
|
158 | typename P1, typename P2, typename I1, typename I2> | |||
|
159 | struct overload_4 : overload<OP,RT,apply_commutativity,P1,P2,I1,I2> { }; | |||
|
160 | ||||
|
161 | /// | |||
|
162 | /// Conversion costs associated with a binary operation | |||
|
163 | /// | |||
|
164 | /// The parameter types must reflect the actual types passed to the binary | |||
|
165 | /// operation, e.g. const T& or T&&. All the other types must be decayed | |||
|
166 | /// types. | |||
|
167 | /// | |||
|
168 | template<typename return_type, typename result_type, | |||
|
169 | typename inter1_type, typename inter2_type, | |||
|
170 | typename param1_type, typename param2_type> | |||
|
171 | static constexpr unsigned binop_conversion_cost() noexcept { | |||
|
172 | static_assert(is_decayed<return_type>::value, ""); | |||
|
173 | static_assert(is_decayed<result_type>::value, ""); | |||
|
174 | static_assert(is_decayed<inter1_type>::value, ""); | |||
|
175 | static_assert(is_decayed<inter2_type>::value, ""); | |||
|
176 | return converter<inter1_type,param1_type>::mutable_cost() + | |||
|
177 | converter<inter2_type,param2_type>::cost() + | |||
|
178 | converter<return_type,result_type>::cost(); | |||
|
179 | } | |||
|
180 | ||||
|
181 | /// | |||
|
182 | /// Select between the regular overload and the commutative alternative | |||
|
183 | /// | |||
|
184 | /// If the operator is not commutative, use the regular overload. | |||
|
185 | /// Otherwise, if only one option is well-formed, use that. | |||
|
186 | /// Otherwise, if both are well-formed, select the lower-cost one. | |||
|
187 | /// | |||
|
188 | ||||
|
189 | template <bool regular_well_formed, bool swapped_well_formed, | |||
|
190 | typename OPN, typename RT, bool commutative=false, | |||
|
191 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2, | |||
|
192 | typename OPS=OPN> | |||
|
193 | struct overload_selector { | |||
|
194 | // overload_selector<false,false,OPN,RT,commutative,P1,P2,I1,I2,OPS> | |||
|
195 | // --> No overload is well-formed | |||
|
196 | static_assert( swapped_well_formed, "Operation is not well-formed"); | |||
|
197 | // overload_selector<false,true ,OPN,RT,false,P1,P2,I1,I2,OPS>> | |||
|
198 | // --> Only swapped overload is well-formed, but we can't use it | |||
|
199 | static_assert(not swapped_well_formed, "Operation is not commutative"); | |||
|
200 | }; | |||
|
201 | ||||
|
202 | template <typename OPN, typename RT, | |||
|
203 | typename P1, typename P2, typename I1, typename I2, typename OPS> | |||
|
204 | struct overload_selector<false,true ,OPN,RT,true ,P1,P2,I1,I2,OPS> { | |||
|
205 | // Only swapped overload is well-formed, and we can use it | |||
|
206 | using type_1 = overload_1<OPS,RT,true ,const P1& , const P2& ,I1,I2>; | |||
|
207 | using type_2 = overload_2<OPS,RT,true ,const P1& , P2&&,I1,I2>; | |||
|
208 | using type_3 = overload_3<OPS,RT,true , P1&&, const P2& ,I1,I2>; | |||
|
209 | using type_4 = overload_4<OPS,RT,true , P1&&, P2&&,I1,I2>; | |||
|
210 | }; | |||
|
211 | ||||
|
212 | template <typename OPN, typename RT, bool commutative, | |||
|
213 | typename P1, typename P2, typename I1, typename I2, typename OPS> | |||
|
214 | struct overload_selector<true ,false,OPN,RT,commutative,P1,P2,I1,I2,OPS> { | |||
|
215 | // Only regular overload is well-formed | |||
|
216 | using type_1 = overload_1<OPN,RT,false,const P1& , const P2& ,I1,I2>; | |||
|
217 | using type_2 = overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>; | |||
|
218 | using type_3 = overload_3<OPN,RT,false, P1&&, const P2& ,I1,I2>; | |||
|
219 | using type_4 = overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>; | |||
|
220 | }; | |||
|
221 | ||||
|
222 | template <typename OPN, typename RT, | |||
|
223 | typename P1, typename P2, typename I1, typename I2, typename OPS> | |||
|
224 | struct overload_selector<true ,true ,OPN,RT,false,P1,P2,I1,I2,OPS> { | |||
|
225 | // Both overloads are well-formed, but we must use the regular one | |||
|
226 | using type_1 = overload_1<OPN,RT,false,const P1& , const P2& ,I1,I2>; | |||
|
227 | using type_2 = overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>; | |||
|
228 | using type_3 = overload_3<OPN,RT,false, P1&&, const P2& ,I1,I2>; | |||
|
229 | using type_4 = overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>; | |||
|
230 | }; | |||
|
231 | ||||
|
232 | template <typename OPN, typename RT, | |||
|
233 | typename P1, typename P2, typename I1, typename I2, typename OPS> | |||
|
234 | struct overload_selector<true ,true ,OPN,RT,true ,P1,P2,I1,I2,OPS> { | |||
|
235 | // Both overloads are well-formed, and we must choose between them | |||
|
236 | ||||
|
237 | template <typename result, typename param1, typename param2> | |||
|
238 | static constexpr unsigned norm_cost() noexcept { | |||
|
239 | return binop_conversion_cost<RT,result,I1,I2,param1,param2>(); | |||
|
240 | } | |||
|
241 | template <typename result, typename param1, typename param2> | |||
|
242 | static constexpr unsigned swap_cost() noexcept { | |||
|
243 | return binop_conversion_cost<RT,result,I2,I1,param2,param1>(); | |||
|
244 | } | |||
|
245 | ||||
|
246 | using RN = typename std::decay<typename | |||
|
247 | is_functor_call_well_formed<OPN,I1&,const I2&>::result_type>::type; | |||
|
248 | using RS = typename std::decay<typename | |||
|
249 | is_functor_call_well_formed<OPS,I2&,const I1&>::result_type>::type; | |||
|
250 | ||||
|
251 | using type_1 = typename std::conditional< | |||
|
252 | swap_cost <RS,const P1& ,const P2& >() < | |||
|
253 | norm_cost <RN,const P1& ,const P2& >(), | |||
|
254 | overload_1<OPS,RT,true ,const P1& ,const P2& ,I1,I2>, | |||
|
255 | overload_1<OPN,RT,false,const P1& ,const P2& ,I1,I2>>::type; | |||
|
256 | using type_2 = typename std::conditional< | |||
|
257 | swap_cost <RS,const P1& , P2&&>() < | |||
|
258 | norm_cost <RN,const P1& , P2&&>(), | |||
|
259 | overload_2<OPS,RT,true ,const P1& , P2&&,I1,I2>, | |||
|
260 | overload_2<OPN,RT,false,const P1& , P2&&,I1,I2>>::type; | |||
|
261 | using type_3 = typename std::conditional< | |||
|
262 | swap_cost <RS, P1&&,const P2& >() < | |||
|
263 | norm_cost <RN, P1&&,const P2& >(), | |||
|
264 | overload_3<OPS,RT,true , P1&&,const P2& ,I1,I2>, | |||
|
265 | overload_3<OPN,RT,false, P1&&,const P2& ,I1,I2>>::type; | |||
|
266 | using type_4 = typename std::conditional< | |||
|
267 | swap_cost <RS, P1&&, P2&&>() < | |||
|
268 | norm_cost <RN, P1&&, P2&&>(), | |||
|
269 | overload_4<OPS,RT,true , P1&&, P2&&,I1,I2>, | |||
|
270 | overload_4<OPN,RT,false, P1&&, P2&&,I1,I2>>::type; | |||
|
271 | }; | |||
|
272 | ||||
|
273 | template <typename OPN, typename RT, bool commutative, | |||
|
274 | typename P1, typename P2, typename I1, typename I2, typename OPS> | |||
|
275 | using overload_selector_t = overload_selector< | |||
|
276 | is_functor_call_well_formed<OPN,I1&,I2>::value, | |||
|
277 | is_functor_call_well_formed<OPS,I2&,I1>::value, | |||
|
278 | OPN,RT,commutative,P1,P2,I1,I2,OPS>; | |||
|
279 | ||||
|
280 | /// | |||
|
281 | /// Generalized binary operator | |||
|
282 | /// | |||
|
283 | template <typename OPN, typename RT, bool commutative=false, | |||
|
284 | typename P1=RT, typename P2=RT, typename I1=P1, typename I2=P2, | |||
|
285 | typename OPS=OPN> | |||
|
286 | struct binary_operator | |||
|
287 | : overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_1 | |||
|
288 | , overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_2 | |||
|
289 | , overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_3 | |||
|
290 | , overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_4 | |||
|
291 | { | |||
|
292 | // | |||
|
293 | // Inheriting a function with the same name from different base classes is | |||
|
294 | // ambiguous (ISO/IEC 14882 οΏ½10.2/6). Work around this by pulling the | |||
|
295 | // declarations into the derived class. | |||
|
296 | // | |||
|
297 | using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_1::func; | |||
|
298 | using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_2::func; | |||
|
299 | using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_3::func; | |||
|
300 | using overload_selector_t<OPN,RT,commutative,P1,P2,I1,I2,OPS>::type_4::func; | |||
|
301 | }; | |||
|
302 | ||||
|
303 | /// @} | |||
|
304 | ||||
|
305 | } | |||
|
306 | } | |||
|
307 | ||||
|
308 | #endif |
@@ -0,0 +1,48 | |||||
|
1 | #ifndef OPAQUE_CONSTEXPR14_HPP | |||
|
2 | #define OPAQUE_CONSTEXPR14_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | ||||
|
32 | namespace opaque { | |||
|
33 | ||||
|
34 | /// \addtogroup miscellaneous | |||
|
35 | /// @{ | |||
|
36 | ||||
|
37 | /// If C++14 constexpr (N3652) is supported, the keyword constexpr, else blank | |||
|
38 | #if defined __cpp_constexpr && __cpp_constexpr >= 201304 | |||
|
39 | #define constexpr14 constexpr | |||
|
40 | #else | |||
|
41 | #define constexpr14 | |||
|
42 | #endif | |||
|
43 | ||||
|
44 | /// @} | |||
|
45 | ||||
|
46 | } | |||
|
47 | ||||
|
48 | #endif |
@@ -0,0 +1,381 | |||||
|
1 | #ifndef OPAQUE_CONVERT_HPP | |||
|
2 | #define OPAQUE_CONVERT_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "type_traits.hpp" | |||
|
32 | #include "utility.hpp" | |||
|
33 | #include "data.hpp" | |||
|
34 | #include <type_traits> | |||
|
35 | ||||
|
36 | namespace opaque { | |||
|
37 | ||||
|
38 | /// \addtogroup internal | |||
|
39 | /// @{ | |||
|
40 | ||||
|
41 | // | |||
|
42 | // Conversion operations | |||
|
43 | // | |||
|
44 | // Convert from one type to a compatible type, avoiding creating a new object | |||
|
45 | // when possible. The function determines whether the output must be mutable | |||
|
46 | // or may be const. | |||
|
47 | // | |||
|
48 | // The cost model is: | |||
|
49 | // 0 = free case | |||
|
50 | // 1 = construction from rvalue reference | |||
|
51 | // 2 = construction from lvalue reference | |||
|
52 | // | |||
|
53 | ||||
|
54 | template <typename T, typename U=T, | |||
|
55 | bool free = is_cast_free<T, typename std::decay<U>::type>::value> | |||
|
56 | struct converter; | |||
|
57 | ||||
|
58 | template <typename T, typename U> | |||
|
59 | struct converter<T, const U&, true> { | |||
|
60 | ||||
|
61 | static constexpr T convert_mutable(const U& u) noexcept( | |||
|
62 | noexcept(static_cast< T >(u))) { | |||
|
63 | return static_cast< T >(u); } | |||
|
64 | ||||
|
65 | static constexpr const T& convert( const U& u) noexcept( | |||
|
66 | noexcept(static_cast<const T& >(u))) { | |||
|
67 | return static_cast<const T& >(u); } | |||
|
68 | ||||
|
69 | static constexpr unsigned mutable_cost() noexcept { return 2; } | |||
|
70 | static constexpr unsigned cost() noexcept { return 0; } | |||
|
71 | ||||
|
72 | }; | |||
|
73 | ||||
|
74 | template <typename T, typename U> | |||
|
75 | struct converter<T, U&, true> { | |||
|
76 | ||||
|
77 | static constexpr T& convert_mutable( U& u) noexcept( | |||
|
78 | noexcept(static_cast< T& >(u))) { | |||
|
79 | return static_cast< T& >(u); } | |||
|
80 | ||||
|
81 | static constexpr T& convert( U& u) noexcept( | |||
|
82 | noexcept(static_cast< T& >(u))) { | |||
|
83 | return static_cast< T& >(u); } | |||
|
84 | ||||
|
85 | static constexpr unsigned mutable_cost() noexcept { return 0; } | |||
|
86 | static constexpr unsigned cost() noexcept { return 0; } | |||
|
87 | ||||
|
88 | }; | |||
|
89 | ||||
|
90 | template <typename T, typename U> | |||
|
91 | struct converter<T, U&&, true> { | |||
|
92 | ||||
|
93 | static constexpr T&& convert_mutable( U&& u) noexcept( | |||
|
94 | noexcept(static_cast< T&&>(opaque::move(u)))) { | |||
|
95 | return static_cast< T&&>(opaque::move(u)); } | |||
|
96 | ||||
|
97 | static constexpr T&& convert( U&& u) noexcept( | |||
|
98 | noexcept(static_cast< T&&>(opaque::move(u)))) { | |||
|
99 | return static_cast< T&&>(opaque::move(u)); } | |||
|
100 | ||||
|
101 | static constexpr unsigned mutable_cost() noexcept { return 0; } | |||
|
102 | static constexpr unsigned cost() noexcept { return 0; } | |||
|
103 | ||||
|
104 | }; | |||
|
105 | ||||
|
106 | template <typename T, typename U> | |||
|
107 | struct converter<T, U, true> { // same as U&& | |||
|
108 | ||||
|
109 | static constexpr T&& convert_mutable( U&& u) noexcept( | |||
|
110 | noexcept(static_cast< T&&>(opaque::move(u)))) { | |||
|
111 | return static_cast< T&&>(opaque::move(u)); } | |||
|
112 | ||||
|
113 | static constexpr T&& convert( U&& u) noexcept( | |||
|
114 | noexcept(static_cast< T&&>(opaque::move(u)))) { | |||
|
115 | return static_cast< T&&>(opaque::move(u)); } | |||
|
116 | ||||
|
117 | static constexpr unsigned mutable_cost() noexcept { return 0; } | |||
|
118 | static constexpr unsigned cost() noexcept { return 0; } | |||
|
119 | ||||
|
120 | }; | |||
|
121 | ||||
|
122 | template <typename T, typename U> | |||
|
123 | struct converter<T, const U&, false> { | |||
|
124 | ||||
|
125 | template <typename R=T> | |||
|
126 | static constexpr | |||
|
127 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
128 | R>::type convert_mutable(const U& u) noexcept( | |||
|
129 | noexcept(static_cast<R>(u))) { | |||
|
130 | return static_cast<R>(u); } | |||
|
131 | ||||
|
132 | template <typename R=T> | |||
|
133 | static constexpr | |||
|
134 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
135 | R>::type convert_mutable(const U& u) noexcept( | |||
|
136 | noexcept(static_cast<R>(u.value))) { | |||
|
137 | return static_cast<R>(u.value); } | |||
|
138 | ||||
|
139 | template <typename R=T> | |||
|
140 | static constexpr | |||
|
141 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
142 | R>::type convert( const U& u) noexcept( | |||
|
143 | noexcept(static_cast<R>(u))) { | |||
|
144 | return static_cast<R>(u); } | |||
|
145 | ||||
|
146 | template <typename R=const T&> | |||
|
147 | static constexpr | |||
|
148 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
149 | R>::type convert( const U& u) noexcept( | |||
|
150 | noexcept(static_cast<R>(u.value))) { | |||
|
151 | return static_cast<R>(u.value); } | |||
|
152 | ||||
|
153 | template <typename R=unsigned> | |||
|
154 | static constexpr | |||
|
155 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
156 | R>::type mutable_cost() noexcept { return 2; } | |||
|
157 | template <typename R=unsigned> | |||
|
158 | static constexpr | |||
|
159 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
160 | R>::type mutable_cost() noexcept { return 2; } | |||
|
161 | template <typename R=unsigned> | |||
|
162 | static constexpr | |||
|
163 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
164 | R>::type cost() noexcept { return 2; } | |||
|
165 | template <typename R=unsigned> | |||
|
166 | static constexpr | |||
|
167 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
168 | R>::type cost() noexcept { return 0; } | |||
|
169 | ||||
|
170 | }; | |||
|
171 | ||||
|
172 | template <typename T, typename U> | |||
|
173 | struct converter<T, U&, false> { | |||
|
174 | ||||
|
175 | template <typename R=T> | |||
|
176 | static constexpr | |||
|
177 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
178 | R>::type convert_mutable( U& u) noexcept( | |||
|
179 | noexcept(static_cast<R>(u))) { | |||
|
180 | return static_cast<R>(u); } | |||
|
181 | ||||
|
182 | template <typename R=T&> | |||
|
183 | static constexpr | |||
|
184 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
185 | R>::type convert_mutable( U& u) noexcept( | |||
|
186 | noexcept(static_cast<R>(u.value))) { | |||
|
187 | return static_cast<R>(u.value); } | |||
|
188 | ||||
|
189 | template <typename R=T> | |||
|
190 | static constexpr | |||
|
191 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
192 | R>::type convert( U& u) noexcept( | |||
|
193 | noexcept(static_cast<R>(u))) { | |||
|
194 | return static_cast<R>(u); } | |||
|
195 | ||||
|
196 | template <typename R=T&> | |||
|
197 | static constexpr | |||
|
198 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
199 | R>::type convert( U& u) noexcept( | |||
|
200 | noexcept(static_cast<R>(u.value))) { | |||
|
201 | return static_cast<R>(u.value); } | |||
|
202 | ||||
|
203 | template <typename R=unsigned> | |||
|
204 | static constexpr | |||
|
205 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
206 | R>::type mutable_cost() noexcept { return 2; } | |||
|
207 | template <typename R=unsigned> | |||
|
208 | static constexpr | |||
|
209 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
210 | R>::type mutable_cost() noexcept { return 0; } | |||
|
211 | template <typename R=unsigned> | |||
|
212 | static constexpr | |||
|
213 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
214 | R>::type cost() noexcept { return 2; } | |||
|
215 | template <typename R=unsigned> | |||
|
216 | static constexpr | |||
|
217 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
218 | R>::type cost() noexcept { return 0; } | |||
|
219 | }; | |||
|
220 | ||||
|
221 | ||||
|
222 | template <typename T, typename U> | |||
|
223 | struct converter<T, U&&, false> { | |||
|
224 | ||||
|
225 | template <typename R=T> | |||
|
226 | static constexpr | |||
|
227 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
228 | R>::type convert_mutable( U&& u) noexcept( | |||
|
229 | noexcept(static_cast<R>(opaque::move(u)))) { | |||
|
230 | return static_cast<R>(opaque::move(u)); } | |||
|
231 | ||||
|
232 | template <typename R=T&&> | |||
|
233 | static constexpr | |||
|
234 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
235 | R>::type convert_mutable( U&& u) noexcept( | |||
|
236 | noexcept(static_cast<R>(opaque::move(u.value)))) { | |||
|
237 | return static_cast<R>(opaque::move(u.value)); } | |||
|
238 | ||||
|
239 | template <typename R=T> | |||
|
240 | static constexpr | |||
|
241 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
242 | R>::type convert( U&& u) noexcept( | |||
|
243 | noexcept(static_cast<R>(opaque::move(u)))) { | |||
|
244 | return static_cast<R>(opaque::move(u)); } | |||
|
245 | ||||
|
246 | template <typename R=T&&> | |||
|
247 | static constexpr | |||
|
248 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
249 | R>::type convert( U&& u) noexcept( | |||
|
250 | noexcept(static_cast<R>(opaque::move(u.value)))) { | |||
|
251 | return static_cast<R>(opaque::move(u.value)); } | |||
|
252 | ||||
|
253 | template <typename R=unsigned> | |||
|
254 | static constexpr | |||
|
255 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
256 | R>::type mutable_cost() noexcept { return 1; } | |||
|
257 | template <typename R=unsigned> | |||
|
258 | static constexpr | |||
|
259 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
260 | R>::type mutable_cost() noexcept { return 0; } | |||
|
261 | template <typename R=unsigned> | |||
|
262 | static constexpr | |||
|
263 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
264 | R>::type cost() noexcept { return 1; } | |||
|
265 | template <typename R=unsigned> | |||
|
266 | static constexpr | |||
|
267 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
268 | R>::type cost() noexcept { return 0; } | |||
|
269 | }; | |||
|
270 | ||||
|
271 | ||||
|
272 | template <typename T, typename U> | |||
|
273 | struct converter<T, U, false> { // same as U&& | |||
|
274 | ||||
|
275 | template <typename R=T> | |||
|
276 | static constexpr | |||
|
277 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
278 | R>::type convert_mutable( U&& u) noexcept( | |||
|
279 | noexcept(static_cast<R>(opaque::move(u)))) { | |||
|
280 | return static_cast<R>(opaque::move(u)); } | |||
|
281 | ||||
|
282 | template <typename R=T&&> | |||
|
283 | static constexpr | |||
|
284 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
285 | R>::type convert_mutable( U&& u) noexcept( | |||
|
286 | noexcept(static_cast<R>(opaque::move(u.value)))) { | |||
|
287 | return static_cast<R>(opaque::move(u.value)); } | |||
|
288 | ||||
|
289 | template <typename R=T> | |||
|
290 | static constexpr | |||
|
291 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
292 | R>::type convert( U&& u) noexcept( | |||
|
293 | noexcept(static_cast<R>(opaque::move(u)))) { | |||
|
294 | return static_cast<R>(opaque::move(u)); } | |||
|
295 | ||||
|
296 | template <typename R=T&&> | |||
|
297 | static constexpr | |||
|
298 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
299 | R>::type convert( U&& u) noexcept( | |||
|
300 | noexcept(static_cast<R>(opaque::move(u.value)))) { | |||
|
301 | return static_cast<R>(opaque::move(u.value)); } | |||
|
302 | ||||
|
303 | template <typename R=unsigned> | |||
|
304 | static constexpr | |||
|
305 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
306 | R>::type mutable_cost() noexcept { return 1; } | |||
|
307 | template <typename R=unsigned> | |||
|
308 | static constexpr | |||
|
309 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
310 | R>::type mutable_cost() noexcept { return 0; } | |||
|
311 | template <typename R=unsigned> | |||
|
312 | static constexpr | |||
|
313 | typename std::enable_if<not std::is_base_of<data<T,U>, U>::value, | |||
|
314 | R>::type cost() noexcept { return 1; } | |||
|
315 | template <typename R=unsigned> | |||
|
316 | static constexpr | |||
|
317 | typename std::enable_if< std::is_base_of<data<T,U>, U>::value, | |||
|
318 | R>::type cost() noexcept { return 0; } | |||
|
319 | ||||
|
320 | }; | |||
|
321 | ||||
|
322 | /// | |||
|
323 | /// Convert the argument and ensure the result is mutable | |||
|
324 | /// | |||
|
325 | /// Where possible, the conversion is performed via a no-cost cast (perhaps an | |||
|
326 | /// up or down cast), but for unrelated or const types, a new object is | |||
|
327 | /// created. | |||
|
328 | /// | |||
|
329 | template <typename T, typename U=T> | |||
|
330 | constexpr auto convert_mutable(U&& u) | |||
|
331 | noexcept(noexcept( | |||
|
332 | converter<typename std::decay<T>::type, U>::convert_mutable( | |||
|
333 | opaque::forward<U>(u)))) -> decltype( | |||
|
334 | converter<typename std::decay<T>::type, U>::convert_mutable( | |||
|
335 | opaque::forward<U>(u))) { return | |||
|
336 | converter<typename std::decay<T>::type, U>::convert_mutable( | |||
|
337 | opaque::forward<U>(u)); | |||
|
338 | } | |||
|
339 | ||||
|
340 | /// | |||
|
341 | /// Convert the argument | |||
|
342 | /// | |||
|
343 | /// Where possible, the conversion is performed via a no-cost cast (perhaps an | |||
|
344 | /// up or down cast), but for unrelated types, a new object is created. | |||
|
345 | /// | |||
|
346 | template <typename T, typename U=T> | |||
|
347 | constexpr auto convert(U&& u) | |||
|
348 | noexcept(noexcept( | |||
|
349 | converter<typename std::decay<T>::type, U>::convert( | |||
|
350 | opaque::forward<U>(u)))) -> decltype( | |||
|
351 | converter<typename std::decay<T>::type, U>::convert( | |||
|
352 | opaque::forward<U>(u))) { return | |||
|
353 | converter<typename std::decay<T>::type, U>::convert( | |||
|
354 | opaque::forward<U>(u)); | |||
|
355 | } | |||
|
356 | ||||
|
357 | template <typename T, typename U> | |||
|
358 | constexpr unsigned convert_mutable_cost() noexcept { | |||
|
359 | return converter<typename std::decay<T>::type, U&&>::mutable_cost(); | |||
|
360 | } | |||
|
361 | ||||
|
362 | template <typename T, typename U> | |||
|
363 | constexpr unsigned convert_mutable_cost(U&&) noexcept { | |||
|
364 | return converter<typename std::decay<T>::type, U&&>::mutable_cost(); | |||
|
365 | } | |||
|
366 | ||||
|
367 | template <typename T, typename U> | |||
|
368 | constexpr unsigned convert_cost() noexcept { | |||
|
369 | return converter<typename std::decay<T>::type, U&&>::cost(); | |||
|
370 | } | |||
|
371 | ||||
|
372 | template <typename T, typename U> | |||
|
373 | constexpr unsigned convert_cost(U&&) noexcept { | |||
|
374 | return converter<typename std::decay<T>::type, U&&>::cost(); | |||
|
375 | } | |||
|
376 | ||||
|
377 | /// @} | |||
|
378 | ||||
|
379 | } | |||
|
380 | ||||
|
381 | #endif |
@@ -0,0 +1,88 | |||||
|
1 | #ifndef OPAQUE_DATA_HPP | |||
|
2 | #define OPAQUE_DATA_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "constexpr14.hpp" | |||
|
32 | #include "utility.hpp" | |||
|
33 | #include <type_traits> | |||
|
34 | ||||
|
35 | namespace opaque { | |||
|
36 | ||||
|
37 | /// \addtogroup internal | |||
|
38 | /// @{ | |||
|
39 | ||||
|
40 | /// | |||
|
41 | /// Data storage for opaque typedefs | |||
|
42 | /// | |||
|
43 | template <typename U, typename O> | |||
|
44 | struct data { | |||
|
45 | typedef U underlying_type; | |||
|
46 | typedef O opaque_type; | |||
|
47 | ||||
|
48 | underlying_type value; | |||
|
49 | ||||
|
50 | /// Copy the underlying value | |||
|
51 | explicit constexpr operator underlying_type() const & | |||
|
52 | noexcept(std::is_nothrow_copy_constructible<underlying_type>::value) { | |||
|
53 | return value ; | |||
|
54 | } | |||
|
55 | ||||
|
56 | /// Move the underlying value | |||
|
57 | explicit constexpr14 operator underlying_type() && | |||
|
58 | noexcept(std::is_nothrow_move_constructible<underlying_type>::value) { | |||
|
59 | return opaque::move(value); | |||
|
60 | } | |||
|
61 | ||||
|
62 | /// Construct | |||
|
63 | template <typename... Args> | |||
|
64 | explicit constexpr data(Args&&... args) | |||
|
65 | noexcept(std::is_nothrow_constructible<underlying_type, Args&&...>::value) | |||
|
66 | : value(opaque::forward<Args>(args)...) { } | |||
|
67 | ||||
|
68 | data() = default; | |||
|
69 | data(const data& ) = default; | |||
|
70 | data( data&&) = default; | |||
|
71 | data& operator=(const data& ) & = default; | |||
|
72 | data& operator=( data&&) & = default; | |||
|
73 | protected: | |||
|
74 | ~data() = default; | |||
|
75 | ||||
|
76 | /// Downcast to the opaque_type | |||
|
77 | constexpr14 opaque_type& downcast() noexcept { | |||
|
78 | static_assert(std::is_base_of<data, opaque_type>::value, "Bad downcast"); | |||
|
79 | return *static_cast<opaque_type*>(this); | |||
|
80 | } | |||
|
81 | ||||
|
82 | }; | |||
|
83 | ||||
|
84 | /// @} | |||
|
85 | ||||
|
86 | } | |||
|
87 | ||||
|
88 | #endif |
@@ -0,0 +1,106 | |||||
|
1 | #ifndef OPAQUE_EXPERIMENTAL_POSITION_TYPEDEF_HPP | |||
|
2 | #define OPAQUE_EXPERIMENTAL_POSITION_TYPEDEF_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "../numeric_typedef.hpp" | |||
|
32 | ||||
|
33 | namespace opaque { | |||
|
34 | namespace experimental { | |||
|
35 | ||||
|
36 | /// \addtogroup typedefs | |||
|
37 | /// @{ | |||
|
38 | ||||
|
39 | /// | |||
|
40 | /// Numeric opaque typedef to represent a position | |||
|
41 | /// | |||
|
42 | /// This is a numeric typedef base class providing interoperability between | |||
|
43 | /// two types for the + and - operations as follows: | |||
|
44 | /// - position + position --> type error | |||
|
45 | /// - position + distance --> position | |||
|
46 | /// - distance + position --> position | |||
|
47 | /// - distance + distance --> distance | |||
|
48 | /// - position - position --> distance | |||
|
49 | /// - position - distance --> position | |||
|
50 | /// - distance - position --> type error | |||
|
51 | /// - distance - distance --> distance | |||
|
52 | /// | |||
|
53 | /// Template arguments for position_typedef: | |||
|
54 | /// -# Distance : The distance type, which must be a numeric opaque typedef | |||
|
55 | /// -# O : The opaque type, your subclass | |||
|
56 | /// | |||
|
57 | template <typename Distance, typename O> | |||
|
58 | struct position_typedef | |||
|
59 | : numeric_typedef_base<typename Distance::underlying_type, O, | |||
|
60 | typename Distance::shift_type> | |||
|
61 | , binop::addable <O , true , O , Distance> | |||
|
62 | , binop::addable <O , true , Distance, O > | |||
|
63 | , binop::subtractable<O , false, O , Distance> | |||
|
64 | , binop::subtractable<Distance, false, O , O , | |||
|
65 | typename Distance::underlying_type, | |||
|
66 | typename Distance::underlying_type> | |||
|
67 | { | |||
|
68 | private: | |||
|
69 | using base = | |||
|
70 | numeric_typedef_base<typename Distance::underlying_type, O, | |||
|
71 | typename Distance::shift_type>; | |||
|
72 | public: | |||
|
73 | using typename base::underlying_type; | |||
|
74 | using typename base::opaque_type; | |||
|
75 | using base::value; | |||
|
76 | ||||
|
77 | opaque_type& operator+=(const opaque_type&) = delete; | |||
|
78 | opaque_type& operator-=(const opaque_type&) = delete; | |||
|
79 | ||||
|
80 | constexpr14 opaque_type& operator+=(const Distance& s) & | |||
|
81 | noexcept(noexcept( value += s.value )) { | |||
|
82 | value += s.value; | |||
|
83 | return downcast(); } | |||
|
84 | ||||
|
85 | constexpr14 opaque_type& operator-=(const Distance& s) & | |||
|
86 | noexcept(noexcept( value -= s.value )) { | |||
|
87 | value -= s.value; | |||
|
88 | return downcast(); } | |||
|
89 | ||||
|
90 | using base::base; | |||
|
91 | explicit position_typedef() = default; | |||
|
92 | position_typedef(const position_typedef& ) = default; | |||
|
93 | position_typedef( position_typedef&&) = default; | |||
|
94 | position_typedef& operator=(const position_typedef& ) & = default; | |||
|
95 | position_typedef& operator=( position_typedef&&) & = default; | |||
|
96 | protected: | |||
|
97 | ~position_typedef() = default; | |||
|
98 | using base::downcast; | |||
|
99 | }; | |||
|
100 | ||||
|
101 | /// @} | |||
|
102 | ||||
|
103 | } | |||
|
104 | } | |||
|
105 | ||||
|
106 | #endif |
This diff has been collapsed as it changes many lines, (581 lines changed) Show them Hide them | |||||
@@ -0,0 +1,581 | |||||
|
1 | #ifndef OPAQUE_EXPERIMENTAL_SAFER_STRING_TYPEDEF_HPP | |||
|
2 | #define OPAQUE_EXPERIMENTAL_SAFER_STRING_TYPEDEF_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "../data.hpp" | |||
|
32 | #include <memory> | |||
|
33 | #include <string> | |||
|
34 | ||||
|
35 | namespace opaque { | |||
|
36 | namespace experimental { | |||
|
37 | ||||
|
38 | /// \addtogroup typedefs | |||
|
39 | /// @{ | |||
|
40 | ||||
|
41 | /// | |||
|
42 | /// Safer string opaque typedef base type | |||
|
43 | /// | |||
|
44 | /// This is an opaque typedef base class for standard strings, but without | |||
|
45 | /// interoperability with character arrays in ways that would modify the | |||
|
46 | /// opaque object or create new opaque object instances. | |||
|
47 | /// | |||
|
48 | /// Template arguments: | |||
|
49 | /// -# S : The string type (e.g. std::string) | |||
|
50 | /// -# R : The result type, your subclass | |||
|
51 | /// | |||
|
52 | template <typename S, typename R> | |||
|
53 | struct safer_string_typedef : data<S,R> { | |||
|
54 | private: | |||
|
55 | using base = opaque::data<S,R>; | |||
|
56 | public: | |||
|
57 | using typename base::underlying_type; | |||
|
58 | using typename base::opaque_type; | |||
|
59 | using base::value; | |||
|
60 | ||||
|
61 | typedef typename S::traits_type traits_type; | |||
|
62 | typedef typename S::value_type value_type; | |||
|
63 | typedef typename S::allocator_type allocator_type; | |||
|
64 | typedef typename S::size_type size_type; | |||
|
65 | typedef typename S::difference_type difference_type; | |||
|
66 | typedef typename S::reference reference; | |||
|
67 | typedef typename S::const_reference const_reference; | |||
|
68 | typedef typename S::pointer pointer; | |||
|
69 | typedef typename S::const_pointer const_pointer; | |||
|
70 | typedef typename S::iterator iterator; | |||
|
71 | typedef typename S::const_iterator const_iterator; | |||
|
72 | typedef typename S::reverse_iterator reverse_iterator; | |||
|
73 | typedef typename S::const_reverse_iterator const_reverse_iterator; | |||
|
74 | static const size_type npos = size_type(0)-size_type(1); | |||
|
75 | ||||
|
76 | private: | |||
|
77 | typedef allocator_type Allocator; | |||
|
78 | typedef typename std::allocator_traits<Allocator>::value_type charT; | |||
|
79 | public: | |||
|
80 | ||||
|
81 | // | |||
|
82 | // Constructor philosophy | |||
|
83 | // | |||
|
84 | // 1) Provide for explicit construction from an instance of underlying_type. | |||
|
85 | // | |||
|
86 | // 2) Constructors that have an argument of underlying_type are provided in | |||
|
87 | // in two flavors: an explicit one taking underlying_type, and one taking | |||
|
88 | // opaque_type that has the explicitness of the original. | |||
|
89 | // | |||
|
90 | // 3) Constructors that do not have an argument of underlying_type are made | |||
|
91 | // explicit. | |||
|
92 | // | |||
|
93 | ||||
|
94 | explicit safer_string_typedef(const underlying_type& str) noexcept | |||
|
95 | : base(str) { } | |||
|
96 | explicit safer_string_typedef( underlying_type&& str) noexcept | |||
|
97 | : base(std::move(str)) { } | |||
|
98 | ||||
|
99 | // | |||
|
100 | // The default constructor has the C++14 interface; a zero-argument | |||
|
101 | // form (defaulted below) and a single-argument form taking an Allocator. | |||
|
102 | // | |||
|
103 | explicit safer_string_typedef(const Allocator& a) | |||
|
104 | : base(a) { } | |||
|
105 | explicit safer_string_typedef(const underlying_type& str, size_type pos, | |||
|
106 | size_type n = npos, const Allocator& a = Allocator()) | |||
|
107 | : base(str.value, pos, n, a) { } | |||
|
108 | safer_string_typedef(const opaque_type& str, size_type pos, | |||
|
109 | size_type n = npos, const Allocator& a = Allocator()) | |||
|
110 | : base(str.value, pos, n, a) { } | |||
|
111 | explicit safer_string_typedef(const charT* s, size_type n, | |||
|
112 | const Allocator& a = Allocator()) | |||
|
113 | : base(s, n, a) { } | |||
|
114 | explicit safer_string_typedef(const charT* s, | |||
|
115 | const Allocator& a = Allocator()) | |||
|
116 | : base(s, a) { } | |||
|
117 | explicit safer_string_typedef(size_type n, charT c, | |||
|
118 | const Allocator& a = Allocator()) | |||
|
119 | : base(n, c, a) { } | |||
|
120 | template <class InputIterator> | |||
|
121 | explicit safer_string_typedef(InputIterator Begin, InputIterator End, | |||
|
122 | const Allocator& a = Allocator()) | |||
|
123 | : base(Begin, End, a) { } | |||
|
124 | explicit safer_string_typedef(std::initializer_list<charT> il, | |||
|
125 | const Allocator& a = Allocator()) | |||
|
126 | : base(il, a) { } | |||
|
127 | explicit safer_string_typedef(const underlying_type& str, const Allocator& a) | |||
|
128 | : base(str.value, a) { } | |||
|
129 | explicit safer_string_typedef(underlying_type&& str, const Allocator& a) | |||
|
130 | : base(std::move(str.value), a) { } | |||
|
131 | safer_string_typedef(const opaque_type& str, const Allocator& a) | |||
|
132 | : base(str.value, a) { } | |||
|
133 | safer_string_typedef(opaque_type&& str, const Allocator& a) | |||
|
134 | : base(std::move(str.value), a) { } | |||
|
135 | ||||
|
136 | // opaque_type& operator=(const charT* s); | |||
|
137 | opaque_type& operator=(charT c) { | |||
|
138 | value = c; | |||
|
139 | return downcast(); | |||
|
140 | } | |||
|
141 | opaque_type& operator=(std::initializer_list<charT> il) { | |||
|
142 | value = il; | |||
|
143 | return downcast(); | |||
|
144 | } | |||
|
145 | ||||
|
146 | iterator begin() noexcept { return value.begin() ; } | |||
|
147 | const_iterator begin() const noexcept { return value.begin() ; } | |||
|
148 | iterator end() noexcept { return value.end() ; } | |||
|
149 | const_iterator end() const noexcept { return value.end() ; } | |||
|
150 | reverse_iterator rbegin() noexcept { return value.rbegin() ; } | |||
|
151 | const_reverse_iterator rbegin() const noexcept { return value.rbegin() ; } | |||
|
152 | reverse_iterator rend() noexcept { return value.rend() ; } | |||
|
153 | const_reverse_iterator rend() const noexcept { return value.rend() ; } | |||
|
154 | const_iterator cbegin() const noexcept { return value.cbegin() ; } | |||
|
155 | const_iterator cend() const noexcept { return value.cend() ; } | |||
|
156 | const_reverse_iterator crbegin() const noexcept { return value.crbegin(); } | |||
|
157 | const_reverse_iterator crend() const noexcept { return value.crend() ; } | |||
|
158 | ||||
|
159 | size_type size() const noexcept { return value.size(); } | |||
|
160 | size_type length() const noexcept { return value.length(); } | |||
|
161 | size_type max_size() const noexcept { return value.max_size(); } | |||
|
162 | void resize(size_type n, charT c) { return value.resize(n, c); } | |||
|
163 | void resize(size_type n) { return value.resize(n); } | |||
|
164 | size_type capacity() const noexcept { return value.capacity(); } | |||
|
165 | void reserve(size_type res_arg = 0) { return value.reserve(res_arg); } | |||
|
166 | void shrink_to_fit() { return value.shrink_to_fit(); } | |||
|
167 | void clear() noexcept { return value.clear(); } | |||
|
168 | bool empty() const noexcept { return value.empty(); } | |||
|
169 | ||||
|
170 | const_reference operator[](size_type pos) const { return value[pos]; } | |||
|
171 | reference operator[](size_type pos) { return value[pos]; } | |||
|
172 | const_reference at(size_type n) const { return value.at(n); } | |||
|
173 | reference at(size_type n) { return value.at(n); } | |||
|
174 | ||||
|
175 | const charT& front() const { return value.front(); } | |||
|
176 | charT& front() { return value.front(); } | |||
|
177 | const charT& back() const { return value.back(); } | |||
|
178 | charT& back() { return value.back(); } | |||
|
179 | ||||
|
180 | opaque_type& operator+=(const opaque_type& str) { | |||
|
181 | value += str.value; | |||
|
182 | return downcast(); | |||
|
183 | } | |||
|
184 | // opaque_type& operator+=(const charT* s); | |||
|
185 | opaque_type& operator+=(charT c) { | |||
|
186 | value += c; | |||
|
187 | return downcast(); | |||
|
188 | } | |||
|
189 | opaque_type& operator+=(std::initializer_list<charT> il) { | |||
|
190 | value += il; | |||
|
191 | return downcast(); | |||
|
192 | } | |||
|
193 | opaque_type& append(const opaque_type& str) { | |||
|
194 | value.append(str.value); | |||
|
195 | return downcast(); | |||
|
196 | } | |||
|
197 | // C++14 interface | |||
|
198 | opaque_type& append(const opaque_type& str, size_type pos, | |||
|
199 | size_type n = npos) { | |||
|
200 | value.append(str.value, pos, n); | |||
|
201 | return downcast(); | |||
|
202 | } | |||
|
203 | //opaque_type& append(const charT* s, size_type n); | |||
|
204 | //opaque_type& append(const charT* s); | |||
|
205 | opaque_type& append(size_type n, charT c) { | |||
|
206 | value.append(n, c); | |||
|
207 | return downcast(); | |||
|
208 | } | |||
|
209 | template <class InputIterator> | |||
|
210 | opaque_type& append(InputIterator first, InputIterator last) { | |||
|
211 | value.append(first, last); | |||
|
212 | return downcast(); | |||
|
213 | } | |||
|
214 | opaque_type& append(std::initializer_list<charT> il) { | |||
|
215 | value.append(il); | |||
|
216 | return downcast(); | |||
|
217 | } | |||
|
218 | void push_back(charT c) { | |||
|
219 | return value.push_back(c); | |||
|
220 | } | |||
|
221 | ||||
|
222 | opaque_type& assign(const opaque_type& str) { | |||
|
223 | value.assign(str.value); | |||
|
224 | return downcast(); | |||
|
225 | } | |||
|
226 | opaque_type& assign(opaque_type&& str) noexcept { | |||
|
227 | value.assign(std::move(str.value)); | |||
|
228 | return downcast(); | |||
|
229 | } | |||
|
230 | // C++14 interface | |||
|
231 | opaque_type& assign(const opaque_type& str, size_type pos, | |||
|
232 | size_type n = npos) { | |||
|
233 | value.assign(str.value, pos, n); | |||
|
234 | return downcast(); | |||
|
235 | } | |||
|
236 | // opaque_type& assign(const charT* s, size_type n); | |||
|
237 | // opaque_type& assign(const charT* s); | |||
|
238 | opaque_type& assign(size_type n, charT c) { | |||
|
239 | value.assign(n, c); | |||
|
240 | return downcast(); | |||
|
241 | } | |||
|
242 | template <class InputIterator> | |||
|
243 | opaque_type& assign(InputIterator first, InputIterator last) { | |||
|
244 | value.assign(first, last); | |||
|
245 | return downcast(); | |||
|
246 | } | |||
|
247 | opaque_type& assign(std::initializer_list<charT> il) { | |||
|
248 | value.assign(il); | |||
|
249 | return downcast(); | |||
|
250 | } | |||
|
251 | ||||
|
252 | opaque_type& insert(size_type pos1, const opaque_type& str) { | |||
|
253 | value.insert(pos1, str.value); | |||
|
254 | return downcast(); | |||
|
255 | } | |||
|
256 | // C++14 interface | |||
|
257 | opaque_type& insert(size_type pos1, const opaque_type& str, | |||
|
258 | size_type pos2, size_type n = npos) { | |||
|
259 | value.insert(pos1, str.value, pos2, n); | |||
|
260 | return downcast(); | |||
|
261 | } | |||
|
262 | // opaque_type& insert(size_type pos, const charT* s, size_type n); | |||
|
263 | // opaque_type& insert(size_type pos, const charT* s); | |||
|
264 | opaque_type& insert(size_type pos, size_type n, charT c) { | |||
|
265 | value.insert(pos, n, c); | |||
|
266 | return downcast(); | |||
|
267 | } | |||
|
268 | // C++03 interface | |||
|
269 | iterator insert(iterator p, charT c) { | |||
|
270 | return insert(p, c); | |||
|
271 | } | |||
|
272 | // C++03 interface | |||
|
273 | iterator insert(iterator p, size_type n, charT c) { | |||
|
274 | return insert(p, n, c); | |||
|
275 | } | |||
|
276 | // C++03 interface | |||
|
277 | template <class InputIterator> | |||
|
278 | iterator insert(iterator p, InputIterator first, InputIterator last) { | |||
|
279 | return insert(p, first, last); | |||
|
280 | } | |||
|
281 | iterator insert(const_iterator p, charT c) { | |||
|
282 | return insert(p, c); | |||
|
283 | } | |||
|
284 | iterator insert(const_iterator p, size_type n, charT c) { | |||
|
285 | return insert(p, n, c); | |||
|
286 | } | |||
|
287 | template <class InputIterator> | |||
|
288 | iterator insert(const_iterator p, InputIterator first, InputIterator last) { | |||
|
289 | return insert(p, first, last); | |||
|
290 | } | |||
|
291 | iterator insert(const_iterator p, std::initializer_list<charT> il) { | |||
|
292 | return insert(p, il); | |||
|
293 | } | |||
|
294 | ||||
|
295 | opaque_type& erase(size_type pos = 0, size_type n = npos) { | |||
|
296 | value.erase(pos, n); | |||
|
297 | return downcast(); | |||
|
298 | } | |||
|
299 | // C++03 interface | |||
|
300 | iterator erase(iterator p) { | |||
|
301 | return value.erase(p); | |||
|
302 | } | |||
|
303 | // C++03 interface | |||
|
304 | iterator erase(iterator first, iterator last) { | |||
|
305 | return value.erase(first, last); | |||
|
306 | } | |||
|
307 | iterator erase(const_iterator p) { | |||
|
308 | return value.erase(p); | |||
|
309 | } | |||
|
310 | iterator erase(const_iterator first, const_iterator last) { | |||
|
311 | return value.erase(first, last); | |||
|
312 | } | |||
|
313 | ||||
|
314 | void pop_back() { return value.pop_back(); } | |||
|
315 | ||||
|
316 | opaque_type& replace(size_type pos1, size_type n1, const opaque_type& str) { | |||
|
317 | value.replace(pos1, n1, str.value); | |||
|
318 | return downcast(); | |||
|
319 | } | |||
|
320 | // C++14 interface | |||
|
321 | opaque_type& replace(size_type pos1, size_type n1, const opaque_type& str, | |||
|
322 | size_type pos2, size_type n2 = npos) { | |||
|
323 | value.replace(pos1, n1, str.value, pos2, n2); | |||
|
324 | return downcast(); | |||
|
325 | } | |||
|
326 | // opaque_type& replace(size_type pos, size_type n1, const charT* s, | |||
|
327 | // size_type n2); | |||
|
328 | // opaque_type& replace(size_type pos, size_type n1, const charT* s); | |||
|
329 | opaque_type& replace(size_type pos, size_type n1, size_type n2, charT c) { | |||
|
330 | value.replace(pos, n1, n2, c); | |||
|
331 | return downcast(); | |||
|
332 | } | |||
|
333 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
334 | const opaque_type& str) { | |||
|
335 | value.replace(i1, i2, str.value); | |||
|
336 | return downcast(); | |||
|
337 | } | |||
|
338 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
339 | const charT* s, size_type n) { | |||
|
340 | value.replace(i1, i2, s, n); | |||
|
341 | return downcast(); | |||
|
342 | } | |||
|
343 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
344 | const charT* s) { | |||
|
345 | value.replace(i1, i2, s); | |||
|
346 | return downcast(); | |||
|
347 | } | |||
|
348 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
349 | size_type n, charT c) { | |||
|
350 | value.replace(i1, i2, n, c); | |||
|
351 | return downcast(); | |||
|
352 | } | |||
|
353 | template <class InputIterator> | |||
|
354 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
355 | InputIterator j1, InputIterator j2) { | |||
|
356 | value.replace(i1, i2, j1, j2); | |||
|
357 | return downcast(); | |||
|
358 | } | |||
|
359 | opaque_type& replace(const_iterator i1, const_iterator i2, | |||
|
360 | std::initializer_list<charT> il) { | |||
|
361 | value.replace(i1, i2, il); | |||
|
362 | return downcast(); | |||
|
363 | } | |||
|
364 | ||||
|
365 | size_type copy(charT* s, size_type n, size_type pos = 0) const { | |||
|
366 | return value.copy(s, n, pos); | |||
|
367 | } | |||
|
368 | void swap(opaque_type& str) { return value.swap(str.value); } | |||
|
369 | ||||
|
370 | const charT* c_str() const noexcept { return value.c_str(); } | |||
|
371 | const charT* data() const noexcept { return value.data(); } | |||
|
372 | allocator_type get_allocator() const noexcept { | |||
|
373 | return value.get_allocator(); | |||
|
374 | } | |||
|
375 | ||||
|
376 | size_type find (const opaque_type& str, size_type pos = 0) const noexcept { | |||
|
377 | return value.find(str.value, pos); | |||
|
378 | } | |||
|
379 | size_type find (const charT* s, size_type pos, size_type n) const { | |||
|
380 | return value.find(s, pos, n); | |||
|
381 | } | |||
|
382 | size_type find (const charT* s, size_type pos = 0) const { | |||
|
383 | return value.find(s, pos); | |||
|
384 | } | |||
|
385 | size_type find (charT c, size_type pos = 0) const noexcept { | |||
|
386 | return value.find(c, pos); | |||
|
387 | } | |||
|
388 | size_type rfind(const opaque_type& str, size_type pos = npos) const noexcept { | |||
|
389 | return value.rfind(str.value, pos); | |||
|
390 | } | |||
|
391 | size_type rfind(const charT* s, size_type pos, size_type n) const { | |||
|
392 | return value.rfind(s, pos, n); | |||
|
393 | } | |||
|
394 | size_type rfind(const charT* s, size_type pos = npos) const { | |||
|
395 | return value.rfind(s, pos); | |||
|
396 | } | |||
|
397 | size_type rfind(charT c, size_type pos = npos) const noexcept { | |||
|
398 | return value.rfind(c, pos); | |||
|
399 | } | |||
|
400 | ||||
|
401 | size_type find_first_of(const opaque_type& str, size_type pos = 0) const noexcept { | |||
|
402 | return value.find_first_of(str.value, pos); | |||
|
403 | } | |||
|
404 | size_type find_first_of(const charT* s, size_type pos, size_type n) const { | |||
|
405 | return value.find_first_of(s, pos, n); | |||
|
406 | } | |||
|
407 | size_type find_first_of(const charT* s, size_type pos = 0) const { | |||
|
408 | return value.find_first_of(s, pos); | |||
|
409 | } | |||
|
410 | size_type find_first_of(charT c, size_type pos = 0) const noexcept { | |||
|
411 | return value.find_first_of(c, pos); | |||
|
412 | } | |||
|
413 | size_type find_last_of (const opaque_type& str, size_type pos = npos) const noexcept { | |||
|
414 | return value.find_last_of(str.value, pos); | |||
|
415 | } | |||
|
416 | size_type find_last_of (const charT* s, size_type pos, size_type n) const { | |||
|
417 | return value.find_last_of(s, pos, n); | |||
|
418 | } | |||
|
419 | size_type find_last_of (const charT* s, size_type pos = npos) const { | |||
|
420 | return value.find_last_of(s, pos); | |||
|
421 | } | |||
|
422 | size_type find_last_of (charT c, size_type pos = npos) const noexcept { | |||
|
423 | return value.find_last_of(c, pos); | |||
|
424 | } | |||
|
425 | ||||
|
426 | size_type find_first_not_of(const opaque_type& str, size_type pos = 0) const noexcept { | |||
|
427 | return value.find_first_not_of(str.value, pos); | |||
|
428 | } | |||
|
429 | size_type find_first_not_of(const charT* s, size_type pos, size_type n) const { | |||
|
430 | return value.find_first_not_of(s, pos, n); | |||
|
431 | } | |||
|
432 | size_type find_first_not_of(const charT* s, size_type pos = 0) const { | |||
|
433 | return value.find_first_not_of(s, pos); | |||
|
434 | } | |||
|
435 | size_type find_first_not_of(charT c, size_type pos = 0) const noexcept { | |||
|
436 | return value.find_first_not_of(c, pos); | |||
|
437 | } | |||
|
438 | size_type find_last_not_of (const opaque_type& str, size_type pos = npos) const noexcept { | |||
|
439 | return value.find_last_not_of(str.value, pos); | |||
|
440 | } | |||
|
441 | size_type find_last_not_of (const charT* s, size_type pos, size_type n) const { | |||
|
442 | return value.find_last_not_of(s, pos, n); | |||
|
443 | } | |||
|
444 | size_type find_last_not_of (const charT* s, size_type pos = npos) const { | |||
|
445 | return value.find_last_not_of(s, pos); | |||
|
446 | } | |||
|
447 | size_type find_last_not_of (charT c, size_type pos = npos) const noexcept { | |||
|
448 | return value.find_last_not_of(c, pos); | |||
|
449 | } | |||
|
450 | ||||
|
451 | opaque_type substr(size_type pos = 0, size_type n = npos) const { | |||
|
452 | return opaque_type(value.substr(pos, n)); | |||
|
453 | } | |||
|
454 | int compare(const opaque_type& str) const noexcept { | |||
|
455 | return value.compare(str.value); | |||
|
456 | } | |||
|
457 | int compare(size_type pos1, size_type n1, const opaque_type& str) const { | |||
|
458 | return value.compare(pos1, n1, str.value); | |||
|
459 | } | |||
|
460 | // C++14 interface | |||
|
461 | int compare(size_type pos1, size_type n1, const opaque_type& str, | |||
|
462 | size_type pos2, size_type n2 = npos) const { | |||
|
463 | return value.compare(pos1, n1, str.value, pos2, n2); | |||
|
464 | } | |||
|
465 | int compare(const charT* s) const { | |||
|
466 | return value.compare(s); | |||
|
467 | } | |||
|
468 | int compare(size_type pos1, size_type n1, const charT* s) const { | |||
|
469 | return value.compare(pos1, n1, s); | |||
|
470 | } | |||
|
471 | int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const { | |||
|
472 | return value.compare(pos1, n1, s, n2); | |||
|
473 | } | |||
|
474 | ||||
|
475 | friend opaque_type operator+(const opaque_type& l, const opaque_type& r) { | |||
|
476 | return opaque_type( l.value + r.value ); | |||
|
477 | } | |||
|
478 | friend opaque_type operator+( opaque_type&& l, const opaque_type& r) { | |||
|
479 | return opaque_type(std::move(l.value) + r.value ); | |||
|
480 | } | |||
|
481 | friend opaque_type operator+(const opaque_type& l, opaque_type&& r) { | |||
|
482 | return opaque_type( l.value + std::move(r.value)); | |||
|
483 | } | |||
|
484 | friend opaque_type operator+( opaque_type&& l, opaque_type&& r) { | |||
|
485 | return opaque_type(std::move(l.value) + std::move(r.value)); | |||
|
486 | } | |||
|
487 | // friend opaque_type operator+(const charT* lhs, const opaque_type& rhs); | |||
|
488 | // friend opaque_type operator+(const charT* lhs, opaque_type&& rhs); | |||
|
489 | friend opaque_type operator+( charT lhs, const opaque_type& rhs) { | |||
|
490 | return lhs + rhs.value ; | |||
|
491 | } | |||
|
492 | friend opaque_type operator+( charT lhs, opaque_type&& rhs) { | |||
|
493 | return lhs + std::move(rhs.value); | |||
|
494 | } | |||
|
495 | // friend opaque_type operator+(const opaque_type& lhs, const charT* rhs); | |||
|
496 | // friend opaque_type operator+( opaque_type&& lhs, const charT* rhs); | |||
|
497 | friend opaque_type operator+(const opaque_type& lhs, charT rhs) { | |||
|
498 | return lhs.value + rhs; | |||
|
499 | } | |||
|
500 | friend opaque_type operator+( opaque_type&& lhs, charT rhs) { | |||
|
501 | return std::move(lhs.value) + rhs; | |||
|
502 | } | |||
|
503 | ||||
|
504 | friend bool operator==(const opaque_type& lhs, const opaque_type& rhs) { | |||
|
505 | return lhs.value == rhs.value; | |||
|
506 | } | |||
|
507 | friend bool operator==(const charT* lhs, const opaque_type& rhs) { | |||
|
508 | return lhs == rhs.value; | |||
|
509 | } | |||
|
510 | friend bool operator==(const opaque_type& lhs, const charT* rhs) { | |||
|
511 | return lhs.value == rhs ; | |||
|
512 | } | |||
|
513 | friend bool operator!=(const opaque_type& lhs, const opaque_type& rhs) { | |||
|
514 | return lhs.value != rhs.value; | |||
|
515 | } | |||
|
516 | friend bool operator!=(const charT* lhs, const opaque_type& rhs) { | |||
|
517 | return lhs != rhs.value; | |||
|
518 | } | |||
|
519 | friend bool operator!=(const opaque_type& lhs, const charT* rhs) { | |||
|
520 | return lhs.value != rhs ; | |||
|
521 | } | |||
|
522 | ||||
|
523 | friend bool operator< (const opaque_type& lhs, const opaque_type& rhs) { | |||
|
524 | return lhs.value < rhs.value; | |||
|
525 | } | |||
|
526 | friend bool operator< (const charT* lhs, const opaque_type& rhs) { | |||
|
527 | return lhs < rhs.value; | |||
|
528 | } | |||
|
529 | friend bool operator< (const opaque_type& lhs, const charT* rhs) { | |||
|
530 | return lhs.value < rhs ; | |||
|
531 | } | |||
|
532 | friend bool operator> (const opaque_type& lhs, const opaque_type& rhs) { | |||
|
533 | return lhs.value > rhs.value; | |||
|
534 | } | |||
|
535 | friend bool operator> (const charT* lhs, const opaque_type& rhs) { | |||
|
536 | return lhs > rhs.value; | |||
|
537 | } | |||
|
538 | friend bool operator> (const opaque_type& lhs, const charT* rhs) { | |||
|
539 | return lhs.value > rhs ; | |||
|
540 | } | |||
|
541 | ||||
|
542 | friend bool operator<=(const opaque_type& lhs, const opaque_type& rhs) { | |||
|
543 | return lhs.value <= rhs.value; | |||
|
544 | } | |||
|
545 | friend bool operator<=(const charT* lhs, const opaque_type& rhs) { | |||
|
546 | return lhs <= rhs.value; | |||
|
547 | } | |||
|
548 | friend bool operator<=(const opaque_type& lhs, const charT* rhs) { | |||
|
549 | return lhs.value <= rhs ; | |||
|
550 | } | |||
|
551 | friend bool operator>=(const opaque_type& lhs, const opaque_type& rhs) { | |||
|
552 | return lhs.value >= rhs.value; | |||
|
553 | } | |||
|
554 | friend bool operator>=(const charT* lhs, const opaque_type& rhs) { | |||
|
555 | return lhs >= rhs.value; | |||
|
556 | } | |||
|
557 | friend bool operator>=(const opaque_type& lhs, const charT* rhs) { | |||
|
558 | return lhs.value >= rhs ; | |||
|
559 | } | |||
|
560 | ||||
|
561 | friend void swap(opaque_type& lhs, opaque_type& rhs) { | |||
|
562 | using std::swap; | |||
|
563 | return swap(lhs.value, rhs.value); | |||
|
564 | } | |||
|
565 | ||||
|
566 | safer_string_typedef() = default; | |||
|
567 | safer_string_typedef(const safer_string_typedef& ) = default; | |||
|
568 | safer_string_typedef( safer_string_typedef&&) = default; | |||
|
569 | safer_string_typedef& operator=(const safer_string_typedef& ) = default; | |||
|
570 | safer_string_typedef& operator=( safer_string_typedef&&) = default; | |||
|
571 | protected: | |||
|
572 | ~safer_string_typedef() = default; | |||
|
573 | using base::downcast; | |||
|
574 | }; | |||
|
575 | ||||
|
576 | /// @} | |||
|
577 | ||||
|
578 | } | |||
|
579 | } | |||
|
580 | ||||
|
581 | #endif |
@@ -0,0 +1,144 | |||||
|
1 | #ifndef OPAQUE_EXPERIMENTAL_STRING_TYPEDEF_HPP | |||
|
2 | #define OPAQUE_EXPERIMENTAL_STRING_TYPEDEF_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "safer_string_typedef.hpp" | |||
|
32 | #include <memory> | |||
|
33 | #include <string> | |||
|
34 | ||||
|
35 | namespace opaque { | |||
|
36 | namespace experimental { | |||
|
37 | ||||
|
38 | /// \addtogroup typedefs | |||
|
39 | /// @{ | |||
|
40 | ||||
|
41 | /// | |||
|
42 | /// String opaque typedef base type | |||
|
43 | /// | |||
|
44 | /// This is an opaque typedef base class for standard strings. | |||
|
45 | /// | |||
|
46 | /// Template arguments: | |||
|
47 | /// -# S : The string type (e.g. std::string) | |||
|
48 | /// -# R : The result type, your subclass | |||
|
49 | /// | |||
|
50 | template <typename S, typename R> | |||
|
51 | struct string_typedef : safer_string_typedef<S,R> { | |||
|
52 | private: | |||
|
53 | using base = safer_string_typedef<S,R>; | |||
|
54 | public: | |||
|
55 | using typename base::underlying_type; | |||
|
56 | using typename base::opaque_type; | |||
|
57 | using base::value; | |||
|
58 | ||||
|
59 | using typename base::allocator_type; | |||
|
60 | using typename base::size_type; | |||
|
61 | using base::npos; | |||
|
62 | ||||
|
63 | private: | |||
|
64 | typedef allocator_type Allocator; | |||
|
65 | typedef typename std::allocator_traits<Allocator>::value_type charT; | |||
|
66 | public: | |||
|
67 | ||||
|
68 | using base::base; | |||
|
69 | ||||
|
70 | opaque_type& operator=(const charT* s) { | |||
|
71 | value = s; | |||
|
72 | return downcast(); | |||
|
73 | } | |||
|
74 | ||||
|
75 | opaque_type& operator+=(const charT* s) { | |||
|
76 | value += s; | |||
|
77 | return downcast(); | |||
|
78 | } | |||
|
79 | opaque_type& append(const charT* s, size_type n) { | |||
|
80 | value.append(s, n); | |||
|
81 | return downcast(); | |||
|
82 | } | |||
|
83 | opaque_type& append(const charT* s) { | |||
|
84 | value.append(s); | |||
|
85 | return downcast(); | |||
|
86 | } | |||
|
87 | ||||
|
88 | opaque_type& assign(const charT* s, size_type n) { | |||
|
89 | value.assign(s, n); | |||
|
90 | return downcast(); | |||
|
91 | } | |||
|
92 | opaque_type& assign(const charT* s) { | |||
|
93 | value.assign(s); | |||
|
94 | return downcast(); | |||
|
95 | } | |||
|
96 | ||||
|
97 | opaque_type& insert(size_type pos, const charT* s, size_type n) { | |||
|
98 | value.insert(pos, s, n); | |||
|
99 | return downcast(); | |||
|
100 | } | |||
|
101 | opaque_type& insert(size_type pos, const charT* s) { | |||
|
102 | value.insert(pos, s); | |||
|
103 | return downcast(); | |||
|
104 | } | |||
|
105 | ||||
|
106 | opaque_type& replace(size_type pos, size_type n1, const charT* s, | |||
|
107 | size_type n2) { | |||
|
108 | value.replace(pos, n1, s, n2); | |||
|
109 | return downcast(); | |||
|
110 | } | |||
|
111 | opaque_type& replace(size_type pos, size_type n1, const charT* s) { | |||
|
112 | value.replace(pos, n1, s); | |||
|
113 | return downcast(); | |||
|
114 | } | |||
|
115 | ||||
|
116 | friend opaque_type operator+(const charT* lhs, const opaque_type& rhs) { | |||
|
117 | return lhs + rhs.value ; | |||
|
118 | } | |||
|
119 | friend opaque_type operator+(const charT* lhs, opaque_type&& rhs) { | |||
|
120 | return lhs + std::move(rhs.value); | |||
|
121 | } | |||
|
122 | friend opaque_type operator+(const opaque_type& lhs, const charT* rhs) { | |||
|
123 | return lhs.value + rhs; | |||
|
124 | } | |||
|
125 | friend opaque_type operator+( opaque_type&& lhs, const charT* rhs) { | |||
|
126 | return std::move(lhs.value) + rhs; | |||
|
127 | } | |||
|
128 | ||||
|
129 | string_typedef() = default; | |||
|
130 | string_typedef(const string_typedef& ) = default; | |||
|
131 | string_typedef( string_typedef&&) = default; | |||
|
132 | string_typedef& operator=(const string_typedef& ) = default; | |||
|
133 | string_typedef& operator=( string_typedef&&) = default; | |||
|
134 | protected: | |||
|
135 | ~string_typedef() = default; | |||
|
136 | using base::downcast; | |||
|
137 | }; | |||
|
138 | ||||
|
139 | /// @} | |||
|
140 | ||||
|
141 | } | |||
|
142 | } | |||
|
143 | ||||
|
144 | #endif |
@@ -0,0 +1,56 | |||||
|
1 | #ifndef OPAQUE_HASH_HPP | |||
|
2 | #define OPAQUE_HASH_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "data.hpp" | |||
|
32 | #include <functional> | |||
|
33 | ||||
|
34 | /// \addtogroup miscellaneous | |||
|
35 | /// @{ | |||
|
36 | ||||
|
37 | /// | |||
|
38 | /// Create a std::hash specialization for an opaque typedef | |||
|
39 | /// | |||
|
40 | /// This macro must be used outside any namespace, because it creates a | |||
|
41 | /// specialization in std. | |||
|
42 | /// | |||
|
43 | #define OPAQUE_HASHABLE(name) \ | |||
|
44 | namespace std {\ | |||
|
45 | template <> struct hash<name> {\ | |||
|
46 | using argument_type = typename name::opaque_type;\ | |||
|
47 | using result_type = size_t;\ | |||
|
48 | result_type operator()(const argument_type& key) const {\ | |||
|
49 | return std::hash<typename name::underlying_type>{}(key.value);\ | |||
|
50 | }\ | |||
|
51 | };\ | |||
|
52 | } | |||
|
53 | ||||
|
54 | /// @} | |||
|
55 | ||||
|
56 | #endif |
@@ -0,0 +1,69 | |||||
|
1 | #ifndef OPAQUE_INCONVERTIBOOL_HPP | |||
|
2 | #define OPAQUE_INCONVERTIBOOL_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "numeric_typedef.hpp" | |||
|
32 | ||||
|
33 | namespace opaque { | |||
|
34 | ||||
|
35 | /// \addtogroup typedefs | |||
|
36 | /// @{ | |||
|
37 | ||||
|
38 | /// | |||
|
39 | /// Safer boolean type. May be implicitly created from a bool, but not | |||
|
40 | /// from any other type, and which is not implicitly convertible to any type. | |||
|
41 | /// | |||
|
42 | /// This is a safer substitute for built-in bool if you are concerned about | |||
|
43 | /// implicit conversions of bool to and from other types (like int) that may | |||
|
44 | /// be bugs. Inconvertibool prevents those implicit conversions. | |||
|
45 | /// | |||
|
46 | /// By request of Christoph Weiss. | |||
|
47 | /// | |||
|
48 | struct inconvertibool : opaque::numeric_typedef<bool, inconvertibool> { | |||
|
49 | using base = opaque::numeric_typedef<bool, inconvertibool>; | |||
|
50 | inconvertibool() = default; | |||
|
51 | ||||
|
52 | // Constructor is not explicit, but is hidden for types other than bool. | |||
|
53 | template <typename T, typename = typename std::enable_if< | |||
|
54 | std::is_same<bool, typename std::decay<T>::type>::value>::type> | |||
|
55 | constexpr inconvertibool(T initial) noexcept : base(initial) { } | |||
|
56 | }; | |||
|
57 | ||||
|
58 | constexpr inline bool operator==(bool b, const inconvertibool& i) noexcept { | |||
|
59 | return b == i.value; | |||
|
60 | } | |||
|
61 | constexpr inline bool operator!=(bool b, const inconvertibool& i) noexcept { | |||
|
62 | return b != i.value; | |||
|
63 | } | |||
|
64 | ||||
|
65 | /// @} | |||
|
66 | ||||
|
67 | } | |||
|
68 | ||||
|
69 | #endif |
@@ -0,0 +1,260 | |||||
|
1 | #ifndef OPAQUE_NUMERIC_TYPEDEF_HPP | |||
|
2 | #define OPAQUE_NUMERIC_TYPEDEF_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015, 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "binop/binop_inherit.hpp" | |||
|
32 | #include "data.hpp" | |||
|
33 | #include <type_traits> | |||
|
34 | #include <utility> | |||
|
35 | ||||
|
36 | namespace opaque { | |||
|
37 | ||||
|
38 | /// \addtogroup typedefs | |||
|
39 | /// @{ | |||
|
40 | ||||
|
41 | /// | |||
|
42 | /// Numeric opaque typedef base type | |||
|
43 | /// | |||
|
44 | /// Same as numeric_typedef, but without providing operator@ in terms of | |||
|
45 | /// operator@= by default. (Deriving from this rather than numeric_typedef | |||
|
46 | /// can avoid the need to remove a provided operator@ via a template | |||
|
47 | /// specialization.) | |||
|
48 | /// | |||
|
49 | /// This is a suitable base class when you want to control the interface of | |||
|
50 | /// your type, including its interoperability with itself and other types. | |||
|
51 | /// Delete operations that you do not want, and add operations that you do | |||
|
52 | /// want. | |||
|
53 | /// | |||
|
54 | /// You may define the behavior of mixed-type operator@ in your subclass by | |||
|
55 | /// inheriting from the opaque::binop::opname classes and providing the type | |||
|
56 | /// details. The list of template arguments for these classes is: | |||
|
57 | /// -# return type | |||
|
58 | /// -# commutative (bool) | |||
|
59 | /// -# type of left operand | |||
|
60 | /// -# type of right operand | |||
|
61 | /// -# type to convert left operand to | |||
|
62 | /// -# type to convert right operand to | |||
|
63 | /// | |||
|
64 | /// If you do not desire certain standard numeric operations, simply delete | |||
|
65 | /// them in your subclass. (Note that it is simpler to delete an unwanted | |||
|
66 | /// operation than to supply a missing one that is desired.) | |||
|
67 | /// | |||
|
68 | template <typename U, typename O, typename S = unsigned> | |||
|
69 | struct numeric_typedef_base : data<U,O> { | |||
|
70 | private: | |||
|
71 | using base = opaque::data<U,O>; | |||
|
72 | public: | |||
|
73 | using typename base::underlying_type; | |||
|
74 | using typename base::opaque_type; | |||
|
75 | typedef S shift_type; | |||
|
76 | using base::value; | |||
|
77 | ||||
|
78 | constexpr14 opaque_type& operator*=(const opaque_type& peer) & | |||
|
79 | noexcept(noexcept( value *= peer.value )) { | |||
|
80 | value *= peer.value; | |||
|
81 | return downcast(); } | |||
|
82 | ||||
|
83 | constexpr14 opaque_type& operator/=(const opaque_type& peer) & | |||
|
84 | noexcept(noexcept( value /= peer.value )) { | |||
|
85 | value /= peer.value; | |||
|
86 | return downcast(); } | |||
|
87 | ||||
|
88 | constexpr14 opaque_type& operator%=(const opaque_type& peer) & | |||
|
89 | noexcept(noexcept( value %= peer.value )) { | |||
|
90 | value %= peer.value; | |||
|
91 | return downcast(); } | |||
|
92 | ||||
|
93 | constexpr14 opaque_type& operator+=(const opaque_type& peer) & | |||
|
94 | noexcept(noexcept( value += peer.value )) { | |||
|
95 | value += peer.value; | |||
|
96 | return downcast(); } | |||
|
97 | ||||
|
98 | constexpr14 opaque_type& operator-=(const opaque_type& peer) & | |||
|
99 | noexcept(noexcept( value -= peer.value )) { | |||
|
100 | value -= peer.value; | |||
|
101 | return downcast(); } | |||
|
102 | ||||
|
103 | constexpr14 opaque_type& operator<<=(const shift_type& count) & | |||
|
104 | noexcept(noexcept( value <<= count )) { | |||
|
105 | value <<= count; | |||
|
106 | return downcast(); } | |||
|
107 | ||||
|
108 | constexpr14 opaque_type& operator>>=(const shift_type& count) & | |||
|
109 | noexcept(noexcept( value >>= count )) { | |||
|
110 | value >>= count; | |||
|
111 | return downcast(); } | |||
|
112 | ||||
|
113 | constexpr14 opaque_type& operator&=(const opaque_type& peer) & | |||
|
114 | noexcept(noexcept( value &= peer.value )) { | |||
|
115 | value &= peer.value; | |||
|
116 | return downcast(); } | |||
|
117 | ||||
|
118 | constexpr14 opaque_type& operator^=(const opaque_type& peer) & | |||
|
119 | noexcept(noexcept( value ^= peer.value )) { | |||
|
120 | value ^= peer.value; | |||
|
121 | return downcast(); } | |||
|
122 | ||||
|
123 | constexpr14 opaque_type& operator|=(const opaque_type& peer) & | |||
|
124 | noexcept(noexcept( value |= peer.value )) { | |||
|
125 | value |= peer.value; | |||
|
126 | return downcast(); } | |||
|
127 | ||||
|
128 | ||||
|
129 | constexpr14 opaque_type& operator++() & | |||
|
130 | noexcept(noexcept( ++value )) { | |||
|
131 | ++value; | |||
|
132 | return downcast(); } | |||
|
133 | ||||
|
134 | constexpr14 opaque_type& operator--() & | |||
|
135 | noexcept(noexcept( --value )) { | |||
|
136 | --value; | |||
|
137 | return downcast(); } | |||
|
138 | ||||
|
139 | constexpr14 opaque_type operator++(int) & noexcept(noexcept( | |||
|
140 | std::declval<numeric_typedef_base&>().operator++()) and | |||
|
141 | std::is_nothrow_constructible<opaque_type, underlying_type>::value) { | |||
|
142 | opaque_type r(value); operator++(); return r; } | |||
|
143 | ||||
|
144 | constexpr14 opaque_type operator--(int) & noexcept(noexcept( | |||
|
145 | std::declval<numeric_typedef_base&>().operator++()) and | |||
|
146 | std::is_nothrow_constructible<opaque_type, underlying_type>::value) { | |||
|
147 | opaque_type r(value); operator--(); return r; } | |||
|
148 | ||||
|
149 | ||||
|
150 | constexpr opaque_type operator+() const & | |||
|
151 | noexcept(noexcept( opaque_type(+ value ) )) { | |||
|
152 | return opaque_type(+ value ); } | |||
|
153 | ||||
|
154 | constexpr14 opaque_type operator+() && | |||
|
155 | noexcept(noexcept( opaque_type(+opaque::move(value)) )) { | |||
|
156 | return opaque_type(+opaque::move(value)); } | |||
|
157 | ||||
|
158 | constexpr opaque_type operator-() const & | |||
|
159 | noexcept(noexcept( opaque_type(- value ) )) { | |||
|
160 | return opaque_type(- value ); } | |||
|
161 | ||||
|
162 | constexpr14 opaque_type operator-() && | |||
|
163 | noexcept(noexcept( opaque_type(-opaque::move(value)) )) { | |||
|
164 | return opaque_type(-opaque::move(value)); } | |||
|
165 | ||||
|
166 | constexpr opaque_type operator~() const & | |||
|
167 | noexcept(noexcept( opaque_type(~ value ) )) { | |||
|
168 | return opaque_type(~ value ); } | |||
|
169 | ||||
|
170 | constexpr14 opaque_type operator~() && | |||
|
171 | noexcept(noexcept( opaque_type(~opaque::move(value)) )) { | |||
|
172 | return opaque_type(~opaque::move(value)); } | |||
|
173 | ||||
|
174 | constexpr bool operator!() const | |||
|
175 | noexcept(noexcept( !value )) { | |||
|
176 | return !value; } | |||
|
177 | ||||
|
178 | constexpr bool operator==(const opaque_type& peer) const | |||
|
179 | noexcept(noexcept( value == peer.value )) { | |||
|
180 | return value == peer.value; } | |||
|
181 | constexpr bool operator!=(const opaque_type& peer) const | |||
|
182 | noexcept(noexcept( value != peer.value )) { | |||
|
183 | return value != peer.value; } | |||
|
184 | constexpr bool operator< (const opaque_type& peer) const | |||
|
185 | noexcept(noexcept( value < peer.value )) { | |||
|
186 | return value < peer.value; } | |||
|
187 | constexpr bool operator> (const opaque_type& peer) const | |||
|
188 | noexcept(noexcept( value > peer.value )) { | |||
|
189 | return value > peer.value; } | |||
|
190 | constexpr bool operator<=(const opaque_type& peer) const | |||
|
191 | noexcept(noexcept( value <= peer.value )) { | |||
|
192 | return value <= peer.value; } | |||
|
193 | constexpr bool operator>=(const opaque_type& peer) const | |||
|
194 | noexcept(noexcept( value >= peer.value )) { | |||
|
195 | return value >= peer.value; } | |||
|
196 | ||||
|
197 | /// Check whether the underlying value is nonzero | |||
|
198 | explicit constexpr operator bool() const | |||
|
199 | noexcept(noexcept( static_cast<bool>(value) )) { | |||
|
200 | return static_cast<bool>(value); } | |||
|
201 | ||||
|
202 | ||||
|
203 | using base::base; | |||
|
204 | explicit numeric_typedef_base() = default; | |||
|
205 | numeric_typedef_base(const numeric_typedef_base& ) = default; | |||
|
206 | numeric_typedef_base( numeric_typedef_base&&) = default; | |||
|
207 | numeric_typedef_base& operator=(const numeric_typedef_base& ) & = default; | |||
|
208 | numeric_typedef_base& operator=( numeric_typedef_base&&) & = default; | |||
|
209 | protected: | |||
|
210 | ~numeric_typedef_base() = default; | |||
|
211 | using base::downcast; | |||
|
212 | }; | |||
|
213 | ||||
|
214 | /// | |||
|
215 | /// Numeric opaque typedef | |||
|
216 | /// | |||
|
217 | /// This is a base class providing wrappers for numeric operations on a | |||
|
218 | /// user-supplied type, which may be user-defined or built-in. The purpose of | |||
|
219 | /// this type is to easily enable the creation of several rigorously separate | |||
|
220 | /// numeric types so that they cannot be accidentally mixed in expressions, | |||
|
221 | /// implicitly converted, and also to enable overloading. | |||
|
222 | /// | |||
|
223 | /// For example, you could create separate types for coordinates in each of | |||
|
224 | /// several dimensions, and it would be a compile-time error to mix those types | |||
|
225 | /// in a single expression, even if the the same underlying type was used to | |||
|
226 | /// represent all of them. | |||
|
227 | /// | |||
|
228 | /// Template arguments for numeric_typedef: | |||
|
229 | /// -# U : The underlying type holding the value | |||
|
230 | /// -# O : The opaque type, your subclass | |||
|
231 | /// -# S : The right-hand operand type for shift operations | |||
|
232 | /// | |||
|
233 | template <typename U, typename O, typename S = unsigned> | |||
|
234 | struct numeric_typedef : numeric_typedef_base<U,O,S> | |||
|
235 | , binop::multipliable <O> | |||
|
236 | , binop::dividable <O> | |||
|
237 | , binop::modulable <O> | |||
|
238 | , binop::addable <O> | |||
|
239 | , binop::subtractable <O> | |||
|
240 | , binop::left_shiftable <O, false, O, S> | |||
|
241 | , binop::right_shiftable<O, false, O, S> | |||
|
242 | , binop::bitandable <O> | |||
|
243 | , binop::bitxorable <O> | |||
|
244 | , binop::bitorable <O> | |||
|
245 | { | |||
|
246 | using numeric_typedef_base<U,O,S>::numeric_typedef_base; | |||
|
247 | explicit numeric_typedef() = default; | |||
|
248 | numeric_typedef(const numeric_typedef& ) = default; | |||
|
249 | numeric_typedef( numeric_typedef&&) = default; | |||
|
250 | numeric_typedef& operator=(const numeric_typedef& ) & = default; | |||
|
251 | numeric_typedef& operator=( numeric_typedef&&) & = default; | |||
|
252 | protected: | |||
|
253 | ~numeric_typedef() = default; | |||
|
254 | }; | |||
|
255 | ||||
|
256 | /// @} | |||
|
257 | ||||
|
258 | } | |||
|
259 | ||||
|
260 | #endif |
@@ -0,0 +1,74 | |||||
|
1 | #ifndef OPAQUE_HPP | |||
|
2 | #define OPAQUE_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | ||||
|
32 | /// | |||
|
33 | /// Opaque Typedefs | |||
|
34 | /// | |||
|
35 | /// Types intended for wrapping other types, used instead of simple type | |||
|
36 | /// aliases. | |||
|
37 | /// | |||
|
38 | namespace opaque { | |||
|
39 | ||||
|
40 | /// | |||
|
41 | /// Binary Operators | |||
|
42 | /// | |||
|
43 | /// Machinery enabling inheritance of configurable operator@ based on | |||
|
44 | /// operator@=. | |||
|
45 | /// | |||
|
46 | namespace binop { } | |||
|
47 | ||||
|
48 | /// | |||
|
49 | /// Experimental Opaque Typedefs | |||
|
50 | /// | |||
|
51 | /// Opaque typedefs that may be useful but have not been used enough to | |||
|
52 | /// have confidence that their definition and interface is correct. | |||
|
53 | /// | |||
|
54 | namespace experimental { } | |||
|
55 | ||||
|
56 | } | |||
|
57 | ||||
|
58 | /// | |||
|
59 | /// \defgroup internal Internal implementation details | |||
|
60 | /// | |||
|
61 | /// Internal implementation details not intended to be directly reused. | |||
|
62 | /// | |||
|
63 | ||||
|
64 | /// | |||
|
65 | /// \defgroup miscellaneous Miscellaneous Utilities | |||
|
66 | /// | |||
|
67 | /// Internal implementation details that may be useful to reuse directly. | |||
|
68 | /// | |||
|
69 | ||||
|
70 | /// | |||
|
71 | /// \defgroup typedefs Opaque typedefs | |||
|
72 | /// | |||
|
73 | ||||
|
74 | #endif |
@@ -0,0 +1,51 | |||||
|
1 | #ifndef OPAQUE_OSTREAM_HPP | |||
|
2 | #define OPAQUE_OSTREAM_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include "data.hpp" | |||
|
32 | #include <ostream> | |||
|
33 | ||||
|
34 | namespace opaque { | |||
|
35 | ||||
|
36 | /// \addtogroup miscellaneous | |||
|
37 | /// @{ | |||
|
38 | ||||
|
39 | /// | |||
|
40 | /// std::ostream compatibility for all opaque typedefs | |||
|
41 | /// | |||
|
42 | template <typename... TP> | |||
|
43 | std::ostream& operator<<(std::ostream& stream, const opaque::data<TP...>& d) { | |||
|
44 | return stream << d.value; | |||
|
45 | } | |||
|
46 | ||||
|
47 | /// @} | |||
|
48 | ||||
|
49 | } | |||
|
50 | ||||
|
51 | #endif |
@@ -0,0 +1,94 | |||||
|
1 | #ifndef OPAQUE_TYPE_TRAITS_HPP | |||
|
2 | #define OPAQUE_TYPE_TRAITS_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2015 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include <type_traits> | |||
|
32 | ||||
|
33 | namespace opaque { | |||
|
34 | ||||
|
35 | /// \addtogroup internal | |||
|
36 | /// @{ | |||
|
37 | ||||
|
38 | #ifdef __cpp_lib_void_t | |||
|
39 | using std::void_t; | |||
|
40 | #else | |||
|
41 | // CWG 1558 | |||
|
42 | template <typename...> struct voider { using type = void; }; | |||
|
43 | template <typename... T> using void_t = typename voider<T...>::type; | |||
|
44 | #endif | |||
|
45 | ||||
|
46 | namespace detail { | |||
|
47 | ||||
|
48 | template <typename F, typename... Args> | |||
|
49 | using functor_result_t = decltype(std::declval<F>()(std::declval<Args>()...)); | |||
|
50 | ||||
|
51 | template <typename F, typename = void, typename... Args> | |||
|
52 | struct functor_well_formed : std::false_type { }; | |||
|
53 | ||||
|
54 | template <typename F, typename... Args> | |||
|
55 | struct functor_well_formed<F, void_t<functor_result_t<F,Args...>>, Args...> | |||
|
56 | : std::true_type { | |||
|
57 | using result_type = functor_result_t<F,Args...>; | |||
|
58 | }; | |||
|
59 | ||||
|
60 | } | |||
|
61 | ||||
|
62 | template <typename F, typename... Args> | |||
|
63 | using is_functor_call_well_formed | |||
|
64 | = detail::functor_well_formed<F, void, Args...>; | |||
|
65 | ||||
|
66 | /// | |||
|
67 | /// Determine whether a type is decayed | |||
|
68 | /// | |||
|
69 | template <typename T> | |||
|
70 | struct is_decayed : std::conditional< | |||
|
71 | std::is_same<T, typename std::decay<T>::type>::value, | |||
|
72 | std::true_type, std::false_type>::type { }; | |||
|
73 | ||||
|
74 | /// | |||
|
75 | /// Determine whether two types are related by inheritance | |||
|
76 | /// | |||
|
77 | template <typename T, typename U> | |||
|
78 | struct is_related : std::conditional< | |||
|
79 | std::is_base_of<T,U>::value or std::is_base_of<U,T>::value, | |||
|
80 | std::true_type, std::false_type>::type { }; | |||
|
81 | ||||
|
82 | /// | |||
|
83 | /// Determine whether casting to T from U is free, or creates a new object | |||
|
84 | /// | |||
|
85 | template <typename T, typename U> | |||
|
86 | struct is_cast_free : std::conditional< | |||
|
87 | std::is_same<T,U>::value or is_related<T,U>::value, | |||
|
88 | std::true_type, std::false_type>::type { }; | |||
|
89 | ||||
|
90 | /// @} | |||
|
91 | ||||
|
92 | } | |||
|
93 | ||||
|
94 | #endif |
@@ -0,0 +1,62 | |||||
|
1 | #ifndef OPAQUE_UTILITY_HPP | |||
|
2 | #define OPAQUE_UTILITY_HPP | |||
|
3 | // | |||
|
4 | // Copyright (c) 2016 | |||
|
5 | // Kyle Markley. All rights reserved. | |||
|
6 | // | |||
|
7 | // Redistribution and use in source and binary forms, with or without | |||
|
8 | // modification, are permitted provided that the following conditions are met: | |||
|
9 | // | |||
|
10 | // 1. Redistributions of source code must retain the above copyright notice, | |||
|
11 | // this list of conditions and the following disclaimer. | |||
|
12 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |||
|
13 | // this list of conditions and the following disclaimer in the documentation | |||
|
14 | // and/or other materials provided with the distribution. | |||
|
15 | // 3. Neither the name of the author nor the names of any contributors may be | |||
|
16 | // used to endorse or promote products derived from this software without | |||
|
17 | // specific prior written permission. | |||
|
18 | // | |||
|
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
|
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
|
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
|
22 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |||
|
23 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
|
24 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
|
25 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
|
26 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
|
27 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
|
28 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
|
29 | // POSSIBILITY OF SUCH DAMAGE. | |||
|
30 | // | |||
|
31 | #include <type_traits> | |||
|
32 | #include <utility> | |||
|
33 | ||||
|
34 | namespace opaque { | |||
|
35 | ||||
|
36 | /// \addtogroup internal | |||
|
37 | /// @{ | |||
|
38 | ||||
|
39 | #if __cplusplus >= 201402L | |||
|
40 | using std::forward; | |||
|
41 | using std::move; | |||
|
42 | #else | |||
|
43 | template <typename T> | |||
|
44 | constexpr T&& forward(typename std::remove_reference<T>::type& t) noexcept { | |||
|
45 | return static_cast<T&&>(t); | |||
|
46 | } | |||
|
47 | template <typename T> | |||
|
48 | constexpr T&& forward(typename std::remove_reference<T>::type&& t) noexcept { | |||
|
49 | static_assert(not std::is_lvalue_reference<T>::value, "lvalue reference"); | |||
|
50 | return static_cast<T&&>(t); | |||
|
51 | } | |||
|
52 | template <typename T> | |||
|
53 | constexpr typename std::remove_reference<T>::type&& move(T&& t) noexcept { | |||
|
54 | return static_cast<typename std::remove_reference<T>::type&&>(t); | |||
|
55 | } | |||
|
56 | #endif | |||
|
57 | ||||
|
58 | /// @} | |||
|
59 | ||||
|
60 | } | |||
|
61 | ||||
|
62 | #endif |
@@ -1,68 +1,159 | |||||
1 | #ifndef SCIQLOP_SQPRANGE_H |
|
1 | #ifndef SCIQLOP_SQPRANGE_H | |
2 | #define SCIQLOP_SQPRANGE_H |
|
2 | #define SCIQLOP_SQPRANGE_H | |
3 |
|
3 | |||
4 | #include <QObject> |
|
4 | #include <QObject> | |
5 |
|
5 | |||
6 | #include <QDebug> |
|
6 | #include <QDebug> | |
7 |
|
7 | |||
8 | #include <Common/DateUtils.h> |
|
8 | #include <Common/DateUtils.h> | |
9 | #include <Common/MetaTypes.h> |
|
9 | #include <Common/MetaTypes.h> | |
|
10 | #include <opaque/numeric_typedef.hpp> | |||
10 |
|
11 | |||
11 | #include <cmath> |
|
12 | #include <cmath> | |
12 |
|
13 | |||
|
14 | ||||
|
15 | template <typename T> | |||
|
16 | struct Seconds : opaque::numeric_typedef<T, Seconds<T>> , | |||
|
17 | opaque::binop::multipliable <Seconds<T>, true , Seconds<T>, T, T>, | |||
|
18 | opaque::binop::dividable <Seconds<T>, true , Seconds<T>, T, T>, | |||
|
19 | opaque::binop::addable <Seconds<T>, true , Seconds<T>, T, T>, | |||
|
20 | opaque::binop::subtractable <Seconds<T>, true , Seconds<T>, T, T> | |||
|
21 | ||||
|
22 | { | |||
|
23 | using base = opaque::numeric_typedef<T, Seconds<T>>; | |||
|
24 | using base::base; | |||
|
25 | }; | |||
|
26 | ||||
13 | /** |
|
27 | /** | |
14 | * @brief The SqpRange struct holds the information of time parameters |
|
28 | * @brief The SqpRange struct holds the information of time parameters | |
15 | */ |
|
29 | */ | |
16 | struct DateTimeRange { |
|
30 | struct DateTimeRange { | |
17 | /// Creates SqpRange from dates and times |
|
31 | /// Creates SqpRange from dates and times | |
18 | static DateTimeRange fromDateTime(const QDate &startDate, const QTime &startTime, |
|
32 | static DateTimeRange fromDateTime(const QDate &startDate, const QTime &startTime, | |
19 | const QDate &endDate, const QTime &endTime) |
|
33 | const QDate &endDate, const QTime &endTime) | |
20 | { |
|
34 | { | |
21 | return {DateUtils::secondsSinceEpoch(QDateTime{startDate, startTime, Qt::UTC}), |
|
35 | return {DateUtils::secondsSinceEpoch(QDateTime{startDate, startTime, Qt::UTC}), | |
22 | DateUtils::secondsSinceEpoch(QDateTime{endDate, endTime, Qt::UTC})}; |
|
36 | DateUtils::secondsSinceEpoch(QDateTime{endDate, endTime, Qt::UTC})}; | |
23 | } |
|
37 | } | |
24 |
|
38 | |||
25 | /// Start time (UTC) |
|
39 | /// Start time (UTC) | |
26 | double m_TStart; |
|
40 | double m_TStart; | |
27 | /// End time (UTC) |
|
41 | /// End time (UTC) | |
28 | double m_TEnd; |
|
42 | double m_TEnd; | |
29 |
|
43 | |||
30 | double delta()const {return this->m_TEnd - this->m_TStart;} |
|
44 | Seconds<double> delta()const {return Seconds<double>{this->m_TEnd - this->m_TStart};} | |
31 |
|
45 | |||
32 | bool contains(const DateTimeRange &dateTime) const noexcept |
|
46 | bool contains(const DateTimeRange &dateTime) const noexcept | |
33 | { |
|
47 | { | |
34 | return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd); |
|
48 | return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd); | |
35 | } |
|
49 | } | |
36 |
|
50 | |||
37 | bool intersect(const DateTimeRange &dateTime) const noexcept |
|
51 | bool intersect(const DateTimeRange &dateTime) const noexcept | |
38 | { |
|
52 | { | |
39 | return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); |
|
53 | return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd); | |
40 | } |
|
54 | } | |
41 |
|
55 | |||
42 | bool operator==(const DateTimeRange &other) const |
|
56 | bool operator==(const DateTimeRange &other) const | |
43 | { |
|
57 | { | |
44 | auto equals = [](const auto &v1, const auto &v2) { |
|
58 | auto equals = [](const auto &v1, const auto &v2) { | |
45 | return (std::isnan(v1) && std::isnan(v2)) || v1 == v2; |
|
59 | return (std::isnan(v1) && std::isnan(v2)) || v1 == v2; | |
46 | }; |
|
60 | }; | |
47 |
|
61 | |||
48 | return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd); |
|
62 | return equals(m_TStart, other.m_TStart) && equals(m_TEnd, other.m_TEnd); | |
49 | } |
|
63 | } | |
50 | bool operator!=(const DateTimeRange &other) const { return !(*this == other); } |
|
64 | bool operator!=(const DateTimeRange &other) const { return !(*this == other); } | |
|
65 | ||||
|
66 | void grow(double factor) | |||
|
67 | { | |||
|
68 | double grow_v{delta()*(factor - 1.)/2.}; | |||
|
69 | m_TStart -= grow_v; | |||
|
70 | m_TEnd += grow_v; | |||
|
71 | } | |||
|
72 | ||||
|
73 | void shrink(double factor) | |||
|
74 | { | |||
|
75 | double shrink_v{this->delta()*(1. - factor)/2.}; | |||
|
76 | m_TStart += shrink_v; | |||
|
77 | m_TEnd -= shrink_v; | |||
|
78 | } | |||
|
79 | ||||
|
80 | DateTimeRange& operator*=(double k) | |||
|
81 | { | |||
|
82 | this->grow(k); | |||
|
83 | return *this; | |||
|
84 | } | |||
|
85 | ||||
|
86 | DateTimeRange& operator/=(double k) | |||
|
87 | { | |||
|
88 | this->shrink(k); | |||
|
89 | return *this; | |||
|
90 | } | |||
|
91 | ||||
51 | }; |
|
92 | }; | |
52 |
|
93 | |||
|
94 | template <class T> | |||
|
95 | DateTimeRange& operator+=(DateTimeRange&r, Seconds<T> offset) | |||
|
96 | { | |||
|
97 | shift(r,offset); | |||
|
98 | return r; | |||
|
99 | } | |||
|
100 | ||||
|
101 | template <class T> | |||
|
102 | DateTimeRange& operator-=(DateTimeRange&r, Seconds<T> offset) | |||
|
103 | { | |||
|
104 | shift(r,-offset); | |||
|
105 | } | |||
|
106 | ||||
|
107 | template <class T> | |||
|
108 | void shift(DateTimeRange& r, Seconds<T> offset) | |||
|
109 | { | |||
|
110 | r.m_TEnd+=static_cast<double>(offset); | |||
|
111 | r.m_TStart+=static_cast<double>(offset); | |||
|
112 | } | |||
|
113 | ||||
|
114 | inline DateTimeRange operator*(const DateTimeRange& r, double k) | |||
|
115 | { | |||
|
116 | DateTimeRange result{r}; | |||
|
117 | result.grow(k); | |||
|
118 | return result; | |||
|
119 | } | |||
|
120 | ||||
|
121 | inline DateTimeRange operator/(const DateTimeRange& r, double k) | |||
|
122 | { | |||
|
123 | DateTimeRange result{r}; | |||
|
124 | result.shrink(k); | |||
|
125 | return result; | |||
|
126 | } | |||
|
127 | ||||
|
128 | template<class T> | |||
|
129 | DateTimeRange operator+(const DateTimeRange& r, Seconds<T> offset) | |||
|
130 | { | |||
|
131 | DateTimeRange result{r}; | |||
|
132 | shift(result,offset); | |||
|
133 | return result; | |||
|
134 | } | |||
|
135 | ||||
|
136 | template<class T> | |||
|
137 | DateTimeRange operator-(const DateTimeRange& r, Seconds<T> offset) | |||
|
138 | { | |||
|
139 | DateTimeRange result{r}; | |||
|
140 | shift(result,-offset); | |||
|
141 | return result; | |||
|
142 | } | |||
|
143 | ||||
53 | const auto INVALID_RANGE |
|
144 | const auto INVALID_RANGE | |
54 | = DateTimeRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()}; |
|
145 | = DateTimeRange{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()}; | |
55 |
|
146 | |||
56 | inline QDebug operator<<(QDebug d, DateTimeRange obj) |
|
147 | inline QDebug operator<<(QDebug d, DateTimeRange obj) | |
57 | { |
|
148 | { | |
58 | auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart); |
|
149 | auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart); | |
59 | auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd); |
|
150 | auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd); | |
60 |
|
151 | |||
61 | d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd; |
|
152 | d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd; | |
62 | return d; |
|
153 | return d; | |
63 | } |
|
154 | } | |
64 |
|
155 | |||
65 | // Required for using shared_ptr in signals/slots |
|
156 | // Required for using shared_ptr in signals/slots | |
66 | SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, DateTimeRange) |
|
157 | SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, DateTimeRange) | |
67 |
|
158 | |||
68 | #endif // SCIQLOP_SQPRANGE_H |
|
159 | #endif // SCIQLOP_SQPRANGE_H |
@@ -1,1103 +1,1103 | |||||
1 | #include <Variable/Variable.h> |
|
1 | #include <Variable/Variable.h> | |
2 | #include <Variable/VariableAcquisitionWorker.h> |
|
2 | #include <Variable/VariableAcquisitionWorker.h> | |
3 | #include <Variable/VariableCacheStrategy.h> |
|
3 | #include <Variable/VariableCacheStrategy.h> | |
4 | #include <Variable/VariableCacheStrategyFactory.h> |
|
4 | #include <Variable/VariableCacheStrategyFactory.h> | |
5 | #include <Variable/VariableController.h> |
|
5 | #include <Variable/VariableController.h> | |
6 | #include <Variable/VariableModel.h> |
|
6 | #include <Variable/VariableModel.h> | |
7 | #include <Variable/VariableSynchronizationGroup.h> |
|
7 | #include <Variable/VariableSynchronizationGroup.h> | |
8 |
|
8 | |||
9 | #include <Data/DataProviderParameters.h> |
|
9 | #include <Data/DataProviderParameters.h> | |
10 | #include <Data/IDataProvider.h> |
|
10 | #include <Data/IDataProvider.h> | |
11 | #include <Data/IDataSeries.h> |
|
11 | #include <Data/IDataSeries.h> | |
12 | #include <Data/VariableRequest.h> |
|
12 | #include <Data/VariableRequest.h> | |
13 | #include <Time/TimeController.h> |
|
13 | #include <Time/TimeController.h> | |
14 |
|
14 | |||
15 | #include <Common/Numeric.h> |
|
15 | #include <Common/Numeric.h> | |
16 |
|
16 | |||
17 | #include <QDataStream> |
|
17 | #include <QDataStream> | |
18 | #include <QMutex> |
|
18 | #include <QMutex> | |
19 | #include <QThread> |
|
19 | #include <QThread> | |
20 | #include <QUuid> |
|
20 | #include <QUuid> | |
21 | #include <QtCore/QItemSelectionModel> |
|
21 | #include <QtCore/QItemSelectionModel> | |
22 |
|
22 | |||
23 | #include <deque> |
|
23 | #include <deque> | |
24 | #include <set> |
|
24 | #include <set> | |
25 | #include <unordered_map> |
|
25 | #include <unordered_map> | |
26 |
|
26 | |||
27 | Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController") |
|
27 | Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController") | |
28 |
|
28 | |||
29 | namespace { |
|
29 | namespace { | |
30 |
|
30 | |||
31 | DateTimeRange computeSynchroRangeRequested(const DateTimeRange &varRange, const DateTimeRange &graphRange, |
|
31 | DateTimeRange computeSynchroRangeRequested(const DateTimeRange &varRange, const DateTimeRange &graphRange, | |
32 | const DateTimeRange &oldGraphRange) |
|
32 | const DateTimeRange &oldGraphRange) | |
33 | { |
|
33 | { | |
34 | auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange); |
|
34 | auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange); | |
35 |
|
35 | |||
36 | auto varRangeRequested = varRange; |
|
36 | auto varRangeRequested = varRange; | |
37 | switch (zoomType) { |
|
37 | switch (zoomType) { | |
38 | case AcquisitionZoomType::ZoomIn: { |
|
38 | case AcquisitionZoomType::ZoomIn: { | |
39 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; |
|
39 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; | |
40 | auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; |
|
40 | auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; | |
41 | varRangeRequested.m_TStart += deltaLeft; |
|
41 | varRangeRequested.m_TStart += deltaLeft; | |
42 | varRangeRequested.m_TEnd -= deltaRight; |
|
42 | varRangeRequested.m_TEnd -= deltaRight; | |
43 | break; |
|
43 | break; | |
44 | } |
|
44 | } | |
45 |
|
45 | |||
46 | case AcquisitionZoomType::ZoomOut: { |
|
46 | case AcquisitionZoomType::ZoomOut: { | |
47 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; |
|
47 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; | |
48 | auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; |
|
48 | auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; | |
49 | varRangeRequested.m_TStart -= deltaLeft; |
|
49 | varRangeRequested.m_TStart -= deltaLeft; | |
50 | varRangeRequested.m_TEnd += deltaRight; |
|
50 | varRangeRequested.m_TEnd += deltaRight; | |
51 | break; |
|
51 | break; | |
52 | } |
|
52 | } | |
53 | case AcquisitionZoomType::PanRight: { |
|
53 | case AcquisitionZoomType::PanRight: { | |
54 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; |
|
54 | auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart; | |
55 | auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; |
|
55 | auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd; | |
56 | varRangeRequested.m_TStart += deltaLeft; |
|
56 | varRangeRequested.m_TStart += deltaLeft; | |
57 | varRangeRequested.m_TEnd += deltaRight; |
|
57 | varRangeRequested.m_TEnd += deltaRight; | |
58 | break; |
|
58 | break; | |
59 | } |
|
59 | } | |
60 | case AcquisitionZoomType::PanLeft: { |
|
60 | case AcquisitionZoomType::PanLeft: { | |
61 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; |
|
61 | auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart; | |
62 | auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; |
|
62 | auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd; | |
63 | varRangeRequested.m_TStart -= deltaLeft; |
|
63 | varRangeRequested.m_TStart -= deltaLeft; | |
64 | varRangeRequested.m_TEnd -= deltaRight; |
|
64 | varRangeRequested.m_TEnd -= deltaRight; | |
65 | break; |
|
65 | break; | |
66 | } |
|
66 | } | |
67 | case AcquisitionZoomType::Unknown: { |
|
67 | case AcquisitionZoomType::Unknown: { | |
68 | qCCritical(LOG_VariableController()) |
|
68 | qCCritical(LOG_VariableController()) | |
69 | << VariableController::tr("Impossible to synchronize: zoom type unknown"); |
|
69 | << VariableController::tr("Impossible to synchronize: zoom type unknown"); | |
70 | break; |
|
70 | break; | |
71 | } |
|
71 | } | |
72 | default: |
|
72 | default: | |
73 | qCCritical(LOG_VariableController()) << VariableController::tr( |
|
73 | qCCritical(LOG_VariableController()) << VariableController::tr( | |
74 | "Impossible to synchronize: zoom type not take into account"); |
|
74 | "Impossible to synchronize: zoom type not take into account"); | |
75 | // No action |
|
75 | // No action | |
76 | break; |
|
76 | break; | |
77 | } |
|
77 | } | |
78 |
|
78 | |||
79 | return varRangeRequested; |
|
79 | return varRangeRequested; | |
80 | } |
|
80 | } | |
81 | } |
|
81 | } | |
82 |
|
82 | |||
83 | enum class VariableRequestHandlerState { OFF, RUNNING, PENDING }; |
|
83 | enum class VariableRequestHandlerState { OFF, RUNNING, PENDING }; | |
84 |
|
84 | |||
85 | struct VariableRequestHandler { |
|
85 | struct VariableRequestHandler { | |
86 |
|
86 | |||
87 | VariableRequestHandler() |
|
87 | VariableRequestHandler() | |
88 | { |
|
88 | { | |
89 | m_CanUpdate = false; |
|
89 | m_CanUpdate = false; | |
90 | m_State = VariableRequestHandlerState::OFF; |
|
90 | m_State = VariableRequestHandlerState::OFF; | |
91 | } |
|
91 | } | |
92 |
|
92 | |||
93 | QUuid m_VarId; |
|
93 | QUuid m_VarId; | |
94 | VariableRequest m_RunningVarRequest; |
|
94 | VariableRequest m_RunningVarRequest; | |
95 | VariableRequest m_PendingVarRequest; |
|
95 | VariableRequest m_PendingVarRequest; | |
96 | VariableRequestHandlerState m_State; |
|
96 | VariableRequestHandlerState m_State; | |
97 | bool m_CanUpdate; |
|
97 | bool m_CanUpdate; | |
98 | }; |
|
98 | }; | |
99 |
|
99 | |||
100 | struct VariableController::VariableControllerPrivate { |
|
100 | struct VariableController::VariableControllerPrivate { | |
101 | explicit VariableControllerPrivate(VariableController *parent) |
|
101 | explicit VariableControllerPrivate(VariableController *parent) | |
102 | : m_WorkingMutex{}, |
|
102 | : m_WorkingMutex{}, | |
103 | m_VariableModel{new VariableModel{parent}}, |
|
103 | m_VariableModel{new VariableModel{parent}}, | |
104 | m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}}, |
|
104 | m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}}, | |
105 | // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()}, |
|
105 | // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()}, | |
106 | m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy( |
|
106 | m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy( | |
107 | CacheStrategy::SingleThreshold)}, |
|
107 | CacheStrategy::SingleThreshold)}, | |
108 | m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}, |
|
108 | m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}, | |
109 | q{parent} |
|
109 | q{parent} | |
110 | { |
|
110 | { | |
111 |
|
111 | |||
112 | m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread); |
|
112 | m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread); | |
113 | m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread"); |
|
113 | m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread"); | |
114 | } |
|
114 | } | |
115 |
|
115 | |||
116 |
|
116 | |||
117 | virtual ~VariableControllerPrivate() |
|
117 | virtual ~VariableControllerPrivate() | |
118 | { |
|
118 | { | |
119 | qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction"); |
|
119 | qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction"); | |
120 | m_VariableAcquisitionWorkerThread.quit(); |
|
120 | m_VariableAcquisitionWorkerThread.quit(); | |
121 | m_VariableAcquisitionWorkerThread.wait(); |
|
121 | m_VariableAcquisitionWorkerThread.wait(); | |
122 | } |
|
122 | } | |
123 |
|
123 | |||
124 |
|
124 | |||
125 | void processRequest(std::shared_ptr<Variable> var, const DateTimeRange &rangeRequested, |
|
125 | void processRequest(std::shared_ptr<Variable> var, const DateTimeRange &rangeRequested, | |
126 | QUuid varRequestId); |
|
126 | QUuid varRequestId); | |
127 |
|
127 | |||
128 | std::shared_ptr<Variable> findVariable(QUuid vIdentifier); |
|
128 | std::shared_ptr<Variable> findVariable(QUuid vIdentifier); | |
129 | std::shared_ptr<IDataSeries> |
|
129 | std::shared_ptr<IDataSeries> | |
130 | retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector); |
|
130 | retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector); | |
131 |
|
131 | |||
132 | void registerProvider(std::shared_ptr<IDataProvider> provider); |
|
132 | void registerProvider(std::shared_ptr<IDataProvider> provider); | |
133 |
|
133 | |||
134 | void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest); |
|
134 | void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest); | |
135 | QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries); |
|
135 | QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries); | |
136 | void updateVariables(QUuid varRequestId); |
|
136 | void updateVariables(QUuid varRequestId); | |
137 | void updateVariableRequest(QUuid varRequestId); |
|
137 | void updateVariableRequest(QUuid varRequestId); | |
138 | void cancelVariableRequest(QUuid varRequestId); |
|
138 | void cancelVariableRequest(QUuid varRequestId); | |
139 | void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest); |
|
139 | void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest); | |
140 | bool hasPendingDownloads(); |
|
140 | bool hasPendingDownloads(); | |
141 | template <typename VariableIterator> |
|
141 | template <typename VariableIterator> | |
142 | void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId); |
|
142 | void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId); | |
143 |
|
143 | |||
144 | QMutex m_WorkingMutex; |
|
144 | QMutex m_WorkingMutex; | |
145 | /// Variable model. The VariableController has the ownership |
|
145 | /// Variable model. The VariableController has the ownership | |
146 | VariableModel *m_VariableModel; |
|
146 | VariableModel *m_VariableModel; | |
147 | QItemSelectionModel *m_VariableSelectionModel; |
|
147 | QItemSelectionModel *m_VariableSelectionModel; | |
148 |
|
148 | |||
149 |
|
149 | |||
150 | std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy; |
|
150 | std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy; | |
151 | std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker; |
|
151 | std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker; | |
152 | QThread m_VariableAcquisitionWorkerThread; |
|
152 | QThread m_VariableAcquisitionWorkerThread; | |
153 |
|
153 | |||
154 | std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> > |
|
154 | std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> > | |
155 | m_VariableToProviderMap; |
|
155 | m_VariableToProviderMap; | |
156 | std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap; |
|
156 | std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap; | |
157 | std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> > |
|
157 | std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> > | |
158 | m_GroupIdToVariableSynchronizationGroupMap; |
|
158 | m_GroupIdToVariableSynchronizationGroupMap; | |
159 | std::map<QUuid, QUuid> m_VariableIdGroupIdMap; |
|
159 | std::map<QUuid, QUuid> m_VariableIdGroupIdMap; | |
160 | std::set<std::shared_ptr<IDataProvider> > m_ProviderSet; |
|
160 | std::set<std::shared_ptr<IDataProvider> > m_ProviderSet; | |
161 |
|
161 | |||
162 | std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds; |
|
162 | std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds; | |
163 | std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler; |
|
163 | std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler; | |
164 |
|
164 | |||
165 | VariableController *q; |
|
165 | VariableController *q; | |
166 | }; |
|
166 | }; | |
167 |
|
167 | |||
168 |
|
168 | |||
169 | VariableController::VariableController(QObject *parent) |
|
169 | VariableController::VariableController(QObject *parent) | |
170 | : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)} |
|
170 | : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)} | |
171 | { |
|
171 | { | |
172 | qCDebug(LOG_VariableController()) << tr("VariableController construction") |
|
172 | qCDebug(LOG_VariableController()) << tr("VariableController construction") | |
173 | << QThread::currentThread(); |
|
173 | << QThread::currentThread(); | |
174 |
|
174 | |||
175 | connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this, |
|
175 | connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this, | |
176 | &VariableController::onAbortProgressRequested); |
|
176 | &VariableController::onAbortProgressRequested); | |
177 |
|
177 | |||
178 | connect(impl->m_VariableAcquisitionWorker.get(), |
|
178 | connect(impl->m_VariableAcquisitionWorker.get(), | |
179 | &VariableAcquisitionWorker::variableCanceledRequested, this, |
|
179 | &VariableAcquisitionWorker::variableCanceledRequested, this, | |
180 | &VariableController::onAbortAcquisitionRequested); |
|
180 | &VariableController::onAbortAcquisitionRequested); | |
181 |
|
181 | |||
182 | connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this, |
|
182 | connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this, | |
183 | &VariableController::onDataProvided); |
|
183 | &VariableController::onDataProvided); | |
184 | connect(impl->m_VariableAcquisitionWorker.get(), |
|
184 | connect(impl->m_VariableAcquisitionWorker.get(), | |
185 | &VariableAcquisitionWorker::variableRequestInProgress, this, |
|
185 | &VariableAcquisitionWorker::variableRequestInProgress, this, | |
186 | &VariableController::onVariableRetrieveDataInProgress); |
|
186 | &VariableController::onVariableRetrieveDataInProgress); | |
187 |
|
187 | |||
188 |
|
188 | |||
189 | connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started, |
|
189 | connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started, | |
190 | impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize); |
|
190 | impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize); | |
191 | connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished, |
|
191 | connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished, | |
192 | impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize); |
|
192 | impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize); | |
193 |
|
193 | |||
194 | connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this, |
|
194 | connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this, | |
195 | &VariableController::onUpdateDateTime); |
|
195 | &VariableController::onUpdateDateTime); | |
196 |
|
196 | |||
197 | impl->m_VariableAcquisitionWorkerThread.start(); |
|
197 | impl->m_VariableAcquisitionWorkerThread.start(); | |
198 | } |
|
198 | } | |
199 |
|
199 | |||
200 | VariableController::~VariableController() |
|
200 | VariableController::~VariableController() | |
201 | { |
|
201 | { | |
202 | qCDebug(LOG_VariableController()) << tr("VariableController destruction") |
|
202 | qCDebug(LOG_VariableController()) << tr("VariableController destruction") | |
203 | << QThread::currentThread(); |
|
203 | << QThread::currentThread(); | |
204 | this->waitForFinish(); |
|
204 | this->waitForFinish(); | |
205 | } |
|
205 | } | |
206 |
|
206 | |||
207 | VariableModel *VariableController::variableModel() noexcept |
|
207 | VariableModel *VariableController::variableModel() noexcept | |
208 | { |
|
208 | { | |
209 | return impl->m_VariableModel; |
|
209 | return impl->m_VariableModel; | |
210 | } |
|
210 | } | |
211 |
|
211 | |||
212 | QItemSelectionModel *VariableController::variableSelectionModel() noexcept |
|
212 | QItemSelectionModel *VariableController::variableSelectionModel() noexcept | |
213 | { |
|
213 | { | |
214 | return impl->m_VariableSelectionModel; |
|
214 | return impl->m_VariableSelectionModel; | |
215 | } |
|
215 | } | |
216 |
|
216 | |||
217 | std::shared_ptr<Variable> |
|
217 | std::shared_ptr<Variable> | |
218 | VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept |
|
218 | VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept | |
219 | { |
|
219 | { | |
220 | if (impl->m_VariableModel->containsVariable(variable)) { |
|
220 | if (impl->m_VariableModel->containsVariable(variable)) { | |
221 | // Clones variable |
|
221 | // Clones variable | |
222 | auto duplicate = variable->clone(); |
|
222 | auto duplicate = variable->clone(); | |
223 |
|
223 | |||
224 | // Adds clone to model |
|
224 | // Adds clone to model | |
225 | impl->m_VariableModel->addVariable(duplicate); |
|
225 | impl->m_VariableModel->addVariable(duplicate); | |
226 |
|
226 | |||
227 | // Generates clone identifier |
|
227 | // Generates clone identifier | |
228 | impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid(); |
|
228 | impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid(); | |
229 |
|
229 | |||
230 | // Registers provider |
|
230 | // Registers provider | |
231 | auto variableProvider = impl->m_VariableToProviderMap.at(variable); |
|
231 | auto variableProvider = impl->m_VariableToProviderMap.at(variable); | |
232 | auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr; |
|
232 | auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr; | |
233 |
|
233 | |||
234 | impl->m_VariableToProviderMap[duplicate] = duplicateProvider; |
|
234 | impl->m_VariableToProviderMap[duplicate] = duplicateProvider; | |
235 | if (duplicateProvider) { |
|
235 | if (duplicateProvider) { | |
236 | impl->registerProvider(duplicateProvider); |
|
236 | impl->registerProvider(duplicateProvider); | |
237 | } |
|
237 | } | |
238 |
|
238 | |||
239 | return duplicate; |
|
239 | return duplicate; | |
240 | } |
|
240 | } | |
241 | else { |
|
241 | else { | |
242 | qCCritical(LOG_VariableController()) |
|
242 | qCCritical(LOG_VariableController()) | |
243 | << tr("Can't create duplicate of variable %1: variable not registered in the model") |
|
243 | << tr("Can't create duplicate of variable %1: variable not registered in the model") | |
244 | .arg(variable->name()); |
|
244 | .arg(variable->name()); | |
245 | return nullptr; |
|
245 | return nullptr; | |
246 | } |
|
246 | } | |
247 | } |
|
247 | } | |
248 |
|
248 | |||
249 | void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept |
|
249 | void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept | |
250 | { |
|
250 | { | |
251 | if (!variable) { |
|
251 | if (!variable) { | |
252 | qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null"; |
|
252 | qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null"; | |
253 | return; |
|
253 | return; | |
254 | } |
|
254 | } | |
255 |
|
255 | |||
256 | // Spreads in SciQlop that the variable will be deleted, so that potential receivers can |
|
256 | // Spreads in SciQlop that the variable will be deleted, so that potential receivers can | |
257 | // make some treatments before the deletion |
|
257 | // make some treatments before the deletion | |
258 | emit variableAboutToBeDeleted(variable); |
|
258 | emit variableAboutToBeDeleted(variable); | |
259 |
|
259 | |||
260 | auto variableIt = impl->m_VariableToIdentifierMap.find(variable); |
|
260 | auto variableIt = impl->m_VariableToIdentifierMap.find(variable); | |
261 | Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend()); |
|
261 | Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend()); | |
262 |
|
262 | |||
263 | auto variableId = variableIt->second; |
|
263 | auto variableId = variableIt->second; | |
264 |
|
264 | |||
265 | // Removes variable's handler |
|
265 | // Removes variable's handler | |
266 | impl->m_VarIdToVarRequestHandler.erase(variableId); |
|
266 | impl->m_VarIdToVarRequestHandler.erase(variableId); | |
267 |
|
267 | |||
268 | // Desynchronizes variable (if the variable is in a sync group) |
|
268 | // Desynchronizes variable (if the variable is in a sync group) | |
269 | auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId); |
|
269 | auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId); | |
270 | if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) { |
|
270 | if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) { | |
271 | impl->desynchronize(variableIt, syncGroupIt->second); |
|
271 | impl->desynchronize(variableIt, syncGroupIt->second); | |
272 | } |
|
272 | } | |
273 |
|
273 | |||
274 | // Deletes identifier |
|
274 | // Deletes identifier | |
275 | impl->m_VariableToIdentifierMap.erase(variableIt); |
|
275 | impl->m_VariableToIdentifierMap.erase(variableIt); | |
276 |
|
276 | |||
277 | // Deletes provider |
|
277 | // Deletes provider | |
278 | auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable); |
|
278 | auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable); | |
279 | qCDebug(LOG_VariableController()) |
|
279 | qCDebug(LOG_VariableController()) | |
280 | << tr("Number of providers deleted for variable %1: %2") |
|
280 | << tr("Number of providers deleted for variable %1: %2") | |
281 | .arg(variable->name(), QString::number(nbProvidersDeleted)); |
|
281 | .arg(variable->name(), QString::number(nbProvidersDeleted)); | |
282 |
|
282 | |||
283 |
|
283 | |||
284 | // Deletes from model |
|
284 | // Deletes from model | |
285 | impl->m_VariableModel->deleteVariable(variable); |
|
285 | impl->m_VariableModel->deleteVariable(variable); | |
286 | } |
|
286 | } | |
287 |
|
287 | |||
288 | void VariableController::deleteVariables( |
|
288 | void VariableController::deleteVariables( | |
289 | const QVector<std::shared_ptr<Variable> > &variables) noexcept |
|
289 | const QVector<std::shared_ptr<Variable> > &variables) noexcept | |
290 | { |
|
290 | { | |
291 | for (auto variable : qAsConst(variables)) { |
|
291 | for (auto variable : qAsConst(variables)) { | |
292 | deleteVariable(variable); |
|
292 | deleteVariable(variable); | |
293 | } |
|
293 | } | |
294 | } |
|
294 | } | |
295 |
|
295 | |||
296 | QByteArray |
|
296 | QByteArray | |
297 | VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const |
|
297 | VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const | |
298 | { |
|
298 | { | |
299 | auto encodedData = QByteArray{}; |
|
299 | auto encodedData = QByteArray{}; | |
300 |
|
300 | |||
301 | QVariantList ids; |
|
301 | QVariantList ids; | |
302 | for (auto &var : variables) { |
|
302 | for (auto &var : variables) { | |
303 | auto itVar = impl->m_VariableToIdentifierMap.find(var); |
|
303 | auto itVar = impl->m_VariableToIdentifierMap.find(var); | |
304 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { |
|
304 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { | |
305 | qCCritical(LOG_VariableController()) |
|
305 | qCCritical(LOG_VariableController()) | |
306 | << tr("Impossible to find the data for an unknown variable."); |
|
306 | << tr("Impossible to find the data for an unknown variable."); | |
307 | } |
|
307 | } | |
308 |
|
308 | |||
309 | ids << itVar->second.toByteArray(); |
|
309 | ids << itVar->second.toByteArray(); | |
310 | } |
|
310 | } | |
311 |
|
311 | |||
312 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; |
|
312 | QDataStream stream{&encodedData, QIODevice::WriteOnly}; | |
313 | stream << ids; |
|
313 | stream << ids; | |
314 |
|
314 | |||
315 | return encodedData; |
|
315 | return encodedData; | |
316 | } |
|
316 | } | |
317 |
|
317 | |||
318 | QList<std::shared_ptr<Variable> > |
|
318 | QList<std::shared_ptr<Variable> > | |
319 | VariableController::variablesForMimeData(const QByteArray &mimeData) const |
|
319 | VariableController::variablesForMimeData(const QByteArray &mimeData) const | |
320 | { |
|
320 | { | |
321 | auto variables = QList<std::shared_ptr<Variable> >{}; |
|
321 | auto variables = QList<std::shared_ptr<Variable> >{}; | |
322 | QDataStream stream{mimeData}; |
|
322 | QDataStream stream{mimeData}; | |
323 |
|
323 | |||
324 | QVariantList ids; |
|
324 | QVariantList ids; | |
325 | stream >> ids; |
|
325 | stream >> ids; | |
326 |
|
326 | |||
327 | for (auto id : ids) { |
|
327 | for (auto id : ids) { | |
328 | auto uuid = QUuid{id.toByteArray()}; |
|
328 | auto uuid = QUuid{id.toByteArray()}; | |
329 | auto var = impl->findVariable(uuid); |
|
329 | auto var = impl->findVariable(uuid); | |
330 | variables << var; |
|
330 | variables << var; | |
331 | } |
|
331 | } | |
332 |
|
332 | |||
333 | return variables; |
|
333 | return variables; | |
334 | } |
|
334 | } | |
335 |
|
335 | |||
336 | std::shared_ptr<Variable> |
|
336 | std::shared_ptr<Variable> | |
337 | VariableController::createVariable(const QString &name, const QVariantHash &metadata, |
|
337 | VariableController::createVariable(const QString &name, const QVariantHash &metadata, | |
338 | std::shared_ptr<IDataProvider> provider, const DateTimeRange& range) noexcept |
|
338 | std::shared_ptr<IDataProvider> provider, const DateTimeRange& range) noexcept | |
339 | { |
|
339 | { | |
340 | // if (!impl->m_TimeController) { |
|
340 | // if (!impl->m_TimeController) { | |
341 | // qCCritical(LOG_VariableController()) |
|
341 | // qCCritical(LOG_VariableController()) | |
342 | // << tr("Impossible to create variable: The time controller is null"); |
|
342 | // << tr("Impossible to create variable: The time controller is null"); | |
343 | // return nullptr; |
|
343 | // return nullptr; | |
344 | // } |
|
344 | // } | |
345 |
|
345 | |||
346 | // auto range = impl->m_TimeController->dateTime(); |
|
346 | // auto range = impl->m_TimeController->dateTime(); | |
347 |
|
347 | |||
348 | if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) { |
|
348 | if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) { | |
349 | auto varId = QUuid::createUuid(); |
|
349 | auto varId = QUuid::createUuid(); | |
350 |
|
350 | |||
351 | // Create the handler |
|
351 | // Create the handler | |
352 | auto varRequestHandler = std::make_unique<VariableRequestHandler>(); |
|
352 | auto varRequestHandler = std::make_unique<VariableRequestHandler>(); | |
353 | varRequestHandler->m_VarId = varId; |
|
353 | varRequestHandler->m_VarId = varId; | |
354 |
|
354 | |||
355 | impl->m_VarIdToVarRequestHandler.insert( |
|
355 | impl->m_VarIdToVarRequestHandler.insert( | |
356 | std::make_pair(varId, std::move(varRequestHandler))); |
|
356 | std::make_pair(varId, std::move(varRequestHandler))); | |
357 |
|
357 | |||
358 | // store the provider |
|
358 | // store the provider | |
359 | impl->registerProvider(provider); |
|
359 | impl->registerProvider(provider); | |
360 |
|
360 | |||
361 | // Associate the provider |
|
361 | // Associate the provider | |
362 | impl->m_VariableToProviderMap[newVariable] = provider; |
|
362 | impl->m_VariableToProviderMap[newVariable] = provider; | |
363 | impl->m_VariableToIdentifierMap[newVariable] = varId; |
|
363 | impl->m_VariableToIdentifierMap[newVariable] = varId; | |
364 |
|
364 | |||
365 | this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false); |
|
365 | this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false); | |
366 |
|
366 | |||
367 | // auto varRequestId = QUuid::createUuid(); |
|
367 | // auto varRequestId = QUuid::createUuid(); | |
368 | // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId; |
|
368 | // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId; | |
369 | // impl->processRequest(newVariable, range, varRequestId); |
|
369 | // impl->processRequest(newVariable, range, varRequestId); | |
370 | // impl->updateVariableRequest(varRequestId); |
|
370 | // impl->updateVariableRequest(varRequestId); | |
371 |
|
371 | |||
372 | emit variableAdded(newVariable); |
|
372 | emit variableAdded(newVariable); | |
373 |
|
373 | |||
374 | return newVariable; |
|
374 | return newVariable; | |
375 | } |
|
375 | } | |
376 |
|
376 | |||
377 | qCCritical(LOG_VariableController()) << tr("Impossible to create variable"); |
|
377 | qCCritical(LOG_VariableController()) << tr("Impossible to create variable"); | |
378 | return nullptr; |
|
378 | return nullptr; | |
379 | } |
|
379 | } | |
380 |
|
380 | |||
381 | void VariableController::onDateTimeOnSelection(const DateTimeRange &dateTime) |
|
381 | void VariableController::onDateTimeOnSelection(const DateTimeRange &dateTime) | |
382 | { |
|
382 | { | |
383 | // NOTE: Even if acquisition request is aborting, the graphe range will be changed |
|
383 | // NOTE: Even if acquisition request is aborting, the graphe range will be changed | |
384 | qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection" |
|
384 | qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection" | |
385 | << QThread::currentThread()->objectName(); |
|
385 | << QThread::currentThread()->objectName(); | |
386 | auto selectedRows = impl->m_VariableSelectionModel->selectedRows(); |
|
386 | auto selectedRows = impl->m_VariableSelectionModel->selectedRows(); | |
387 |
|
387 | |||
388 | // NOTE we only permit the time modification for one variable |
|
388 | // NOTE we only permit the time modification for one variable | |
389 | // DEPRECATED |
|
389 | // DEPRECATED | |
390 | // auto variables = QVector<std::shared_ptr<Variable> >{}; |
|
390 | // auto variables = QVector<std::shared_ptr<Variable> >{}; | |
391 | // for (const auto &selectedRow : qAsConst(selectedRows)) { |
|
391 | // for (const auto &selectedRow : qAsConst(selectedRows)) { | |
392 | // if (auto selectedVariable = |
|
392 | // if (auto selectedVariable = | |
393 | // impl->m_VariableModel->variable(selectedRow.row())) { |
|
393 | // impl->m_VariableModel->variable(selectedRow.row())) { | |
394 | // variables << selectedVariable; |
|
394 | // variables << selectedVariable; | |
395 |
|
395 | |||
396 | // // notify that rescale operation has to be done |
|
396 | // // notify that rescale operation has to be done | |
397 | // emit rangeChanged(selectedVariable, dateTime); |
|
397 | // emit rangeChanged(selectedVariable, dateTime); | |
398 | // } |
|
398 | // } | |
399 | // } |
|
399 | // } | |
400 | // if (!variables.isEmpty()) { |
|
400 | // if (!variables.isEmpty()) { | |
401 | // this->onRequestDataLoading(variables, dateTime, synchro); |
|
401 | // this->onRequestDataLoading(variables, dateTime, synchro); | |
402 | // } |
|
402 | // } | |
403 | if (selectedRows.size() == 1) { |
|
403 | if (selectedRows.size() == 1) { | |
404 |
|
404 | |||
405 | if (auto selectedVariable |
|
405 | if (auto selectedVariable | |
406 | = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) { |
|
406 | = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) { | |
407 |
|
407 | |||
408 | onUpdateDateTime(selectedVariable, dateTime); |
|
408 | onUpdateDateTime(selectedVariable, dateTime); | |
409 | } |
|
409 | } | |
410 | } |
|
410 | } | |
411 | else if (selectedRows.size() > 1) { |
|
411 | else if (selectedRows.size() > 1) { | |
412 | qCCritical(LOG_VariableController()) |
|
412 | qCCritical(LOG_VariableController()) | |
413 | << tr("Impossible to set time for more than 1 variable in the same time"); |
|
413 | << tr("Impossible to set time for more than 1 variable in the same time"); | |
414 | } |
|
414 | } | |
415 | else { |
|
415 | else { | |
416 | qCWarning(LOG_VariableController()) |
|
416 | qCWarning(LOG_VariableController()) | |
417 | << tr("There is no variable selected to set the time one"); |
|
417 | << tr("There is no variable selected to set the time one"); | |
418 | } |
|
418 | } | |
419 | } |
|
419 | } | |
420 |
|
420 | |||
421 | void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable, |
|
421 | void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable, | |
422 | const DateTimeRange &dateTime) |
|
422 | const DateTimeRange &dateTime) | |
423 | { |
|
423 | { | |
424 | auto itVar = impl->m_VariableToIdentifierMap.find(variable); |
|
424 | auto itVar = impl->m_VariableToIdentifierMap.find(variable); | |
425 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { |
|
425 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { | |
426 | qCCritical(LOG_VariableController()) |
|
426 | qCCritical(LOG_VariableController()) | |
427 | << tr("Impossible to onDateTimeOnSelection request for unknown variable"); |
|
427 | << tr("Impossible to onDateTimeOnSelection request for unknown variable"); | |
428 | return; |
|
428 | return; | |
429 | } |
|
429 | } | |
430 |
|
430 | |||
431 | // notify that rescale operation has to be done |
|
431 | // notify that rescale operation has to be done | |
432 | emit rangeChanged(variable, dateTime); |
|
432 | emit rangeChanged(variable, dateTime); | |
433 |
|
433 | |||
434 | auto synchro |
|
434 | auto synchro | |
435 | = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend(); |
|
435 | = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend(); | |
436 |
|
436 | |||
437 | this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro); |
|
437 | this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro); | |
438 | } |
|
438 | } | |
439 |
|
439 | |||
440 | void VariableController::onDataProvided(QUuid vIdentifier, const DateTimeRange &rangeRequested, |
|
440 | void VariableController::onDataProvided(QUuid vIdentifier, const DateTimeRange &rangeRequested, | |
441 | const DateTimeRange &cacheRangeRequested, |
|
441 | const DateTimeRange &cacheRangeRequested, | |
442 | QVector<AcquisitionDataPacket> dataAcquired) |
|
442 | QVector<AcquisitionDataPacket> dataAcquired) | |
443 | { |
|
443 | { | |
444 | qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread(); |
|
444 | qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread(); | |
445 | auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired); |
|
445 | auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired); | |
446 | auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries); |
|
446 | auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries); | |
447 | if (!varRequestId.isNull()) { |
|
447 | if (!varRequestId.isNull()) { | |
448 | impl->updateVariables(varRequestId); |
|
448 | impl->updateVariables(varRequestId); | |
449 | } |
|
449 | } | |
450 | } |
|
450 | } | |
451 |
|
451 | |||
452 | void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress) |
|
452 | void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress) | |
453 | { |
|
453 | { | |
454 | qCDebug(LOG_VariableController()) |
|
454 | qCDebug(LOG_VariableController()) | |
455 | << "TORM: variableController::onVariableRetrieveDataInProgress" |
|
455 | << "TORM: variableController::onVariableRetrieveDataInProgress" | |
456 | << QThread::currentThread()->objectName() << progress; |
|
456 | << QThread::currentThread()->objectName() << progress; | |
457 | if (auto var = impl->findVariable(identifier)) { |
|
457 | if (auto var = impl->findVariable(identifier)) { | |
458 | impl->m_VariableModel->setDataProgress(var, progress); |
|
458 | impl->m_VariableModel->setDataProgress(var, progress); | |
459 | } |
|
459 | } | |
460 | else { |
|
460 | else { | |
461 | qCCritical(LOG_VariableController()) |
|
461 | qCCritical(LOG_VariableController()) | |
462 | << tr("Impossible to notify progression of a null variable"); |
|
462 | << tr("Impossible to notify progression of a null variable"); | |
463 | } |
|
463 | } | |
464 | } |
|
464 | } | |
465 |
|
465 | |||
466 | void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable) |
|
466 | void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable) | |
467 | { |
|
467 | { | |
468 | qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested" |
|
468 | qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested" | |
469 | << QThread::currentThread()->objectName() << variable->name(); |
|
469 | << QThread::currentThread()->objectName() << variable->name(); | |
470 |
|
470 | |||
471 | auto itVar = impl->m_VariableToIdentifierMap.find(variable); |
|
471 | auto itVar = impl->m_VariableToIdentifierMap.find(variable); | |
472 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { |
|
472 | if (itVar == impl->m_VariableToIdentifierMap.cend()) { | |
473 | qCCritical(LOG_VariableController()) |
|
473 | qCCritical(LOG_VariableController()) | |
474 | << tr("Impossible to onAbortProgressRequested request for unknown variable"); |
|
474 | << tr("Impossible to onAbortProgressRequested request for unknown variable"); | |
475 | return; |
|
475 | return; | |
476 | } |
|
476 | } | |
477 |
|
477 | |||
478 | auto varId = itVar->second; |
|
478 | auto varId = itVar->second; | |
479 |
|
479 | |||
480 | auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId); |
|
480 | auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId); | |
481 | if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) { |
|
481 | if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) { | |
482 | qCCritical(LOG_VariableController()) |
|
482 | qCCritical(LOG_VariableController()) | |
483 | << tr("Impossible to onAbortProgressRequested for variable with unknown handler"); |
|
483 | << tr("Impossible to onAbortProgressRequested for variable with unknown handler"); | |
484 | return; |
|
484 | return; | |
485 | } |
|
485 | } | |
486 |
|
486 | |||
487 | auto varHandler = itVarHandler->second.get(); |
|
487 | auto varHandler = itVarHandler->second.get(); | |
488 |
|
488 | |||
489 | // case where a variable has a running request |
|
489 | // case where a variable has a running request | |
490 | if (varHandler->m_State != VariableRequestHandlerState::OFF) { |
|
490 | if (varHandler->m_State != VariableRequestHandlerState::OFF) { | |
491 | impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId); |
|
491 | impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId); | |
492 | } |
|
492 | } | |
493 | } |
|
493 | } | |
494 |
|
494 | |||
495 | void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier) |
|
495 | void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier) | |
496 | { |
|
496 | { | |
497 | qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested" |
|
497 | qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested" | |
498 | << QThread::currentThread()->objectName() << vIdentifier; |
|
498 | << QThread::currentThread()->objectName() << vIdentifier; | |
499 |
|
499 | |||
500 | if (auto var = impl->findVariable(vIdentifier)) { |
|
500 | if (auto var = impl->findVariable(vIdentifier)) { | |
501 | this->onAbortProgressRequested(var); |
|
501 | this->onAbortProgressRequested(var); | |
502 | } |
|
502 | } | |
503 | else { |
|
503 | else { | |
504 | qCCritical(LOG_VariableController()) |
|
504 | qCCritical(LOG_VariableController()) | |
505 | << tr("Impossible to abort Acquisition Requestof a null variable"); |
|
505 | << tr("Impossible to abort Acquisition Requestof a null variable"); | |
506 | } |
|
506 | } | |
507 | } |
|
507 | } | |
508 |
|
508 | |||
509 | void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId) |
|
509 | void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId) | |
510 | { |
|
510 | { | |
511 | qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId" |
|
511 | qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId" | |
512 | << QThread::currentThread()->objectName() |
|
512 | << QThread::currentThread()->objectName() | |
513 | << synchronizationGroupId; |
|
513 | << synchronizationGroupId; | |
514 | auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>(); |
|
514 | auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>(); | |
515 | impl->m_GroupIdToVariableSynchronizationGroupMap.insert( |
|
515 | impl->m_GroupIdToVariableSynchronizationGroupMap.insert( | |
516 | std::make_pair(synchronizationGroupId, vSynchroGroup)); |
|
516 | std::make_pair(synchronizationGroupId, vSynchroGroup)); | |
517 | } |
|
517 | } | |
518 |
|
518 | |||
519 | void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId) |
|
519 | void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId) | |
520 | { |
|
520 | { | |
521 | impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId); |
|
521 | impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId); | |
522 | } |
|
522 | } | |
523 |
|
523 | |||
524 | void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable, |
|
524 | void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable, | |
525 | QUuid synchronizationGroupId) |
|
525 | QUuid synchronizationGroupId) | |
526 |
|
526 | |||
527 | { |
|
527 | { | |
528 | qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized" |
|
528 | qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized" | |
529 | << synchronizationGroupId; |
|
529 | << synchronizationGroupId; | |
530 | auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable); |
|
530 | auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable); | |
531 | if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) { |
|
531 | if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) { | |
532 | auto groupIdToVSGIt |
|
532 | auto groupIdToVSGIt | |
533 | = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId); |
|
533 | = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId); | |
534 | if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) { |
|
534 | if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) { | |
535 | impl->m_VariableIdGroupIdMap.insert( |
|
535 | impl->m_VariableIdGroupIdMap.insert( | |
536 | std::make_pair(varToVarIdIt->second, synchronizationGroupId)); |
|
536 | std::make_pair(varToVarIdIt->second, synchronizationGroupId)); | |
537 | groupIdToVSGIt->second->addVariable(varToVarIdIt->second); |
|
537 | groupIdToVSGIt->second->addVariable(varToVarIdIt->second); | |
538 | } |
|
538 | } | |
539 | else { |
|
539 | else { | |
540 | qCCritical(LOG_VariableController()) |
|
540 | qCCritical(LOG_VariableController()) | |
541 | << tr("Impossible to synchronize a variable with an unknown sycnhronization group") |
|
541 | << tr("Impossible to synchronize a variable with an unknown sycnhronization group") | |
542 | << variable->name(); |
|
542 | << variable->name(); | |
543 | } |
|
543 | } | |
544 | } |
|
544 | } | |
545 | else { |
|
545 | else { | |
546 | qCCritical(LOG_VariableController()) |
|
546 | qCCritical(LOG_VariableController()) | |
547 | << tr("Impossible to synchronize a variable with no identifier") << variable->name(); |
|
547 | << tr("Impossible to synchronize a variable with no identifier") << variable->name(); | |
548 | } |
|
548 | } | |
549 | } |
|
549 | } | |
550 |
|
550 | |||
551 | void VariableController::desynchronize(std::shared_ptr<Variable> variable, |
|
551 | void VariableController::desynchronize(std::shared_ptr<Variable> variable, | |
552 | QUuid synchronizationGroupId) |
|
552 | QUuid synchronizationGroupId) | |
553 | { |
|
553 | { | |
554 | // Gets variable id |
|
554 | // Gets variable id | |
555 | auto variableIt = impl->m_VariableToIdentifierMap.find(variable); |
|
555 | auto variableIt = impl->m_VariableToIdentifierMap.find(variable); | |
556 | if (variableIt == impl->m_VariableToIdentifierMap.cend()) { |
|
556 | if (variableIt == impl->m_VariableToIdentifierMap.cend()) { | |
557 | qCCritical(LOG_VariableController()) |
|
557 | qCCritical(LOG_VariableController()) | |
558 | << tr("Can't desynchronize variable %1: variable identifier not found") |
|
558 | << tr("Can't desynchronize variable %1: variable identifier not found") | |
559 | .arg(variable->name()); |
|
559 | .arg(variable->name()); | |
560 | return; |
|
560 | return; | |
561 | } |
|
561 | } | |
562 |
|
562 | |||
563 | impl->desynchronize(variableIt, synchronizationGroupId); |
|
563 | impl->desynchronize(variableIt, synchronizationGroupId); | |
564 | } |
|
564 | } | |
565 |
|
565 | |||
566 | void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, |
|
566 | void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, | |
567 | const DateTimeRange &range, bool synchronise) |
|
567 | const DateTimeRange &range, bool synchronise) | |
568 | { |
|
568 | { | |
569 | // variables is assumed synchronized |
|
569 | // variables is assumed synchronized | |
570 | // TODO: Asser variables synchronization |
|
570 | // TODO: Asser variables synchronization | |
571 | // we want to load data of the variable for the dateTime. |
|
571 | // we want to load data of the variable for the dateTime. | |
572 | if (variables.isEmpty()) { |
|
572 | if (variables.isEmpty()) { | |
573 | return; |
|
573 | return; | |
574 | } |
|
574 | } | |
575 |
|
575 | |||
576 | auto varRequestId = QUuid::createUuid(); |
|
576 | auto varRequestId = QUuid::createUuid(); | |
577 | qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading" |
|
577 | qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading" | |
578 | << QThread::currentThread()->objectName() << varRequestId |
|
578 | << QThread::currentThread()->objectName() << varRequestId | |
579 | << range << synchronise; |
|
579 | << range << synchronise; | |
580 |
|
580 | |||
581 | if (!synchronise) { |
|
581 | if (!synchronise) { | |
582 | auto varIds = std::list<QUuid>{}; |
|
582 | auto varIds = std::list<QUuid>{}; | |
583 | for (const auto &var : variables) { |
|
583 | for (const auto &var : variables) { | |
584 | auto vId = impl->m_VariableToIdentifierMap.at(var); |
|
584 | auto vId = impl->m_VariableToIdentifierMap.at(var); | |
585 | varIds.push_back(vId); |
|
585 | varIds.push_back(vId); | |
586 | } |
|
586 | } | |
587 | impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); |
|
587 | impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); | |
588 | for (const auto &var : variables) { |
|
588 | for (const auto &var : variables) { | |
589 | qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId |
|
589 | qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId | |
590 | << varIds.size(); |
|
590 | << varIds.size(); | |
591 | impl->processRequest(var, range, varRequestId); |
|
591 | impl->processRequest(var, range, varRequestId); | |
592 | } |
|
592 | } | |
593 | } |
|
593 | } | |
594 | else { |
|
594 | else { | |
595 | auto vId = impl->m_VariableToIdentifierMap.at(variables.first()); |
|
595 | auto vId = impl->m_VariableToIdentifierMap.at(variables.first()); | |
596 | auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId); |
|
596 | auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId); | |
597 | if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) { |
|
597 | if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) { | |
598 | auto groupId = varIdToGroupIdIt->second; |
|
598 | auto groupId = varIdToGroupIdIt->second; | |
599 |
|
599 | |||
600 | auto vSynchronizationGroup |
|
600 | auto vSynchronizationGroup | |
601 | = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId); |
|
601 | = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId); | |
602 | auto vSyncIds = vSynchronizationGroup->getIds(); |
|
602 | auto vSyncIds = vSynchronizationGroup->getIds(); | |
603 |
|
603 | |||
604 | auto varIds = std::list<QUuid>{}; |
|
604 | auto varIds = std::list<QUuid>{}; | |
605 | for (auto vId : vSyncIds) { |
|
605 | for (auto vId : vSyncIds) { | |
606 | varIds.push_back(vId); |
|
606 | varIds.push_back(vId); | |
607 | } |
|
607 | } | |
608 | impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); |
|
608 | impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds)); | |
609 |
|
609 | |||
610 | for (auto vId : vSyncIds) { |
|
610 | for (auto vId : vSyncIds) { | |
611 | auto var = impl->findVariable(vId); |
|
611 | auto var = impl->findVariable(vId); | |
612 |
|
612 | |||
613 | // Don't process already processed var |
|
613 | // Don't process already processed var | |
614 | if (var != nullptr) { |
|
614 | if (var != nullptr) { | |
615 | qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name() |
|
615 | qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name() | |
616 | << varRequestId; |
|
616 | << varRequestId; | |
617 | auto vSyncRangeRequested |
|
617 | auto vSyncRangeRequested | |
618 | = variables.contains(var) |
|
618 | = variables.contains(var) | |
619 | ? range |
|
619 | ? range | |
620 | : computeSynchroRangeRequested(var->range(), range, |
|
620 | : computeSynchroRangeRequested(var->range(), range, | |
621 | variables.first()->range()); |
|
621 | variables.first()->range()); | |
622 | qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested; |
|
622 | qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested; | |
623 | impl->processRequest(var, vSyncRangeRequested, varRequestId); |
|
623 | impl->processRequest(var, vSyncRangeRequested, varRequestId); | |
624 | } |
|
624 | } | |
625 | else { |
|
625 | else { | |
626 | qCCritical(LOG_VariableController()) |
|
626 | qCCritical(LOG_VariableController()) | |
627 |
|
627 | |||
628 | << tr("Impossible to synchronize a null variable"); |
|
628 | << tr("Impossible to synchronize a null variable"); | |
629 | } |
|
629 | } | |
630 | } |
|
630 | } | |
631 | } |
|
631 | } | |
632 | } |
|
632 | } | |
633 |
|
633 | |||
634 | impl->updateVariables(varRequestId); |
|
634 | impl->updateVariables(varRequestId); | |
635 | } |
|
635 | } | |
636 |
|
636 | |||
637 |
|
637 | |||
638 | void VariableController::initialize() |
|
638 | void VariableController::initialize() | |
639 | { |
|
639 | { | |
640 | qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread(); |
|
640 | qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread(); | |
641 | impl->m_WorkingMutex.lock(); |
|
641 | impl->m_WorkingMutex.lock(); | |
642 | qCDebug(LOG_VariableController()) << tr("VariableController init END"); |
|
642 | qCDebug(LOG_VariableController()) << tr("VariableController init END"); | |
643 | } |
|
643 | } | |
644 |
|
644 | |||
645 | void VariableController::finalize() |
|
645 | void VariableController::finalize() | |
646 | { |
|
646 | { | |
647 | impl->m_WorkingMutex.unlock(); |
|
647 | impl->m_WorkingMutex.unlock(); | |
648 | } |
|
648 | } | |
649 |
|
649 | |||
650 | void VariableController::waitForFinish() |
|
650 | void VariableController::waitForFinish() | |
651 | { |
|
651 | { | |
652 | QMutexLocker locker{&impl->m_WorkingMutex}; |
|
652 | QMutexLocker locker{&impl->m_WorkingMutex}; | |
653 | } |
|
653 | } | |
654 |
|
654 | |||
655 | bool VariableController::hasPendingDownloads() |
|
655 | bool VariableController::hasPendingDownloads() | |
656 | { |
|
656 | { | |
657 | return impl->hasPendingDownloads(); |
|
657 | return impl->hasPendingDownloads(); | |
658 | } |
|
658 | } | |
659 |
|
659 | |||
660 | AcquisitionZoomType VariableController::getZoomType(const DateTimeRange &range, const DateTimeRange &oldRange) |
|
660 | AcquisitionZoomType VariableController::getZoomType(const DateTimeRange &range, const DateTimeRange &oldRange) | |
661 | { |
|
661 | { | |
662 | if (almost_equal(range.delta(), oldRange.delta(), 1)) // same delta -> must be a pan or nothing |
|
662 | if (almost_equal(static_cast<double>(range.delta()), static_cast<double>(oldRange.delta()), 1)) // same delta -> must be a pan or nothing | |
663 | { |
|
663 | { | |
664 | if(range.m_TStart > oldRange.m_TStart) |
|
664 | if(range.m_TStart > oldRange.m_TStart) | |
665 | return AcquisitionZoomType::PanRight; |
|
665 | return AcquisitionZoomType::PanRight; | |
666 | if(range.m_TStart < oldRange.m_TStart) |
|
666 | if(range.m_TStart < oldRange.m_TStart) | |
667 | return AcquisitionZoomType::PanLeft; |
|
667 | return AcquisitionZoomType::PanLeft; | |
668 | } |
|
668 | } | |
669 | else // different delta -> must be a zoom |
|
669 | else // different delta -> must be a zoom | |
670 | { |
|
670 | { | |
671 | if(range.m_TStart > oldRange.m_TStart) |
|
671 | if(range.m_TStart > oldRange.m_TStart) | |
672 | return AcquisitionZoomType::ZoomIn; |
|
672 | return AcquisitionZoomType::ZoomIn; | |
673 | if(range.m_TStart < oldRange.m_TStart) |
|
673 | if(range.m_TStart < oldRange.m_TStart) | |
674 | return AcquisitionZoomType::ZoomOut; |
|
674 | return AcquisitionZoomType::ZoomOut; | |
675 | } |
|
675 | } | |
676 | return AcquisitionZoomType::Unknown; |
|
676 | return AcquisitionZoomType::Unknown; | |
677 | } |
|
677 | } | |
678 |
|
678 | |||
679 | void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var, |
|
679 | void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var, | |
680 | const DateTimeRange &rangeRequested, |
|
680 | const DateTimeRange &rangeRequested, | |
681 | QUuid varRequestId) |
|
681 | QUuid varRequestId) | |
682 | { |
|
682 | { | |
683 | auto itVar = m_VariableToIdentifierMap.find(var); |
|
683 | auto itVar = m_VariableToIdentifierMap.find(var); | |
684 | if (itVar == m_VariableToIdentifierMap.cend()) { |
|
684 | if (itVar == m_VariableToIdentifierMap.cend()) { | |
685 | qCCritical(LOG_VariableController()) |
|
685 | qCCritical(LOG_VariableController()) | |
686 | << tr("Impossible to process request for unknown variable"); |
|
686 | << tr("Impossible to process request for unknown variable"); | |
687 | return; |
|
687 | return; | |
688 | } |
|
688 | } | |
689 |
|
689 | |||
690 | auto varId = itVar->second; |
|
690 | auto varId = itVar->second; | |
691 |
|
691 | |||
692 | auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); |
|
692 | auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); | |
693 | if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { |
|
693 | if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { | |
694 | qCCritical(LOG_VariableController()) |
|
694 | qCCritical(LOG_VariableController()) | |
695 | << tr("Impossible to process request for variable with unknown handler"); |
|
695 | << tr("Impossible to process request for variable with unknown handler"); | |
696 | return; |
|
696 | return; | |
697 | } |
|
697 | } | |
698 |
|
698 | |||
699 | auto oldRange = var->range(); |
|
699 | auto oldRange = var->range(); | |
700 |
|
700 | |||
701 | auto varHandler = itVarHandler->second.get(); |
|
701 | auto varHandler = itVarHandler->second.get(); | |
702 |
|
702 | |||
703 | if (varHandler->m_State != VariableRequestHandlerState::OFF) { |
|
703 | if (varHandler->m_State != VariableRequestHandlerState::OFF) { | |
704 | oldRange = varHandler->m_RunningVarRequest.m_RangeRequested; |
|
704 | oldRange = varHandler->m_RunningVarRequest.m_RangeRequested; | |
705 | } |
|
705 | } | |
706 |
|
706 | |||
707 | auto varRequest = VariableRequest{}; |
|
707 | auto varRequest = VariableRequest{}; | |
708 | varRequest.m_VariableGroupId = varRequestId; |
|
708 | varRequest.m_VariableGroupId = varRequestId; | |
709 | auto varStrategyRangesRequested |
|
709 | auto varStrategyRangesRequested | |
710 | = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested); |
|
710 | = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested); | |
711 | varRequest.m_RangeRequested = varStrategyRangesRequested.first; |
|
711 | varRequest.m_RangeRequested = varStrategyRangesRequested.first; | |
712 | varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second; |
|
712 | varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second; | |
713 |
|
713 | |||
714 | switch (varHandler->m_State) { |
|
714 | switch (varHandler->m_State) { | |
715 | case VariableRequestHandlerState::OFF: { |
|
715 | case VariableRequestHandlerState::OFF: { | |
716 | qCDebug(LOG_VariableController()) << tr("Process Request OFF") |
|
716 | qCDebug(LOG_VariableController()) << tr("Process Request OFF") | |
717 | << varRequest.m_RangeRequested |
|
717 | << varRequest.m_RangeRequested | |
718 | << varRequest.m_CacheRangeRequested; |
|
718 | << varRequest.m_CacheRangeRequested; | |
719 | varHandler->m_RunningVarRequest = varRequest; |
|
719 | varHandler->m_RunningVarRequest = varRequest; | |
720 | varHandler->m_State = VariableRequestHandlerState::RUNNING; |
|
720 | varHandler->m_State = VariableRequestHandlerState::RUNNING; | |
721 | executeVarRequest(var, varRequest); |
|
721 | executeVarRequest(var, varRequest); | |
722 | break; |
|
722 | break; | |
723 | } |
|
723 | } | |
724 | case VariableRequestHandlerState::RUNNING: { |
|
724 | case VariableRequestHandlerState::RUNNING: { | |
725 | qCDebug(LOG_VariableController()) << tr("Process Request RUNNING") |
|
725 | qCDebug(LOG_VariableController()) << tr("Process Request RUNNING") | |
726 | << varRequest.m_RangeRequested |
|
726 | << varRequest.m_RangeRequested | |
727 | << varRequest.m_CacheRangeRequested; |
|
727 | << varRequest.m_CacheRangeRequested; | |
728 | varHandler->m_State = VariableRequestHandlerState::PENDING; |
|
728 | varHandler->m_State = VariableRequestHandlerState::PENDING; | |
729 | varHandler->m_PendingVarRequest = varRequest; |
|
729 | varHandler->m_PendingVarRequest = varRequest; | |
730 | break; |
|
730 | break; | |
731 | } |
|
731 | } | |
732 | case VariableRequestHandlerState::PENDING: { |
|
732 | case VariableRequestHandlerState::PENDING: { | |
733 | qCDebug(LOG_VariableController()) << tr("Process Request PENDING") |
|
733 | qCDebug(LOG_VariableController()) << tr("Process Request PENDING") | |
734 | << varRequest.m_RangeRequested |
|
734 | << varRequest.m_RangeRequested | |
735 | << varRequest.m_CacheRangeRequested; |
|
735 | << varRequest.m_CacheRangeRequested; | |
736 | auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId; |
|
736 | auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId; | |
737 | cancelVariableRequest(variableGroupIdToCancel); |
|
737 | cancelVariableRequest(variableGroupIdToCancel); | |
738 | // Cancel variable can make state downgrade |
|
738 | // Cancel variable can make state downgrade | |
739 | varHandler->m_State = VariableRequestHandlerState::PENDING; |
|
739 | varHandler->m_State = VariableRequestHandlerState::PENDING; | |
740 | varHandler->m_PendingVarRequest = varRequest; |
|
740 | varHandler->m_PendingVarRequest = varRequest; | |
741 |
|
741 | |||
742 | break; |
|
742 | break; | |
743 | } |
|
743 | } | |
744 | default: |
|
744 | default: | |
745 | qCCritical(LOG_VariableController()) |
|
745 | qCCritical(LOG_VariableController()) | |
746 | << QObject::tr("Unknown VariableRequestHandlerState"); |
|
746 | << QObject::tr("Unknown VariableRequestHandlerState"); | |
747 | } |
|
747 | } | |
748 | } |
|
748 | } | |
749 |
|
749 | |||
750 | std::shared_ptr<Variable> |
|
750 | std::shared_ptr<Variable> | |
751 | VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier) |
|
751 | VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier) | |
752 | { |
|
752 | { | |
753 | std::shared_ptr<Variable> var; |
|
753 | std::shared_ptr<Variable> var; | |
754 | auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; }; |
|
754 | auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; }; | |
755 |
|
755 | |||
756 | auto end = m_VariableToIdentifierMap.cend(); |
|
756 | auto end = m_VariableToIdentifierMap.cend(); | |
757 | auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply); |
|
757 | auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply); | |
758 | if (it != end) { |
|
758 | if (it != end) { | |
759 | var = it->first; |
|
759 | var = it->first; | |
760 | } |
|
760 | } | |
761 | else { |
|
761 | else { | |
762 | qCCritical(LOG_VariableController()) |
|
762 | qCCritical(LOG_VariableController()) | |
763 | << tr("Impossible to find the variable with the identifier: ") << vIdentifier; |
|
763 | << tr("Impossible to find the variable with the identifier: ") << vIdentifier; | |
764 | } |
|
764 | } | |
765 |
|
765 | |||
766 | return var; |
|
766 | return var; | |
767 | } |
|
767 | } | |
768 |
|
768 | |||
769 | std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries( |
|
769 | std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries( | |
770 | const QVector<AcquisitionDataPacket> acqDataPacketVector) |
|
770 | const QVector<AcquisitionDataPacket> acqDataPacketVector) | |
771 | { |
|
771 | { | |
772 | qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size") |
|
772 | qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size") | |
773 | << acqDataPacketVector.size(); |
|
773 | << acqDataPacketVector.size(); | |
774 | std::shared_ptr<IDataSeries> dataSeries; |
|
774 | std::shared_ptr<IDataSeries> dataSeries; | |
775 | if (!acqDataPacketVector.isEmpty()) { |
|
775 | if (!acqDataPacketVector.isEmpty()) { | |
776 | dataSeries = acqDataPacketVector[0].m_DateSeries; |
|
776 | dataSeries = acqDataPacketVector[0].m_DateSeries; | |
777 | for (int i = 1; i < acqDataPacketVector.size(); ++i) { |
|
777 | for (int i = 1; i < acqDataPacketVector.size(); ++i) { | |
778 | dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get()); |
|
778 | dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get()); | |
779 | } |
|
779 | } | |
780 | } |
|
780 | } | |
781 | qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END") |
|
781 | qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END") | |
782 | << acqDataPacketVector.size(); |
|
782 | << acqDataPacketVector.size(); | |
783 | return dataSeries; |
|
783 | return dataSeries; | |
784 | } |
|
784 | } | |
785 |
|
785 | |||
786 | void VariableController::VariableControllerPrivate::registerProvider( |
|
786 | void VariableController::VariableControllerPrivate::registerProvider( | |
787 | std::shared_ptr<IDataProvider> provider) |
|
787 | std::shared_ptr<IDataProvider> provider) | |
788 | { |
|
788 | { | |
789 | if (m_ProviderSet.find(provider) == m_ProviderSet.end()) { |
|
789 | if (m_ProviderSet.find(provider) == m_ProviderSet.end()) { | |
790 | qCDebug(LOG_VariableController()) << tr("Registering of a new provider") |
|
790 | qCDebug(LOG_VariableController()) << tr("Registering of a new provider") | |
791 | << provider->objectName(); |
|
791 | << provider->objectName(); | |
792 | m_ProviderSet.insert(provider); |
|
792 | m_ProviderSet.insert(provider); | |
793 | connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(), |
|
793 | connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(), | |
794 | &VariableAcquisitionWorker::onVariableDataAcquired); |
|
794 | &VariableAcquisitionWorker::onVariableDataAcquired); | |
795 | connect(provider.get(), &IDataProvider::dataProvidedProgress, |
|
795 | connect(provider.get(), &IDataProvider::dataProvidedProgress, | |
796 | m_VariableAcquisitionWorker.get(), |
|
796 | m_VariableAcquisitionWorker.get(), | |
797 | &VariableAcquisitionWorker::onVariableRetrieveDataInProgress); |
|
797 | &VariableAcquisitionWorker::onVariableRetrieveDataInProgress); | |
798 | connect(provider.get(), &IDataProvider::dataProvidedFailed, |
|
798 | connect(provider.get(), &IDataProvider::dataProvidedFailed, | |
799 | m_VariableAcquisitionWorker.get(), |
|
799 | m_VariableAcquisitionWorker.get(), | |
800 | &VariableAcquisitionWorker::onVariableAcquisitionFailed); |
|
800 | &VariableAcquisitionWorker::onVariableAcquisitionFailed); | |
801 | } |
|
801 | } | |
802 | else { |
|
802 | else { | |
803 | qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists "); |
|
803 | qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists "); | |
804 | } |
|
804 | } | |
805 | } |
|
805 | } | |
806 |
|
806 | |||
807 | QUuid VariableController::VariableControllerPrivate::acceptVariableRequest( |
|
807 | QUuid VariableController::VariableControllerPrivate::acceptVariableRequest( | |
808 | QUuid varId, std::shared_ptr<IDataSeries> dataSeries) |
|
808 | QUuid varId, std::shared_ptr<IDataSeries> dataSeries) | |
809 | { |
|
809 | { | |
810 | auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); |
|
810 | auto itVarHandler = m_VarIdToVarRequestHandler.find(varId); | |
811 | if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { |
|
811 | if (itVarHandler == m_VarIdToVarRequestHandler.cend()) { | |
812 | return QUuid(); |
|
812 | return QUuid(); | |
813 | } |
|
813 | } | |
814 |
|
814 | |||
815 | auto varHandler = itVarHandler->second.get(); |
|
815 | auto varHandler = itVarHandler->second.get(); | |
816 | if (varHandler->m_State == VariableRequestHandlerState::OFF) { |
|
816 | if (varHandler->m_State == VariableRequestHandlerState::OFF) { | |
817 | qCCritical(LOG_VariableController()) |
|
817 | qCCritical(LOG_VariableController()) | |
818 | << tr("acceptVariableRequest impossible on a variable with OFF state"); |
|
818 | << tr("acceptVariableRequest impossible on a variable with OFF state"); | |
819 | } |
|
819 | } | |
820 |
|
820 | |||
821 | varHandler->m_RunningVarRequest.m_DataSeries = dataSeries; |
|
821 | varHandler->m_RunningVarRequest.m_DataSeries = dataSeries; | |
822 | varHandler->m_CanUpdate = true; |
|
822 | varHandler->m_CanUpdate = true; | |
823 |
|
823 | |||
824 | // Element traitΓ©, on a dΓ©jΓ toutes les donnΓ©es necessaires |
|
824 | // Element traitΓ©, on a dΓ©jΓ toutes les donnΓ©es necessaires | |
825 | auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId; |
|
825 | auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId; | |
826 | qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId |
|
826 | qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId | |
827 | << m_VarGroupIdToVarIds.size(); |
|
827 | << m_VarGroupIdToVarIds.size(); | |
828 |
|
828 | |||
829 | return varHandler->m_RunningVarRequest.m_VariableGroupId; |
|
829 | return varHandler->m_RunningVarRequest.m_VariableGroupId; | |
830 | } |
|
830 | } | |
831 |
|
831 | |||
832 | void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId) |
|
832 | void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId) | |
833 | { |
|
833 | { | |
834 | qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" |
|
834 | qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" | |
835 | << QThread::currentThread()->objectName() << varRequestId; |
|
835 | << QThread::currentThread()->objectName() << varRequestId; | |
836 |
|
836 | |||
837 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); |
|
837 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); | |
838 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { |
|
838 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { | |
839 | qCWarning(LOG_VariableController()) |
|
839 | qCWarning(LOG_VariableController()) | |
840 | << tr("Impossible to updateVariables of unknown variables") << varRequestId; |
|
840 | << tr("Impossible to updateVariables of unknown variables") << varRequestId; | |
841 | return; |
|
841 | return; | |
842 | } |
|
842 | } | |
843 |
|
843 | |||
844 | auto &varIds = varGroupIdToVarIdsIt->second; |
|
844 | auto &varIds = varGroupIdToVarIdsIt->second; | |
845 | auto varIdsEnd = varIds.end(); |
|
845 | auto varIdsEnd = varIds.end(); | |
846 | bool processVariableUpdate = true; |
|
846 | bool processVariableUpdate = true; | |
847 | qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" |
|
847 | qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables" | |
848 | << varRequestId << varIds.size(); |
|
848 | << varRequestId << varIds.size(); | |
849 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate; |
|
849 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate; | |
850 | ++varIdsIt) { |
|
850 | ++varIdsIt) { | |
851 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); |
|
851 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); | |
852 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { |
|
852 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { | |
853 | processVariableUpdate &= itVarHandler->second->m_CanUpdate; |
|
853 | processVariableUpdate &= itVarHandler->second->m_CanUpdate; | |
854 | } |
|
854 | } | |
855 | } |
|
855 | } | |
856 |
|
856 | |||
857 | if (processVariableUpdate) { |
|
857 | if (processVariableUpdate) { | |
858 | qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size(); |
|
858 | qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size(); | |
859 | for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) { |
|
859 | for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) { | |
860 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); |
|
860 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); | |
861 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { |
|
861 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { | |
862 | if (auto var = findVariable(*varIdsIt)) { |
|
862 | if (auto var = findVariable(*varIdsIt)) { | |
863 | auto &varRequest = itVarHandler->second->m_RunningVarRequest; |
|
863 | auto &varRequest = itVarHandler->second->m_RunningVarRequest; | |
864 | var->setRange(varRequest.m_RangeRequested); |
|
864 | var->setRange(varRequest.m_RangeRequested); | |
865 | var->setCacheRange(varRequest.m_CacheRangeRequested); |
|
865 | var->setCacheRange(varRequest.m_CacheRangeRequested); | |
866 | qCDebug(LOG_VariableController()) << tr("1: onDataProvided") |
|
866 | qCDebug(LOG_VariableController()) << tr("1: onDataProvided") | |
867 | << varRequest.m_RangeRequested |
|
867 | << varRequest.m_RangeRequested | |
868 | << varRequest.m_CacheRangeRequested; |
|
868 | << varRequest.m_CacheRangeRequested; | |
869 | qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before") |
|
869 | qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before") | |
870 | << var->nbPoints() |
|
870 | << var->nbPoints() | |
871 | << varRequest.m_DataSeries->nbPoints(); |
|
871 | << varRequest.m_DataSeries->nbPoints(); | |
872 | var->mergeDataSeries(varRequest.m_DataSeries); |
|
872 | var->mergeDataSeries(varRequest.m_DataSeries); | |
873 | qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after") |
|
873 | qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after") | |
874 | << var->nbPoints(); |
|
874 | << var->nbPoints(); | |
875 |
|
875 | |||
876 | emit var->updated(); |
|
876 | emit var->updated(); | |
877 | qCDebug(LOG_VariableController()) << tr("Update OK"); |
|
877 | qCDebug(LOG_VariableController()) << tr("Update OK"); | |
878 | } |
|
878 | } | |
879 | else { |
|
879 | else { | |
880 | qCCritical(LOG_VariableController()) |
|
880 | qCCritical(LOG_VariableController()) | |
881 | << tr("Impossible to update data to a null variable"); |
|
881 | << tr("Impossible to update data to a null variable"); | |
882 | } |
|
882 | } | |
883 | } |
|
883 | } | |
884 | } |
|
884 | } | |
885 | updateVariableRequest(varRequestId); |
|
885 | updateVariableRequest(varRequestId); | |
886 |
|
886 | |||
887 | // cleaning varRequestId |
|
887 | // cleaning varRequestId | |
888 | qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId; |
|
888 | qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId; | |
889 | m_VarGroupIdToVarIds.erase(varRequestId); |
|
889 | m_VarGroupIdToVarIds.erase(varRequestId); | |
890 | if (m_VarGroupIdToVarIds.empty()) { |
|
890 | if (m_VarGroupIdToVarIds.empty()) { | |
891 | emit q->acquisitionFinished(); |
|
891 | emit q->acquisitionFinished(); | |
892 | } |
|
892 | } | |
893 | } |
|
893 | } | |
894 | } |
|
894 | } | |
895 |
|
895 | |||
896 |
|
896 | |||
897 | void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId) |
|
897 | void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId) | |
898 | { |
|
898 | { | |
899 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); |
|
899 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); | |
900 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { |
|
900 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { | |
901 | qCCritical(LOG_VariableController()) << QObject::tr( |
|
901 | qCCritical(LOG_VariableController()) << QObject::tr( | |
902 | "Impossible to updateVariableRequest since varGroupdId isn't here anymore"); |
|
902 | "Impossible to updateVariableRequest since varGroupdId isn't here anymore"); | |
903 |
|
903 | |||
904 | return; |
|
904 | return; | |
905 | } |
|
905 | } | |
906 |
|
906 | |||
907 | auto &varIds = varGroupIdToVarIdsIt->second; |
|
907 | auto &varIds = varGroupIdToVarIdsIt->second; | |
908 | auto varIdsEnd = varIds.end(); |
|
908 | auto varIdsEnd = varIds.end(); | |
909 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { |
|
909 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { | |
910 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); |
|
910 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); | |
911 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { |
|
911 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { | |
912 |
|
912 | |||
913 | auto varHandler = itVarHandler->second.get(); |
|
913 | auto varHandler = itVarHandler->second.get(); | |
914 | varHandler->m_CanUpdate = false; |
|
914 | varHandler->m_CanUpdate = false; | |
915 |
|
915 | |||
916 |
|
916 | |||
917 | switch (varHandler->m_State) { |
|
917 | switch (varHandler->m_State) { | |
918 | case VariableRequestHandlerState::OFF: { |
|
918 | case VariableRequestHandlerState::OFF: { | |
919 | qCCritical(LOG_VariableController()) |
|
919 | qCCritical(LOG_VariableController()) | |
920 | << QObject::tr("Impossible to update a variable with handler in OFF state"); |
|
920 | << QObject::tr("Impossible to update a variable with handler in OFF state"); | |
921 | } break; |
|
921 | } break; | |
922 | case VariableRequestHandlerState::RUNNING: { |
|
922 | case VariableRequestHandlerState::RUNNING: { | |
923 | varHandler->m_State = VariableRequestHandlerState::OFF; |
|
923 | varHandler->m_State = VariableRequestHandlerState::OFF; | |
924 | varHandler->m_RunningVarRequest = VariableRequest{}; |
|
924 | varHandler->m_RunningVarRequest = VariableRequest{}; | |
925 | break; |
|
925 | break; | |
926 | } |
|
926 | } | |
927 | case VariableRequestHandlerState::PENDING: { |
|
927 | case VariableRequestHandlerState::PENDING: { | |
928 | varHandler->m_State = VariableRequestHandlerState::RUNNING; |
|
928 | varHandler->m_State = VariableRequestHandlerState::RUNNING; | |
929 | varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; |
|
929 | varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; | |
930 | varHandler->m_PendingVarRequest = VariableRequest{}; |
|
930 | varHandler->m_PendingVarRequest = VariableRequest{}; | |
931 | auto var = findVariable(itVarHandler->first); |
|
931 | auto var = findVariable(itVarHandler->first); | |
932 | executeVarRequest(var, varHandler->m_RunningVarRequest); |
|
932 | executeVarRequest(var, varHandler->m_RunningVarRequest); | |
933 | updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId); |
|
933 | updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId); | |
934 | break; |
|
934 | break; | |
935 | } |
|
935 | } | |
936 | default: |
|
936 | default: | |
937 | qCCritical(LOG_VariableController()) |
|
937 | qCCritical(LOG_VariableController()) | |
938 | << QObject::tr("Unknown VariableRequestHandlerState"); |
|
938 | << QObject::tr("Unknown VariableRequestHandlerState"); | |
939 | } |
|
939 | } | |
940 | } |
|
940 | } | |
941 | } |
|
941 | } | |
942 | } |
|
942 | } | |
943 |
|
943 | |||
944 |
|
944 | |||
945 | void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId) |
|
945 | void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId) | |
946 | { |
|
946 | { | |
947 | qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId; |
|
947 | qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId; | |
948 |
|
948 | |||
949 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); |
|
949 | auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId); | |
950 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { |
|
950 | if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) { | |
951 | qCCritical(LOG_VariableController()) |
|
951 | qCCritical(LOG_VariableController()) | |
952 | << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId; |
|
952 | << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId; | |
953 | return; |
|
953 | return; | |
954 | } |
|
954 | } | |
955 |
|
955 | |||
956 | auto &varIds = varGroupIdToVarIdsIt->second; |
|
956 | auto &varIds = varGroupIdToVarIdsIt->second; | |
957 | auto varIdsEnd = varIds.end(); |
|
957 | auto varIdsEnd = varIds.end(); | |
958 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { |
|
958 | for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) { | |
959 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); |
|
959 | auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt); | |
960 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { |
|
960 | if (itVarHandler != m_VarIdToVarRequestHandler.cend()) { | |
961 |
|
961 | |||
962 | auto varHandler = itVarHandler->second.get(); |
|
962 | auto varHandler = itVarHandler->second.get(); | |
963 | varHandler->m_VarId = QUuid{}; |
|
963 | varHandler->m_VarId = QUuid{}; | |
964 | switch (varHandler->m_State) { |
|
964 | switch (varHandler->m_State) { | |
965 | case VariableRequestHandlerState::OFF: { |
|
965 | case VariableRequestHandlerState::OFF: { | |
966 | qCWarning(LOG_VariableController()) |
|
966 | qCWarning(LOG_VariableController()) | |
967 | << QObject::tr("Impossible to cancel a variable with no running request"); |
|
967 | << QObject::tr("Impossible to cancel a variable with no running request"); | |
968 | break; |
|
968 | break; | |
969 | } |
|
969 | } | |
970 | case VariableRequestHandlerState::RUNNING: { |
|
970 | case VariableRequestHandlerState::RUNNING: { | |
971 |
|
971 | |||
972 | if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { |
|
972 | if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { | |
973 | auto var = findVariable(itVarHandler->first); |
|
973 | auto var = findVariable(itVarHandler->first); | |
974 | auto varProvider = m_VariableToProviderMap.at(var); |
|
974 | auto varProvider = m_VariableToProviderMap.at(var); | |
975 | if (varProvider != nullptr) { |
|
975 | if (varProvider != nullptr) { | |
976 | m_VariableAcquisitionWorker->abortProgressRequested( |
|
976 | m_VariableAcquisitionWorker->abortProgressRequested( | |
977 | itVarHandler->first); |
|
977 | itVarHandler->first); | |
978 | } |
|
978 | } | |
979 | m_VariableModel->setDataProgress(var, 0.0); |
|
979 | m_VariableModel->setDataProgress(var, 0.0); | |
980 | varHandler->m_CanUpdate = false; |
|
980 | varHandler->m_CanUpdate = false; | |
981 | varHandler->m_State = VariableRequestHandlerState::OFF; |
|
981 | varHandler->m_State = VariableRequestHandlerState::OFF; | |
982 | varHandler->m_RunningVarRequest = VariableRequest{}; |
|
982 | varHandler->m_RunningVarRequest = VariableRequest{}; | |
983 | } |
|
983 | } | |
984 | else { |
|
984 | else { | |
985 | // TODO: log Impossible to cancel the running variable request beacause its |
|
985 | // TODO: log Impossible to cancel the running variable request beacause its | |
986 | // varRequestId isn't not the canceled one |
|
986 | // varRequestId isn't not the canceled one | |
987 | } |
|
987 | } | |
988 | break; |
|
988 | break; | |
989 | } |
|
989 | } | |
990 | case VariableRequestHandlerState::PENDING: { |
|
990 | case VariableRequestHandlerState::PENDING: { | |
991 | if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { |
|
991 | if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) { | |
992 | auto var = findVariable(itVarHandler->first); |
|
992 | auto var = findVariable(itVarHandler->first); | |
993 | auto varProvider = m_VariableToProviderMap.at(var); |
|
993 | auto varProvider = m_VariableToProviderMap.at(var); | |
994 | if (varProvider != nullptr) { |
|
994 | if (varProvider != nullptr) { | |
995 | m_VariableAcquisitionWorker->abortProgressRequested( |
|
995 | m_VariableAcquisitionWorker->abortProgressRequested( | |
996 | itVarHandler->first); |
|
996 | itVarHandler->first); | |
997 | } |
|
997 | } | |
998 | m_VariableModel->setDataProgress(var, 0.0); |
|
998 | m_VariableModel->setDataProgress(var, 0.0); | |
999 | varHandler->m_CanUpdate = false; |
|
999 | varHandler->m_CanUpdate = false; | |
1000 | varHandler->m_State = VariableRequestHandlerState::RUNNING; |
|
1000 | varHandler->m_State = VariableRequestHandlerState::RUNNING; | |
1001 | varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; |
|
1001 | varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest; | |
1002 | varHandler->m_PendingVarRequest = VariableRequest{}; |
|
1002 | varHandler->m_PendingVarRequest = VariableRequest{}; | |
1003 | executeVarRequest(var, varHandler->m_RunningVarRequest); |
|
1003 | executeVarRequest(var, varHandler->m_RunningVarRequest); | |
1004 | } |
|
1004 | } | |
1005 | else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) { |
|
1005 | else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) { | |
1006 | varHandler->m_State = VariableRequestHandlerState::RUNNING; |
|
1006 | varHandler->m_State = VariableRequestHandlerState::RUNNING; | |
1007 | varHandler->m_PendingVarRequest = VariableRequest{}; |
|
1007 | varHandler->m_PendingVarRequest = VariableRequest{}; | |
1008 | } |
|
1008 | } | |
1009 | else { |
|
1009 | else { | |
1010 | // TODO: log Impossible to cancel the variable request beacause its |
|
1010 | // TODO: log Impossible to cancel the variable request beacause its | |
1011 | // varRequestId isn't not the canceled one |
|
1011 | // varRequestId isn't not the canceled one | |
1012 | } |
|
1012 | } | |
1013 | break; |
|
1013 | break; | |
1014 | } |
|
1014 | } | |
1015 | default: |
|
1015 | default: | |
1016 | qCCritical(LOG_VariableController()) |
|
1016 | qCCritical(LOG_VariableController()) | |
1017 | << QObject::tr("Unknown VariableRequestHandlerState"); |
|
1017 | << QObject::tr("Unknown VariableRequestHandlerState"); | |
1018 | } |
|
1018 | } | |
1019 | } |
|
1019 | } | |
1020 | } |
|
1020 | } | |
1021 | qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId; |
|
1021 | qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId; | |
1022 | m_VarGroupIdToVarIds.erase(varRequestId); |
|
1022 | m_VarGroupIdToVarIds.erase(varRequestId); | |
1023 | if (m_VarGroupIdToVarIds.empty()) { |
|
1023 | if (m_VarGroupIdToVarIds.empty()) { | |
1024 | emit q->acquisitionFinished(); |
|
1024 | emit q->acquisitionFinished(); | |
1025 | } |
|
1025 | } | |
1026 | } |
|
1026 | } | |
1027 |
|
1027 | |||
1028 | void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var, |
|
1028 | void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var, | |
1029 | VariableRequest &varRequest) |
|
1029 | VariableRequest &varRequest) | |
1030 | { |
|
1030 | { | |
1031 | qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest"); |
|
1031 | qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest"); | |
1032 |
|
1032 | |||
1033 | auto varIdIt = m_VariableToIdentifierMap.find(var); |
|
1033 | auto varIdIt = m_VariableToIdentifierMap.find(var); | |
1034 | if (varIdIt == m_VariableToIdentifierMap.cend()) { |
|
1034 | if (varIdIt == m_VariableToIdentifierMap.cend()) { | |
1035 | qCWarning(LOG_VariableController()) << tr( |
|
1035 | qCWarning(LOG_VariableController()) << tr( | |
1036 | "Can't execute request of a variable that is not registered (may has been deleted)"); |
|
1036 | "Can't execute request of a variable that is not registered (may has been deleted)"); | |
1037 | return; |
|
1037 | return; | |
1038 | } |
|
1038 | } | |
1039 |
|
1039 | |||
1040 | auto varId = varIdIt->second; |
|
1040 | auto varId = varIdIt->second; | |
1041 |
|
1041 | |||
1042 | auto varCacheRange = var->cacheRange(); |
|
1042 | auto varCacheRange = var->cacheRange(); | |
1043 | auto varCacheRangeRequested = varRequest.m_CacheRangeRequested; |
|
1043 | auto varCacheRangeRequested = varRequest.m_CacheRangeRequested; | |
1044 | auto notInCacheRangeList |
|
1044 | auto notInCacheRangeList | |
1045 | = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested); |
|
1045 | = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested); | |
1046 | auto inCacheRangeList |
|
1046 | auto inCacheRangeList | |
1047 | = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested); |
|
1047 | = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested); | |
1048 |
|
1048 | |||
1049 | if (!notInCacheRangeList.empty()) { |
|
1049 | if (!notInCacheRangeList.empty()) { | |
1050 |
|
1050 | |||
1051 | auto varProvider = m_VariableToProviderMap.at(var); |
|
1051 | auto varProvider = m_VariableToProviderMap.at(var); | |
1052 | if (varProvider != nullptr) { |
|
1052 | if (varProvider != nullptr) { | |
1053 | qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested |
|
1053 | qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested | |
1054 | << varRequest.m_CacheRangeRequested; |
|
1054 | << varRequest.m_CacheRangeRequested; | |
1055 | m_VariableAcquisitionWorker->pushVariableRequest( |
|
1055 | m_VariableAcquisitionWorker->pushVariableRequest( | |
1056 | varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested, |
|
1056 | varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested, | |
1057 | varRequest.m_CacheRangeRequested, |
|
1057 | varRequest.m_CacheRangeRequested, | |
1058 | DataProviderParameters{std::move(notInCacheRangeList), var->metadata()}, |
|
1058 | DataProviderParameters{std::move(notInCacheRangeList), var->metadata()}, | |
1059 | varProvider); |
|
1059 | varProvider); | |
1060 | } |
|
1060 | } | |
1061 | else { |
|
1061 | else { | |
1062 | qCCritical(LOG_VariableController()) |
|
1062 | qCCritical(LOG_VariableController()) | |
1063 | << "Impossible to provide data with a null provider"; |
|
1063 | << "Impossible to provide data with a null provider"; | |
1064 | } |
|
1064 | } | |
1065 |
|
1065 | |||
1066 | if (!inCacheRangeList.empty()) { |
|
1066 | if (!inCacheRangeList.empty()) { | |
1067 | emit q->updateVarDisplaying(var, inCacheRangeList.first()); |
|
1067 | emit q->updateVarDisplaying(var, inCacheRangeList.first()); | |
1068 | } |
|
1068 | } | |
1069 | } |
|
1069 | } | |
1070 | else { |
|
1070 | else { | |
1071 | acceptVariableRequest(varId, |
|
1071 | acceptVariableRequest(varId, | |
1072 | var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested)); |
|
1072 | var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested)); | |
1073 | } |
|
1073 | } | |
1074 | } |
|
1074 | } | |
1075 |
|
1075 | |||
1076 | bool VariableController::VariableControllerPrivate::hasPendingDownloads() |
|
1076 | bool VariableController::VariableControllerPrivate::hasPendingDownloads() | |
1077 | { |
|
1077 | { | |
1078 | return !m_VarGroupIdToVarIds.empty(); |
|
1078 | return !m_VarGroupIdToVarIds.empty(); | |
1079 | } |
|
1079 | } | |
1080 |
|
1080 | |||
1081 | template <typename VariableIterator> |
|
1081 | template <typename VariableIterator> | |
1082 | void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt, |
|
1082 | void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt, | |
1083 | const QUuid &syncGroupId) |
|
1083 | const QUuid &syncGroupId) | |
1084 | { |
|
1084 | { | |
1085 | const auto &variable = variableIt->first; |
|
1085 | const auto &variable = variableIt->first; | |
1086 | const auto &variableId = variableIt->second; |
|
1086 | const auto &variableId = variableIt->second; | |
1087 |
|
1087 | |||
1088 | // Gets synchronization group |
|
1088 | // Gets synchronization group | |
1089 | auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId); |
|
1089 | auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId); | |
1090 | if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) { |
|
1090 | if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) { | |
1091 | qCCritical(LOG_VariableController()) |
|
1091 | qCCritical(LOG_VariableController()) | |
1092 | << tr("Can't desynchronize variable %1: unknown synchronization group") |
|
1092 | << tr("Can't desynchronize variable %1: unknown synchronization group") | |
1093 | .arg(variable->name()); |
|
1093 | .arg(variable->name()); | |
1094 | return; |
|
1094 | return; | |
1095 | } |
|
1095 | } | |
1096 |
|
1096 | |||
1097 | // Removes variable from synchronization group |
|
1097 | // Removes variable from synchronization group | |
1098 | auto synchronizationGroup = groupIt->second; |
|
1098 | auto synchronizationGroup = groupIt->second; | |
1099 | synchronizationGroup->removeVariable(variableId); |
|
1099 | synchronizationGroup->removeVariable(variableId); | |
1100 |
|
1100 | |||
1101 | // Removes link between variable and synchronization group |
|
1101 | // Removes link between variable and synchronization group | |
1102 | m_VariableIdGroupIdMap.erase(variableId); |
|
1102 | m_VariableIdGroupIdMap.erase(variableId); | |
1103 | } |
|
1103 | } |
@@ -1,139 +1,170 | |||||
1 | #include <cmath> |
|
1 | #include <cmath> | |
2 | #include <algorithm> |
|
2 | #include <algorithm> | |
3 | #include <numeric> |
|
3 | #include <numeric> | |
4 | #include <QtTest> |
|
4 | #include <QtTest> | |
5 | #include <QObject> |
|
5 | #include <QObject> | |
6 | #include <Variable/VariableController2.h> |
|
6 | #include <Variable/VariableController2.h> | |
7 | #include <Data/DateTimeRange.h> |
|
7 | #include <Data/DateTimeRange.h> | |
8 | #include <Data/IDataProvider.h> |
|
8 | #include <Data/IDataProvider.h> | |
9 | #include <Data/ScalarSeries.h> |
|
9 | #include <Data/ScalarSeries.h> | |
10 | #include <Data/DataProviderParameters.h> |
|
10 | #include <Data/DataProviderParameters.h> | |
11 | #include <Common/containers.h> |
|
11 | #include <Common/containers.h> | |
12 |
|
12 | |||
13 | template<int slope> |
|
13 | template<int slope> | |
14 | class SimpleRange: public IDataProvider |
|
14 | class SimpleRange: public IDataProvider | |
15 | { |
|
15 | { | |
16 | public: |
|
16 | public: | |
17 | SimpleRange() = default; |
|
17 | SimpleRange() = default; | |
18 |
|
18 | |||
19 | std::shared_ptr<IDataProvider> clone() const override{ return std::make_shared<SimpleRange>(); } |
|
19 | std::shared_ptr<IDataProvider> clone() const override{ return std::make_shared<SimpleRange>(); } | |
20 |
|
20 | |||
21 | IDataSeries* getData(const DataProviderParameters ¶meters) override |
|
21 | IDataSeries* getData(const DataProviderParameters ¶meters) override | |
22 | { |
|
22 | { | |
23 | auto tstart = parameters.m_Times[0].m_TStart; |
|
23 | auto tstart = parameters.m_Times[0].m_TStart; | |
24 | auto tend = parameters.m_Times[0].m_TEnd; |
|
24 | auto tend = parameters.m_Times[0].m_TEnd; | |
25 | std::vector<double> x; |
|
25 | std::vector<double> x; | |
26 | std::vector<double> y; |
|
26 | std::vector<double> y; | |
27 | for(auto i = tstart;i<tend;i+=1.) //1 seconde data resolution |
|
27 | for(auto i = tstart;i<tend;i+=1.) //1 seconde data resolution | |
28 | { |
|
28 | { | |
29 | x.push_back(i); |
|
29 | x.push_back(i); | |
30 | y.push_back(i*slope); |
|
30 | y.push_back(i*slope); | |
31 | } |
|
31 | } | |
32 | auto serie = new ScalarSeries(std::move(x),std::move(y),Unit("Secondes",true),Unit("Volts",false)); |
|
32 | auto serie = new ScalarSeries(std::move(x),std::move(y),Unit("Secondes",true),Unit("Volts",false)); | |
33 | return serie; |
|
33 | return serie; | |
34 | } |
|
34 | } | |
35 |
|
35 | |||
36 |
|
36 | |||
37 |
|
37 | |||
38 | void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters ¶meters) override |
|
38 | void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters ¶meters) override | |
39 | { |
|
39 | { | |
40 | Q_UNUSED(acqIdentifier) |
|
40 | Q_UNUSED(acqIdentifier) | |
41 | Q_UNUSED(parameters) |
|
41 | Q_UNUSED(parameters) | |
42 | } |
|
42 | } | |
43 |
|
43 | |||
44 | void requestDataAborting(QUuid acqIdentifier) override |
|
44 | void requestDataAborting(QUuid acqIdentifier) override | |
45 | { |
|
45 | { | |
46 | Q_UNUSED(acqIdentifier) |
|
46 | Q_UNUSED(acqIdentifier) | |
47 | } |
|
47 | } | |
48 |
|
48 | |||
49 | }; |
|
49 | }; | |
50 |
|
50 | |||
51 |
|
51 | |||
52 | template <class T> |
|
52 | template <class T> | |
53 | auto sumdiff(T begin, T end) |
|
53 | auto sumdiff(T begin, T end) | |
54 | { |
|
54 | { | |
55 | std::vector<double> diff_vect(end-begin-1); |
|
55 | std::vector<double> diff_vect(end-begin-1); | |
56 | auto diff = [](auto next,auto item) |
|
56 | auto diff = [](auto next,auto item) | |
57 | { |
|
57 | { | |
58 | return next.value() - item.value(); |
|
58 | return next.value() - item.value(); | |
59 | }; |
|
59 | }; | |
60 | std::transform (begin+1, end, begin, diff_vect.begin(),diff); |
|
60 | std::transform (begin+1, end, begin, diff_vect.begin(),diff); | |
61 | return std::accumulate(diff_vect.cbegin(), diff_vect.cend(), 0); |
|
61 | return std::accumulate(diff_vect.cbegin(), diff_vect.cend(), 0); | |
62 | } |
|
62 | } | |
63 |
|
63 | |||
64 | template <int slope=1> |
|
64 | template <int slope=1> | |
65 | struct RangeType |
|
65 | struct RangeType | |
66 | { |
|
66 | { | |
67 | static void check_properties(std::shared_ptr<Variable> v, DateTimeRange r) |
|
67 | static void check_properties(std::shared_ptr<Variable> v, DateTimeRange r) | |
68 | { |
|
68 | { | |
69 | auto s = sumdiff(v->dataSeries()->cbegin(), v->dataSeries()->cend()) / slope; |
|
69 | auto bounds = v->dataSeries()->valuesBounds(r.m_TStart, r.m_TEnd); | |
70 | QCOMPARE(v->nbPoints(), int(s)+1); |
|
70 | auto s = sumdiff(bounds.first, bounds.second) / slope; | |
71 | QCOMPARE(r.m_TStart, v->dataSeries()->begin()->value()/slope); |
|
71 | auto nbpoints = bounds.second - bounds.first+1.; | |
|
72 | QCOMPARE(nbpoints, int(s)+2);//<- @TODO weird has to be investigated why +2? | |||
|
73 | QCOMPARE(r.m_TStart, bounds.first->value()/slope); | |||
72 | } |
|
74 | } | |
73 | }; |
|
75 | }; | |
74 |
|
76 | |||
75 | template <class T> |
|
77 | template <class T> | |
76 | void check_variable_state(std::shared_ptr<Variable> v, DateTimeRange r) |
|
78 | void check_variable_state(std::shared_ptr<Variable> v, DateTimeRange r) | |
77 | { |
|
79 | { | |
78 | QCOMPARE(v->nbPoints(), int(r.delta())); |
|
80 | auto bounds = v->dataSeries()->valuesBounds(r.m_TStart, r.m_TEnd); | |
|
81 | auto nbpoints = bounds.second - bounds.first+1.; | |||
|
82 | QCOMPARE(nbpoints, int(static_cast<double>(r.delta()))); | |||
79 | T::check_properties(v,r); |
|
83 | T::check_properties(v,r); | |
80 | } |
|
84 | } | |
81 |
|
85 | |||
82 | class TestVariableController2 : public QObject |
|
86 | class TestVariableController2 : public QObject | |
83 | { |
|
87 | { | |
84 | Q_OBJECT |
|
88 | Q_OBJECT | |
85 | public: |
|
89 | public: | |
86 | explicit TestVariableController2(QObject *parent = nullptr) : QObject(parent){} |
|
90 | explicit TestVariableController2(QObject *parent = nullptr) : QObject(parent){} | |
87 | signals: |
|
91 | signals: | |
88 |
|
92 | |||
89 | private slots: |
|
93 | private slots: | |
90 | void initTestCase(){} |
|
94 | void initTestCase(){} | |
91 | void cleanupTestCase(){} |
|
95 | void cleanupTestCase(){} | |
92 |
|
96 | |||
93 | void testCreateVariable() |
|
97 | void testCreateVariable() | |
94 | { |
|
98 | { | |
95 | VariableController2 vc; |
|
99 | VariableController2 vc; | |
96 | bool callbackCalled = false; |
|
100 | bool callbackCalled = false; | |
97 | connect(&vc,&VariableController2::variableAdded, [&callbackCalled](std::shared_ptr<Variable>){callbackCalled=true;}); |
|
101 | connect(&vc,&VariableController2::variableAdded, [&callbackCalled](std::shared_ptr<Variable>){callbackCalled=true;}); | |
98 | auto provider = std::make_shared<SimpleRange<1>>(); |
|
102 | auto provider = std::make_shared<SimpleRange<1>>(); | |
99 | QVERIFY(!callbackCalled); |
|
103 | QVERIFY(!callbackCalled); | |
100 | auto var1 = vc.createVariable("var1",{},provider,DateTimeRange()); |
|
104 | auto var1 = vc.createVariable("var1",{},provider,DateTimeRange()); | |
101 | QVERIFY(SciQLop::containers::contains(vc.variables(), var1)); |
|
105 | QVERIFY(SciQLop::containers::contains(vc.variables(), var1)); | |
102 | QVERIFY(callbackCalled); |
|
106 | QVERIFY(callbackCalled); | |
103 | } |
|
107 | } | |
104 |
|
108 | |||
105 | void testDeleteVariable() |
|
109 | void testDeleteVariable() | |
106 | { |
|
110 | { | |
107 | VariableController2 vc; |
|
111 | VariableController2 vc; | |
108 | bool callbackCalled = false; |
|
112 | bool callbackCalled = false; | |
109 | connect(&vc,&VariableController2::variableDeleted, [&callbackCalled](std::shared_ptr<Variable>){callbackCalled=true;}); |
|
113 | connect(&vc,&VariableController2::variableDeleted, [&callbackCalled](std::shared_ptr<Variable>){callbackCalled=true;}); | |
110 | auto provider = std::make_shared<SimpleRange<1>>(); |
|
114 | auto provider = std::make_shared<SimpleRange<1>>(); | |
111 | auto var1 = vc.createVariable("var1",{},provider,DateTimeRange()); |
|
115 | auto var1 = vc.createVariable("var1",{},provider,DateTimeRange()); | |
112 | QVERIFY(SciQLop::containers::contains(vc.variables(), var1)); |
|
116 | QVERIFY(SciQLop::containers::contains(vc.variables(), var1)); | |
113 | QVERIFY(!callbackCalled); |
|
117 | QVERIFY(!callbackCalled); | |
114 | vc.deleteVariable(var1); |
|
118 | vc.deleteVariable(var1); | |
115 | QVERIFY(!SciQLop::containers::contains(vc.variables(), var1)); |
|
119 | QVERIFY(!SciQLop::containers::contains(vc.variables(), var1)); | |
116 | QVERIFY(callbackCalled); |
|
120 | QVERIFY(callbackCalled); | |
117 | } |
|
121 | } | |
118 |
|
122 | |||
119 | void testGetData() |
|
123 | void testGetData() | |
120 | { |
|
124 | { | |
121 | VariableController2 vc; |
|
125 | VariableController2 vc; | |
122 | auto provider = std::make_shared<SimpleRange<10>>(); |
|
126 | auto provider = std::make_shared<SimpleRange<10>>(); | |
123 |
auto range |
|
127 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00), | |
124 | QDate(2018,8,7),QTime(16,00)); |
|
128 | QDate(2018,8,7),QTime(16,00)); | |
125 | auto range2 = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(12,00), |
|
129 | ||
126 | QDate(2018,8,7),QTime(18,00)); |
|
130 | auto var1 = vc.createVariable("var1", {}, provider, range); | |
127 | auto var1 = vc.createVariable("var1", {}, provider, range1); |
|
131 | check_variable_state<RangeType<10>>(var1, range); | |
128 | check_variable_state<RangeType<10>>(var1, range1); |
|
132 | } | |
129 | vc.changeRange(var1, range2); |
|
133 | ||
130 | check_variable_state<RangeType<10>>(var1, range2); |
|
134 | void testZoomOut() | |
|
135 | { | |||
|
136 | VariableController2 vc; | |||
|
137 | auto provider = std::make_shared<SimpleRange<10>>(); | |||
|
138 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00), | |||
|
139 | QDate(2018,8,7),QTime(16,00)); | |||
|
140 | ||||
|
141 | auto var1 = vc.createVariable("var1", {}, provider, range); | |||
|
142 | check_variable_state<RangeType<10>>(var1, range); | |||
|
143 | ||||
|
144 | range *=2.; | |||
|
145 | vc.changeRange(var1, range); | |||
|
146 | check_variable_state<RangeType<10>>(var1, range); | |||
|
147 | } | |||
|
148 | ||||
|
149 | void testPanRight() | |||
|
150 | { | |||
|
151 | VariableController2 vc; | |||
|
152 | auto provider = std::make_shared<SimpleRange<10>>(); | |||
|
153 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00), | |||
|
154 | QDate(2018,8,7),QTime(16,00)); | |||
|
155 | ||||
|
156 | auto var1 = vc.createVariable("var1", {}, provider, range); | |||
|
157 | check_variable_state<RangeType<10>>(var1, range); | |||
|
158 | ||||
|
159 | range += Seconds<double>{1000.}; | |||
|
160 | vc.changeRange(var1, range); | |||
|
161 | check_variable_state<RangeType<10>>(var1, range); | |||
131 | } |
|
162 | } | |
132 |
|
163 | |||
133 | }; |
|
164 | }; | |
134 |
|
165 | |||
135 |
|
166 | |||
136 | QTEST_MAIN(TestVariableController2) |
|
167 | QTEST_MAIN(TestVariableController2) | |
137 |
|
168 | |||
138 | #include "TestVariableController2.moc" |
|
169 | #include "TestVariableController2.moc" | |
139 |
|
170 |
General Comments 0
You need to be logged in to leave comments.
Login now