source: rrlib_rtti/tTypedPointer.h @ 127:c83307692316

17.03
Last change on this file since 127:c83307692316 was 127:c83307692316, checked in by Max Reichardt <max.reichardt@…>, 15 months ago

Adds basic size check assertion to tTypedPointer::GetUnchecked method (there are no use cases for returning pointers to objects in invalid memory) and relaxes type check assertion in tTypedPointer::DeepCopyFrom to support several levels of underlying types

File size: 15.8 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/tTypedPointer.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2016-07-21
27 *
28 * \brief   Contains tTypedPointer
29 *
30 * \b tTypedPointer
31 *
32 * Pointer with runtime type information attached.
33 * It points to an object whose type is not known at compile time.
34 * The rrlib_rtti runtime information allows to perform various generic operations
35 * with the object (including type conversion with rrlib_rtti_conversion) -
36 * even without casting it back to the original type.
37 *
38 */
39//----------------------------------------------------------------------
40#ifndef __rrlib__rtti__tTypedPointer_h__
41#define __rrlib__rtti__tTypedPointer_h__
42
43//----------------------------------------------------------------------
44// External includes (system with <>, local with "")
45//----------------------------------------------------------------------
46
47//----------------------------------------------------------------------
48// Internal includes with ""
49//----------------------------------------------------------------------
50#include "rrlib/rtti/tType.h"
51
52//----------------------------------------------------------------------
53// Namespace declaration
54//----------------------------------------------------------------------
55namespace rrlib
56{
57namespace rtti
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64//----------------------------------------------------------------------
65// Class declaration
66//----------------------------------------------------------------------
67//! Pointer with runtime type information attached.
68/*!
69 * Pointer with runtime type information attached.
70 * It points to data whose type is not known at compile time.
71 * The rrlib_rtti runtime information allows to perform various generic operations
72 * with the data (including type conversion with rrlib_rtti_conversion) -
73 * even without casting it back to the original type.
74 *
75 * There is tTypedPointer for non-const data and tTypedConstPointer for const data
76 */
77class tTypedConstPointer
78{
79
80//----------------------------------------------------------------------
81// Public methods and typedefs
82//----------------------------------------------------------------------
83public:
84
85  tTypedConstPointer() : data(nullptr), type() {}
86  tTypedConstPointer(const void* pointer, const tType& type) : data(pointer), type(type)
87  {
88    assert((pointer == nullptr || (type.GetTypeClassification() != tTypeClassification::RPC_TYPE)) && "Only data types are valid");
89  }
90  template <typename T>
91  explicit tTypedConstPointer(const T* object) : data(object), type(tDataType<T>())
92  {}
93
94  inline operator bool() const
95  {
96    return data != nullptr;
97  }
98
99  /*!
100   * Returns whether data of two pointers is equal.
101   * Serializing equal objects must produce identical data.
102   *
103   * \param other Data to compare with
104   */
105  bool Equals(const tTypedConstPointer& other) const
106  {
107    if (other.GetRawDataPointer() == data)
108    {
109      return true;
110    }
111    if (type == this->GetType() && data && other.GetRawDataPointer())
112    {
113      return (type.GetTypeTraits() & trait_flags::cSUPPORTS_BITWISE_COPY) ? memcmp(data, other.GetRawDataPointer(), type.GetSize()) == 0 : (*type.GetBinaryOperations().equals)(*this, other);
114    }
115    return false;
116  }
117
118  /*!
119   * Same as Equals, but also returns true if only underlying types are equal.
120   *
121   * \param other Data to compare with
122   */
123  bool EqualsUnderlying(const tTypedConstPointer& other) const
124  {
125    if (other.GetRawDataPointer() == data)
126    {
127      return true;
128    }
129    if (data && other.GetRawDataPointer() && type.GetUnderlyingType() == this->GetType().GetUnderlyingType())
130    {
131      return (type.GetTypeTraits() & trait_flags::cSUPPORTS_BITWISE_COPY) ? memcmp(data, other.GetRawDataPointer(), type.GetSize()) == 0 : (*type.GetBinaryOperations().equals)(*this, other);
132    }
133    return false;
134  }
135
136  /*!
137   * \return Wrapped object (type T must match original type)
138   */
139  template <typename T>
140  inline const T* Get() const
141  {
142    assert(typeid(typename NormalizedType<T>::type).name() == type.GetRttiName());
143    return static_cast<const T*>(data);
144  }
145
146  /*!
147   * Raw void pointer to wrapped object
148   */
149  inline const void* GetRawDataPointer() const
150  {
151    return data;
152  }
153
154  /*!
155   * \ŗeturn Type information for object
156   */
157  inline const tType& GetType() const
158  {
159    return type;
160  }
161
162  /*!
163   * \param check_exact_size Check that sizeof(T) matches size of wrapped object? (otherwise T may be smaller than wrapped object)
164   * \return Wrapped object (no check for exact type is performed)
165   */
166  template <typename T>
167  inline const T* GetUnchecked(bool check_exact_size = true) const
168  {
169    assert(sizeof(T) == type.GetSize() || ((!check_exact_size) && sizeof(T) <= type.GetSize()));
170    return static_cast<const T*>(data);
171  }
172
173  /*!
174   * Obtain element from vector.
175   *
176   * \param data Data pointer
177   * \param size Index of element
178   * \return
179   * - If index >= return value of tGetVectorSize(), returns nullptr
180   * - If data points to std::vector, returns &std::vector[index]
181   * - Otherwise, returns contents of data
182   */
183  inline tTypedConstPointer GetVectorElement(size_t index) const
184  {
185    if (type.IsListType())
186    {
187      return (*type.GetBinaryOperationsVector().get_vector_element)(*this, index);
188    }
189    else if (index >= 1)
190    {
191      return tTypedConstPointer();
192    }
193    return *this;
194  }
195
196  /*!
197   * \param data Data pointer
198   * \return
199   * - If this points to std::vector, returns std::vector::size()
200   * - If nullptr, returns 0
201   * - Otherwise, returns 1
202   */
203  inline size_t GetVectorSize() const
204  {
205    return type.IsListType() ? (*type.GetBinaryOperationsVector().get_vector_size)(*this) : (data ? 1 : 0);
206  }
207
208  /*!
209   * Serialize data to output stream
210   *
211   * \param stream Output stream
212   */
213  inline void Serialize(serialization::tOutputStream& stream) const
214  {
215    if (data && (type.GetTypeTraits() & trait_flags::cIS_BINARY_SERIALIZABLE))
216    {
217      (*type.GetBinarySerialization().serialize)(stream, *this);
218    }
219    else
220    {
221      throw std::runtime_error("Serialization not supported");
222    }
223  }
224
225  /*!
226   * Serialize data to output stream
227   *
228   * \param stream Output stream
229   */
230  void Serialize(serialization::tStringOutputStream& stream) const;
231
232  /*!
233   * Serialize data to XML node
234   *
235   * \param node XML node
236   */
237  void Serialize(xml::tNode& node) const;
238
239  /*!
240   * Serialize data to binary output stream - possibly using non-binary encoding.
241   *
242   * \param stream Binary output stream
243   * \param encoding Encoding to use
244   */
245  void Serialize(serialization::tOutputStream& stream, serialization::tDataEncoding encoding) const;
246
247  /*!
248   * \return String representation of object this points to. This is the serialized value for string serializable types. Otherwise it is type name + pointer (or "nullptr").
249   */
250  std::string ToString() const;
251
252//----------------------------------------------------------------------
253// Private methods and fields
254//----------------------------------------------------------------------
255private:
256
257  /*! Raw pointer to data/object */
258  const void* data;
259
260  /*! Runtime type information for the data/object that 'data' points to */
261  tType type;
262};
263
264
265class tTypedPointer
266{
267
268//----------------------------------------------------------------------
269// Public methods and typedefs
270//----------------------------------------------------------------------
271public:
272
273  tTypedPointer() : data(nullptr), type() {}
274  tTypedPointer(void* pointer, const tType& type) : data(pointer), type(type)
275  {
276    assert((pointer == nullptr || (type.GetTypeTraits() & trait_flags::cTYPE_CLASSIFICATION_BITS) != static_cast<uint>(tTypeClassification::RPC_TYPE)) && "Only data types are valid");
277  }
278  template <typename T>
279  explicit tTypedPointer(T* object) : data(object), type(tDataType<T>())
280  {}
281
282  inline operator const tTypedConstPointer&() const
283  {
284    return reinterpret_cast<const tTypedConstPointer&>(*this);
285  }
286
287  inline operator bool() const
288  {
289    return data != nullptr;
290  }
291
292  /*!
293   * Deep copy data to data pointed to by this pointer.
294   * A deep copy means that the destination object must not change if the source object is modified or deleted.
295   * Serialization of source and destination objects are equal after calling this.
296   * Caller must ensure that source and destination have the same (underlying) type and are not nullptr.
297   *
298   * \param source Pointer to data to be copied
299   * \throws May throw std::exception on invalid arguments or other failure
300   */
301  inline void DeepCopyFrom(const tTypedConstPointer& source) const
302  {
303    assert((source.GetType().GetSize() == this->GetType().GetSize()) && this->GetRawDataPointer() && source.GetRawDataPointer() && "Types must match and pointers must not be null");
304    if (source.GetRawDataPointer() != this->GetRawDataPointer())
305    {
306      if (type.GetTypeTraits() & trait_flags::cSUPPORTS_BITWISE_COPY)
307      {
308        memcpy(this->GetRawDataPointer(), source.GetRawDataPointer(), type.GetSize());
309      }
310      else
311      {
312        (*type.GetBinaryOperations().deep_copy)(source, *this);
313      }
314    }
315  }
316
317  /*!
318   * Deserialize data from input stream
319   *
320   * \param stream Input stream
321   * \throws Throws std::exception on invalid data in stream
322   */
323  inline void Deserialize(serialization::tInputStream& stream) const
324  {
325    if (data && (type.GetTypeTraits() & trait_flags::cIS_BINARY_SERIALIZABLE))
326    {
327      (*type.GetBinarySerialization().deserialize)(stream, *this);
328    }
329    else
330    {
331      throw std::runtime_error("Deserialization not supported");
332    }
333  }
334
335  /*!
336   * Deserialize data from input stream
337   *
338   * \param stream Input stream
339   * \throws Throws std::exception on invalid data in stream
340   */
341  void Deserialize(serialization::tStringInputStream& stream) const;
342
343  /*!
344   * Deserialize data from XML node
345   *
346   * \param node XML node
347   * \throws Throws std::exception on invalid data in XML node
348   */
349  void Deserialize(const xml::tNode& node) const;
350
351  /*!
352   * Deserialize data from binary input stream - possibly using non-binary encoding.
353   *
354   * \param stream Binary input stream
355   * \param encoding Encoding to use
356   */
357  void Deserialize(serialization::tInputStream& stream, serialization::tDataEncoding encoding) const;
358
359  /*!
360   * Destruct object that this pointer points to.
361   * After this operation, pointer is nullptr.
362   * If already nullptr, nothing is done.
363   */
364  inline void Destruct()
365  {
366    type.DestructInstance(data);
367    data = nullptr;
368  }
369
370  /*!
371   * Returns whether data of two pointers is equal.
372   * Serializing equal objects must produce identical data.
373   *
374   * \param other Data to compare with
375   */
376  bool Equals(const tTypedConstPointer& other) const
377  {
378    return reinterpret_cast<const tTypedConstPointer&>(*this).Equals(other);
379  }
380
381  /*!
382   * Same as Equals, but also returns true if only underlying types are equal.
383   *
384   * \param other Data to compare with
385   */
386  bool EqualsUnderlying(const tTypedConstPointer& other) const
387  {
388    return reinterpret_cast<const tTypedConstPointer&>(*this).EqualsUnderlying(other);
389  }
390
391  /*!
392   * \return Wrapped object (type T must match original type)
393   */
394  template <typename T>
395  inline T* Get() const
396  {
397    assert(typeid(typename NormalizedType<T>::type).name() == type.GetRttiName());
398    return static_cast<T*>(data);
399  }
400
401  /*!
402   * \return Raw void pointer to wrapped object
403   */
404  inline void* GetRawDataPointer() const
405  {
406    return data;
407  }
408
409  /*!
410   * \ŗeturn Type information for object
411   */
412  inline const tType& GetType() const
413  {
414    return type;
415  }
416
417  /*!
418   * \param check_exact_size Check that sizeof(T) matches size of wrapped object? (otherwise T may be smaller than wrapped object)
419   * \return Wrapped object (no check for exact type is performed)
420   */
421  template <typename T>
422  inline T* GetUnchecked(bool check_exact_size = true) const
423  {
424    assert(sizeof(T) == type.GetSize() || ((!check_exact_size) && sizeof(T) <= type.GetSize()));
425    return static_cast<T*>(data);
426  }
427
428  /*!
429   * Obtain element from vector.
430   *
431   * \param data Data pointer
432   * \param size Index of element
433   * \return
434   * - If this points to std::vector, returns &std::vector[index]
435   * - Otherwise, returns this object if index == 0
436   * \throws Throws std::invalid_argument if index is >= of what is returned by tGetVectorSize
437   */
438  inline tTypedPointer GetVectorElement(size_t index) const
439  {
440    if (type.IsListType())
441    {
442      tTypedConstPointer temp = (*type.GetBinaryOperationsVector().get_vector_element)(*this, index);
443      return tTypedPointer(const_cast<void*>(temp.GetRawDataPointer()), temp.GetType());
444    }
445    else if (index >= 1)
446    {
447      throw std::invalid_argument("Invalid index");
448    }
449    return *this;
450  }
451
452  /*!
453   * \param data Data pointer
454   * \return
455   * - If this points to std::vector, returns std::vector::size()
456   * - If nullptr, returns 0
457   * - Otherwise, returns 1
458   */
459  inline size_t GetVectorSize() const
460  {
461    return reinterpret_cast<const tTypedConstPointer&>(*this).GetVectorSize();
462  }
463
464  /*!
465   * Resizes std::vector.
466   *
467   * \param data Pointer to std::vector
468   * \param new_size New size
469   * \throws Throws std::invalid_argument 'data' does not point std::vector
470   */
471  void ResizeVector(size_t new_size) const
472  {
473    if (type.IsListType())
474    {
475      (*type.GetBinaryOperationsVector().resize_vector)(*this, new_size);
476    }
477    else if (new_size != 1)
478    {
479      throw std::invalid_argument("Invalid size - object is not a std::vector");
480    }
481  }
482
483  /*!
484   * Serialize data
485   *
486   * \param target Target to serialize to (output stream or XML node)
487   */
488  template <typename TTarget>
489  inline void Serialize(TTarget& target) const
490  {
491    reinterpret_cast<const tTypedConstPointer&>(*this).Serialize(target);
492  }
493
494  /*!
495   * Serialize data to binary output stream - possibly using non-binary encoding.
496   *
497   * \param stream Binary output stream
498   * \param encoding Encoding to use
499   */
500  void Serialize(serialization::tOutputStream& stream, serialization::tDataEncoding encoding) const
501  {
502    reinterpret_cast<const tTypedConstPointer&>(*this).Serialize(stream, encoding);
503  }
504
505  /*!
506   * \return String representation of object this points to. This is the serialized value for string serializable types. Otherwise it is type name + pointer (or "nullptr").
507   */
508  std::string ToString() const
509  {
510    return reinterpret_cast<const tTypedConstPointer&>(*this).ToString();
511  }
512
513//----------------------------------------------------------------------
514// Private methods and fields
515//----------------------------------------------------------------------
516private:
517
518  /*! Raw pointer to data/object */
519  void* data;
520
521  /*! Runtime type information for the data/object that 'data' points to */
522  tType type;
523
524};
525
526
527//----------------------------------------------------------------------
528// End of namespace declaration
529//----------------------------------------------------------------------
530}
531}
532
533#include "rrlib/rtti/tGenericObject.h"
534
535#endif
Note: See TracBrowser for help on using the repository browser.