source: rrlib_rtti_conversion/tStaticCastOperation.cpp @ 40:3a50f65e594b

17.03
Last change on this file since 40:3a50f65e594b was 40:3a50f65e594b, checked in by Max Reichardt <mreichardt@…>, 10 months ago

Revises implementation of tCustomOperationData: custom types can now be emplaced into storage (instead of using a semi-clean union of variants with use cases).

File size: 26.3 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
150struct tConvertToEnumOperationData
151{
152  typedef void (*tConversionFunction)(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation);
153  tConversionFunction conversion_function;
154};
155
156template <typename TEnumUnderlyingType>
157void ConvertToEnumFinal(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
158{
159  static_assert(std::is_unsigned<TEnumUnderlyingType>::value && std::is_integral<TEnumUnderlyingType>::value, "Currently only unsigned int types are supported");
160
161  // Obtain value
162  tConversionOption::tConversionFunction function = operation.GetCustomData().Get<tConvertToEnumOperationData>().conversion_function;
163  TEnumUnderlyingType value = 0;
164  if (function)
165  {
166    (*function)(source_object, tTypedPointer(&value, tDataType<TEnumUnderlyingType>()), operation);
167  }
168  else
169  {
170    assert(source_object.GetType().GetSize() == sizeof(TEnumUnderlyingType));
171    memcpy(&value, source_object.GetRawDataPointer(), sizeof(TEnumUnderlyingType));
172  }
173
174  // Check whether value is in bounds
175  auto enum_strings = destination_object.GetType().GetEnumStringsData();
176  if (enum_strings->non_standard_values)
177  {
178    const TEnumUnderlyingType* values = static_cast<const TEnumUnderlyingType*>(enum_strings->non_standard_values);
179    bool found = false;
180    for (size_t i = 0; i < enum_strings->size; i++)
181    {
182      if (values[i] == value)
183      {
184        found = true;
185        break;
186      }
187    }
188    if (!found)
189    {
190      serialization::tStringOutputStream stream;
191      stream << "Error casting value '";
192      source_object.Serialize(stream);
193      stream << "' to enum '" << destination_object.GetType().GetName() << "'";
194      throw std::invalid_argument(stream.ToString());
195    }
196  }
197  else if (value >= enum_strings->size)
198  {
199    serialization::tStringOutputStream stream;
200    stream << "Error casting out of bounds value '";
201    source_object.Serialize(stream);
202    stream << "' to enum '" << destination_object.GetType().GetName() << "'";
203    throw std::invalid_argument(stream.ToString());
204  }
205
206  assert(destination_object.GetType().GetSize() == sizeof(TEnumUnderlyingType));
207  memcpy(destination_object.GetRawDataPointer(), &value, sizeof(TEnumUnderlyingType));
208}
209
210template <typename TEnumUnderlyingType>
211static void ConvertToEnumFirst(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
212{
213  TEnumUnderlyingType intermediate_buffer = 0;
214  tTypedPointer intermediate(&intermediate_buffer, operation.compiled_operation.IntermediateType());
215  ConvertToEnumFinal<TEnumUnderlyingType>(source_object, intermediate, operation);
216  operation.Continue(intermediate, destination_object);
217}
218
219template <typename TEnumUnderlyingType>
220static void OnCompileToEnum(const tRegisteredConversionOperation& static_cast_operation, const tConversionOption& conversion_option, tCustomOperationData& custom_data)
221{
222  // Lookup underlying type conversion function
223  if (conversion_option.first_conversion_function == &ConvertToEnumFirst<TEnumUnderlyingType> && conversion_option.source_type.GetSize() != sizeof(TEnumUnderlyingType))
224  {
225    tConversionOption option = static_cast_operation.GetConversionOption(conversion_option.source_type, tDataType<TEnumUnderlyingType>(), nullptr);
226    assert(option.first_conversion_function && option.type == tConversionOptionType::STANDARD_CONVERSION_FUNCTION);
227    tConvertToEnumOperationData operation_data;
228    operation_data.conversion_function = option.final_conversion_function;
229    custom_data.Emplace(operation_data);
230  }
231}
232
233void CheckEquivalence(const std::vector<tType>& base_result, const std::vector<tType>& result)
234{
235  if (!cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
236  {
237    return;
238  }
239
240  bool equivalent = base_result.size() == result.size();
241  if (base_result.size() != result.size())
242  {
243    RRLIB_LOG_PRINT(ERROR, "Results have different size (", base_result.size(), " vs. ", result.size(), ")");
244  }
245  for (auto & type : result)
246  {
247    if (std::count(base_result.begin(), base_result.end(), type) == 0)
248    {
249      RRLIB_LOG_PRINT(ERROR, "Type ", type, " missing in base result");
250      equivalent = false;
251    }
252  }
253  for (auto & type : base_result)
254  {
255    if (std::count(result.begin(), result.end(), type) == 0)
256    {
257      RRLIB_LOG_PRINT(ERROR, "Type ", type, " missing in result");
258      equivalent = false;
259    }
260  }
261
262  if (!equivalent)
263  {
264    throw std::runtime_error("Invalid result");
265  }
266}
267
268}
269
270tStaticCastOperation::tStaticCastOperation() : tRegisteredConversionOperation()
271{}
272
273tConversionOption tStaticCastOperation::GetConversionOption(const tType& source_type, const tType& destination_type, const tGenericObject* parameter) const
274{
275  if (source_type == destination_type)
276  {
277    return tConversionOption(source_type, destination_type, 0);
278  }
279  tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
280  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)))
281  {
282    return tConversionOption(source_type, destination_type, 0);
283  }
284  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
285  for (auto & option : registered_operations.static_casts)
286  {
287    if (source_type == option->conversion_option.source_type && destination_type == option->conversion_option.destination_type)
288    {
289      return option->conversion_option;
290    }
291  }
292
293  // If destination is enum type, use checked conversion
294  if (destination_type.GetEnumStringsData())
295  {
296    if (source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC)
297    {
298      if (destination_type.GetSize() == 1)
299      {
300        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint8_t>, &ConvertToEnumFinal<uint8_t>);
301      }
302      else if (destination_type.GetSize() == 2)
303      {
304        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint16_t>, &ConvertToEnumFinal<uint16_t>);
305      }
306      else if (destination_type.GetSize() == 4)
307      {
308        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint32_t>, &ConvertToEnumFinal<uint32_t>);
309      }
310      else if (destination_type.GetSize() == 8)
311      {
312        return tConversionOption(source_type, destination_type, false, &ConvertToEnumFirst<uint64_t>, &ConvertToEnumFinal<uint64_t>);
313      }
314    }
315
316    return tConversionOption();
317  }
318
319  // Combining (non-implicit) underlying type casts with implicit or arithmetic casts can be done in a single operation
320  for (auto & option : registered_operations.static_casts)
321  {
322    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;
323    if ((option->implicit || arithmetic_cast) && destination_type == option->conversion_option.destination_type)
324    {
325      result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
326      if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
327      {
328        return option->conversion_option;
329      }
330    }
331    if ((option->implicit || arithmetic_cast) && source_type == option->conversion_option.source_type)
332    {
333      result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
334      if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
335      {
336        return option->conversion_option;
337      }
338    }
339  }
340
341  return tConversionOption();
342}
343
344tConversionOption tStaticCastOperation::GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type)
345{
346  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
347  return GetImplicitConversionOption(source_type, destination_type, registered_operations);
348}
349
350tConversionOption tStaticCastOperation::GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type, const tRegisteredConversionOperation::tRegisteredOperations& registered_operations)
351{
352  if (source_type == destination_type)
353  {
354    return tConversionOption(source_type, destination_type, 0);
355  }
356  tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
357  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))
358  {
359    return tConversionOption(source_type, destination_type, 0);
360  }
361  for (auto & option : registered_operations.static_casts)
362  {
363    if (option->implicit && source_type == option->conversion_option.source_type && destination_type == option->conversion_option.destination_type)
364    {
365      return option->conversion_option;
366    }
367  }
368
369  // Combining implicit underlying type casts with implicit casts can be done in a single operation
370  for (auto & option : registered_operations.static_casts)
371  {
372    if (option->implicit && destination_type == option->conversion_option.destination_type)
373    {
374      result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
375      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))
376      {
377        return option->conversion_option;
378      }
379    }
380    if (option->implicit && source_type == option->conversion_option.source_type)
381    {
382      result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
383      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))
384      {
385        return option->conversion_option;
386      }
387    }
388  }
389
390  return tConversionOption();
391}
392
393
394std::pair<tConversionOption, tConversionOption> tStaticCastOperation::GetImplicitConversionOptions(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type)
395{
396  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
397  tConversionOption single_result = GetImplicitConversionOption(source_type, destination_type, registered_operations);
398  if (single_result.type != tConversionOptionType::NONE)
399  {
400    return std::pair<tConversionOption, tConversionOption>(single_result, tConversionOption());
401  }
402
403  // Try all registered operations
404  for (auto & option : registered_operations.static_casts)
405  {
406    if (option->implicit)
407    {
408      if (source_type == option->conversion_option.source_type && option->conversion_option.destination_type != tDataType<bool>())
409      {
410        tConversionOption second_option = GetImplicitConversionOption(option->conversion_option.destination_type, destination_type, registered_operations);
411        if (second_option.type != tConversionOptionType::NONE)
412        {
413          return std::pair<tConversionOption, tConversionOption>(option->conversion_option, second_option);
414        }
415      }
416      if (destination_type == option->conversion_option.destination_type && option->conversion_option.source_type != tDataType<bool>())
417      {
418        tConversionOption first_option = GetImplicitConversionOption(source_type, option->conversion_option.source_type, registered_operations);
419        if (first_option.type != tConversionOptionType::NONE)
420        {
421          return std::pair<tConversionOption, tConversionOption>(first_option, option->conversion_option);
422        }
423      }
424    }
425  }
426  return std::pair<tConversionOption, tConversionOption>(tConversionOption(), tConversionOption());
427}
428
429void tStaticCastOperation::OnCompile(const tConversionOption& conversion_option, tCustomOperationData& custom_data) const
430{
431  OnCompileToEnum<uint8_t>(*this, conversion_option, custom_data);
432  OnCompileToEnum<uint16_t>(*this, conversion_option, custom_data);
433  OnCompileToEnum<uint32_t>(*this, conversion_option, custom_data);
434  OnCompileToEnum<uint64_t>(*this, conversion_option, custom_data);
435}
436
437std::vector<tType> tStaticCastOperation::SupportedDestinationTypes(const tType& source_type) const
438{
439  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
440  const auto& type_register = tType::GetTypeRegister();
441  std::vector<tType> options;
442
443  size_t type_count = tType::GetTypeCount();
444  bool types_tested[type_count];
445  memset(types_tested, 0, sizeof(types_tested));
446
447  if (source_type)
448  {
449    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
450    {
451      auto destination_type = *it;
452      if (destination_type != source_type)
453      {
454        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
455        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)))
456        {
457          options.emplace_back(destination_type);
458          types_tested[destination_type.GetHandle()] = true;
459        }
460      }
461    }
462
463    for (auto & option : registered_operations.static_casts)
464    {
465      if (source_type == option->conversion_option.source_type && (!types_tested[option->conversion_option.destination_type.GetHandle()]))
466      {
467        options.push_back(option->conversion_option.destination_type);
468        types_tested[option->conversion_option.destination_type.GetHandle()] = true;
469      }
470    }
471
472    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
473    {
474      if (it->GetEnumStringsData() && (!types_tested[it->GetHandle()]))
475      {
476        if (source_type.GetTypeTraits() & trait_flags::cIS_ARITHMETIC)
477        {
478          options.push_back(*it);
479        }
480        types_tested[it->GetHandle()] = true;
481      }
482    }
483
484    for (auto & option : registered_operations.static_casts)
485    {
486      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;
487      if ((option->implicit || arithmetic_cast) && (!types_tested[option->conversion_option.destination_type.GetHandle()]))
488      {
489        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
490        if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
491        {
492          options.emplace_back(option->conversion_option.destination_type);
493          types_tested[option->conversion_option.destination_type.GetHandle()] = true;
494        }
495      }
496      if ((option->implicit || arithmetic_cast) && source_type == option->conversion_option.source_type)
497      {
498        for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
499        {
500          if (!types_tested[it->GetHandle()])
501          {
502            auto destination_type = *it;
503            tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
504            if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
505            {
506              options.emplace_back(destination_type);
507              types_tested[destination_type.GetHandle()] = true;
508            }
509          }
510        }
511      }
512    }
513  }
514
515  if (cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
516  {
517    //RRLIB_LOG_PRINT(DEBUG, "Checking result from ", source_type);
518    CheckEquivalence(tRegisteredConversionOperation::SupportedDestinationTypes(source_type), options);
519  }
520  return options;
521}
522
523std::vector<tType> tStaticCastOperation::SupportedSourceTypes(const tType& destination_type) const
524{
525  const tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
526  const auto& type_register = tType::GetTypeRegister();
527  std::vector<tType> options;
528
529  size_t type_count = tType::GetTypeCount();
530  bool types_tested[type_count];
531  memset(types_tested, 0, sizeof(types_tested));
532
533  if (destination_type)
534  {
535    for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
536    {
537      auto source_type = *it;
538      if (destination_type != source_type)
539      {
540        tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, destination_type);
541        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)))
542        {
543          options.emplace_back(source_type);
544          types_tested[source_type.GetHandle()] = true;
545        }
546      }
547    }
548
549    for (auto & option : registered_operations.static_casts)
550    {
551      if (destination_type == option->conversion_option.destination_type && (!types_tested[option->conversion_option.source_type.GetHandle()]))
552      {
553        options.push_back(option->conversion_option.source_type);
554        types_tested[option->conversion_option.source_type.GetHandle()] = true;
555      }
556    }
557
558    if (destination_type.GetEnumStringsData())
559    {
560      for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
561      {
562        if (it->GetTypeTraits() & trait_flags::cIS_ARITHMETIC && (!types_tested[it->GetHandle()]))
563        {
564          options.push_back(*it);
565        }
566      }
567    }
568    else
569    {
570      for (auto & option : registered_operations.static_casts)
571      {
572        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;
573        if ((option->implicit || arithmetic_cast) && destination_type == option->conversion_option.destination_type)
574        {
575          for (auto it = type_register.Begin(), end = type_register.End(); it != end; ++it)
576          {
577            if (!types_tested[it->GetHandle()])
578            {
579              auto source_type = *it;
580              tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(source_type, option->conversion_option.source_type);
581              if (result.common_underlying_type == option->conversion_option.source_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == source_type))
582              {
583                options.emplace_back(source_type);
584                types_tested[source_type.GetHandle()] = true;
585              }
586            }
587          }
588        }
589        if ((option->implicit || arithmetic_cast) && (!types_tested[option->conversion_option.source_type.GetHandle()]))
590        {
591          tCommonUnderlyingTypeResult result = GetCommonUnderlyingType(option->conversion_option.destination_type, destination_type);
592          if (result.common_underlying_type == destination_type || (result.cast_from_common_to_destination_type_valid && result.common_underlying_type == option->conversion_option.destination_type))
593          {
594            options.emplace_back(option->conversion_option.source_type);
595            types_tested[option->conversion_option.source_type.GetHandle()] = true;
596          }
597        }
598      }
599    }
600  }
601
602  if (cVERIFIY_GET_SUPPORTED_TYPES_RESULT)
603  {
604    //RRLIB_LOG_PRINT(DEBUG, "Checking result to ", destination_type);
605    CheckEquivalence(tRegisteredConversionOperation::SupportedSourceTypes(destination_type), options);
606  }
607  return options;
608}
609
610
611//----------------------------------------------------------------------
612// End of namespace declaration
613//----------------------------------------------------------------------
614}
615}
616}
Note: See TracBrowser for help on using the repository browser.