Remote Call Framework 3.2
Serializer.hpp
Go to the documentation of this file.
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2020, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 3.2
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
20 
21 #ifndef INCLUDE_SF_SERIALIZER_HPP
22 #define INCLUDE_SF_SERIALIZER_HPP
23 
24 #include <RCF/Exception.hpp>
25 #include <RCF/Export.hpp>
26 #include <RCF/MemStream.hpp>
27 #include <RCF/TypeTraits.hpp>
28 
29 #include <SF/Archive.hpp>
30 #include <SF/I_Stream.hpp>
31 #include <SF/SerializeFundamental.hpp>
32 #include <SF/SfNew.hpp>
33 #include <RCF/Tools.hpp>
34 
35 namespace SF {
36 
37  // Generic serializer, subclassed by all other serializers.
38 
39  class RCF_EXPORT SerializerBase : Noncopyable
40  {
41  private:
42  void invokeRead(Archive &ar);
43  void invokeWrite(Archive &ar);
44 
45  // Following are overridden to provide type-specific operations.
46  virtual std::string getTypeName() = 0;
47  virtual void newObject(Archive &ar) = 0;
48  virtual bool isDerived() = 0;
49  virtual std::string getDerivedTypeName() = 0;
50  virtual void getSerializerPolymorphic(const std::string &derivedTypeName) = 0;
51  virtual void invokeSerializerPolymorphic(SF::Archive &) = 0;
52  virtual void serializeContents(Archive &ar) = 0;
53  virtual void addToInputContext(IStream *, const UInt32 &) = 0;
54  virtual bool queryInputContext(IStream *, const UInt32 &) = 0;
55  virtual void addToOutputContext(OStream *, UInt32 &) = 0;
56  virtual bool queryOutputContext(OStream *, UInt32 &) = 0;
57  virtual void setFromId() = 0;
58  virtual void setToNull() = 0;
59  virtual bool isNull() = 0;
60  virtual bool isNonAtomic() = 0;
61 
62  public:
63  SerializerBase();
64  virtual ~SerializerBase();
65  void invoke(Archive &ar);
66  };
67 
68  //---------------------------------------------------------------------
69  // Type-specific serializers
70 
71  // These pragmas concern Serializer<T>::newObject, but needs to be up here, probably because Serializer<T> is a template
72 #ifdef _MSC_VER
73 #pragma warning( push )
74 #pragma warning( disable : 4675 ) // warning C4675: resolved overload was found by argument-dependent lookup
75 #pragma warning( disable : 4702 ) // warning C4702: unreachable code
76 #endif
77 
78  class I_SerializerPolymorphic;
79 
80  template<typename T>
81  class Serializer : public SerializerBase
82  {
83  public:
84  Serializer(T ** ppt);
85 
86  private:
87  typedef ObjectId IdT;
88  T ** ppt;
89  I_SerializerPolymorphic * pf;
90  IdT id;
91 
92  std::string getTypeName();
93  void newObject(Archive &ar);
94  bool isDerived();
95  std::string getDerivedTypeName();
96  void getSerializerPolymorphic(const std::string &derivedTypeName);
97  void invokeSerializerPolymorphic(SF::Archive &ar);
98  void serializeContents(Archive &ar);
99  void addToInputContext(SF::IStream *stream, const UInt32 &nid);
100  bool queryInputContext(SF::IStream *stream, const UInt32 &nid);
101  void addToOutputContext(SF::OStream *stream, UInt32 &nid);
102  bool queryOutputContext(SF::OStream *stream, UInt32 &nid);
103  void setFromId();
104  void setToNull();
105  bool isNull();
106  bool isNonAtomic();
107  };
108 
109 #ifdef _MSC_VER
110 #pragma warning( pop )
111 #endif
112 
113  template<typename PPT>
114  struct GetIndirection
115  {
116  typedef typename RCF::RemovePointer<PPT>::type PT;
117  typedef typename RCF::IsPointer<PPT>::type is_single;
118  typedef typename RCF::IsPointer<PT>::type is_double;
119 
120  typedef
121  typename RCF::If<
122  is_double,
123  RCF::Int<2>,
124  typename RCF::If<
125  is_single,
126  RCF::Int<1>,
127  RCF::Int<0>
128  >::type
129  >::type Level;
130 
131  typedef
132  typename RCF::RemoveCv<
133  typename RCF::RemovePointer<
134  typename RCF::RemoveCv<
135  typename RCF::RemovePointer<
136  typename RCF::RemoveCv<PPT>::type
137  >::type
138  >::type
139  >::type
140  >::type Base;
141  };
142 
143  template<typename T>
144  inline void invokeCustomSerializer(
145  T **ppt,
146  Archive &ar,
147  int)
148  {
149  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
150  Serializer<T>(ppt).invoke(ar);
151  }
152 
153  template<typename U, typename T>
154  inline void invokeSerializer(
155  U *,
156  T *,
157  RCF::Int<0> *,
158  const U &u,
159  Archive &ar)
160  {
161  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
162  T *pt = const_cast<T *>(&u);
163  invokeCustomSerializer( (T **) (&pt), ar, 0);
164  }
165 
166  template<typename U, typename T>
167  inline void invokeSerializer(
168  U *,
169  T *,
170  RCF::Int<1> *,
171  const U &u,
172  Archive &ar)
173  {
174  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
175  invokeCustomSerializer( (T **) (&u), ar, 0);
176  }
177 
178  template<typename U, typename T>
179  inline void invokeSerializer(
180  U *,
181  T *,
182  RCF::Int<2> *,
183  const U &u,
184  Archive &ar)
185  {
186  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
187  invokeCustomSerializer( (T**) (u), ar, 0);
188  }
189 
190  template<typename U>
191  inline void invokeSerializer(U u, Archive &ar)
192  {
193  typedef typename GetIndirection<U>::Level Level;
194  typedef typename GetIndirection<U>::Base T;
195  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
196  invokeSerializer( (U *) 0, (T *) 0, (Level *) 0, u, ar);
197  }
198 
199  template<typename U>
200  inline void invokePtrSerializer(U u, Archive &ar)
201  {
202  typedef typename GetIndirection<U>::Level Level;
203  const int levelOfIndirection = Level::value;
204  static_assert( levelOfIndirection == 1 || levelOfIndirection == 2, "Incorrect value from GetIndirection<>.");
205  const bool isPointer = (levelOfIndirection == 2);
206 
207 //#ifdef _MSC_VER
208 //#pragma warning(push)
209 //#pragma warning(disable: 6326) // warning C6326: Potential comparison of a constant with another constant.
210 //#endif
211 
212  ar.setFlag( SF::Archive::POINTER, isPointer );
213 
214 //#ifdef _MSC_VER
215 //#pragma warning(pop)
216 //#endif
217 
218  invokeSerializer(u, ar);
219  }
220 
221  // Forward declaration.
222  template<typename T>
223  Archive & operator&(
224  Archive & archive,
225  const T & t);
226 
227  template<typename T>
228  inline void serializeEnum(SF::Archive &ar, T &t)
229  {
230  int runtimeVersion = ar.getRuntimeVersion();
231  if (runtimeVersion >= 2)
232  {
233  ar & SF::Archive::Flag(SF::Archive::NO_BEGIN_END);
234  }
235 
236  if (ar.isRead())
237  {
238  std::int32_t n = 0;
239  ar & n;
240  t = T(n);
241  }
242  else /* if (ar.isWrite())) */
243  {
244  std::int32_t n = t;
245  ar & n;
246  }
247  }
248 
249  template<typename T>
250  inline void serializeInternal(Archive &archive, T &t)
251  {
252  // A compiler error here indicates that the class T has not implemented
253  // an internal SF serialization function. Here are a few situations in
254  // which this can happen:
255 
256  // * No serialization function was provided at all, in which case one
257  // needs to be written (either internal or external).
258  //
259  // * The intention was to provide an external SF serialization function,
260  // but the external serialization function definition is incorrect and
261  // hence not visible to the framework.
262 
263  // * The class is a Protocol Buffers generated class, and the intention
264  // was to serialize it as such, in which case RCF_FEATURE_PROTOBUF=1
265  // needs to be defined.
266 
267  t.serialize(archive);
268  }
269 
270  template<typename T>
271  inline void serializeFundamentalOrNot(
272  Archive & archive,
273  T & t,
274  RCF::TrueType *)
275  {
276  serializeFundamental(archive, t);
277  }
278 
279  template<typename T>
280  inline void serializeFundamentalOrNot(
281  Archive & archive,
282  T & t,
283  RCF::FalseType *)
284  {
285  serializeInternal(archive, t);
286  }
287 
288  template<typename T>
289  inline void serializeEnumOrNot(
290  Archive & archive,
291  T & t,
292  RCF::TrueType *)
293  {
294  serializeEnum(archive, t);
295  }
296 
297  template<typename T>
298  inline void serializeEnumOrNot(
299  Archive & archive,
300  T & t,
301  RCF::FalseType *)
302  {
303  typedef typename RCF::IsFundamental<T>::type type;
304  serializeFundamentalOrNot(archive, t, (type *) NULL);
305  }
306 
307  template<typename T>
308  inline void serialize(
309  Archive & archive,
310  T & t)
311  {
312  typedef typename std::is_enum<T>::type type;
313  serializeEnumOrNot(archive, t, (type *) NULL);
314  }
315 
316  template<typename T>
317  inline void serialize_vc6(
318  Archive & archive,
319  T & t,
320  const unsigned int)
321  {
322  serialize(archive, t);
323  }
324 
325  template<typename T>
326  inline void preserialize(
327  Archive & archive,
328  T *& pt,
329  const unsigned int)
330  {
331  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
332  typedef typename RCF::RemoveCv<T>::type U;
333  serialize_vc6(archive, (U &) *pt, static_cast<const unsigned int>(0) );
334  }
335 
336  template<typename T>
337  Archive & operator&(
338  Archive & archive,
339  const T & t)
340  {
341  invokePtrSerializer(&t, archive);
342  return archive;
343  }
344 
345  template<typename T, typename U>
346  inline void serializeAs(Archive & ar, T &t)
347  {
348  if (ar.isWrite())
349  {
350  U u = static_cast<U>(t);
351  ar & u;
352  }
353  else
354  {
355  U u;
356  ar & u;
357  t = static_cast<T>(u);
358  }
359  }
360 
362 #define SF_SERIALIZE_ENUM_CLASS(EnumType, BaseType) \
363  void serialize(SF::Archive & ar, EnumType & e) \
364  { \
365  SF::serializeAs<EnumType, BaseType>(ar, e); \
366  }
367 
368 }
369 
370 #include <SF/Registry.hpp>
371 #include <SF/SerializePolymorphic.hpp>
372 #include <SF/Stream.hpp>
373 
374 namespace SF {
375 
376  template<typename T>
377  Serializer<T>::Serializer(T **ppt) :
378  ppt(ppt),
379  pf(),
380  id()
381  {}
382 
383  template<typename T>
384  std::string Serializer<T>::getTypeName()
385  {
386  return SF::Registry::getSingleton().getTypeName( (T *) 0);
387  }
388 
389 #ifdef _MSC_VER
390 #pragma warning( push )
391 #pragma warning( disable: 4702 )
392 #endif
393 
394  template<typename T>
395  void Serializer<T>::newObject(Archive &ar)
396  {
397  *ppt = sfNew((T *) NULL, (T **) NULL, ar);
398  }
399 
400 #ifdef _MSC_VER
401 #pragma warning( pop )
402 #endif
403 
404  template<typename T>
405  bool Serializer<T>::isDerived()
406  {
407  static const bool isFundamental = RCF::IsFundamental<T>::value;
408  if RCF_CONSTEXPR(!isFundamental)
409  {
410  if ( *ppt && typeid(T) != typeid(**ppt) )
411  {
412  if ( !SF::Registry::getSingleton().isTypeRegistered(typeid(**ppt)) )
413  {
414  RCF::Exception e(RCF::RcfError_SfTypeRegistration, typeid(**ppt).name());
415  RCF_THROW(e);
416  }
417  return true;
418  }
419  }
420  return false;
421  }
422 
423  template<typename T>
424  std::string Serializer<T>::getDerivedTypeName()
425  {
426  return SF::Registry::getSingleton().getTypeName( typeid(**ppt) );
427  }
428 
429  template<typename T>
430  void Serializer<T>::getSerializerPolymorphic(
431  const std::string &derivedTypeName)
432  {
433  pf = & SF::Registry::getSingleton().getSerializerPolymorphic(
434  (T *) 0,
435  derivedTypeName);
436  }
437 
438  template<typename T>
439  void Serializer<T>::invokeSerializerPolymorphic(SF::Archive &ar)
440  {
441  RCF_ASSERT(pf);
442  void **ppvb = (void **) (ppt); // not even reinterpret_cast wants to touch this
443  pf->invoke(ppvb, ar);
444  }
445 
446  template<typename T>
447  void Serializer<T>::serializeContents(Archive &ar)
448  {
449  preserialize(ar, *ppt, 0);
450  }
451 
452  template<typename T>
453  void Serializer<T>::addToInputContext(SF::IStream *stream, const UInt32 &nid)
454  {
455  ContextRead &ctx = stream->getTrackingContext();
456  ctx.add(nid, IdT( (void *) (*ppt), &typeid(T)));
457  }
458 
459  template<typename T>
460  bool Serializer<T>::queryInputContext(SF::IStream *stream, const UInt32 &nid)
461  {
462  ContextRead &ctx = stream->getTrackingContext();
463  return ctx.query(nid, id);
464  }
465 
466  template<typename T>
467  void Serializer<T>::addToOutputContext(SF::OStream *stream, UInt32 &nid)
468  {
469  ContextWrite &ctx = stream->getTrackingContext();
470  ctx.add( IdT( (void *) *ppt, &typeid(T)), nid);
471  }
472 
473  template<typename T>
474  bool Serializer<T>::queryOutputContext(SF::OStream *stream, UInt32 &nid)
475  {
476  ContextWrite &ctx = stream->getTrackingContext();
477  return ctx.query( IdT( (void *) *ppt, &typeid(T)), nid);
478  }
479 
480  template<typename T>
481  void Serializer<T>::setFromId()
482  {
483  *ppt = reinterpret_cast<T *>(id.first);
484  }
485 
486  template<typename T>
487  void Serializer<T>::setToNull()
488  {
489  *ppt = NULL;
490  }
491 
492  template<typename T>
493  bool Serializer<T>::isNull()
494  {
495  return *ppt == NULL;
496  }
497 
498  template<typename T>
499  bool Serializer<T>::isNonAtomic()
500  {
501  bool isFundamental = RCF::IsFundamental<T>::value;
502  return !isFundamental;
503  }
504 
505 } // namespace SF
506 
507 #endif // ! INCLUDE_SF_SERIALIZER_HPP
Represents an archive, in which serialized objects are stored.
Definition: Archive.hpp:32
int getRuntimeVersion()
Gets the RCF runtime version associated with this archive.
Base class for all RCF exceptions.
Definition: Exception.hpp:64
Definition: ByteBuffer.hpp:189
Base class for output streams using SF serialization. Use operator <<() to serialize objects into the...
Definition: Stream.hpp:236
bool isRead() const
Returns true if this archive is being read from.
Base class for input streams using SF serialization. Use operator >>() to deserialize objects from th...
Definition: Stream.hpp:138