|
@@ -81,10 +81,14 @@ enum SerializationLvl
|
|
|
|
|
|
struct TypeComparer
|
|
|
{
|
|
|
- bool operator()(const std::type_info *a, const std::type_info *b) const
|
|
|
- {
|
|
|
- return a->before(*b);
|
|
|
- }
|
|
|
+ bool operator()(const std::type_info *a, const std::type_info *b) const
|
|
|
+ {
|
|
|
+ #ifndef __APPLE__
|
|
|
+ return a->before(*b);
|
|
|
+ #else
|
|
|
+ return strcmp(a->name(), b->name()) < 0;
|
|
|
+ #endif
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
struct IPointerCaster
|
|
@@ -102,6 +106,11 @@ struct PointerCaster : IPointerCaster
|
|
|
{
|
|
|
From * from = (From*)boost::any_cast<void*>(ptr);
|
|
|
To * ret = dynamic_cast<To*>(from);
|
|
|
+ if (ret == nullptr)
|
|
|
+ {
|
|
|
+ // Last resort when RTTI goes mad
|
|
|
+ ret = static_cast<To*>(from);
|
|
|
+ }
|
|
|
return (void*)ret;
|
|
|
}
|
|
|
|
|
@@ -113,6 +122,11 @@ struct PointerCaster : IPointerCaster
|
|
|
{
|
|
|
auto from = boost::any_cast<SmartPt>(ptr);
|
|
|
auto ret = std::dynamic_pointer_cast<To>(from);
|
|
|
+ if (!ret)
|
|
|
+ {
|
|
|
+ // Last resort when RTTI goes mad
|
|
|
+ ret = std::static_pointer_cast<To>(from);
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
catch(std::exception &e)
|
|
@@ -136,7 +150,7 @@ struct PointerCaster : IPointerCaster
|
|
|
// }
|
|
|
};
|
|
|
|
|
|
-class DLL_LINKAGE CTypeList
|
|
|
+class DLL_LINKAGE CTypeList: public boost::noncopyable
|
|
|
{
|
|
|
public:
|
|
|
struct TypeDescriptor;
|
|
@@ -147,33 +161,53 @@ public:
|
|
|
const char *name;
|
|
|
std::vector<TypeInfoPtr> children, parents;
|
|
|
};
|
|
|
+ typedef boost::shared_mutex TMutex;
|
|
|
+ typedef boost::unique_lock<TMutex> TUniqueLock;
|
|
|
+ typedef boost::shared_lock<TMutex> TSharedLock;
|
|
|
private:
|
|
|
+ mutable TMutex mx;
|
|
|
|
|
|
std::map<const std::type_info *, TypeInfoPtr, TypeComparer> typeInfos;
|
|
|
std::map<std::pair<TypeInfoPtr, TypeInfoPtr>, std::unique_ptr<const IPointerCaster>> casters; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
|
|
|
|
|
|
- CTypeList(CTypeList &)
|
|
|
- {
|
|
|
- // This type is non-copyable.
|
|
|
- // Unfortunately on Windows it is required for DLL_EXPORT-ed type to provide copy c-tor, so we can't =delete it.
|
|
|
- assert(0);
|
|
|
- }
|
|
|
- CTypeList &operator=(CTypeList &)
|
|
|
+ /// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
|
|
|
+ /// Throws if there is no link registered.
|
|
|
+ std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to) const;
|
|
|
+ std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to) const;
|
|
|
+
|
|
|
+
|
|
|
+ template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
|
|
|
+ boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) const
|
|
|
{
|
|
|
- // As above.
|
|
|
- assert(0);
|
|
|
- return *this;
|
|
|
+ TSharedLock lock(mx);
|
|
|
+ auto typesSequence = castSequence(fromArg, toArg);
|
|
|
+
|
|
|
+ boost::any ptr = inputPtr;
|
|
|
+ for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
|
|
|
+ {
|
|
|
+ auto &from = typesSequence[i];
|
|
|
+ auto &to = typesSequence[i + 1];
|
|
|
+ auto castingPair = std::make_pair(from, to);
|
|
|
+ if(!casters.count(castingPair))
|
|
|
+ THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
|
|
|
+
|
|
|
+ auto &caster = casters.at(castingPair);
|
|
|
+ ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr not have operator->* ..?
|
|
|
+ }
|
|
|
+
|
|
|
+ return ptr;
|
|
|
}
|
|
|
-public:
|
|
|
|
|
|
- CTypeList();
|
|
|
+ TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true) const; //if not throws, failure returns nullptr
|
|
|
|
|
|
TypeInfoPtr registerType(const std::type_info *type);
|
|
|
-
|
|
|
+public:
|
|
|
+ CTypeList();
|
|
|
|
|
|
template <typename Base, typename Derived>
|
|
|
void registerType(const Base * b = nullptr, const Derived * d = nullptr)
|
|
|
{
|
|
|
+ TUniqueLock lock(mx);
|
|
|
static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
|
|
|
static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
|
|
|
static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two diffrenet types.");
|
|
@@ -187,77 +221,52 @@ public:
|
|
|
casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
|
|
|
}
|
|
|
|
|
|
- ui16 getTypeID(const std::type_info *type);
|
|
|
- TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true); //if not throws, failure returns nullptr
|
|
|
+ ui16 getTypeID(const std::type_info *type, bool throws = false) const;
|
|
|
|
|
|
template <typename T>
|
|
|
- ui16 getTypeID(const T * t = nullptr)
|
|
|
- {
|
|
|
- return getTypeID(getTypeInfo(t));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
|
|
|
- // Throws if there is no link registered.
|
|
|
- std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to);
|
|
|
- std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to);
|
|
|
-
|
|
|
- template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
|
|
|
- boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg)
|
|
|
+ ui16 getTypeID(const T * t = nullptr, bool throws = false) const
|
|
|
{
|
|
|
- auto typesSequence = castSequence(fromArg, toArg);
|
|
|
-
|
|
|
- boost::any ptr = inputPtr;
|
|
|
- for(int i = 0; i < (int)typesSequence.size() - 1; i++)
|
|
|
- {
|
|
|
- auto &from = typesSequence[i];
|
|
|
- auto &to = typesSequence[i + 1];
|
|
|
- auto castingPair = std::make_pair(from, to);
|
|
|
- if(!casters.count(castingPair))
|
|
|
- THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
|
|
|
-
|
|
|
- auto &caster = casters.at(castingPair);
|
|
|
- ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr does not have operator->* ..?
|
|
|
- }
|
|
|
-
|
|
|
- return ptr;
|
|
|
+ return getTypeID(getTypeInfo(t), throws);
|
|
|
}
|
|
|
|
|
|
template<typename TInput>
|
|
|
- void *castToMostDerived(const TInput *inputPtr)
|
|
|
+ void * castToMostDerived(const TInput * inputPtr) const
|
|
|
{
|
|
|
auto &baseType = typeid(typename std::remove_cv<TInput>::type);
|
|
|
auto derivedType = getTypeInfo(inputPtr);
|
|
|
|
|
|
- if(baseType == *derivedType)
|
|
|
- return (void*)inputPtr;
|
|
|
+ if (!strcmp(baseType.name(), derivedType->name()))
|
|
|
+ {
|
|
|
+ return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
|
|
|
+ }
|
|
|
|
|
|
- return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType));
|
|
|
+ return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
|
|
|
+ const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
|
|
|
+ derivedType));
|
|
|
}
|
|
|
|
|
|
template<typename TInput>
|
|
|
- boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr)
|
|
|
+ boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr) const
|
|
|
{
|
|
|
auto &baseType = typeid(typename std::remove_cv<TInput>::type);
|
|
|
auto derivedType = getTypeInfo(inputPtr.get());
|
|
|
|
|
|
- if(baseType == *derivedType)
|
|
|
+ if (!strcmp(baseType.name(), derivedType->name()))
|
|
|
return inputPtr;
|
|
|
|
|
|
return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
|
|
|
}
|
|
|
|
|
|
- void* castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to)
|
|
|
+ void * castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) const
|
|
|
{
|
|
|
return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to));
|
|
|
}
|
|
|
- boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to)
|
|
|
+ boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) const
|
|
|
{
|
|
|
return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr)
|
|
|
+ template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr) const
|
|
|
{
|
|
|
if(t)
|
|
|
return &typeid(*t);
|
|
@@ -444,13 +453,13 @@ public:
|
|
|
virtual int write(const void * data, unsigned size) = 0;
|
|
|
};
|
|
|
|
|
|
-class DLL_LINKAGE CSaverBase
|
|
|
+class DLL_LINKAGE CSaverBase
|
|
|
{
|
|
|
protected:
|
|
|
IBinaryWriter * writer;
|
|
|
public:
|
|
|
CSaverBase(IBinaryWriter * w): writer(w){};
|
|
|
-
|
|
|
+
|
|
|
inline int write(const void * data, unsigned size)
|
|
|
{
|
|
|
return writer->write(data, size);
|
|
@@ -586,15 +595,15 @@ struct LoadIfStackInstance<Ser, CStackInstance *>
|
|
|
class DLL_LINKAGE COSer : public CSaverBase
|
|
|
{
|
|
|
public:
|
|
|
-
|
|
|
+
|
|
|
struct SaveBoolean
|
|
|
{
|
|
|
static void invoke(COSer &s, const bool &data)
|
|
|
{
|
|
|
s.saveBoolean(data);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
struct SaveBooleanVector
|
|
|
{
|
|
|
static void invoke(COSer &s, const std::vector<bool> &data)
|
|
@@ -629,7 +638,7 @@ public:
|
|
|
s.saveEnum(data);
|
|
|
}
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
template<typename T>
|
|
|
struct SavePointer
|
|
|
{
|
|
@@ -638,7 +647,7 @@ public:
|
|
|
s.savePointer(data);
|
|
|
}
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
template<typename T>
|
|
|
struct SaveArray
|
|
|
{
|
|
@@ -655,22 +664,21 @@ public:
|
|
|
{
|
|
|
throw std::runtime_error("Wrong save serialization call!");
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class CPointerSaver : public CBasicPointerSaver
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ class CPointerSaver : public CBasicPointerSaver
|
|
|
{
|
|
|
public:
|
|
|
void savePtr(CSaverBase &ar, const void *data) const override
|
|
|
- {
|
|
|
+ {
|
|
|
COSer &s = static_cast<COSer&>(ar);
|
|
|
- const T *ptr = static_cast<const T*>(data);
|
|
|
-
|
|
|
+ const T *ptr = static_cast<const T*>(data);
|
|
|
//T is most derived known type, it's time to call actual serialize
|
|
|
- const_cast<T&>(*ptr).serialize(s,version);
|
|
|
+ const_cast<T*>(ptr)->serialize(s,version);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
bool saving;
|
|
|
std::map<ui16,CBasicPointerSaver*> savers; // typeID => CPointerSaver<serializer,type>
|
|
|
|
|
@@ -777,7 +785,7 @@ public:
|
|
|
|
|
|
//write type identifier
|
|
|
ui16 tid = typeList.getTypeID(data);
|
|
|
- *this << tid;
|
|
|
+ *this << tid;
|
|
|
|
|
|
this->savePointerHlp(tid, data);
|
|
|
}
|
|
@@ -964,13 +972,13 @@ public:
|
|
|
virtual int read(void * data, unsigned size) = 0;
|
|
|
};
|
|
|
|
|
|
-class DLL_LINKAGE CLoaderBase
|
|
|
+class DLL_LINKAGE CLoaderBase
|
|
|
{
|
|
|
protected:
|
|
|
IBinaryReader * reader;
|
|
|
public:
|
|
|
CLoaderBase(IBinaryReader * r): reader(r){};
|
|
|
-
|
|
|
+
|
|
|
inline int read(void * data, unsigned size)
|
|
|
{
|
|
|
return reader->read(data, size);
|
|
@@ -1015,15 +1023,15 @@ public:
|
|
|
s.loadBoolean(data);
|
|
|
}
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
struct LoadBooleanVector
|
|
|
{
|
|
|
static void invoke(CISer &s, std::vector<bool> &data)
|
|
|
{
|
|
|
s.loadBooleanVector(data);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
template<typename T>
|
|
|
struct LoadEnum
|
|
|
{
|
|
@@ -1040,7 +1048,7 @@ public:
|
|
|
{
|
|
|
s.loadPrimitive(data);
|
|
|
}
|
|
|
- };
|
|
|
+ };
|
|
|
|
|
|
template<typename T>
|
|
|
struct LoadPointer
|
|
@@ -1049,8 +1057,8 @@ public:
|
|
|
{
|
|
|
s.loadPointer(data);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
template<typename T>
|
|
|
struct LoadArray
|
|
|
{
|
|
@@ -1076,8 +1084,8 @@ public:
|
|
|
{
|
|
|
throw std::runtime_error("Wrong load serialization call!");
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
template <typename T> class CPointerLoader : public CBasicPointerLoader
|
|
|
{
|
|
|
public:
|
|
@@ -1094,8 +1102,8 @@ public:
|
|
|
ptr->serialize(s,version);
|
|
|
return &typeid(T);
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
+ };
|
|
|
+
|
|
|
bool saving;
|
|
|
std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
|
|
|
si32 fileVersion;
|
|
@@ -1539,9 +1547,9 @@ class DLL_LINKAGE CSaveFile
|
|
|
:public IBinaryWriter
|
|
|
{
|
|
|
public:
|
|
|
-
|
|
|
+
|
|
|
COSer serializer;
|
|
|
-
|
|
|
+
|
|
|
std::string fName;
|
|
|
unique_ptr<std::ofstream> sfile;
|
|
|
|
|
@@ -1554,13 +1562,13 @@ public:
|
|
|
void reportState(CLogger * out) override;
|
|
|
|
|
|
void putMagicBytes(const std::string &text);
|
|
|
-
|
|
|
+
|
|
|
template<class T>
|
|
|
CSaveFile & operator<<(const T &t)
|
|
|
{
|
|
|
serializer << t;
|
|
|
return * this;
|
|
|
- }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
class DLL_LINKAGE CLoadFile
|
|
@@ -1568,7 +1576,7 @@ class DLL_LINKAGE CLoadFile
|
|
|
{
|
|
|
public:
|
|
|
CISer serializer;
|
|
|
-
|
|
|
+
|
|
|
std::string fName;
|
|
|
unique_ptr<boost::filesystem::ifstream> sfile;
|
|
|
|
|
@@ -1581,20 +1589,20 @@ public:
|
|
|
void reportState(CLogger * out) override;
|
|
|
|
|
|
void checkMagicBytes(const std::string & text);
|
|
|
-
|
|
|
+
|
|
|
template<class T>
|
|
|
CLoadFile & operator>>(T &t)
|
|
|
{
|
|
|
serializer >> t;
|
|
|
return * this;
|
|
|
- }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-class DLL_LINKAGE CLoadIntegrityValidator
|
|
|
+class DLL_LINKAGE CLoadIntegrityValidator
|
|
|
: public IBinaryReader
|
|
|
{
|
|
|
public:
|
|
|
- CISer serializer;
|
|
|
+ CISer serializer;
|
|
|
unique_ptr<CLoadFile> primaryFile, controlFile;
|
|
|
bool foundDesync;
|
|
|
|
|
@@ -1620,7 +1628,7 @@ class DLL_LINKAGE CConnection
|
|
|
public:
|
|
|
CISer iser;
|
|
|
COSer oser;
|
|
|
-
|
|
|
+
|
|
|
boost::mutex *rmx, *wmx; // read/write mutexes
|
|
|
TSocket * socket;
|
|
|
bool logging;
|
|
@@ -1658,14 +1666,14 @@ public:
|
|
|
|
|
|
void prepareForSendingHeroes(); //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
|
|
|
void enterPregameConnectionMode();
|
|
|
-
|
|
|
+
|
|
|
template<class T>
|
|
|
CConnection & operator>>(T &t)
|
|
|
{
|
|
|
iser >> t;
|
|
|
return * this;
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
+
|
|
|
template<class T>
|
|
|
CConnection & operator<<(const T &t)
|
|
|
{
|
|
@@ -1687,7 +1695,7 @@ class DLL_LINKAGE CMemorySerializer
|
|
|
public:
|
|
|
CISer iser;
|
|
|
COSer oser;
|
|
|
-
|
|
|
+
|
|
|
int read(void * data, unsigned size) override; //throws!
|
|
|
int write(const void * data, unsigned size) override;
|
|
|
|