Remote Call Framework 3.4
Serializer.hpp
Go to the documentation of this file.
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2023, Delta V Software. All rights reserved.
6 // https://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 under GPL terms.
12 //
13 // Version: 3.4
14 // Contact: support <at> deltavsoft.com
15 //
16 //******************************************************************************
17 
19 
20 #ifndef INCLUDE_SF_SERIALIZER_HPP
21 #define INCLUDE_SF_SERIALIZER_HPP
22 
23 #include <RCF/Exception.hpp>
24 #include <RCF/Export.hpp>
25 #include <RCF/MemStream.hpp>
26 #include <RCF/TypeTraits.hpp>
27 
28 #include <SF/Archive.hpp>
29 #include <SF/I_Stream.hpp>
30 #include <SF/SerializeFundamental.hpp>
31 #include <SF/SfNew.hpp>
32 #include <RCF/Tools.hpp>
33 
34 namespace SF {
35 
36  // Generic serializer, subclassed by all other serializers.
37 
38  class RCF_EXPORT SerializerBase : Noncopyable
39  {
40  private:
41  void invokeRead(Archive &ar);
42  void invokeWrite(Archive &ar);
43 
44  // Following are overridden to provide type-specific operations.
45  virtual std::string getTypeName() = 0;
46  virtual void newObject(Archive &ar) = 0;
47  virtual bool isDerived() = 0;
48  virtual std::string getDerivedTypeName() = 0;
49  virtual void getSerializerPolymorphic(const std::string &derivedTypeName) = 0;
50  virtual void invokeSerializerPolymorphic(SF::Archive &) = 0;
51  virtual void serializeContents(Archive &ar) = 0;
52  virtual void addToInputContext(IStream *, const UInt32 &) = 0;
53  virtual bool queryInputContext(IStream *, const UInt32 &) = 0;
54  virtual void addToOutputContext(OStream *, UInt32 &) = 0;
55  virtual bool queryOutputContext(OStream *, UInt32 &) = 0;
56  virtual void setFromId() = 0;
57  virtual void setToNull() = 0;
58  virtual bool isNull() = 0;
59  virtual bool isNonAtomic() = 0;
60 
61  public:
62  SerializerBase();
63  virtual ~SerializerBase();
64  void invoke(Archive &ar);
65  };
66 
67  //---------------------------------------------------------------------
68  // Type-specific serializers
69 
70  // These pragmas concern Serializer<T>::newObject, but needs to be up here, probably because Serializer<T> is a template
71 #ifdef _MSC_VER
72 #pragma warning( push )
73 #pragma warning( disable : 4675 ) // warning C4675: resolved overload was found by argument-dependent lookup
74 #pragma warning( disable : 4702 ) // warning C4702: unreachable code
75 #endif
76 
77  class I_SerializerPolymorphic;
78 
79  template<typename T>
80  class Serializer : public SerializerBase
81  {
82  public:
83  Serializer(T ** ppt);
84 
85  private:
86  typedef ObjectId IdT;
87  T ** ppt;
88  I_SerializerPolymorphic * pf;
89  IdT id;
90 
91  std::string getTypeName();
92  void newObject(Archive &ar);
93  bool isDerived();
94  std::string getDerivedTypeName();
95  void getSerializerPolymorphic(const std::string &derivedTypeName);
96  void invokeSerializerPolymorphic(SF::Archive &ar);
97  void serializeContents(Archive &ar);
98  void addToInputContext(SF::IStream *stream, const UInt32 &nid);
99  bool queryInputContext(SF::IStream *stream, const UInt32 &nid);
100  void addToOutputContext(SF::OStream *stream, UInt32 &nid);
101  bool queryOutputContext(SF::OStream *stream, UInt32 &nid);
102  void setFromId();
103  void setToNull();
104  bool isNull();
105  bool isNonAtomic();
106  };
107 
108 #ifdef _MSC_VER
109 #pragma warning( pop )
110 #endif
111 
112  template<typename PPT>
113  struct GetIndirection
114  {
115  typedef typename RCF::RemovePointer<PPT>::type PT;
116  typedef typename RCF::IsPointer<PPT>::type is_single;
117  typedef typename RCF::IsPointer<PT>::type is_double;
118 
119  typedef
120  typename RCF::If<
121  is_double,
122  RCF::Int<2>,
123  typename RCF::If<
124  is_single,
125  RCF::Int<1>,
126  RCF::Int<0>
127  >::type
128  >::type Level;
129 
130  typedef
131  typename RCF::RemoveCv<
132  typename RCF::RemovePointer<
133  typename RCF::RemoveCv<
134  typename RCF::RemovePointer<
135  typename RCF::RemoveCv<PPT>::type
136  >::type
137  >::type
138  >::type
139  >::type Base;
140  };
141 
142  template<typename T>
143  inline void invokeCustomSerializer(
144  T **ppt,
145  Archive &ar,
146  int)
147  {
148  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
149  Serializer<T>(ppt).invoke(ar);
150  }
151 
152  template<typename U, typename T>
153  inline void invokeSerializer(
154  U *,
155  T *,
156  RCF::Int<0> *,
157  const U &u,
158  Archive &ar)
159  {
160  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
161  T *pt = const_cast<T *>(&u);
162  invokeCustomSerializer( (T **) (&pt), ar, 0);
163  }
164 
165  template<typename U, typename T>
166  inline void invokeSerializer(
167  U *,
168  T *,
169  RCF::Int<1> *,
170  const U &u,
171  Archive &ar)
172  {
173  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
174  invokeCustomSerializer( (T **) (&u), ar, 0);
175  }
176 
177  template<typename U, typename T>
178  inline void invokeSerializer(
179  U *,
180  T *,
181  RCF::Int<2> *,
182  const U &u,
183  Archive &ar)
184  {
185  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
186  invokeCustomSerializer( (T**) (u), ar, 0);
187  }
188 
189  template<typename U>
190  inline void invokeSerializer(U u, Archive &ar)
191  {
192  typedef typename GetIndirection<U>::Level Level;
193  typedef typename GetIndirection<U>::Base T;
194  static_assert(!RCF::IsPointer<T>::value, "Incorrect serialization code.");
195  invokeSerializer( (U *) 0, (T *) 0, (Level *) 0, u, ar);
196  }
197 
198  template<typename U>
199  inline void invokePtrSerializer(U u, Archive &ar)
200  {
201  typedef typename GetIndirection<U>::Level Level;
202  const int levelOfIndirection = Level::value;
203  static_assert( levelOfIndirection == 1 || levelOfIndirection == 2, "Incorrect value from GetIndirection<>.");
204  const bool isPointer = (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, isPointer );
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 RCF_CONSTEXPR(!isFundamental)
408  {
409  if ( *ppt && typeid(T) != typeid(**ppt) )
410  {
411  if ( !SF::Registry::getSingleton().isTypeRegistered(typeid(**ppt)) )
412  {
413  RCF::Exception e(RCF::RcfError_SfTypeRegistration, typeid(**ppt).name());
414  RCF_THROW(e);
415  }
416  return true;
417  }
418  }
419  return false;
420  }
421 
422  template<typename T>
423  std::string Serializer<T>::getDerivedTypeName()
424  {
425  return SF::Registry::getSingleton().getTypeName( typeid(**ppt) );
426  }
427 
428  template<typename T>
429  void Serializer<T>::getSerializerPolymorphic(
430  const std::string &derivedTypeName)
431  {
432  pf = & SF::Registry::getSingleton().getSerializerPolymorphic(
433  (T *) 0,
434  derivedTypeName);
435  }
436 
437  template<typename T>
438  void Serializer<T>::invokeSerializerPolymorphic(SF::Archive &ar)
439  {
440  RCF_ASSERT(pf);
441  void **ppvb = (void **) (ppt); // not even reinterpret_cast wants to touch this
442  pf->invoke(ppvb, ar);
443  }
444 
445  template<typename T>
446  void Serializer<T>::serializeContents(Archive &ar)
447  {
448  preserialize(ar, *ppt, 0);
449  }
450 
451  template<typename T>
452  void Serializer<T>::addToInputContext(SF::IStream *stream, const UInt32 &nid)
453  {
454  ContextRead &ctx = stream->getTrackingContext();
455  ctx.add(nid, IdT( (void *) (*ppt), &typeid(T)));
456  }
457 
458  template<typename T>
459  bool Serializer<T>::queryInputContext(SF::IStream *stream, const UInt32 &nid)
460  {
461  ContextRead &ctx = stream->getTrackingContext();
462  return ctx.query(nid, id);
463  }
464 
465  template<typename T>
466  void Serializer<T>::addToOutputContext(SF::OStream *stream, UInt32 &nid)
467  {
468  ContextWrite &ctx = stream->getTrackingContext();
469  ctx.add( IdT( (void *) *ppt, &typeid(T)), nid);
470  }
471 
472  template<typename T>
473  bool Serializer<T>::queryOutputContext(SF::OStream *stream, UInt32 &nid)
474  {
475  ContextWrite &ctx = stream->getTrackingContext();
476  return ctx.query( IdT( (void *) *ppt, &typeid(T)), nid);
477  }
478 
479  template<typename T>
480  void Serializer<T>::setFromId()
481  {
482  *ppt = reinterpret_cast<T *>(id.first);
483  }
484 
485  template<typename T>
486  void Serializer<T>::setToNull()
487  {
488  *ppt = NULL;
489  }
490 
491  template<typename T>
492  bool Serializer<T>::isNull()
493  {
494  return *ppt == NULL;
495  }
496 
497  template<typename T>
498  bool Serializer<T>::isNonAtomic()
499  {
500  bool isFundamental = RCF::IsFundamental<T>::value;
501  return !isFundamental;
502  }
503 
504 } // namespace SF
505 
506 #endif // ! INCLUDE_SF_SERIALIZER_HPP
Represents an archive, in which serialized objects are stored.
Definition: Archive.hpp:31
int getRuntimeVersion()
Gets the RCF runtime version associated with this archive.
Base class for all RCF exceptions.
Definition: Exception.hpp:67
Definition: ByteBuffer.hpp:188
Base class for output streams using SF serialization. Use operator <<() to serialize objects into the...
Definition: Stream.hpp:235
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:137