Remote Call Framework 3.0
Serializer.hpp
Go to the documentation of this file.
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2018, 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.0
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  RCF_ASSERT( levelOfIndirection == 1 || levelOfIndirection == 2);
205 
206 #ifdef _MSC_VER
207 #pragma warning(push)
208 #pragma warning(disable: 6326) // warning C6326: Potential comparison of a constant with another constant.
209 #endif
210 
211  ar.setFlag( SF::Archive::POINTER, levelOfIndirection == 2 );
212 
213 #ifdef _MSC_VER
214 #pragma warning(pop)
215 #endif
216 
217  invokeSerializer(u, ar);
218  }
219 
220  // Forward declaration.
221  template<typename T>
222  Archive & operator&(
223  Archive & archive,
224  const T & t);
225 
226  template<typename T>
227  inline void serializeEnum(SF::Archive &ar, T &t)
228  {
229  int runtimeVersion = ar.getRuntimeVersion();
230  if (runtimeVersion >= 2)
231  {
232  ar & SF::Archive::Flag(SF::Archive::NO_BEGIN_END);
233  }
234 
235  if (ar.isRead())
236  {
237  std::int32_t n = 0;
238  ar & n;
239  t = T(n);
240  }
241  else /* if (ar.isWrite())) */
242  {
243  std::int32_t n = t;
244  ar & n;
245  }
246  }
247 
248  template<typename T>
249  inline void serializeInternal(Archive &archive, T &t)
250  {
251  // A compiler error here indicates that the class T has not implemented
252  // an internal SF serialization function. Here are a few situations in
253  // which this can happen:
254 
255  // * No serialization function was provided at all, in which case one
256  // needs to be written (either internal or external).
257  //
258  // * The intention was to provide an external SF serialization function,
259  // but the external serialization function definition is incorrect and
260  // hence not visible to the framework.
261 
262  // * The class is a Protocol Buffers generated class, and the intention
263  // was to serialize it as such, in which case RCF_FEATURE_PROTOBUF=1
264  // needs to be defined.
265 
266  t.serialize(archive);
267  }
268 
269  template<typename T>
270  inline void serializeFundamentalOrNot(
271  Archive & archive,
272  T & t,
273  RCF::TrueType *)
274  {
275  serializeFundamental(archive, t);
276  }
277 
278  template<typename T>
279  inline void serializeFundamentalOrNot(
280  Archive & archive,
281  T & t,
282  RCF::FalseType *)
283  {
284  serializeInternal(archive, t);
285  }
286 
287  template<typename T>
288  inline void serializeEnumOrNot(
289  Archive & archive,
290  T & t,
291  RCF::TrueType *)
292  {
293  serializeEnum(archive, t);
294  }
295 
296  template<typename T>
297  inline void serializeEnumOrNot(
298  Archive & archive,
299  T & t,
300  RCF::FalseType *)
301  {
302  typedef typename RCF::IsFundamental<T>::type type;
303  serializeFundamentalOrNot(archive, t, (type *) NULL);
304  }
305 
306  template<typename T>
307  inline void serialize(
308  Archive & archive,
309  T & t)
310  {
311  typedef typename std::is_enum<T>::type type;
312  serializeEnumOrNot(archive, t, (type *) NULL);
313  }
314 
315  template<typename T>
316  inline void serialize_vc6(
317  Archive & archive,
318  T & t,
319  const unsigned int)
320  {
321  serialize(archive, t);
322  }
323 
324  template<typename T>
325  inline void preserialize(
326  Archive & archive,
327  T *& pt,
328  const unsigned int)
329  {
330  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
331  typedef typename RCF::RemoveCv<T>::type U;
332  serialize_vc6(archive, (U &) *pt, static_cast<const unsigned int>(0) );
333  }
334 
335  template<typename T>
336  Archive & operator&(
337  Archive & archive,
338  const T & t)
339  {
340  invokePtrSerializer(&t, archive);
341  return archive;
342  }
343 
344  template<typename T, typename U>
345  inline void serializeAs(Archive & ar, T &t)
346  {
347  if (ar.isWrite())
348  {
349  U u = static_cast<U>(t);
350  ar & u;
351  }
352  else
353  {
354  U u;
355  ar & u;
356  t = static_cast<T>(u);
357  }
358  }
359 
361 #define SF_SERIALIZE_ENUM_CLASS(EnumType, BaseType) \
362  void serialize(SF::Archive & ar, EnumType & e) \
363  { \
364  SF::serializeAs<EnumType, BaseType>(ar, e); \
365  }
366 
367 }
368 
369 #include <SF/Registry.hpp>
370 #include <SF/SerializePolymorphic.hpp>
371 #include <SF/Stream.hpp>
372 
373 namespace SF {
374 
375  template<typename T>
376  Serializer<T>::Serializer(T **ppt) :
377  ppt(ppt),
378  pf(),
379  id()
380  {}
381 
382  template<typename T>
383  std::string Serializer<T>::getTypeName()
384  {
385  return SF::Registry::getSingleton().getTypeName( (T *) 0);
386  }
387 
388 #ifdef _MSC_VER
389 #pragma warning( push )
390 #pragma warning( disable: 4702 )
391 #endif
392 
393  template<typename T>
394  void Serializer<T>::newObject(Archive &ar)
395  {
396  *ppt = sfNew((T *) NULL, (T **) NULL, ar);
397  }
398 
399 #ifdef _MSC_VER
400 #pragma warning( pop )
401 #endif
402 
403  template<typename T>
404  bool Serializer<T>::isDerived()
405  {
406  static const bool isFundamental = RCF::IsFundamental<T>::value;
407  if (!isFundamental && *ppt && typeid(T) != typeid(**ppt))
408  {
409  if (!SF::Registry::getSingleton().isTypeRegistered( typeid(**ppt)))
410  {
411  RCF::Exception e(RCF::RcfError_SfTypeRegistration, typeid(**ppt).name());
412  RCF_THROW(e);
413  }
414  return true;
415  }
416  return false;
417  }
418 
419  template<typename T>
420  std::string Serializer<T>::getDerivedTypeName()
421  {
422  return SF::Registry::getSingleton().getTypeName( typeid(**ppt) );
423  }
424 
425  template<typename T>
426  void Serializer<T>::getSerializerPolymorphic(
427  const std::string &derivedTypeName)
428  {
429  pf = & SF::Registry::getSingleton().getSerializerPolymorphic(
430  (T *) 0,
431  derivedTypeName);
432  }
433 
434  template<typename T>
435  void Serializer<T>::invokeSerializerPolymorphic(SF::Archive &ar)
436  {
437  RCF_ASSERT(pf);
438  void **ppvb = (void **) (ppt); // not even reinterpret_cast wants to touch this
439  pf->invoke(ppvb, ar);
440  }
441 
442  template<typename T>
443  void Serializer<T>::serializeContents(Archive &ar)
444  {
445  preserialize(ar, *ppt, 0);
446  }
447 
448  template<typename T>
449  void Serializer<T>::addToInputContext(SF::IStream *stream, const UInt32 &nid)
450  {
451  ContextRead &ctx = stream->getTrackingContext();
452  ctx.add(nid, IdT( (void *) (*ppt), &typeid(T)));
453  }
454 
455  template<typename T>
456  bool Serializer<T>::queryInputContext(SF::IStream *stream, const UInt32 &nid)
457  {
458  ContextRead &ctx = stream->getTrackingContext();
459  return ctx.query(nid, id);
460  }
461 
462  template<typename T>
463  void Serializer<T>::addToOutputContext(SF::OStream *stream, UInt32 &nid)
464  {
465  ContextWrite &ctx = stream->getTrackingContext();
466  ctx.add( IdT( (void *) *ppt, &typeid(T)), nid);
467  }
468 
469  template<typename T>
470  bool Serializer<T>::queryOutputContext(SF::OStream *stream, UInt32 &nid)
471  {
472  ContextWrite &ctx = stream->getTrackingContext();
473  return ctx.query( IdT( (void *) *ppt, &typeid(T)), nid);
474  }
475 
476  template<typename T>
477  void Serializer<T>::setFromId()
478  {
479  *ppt = reinterpret_cast<T *>(id.first);
480  }
481 
482  template<typename T>
483  void Serializer<T>::setToNull()
484  {
485  *ppt = NULL;
486  }
487 
488  template<typename T>
489  bool Serializer<T>::isNull()
490  {
491  return *ppt == NULL;
492  }
493 
494  template<typename T>
495  bool Serializer<T>::isNonAtomic()
496  {
497  bool isFundamental = RCF::IsFundamental<T>::value;
498  return !isFundamental;
499  }
500 
501 } // namespace SF
502 
503 #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:233
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