00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbistd.hpp>
00034 #include <corelib/ncbithr.hpp>
00035 #include <serial/impl/classinfob.hpp>
00036 #include <serial/objectinfo.hpp>
00037 #include <serial/objhook.hpp>
00038 #include <serial/serialimpl.hpp>
00039
00040 BEGIN_NCBI_SCOPE
00041
00042 DEFINE_STATIC_MUTEX(s_ClassInfoMutex);
00043
00044 CClassTypeInfoBase::CClassTypeInfoBase(ETypeFamily typeFamily,
00045 size_t size, const char* name,
00046 const void* ,
00047 TTypeCreate createFunc,
00048 const type_info& ti)
00049 : CParent(typeFamily, size, name)
00050 {
00051 InitClassTypeInfoBase(ti);
00052 SetCreateFunction(createFunc);
00053 }
00054
00055 CClassTypeInfoBase::CClassTypeInfoBase(ETypeFamily typeFamily,
00056 size_t size, const char* name,
00057 const CObject* ,
00058 TTypeCreate createFunc,
00059 const type_info& ti)
00060 : CParent(typeFamily, size, name)
00061 {
00062 m_IsCObject = true;
00063 InitClassTypeInfoBase(ti);
00064 SetCreateFunction(createFunc);
00065 }
00066
00067 CClassTypeInfoBase::CClassTypeInfoBase(ETypeFamily typeFamily,
00068 size_t size, const string& name,
00069 const void* ,
00070 TTypeCreate createFunc,
00071 const type_info& ti)
00072 : CParent(typeFamily, size, name)
00073 {
00074 InitClassTypeInfoBase(ti);
00075 SetCreateFunction(createFunc);
00076 }
00077
00078 CClassTypeInfoBase::CClassTypeInfoBase(ETypeFamily typeFamily,
00079 size_t size, const string& name,
00080 const CObject* ,
00081 TTypeCreate createFunc,
00082 const type_info& ti)
00083 : CParent(typeFamily, size, name)
00084 {
00085 m_IsCObject = true;
00086 InitClassTypeInfoBase(ti);
00087 SetCreateFunction(createFunc);
00088 }
00089
00090 CClassTypeInfoBase::~CClassTypeInfoBase(void)
00091 {
00092 Deregister();
00093 }
00094
00095 CMemberInfo* CClassTypeInfoBase::AddMember(const char* memberId,
00096 const void* memberPtr,
00097 const CTypeRef& memberType)
00098 {
00099 CMemberInfo* memberInfo = new CMemberInfo(this, memberId,
00100 TPointerOffsetType(memberPtr),
00101 memberType);
00102 GetItems().AddItem(memberInfo);
00103 return memberInfo;
00104 }
00105
00106 CMemberInfo* CClassTypeInfoBase::AddMember(const CMemberId& memberId,
00107 const void* memberPtr,
00108 const CTypeRef& memberType)
00109 {
00110 CMemberInfo* memberInfo = new CMemberInfo(this, memberId,
00111 TPointerOffsetType(memberPtr),
00112 memberType);
00113 GetItems().AddItem(memberInfo);
00114 return memberInfo;
00115 }
00116
00117 void CClassTypeInfoBase::InitClassTypeInfoBase(const type_info& id)
00118 {
00119 m_Id = &id;
00120 Register();
00121 }
00122
00123 CClassTypeInfoBase::TClasses* CClassTypeInfoBase::sm_Classes = 0;
00124 CClassTypeInfoBase::TClassesById* CClassTypeInfoBase::sm_ClassesById = 0;
00125 CClassTypeInfoBase::TClassesByName* CClassTypeInfoBase::sm_ClassesByName = 0;
00126 set<string>* CClassTypeInfoBase::sm_Modules = 0;
00127
00128 inline
00129 CClassTypeInfoBase::TClasses& CClassTypeInfoBase::Classes(void)
00130 {
00131 TClasses* classes = sm_Classes;
00132 if ( !classes ) {
00133 CMutexGuard GUARD(s_ClassInfoMutex);
00134 classes = sm_Classes;
00135 if ( !classes ) {
00136 classes = sm_Classes = new TClasses;
00137 }
00138 }
00139 return *classes;
00140 }
00141
00142 inline
00143 CClassTypeInfoBase::TClassesById& CClassTypeInfoBase::ClassesById(void)
00144 {
00145 TClassesById* classes = sm_ClassesById;
00146 if ( !classes ) {
00147 CMutexGuard GUARD(s_ClassInfoMutex);
00148 classes = sm_ClassesById;
00149 if ( !classes ) {
00150 const TClasses& cc = Classes();
00151 auto_ptr<TClassesById> keep(classes = new TClassesById);
00152 ITERATE ( TClasses, i , cc ) {
00153 const CClassTypeInfoBase* info = *i;
00154 if ( info->GetId() != typeid(bool) ) {
00155 if ( !classes->insert(
00156 TClassesById::value_type(&info->GetId(),
00157 info)).second ) {
00158 NCBI_THROW(CSerialException,eInvalidData,
00159 string("duplicate class id: ")+
00160 info->GetId().name());
00161 }
00162 }
00163 }
00164 sm_ClassesById = keep.release();
00165 }
00166 }
00167 return *classes;
00168 }
00169
00170 inline
00171 CClassTypeInfoBase::TClassesByName& CClassTypeInfoBase::ClassesByName(void)
00172 {
00173 TClassesByName* classes = sm_ClassesByName;
00174 if ( !classes ) {
00175 CMutexGuard GUARD(s_ClassInfoMutex);
00176 classes = sm_ClassesByName;
00177 if ( !classes ) {
00178 auto_ptr<TClassesByName> keep(classes = new TClassesByName);
00179 const TClasses& cc = Classes();
00180 ITERATE ( TClasses, i, cc ) {
00181 const CClassTypeInfoBase* info = *i;
00182 if ( !info->GetName().empty() ) {
00183 if ( !classes->insert(
00184 TClassesByName::value_type(info->GetName(),
00185 info)).second ) {
00186 NCBI_THROW(CSerialException,eInvalidData,
00187 string("duplicate class name: ")+info->GetName());
00188 }
00189 }
00190 }
00191 sm_ClassesByName = keep.release();
00192 }
00193 }
00194 return *classes;
00195 }
00196
00197 void CClassTypeInfoBase::Register(void)
00198 {
00199 CMutexGuard GUARD(s_ClassInfoMutex);
00200 delete sm_ClassesById;
00201 sm_ClassesById = 0;
00202 delete sm_ClassesByName;
00203 sm_ClassesByName = 0;
00204 Classes().insert(this);
00205 }
00206
00207 void CClassTypeInfoBase::Deregister(void)
00208 {
00209 CMutexGuard GUARD(s_ClassInfoMutex);
00210 delete sm_ClassesById;
00211 sm_ClassesById = 0;
00212 delete sm_ClassesByName;
00213 sm_ClassesByName = 0;
00214 Classes().erase(this);
00215 if (Classes().size() == 0) {
00216 delete sm_Classes;
00217 sm_Classes = 0;
00218 }
00219 }
00220
00221 TTypeInfo CClassTypeInfoBase::GetClassInfoById(const type_info& id)
00222 {
00223 TClassesById& types = ClassesById();
00224 TClassesById::iterator i = types.find(&id);
00225 if ( i == types.end() ) {
00226 string msg("class not found: ");
00227 msg += id.name();
00228 NCBI_THROW(CSerialException,eInvalidData, msg);
00229 }
00230 return i->second;
00231 }
00232
00233 TTypeInfo CClassTypeInfoBase::GetClassInfoByName(const string& name)
00234 {
00235 TClassesByName& classes = ClassesByName();
00236 TClassesByName::iterator i = classes.find(name);
00237 if ( i == classes.end() ) {
00238 string msg("class not found: ");
00239 msg += name;
00240 NCBI_THROW(CSerialException,eInvalidData, msg);
00241 }
00242 return i->second;
00243 }
00244
00245 void CClassTypeInfoBase::GetRegisteredModuleNames(
00246 CClassTypeInfoBase::TRegModules& modules)
00247 {
00248 modules.clear();
00249 CMutexGuard GUARD(s_ClassInfoMutex);
00250 if (sm_Modules) {
00251 modules.insert(sm_Modules->begin(), sm_Modules->end());
00252 }
00253 }
00254
00255 void CClassTypeInfoBase::GetRegisteredClassNames(
00256 const string& module, CClassTypeInfoBase::TRegClasses& names)
00257 {
00258 names.clear();
00259 CMutexGuard GUARD(s_ClassInfoMutex);
00260 TClasses& cc = Classes();
00261 ITERATE ( TClasses, i , cc ) {
00262 const CClassTypeInfoBase* info = *i;
00263 if (info->GetModuleName() == module) {
00264 names.insert( info->GetName());
00265 }
00266 }
00267 }
00268
00269 void CClassTypeInfoBase::RegisterModule(const string& module)
00270 {
00271 CMutexGuard GUARD(s_ClassInfoMutex);
00272 if (!sm_Modules) {
00273 sm_Modules = new set<string>;
00274 }
00275 sm_Modules->insert(module);
00276 }
00277
00278 const CObject* CClassTypeInfoBase::GetCObjectPtr(TConstObjectPtr objectPtr) const
00279 {
00280 if ( IsCObject() ) {
00281 return static_cast<const CObject*>(objectPtr);
00282 }
00283 return 0;
00284 }
00285
00286 CTypeInfo::EMayContainType
00287 CClassTypeInfoBase::GetMayContainType(TTypeInfo typeInfo) const
00288 {
00289 CMutexGuard GUARD(GetTypeInfoMutex());
00290 TContainedTypes* cache = m_ContainedTypes.get();
00291 if ( !cache ) {
00292 m_ContainedTypes.reset(cache = new TContainedTypes);
00293 }
00294 pair<TContainedTypes::iterator, bool> ins =
00295 cache->insert(TContainedTypes::value_type(typeInfo,
00296 eMayContainType_recursion));
00297 if ( !ins.second ) {
00298 return ins.first->second;
00299 }
00300
00301 static int recursion_level = 0;
00302 ++recursion_level;
00303 EMayContainType ret;
00304 try {
00305 ret = CalcMayContainType(typeInfo);
00306 --recursion_level;
00307 if ( ret == eMayContainType_recursion ) {
00308 if ( recursion_level == 0 ) {
00309 ins.first->second = ret = eMayContainType_no;
00310 }
00311 else {
00312 cache->erase(ins.first);
00313 }
00314 }
00315 else {
00316 ins.first->second = ret;
00317 }
00318 }
00319 catch ( ... ) {
00320 --recursion_level;
00321 cache->erase(ins.first);
00322 throw;
00323 }
00324 return ret;
00325 }
00326
00327 CTypeInfo::EMayContainType
00328 CClassTypeInfoBase::CalcMayContainType(TTypeInfo typeInfo) const
00329 {
00330 EMayContainType ret = eMayContainType_no;
00331
00332 for ( TMemberIndex i = GetItems().FirstIndex(),
00333 last = GetItems().LastIndex(); i <= last; ++i ) {
00334 EMayContainType contains = GetItems().GetItemInfo(i)->GetTypeInfo()->
00335 IsOrMayContainType(typeInfo);
00336 if ( contains == eMayContainType_yes ) {
00337 return contains;
00338 }
00339 if ( contains == eMayContainType_recursion ) {
00340 ret = contains;
00341 }
00342 }
00343 return ret;
00344 }
00345
00346 class CPreReadHook : public CReadObjectHook
00347 {
00348 typedef CReadObjectHook CParent;
00349 public:
00350 typedef CClassTypeInfoBase::TPreReadFunction TPreReadFunction;
00351
00352 CPreReadHook(TPreReadFunction func);
00353
00354 void ReadObject(CObjectIStream& in, const CObjectInfo& object);
00355
00356 private:
00357 TPreReadFunction m_PreRead;
00358 };
00359
00360 CPreReadHook::CPreReadHook(TPreReadFunction func)
00361 : m_PreRead(func)
00362 {
00363 }
00364
00365 void CPreReadHook::ReadObject(CObjectIStream& in,
00366 const CObjectInfo& object)
00367 {
00368 m_PreRead(object.GetTypeInfo(), object.GetObjectPtr());
00369 object.GetTypeInfo()->DefaultReadData(in, object.GetObjectPtr());
00370 }
00371
00372 class CPostReadHook : public CReadObjectHook
00373 {
00374 typedef CReadObjectHook CParent;
00375 public:
00376 typedef CClassTypeInfoBase::TPostReadFunction TPostReadFunction;
00377
00378 CPostReadHook(TPostReadFunction func);
00379
00380 void ReadObject(CObjectIStream& in, const CObjectInfo& object);
00381
00382 private:
00383 TPostReadFunction m_PostRead;
00384 };
00385
00386 CPostReadHook::CPostReadHook(TPostReadFunction func)
00387 : m_PostRead(func)
00388 {
00389 }
00390
00391 void CPostReadHook::ReadObject(CObjectIStream& in,
00392 const CObjectInfo& object)
00393 {
00394 object.GetTypeInfo()->DefaultReadData(in, object.GetObjectPtr());
00395 m_PostRead(object.GetTypeInfo(), object.GetObjectPtr());
00396 }
00397
00398 class CPreWriteHook : public CWriteObjectHook
00399 {
00400 typedef CWriteObjectHook CParent;
00401 public:
00402 typedef CClassTypeInfoBase::TPreWriteFunction TPreWriteFunction;
00403
00404 CPreWriteHook(TPreWriteFunction func);
00405
00406 void WriteObject(CObjectOStream& out, const CConstObjectInfo& object);
00407
00408 private:
00409 TPreWriteFunction m_PreWrite;
00410 };
00411
00412 CPreWriteHook::CPreWriteHook(TPreWriteFunction func)
00413 : m_PreWrite(func)
00414 {
00415 }
00416
00417 void CPreWriteHook::WriteObject(CObjectOStream& out,
00418 const CConstObjectInfo& object)
00419 {
00420 m_PreWrite(object.GetTypeInfo(), object.GetObjectPtr());
00421 object.GetTypeInfo()->DefaultWriteData(out, object.GetObjectPtr());
00422 }
00423
00424 class CPostWriteHook : public CWriteObjectHook
00425 {
00426 typedef CWriteObjectHook CParent;
00427 public:
00428 typedef CClassTypeInfoBase::TPostWriteFunction TPostWriteFunction;
00429
00430 CPostWriteHook(TPostWriteFunction func);
00431
00432 void WriteObject(CObjectOStream& out, const CConstObjectInfo& object);
00433
00434 private:
00435 TPostWriteFunction m_PostWrite;
00436 };
00437
00438 CPostWriteHook::CPostWriteHook(TPostWriteFunction func)
00439 : m_PostWrite(func)
00440 {
00441 }
00442
00443 void CPostWriteHook::WriteObject(CObjectOStream& out,
00444 const CConstObjectInfo& object)
00445 {
00446 object.GetTypeInfo()->DefaultWriteData(out, object.GetObjectPtr());
00447 m_PostWrite(object.GetTypeInfo(), object.GetObjectPtr());
00448 }
00449
00450 void CClassTypeInfoBase::SetPreReadFunction(TPreReadFunction func)
00451 {
00452 SetGlobalReadHook(new CPreReadHook(func));
00453 }
00454
00455 void CClassTypeInfoBase::SetPostReadFunction(TPostReadFunction func)
00456 {
00457 SetGlobalReadHook(new CPostReadHook(func));
00458 }
00459
00460 void CClassTypeInfoBase::SetPreWriteFunction(TPreWriteFunction func)
00461 {
00462 SetGlobalWriteHook(new CPreWriteHook(func));
00463 }
00464
00465 void CClassTypeInfoBase::SetPostWriteFunction(TPostWriteFunction func)
00466 {
00467 SetGlobalWriteHook(new CPostWriteHook(func));
00468 }
00469
00470 END_NCBI_SCOPE
00471
00472