source: rrlib_rtti_conversion/tStaticCastOperation.cpp @ 30:f0f4df817436

17.03
Last change on this file since 30:f0f4df817436 was 30:f0f4df817436, checked in by Max Reichardt <mreichardt@…>, 21 months ago

Adds functionality to resolve non-ambiguous combinations of an explicit conversion operation (that supports multiple types) with an automatic implicit cast - without an intermediate type specified. This works if there is only one valid combination. In practice this means in particular, that more conversion can be done with a single static_cast.

File size: 26.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/tStaticCastOperation.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2016-07-17
27 *
28 */
29//----------------------------------------------------------------------
30#include "rrlib/rtti_conversion/tStaticCastOperation.h"
31
32//----------------------------------------------------------------------
33// External includes (system with <>, local with "")
34//----------------------------------------------------------------------
35#include "rrlib/thread/tLock.h"
36
37//----------------------------------------------------------------------
38// Internal includes with ""
39//----------------------------------------------------------------------
40
41//----------------------------------------------------------------------
42// Debugging
43//----------------------------------------------------------------------
44#include <cassert>
45
46//----------------------------------------------------------------------
47// Namespace usage
48//----------------------------------------------------------------------
49
50//----------------------------------------------------------------------
51// Namespace declaration
52//----------------------------------------------------------------------
53namespace rrlib
54{
55namespace rtti
56{
57namespace conversion
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64//----------------------------------------------------------------------
65// Const values
66//----------------------------------------------------------------------
67
68const bool cVERIFIY_GET_SUPPORTED_TYPES_RESULT = false;
69
70//----------------------------------------------------------------------
71// Implementation
72//----------------------------------------------------------------------
73
74tStaticCastOperation tStaticCastOperation::instance;
75
76const tStaticCastOperation::tStaticCast tStaticCastOperation::tInstanceNone::value = { { tConversionOption() }, false };
77
78namespace
79{
80
81struct tCommonUnderlyingTypeResult
82{
83  rrlib::rtti::tType common_underlying_type;
84  bool cast_from_source_to_common_type_implicit = false;
85  bool cast_from_common_to_destination_type_implicit = false;
86  bool cast_from_common_to_destination_type_valid = false;
87};
88
89tCommonUnderlyingTypeResult GetCommonUnderlyingType(const tType& source_type, const tType& destination_type)
90{
91  // Count underlying types
92  int underlying_type_count_source = 0;
93  tType final_underlying_type_source = source_type;
94  while (final_underlying_type_source.GetUnderlyingType() != final_underlying_type_source)
95  {
96    underlying_type_count_source++;
97    final_underlying_type_source = final_underlying_type_source.GetUnderlyingType();
98  }
99  int underlying_type_count_destination = 0;
100  tType final_underlying_type_destination = destination_type;
101  while (final_underlying_type_destination.GetUnderlyingType() != final_underlying_type_destination)
102  {
103    underlying_type_count_destination++;
104    final_underlying_type_destination = final_underlying_type_destination.GetUnderlyingType();
105  }
106
107  tCommonUnderlyingTypeResult result;
108  if (final_underlying_type_destination != final_underlying_type_source)
109  {
110    return result;
111  }
112
113  // Find common parent
114  int remaining_types_source = underlying_type_count_source;
115  int remaining_types_destination = underlying_type_count_destination;
116  tType current_type_source = source_type;
117  tType current_type_destination = destination_type;
118  result.cast_from_source_to_common_type_implicit = true;
119  result.cast_from_common_to_destination_type_implicit = true;
120  result.cast_from_common_to_destination_type_valid = true;
121
122  while (remaining_types_source || remaining_types_destination)
123  {
124    if (current_type_source == current_type_destination)
125    {
126      break;
127    }
128
129    bool process_source = remaining_types_source >= remaining_types_destination;
130    bool process_destination = remaining_types_destination >= remaining_types_source;
131    if (process_source)
132    {
133      result.cast_from_source_to_common_type_implicit &= static_cast<bool>(current_type_source.GetTypeTraits() & trait_flags::cIS_CAST_TO_UNDERLYING_TYPE_IMPLICIT);
134      current_type_source = current_type_source.GetUnderlyingType();
135      remaining_types_source--;
136    }
137    if (process_destination)
138    {
139      result.cast_from_common_to_destination_type_valid &= static_cast<bool>(current_type_destination.GetTypeTraits() & trait_flags::cIS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID);
140      result.cast_from_common_to_destination_type_implicit &= static_cast<bool>(current_type_destination.GetTypeTraits() & trait_flags::cIS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT);
141      current_type_destination = current_type_destination.GetUnderlyingType();
142      remaining_types_destination--;
143    }
144  }
145  assert(current_type_source == current_type_destination);
146  result.common_underlying_type = current_type_source;
147  return result;
148}
149
150template <typename TEnumUnderlyingType>
151void ConvertToEnumFinal(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
152{
153  static_assert(std::is_unsigned<TEnumUnderlyingType>::value && std::is_integral<TEnumUnderlyingType>::value, "Currently only unsigned int types are supported");
154
155  // Obtain value
156  tConversionOption::tConversionFunction function = operation.GetCustomData().conversion_function;
157  TEnumUnderlyingType value = 0;
158  if (function)
159  {
160    (*function)(source_object, tTypedPointer(&value, tDataType<TEnumUnderlyingType>()), operation);
161  }
162  else
163  {
164    assert(source_object.GetType().GetSize() == sizeof(TEnumUnderlyingType));
165    memcpy(&value, source_object.GetRawDataPointer(), sizeof(TEnumUnderlyingType));
166  }
167
168  // Check whether value is in bounds
169  auto enum_strings = destination_object.GetType().GetEnumStringsData();
170  if (enum_strings->non_standard_values)
171  {
172    const TEnumUnderlyingType* values = static_cast<const TEnumUnderlyingType*>(enum_strings->non_standard_values);
173    bool found = false;
174    for (size_t i = 0; i < enum_strings->size; i++)
175    {
176      if (values[i] == value)
177      {
178        found = true;
179        break;
180      }
181    }
182    if (!found)
183    {
184      serialization::tStringOutputStream stream;
185      stream << "Error casting value '";
186      source_object.Serialize(stream);
187      stream << "' to enum '" << destination_object.GetType().GetName() << "'";
188      throw std::invalid_argument(stream.ToString());
189    }
190  }
191  else if (value >= enum_strings->size)
192  {
193    serialization::tStringOutputStream stream;
194    stream << "Error casting out of bounds value '";
195    source_object.Serialize(stream);
196    stream << "' to enum '" << destination_object.GetType().GetName() << "'";
197    throw std::invalid_argument(stream.ToString());
198  }
199
200  assert(destination_object.GetType().GetSize() == sizeof(TEnumUnderlyingType));
201  memcpy(destination_object.GetRawDataPointer(), &value, sizeof(TEnumUnderlyingType));
202}
203
204template <typename TEnumUnderlyingType>
205static void ConvertToEnumFirst(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
206{
207  TEnumUnderlyingType intermediate_buffer = 0;
208  tTypedPointer intermediate(&intermediate_buffer, operation.compiled_operation.IntermediateType());
209  ConvertToEnumFinal<TEnumUnderlyingType>(source_object, intermediate, operation);
210  operation.Continue(intermediate, destination_object);
211}
212
213template <typename TEnumUnderlyingType>
214static void OnCompileToEnum(const tRegisteredConversionOperation& static_cast_operation, const tConversionOption& conversion_option, tCustomOperationData& custom_data)
215{
216  // Lookup underlying type conversion function
217  if (conversion_option.first_conversion_function == &ConvertToEnumFirst<TEnumUnderlyingType> && conversion_option.source_type.GetSize() != sizeof(TEnumUnderlyingType))
218  {
219    tConversionOption option = static_cast_operation.GetConversionOption(conversion_option.source_type, tDataType<TEnumUnderlyingType>(), nullptr);
220    assert(option.first_conversion_function && option.type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION);
221    custom_data.conversion_function = option.final_conversion_function;
222  }
223}
224
225void CheckEquivalence(const std::vector<tType>& base_result, const std::vector<tType>& result)
226{
227  if (!cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
228  {
229    return;
230  }
231
232  bool equivalent = base_result.size() == result.size();
233  if (base_result.size() != result.size())
234  {
235    RRLIB_LOG_PRINT(ERROR, "Results have different size (", base_result.size(), " vs. ", result.size(), ")");
236  }
237  for (auto & type : result)
238  {
239    if (std::count(base_result.begin(), base_result.end(), type) == 0)
240    {
241      RRLIB_LOG_PRINT(ERROR, "Type ", type, " missing in base result");
242      equivalent = false;
243    }
244  }
245  for (auto & type : base_result)
246  {
247    if (std::count(result.begin(), result.end(), type) == 0)
248    {
249      RRLIB_LOG_PRINT(ERROR, "Type ", type, " missing in result");
250      equivalent = false;
251    }
252  }
253
254  if (!equivalent)
255  {
256    throw std::runtime_error("Invalid result");
257  }
258}
259
260}
261
262tStaticCastOperation::tStaticCastOperation() : tRegisteredConversionOperation()
263{}
264
265tConversionOption tStaticCastOperation::GetConversionOption(const tType& source_type, const tType& destination_type, const tGenericObject* parameter) const
266{
267  if (source_type == destination_type)
268  {
269    return tConversionOption(source_type, destination_type, 0);
270  }
271  tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
272  if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && (result.common_underlying_type == source_type || result.cast_from_common_to_destination_type_implicit || result.cast_from_source_to_common_type_implicit)))
273  {
274    return tConversionOption(source_type, destination_type, 0);
275  }
276  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
277  for (auto & option : registered_operations.static_casts)
278  {
279    if (source_type == option->conversion_option.source_type && destination_type == option->conversion_option.destination_type)
280    {
281      return option->conversion_option;
282    }
283  }
284
285  // If destination is enum type, use checked conversion
286  if (destination_type.GetEnumStringsData())
287  {
288    if (source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC)
289    {
290      if (destination_type.GetSize() == 1)
291      {
292        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint8_t>, &ConvertToEnumFinal<uint8_t>);
293      }
294      else if (destination_type.GetSize() == 2)
295      {
296        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint16_t>, &ConvertToEnumFinal<uint16_t>);
297      }
298      else if (destination_type.GetSize() == 4)
299      {
300        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint32_t>, &ConvertToEnumFinal<uint32_t>);
301      }
302      else if (destination_type.GetSize() == 8)
303      {
304        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint64_t>, &ConvertToEnumFinal<uint64_t>);
305      }
306    }
307
308    return tConversionOption();
309  }
310
311  // Combining (non-implicit) underlying type casts with implicit or arithmetic casts can be done in a single operation
312  for (auto & option : registered_operations.static_casts)
313  {
314    bool arithmetic_cast = (option->conversion_option.source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0 && (option->conversion_option.destination_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0;
315    if ((option->implicit || arithmetic_cast) && destination_type == option->conversion_option.destination_type)
316    {
317      result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
318      if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
319      {
320        return option->conversion_option;
321      }
322    }
323    if ((option->implicit || arithmetic_cast) && source_type == option->conversion_option.source_type)
324    {
325      result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
326      if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
327      {
328        return option->conversion_option;
329      }
330    }
331  }
332
333  return tConversionOption();
334}
335
336tConversionOption tStaticCastOperation::GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type)
337{
338  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
339  return GetImplicitConversionOption(source_type, destination_type, registered_operations);
340}
341
342tConversionOption tStaticCastOperation::GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type, const tRegisteredConversionOperation::tRegisteredOperations& registered_operations)
343{
344  if (source_type == destination_type)
345  {
346    return tConversionOption(source_type, destination_type, 0);
347  }
348  tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
349  if ((result.common_underlying_type == destination_type && result.cast_from_source_to_common_type_implicit) || (result.common_underlying_type == source_type && result.cast_from_common_to_destination_type_valid && result.cast_from_common_to_destination_type_implicit))
350  {
351    return tConversionOption(source_type, destination_type, 0);
352  }
353  for (auto & option : registered_operations.static_casts)
354  {
355    if (option->implicit && source_type == option->conversion_option.source_type && destination_type == option->conversion_option.destination_type)
356    {
357      return option->conversion_option;
358    }
359  }
360
361  // Combining implicit underlying type casts with implicit casts can be done in a single operation
362  for (auto & option : registered_operations.static_casts)
363  {
364    if (option->implicit && destination_type == option->conversion_option.destination_type)
365    {
366      result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
367      if ((result.common_underlying_type == option->conversion_option.source_type && result.cast_from_source_to_common_type_implicit) || (result.cast_from_common_to_destination_type_valid && result.cast_from_common_to_destination_type_implicit && result.common_underlying_type == source_type))
368      {
369        return option->conversion_option;
370      }
371    }
372    if (option->implicit && source_type == option->conversion_option.source_type)
373    {
374      result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
375      if ((result.common_underlying_type == destination_type && result.cast_from_source_to_common_type_implicit) || (result.cast_from_common_to_destination_type_valid && result.cast_from_common_to_destination_type_implicit && result.common_underlying_type == option->conversion_option.destination_type))
376      {
377        return option->conversion_option;
378      }
379    }
380  }
381
382  return tConversionOption();
383}
384
385
386std::pair<tConversionOption, tConversionOption> tStaticCastOperation::GetImplicitConversionOptions(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type)
387{
388  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
389  tConversionOption single_result = GetImplicitConversionOption(source_type, destination_type, registered_operations);
390  if (single_result.type != tConversionOptionType::NONE)
391  {
392    return std::pair<tConversionOption, tConversionOption>(single_result, tConversionOption());
393  }
394
395  // Try all registered operations
396  for (auto & option : registered_operations.static_casts)
397  {
398    if (option->implicit)
399    {
400      if (source_type == option->conversion_option.source_type && option->conversion_option.destination_type != tDataType<bool>())
401      {
402        tConversionOption second_option = GetImplicitConversionOption(option->conversion_option.destination_type, destination_type, registered_operations);
403        if (second_option.type != tConversionOptionType::NONE)
404        {
405          return std::pair<tConversionOption, tConversionOption>(option->conversion_option, second_option);
406        }
407      }
408      if (destination_type == option->conversion_option.destination_type && option->conversion_option.source_type != tDataType<bool>())
409      {
410        tConversionOption first_option = GetImplicitConversionOption(source_type, option->conversion_option.source_type, registered_operations);
411        if (first_option.type != tConversionOptionType::NONE)
412        {
413          return std::pair<tConversionOption, tConversionOption>(first_option, option->conversion_option);
414        }
415      }
416    }
417  }
418  return std::pair<tConversionOption, tConversionOption>(tConversionOption(), tConversionOption());
419}
420
421void tStaticCastOperation::OnCompile(const tConversionOption& conversion_option, tCustomOperationData& custom_data) const
422{
423  OnCompileToEnum<uint8_t>(*this, conversion_option, custom_data);
424  OnCompileToEnum<uint16_t>(*this, conversion_option, custom_data);
425  OnCompileToEnum<uint32_t>(*this, conversion_option, custom_data);
426  OnCompileToEnum<uint64_t>(*this, conversion_option, custom_data);
427}
428
429std::vector<tType> tStaticCastOperation::SupportedDestinationTypes(const tType& source_type) const
430{
431  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
432  const auto& type_register = tType::GetTypeRegister();
433  std::vector<tType> options;
434
435  size_t type_count = tType::GetTypeCount();
436  bool types_tested[type_count];
437  memset(types_tested, 0, sizeof(types_tested));
438
439  if (source_type)
440  {
441    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
442    {
443      auto destination_type = *it;
444      if (destination_type != source_type)
445      {
446        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
447        if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && (result.common_underlying_type == source_type || result.cast_from_common_to_destination_type_implicit || result.cast_from_source_to_common_type_implicit)))
448        {
449          options.emplace_back(destination_type);
450          types_tested[destination_type.GetHandle()] = true;
451        }
452      }
453    }
454
455    for (auto & option : registered_operations.static_casts)
456    {
457      if (source_type == option->conversion_option.source_type && (!types_tested[option->conversion_option.destination_type.GetHandle()]))
458      {
459        options.push_back(option->conversion_option.destination_type);
460        types_tested[option->conversion_option.destination_type.GetHandle()] = true;
461      }
462    }
463
464    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
465    {
466      if (it->GetEnumStringsData() && (!types_tested[it->GetHandle()]))
467      {
468        if (source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC)
469        {
470          options.push_back(*it);
471        }
472        types_tested[it->GetHandle()] = true;
473      }
474    }
475
476    for (auto & option : registered_operations.static_casts)
477    {
478      bool arithmetic_cast = (option->conversion_option.source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0 && (option->conversion_option.destination_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0;
479      if ((option->implicit || arithmetic_cast) && (!types_tested[option->conversion_option.destination_type.GetHandle()]))
480      {
481        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
482        if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
483        {
484          options.emplace_back(option->conversion_option.destination_type);
485          types_tested[option->conversion_option.destination_type.GetHandle()] = true;
486        }
487      }
488      if ((option->implicit || arithmetic_cast) && source_type == option->conversion_option.source_type)
489      {
490        for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
491        {
492          if (!types_tested[it->GetHandle()])
493          {
494            auto destination_type = *it;
495            tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
496            if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
497            {
498              options.emplace_back(destination_type);
499              types_tested[destination_type.GetHandle()] = true;
500            }
501          }
502        }
503      }
504    }
505  }
506
507  if (cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
508  {
509    //RRLIB_LOG_PRINT(DEBUG, "Checking result from ", source_type);
510    CheckEquivalence(tRegisteredConversionOperation::SupportedDestinationTypes(source_type), options);
511  }
512  return options;
513}
514
515std::vector<tType> tStaticCastOperation::SupportedSourceTypes(const tType& destination_type) const
516{
517  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
518  const auto& type_register = tType::GetTypeRegister();
519  std::vector<tType> options;
520
521  size_t type_count = tType::GetTypeCount();
522  bool types_tested[type_count];
523  memset(types_tested, 0, sizeof(types_tested));
524
525  if (destination_type)
526  {
527    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
528    {
529      auto source_type = *it;
530      if (destination_type != source_type)
531      {
532        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
533        if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && (result.common_underlying_type == source_type || result.cast_from_common_to_destination_type_implicit || result.cast_from_source_to_common_type_implicit)))
534        {
535          options.emplace_back(source_type);
536          types_tested[source_type.GetHandle()] = true;
537        }
538      }
539    }
540
541    for (auto & option : registered_operations.static_casts)
542    {
543      if (destination_type == option->conversion_option.destination_type && (!types_tested[option->conversion_option.source_type.GetHandle()]))
544      {
545        options.push_back(option->conversion_option.source_type);
546        types_tested[option->conversion_option.source_type.GetHandle()] = true;
547      }
548    }
549
550    if (destination_type.GetEnumStringsData())
551    {
552      for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
553      {
554        if (it->GetTypeTraits() & trait_flags::cIS_ARITHMETIC && (!types_tested[it->GetHandle()]))
555        {
556          options.push_back(*it);
557        }
558      }
559    }
560    else
561    {
562      for (auto & option : registered_operations.static_casts)
563      {
564        bool arithmetic_cast = (option->conversion_option.source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0 && (option->conversion_option.destination_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC) != 0;
565        if ((option->implicit || arithmetic_cast) && destination_type == option->conversion_option.destination_type)
566        {
567          for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
568          {
569            if (!types_tested[it->GetHandle()])
570            {
571              auto source_type = *it;
572              tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
573              if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
574              {
575                options.emplace_back(source_type);
576                types_tested[source_type.GetHandle()] = true;
577              }
578            }
579          }
580        }
581        if ((option->implicit || arithmetic_cast) && (!types_tested[option->conversion_option.source_type.GetHandle()]))
582        {
583          tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
584          if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
585          {
586            options.emplace_back(option->conversion_option.source_type);
587            types_tested[option->conversion_option.source_type.GetHandle()] = true;
588          }
589        }
590      }
591    }
592  }
593
594  if (cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
595  {
596    //RRLIB_LOG_PRINT(DEBUG, "Checking result to ", destination_type);
597    CheckEquivalence(tRegisteredConversionOperation::SupportedSourceTypes(destination_type), options);
598  }
599  return options;
600}
601
602
603//----------------------------------------------------------------------
604// End of namespace declaration
605//----------------------------------------------------------------------
606}
607}
608}
Note: See TracBrowser for help on using the repository browser.