source: rrlib_rtti_conversion/tStaticCastOperation.h @ 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: 15.4 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.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2016-07-17
27 *
28 * \brief   Contains tStaticCastOperation
29 *
30 * \b tStaticCastOperation
31 *
32 * Due to their special/universal nature, casts are handled separately from other conversion operations.
33 * For instance, they may be implicit and new casts can be registered at any time.
34 *
35 */
36//----------------------------------------------------------------------
37#ifndef __rrlib__rtti_conversion__tStaticCastOperation_h__
38#define __rrlib__rtti_conversion__tStaticCastOperation_h__
39
40//----------------------------------------------------------------------
41// External includes (system with <>, local with "")
42//----------------------------------------------------------------------
43#include "rrlib/thread/tLock.h"
44
45//----------------------------------------------------------------------
46// Internal includes with ""
47//----------------------------------------------------------------------
48#include "rrlib/rtti_conversion/tRegisteredConversionOperation.h"
49#include "rrlib/rtti_conversion/type_traits.h"
50#include "rrlib/rtti_conversion/tCompiledConversionOperation.h"
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// Class declaration
68//----------------------------------------------------------------------
69//! Static cast operations
70/*!
71 * Due to their special/universal nature, casts are handled separately from other conversion operations.
72 * For instance, they may be implicit and new casts can be registered at any time.
73 */
74class tStaticCastOperation : public tRegisteredConversionOperation
75{
76  typedef tConversionOptionStaticCast tStaticCast;
77
78  /*! Standard static cast operation */
79  template <typename TSource, typename TDestination>
80  struct tInstanceStandard
81  {
82    static void ConvertFinal(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
83    {
84      (*destination_object.Get<TDestination>()) = static_cast<TDestination>(*source_object.Get<TSource>());
85    }
86
87    static void ConvertFirst(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
88    {
89      TDestination intermediate = static_cast<TDestination>(*source_object.Get<TSource>());
90      operation.Continue(tTypedConstPointer(&intermediate), destination_object);
91    }
92
93    static constexpr tStaticCast value = { { tConversionOption(tDataType<TSource>(), tDataType<TDestination>(), StaticCastReferencesSourceWithVariableOffset<TSource, TDestination>::value, &ConvertFirst, &ConvertFinal) }, IsImplicitlyConvertible<TDestination, TSource>::value };
94    enum { cREGISTER_OPERATION = 1 };
95  };
96
97  /*! If source and destination types have the same underlying type, this is used */
98  template <typename TSource, typename TDestination>
99  struct tInstanceDeepCopy
100  {
101    static constexpr tStaticCast value = { { tConversionOption(tDataType<TSource>(), tDataType<TDestination>(), 0) }, IsImplicitlyConvertible<TDestination, TSource>::value };
102    enum { cREGISTER_OPERATION = 0 };
103  };
104
105  struct tInstanceNone
106  {
107    static const tStaticCast value;
108    enum { cREGISTER_OPERATION = 0 };
109  };
110
111
112  /*! Any static cast operation */
113  template <typename TSource, typename TDestination>
114  struct tInstance : std::conditional<std::is_same<TSource, void>::value, tInstanceNone, typename std::conditional<std::is_same<typename UnderlyingType<TSource>::type, typename UnderlyingType<TDestination>::type>::value, tInstanceDeepCopy<TSource, TDestination>, tInstanceStandard<TSource, TDestination>>::type>::type
115  {
116  };
117
118  /*! Static cast operation with fixed offset reference to source */
119  template <typename TSource, typename TDestination>
120  struct tInstanceReferenceStaticOffset
121  {
122    static_assert(sizeof(TSource) >= sizeof(TDestination), "Static up-casts by-reference are not supported (potentially unsafe without further checks)");
123
124    static const tStaticCast value;
125
126    static size_t ComputePointerSourceOffset()
127    {
128      const TSource source_object = TSource();
129      const TDestination& returned_object = static_cast<const TDestination&>(source_object);
130      size_t difference = reinterpret_cast<const char*>(&returned_object) - reinterpret_cast<const char*>(&source_object);
131      assert(difference + sizeof(TDestination) <= sizeof(TSource));
132      return difference;
133    }
134  };
135
136  /*! Static cast operation with variable offset reference to source */
137  template <typename TSource, typename TDestination>
138  struct tInstanceReferenceVariableOffset
139  {
140    static tTypedConstPointer GetDestinationReference(const tTypedConstPointer& source_object, const tCurrentConversionOperation& operation)
141    {
142      return tTypedConstPointer(&static_cast<const TDestination&>(*source_object.Get<TSource>()));
143    }
144
145    static void ConvertFirst(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
146    {
147      const TDestination& intermediate = static_cast<const TDestination&>(*source_object.Get<TSource>());
148      operation.Continue(tTypedConstPointer(&intermediate), destination_object);
149    }
150
151    static constexpr tStaticCast value = { { tConversionOption(tDataType<TSource>(), tDataType<TDestination>(), &ConvertFirst, &GetDestinationReference) }, IsImplicitlyConvertible<TDestination&, TSource>::value };
152  };
153
154  /* Specialization for reference type destination */
155  template <typename TSource, typename TDestination>
156  struct tInstance<TSource, TDestination&> : std::conditional<StaticCastReferencesSourceWithVariableOffset<TSource, TDestination&>::value, tInstanceReferenceVariableOffset<TSource, TDestination>, tInstanceReferenceStaticOffset<TSource, TDestination>>::type
157  {
158    enum { cREGISTER_OPERATION = 1 };
159  };
160
161  /*! Standard dedicated static cast operation for vectors*/
162  template <typename TSource, typename TDestination>
163  struct tInstanceVectorStandard
164  {
165    static void ConvertFinal(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
166    {
167      const std::vector<TSource>& source = *source_object.Get<std::vector<TSource>>();
168      std::vector<TDestination>& destination = *destination_object.Get<std::vector<TDestination>>();
169      destination.resize(source.size());
170      auto it_dest = destination.begin();
171      for (auto it = source.begin(); it != source.end(); ++it, ++it_dest)
172      {
173        *it_dest = static_cast<TDestination>(*it);
174      }
175    }
176
177    static void ConvertFirst(const tTypedConstPointer& source_object, const tTypedPointer& destination_object, const tCurrentConversionOperation& operation)
178    {
179      const std::vector<TSource>& source = *source_object.Get<std::vector<TSource>>();
180      std::vector<TDestination> intermediate;
181      intermediate.resize(source.size());
182      auto it_dest = intermediate.begin();
183      for (auto it = source.begin(); it != source.end(); ++it, ++it_dest)
184      {
185        *it_dest = static_cast<TDestination>(*it);
186      }
187      operation.Continue(tTypedConstPointer(&intermediate), destination_object);
188    }
189
190    static constexpr tStaticCast value = { { tConversionOption(tDataType<std::vector<TSource>>(), tDataType<std::vector<TDestination>>(), StaticCastReferencesSourceWithVariableOffset<TSource, TDestination>::value, &ConvertFirst, &ConvertFinal) }, false };
191    enum { cREGISTER_OPERATION = 1 };
192  };
193
194  /*! If source and destination types have the same underlying type, this is used */
195  template <typename TSource, typename TDestination>
196  struct tInstanceVectorDeepCopy
197  {
198    static constexpr tStaticCast value = { { tConversionOption(tDataType<std::vector<TSource>>(), tDataType<std::vector<TDestination>>(), 0) }, false };
199    enum { cREGISTER_OPERATION = 0 };
200  };
201
202  /*! Any static cast operation */
203  template <typename TSource, typename TDestination>
204  struct tInstanceVector : std::conditional<std::is_same<TSource, void>::value, tInstanceNone, typename std::conditional<std::is_same<typename UnderlyingType<TSource>::type, typename UnderlyingType<TDestination>::type>::value, tInstanceVectorDeepCopy<TSource, TDestination>, tInstanceVectorStandard<TSource, TDestination>>::type>::type
205  {
206  };
207
208//----------------------------------------------------------------------
209// Public methods and typedefs
210//----------------------------------------------------------------------
211public:
212
213  /*!
214   * Get single implicit conversion option from source to destination type (if any).
215   *
216   * \param source_type Source type of implicit conversion operation
217   * \param destination_type Destination type of implicit conversion operation
218   * \return Implicit conversion option. If there is no implicit conversion option, the type is NONE. If source_type == destination_type, returns CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT option (with offset 0).
219   */
220  static tConversionOption GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type);
221
222  /*!
223   * Get implicit conversion options from source to destination type (if any).
224   *
225   * \param source_type Source type of implicit conversion operations
226   * \param destination_type Destination type of implicit conversion operations
227   * \return Implicit conversion options. If there is no implicit conversion option, the type is NONE. If one conversion option is sufficient, the second's type is NONE. If source_type == destination_type, returns CONST_OFFSET_REFERENCE_TO_SOURCE_OBJECT option (with offset 0).
228   */
229  static std::pair<tConversionOption, tConversionOption> GetImplicitConversionOptions(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type);
230
231  /*!
232   * \return Single instance of static cast operation
233   */
234  static const tStaticCastOperation& GetInstance()
235  {
236    return instance;
237  }
238
239  /*!
240   * Is source type implicitly convertible to destination type (possibly using a sequence of two implicit cast operations)?
241   *
242   * \param source_type Source type of implicit conversion
243   * \param destination_type Destination type of implicit conversion
244   * \return Whether implicit conversion is possible (also true if source_type == destination_type)
245   */
246  static bool IsImplicitlyConvertibleTo(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type)
247  {
248    return GetImplicitConversionOptions(source_type, destination_type).first.type != tConversionOptionType::NONE;
249  }
250
251  /*!
252   * Registers static cast operation.
253   * (Not necessary for casts specified via WrapsType type trait)
254   *
255   * \tparam TSource Source type of conversion operation
256   * \tparam TDestination Destination type of conversion operation. Append '&' to cast source reference to destination reference.
257   * \tparam Tregister_reverse_operation Also create/register reverse operation?
258   * \tparam Tregister_dedicated_vector_cast Create dedicated cast-operation for std::vector<TSource> to std::vector<TDestination>, too? (otherwise a less efficient generic one will be used; a dedicated one makes sense for vectors with typically many elements such as std::vector<float>)
259   * \return Reference to static_cast operation for convenience (to make additional Register calls)
260   */
261  template <typename TSource, typename TDestination, bool Tregister_reverse_operation = false, bool Tregister_dedicated_vector_cast = false>
262  static tStaticCastOperation& Register()
263  {
264    static_assert(!std::is_reference<TSource>::value, "Source type must not be reference");
265    static_assert((!std::is_reference<TDestination>::value) || (!Tregister_reverse_operation), "Cannot register reverse operation for reference type destination");
266    static_assert(((!IsStdVector<TSource>::value) && (!IsStdVector<TDestination>::value)) || (!Tregister_dedicated_vector_cast), "Cannot register dedicated vector cast for std::vector types");
267
268    typedef tInstance<TSource, TDestination> tOperation;
269    typedef tInstance<typename std::conditional<Tregister_reverse_operation, TDestination, void>::type, typename std::conditional<Tregister_reverse_operation, TSource, void>::type> tOperationReverse;
270    typedef tInstanceVector < typename std::conditional<Tregister_dedicated_vector_cast, TSource, void>::type,
271            typename std::conditional<Tregister_dedicated_vector_cast, TDestination, void>::type > tVectorOperation;
272    typedef tInstanceVector < typename std::conditional < Tregister_dedicated_vector_cast && Tregister_reverse_operation, TDestination, void >::type,
273            typename std::conditional < Tregister_dedicated_vector_cast && Tregister_reverse_operation, TSource, void >::type > tVectorOperationReverse;
274
275    tRegisteredOperations& registered_ops = tRegisteredConversionOperation::RegisteredOperations();
276    if (tOperation::cREGISTER_OPERATION)
277    {
278      registered_ops.static_casts.Add(&tOperation::value);
279    }
280    if (tOperationReverse::cREGISTER_OPERATION)
281    {
282      registered_ops.static_casts.Add(&tOperationReverse::value);
283    }
284    if (tVectorOperation::cREGISTER_OPERATION)
285    {
286      registered_ops.static_casts.Add(&tVectorOperation::value);
287    }
288    if (tVectorOperationReverse::cREGISTER_OPERATION)
289    {
290      registered_ops.static_casts.Add(&tVectorOperationReverse::value);
291    }
292
293    return instance;
294  }
295
296//----------------------------------------------------------------------
297// Private fields and methods
298//----------------------------------------------------------------------
299private:
300
301  /*! Single instance of static cast operation */
302  static tStaticCastOperation instance;
303
304  tStaticCastOperation();
305
306  /*!
307   * Internal version of GetImplicitConversionOption (must only be called with lock in registered_operations)
308   */
309  static tConversionOption GetImplicitConversionOption(const rrlib::rtti::tType& source_type, const rrlib::rtti::tType& destination_type, const tRegisteredConversionOperation::tRegisteredOperations& registered_operations);
310
311  virtual tConversionOption GetConversionOption(const tType& source_type, const tType& destination_type, const tGenericObject* parameter) const override;
312};
313
314//----------------------------------------------------------------------
315// End of namespace declaration
316//----------------------------------------------------------------------
317}
318}
319}
320
321#include "rrlib/rtti_conversion/tStaticCastOperation.hpp"
322
323#endif
Note: See TracBrowser for help on using the repository browser.