1 | // |
---|
2 | // You received this file as part of RRLib |
---|
3 | // Robotics Research Library |
---|
4 | // |
---|
5 | // Copyright (C) Finroc GbR (finroc.org) |
---|
6 | // |
---|
7 | // This program is free software; you can redistribute it and/or modify |
---|
8 | // it under the terms of the GNU General Public License as published by |
---|
9 | // the Free Software Foundation; either version 2 of the License, or |
---|
10 | // (at your option) any later version. |
---|
11 | // |
---|
12 | // This program is distributed in the hope that it will be useful, |
---|
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | // GNU General Public License for more details. |
---|
16 | // |
---|
17 | // You should have received a copy of the GNU General Public License along |
---|
18 | // with this program; if not, write to the Free Software Foundation, Inc., |
---|
19 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
---|
20 | // |
---|
21 | //---------------------------------------------------------------------- |
---|
22 | /*!\file rrlib/rtti_conversion/tConversionOperationSequence.cpp |
---|
23 | * |
---|
24 | * \author Max Reichardt |
---|
25 | * |
---|
26 | * \date 2016-07-31 |
---|
27 | * |
---|
28 | */ |
---|
29 | //---------------------------------------------------------------------- |
---|
30 | #include "rrlib/rtti_conversion/tConversionOperationSequence.h" |
---|
31 | |
---|
32 | //---------------------------------------------------------------------- |
---|
33 | // External includes (system with <>, local with "") |
---|
34 | //---------------------------------------------------------------------- |
---|
35 | |
---|
36 | //---------------------------------------------------------------------- |
---|
37 | // Internal includes with "" |
---|
38 | //---------------------------------------------------------------------- |
---|
39 | #include "rrlib/rtti_conversion/tCompiledConversionOperation.h" |
---|
40 | #include "rrlib/rtti_conversion/tStaticCastOperation.h" |
---|
41 | |
---|
42 | //---------------------------------------------------------------------- |
---|
43 | // Debugging |
---|
44 | //---------------------------------------------------------------------- |
---|
45 | #include <cassert> |
---|
46 | |
---|
47 | //---------------------------------------------------------------------- |
---|
48 | // Namespace usage |
---|
49 | //---------------------------------------------------------------------- |
---|
50 | |
---|
51 | //---------------------------------------------------------------------- |
---|
52 | // Namespace declaration |
---|
53 | //---------------------------------------------------------------------- |
---|
54 | namespace rrlib |
---|
55 | { |
---|
56 | namespace rtti |
---|
57 | { |
---|
58 | namespace conversion |
---|
59 | { |
---|
60 | |
---|
61 | //---------------------------------------------------------------------- |
---|
62 | // Forward declarations / typedefs / enums |
---|
63 | //---------------------------------------------------------------------- |
---|
64 | |
---|
65 | //---------------------------------------------------------------------- |
---|
66 | // Const values |
---|
67 | //---------------------------------------------------------------------- |
---|
68 | |
---|
69 | const tConversionOperationSequence tConversionOperationSequence::cNONE; |
---|
70 | const tTypedConstPointer tConversionOperationSequence::cNO_PARAMETER_VALUE; |
---|
71 | |
---|
72 | /*! Enum for binary serialization */ |
---|
73 | enum tOperationSerializationFlags : uint8_t { cFULL_OPERATION = 1, cPARAMETER = 2, cSTRING_PARAMETER = 4 }; |
---|
74 | |
---|
75 | //---------------------------------------------------------------------- |
---|
76 | // Implementation |
---|
77 | //---------------------------------------------------------------------- |
---|
78 | |
---|
79 | namespace |
---|
80 | { |
---|
81 | |
---|
82 | struct tConversionOptionWithOrigin : tConversionOption |
---|
83 | { |
---|
84 | const tRegisteredConversionOperation* origin; |
---|
85 | |
---|
86 | tConversionOptionWithOrigin(const tRegisteredConversionOperation* origin = nullptr, const tConversionOption& option = tConversionOption()) : |
---|
87 | tConversionOption(option), |
---|
88 | origin(origin) |
---|
89 | { |
---|
90 | } |
---|
91 | |
---|
92 | void Set(const tRegisteredConversionOperation* origin, const tConversionOption& option) |
---|
93 | { |
---|
94 | this->origin = origin; |
---|
95 | static_cast<tConversionOption&>(*this) = option; |
---|
96 | } |
---|
97 | }; |
---|
98 | |
---|
99 | tConversionOptionWithOrigin GetConversionOption(const tRegisteredConversionOperation* operation, const tType& source_type, const tType& destination_type, const tGenericObject* parameter) |
---|
100 | { |
---|
101 | return tConversionOptionWithOrigin(operation, operation->GetConversionOption(source_type, destination_type, parameter)); |
---|
102 | } |
---|
103 | |
---|
104 | tConversionOptionWithOrigin GetImplicitConversionOption(const tType& source_type, const tType& destination_type) |
---|
105 | { |
---|
106 | return tConversionOptionWithOrigin(&tStaticCastOperation::GetInstance(), tStaticCastOperation::GetImplicitConversionOption(source_type, destination_type)); |
---|
107 | } |
---|
108 | |
---|
109 | } |
---|
110 | |
---|
111 | tConversionOperationSequence::tConversionOperationSequence(const std::string& first, const std::string& second, const tType& intermediate_type) : |
---|
112 | operations {nullptr, nullptr}, |
---|
113 | ambiguous_operation_lookup {false, false}, |
---|
114 | intermediate_type(intermediate_type) |
---|
115 | { |
---|
116 | auto find_result = tRegisteredConversionOperation::Find(first); |
---|
117 | operations[0].operation = find_result.first; |
---|
118 | ambiguous_operation_lookup[0] = find_result.second; |
---|
119 | if (operations[0].operation == nullptr) |
---|
120 | { |
---|
121 | throw std::runtime_error("Could not find registered conversion operation with name: " + first); |
---|
122 | } |
---|
123 | if (second.length()) |
---|
124 | { |
---|
125 | find_result = tRegisteredConversionOperation::Find(second); |
---|
126 | operations[1].operation = find_result.first; |
---|
127 | ambiguous_operation_lookup[1] = find_result.second; |
---|
128 | if (operations[1].operation == nullptr) |
---|
129 | { |
---|
130 | throw std::runtime_error("Could not find registered conversion operation with name: " + second); |
---|
131 | } |
---|
132 | } |
---|
133 | } |
---|
134 | |
---|
135 | tConversionOperationSequence& tConversionOperationSequence::operator=(const tConversionOperationSequence & other) |
---|
136 | { |
---|
137 | operations[0].operation = other.operations[0].operation; |
---|
138 | operations[1].operation = other.operations[1].operation; |
---|
139 | CopyParameter(other.operations[0].parameter ? *other.operations[0].parameter : tTypedConstPointer(), operations[0].parameter); |
---|
140 | CopyParameter(other.operations[1].parameter ? *other.operations[1].parameter : tTypedConstPointer(), operations[1].parameter); |
---|
141 | memcpy(ambiguous_operation_lookup, other.ambiguous_operation_lookup, sizeof(ambiguous_operation_lookup)); |
---|
142 | intermediate_type = other.intermediate_type; |
---|
143 | return *this; |
---|
144 | } |
---|
145 | |
---|
146 | tCompiledConversionOperation tConversionOperationSequence::Compile(bool allow_reference_to_source, const tType& source_type, const tType& destination_type) const |
---|
147 | { |
---|
148 | // ############ |
---|
149 | // Resolve any ambiguous conversion operations |
---|
150 | // ############ |
---|
151 | const tRegisteredConversionOperation* first_operation = operations[0].operation; |
---|
152 | if (first_operation && ambiguous_operation_lookup[0]) |
---|
153 | { |
---|
154 | first_operation = &tRegisteredConversionOperation::Find(first_operation->Name(), source_type, Size() == 2 ? intermediate_type : destination_type); |
---|
155 | } |
---|
156 | const tRegisteredConversionOperation* second_operation = operations[1].operation; |
---|
157 | if (second_operation && ambiguous_operation_lookup[1]) |
---|
158 | { |
---|
159 | if (first_operation == &cFOR_EACH_OPERATION) |
---|
160 | { |
---|
161 | second_operation = &tRegisteredConversionOperation::Find(second_operation->Name(), intermediate_type, destination_type.GetElementType()); |
---|
162 | } |
---|
163 | else |
---|
164 | { |
---|
165 | second_operation = &tRegisteredConversionOperation::Find(second_operation->Name(), intermediate_type, destination_type); |
---|
166 | } |
---|
167 | } |
---|
168 | |
---|
169 | // ############ |
---|
170 | // Infer conversion options |
---|
171 | // This includes adding implicit conversions if less than two registered conversions are in chain |
---|
172 | // ############ |
---|
173 | |
---|
174 | // Infer any undefined types |
---|
175 | tType type_source = source_type; |
---|
176 | tType type_destination = destination_type; |
---|
177 | tType type_intermediate = this->intermediate_type; |
---|
178 | if (!type_source) |
---|
179 | { |
---|
180 | type_source = first_operation && (!first_operation->SupportedSourceTypes().applies_to_underlying_types) ? first_operation->SupportedSourceTypes().single_type : tType(); |
---|
181 | } |
---|
182 | if (!type_source) |
---|
183 | { |
---|
184 | throw std::runtime_error("Source type must be specified"); |
---|
185 | } |
---|
186 | const tRegisteredConversionOperation* last_operation = second_operation ? second_operation : first_operation; |
---|
187 | if (!type_destination) |
---|
188 | { |
---|
189 | type_destination = last_operation && (!last_operation->SupportedDestinationTypes().applies_to_underlying_types) ? last_operation->SupportedDestinationTypes().single_type : tType(); |
---|
190 | } |
---|
191 | if (!type_destination) |
---|
192 | { |
---|
193 | throw std::runtime_error("Destination type must be specified"); |
---|
194 | } |
---|
195 | if ((!type_intermediate) && second_operation) |
---|
196 | { |
---|
197 | std::vector<rrlib::rtti::tType> intermediate_type_candidates_operation_1 = first_operation->SupportedDestinationTypes(type_source); |
---|
198 | std::vector<rrlib::rtti::tType> intermediate_type_candidates_operation_2 = first_operation->SupportedSourceTypes(type_destination); |
---|
199 | size_t candidate_count = 0; |
---|
200 | for (auto & candidate1 : intermediate_type_candidates_operation_1) |
---|
201 | { |
---|
202 | for (auto & candidate2 : intermediate_type_candidates_operation_2) |
---|
203 | { |
---|
204 | if (candidate1 == candidate2) |
---|
205 | { |
---|
206 | type_intermediate = candidate1; |
---|
207 | candidate_count++; |
---|
208 | } |
---|
209 | } |
---|
210 | } |
---|
211 | |
---|
212 | if (candidate_count != 1) |
---|
213 | { |
---|
214 | throw std::runtime_error("Intermediate type must be specified (" + std::to_string(candidate_count) + " candidates)"); |
---|
215 | } |
---|
216 | } |
---|
217 | |
---|
218 | // Variables for result |
---|
219 | tConversionOptionWithOrigin temp_conversion_option_1, temp_conversion_option_2; |
---|
220 | const tConversionOptionWithOrigin* conversion1 = nullptr; |
---|
221 | const tConversionOptionWithOrigin* conversion2 = nullptr; |
---|
222 | |
---|
223 | // No conversion operation specified: Look for implicit cast |
---|
224 | if ((!first_operation)) |
---|
225 | { |
---|
226 | if (type_source == type_destination) |
---|
227 | { |
---|
228 | temp_conversion_option_1.Set(nullptr, tConversionOption(type_source, type_destination, 0)); |
---|
229 | conversion1 = &temp_conversion_option_1; |
---|
230 | } |
---|
231 | else |
---|
232 | { |
---|
233 | auto implicit_conversion = tStaticCastOperation::GetImplicitConversionOptions(type_source, type_destination); |
---|
234 | if (implicit_conversion.first.type == tConversionOptionType::NONE) |
---|
235 | { |
---|
236 | throw std::runtime_error("Type " + source_type.GetName() + " cannot be implicitly casted to " + destination_type.GetName()); |
---|
237 | } |
---|
238 | temp_conversion_option_1.Set(&tStaticCastOperation::GetInstance(), implicit_conversion.first); |
---|
239 | conversion1 = &temp_conversion_option_1; |
---|
240 | if (implicit_conversion.second.type != tConversionOptionType::NONE) |
---|
241 | { |
---|
242 | temp_conversion_option_2.Set(&tStaticCastOperation::GetInstance(), implicit_conversion.second); |
---|
243 | conversion2 = &temp_conversion_option_2; |
---|
244 | } |
---|
245 | } |
---|
246 | } |
---|
247 | |
---|
248 | // For each operation |
---|
249 | else if (first_operation == &cFOR_EACH_OPERATION) |
---|
250 | { |
---|
251 | rrlib::rtti::tType internal_type_source = type_source; |
---|
252 | while (internal_type_source && (!(internal_type_source.IsListType() || internal_type_source.IsArray()))) |
---|
253 | { |
---|
254 | internal_type_source = tRegisteredConversionOperation::GetUnderlyingTypeOperationsAreInheritedFrom(internal_type_source); |
---|
255 | } |
---|
256 | rrlib::rtti::tType internal_type_destination = type_destination; |
---|
257 | while (internal_type_destination && (!(internal_type_destination.IsListType() || internal_type_destination.IsArray()))) |
---|
258 | { |
---|
259 | internal_type_destination = tRegisteredConversionOperation::GetUnderlyingTypeOperationsAreInheritedFrom(internal_type_destination); |
---|
260 | } |
---|
261 | |
---|
262 | if ((!internal_type_source) || (!internal_type_destination)) |
---|
263 | { |
---|
264 | throw std::runtime_error("ForEach operation only applicable on list types and array types"); |
---|
265 | } |
---|
266 | if (!second_operation) |
---|
267 | { |
---|
268 | temp_conversion_option_2 = GetImplicitConversionOption(internal_type_source.GetElementType(), internal_type_destination.GetElementType()); |
---|
269 | if (temp_conversion_option_2.type == tConversionOptionType::NONE) |
---|
270 | { |
---|
271 | throw std::runtime_error("Type " + internal_type_source.GetElementType().GetName() + " cannot be implicitly casted to " + internal_type_destination.GetElementType().GetName() + ". Second operation for ForEach must be specified."); |
---|
272 | } |
---|
273 | } |
---|
274 | else |
---|
275 | { |
---|
276 | temp_conversion_option_2 = GetConversionOption(second_operation, internal_type_source.GetElementType(), internal_type_destination.GetElementType(), operations[1].parameter.get()); |
---|
277 | if (temp_conversion_option_2.type == tConversionOptionType::NONE) |
---|
278 | { |
---|
279 | throw std::runtime_error("Type " + source_type.GetElementType().GetName() + " cannot be converted to " + destination_type.GetElementType().GetName() + " with the selected operations."); |
---|
280 | } |
---|
281 | } |
---|
282 | conversion2 = &temp_conversion_option_2; |
---|
283 | temp_conversion_option_1 = GetConversionOption(first_operation, type_source, type_destination, operations[0].parameter.get()); |
---|
284 | conversion1 = &temp_conversion_option_1; |
---|
285 | } |
---|
286 | |
---|
287 | // Two conversion operations specified: Check types |
---|
288 | else if (second_operation) |
---|
289 | { |
---|
290 | temp_conversion_option_1 = GetConversionOption(first_operation, type_source, type_intermediate, operations[0].parameter.get()); |
---|
291 | temp_conversion_option_2 = GetConversionOption(second_operation, type_intermediate, type_destination, operations[1].parameter.get()); |
---|
292 | if (temp_conversion_option_1.type != tConversionOptionType::NONE && temp_conversion_option_2.type != tConversionOptionType::NONE) |
---|
293 | { |
---|
294 | conversion1 = &temp_conversion_option_1; |
---|
295 | conversion2 = &temp_conversion_option_2; |
---|
296 | } |
---|
297 | } |
---|
298 | |
---|
299 | // One conversion option specified: Is it enough - or do we need additional implicit cast? |
---|
300 | else |
---|
301 | { |
---|
302 | temp_conversion_option_1 = GetConversionOption(first_operation, type_source, type_destination, operations[0].parameter.get()); |
---|
303 | if (temp_conversion_option_1.type != tConversionOptionType::NONE) |
---|
304 | { |
---|
305 | conversion1 = &temp_conversion_option_1; |
---|
306 | } |
---|
307 | else |
---|
308 | { |
---|
309 | // Try implicit cast as second |
---|
310 | if (tRegisteredConversionOperation::InheritsOperationsFrom(first_operation->SupportedSourceTypes().single_type, type_source) && ((first_operation->SupportedDestinationTypes().single_type && (!first_operation->SupportedDestinationTypes().applies_to_underlying_types)) || type_intermediate)) |
---|
311 | { |
---|
312 | type_intermediate = type_intermediate ? type_intermediate : first_operation->SupportedDestinationTypes().single_type; |
---|
313 | temp_conversion_option_1 = GetConversionOption(first_operation, type_source, type_intermediate, operations[0].parameter.get()); |
---|
314 | temp_conversion_option_2 = GetImplicitConversionOption(type_intermediate, type_destination); |
---|
315 | } |
---|
316 | else if (((first_operation->SupportedSourceTypes().single_type && (!first_operation->SupportedSourceTypes().applies_to_underlying_types)) || type_intermediate) && tRegisteredConversionOperation::InheritsOperationsFrom(first_operation->SupportedDestinationTypes().single_type, destination_type)) |
---|
317 | { |
---|
318 | type_intermediate = type_intermediate ? type_intermediate : first_operation->SupportedSourceTypes().single_type; |
---|
319 | temp_conversion_option_1 = GetImplicitConversionOption(type_source, type_intermediate); |
---|
320 | temp_conversion_option_2 = GetConversionOption(first_operation, type_intermediate, type_destination, operations[1].parameter.get()); |
---|
321 | } |
---|
322 | if (temp_conversion_option_1.type == tConversionOptionType::NONE && (!intermediate_type)) |
---|
323 | { |
---|
324 | RRLIB_LOG_PRINT(DEBUG_VERBOSE_1, "Attempting to resolve intermediate type for ambiguous cast from ", type_source, " to ", type_destination, " with operation ", first_operation->Name()); |
---|
325 | std::vector<tType> from_source_options = first_operation->SupportedDestinationTypes(source_type); |
---|
326 | std::vector<tType> to_destination_options = first_operation->SupportedSourceTypes(destination_type); |
---|
327 | int combinations_found = 0; |
---|
328 | for (auto & type : from_source_options) |
---|
329 | { |
---|
330 | auto implicit_option = GetImplicitConversionOption(type, type_destination); |
---|
331 | if (implicit_option.type != tConversionOptionType::NONE) |
---|
332 | { |
---|
333 | combinations_found++; |
---|
334 | type_intermediate = type; |
---|
335 | temp_conversion_option_1 = GetConversionOption(first_operation, type_source, type_intermediate, operations[0].parameter.get()); |
---|
336 | temp_conversion_option_2 = GetImplicitConversionOption(type_intermediate, type_destination); |
---|
337 | } |
---|
338 | } |
---|
339 | for (auto & type : to_destination_options) |
---|
340 | { |
---|
341 | auto implicit_option = GetImplicitConversionOption(type_source, type); |
---|
342 | if (implicit_option.type != tConversionOptionType::NONE) |
---|
343 | { |
---|
344 | combinations_found++; |
---|
345 | type_intermediate = type; |
---|
346 | temp_conversion_option_1 = GetImplicitConversionOption(type_source, type_intermediate); |
---|
347 | temp_conversion_option_2 = GetConversionOption(first_operation, type_intermediate, type_destination, operations[1].parameter.get()); |
---|
348 | } |
---|
349 | } |
---|
350 | if (combinations_found > 1) |
---|
351 | { |
---|
352 | std::stringstream error_message; |
---|
353 | error_message << "Found " << combinations_found << " variants to convert " << type_source << " to " << type_destination << " with operation " << first_operation->Name() << " and an implicit cast"; |
---|
354 | if (combinations_found) |
---|
355 | { |
---|
356 | error_message << ". Intermediate type must be specified"; |
---|
357 | } |
---|
358 | RRLIB_LOG_PRINT(DEBUG_VERBOSE_1, error_message.str()); |
---|
359 | throw std::runtime_error(error_message.str()); |
---|
360 | } |
---|
361 | else if (combinations_found == 1) |
---|
362 | { |
---|
363 | RRLIB_LOG_PRINT(DEBUG_VERBOSE_1, "Resolved intermediate type ", temp_conversion_option_1.destination_type, " in cast from ", type_source, " to ", type_destination, " with operation ", first_operation->Name(), " and an implicit cast (", from_source_options.size(), " options from source; ", to_destination_options.size(), " to destination)"); |
---|
364 | } |
---|
365 | else |
---|
366 | { |
---|
367 | RRLIB_LOG_PRINT(DEBUG_VERBOSE_1, "Not found"); |
---|
368 | } |
---|
369 | } |
---|
370 | |
---|
371 | if (temp_conversion_option_1.type != tConversionOptionType::NONE && temp_conversion_option_2.type != tConversionOptionType::NONE) |
---|
372 | { |
---|
373 | conversion1 = &temp_conversion_option_1; |
---|
374 | conversion2 = &temp_conversion_option_2; |
---|
375 | } |
---|
376 | else |
---|
377 | { |
---|
378 | throw std::runtime_error("Intermediate type must be specified"); |
---|
379 | } |
---|
380 | } |
---|
381 | } |
---|
382 | if (!conversion1) |
---|
383 | { |
---|
384 | throw std::runtime_error("Type " + source_type.GetName() + " cannot be casted to " + destination_type.GetName() + " with the selected operations"); |
---|
385 | } |
---|
386 | |
---|
387 | |
---|
388 | // ############ |
---|
389 | // Compile conversion operation from conversion options |
---|
390 | // ############ |
---|
391 | typedef tCompiledConversionOperation::tFlag tFlag; |
---|
392 | assert(conversion1); |
---|
393 | const tConversionOptionWithOrigin* last_conversion = conversion2 ? conversion2 : conversion1; |
---|
394 | |
---|
395 | // Do some sanity checks |
---|
396 | if ((conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT && conversion1->const_offset_reference_to_source_object > std::numeric_limits<unsigned int>::max() / 2) || |
---|
397 | (last_conversion->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT && last_conversion->const_offset_reference_to_source_object > std::numeric_limits<unsigned int>::max() / 2)) |
---|
398 | { |
---|
399 | throw std::runtime_error("Invalid fixed offset in conversion option"); |
---|
400 | } |
---|
401 | |
---|
402 | // Prepare result |
---|
403 | tCompiledConversionOperation result; |
---|
404 | result.operations[0].operation = first_operation; |
---|
405 | result.operations[1].operation = second_operation; |
---|
406 | result.destination_type = last_conversion->destination_type; |
---|
407 | static_cast<tConversionOperationSequence&>(result).intermediate_type = this->intermediate_type; |
---|
408 | |
---|
409 | // Handle special case: only const offsets |
---|
410 | if (conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT && last_conversion->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
411 | { |
---|
412 | result.type_after_first_fixed_offset = result.destination_type; |
---|
413 | result.intermediate_type = result.destination_type; |
---|
414 | result.fixed_offset_first = static_cast<unsigned int>(conversion1->const_offset_reference_to_source_object + (conversion2 ? conversion2->const_offset_reference_to_source_object : 0)); |
---|
415 | result.flags = tFlag::cRESULT_INDEPENDENT | tFlag::cRESULT_REFERENCES_SOURCE_DIRECTLY | tFlag::cDEEPCOPY_ONLY; |
---|
416 | } |
---|
417 | else |
---|
418 | { |
---|
419 | // Handle cases where first operation is const offset |
---|
420 | bool first_op_is_const_offset = conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT; |
---|
421 | result.type_after_first_fixed_offset = first_op_is_const_offset ? conversion1->destination_type : conversion1->source_type; |
---|
422 | if (first_op_is_const_offset) |
---|
423 | { |
---|
424 | result.fixed_offset_first = static_cast<unsigned int>(conversion1->const_offset_reference_to_source_object); |
---|
425 | |
---|
426 | // first operation is done, so move second to first |
---|
427 | conversion1 = nullptr; |
---|
428 | std::swap(conversion1, conversion2); |
---|
429 | result.flags |= tFlag::cFIRST_OPERATION_OPTIMIZED_AWAY; |
---|
430 | } |
---|
431 | result.intermediate_type = conversion1->destination_type; |
---|
432 | |
---|
433 | // Single operation REFERENCES_SOURCE |
---|
434 | if (conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT && (!conversion2)) |
---|
435 | { |
---|
436 | result.conversion_function_first = allow_reference_to_source ? conversion1->final_conversion_function : conversion1->first_conversion_function; |
---|
437 | result.flags = allow_reference_to_source ? tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY : (tFlag::cRESULT_INDEPENDENT | tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION); |
---|
438 | } |
---|
439 | // First operation is standard or REFERENCES_SOURCE |
---|
440 | else if (conversion1->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION || conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT) |
---|
441 | { |
---|
442 | result.conversion_function_first = conversion2 ? conversion1->first_conversion_function : conversion1->final_conversion_function; |
---|
443 | result.flags = tFlag::cRESULT_INDEPENDENT; |
---|
444 | if (conversion2 && conversion2->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION) |
---|
445 | { |
---|
446 | result.conversion_function_final = conversion2->final_conversion_function; |
---|
447 | } |
---|
448 | else if (conversion2 && conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
449 | { |
---|
450 | if (conversion2->const_offset_reference_to_source_object == 0 && conversion2->source_type == conversion2->destination_type && (conversion1->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION || allow_reference_to_source)) |
---|
451 | { |
---|
452 | result.conversion_function_first = conversion1->final_conversion_function; // second operation can be optimized away |
---|
453 | result.intermediate_type = result.destination_type; |
---|
454 | if (conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT) |
---|
455 | { |
---|
456 | assert(allow_reference_to_source); |
---|
457 | result.flags = tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY; |
---|
458 | } |
---|
459 | } |
---|
460 | else |
---|
461 | { |
---|
462 | result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION; |
---|
463 | result.fixed_offset_final = conversion2->const_offset_reference_to_source_object; |
---|
464 | } |
---|
465 | } |
---|
466 | else if (conversion2 && (conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT || conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT)) |
---|
467 | { |
---|
468 | result.conversion_function_final = conversion2->first_conversion_function; |
---|
469 | result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_SECOND_FUNCTION; |
---|
470 | } |
---|
471 | } |
---|
472 | // First operation is variable offset |
---|
473 | else if (conversion1->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
474 | { |
---|
475 | bool reference_result = allow_reference_to_source && ((!conversion2) || conversion2->type != tConversionOptionType::STANDARD_CONVERSION_FUNCTION); |
---|
476 | if (reference_result) |
---|
477 | { |
---|
478 | if (conversion2 && conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT) |
---|
479 | { |
---|
480 | result.flags |= tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY; |
---|
481 | result.conversion_function_first = conversion1->first_conversion_function; |
---|
482 | result.conversion_function_final = conversion2->final_conversion_function; |
---|
483 | } |
---|
484 | else |
---|
485 | { |
---|
486 | result.flags |= tFlag::cRESULT_REFERENCES_SOURCE_DIRECTLY; |
---|
487 | result.get_destination_reference_function_first = conversion2->destination_reference_function; |
---|
488 | if (conversion2 && conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
489 | { |
---|
490 | result.fixed_offset_final = conversion2->const_offset_reference_to_source_object; |
---|
491 | } |
---|
492 | else if (conversion2 && conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
493 | { |
---|
494 | result.get_destination_reference_function_final = conversion2->destination_reference_function; |
---|
495 | } |
---|
496 | } |
---|
497 | } |
---|
498 | else |
---|
499 | { |
---|
500 | result.conversion_function_first = conversion1->first_conversion_function; |
---|
501 | result.flags |= tFlag::cRESULT_INDEPENDENT; |
---|
502 | if (!conversion2) |
---|
503 | { |
---|
504 | result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION; |
---|
505 | } |
---|
506 | else if (conversion2->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION) |
---|
507 | { |
---|
508 | result.conversion_function_final = conversion2->final_conversion_function; |
---|
509 | } |
---|
510 | else if (conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT) |
---|
511 | { |
---|
512 | result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION; |
---|
513 | result.fixed_offset_final = conversion2->const_offset_reference_to_source_object; |
---|
514 | } |
---|
515 | else if (conversion2 && (conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT || conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT)) |
---|
516 | { |
---|
517 | result.conversion_function_final = conversion2->first_conversion_function; |
---|
518 | result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_SECOND_FUNCTION; |
---|
519 | } |
---|
520 | } |
---|
521 | } |
---|
522 | } |
---|
523 | |
---|
524 | // ############ |
---|
525 | // Convert any parameters provided as strings to their required types |
---|
526 | // ############ |
---|
527 | for (size_t i = 0; i < 2; i++) |
---|
528 | { |
---|
529 | const tRegisteredConversionOperation* operation = i == 0 ? first_operation : second_operation; |
---|
530 | if (operation && operation->Parameter() && GetParameterValue(i)) |
---|
531 | { |
---|
532 | const tTypedConstPointer& value = GetParameterValue(i); |
---|
533 | if (value.GetType() == operation->Parameter().GetType()) |
---|
534 | { |
---|
535 | CopyParameter(value, result.operations[i].parameter); |
---|
536 | } |
---|
537 | else if (value.GetType() == tDataType<std::string>()) |
---|
538 | { |
---|
539 | serialization::tStringInputStream stream(*value.Get<std::string>()); |
---|
540 | result.operations[i].parameter.reset(operation->Parameter().GetType().CreateGenericObject()); |
---|
541 | result.operations[i].parameter->Deserialize(stream); |
---|
542 | } |
---|
543 | else |
---|
544 | { |
---|
545 | throw std::runtime_error(std::string("Parameter ") + operation->Parameter().GetName() + " has invalid type"); |
---|
546 | } |
---|
547 | } |
---|
548 | } |
---|
549 | |
---|
550 | // Optional operation-specific processing |
---|
551 | if ((result.conversion_function_first || result.get_destination_reference_function_first) && conversion1 && conversion1->origin) |
---|
552 | { |
---|
553 | auto custom_operation_data = result.CustomOperationData(0); |
---|
554 | conversion1->origin->OnCompile(*conversion1, custom_operation_data); |
---|
555 | } |
---|
556 | if ((result.conversion_function_final || result.get_destination_reference_function_final) && conversion2 && conversion2->origin) |
---|
557 | { |
---|
558 | auto custom_operation_data = result.CustomOperationData(1); |
---|
559 | conversion2->origin->OnCompile(*conversion2, custom_operation_data); |
---|
560 | } |
---|
561 | |
---|
562 | return result; |
---|
563 | } |
---|
564 | |
---|
565 | void tConversionOperationSequence::CopyParameter(const tTypedConstPointer& source, std::unique_ptr<tGenericObject>& destination) |
---|
566 | { |
---|
567 | if (source) |
---|
568 | { |
---|
569 | if ((!destination) || destination->GetType() != source.GetType()) |
---|
570 | { |
---|
571 | destination.reset(source.GetType().CreateGenericObject()); |
---|
572 | } |
---|
573 | destination->DeepCopyFrom(source); |
---|
574 | } |
---|
575 | else |
---|
576 | { |
---|
577 | destination.reset(); |
---|
578 | } |
---|
579 | } |
---|
580 | |
---|
581 | void tConversionOperationSequence::SetParameterValue(size_t operation_index, const tTypedConstPointer& new_value) |
---|
582 | { |
---|
583 | assert(operation_index < 2); |
---|
584 | CopyParameter(new_value, operations[operation_index].parameter); |
---|
585 | } |
---|
586 | |
---|
587 | serialization::tOutputStream& operator << (serialization::tOutputStream& stream, const tConversionOperationSequence& sequence) |
---|
588 | { |
---|
589 | stream.WriteByte(static_cast<uint8_t>(sequence.Size())); |
---|
590 | for (size_t i = 0; i < sequence.Size(); i++) |
---|
591 | { |
---|
592 | auto operation = sequence[i]; |
---|
593 | auto parameter_value = sequence.GetParameterValue(i); |
---|
594 | uint8_t flags = (operation.second ? cFULL_OPERATION : 0) | (parameter_value && operation.second && (!operation.second->ParameterHandlingAsStringIsDefault()) && parameter_value.GetType() == operation.second->Parameter().GetType() ? cPARAMETER : (parameter_value ? cSTRING_PARAMETER : 0)); |
---|
595 | stream.WriteByte(flags); |
---|
596 | if (operation.second) |
---|
597 | { |
---|
598 | stream << *operation.second; |
---|
599 | } |
---|
600 | else |
---|
601 | { |
---|
602 | assert(operation.first); |
---|
603 | stream << operation.first; |
---|
604 | } |
---|
605 | if (flags & cPARAMETER) |
---|
606 | { |
---|
607 | parameter_value.Serialize(stream); |
---|
608 | } |
---|
609 | else if (flags & cSTRING_PARAMETER) |
---|
610 | { |
---|
611 | if (parameter_value.GetType() == tDataType<std::string>()) |
---|
612 | { |
---|
613 | stream << *parameter_value.Get<std::string>(); |
---|
614 | } |
---|
615 | else |
---|
616 | { |
---|
617 | parameter_value.Serialize(stream, serialization::tDataEncoding::STRING); |
---|
618 | } |
---|
619 | } |
---|
620 | } |
---|
621 | if (sequence.Size() > 1) |
---|
622 | { |
---|
623 | stream << sequence.IntermediateType(); |
---|
624 | } |
---|
625 | return stream; |
---|
626 | } |
---|
627 | |
---|
628 | serialization::tInputStream& operator >> (serialization::tInputStream& stream, tConversionOperationSequence& sequence) |
---|
629 | { |
---|
630 | size_t size = stream.ReadByte(); |
---|
631 | if (size > 2) |
---|
632 | { |
---|
633 | throw std::runtime_error("Invalid sequence size"); |
---|
634 | } |
---|
635 | for (size_t i = 0; i < 2; i++) |
---|
636 | { |
---|
637 | if (i >= size) |
---|
638 | { |
---|
639 | sequence.operations[i].operation = nullptr; |
---|
640 | sequence.operations[i].parameter.reset(); |
---|
641 | sequence.ambiguous_operation_lookup[i] = false; |
---|
642 | } |
---|
643 | else |
---|
644 | { |
---|
645 | uint8_t flags = stream.ReadByte(); |
---|
646 | if (flags & cFULL_OPERATION) |
---|
647 | { |
---|
648 | sequence.operations[i].operation = tRegisteredConversionOperation::Deserialize(stream, true); |
---|
649 | sequence.ambiguous_operation_lookup[i] = false; |
---|
650 | } |
---|
651 | else |
---|
652 | { |
---|
653 | std::string name = stream.ReadString(); |
---|
654 | auto search_result = tRegisteredConversionOperation::Find(name); |
---|
655 | if (!search_result.first) |
---|
656 | { |
---|
657 | throw std::runtime_error("No conversion operation named " + name + " found"); |
---|
658 | } |
---|
659 | sequence.operations[i].operation = search_result.first; |
---|
660 | sequence.ambiguous_operation_lookup[i] = search_result.second; |
---|
661 | } |
---|
662 | if (flags & cPARAMETER) |
---|
663 | { |
---|
664 | if ((!sequence.operations[i].operation) || (!sequence.operations[i].operation->Parameter().GetType())) |
---|
665 | { |
---|
666 | throw std::runtime_error("No parameter defined in conversion operation to deserialize"); |
---|
667 | } |
---|
668 | if ((!sequence.operations[i].parameter) || sequence.operations[i].parameter->GetType() != sequence.operations[i].operation->Parameter().GetType()) |
---|
669 | { |
---|
670 | sequence.operations[i].parameter.reset(sequence.operations[i].operation->Parameter().GetType().CreateGenericObject()); |
---|
671 | } |
---|
672 | sequence.operations[i].parameter->Deserialize(stream); |
---|
673 | } |
---|
674 | else if (flags & cSTRING_PARAMETER) |
---|
675 | { |
---|
676 | if (!sequence.operations[i].operation) |
---|
677 | { |
---|
678 | throw std::runtime_error("No conversion operation found"); |
---|
679 | } |
---|
680 | if ((!sequence.operations[i].parameter) || sequence.operations[i].parameter->GetType() != tDataType<std::string>()) |
---|
681 | { |
---|
682 | sequence.operations[i].parameter.reset(tDataType<std::string>().CreateGenericObject()); |
---|
683 | } |
---|
684 | stream >> sequence.operations[i].parameter->GetData<std::string>(); |
---|
685 | } |
---|
686 | else |
---|
687 | { |
---|
688 | sequence.operations[i].parameter.reset(); |
---|
689 | } |
---|
690 | } |
---|
691 | } |
---|
692 | if (size > 1) |
---|
693 | { |
---|
694 | stream >> sequence.intermediate_type; |
---|
695 | } |
---|
696 | else |
---|
697 | { |
---|
698 | sequence.intermediate_type = rrlib::rtti::tType(); |
---|
699 | } |
---|
700 | return stream; |
---|
701 | } |
---|
702 | |
---|
703 | //---------------------------------------------------------------------- |
---|
704 | // End of namespace declaration |
---|
705 | //---------------------------------------------------------------------- |
---|
706 | } |
---|
707 | } |
---|
708 | } |
---|