source: rrlib_rtti_conversion/tRegisteredConversionOperation.cpp @ 9:f909044a9f7b

17.03
Last change on this file since 9:f909044a9f7b was 9:f909044a9f7b, checked in by Max Reichardt <mreichardt@…>, 2 years ago

Adds option to specify type conversions operations that are not usually combined (you could call combinations deprecated) and fixes various bugs found with unit test in finroc_plugins_runtime_construction

File size: 10.1 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/tRegisteredConversionOperation.cpp
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2016-07-15
27 *
28 */
29//----------------------------------------------------------------------
30#include "rrlib/rtti_conversion/tRegisteredConversionOperation.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#include "rrlib/rtti_conversion/tConversionOption.h"
41#include "rrlib/rtti_conversion/tStaticCastOperation.h"
42
43//----------------------------------------------------------------------
44// Debugging
45//----------------------------------------------------------------------
46#include <cassert>
47
48//----------------------------------------------------------------------
49// Namespace usage
50//----------------------------------------------------------------------
51
52//----------------------------------------------------------------------
53// Namespace declaration
54//----------------------------------------------------------------------
55namespace rrlib
56{
57namespace rtti
58{
59namespace conversion
60{
61
62//----------------------------------------------------------------------
63// Forward declarations / typedefs / enums
64//----------------------------------------------------------------------
65
66//----------------------------------------------------------------------
67// Const values
68//----------------------------------------------------------------------
69const char* tRegisteredConversionOperation::cSTATIC_CAST_NAME = "static_cast";
70
71//----------------------------------------------------------------------
72// Implementation
73//----------------------------------------------------------------------
74
75tRegisteredConversionOperation::tRegisteredConversionOperation(util::tManagedConstCharPointer name, const tSupportedTypes& supported_source_types, const tSupportedTypes& supported_destination_types,
76    const tConversionOption* single_conversion_option, const tParameterDefinition& parameter, const tRegisteredConversionOperation* not_usually_combined_with) :
77  name(std::move(name)),
78  supported_source_types(supported_source_types),
79  supported_destination_types(supported_destination_types),
80  parameter(parameter),
81  single_conversion_option(single_conversion_option),
82  not_usually_combined_with_handle(not_usually_combined_with ? not_usually_combined_with->GetHandle() : 0xFFFF)
83{
84  if (parameter && (!(parameter.GetType().GetTypeTraits() & trait_flags::cIS_STRING_SERIALIZABLE)))
85  {
86    throw std::runtime_error(std::string("Conversion operation: '") + this->name.Get() + "'. Parameters have to be string serializable.");
87  }
88  handle = static_cast<decltype(handle)>(tRegisteredConversionOperation::RegisteredOperations().operations.Add(this));
89}
90
91tRegisteredConversionOperation::tRegisteredConversionOperation() :
92  name(cSTATIC_CAST_NAME, false),
93  supported_source_types(tSupportedTypeFilter::STATIC_CAST),
94  supported_destination_types(tSupportedTypeFilter::STATIC_CAST),
95  parameter(),
96  single_conversion_option(nullptr),
97  handle(-1),
98  not_usually_combined_with_handle(0xFFFF)
99{
100  handle = static_cast<decltype(handle)>(tRegisteredConversionOperation::RegisteredOperations().operations.Add(this));
101}
102
103tRegisteredConversionOperation::~tRegisteredConversionOperation()
104{
105}
106
107void tRegisteredConversionOperation::AutoDelete()
108{
109  tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
110  registered_operations.auto_delete.Emplace(this);
111}
112
113const tRegisteredConversionOperation* tRegisteredConversionOperation::Deserialize(rrlib::serialization::tInputStream& stream, bool throw_exception_if_not_found)
114{
115  const tRegisteredConversionOperation* result = nullptr;
116  if (tRegisteredConversionOperation::GetRegisteredOperations().operations.ReadEntry(stream, result))
117  {
118    std::string name = stream.ReadString();
119    tRegisteredConversionOperation::tSupportedTypes source_types = tType();
120    tRegisteredConversionOperation::tSupportedTypes destination_types = tType();
121    stream >> source_types.filter;
122    if (source_types.filter == tSupportedTypeFilter::SINGLE)
123    {
124      source_types.single_type = tType::GetType(stream.ReadShort());
125    }
126    stream >> destination_types.filter;
127    if (destination_types.filter == tSupportedTypeFilter::SINGLE)
128    {
129      destination_types.single_type = tType::GetType(stream.ReadShort());
130    }
131
132    // Find matching conversion operation
133    if (name == cSTATIC_CAST_NAME)
134    {
135      return &tStaticCastOperation::GetInstance();
136    }
137
138    tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
139    for (auto & operation : registered_operations.operations)
140    {
141      if (operation->supported_source_types.filter == source_types.filter && operation->supported_source_types.single_type == source_types.single_type && operation->supported_destination_types.filter == destination_types.filter && operation->supported_destination_types.single_type == destination_types.single_type && name == operation->Name())
142      {
143        return operation;
144      }
145    }
146    if (throw_exception_if_not_found)
147    {
148      throw std::runtime_error("Encoded registered conversion operation not found");
149    }
150  }
151  return result;
152}
153
154std::pair<const tRegisteredConversionOperation*, bool> tRegisteredConversionOperation::Find(const std::string& name)
155{
156  std::pair<const tRegisteredConversionOperation*, bool> result(nullptr, false);
157  if (name == cSTATIC_CAST_NAME)
158  {
159    result.first = &tStaticCastOperation::GetInstance();
160    return result;
161  }
162
163  tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
164  for (auto & operation : registered_operations.operations)
165  {
166    if (name == operation->Name())
167    {
168      if (!result.first)
169      {
170        result.first = operation;
171      }
172      else
173      {
174        result.second = true;
175        return result;
176      }
177    }
178  }
179  return result;
180}
181
182const tRegisteredConversionOperation& tRegisteredConversionOperation::Find(const std::string& name, const tType& source_type, const tType& destination_type)
183{
184  const tRegisteredConversionOperation* result = nullptr;
185  if (name == cSTATIC_CAST_NAME)
186  {
187    return tStaticCastOperation::GetInstance();
188  }
189
190  tRegisteredConversionOperation::tRegisteredOperations& registered_operations = tRegisteredConversionOperation::RegisteredOperations();
191  for (auto & operation : registered_operations.operations)
192  {
193    if (name == operation->Name())
194    {
195      auto option = operation->GetConversionOption((!source_type) && operation->SupportedSourceTypes().filter == tSupportedTypeFilter::SINGLE ? operation->SupportedSourceTypes().single_type : source_type,
196                    (!destination_type) && operation->SupportedDestinationTypes().filter == tSupportedTypeFilter::SINGLE ? operation->SupportedDestinationTypes().single_type : destination_type, nullptr);
197      if (option.type != tConversionOptionType::NONE)
198      {
199        if (result)
200        {
201          throw std::runtime_error("Lookup of registered conversion operation " + name + " is ambiguous");
202        }
203        result = operation;
204      }
205    }
206  }
207  if (!result)
208  {
209    throw std::runtime_error("Lookup of registered conversion operation " + name + " with specified types failed");
210  }
211
212  return *result;
213}
214
215tConversionOption tRegisteredConversionOperation::GetConversionOption(const tType& source_type, const tType& destination_type, const tGenericObject* parameter) const
216{
217  if ((!source_type) || (!destination_type))
218  {
219    throw std::invalid_argument("Source type and destination type must be specified");
220  }
221  if (!single_conversion_option)
222  {
223    throw std::logic_error("Method must be overridden if no single conversion option is specified");
224  }
225  if (single_conversion_option->source_type == source_type && single_conversion_option->destination_type == destination_type)
226  {
227    return *single_conversion_option;
228  }
229  return tConversionOption();
230}
231
232tRegisteredConversionOperation::tRegisteredOperations& tRegisteredConversionOperation::RegisteredOperations()
233{
234  static tRegisteredOperations operations;
235  return operations;
236}
237
238serialization::tOutputStream& operator << (serialization::tOutputStream& stream, const tRegisteredConversionOperation& operation)
239{
240  if (tRegisteredConversionOperation::GetRegisteredOperations().operations.WriteEntry(stream, operation.GetHandle()))
241  {
242    stream << operation.Name() << operation.SupportedSourceTypes().filter;
243    if (operation.SupportedSourceTypes().filter == tSupportedTypeFilter::SINGLE)
244    {
245      stream << operation.SupportedSourceTypes().single_type;
246    }
247    stream << operation.SupportedDestinationTypes().filter;
248    if (operation.SupportedDestinationTypes().filter == tSupportedTypeFilter::SINGLE)
249    {
250      stream << operation.SupportedDestinationTypes().single_type;
251    }
252  }
253
254  return stream;
255}
256
257//----------------------------------------------------------------------
258// End of namespace declaration
259//----------------------------------------------------------------------
260}
261}
262}
Note: See TracBrowser for help on using the repository browser.