//****************************************************************************** // RCF - Remote Call Framework // // Copyright (c) 2005 - 2020, Delta V Software. All rights reserved. // http://www.deltavsoft.com // // RCF is distributed under dual licenses - closed source or GPL. // Consult your particular license for conditions of use. // // If you have not purchased a commercial license, you are using RCF // under GPL terms. // // Version: 3.2 // Contact: support deltavsoft.com // //****************************************************************************** /// @file #ifndef INCLUDE_SF_SERIALIZER_HPP #define INCLUDE_SF_SERIALIZER_HPP #include #include #include #include #include #include #include #include #include namespace SF { // Generic serializer, subclassed by all other serializers. class RCF_EXPORT SerializerBase : Noncopyable { private: void invokeRead(Archive &ar); void invokeWrite(Archive &ar); // Following are overridden to provide type-specific operations. virtual std::string getTypeName() = 0; virtual void newObject(Archive &ar) = 0; virtual bool isDerived() = 0; virtual std::string getDerivedTypeName() = 0; virtual void getSerializerPolymorphic(const std::string &derivedTypeName) = 0; virtual void invokeSerializerPolymorphic(SF::Archive &) = 0; virtual void serializeContents(Archive &ar) = 0; virtual void addToInputContext(IStream *, const UInt32 &) = 0; virtual bool queryInputContext(IStream *, const UInt32 &) = 0; virtual void addToOutputContext(OStream *, UInt32 &) = 0; virtual bool queryOutputContext(OStream *, UInt32 &) = 0; virtual void setFromId() = 0; virtual void setToNull() = 0; virtual bool isNull() = 0; virtual bool isNonAtomic() = 0; public: SerializerBase(); virtual ~SerializerBase(); void invoke(Archive &ar); }; //--------------------------------------------------------------------- // Type-specific serializers // These pragmas concern Serializer::newObject, but needs to be up here, probably because Serializer is a template #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4675 ) // warning C4675: resolved overload was found by argument-dependent lookup #pragma warning( disable : 4702 ) // warning C4702: unreachable code #endif class I_SerializerPolymorphic; template class Serializer : public SerializerBase { public: Serializer(T ** ppt); private: typedef ObjectId IdT; T ** ppt; I_SerializerPolymorphic * pf; IdT id; std::string getTypeName(); void newObject(Archive &ar); bool isDerived(); std::string getDerivedTypeName(); void getSerializerPolymorphic(const std::string &derivedTypeName); void invokeSerializerPolymorphic(SF::Archive &ar); void serializeContents(Archive &ar); void addToInputContext(SF::IStream *stream, const UInt32 &nid); bool queryInputContext(SF::IStream *stream, const UInt32 &nid); void addToOutputContext(SF::OStream *stream, UInt32 &nid); bool queryOutputContext(SF::OStream *stream, UInt32 &nid); void setFromId(); void setToNull(); bool isNull(); bool isNonAtomic(); }; #ifdef _MSC_VER #pragma warning( pop ) #endif template struct GetIndirection { typedef typename RCF::RemovePointer::type PT; typedef typename RCF::IsPointer::type is_single; typedef typename RCF::IsPointer::type is_double; typedef typename RCF::If< is_double, RCF::Int<2>, typename RCF::If< is_single, RCF::Int<1>, RCF::Int<0> >::type >::type Level; typedef typename RCF::RemoveCv< typename RCF::RemovePointer< typename RCF::RemoveCv< typename RCF::RemovePointer< typename RCF::RemoveCv::type >::type >::type >::type >::type Base; }; template inline void invokeCustomSerializer( T **ppt, Archive &ar, int) { static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); Serializer(ppt).invoke(ar); } template inline void invokeSerializer( U *, T *, RCF::Int<0> *, const U &u, Archive &ar) { static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); T *pt = const_cast(&u); invokeCustomSerializer( (T **) (&pt), ar, 0); } template inline void invokeSerializer( U *, T *, RCF::Int<1> *, const U &u, Archive &ar) { static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); invokeCustomSerializer( (T **) (&u), ar, 0); } template inline void invokeSerializer( U *, T *, RCF::Int<2> *, const U &u, Archive &ar) { static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); invokeCustomSerializer( (T**) (u), ar, 0); } template inline void invokeSerializer(U u, Archive &ar) { typedef typename GetIndirection::Level Level; typedef typename GetIndirection::Base T; static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); invokeSerializer( (U *) 0, (T *) 0, (Level *) 0, u, ar); } template inline void invokePtrSerializer(U u, Archive &ar) { typedef typename GetIndirection::Level Level; const int levelOfIndirection = Level::value; static_assert( levelOfIndirection == 1 || levelOfIndirection == 2, "Incorrect value from GetIndirection<>."); const bool isPointer = (levelOfIndirection == 2); //#ifdef _MSC_VER //#pragma warning(push) //#pragma warning(disable: 6326) // warning C6326: Potential comparison of a constant with another constant. //#endif ar.setFlag( SF::Archive::POINTER, isPointer ); //#ifdef _MSC_VER //#pragma warning(pop) //#endif invokeSerializer(u, ar); } // Forward declaration. template Archive & operator&( Archive & archive, const T & t); template inline void serializeEnum(SF::Archive &ar, T &t) { int runtimeVersion = ar.getRuntimeVersion(); if (runtimeVersion >= 2) { ar & SF::Archive::Flag(SF::Archive::NO_BEGIN_END); } if (ar.isRead()) { std::int32_t n = 0; ar & n; t = T(n); } else /* if (ar.isWrite())) */ { std::int32_t n = t; ar & n; } } template inline void serializeInternal(Archive &archive, T &t) { // A compiler error here indicates that the class T has not implemented // an internal SF serialization function. Here are a few situations in // which this can happen: // * No serialization function was provided at all, in which case one // needs to be written (either internal or external). // // * The intention was to provide an external SF serialization function, // but the external serialization function definition is incorrect and // hence not visible to the framework. // * The class is a Protocol Buffers generated class, and the intention // was to serialize it as such, in which case RCF_FEATURE_PROTOBUF=1 // needs to be defined. t.serialize(archive); } template inline void serializeFundamentalOrNot( Archive & archive, T & t, RCF::TrueType *) { serializeFundamental(archive, t); } template inline void serializeFundamentalOrNot( Archive & archive, T & t, RCF::FalseType *) { serializeInternal(archive, t); } template inline void serializeEnumOrNot( Archive & archive, T & t, RCF::TrueType *) { serializeEnum(archive, t); } template inline void serializeEnumOrNot( Archive & archive, T & t, RCF::FalseType *) { typedef typename RCF::IsFundamental::type type; serializeFundamentalOrNot(archive, t, (type *) NULL); } template inline void serialize( Archive & archive, T & t) { typedef typename std::is_enum::type type; serializeEnumOrNot(archive, t, (type *) NULL); } template inline void serialize_vc6( Archive & archive, T & t, const unsigned int) { serialize(archive, t); } template inline void preserialize( Archive & archive, T *& pt, const unsigned int) { static_assert(!RCF::IsPointer::value, "Incorrect serialization code."); typedef typename RCF::RemoveCv::type U; serialize_vc6(archive, (U &) *pt, static_cast(0) ); } template Archive & operator&( Archive & archive, const T & t) { invokePtrSerializer(&t, archive); return archive; } template inline void serializeAs(Archive & ar, T &t) { if (ar.isWrite()) { U u = static_cast(t); ar & u; } else { U u; ar & u; t = static_cast(u); } } /// Instructs RCF to serialize enum class EnumType, as a BaseType object. #define SF_SERIALIZE_ENUM_CLASS(EnumType, BaseType) \ void serialize(SF::Archive & ar, EnumType & e) \ { \ SF::serializeAs(ar, e); \ } } #include #include #include namespace SF { template Serializer::Serializer(T **ppt) : ppt(ppt), pf(), id() {} template std::string Serializer::getTypeName() { return SF::Registry::getSingleton().getTypeName( (T *) 0); } #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable: 4702 ) #endif template void Serializer::newObject(Archive &ar) { *ppt = sfNew((T *) NULL, (T **) NULL, ar); } #ifdef _MSC_VER #pragma warning( pop ) #endif template bool Serializer::isDerived() { static const bool isFundamental = RCF::IsFundamental::value; if RCF_CONSTEXPR(!isFundamental) { if ( *ppt && typeid(T) != typeid(**ppt) ) { if ( !SF::Registry::getSingleton().isTypeRegistered(typeid(**ppt)) ) { RCF::Exception e(RCF::RcfError_SfTypeRegistration, typeid(**ppt).name()); RCF_THROW(e); } return true; } } return false; } template std::string Serializer::getDerivedTypeName() { return SF::Registry::getSingleton().getTypeName( typeid(**ppt) ); } template void Serializer::getSerializerPolymorphic( const std::string &derivedTypeName) { pf = & SF::Registry::getSingleton().getSerializerPolymorphic( (T *) 0, derivedTypeName); } template void Serializer::invokeSerializerPolymorphic(SF::Archive &ar) { RCF_ASSERT(pf); void **ppvb = (void **) (ppt); // not even reinterpret_cast wants to touch this pf->invoke(ppvb, ar); } template void Serializer::serializeContents(Archive &ar) { preserialize(ar, *ppt, 0); } template void Serializer::addToInputContext(SF::IStream *stream, const UInt32 &nid) { ContextRead &ctx = stream->getTrackingContext(); ctx.add(nid, IdT( (void *) (*ppt), &typeid(T))); } template bool Serializer::queryInputContext(SF::IStream *stream, const UInt32 &nid) { ContextRead &ctx = stream->getTrackingContext(); return ctx.query(nid, id); } template void Serializer::addToOutputContext(SF::OStream *stream, UInt32 &nid) { ContextWrite &ctx = stream->getTrackingContext(); ctx.add( IdT( (void *) *ppt, &typeid(T)), nid); } template bool Serializer::queryOutputContext(SF::OStream *stream, UInt32 &nid) { ContextWrite &ctx = stream->getTrackingContext(); return ctx.query( IdT( (void *) *ppt, &typeid(T)), nid); } template void Serializer::setFromId() { *ppt = reinterpret_cast(id.first); } template void Serializer::setToNull() { *ppt = NULL; } template bool Serializer::isNull() { return *ppt == NULL; } template bool Serializer::isNonAtomic() { bool isFundamental = RCF::IsFundamental::value; return !isFundamental; } } // namespace SF #endif // ! INCLUDE_SF_SERIALIZER_HPP