source: rrlib_rtti_conversion/tConversionOperationSequence.cpp @ 11:08b89b764823

17.03
Last change on this file since 11:08b89b764823 was 11:08b89b764823, checked in by Max Reichardt <max.reichardt@…>, 5 months ago

Fixes bug in lookup of ambiguous conversion operations used together with FOR_EACH operation

File size: 25.0 KB
Line 
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//----------------------------------------------------------------------
54namespace rrlib
55{
56namespace rtti
57{
58namespace conversion
59{
60
61//----------------------------------------------------------------------
62// Forward declarations / typedefs / enums
63//----------------------------------------------------------------------
64
65//----------------------------------------------------------------------
66// Const values
67//----------------------------------------------------------------------
68
69const tConversionOperationSequence tConversionOperationSequence::cNONE;
70const tTypedConstPointer tConversionOperationSequence::cNO_PARAMETER_VALUE;
71
72/*! Enum for binary serialization */
73enum tOperationSerializationFlags : uint8_t { cFULL_OPERATION = 1, cPARAMETER = 2, cSTRING_PARAMETER = 4 };
74
75//----------------------------------------------------------------------
76// Implementation
77//----------------------------------------------------------------------
78
79tConversionOperationSequence::tConversionOperationSequence(const std::string& first, const std::string& second, const tType& intermediate_type) :
80  operations {nullptr, nullptr},
81           ambiguous_operation_lookup {false, false},
82           intermediate_type(intermediate_type)
83{
84  auto find_result = tRegisteredConversionOperation::Find(first);
85  operations[0].operation = find_result.first;
86  ambiguous_operation_lookup[0] = find_result.second;
87  if (operations[0].operation == nullptr)
88  {
89    throw std::runtime_error("Could not find registered conversion operation with name: " + first);
90  }
91  if (second.length())
92  {
93    find_result = tRegisteredConversionOperation::Find(second);
94    operations[1].operation = find_result.first;
95    ambiguous_operation_lookup[1] = find_result.second;
96    if (operations[1].operation == nullptr)
97    {
98      throw std::runtime_error("Could not find registered conversion operation with name: " + second);
99    }
100  }
101}
102
103tConversionOperationSequence& tConversionOperationSequence::operator=(const tConversionOperationSequence & other)
104{
105  operations[0].operation = other.operations[0].operation;
106  operations[1].operation = other.operations[1].operation;
107  CopyParameter(other.operations[0].parameter ? *other.operations[0].parameter : tTypedConstPointer(), operations[0].parameter);
108  CopyParameter(other.operations[1].parameter ? *other.operations[1].parameter : tTypedConstPointer(), operations[1].parameter);
109  memcpy(ambiguous_operation_lookup, other.ambiguous_operation_lookup, sizeof(ambiguous_operation_lookup));
110  intermediate_type = other.intermediate_type;
111  return *this;
112}
113
114tCompiledConversionOperation tConversionOperationSequence::Compile(bool allow_reference_to_source, const tType& source_type, const tType& destination_type) const
115{
116  // ############
117  // Resolve any ambiguous conversion operations
118  // ############
119  const tRegisteredConversionOperation* first_operation = operations[0].operation;
120  if (first_operation && ambiguous_operation_lookup[0])
121  {
122    first_operation = &tRegisteredConversionOperation::Find(first_operation->Name(), source_type, Size() == 2 ? intermediate_type : destination_type);
123  }
124  const tRegisteredConversionOperation* second_operation = operations[1].operation;
125  if (second_operation && ambiguous_operation_lookup[1])
126  {
127    if (first_operation == &cFOR_EACH_OPERATION)
128    {
129      second_operation = &tRegisteredConversionOperation::Find(second_operation->Name(), intermediate_type, destination_type.GetElementType());
130    }
131    else
132    {
133      second_operation = &tRegisteredConversionOperation::Find(second_operation->Name(), intermediate_type, destination_type);
134    }
135  }
136
137  // ############
138  // Infer conversion options
139  // This includes adding implicit conversions if less than two registered conversions are in chain
140  // ############
141
142  // Infer any undefined types
143  tType type_source = source_type;
144  tType type_destination = destination_type;
145  tType type_intermediate = this->intermediate_type;
146  if (!type_source)
147  {
148    type_source = first_operation ? first_operation->SupportedSourceTypes().single_type : tType();
149  }
150  if (!type_source)
151  {
152    throw std::runtime_error("Source type must be specified");
153  }
154  const tRegisteredConversionOperation* last_operation = second_operation ? second_operation : first_operation;
155  if (!type_destination)
156  {
157    type_destination = last_operation ? last_operation->SupportedDestinationTypes().single_type : tType();
158  }
159  if (!type_destination)
160  {
161    throw std::runtime_error("Destination type must be specified");
162  }
163  if ((!type_intermediate) && second_operation)
164  {
165    type_intermediate = first_operation ? first_operation->SupportedDestinationTypes().single_type : tType();
166    if (!type_intermediate)
167    {
168      type_intermediate = second_operation ? second_operation->SupportedSourceTypes().single_type : tType();
169    }
170    if (!type_intermediate)
171    {
172      throw std::runtime_error("Intermediate type must be specified");
173    }
174  }
175
176  // Variables for result
177  tConversionOption temp_conversion_option_1, temp_conversion_option_2;
178  const tConversionOption* conversion1 = nullptr;
179  const tConversionOption* conversion2 = nullptr;
180
181  // No conversion operation specified: Look for implicit cast
182  if ((!first_operation))
183  {
184    if (type_source == type_destination)
185    {
186      temp_conversion_option_1 = tConversionOption(type_source, type_destination, 0);
187      conversion1 = &temp_conversion_option_1;
188    }
189    else
190    {
191      auto implicit_conversion = tStaticCastOperation::GetImplicitConversionOptions(type_source, type_destination);
192      if (implicit_conversion.first.type == tConversionOptionType::NONE)
193      {
194        throw std::runtime_error("Type " + source_type.GetName() + " cannot be implicitly casted to " + destination_type.GetName());
195      }
196      temp_conversion_option_1 = implicit_conversion.first;
197      conversion1 = &temp_conversion_option_1;
198      if (implicit_conversion.second.type != tConversionOptionType::NONE)
199      {
200        temp_conversion_option_2 = implicit_conversion.second;
201        conversion2 = &temp_conversion_option_2;
202      }
203    }
204  }
205
206  // For each operation
207  else if (first_operation == &cFOR_EACH_OPERATION)
208  {
209    if (!((type_source.IsListType() && type_destination.IsListType()) ||
210          (type_source.IsArray() && type_destination.IsArray() && type_source.GetArraySize() == destination_type.GetArraySize()) ||
211          (type_source.IsArray() && type_destination.IsListType())))
212    {
213      throw std::runtime_error("ForEach operation only applicable on list types and array types");
214    }
215    if (!second_operation)
216    {
217      temp_conversion_option_2 = tStaticCastOperation::GetImplicitConversionOption(type_source.GetElementType(), type_destination.GetElementType());
218      if (temp_conversion_option_2.type == tConversionOptionType::NONE)
219      {
220        throw std::runtime_error("Type " + source_type.GetElementType().GetName() + " cannot be implicitly casted to " + destination_type.GetElementType().GetName() + ". Second operation for ForEach must be specified.");
221      }
222    }
223    else
224    {
225      temp_conversion_option_2 = second_operation->GetConversionOption(type_source.GetElementType(), type_destination.GetElementType(), operations[1].parameter.get());
226      if (temp_conversion_option_2.type == tConversionOptionType::NONE)
227      {
228        throw std::runtime_error("Type " + source_type.GetElementType().GetName() + " cannot be converted to " + destination_type.GetElementType().GetName() + " with the selected operations.");
229      }
230    }
231    conversion2 = &temp_conversion_option_2;
232    temp_conversion_option_1 = first_operation->GetConversionOption(type_source, type_destination, operations[0].parameter.get());
233    conversion1 = &temp_conversion_option_1;
234  }
235
236  // Two conversion operations specified: Check types
237  else if (second_operation)
238  {
239    temp_conversion_option_1 = first_operation->GetConversionOption(type_source, type_intermediate, operations[0].parameter.get());
240    temp_conversion_option_2 = second_operation->GetConversionOption(type_intermediate, type_destination, operations[1].parameter.get());
241    if (temp_conversion_option_1.type != tConversionOptionType::NONE && temp_conversion_option_2.type != tConversionOptionType::NONE)
242    {
243      conversion1 = &temp_conversion_option_1;
244      conversion2 = &temp_conversion_option_2;
245    }
246  }
247
248  // One conversion option specified: Is it enough - or do we need additional implicit cast?
249  else
250  {
251    temp_conversion_option_1 = first_operation->GetConversionOption(type_source, type_destination, operations[0].parameter.get());
252    if (temp_conversion_option_1.type != tConversionOptionType::NONE)
253    {
254      conversion1 = &temp_conversion_option_1;
255    }
256    else
257    {
258      // Try implicit cast as second
259      if (first_operation->SupportedSourceTypes().single_type == source_type && (first_operation->SupportedDestinationTypes().single_type || type_intermediate))
260      {
261        type_intermediate = type_intermediate ? type_intermediate : first_operation->SupportedDestinationTypes().single_type;
262        temp_conversion_option_1 = first_operation->GetConversionOption(type_source, type_intermediate, operations[0].parameter.get());
263        temp_conversion_option_2 = tStaticCastOperation::GetImplicitConversionOption(type_intermediate, type_destination);
264      }
265      else if ((first_operation->SupportedSourceTypes().single_type || type_intermediate) && first_operation->SupportedDestinationTypes().single_type == destination_type)
266      {
267        type_intermediate = type_intermediate ? type_intermediate : first_operation->SupportedSourceTypes().single_type;
268        temp_conversion_option_1 = tStaticCastOperation::GetImplicitConversionOption(type_source, type_intermediate);
269        temp_conversion_option_2 = first_operation->GetConversionOption(type_intermediate, type_destination, operations[1].parameter.get());
270      }
271      if (temp_conversion_option_1.type != tConversionOptionType::NONE && temp_conversion_option_2.type != tConversionOptionType::NONE)
272      {
273        conversion1 = &temp_conversion_option_1;
274        conversion2 = &temp_conversion_option_2;
275      }
276      else
277      {
278        throw std::runtime_error("Intermediate type must be specified");
279      }
280    }
281  }
282  if (!conversion1)
283  {
284    throw std::runtime_error("Type " + source_type.GetName() + " cannot be casted to " + destination_type.GetName() + " with the selected operations");
285  }
286
287
288  // ############
289  // Compile conversion operation from conversion options
290  // ############
291  typedef tCompiledConversionOperation::tFlag tFlag;
292  assert(conversion1);
293  const tConversionOption* last_conversion = conversion2 ? conversion2 : conversion1;
294
295  // Do some sanity checks
296  if ((conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT && conversion1->const_offset_reference_to_source_object > std::numeric_limits<unsigned int>::max() / 2) ||
297      (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))
298  {
299    throw std::runtime_error("Invalid fixed offset in conversion option");
300  }
301
302  // Prepare result
303  tCompiledConversionOperation result;
304  result.operations[0].operation = first_operation;
305  result.operations[1].operation = second_operation;
306  result.destination_type = last_conversion->destination_type;
307  static_cast<tConversionOperationSequence&>(result).intermediate_type = this->intermediate_type;
308
309  // Handle special case: only const offsets
310  if (conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT && last_conversion->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
311  {
312    result.type_after_first_fixed_offset = result.destination_type;
313    result.intermediate_type = result.destination_type;
314    result.fixed_offset_first = static_cast<unsigned int>(conversion1->const_offset_reference_to_source_object + (conversion2 ? conversion2->const_offset_reference_to_source_object : 0));
315    result.flags = tFlag::cRESULT_INDEPENDENT | tFlag::cRESULT_REFERENCES_SOURCE_DIRECTLY | tFlag::cDEEPCOPY_ONLY;
316  }
317  else
318  {
319    // Handle cases where first operation is const offset
320    bool first_op_is_const_offset = conversion1->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT;
321    result.type_after_first_fixed_offset = first_op_is_const_offset ? conversion1->destination_type : conversion1->source_type;
322    if (first_op_is_const_offset)
323    {
324      result.fixed_offset_first = static_cast<unsigned int>(conversion1->const_offset_reference_to_source_object);
325
326      // first operation is done, so move second to first
327      conversion1 = nullptr;
328      std::swap(conversion1, conversion2);
329      result.flags |= tFlag::cFIRST_OPERATION_OPTIMIZED_AWAY;
330    }
331    result.intermediate_type = conversion1->destination_type;
332
333    // Single operation REFERENCES_SOURCE
334    if (conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT && (!conversion2))
335    {
336      result.conversion_function_first = allow_reference_to_source ? conversion1->final_conversion_function : conversion1->first_conversion_function;
337      result.flags = allow_reference_to_source ? tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY : (tFlag::cRESULT_INDEPENDENT | tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION);
338    }
339    // First operation is standard or REFERENCES_SOURCE
340    else if (conversion1->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION || conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT)
341    {
342      result.conversion_function_first = conversion2 ? conversion1->first_conversion_function : conversion1->final_conversion_function;
343      result.flags = tFlag::cRESULT_INDEPENDENT;
344      if (conversion2 && conversion2->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION)
345      {
346        result.conversion_function_final = conversion2->final_conversion_function;
347      }
348      else if (conversion2 && conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
349      {
350        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))
351        {
352          result.conversion_function_first =  conversion1->final_conversion_function; // second operation can be optimized away
353          result.intermediate_type = result.destination_type;
354          if (conversion1->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT)
355          {
356            assert(allow_reference_to_source);
357            result.flags = tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY;
358          }
359        }
360        else
361        {
362          result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION;
363          result.fixed_offset_final = conversion2->const_offset_reference_to_source_object;
364        }
365      }
366      else if (conversion2 && (conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT || conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT))
367      {
368        result.conversion_function_final = conversion2->first_conversion_function;
369        result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_SECOND_FUNCTION;
370      }
371    }
372    // First operation is variable offset
373    else if (conversion1->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
374    {
375      bool reference_result = allow_reference_to_source && ((!conversion2) || conversion2->type != tConversionOptionType::STANDARD_CONVERSION_FUNCTION);
376      if (reference_result)
377      {
378        if (conversion2 && conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT)
379        {
380          result.flags |= tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY;
381          result.conversion_function_first = conversion1->first_conversion_function;
382          result.conversion_function_final = conversion2->final_conversion_function;
383        }
384        else
385        {
386          result.flags |= tFlag::cRESULT_REFERENCES_SOURCE_DIRECTLY;
387          result.get_destination_reference_function_first = conversion2->destination_reference_function;
388          if (conversion2 && conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
389          {
390            result.fixed_offset_final = conversion2->const_offset_reference_to_source_object;
391          }
392          else if (conversion2 && conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
393          {
394            result.get_destination_reference_function_final = conversion2->destination_reference_function;
395          }
396        }
397      }
398      else
399      {
400        result.conversion_function_first = conversion1->first_conversion_function;
401        result.flags |= tFlag::cRESULT_INDEPENDENT;
402        if (!conversion2)
403        {
404          result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION;
405        }
406        else if (conversion2->type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION)
407        {
408          result.conversion_function_final = conversion2->final_conversion_function;
409        }
410        else if (conversion2->type == tConversionOptionType::CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT)
411        {
412          result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION;
413          result.fixed_offset_final = conversion2->const_offset_reference_to_source_object;
414        }
415        else if (conversion2 && (conversion2->type == tConversionOptionType::VARIABLE_OFFSET_REFERENCE_TO_SOURCE_OBJECT || conversion2->type == tConversionOptionType::RESULT_REFERENCES_SOURCE_OBJECT))
416        {
417          result.conversion_function_final = conversion2->first_conversion_function;
418          result.flags |= tFlag::cDO_FINAL_DEEPCOPY_AFTER_SECOND_FUNCTION;
419        }
420      }
421    }
422  }
423
424  // ############
425  // Convert any parameters provided as strings to their required types
426  // ############
427  for (size_t i = 0; i < 2; i++)
428  {
429    const tRegisteredConversionOperation* operation = i == 0 ? first_operation : second_operation;
430    if (operation && operation->Parameter() && GetParameterValue(i))
431    {
432      const tTypedConstPointer& value = GetParameterValue(i);
433      if (value.GetType() == operation->Parameter().GetType())
434      {
435        CopyParameter(value, result.operations[i].parameter);
436      }
437      else if (value.GetType() == tDataType<std::string>())
438      {
439        serialization::tStringInputStream stream(*value.Get<std::string>());
440        result.operations[i].parameter.reset(operation->Parameter().GetType().CreateGenericObject());
441        result.operations[i].parameter->Deserialize(stream);
442      }
443      else
444      {
445        throw std::runtime_error(std::string("Parameter ") + operation->Parameter().GetName() + " has invalid type");
446      }
447    }
448  }
449
450  return result;
451}
452
453void tConversionOperationSequence::CopyParameter(const tTypedConstPointer& source, std::unique_ptr<tGenericObject>& destination)
454{
455  if (source)
456  {
457    if ((!destination) || destination->GetType() != source.GetType())
458    {
459      destination.reset(source.GetType().CreateGenericObject());
460      destination->DeepCopyFrom(source);
461    }
462  }
463  else
464  {
465    destination.reset();
466  }
467}
468
469void tConversionOperationSequence::SetParameterValue(size_t operation_index, const tTypedConstPointer& new_value)
470{
471  assert(operation_index < 2);
472  CopyParameter(new_value, operations[operation_index].parameter);
473}
474
475serialization::tOutputStream& operator << (serialization::tOutputStream& stream, const tConversionOperationSequence& sequence)
476{
477  stream.WriteByte(static_cast<uint8_t>(sequence.Size()));
478  for (size_t i = 0; i < sequence.Size(); i++)
479  {
480    auto operation = sequence[i];
481    auto parameter_value = sequence.GetParameterValue(i);
482    uint8_t flags = (operation.second ? cFULL_OPERATION : 0) | (parameter_value && operation.second && parameter_value.GetType() == operation.second->Parameter().GetType() ? cPARAMETER : (parameter_value ? cSTRING_PARAMETER : 0));
483    stream.WriteByte(flags);
484    if (operation.second)
485    {
486      stream << *operation.second;
487    }
488    else
489    {
490      assert(operation.first);
491      stream << operation.first;
492    }
493    if (flags & cPARAMETER)
494    {
495      parameter_value.Serialize(stream);
496    }
497    else if (flags & cSTRING_PARAMETER)
498    {
499      assert(parameter_value.GetType() == tDataType<std::string>());
500      stream << *parameter_value.Get<std::string>();
501    }
502  }
503  if (sequence.Size() > 1)
504  {
505    stream << sequence.IntermediateType();
506  }
507  return stream;
508}
509
510serialization::tInputStream& operator >> (serialization::tInputStream& stream, tConversionOperationSequence& sequence)
511{
512  size_t size = stream.ReadByte();
513  if (size > 2)
514  {
515    throw std::runtime_error("Invalid sequence size");
516  }
517  for (size_t i = 0; i < 2; i++)
518  {
519    if (i >= size)
520    {
521      sequence.operations[i].operation = nullptr;
522      sequence.operations[i].parameter.reset();
523      sequence.ambiguous_operation_lookup[i] = false;
524    }
525    else
526    {
527      uint8_t flags = stream.ReadByte();
528      if (flags & cFULL_OPERATION)
529      {
530        sequence.operations[i].operation = tRegisteredConversionOperation::Deserialize(stream, true);
531        sequence.ambiguous_operation_lookup[i] = false;
532      }
533      else
534      {
535        std::string name = stream.ReadString();
536        auto search_result = tRegisteredConversionOperation::Find(name);
537        if (!search_result.first)
538        {
539          throw std::runtime_error("No conversion operation named " + name + " found");
540        }
541        sequence.operations[i].operation = search_result.first;
542        sequence.ambiguous_operation_lookup[i] = search_result.second;
543      }
544      if (flags & cPARAMETER)
545      {
546        if ((!sequence.operations[i].operation) || (!sequence.operations[i].operation->Parameter().GetType()))
547        {
548          throw std::runtime_error("No parameter defined in conversion operation to deserialize");
549        }
550        if ((!sequence.operations[i].parameter) || sequence.operations[i].parameter->GetType() != sequence.operations[i].operation->Parameter().GetType())
551        {
552          sequence.operations[i].parameter.reset(sequence.operations[i].operation->Parameter().GetType().CreateGenericObject());
553        }
554        sequence.operations[i].parameter->Deserialize(stream);
555      }
556      else if (flags & cSTRING_PARAMETER)
557      {
558        if (!sequence.operations[i].operation)
559        {
560          throw std::runtime_error("No conversion operation found");
561        }
562        if ((!sequence.operations[i].parameter) || sequence.operations[i].parameter->GetType() != tDataType<std::string>())
563        {
564          sequence.operations[i].parameter.reset(tDataType<std::string>().CreateGenericObject());
565        }
566        stream >> sequence.operations[i].parameter->GetData<std::string>();
567      }
568      else
569      {
570        sequence.operations[i].parameter.reset();
571      }
572    }
573  }
574  if (size > 1)
575  {
576    stream >> sequence.intermediate_type;
577  }
578  else
579  {
580    sequence.intermediate_type = rrlib::rtti::tType();
581  }
582  return stream;
583}
584
585//----------------------------------------------------------------------
586// End of namespace declaration
587//----------------------------------------------------------------------
588}
589}
590}
Note: See TracBrowser for help on using the repository browser.