source: rrlib_rtti_conversion/tCompiledConversionOperation.h @ 40:3a50f65e594b

17.03
Last change on this file since 40:3a50f65e594b was 40:3a50f65e594b, checked in by Max Reichardt <mreichardt@…>, 2 years 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: 11.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/tCompiledConversionOperation.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2016-07-15
27 *
28 * \brief   Contains tCompiledConversionOperation
29 *
30 * \b tCompiledConversionOperation
31 *
32 * Conversion operation compiled from possibly multiple elementary and/or possibly generic ones.
33 * Compiled conversion operations are furthermore optimized for runtime performance.
34 *
35 */
36//----------------------------------------------------------------------
37#ifndef __rrlib__rtti_conversion__tCompiledConversionOperation_h__
38#define __rrlib__rtti_conversion__tCompiledConversionOperation_h__
39
40//----------------------------------------------------------------------
41// External includes (system with <>, local with "")
42//----------------------------------------------------------------------
43
44//----------------------------------------------------------------------
45// Internal includes with ""
46//----------------------------------------------------------------------
47#include "rrlib/rtti_conversion/defined_conversions.h"
48#include "rrlib/rtti_conversion/tConversionOperationSequence.h"
49#include "rrlib/rtti_conversion/tConversionOption.h"
50#include "rrlib/rtti_conversion/tCurrentConversionOperation.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//! Compiled conversion operation
70/*!
71 * Conversion operation compiled from possibly multiple elementary and/or possibly generic ones.
72 * Compiled conversion operations are furthermore optimized for runtime performance.
73 */
74class tCompiledConversionOperation : public tConversionOperationSequence
75{
76
77//----------------------------------------------------------------------
78// Public methods and typedefs
79//----------------------------------------------------------------------
80public:
81
82  /*! Flags for conversion operation */
83  enum tFlag
84  {
85    /*! Info required for execution */
86    cDO_FINAL_DEEPCOPY_AFTER_FIRST_FUNCTION = 1 << 0,  //!< Do final DeepCopy after first conversion function?
87    cDO_FINAL_DEEPCOPY_AFTER_SECOND_FUNCTION = 1 << 1, //!< Do final DeepCopy after second conversion function?
88    cDEEPCOPY_ONLY = 1 << 2,                           //!< True if conversion operation can be performed with a simple memcpy
89    cFIRST_OPERATION_OPTIMIZED_AWAY = 1 << 3,          //!< True if first operation was optimized away (relevant for parameter lookup)
90
91    /*! Result of conversion operation */
92    cRESULT_INDEPENDENT = 1 << 29,                   //!< Conversion can be performed with Convert(source_object, destination_object). Destination does not reference source object.
93    cRESULT_REFERENCES_SOURCE_INTERNALLY = 1 << 30,  //!< Conversion can be performed with Convert(source_object, destination_object). Destination references source object.
94    cRESULT_REFERENCES_SOURCE_DIRECTLY = 1 << 31,    //!< Conversion can be performed with Convert(source_object).
95  };
96
97  tCompiledConversionOperation() : tConversionOperationSequence(), conversion_function_first(nullptr), conversion_function_final(nullptr), fixed_offset_first(0), fixed_offset_final(0), flags(0)
98  {
99    memset(custom_operation_data_storage, 0, sizeof(custom_operation_data_storage));
100  }
101
102  /*!
103   * Perform actual conversion operation.
104   * Available for any conversion result type. Fills provided destination objects with result.
105   *
106   * \param source_object Typed pointer containing data to convert. Must have source type of this operation.
107   * \param destination_object Typed pointer containing buffer to write converted data to. Its type must be equal to destination_type.
108   *
109   * (note: For performance reasons, in general no type checks are performed.
110   *        The caller is responsible for ensuring that typed pointer point to objects of correct types.)
111   */
112  inline void Convert(const tTypedConstPointer& source_object, const tTypedPointer& destination_object) const
113  {
114    assert(flags & (tFlag::cRESULT_INDEPENDENT | tFlag::cRESULT_REFERENCES_SOURCE_INTERNALLY));
115    tTypedConstPointer intermediate_object(static_cast<const char*>(source_object.GetRawDataPointer()) + fixed_offset_first, type_after_first_fixed_offset); // in case we have a fixed offset and conversion function is a deep copy operation
116    if (flags & tFlag::cDEEPCOPY_ONLY)
117    {
118      destination_object.DeepCopyFrom(intermediate_object);
119    }
120    else
121    {
122      tCurrentConversionOperation current_operation = { *this, 0 };
123      (*conversion_function_first)(intermediate_object, destination_object, current_operation);
124    }
125  }
126
127  /*!
128   * Perform actual conversion operation.
129   * This method is only available if conversion result type is REFERENCES_SOURCE_DIRECTLY.
130   * It returns a direct result to the source object - and therefore does not require any copying.
131   *
132   * \param source_object Source object
133   * \return Destination object (references source object)
134   *
135   * (note: For performance reasons, in general no type checks are performed.
136   *        The caller is responsible for ensuring that typed pointer point to objects of correct types.)
137   */
138  inline tTypedConstPointer Convert(const tTypedConstPointer& source_object) const
139  {
140    assert(flags & tFlag::cRESULT_REFERENCES_SOURCE_DIRECTLY);
141    tTypedConstPointer result(static_cast<const char*>(source_object.GetRawDataPointer()) + fixed_offset_first, type_after_first_fixed_offset);
142    if (get_destination_reference_function_first != nullptr)
143    {
144      tCurrentConversionOperation current_operation = { *this, 0 };
145      result = (*get_destination_reference_function_first)(result, current_operation);
146      if (get_destination_reference_function_final != nullptr)
147      {
148        tCurrentConversionOperation current_operation = { *this, 1 };
149        result = (*get_destination_reference_function_final)(result, current_operation);
150      }
151    }
152    result = tTypedConstPointer(static_cast<const char*>(result.GetRawDataPointer()) + fixed_offset_final, destination_type);
153    return result;
154  }
155
156  /*!
157   * \return Flags for conversion operation
158   */
159  unsigned int Flags() const
160  {
161    return flags;
162  }
163
164  /*!
165   * \return Data type after first conversion function (possibly == destination_type)
166   */
167  const tType& IntermediateType() const
168  {
169    return intermediate_type;
170  }
171
172//----------------------------------------------------------------------
173// Private fields and methods
174//----------------------------------------------------------------------
175private:
176
177  friend class tConversionOperationSequence;
178  friend struct tCurrentConversionOperation;
179
180  /*! Data type after applying first fixed offset */
181  tType type_after_first_fixed_offset;
182
183  /*! Data type after first conversion function (possibly == destination_type) */
184  tType intermediate_type;
185
186  /*! Final data type */
187  tType destination_type;
188
189  /*!
190   * Function pointers to conversion operations. May be null if conversion is performed in another way.
191   * This is preferred to a std::function object here, as it always has minimal memory and computation overhead.
192   * A std::function might be added as a third option if binding of parameters is required.
193   */
194  union
195  {
196    tConversionOption::tConversionFunction conversion_function_first;
197    tConversionOption::tGetDestinationReferenceFunction get_destination_reference_function_first;
198  };
199  union
200  {
201    tConversionOption::tConversionFunction conversion_function_final;
202    tConversionOption::tGetDestinationReferenceFunction get_destination_reference_function_final;
203  };
204
205  /*!
206   * Fixed offsets. In case a memcpy is possible, the second one is the size.
207   */
208  unsigned int fixed_offset_first, fixed_offset_final;
209
210  /*! Flags for conversion operation */
211  unsigned int flags;
212
213  /*!
214   * Custom operation-specific data (e.g. may be filled during compilation for optimization)
215   * (note: if use cases appear that require more or different data, this should be extended)
216   */
217  char* custom_operation_data_storage[2 * tCustomOperationData::cMAX_SIZE];
218
219  tCustomOperationData CustomOperationData(size_t index)
220  {
221    return tCustomOperationData(custom_operation_data_storage + index * tCustomOperationData::cMAX_SIZE);
222  }
223  tConstCustomOperationData CustomOperationData(size_t index) const
224  {
225    return tConstCustomOperationData(custom_operation_data_storage + index * tCustomOperationData::cMAX_SIZE);
226  }
227};
228
229
230// defined here to handle cyclic dependency (also very closely coupled to tCompiledConversionOperation)
231inline void tCurrentConversionOperation::Continue(const tTypedConstPointer& intermediate_object, const tTypedPointer& destination_object) const
232{
233  unsigned int next_operation_index = operation_index + 1;
234  if (compiled_operation.flags & next_operation_index)
235  {
236    // Do final DeepCopy
237    tTypedConstPointer intermediate_2(static_cast<const char*>(intermediate_object.GetRawDataPointer()) + compiled_operation.fixed_offset_final, destination_object.GetType());  // in case second operation is a const_offset
238    destination_object.DeepCopyFrom(intermediate_2);
239  }
240  else
241  {
242    // Call second conversion function
243    tCurrentConversionOperation current_operation = { compiled_operation, next_operation_index };
244    (*compiled_operation.conversion_function_final)(intermediate_object, destination_object, current_operation);
245  }
246}
247
248inline tTypedConstPointer tCurrentConversionOperation::GetParameterValue() const
249{
250  return compiled_operation.GetParameterValue((compiled_operation.flags & tCompiledConversionOperation::tFlag::cFIRST_OPERATION_OPTIMIZED_AWAY) ? 1 : operation_index);
251}
252
253inline tConstCustomOperationData tCurrentConversionOperation::GetCustomData() const
254{
255  return compiled_operation.CustomOperationData(operation_index);
256}
257
258
259//----------------------------------------------------------------------
260// End of namespace declaration
261//----------------------------------------------------------------------
262}
263}
264}
265
266
267#endif
Note: See TracBrowser for help on using the repository browser.