NCBI C++ ToolKit
obj_convert.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: obj_convert.cpp 40222 2018-01-10 18:45:15Z katargir $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Mike DiCuccio
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbimtx.hpp>
35 #include "convert_graph.hpp"
36 #include <serial/iterator.hpp>
37 
38 #include <algorithm>
39 
40 
41 
44 
45 
46 DEFINE_STATIC_MUTEX(s_ObjCvtMutex);
49 
51 
52 // New Interface
53 //////////////////////////////////////////////////////////////////////////
54 //
55 // converter registration
56 //
57 
59 {
60  CMutexGuard LOCK(s_ObjCvtMutex);
62  sm_Relations.push_back(CRef<CRelation>(rel));
63 }
64 
66 {
67  CMutexGuard LOCK(s_ObjCvtMutex);
68 
69  size_t idx = x_FindRelationByName(name);
70  if (idx == numeric_limits<size_t>::max())
71  return 0;
72 
73  return sm_Relations[idx];
74 }
75 
76 
77 static bool PCompare(const CConvGraph::TPath& p1, const CConvGraph::TPath& p2)
78 {
79  return p1.size() < p2.size();
80 }
81 
82 static void x_BuildRelations
83  (const CObjectConverter::TRelationVector& registered,
84  const vector<CConvGraph::TPath>& paths,
86 {
87  if (paths.size() == 0)
88  return;
89 
90  // Find out if there are several paths with smallest length
91  size_t count = 0, length;
92  length = paths[0].size();
93  ITERATE(vector<CConvGraph::TPath>, iter, paths) {
94  if ((*iter).size() > length)
95  break;
96  ++count;
97  }
98 
99  // Add composite relation with paths of smallest length
100  CRef<CComplexRelation> composite(new CComplexRelation(true));
101  if (count > 1)
102  relations.push_back(CRef<CRelation>(composite));
103 
104  ITERATE(vector<CConvGraph::TPath>, iter, paths) {
105  if ((*iter).size() > length)
106  break;
107 
108  CRef<CRelation> rel;
109 
110  if ((*iter).size() == 1) {
111  rel = registered[(*iter).front()];
112  }
113  else {
115  ITERATE(CConvGraph::TPath, iter2, *iter)
116  complex->AddRelation(registered[*iter2]);
117  rel = complex;
118  }
119 
120  relations.push_back(rel);
121  if (count > 1)
122  composite->AddRelation(rel);
123  }
124 }
125 
126 void CObjectConverter::FindRelations(objects::CScope& scope,
127  const CObject& obj,
128  const string& to_type_in,
129  TRelationVector& relations)
130 {
131  CMutexGuard LOCK(s_ObjCvtMutex);
132 
133  size_t idxIdentity = x_FindRelationByName(CIdentityRelation::m_Name);
134  if (idxIdentity == numeric_limits<size_t>::max())
135  return;
136 
137  const string& to_type = x_NormalizeTypeName(to_type_in);
138 
139  const CSerialObject* so = dynamic_cast<const CSerialObject*>(&obj);
140  string from_type = so ? so->GetThisTypeInfo()->GetName() : typeid(obj).name();
141 
142  CConvGraph graph;
143  map<string, size_t> vertices;
144  x_BuildGraph(graph, vertices);
145 
147  it = vertices.find(from_type);
148  size_t from_vertex = (it != vertices.end()) ?
149  it->second : numeric_limits<size_t>::max();
150 
151  it = vertices.find(to_type);
152  size_t to_vertex = (it != vertices.end()) ?
153  it->second : numeric_limits<size_t>::max();
154 
155  //
156  // check to see if our object is a serial object first
157  //
158 
159  vector<CConvGraph::TPath> paths;
160 
161  if (so && (to_type == "Object" || to_type == "SerialObject")) {
162  graph.FindPaths(from_vertex, to_vertex, paths);
163  if (paths.size() > 0 && paths[0].size() <= 2)
164  x_BuildRelations (sm_Relations, paths, relations);
165  else
166  relations.push_back(sm_Relations[idxIdentity]);
167  return;
168  }
169 
170  // If types not present among converters we still can handle identity case
171  if (from_type == to_type) {
172  relations.push_back(sm_Relations[idxIdentity]);
173  return;
174  }
175 
176  graph.FindPaths(from_vertex, to_vertex, paths);
177 
178  if (paths.size() > 0) {
179  x_BuildRelations (sm_Relations, paths, relations);
180  return;
181  }
182 
183  //
184  // Handle Container Object (CDocument, CGBProjectHandle, CProjectItem)
185  //
186 
187  size_t idxContainer2Object = x_FindRelationByName("Any Container --> Object");
188  if (idxContainer2Object == numeric_limits<size_t>::max())
189  return;
190 
191  CRelation::TObjects related;
192  sm_Relations[idxContainer2Object]->GetRelated(scope, obj, related);
193  if (related.size() == 0)
194  return;
195 
196  set<CConvGraph::TPath> pathSet;
197 
198  ITERATE(CRelation::TObjects, iter, related) {
199  const CObject& o = **iter;
200  const CSerialObject* so = dynamic_cast<const CSerialObject*>(&o);
201  from_type = so ? so->GetThisTypeInfo()->GetName() : typeid(o).name();
202 
203  if (from_type == to_type) {
204  pathSet.insert(CConvGraph::TPath(1, idxIdentity));
205  continue;
206  }
207 
208  it = vertices.find(from_type);
209  from_vertex = (it != vertices.end()) ?
210  it->second : numeric_limits<size_t>::max();
211 
212  vector<CConvGraph::TPath> paths2;
213  graph.FindPaths(from_vertex, to_vertex, paths2);
214  ITERATE(vector<CConvGraph::TPath>, iter2, paths2)
215  pathSet.insert(*iter2);
216  }
217 
218  if (pathSet.size() == 0)
219  return;
220 
221  // paths.insert(paths.begin(), pathSet.begin(), pathSet.end());
222  ITERATE(set<CConvGraph::TPath>, it, pathSet)
223  paths.push_back(*it);
224 
225  NON_CONST_ITERATE(vector<CConvGraph::TPath>, it, paths)
226  (*it).insert((*it).begin(), idxContainer2Object);
227 
228  sort(paths.begin(), paths.end(), PCompare);
229  x_BuildRelations (sm_Relations, paths, relations);
230 }
231 
232 void CObjectConverter::DumpDotGraph(ostream& ostream, bool dumpIDs)
233 {
234  CMutexGuard LOCK(s_ObjCvtMutex);
235 
236  CConvGraph graph;
237  map<string, size_t> vertices;
238  x_BuildGraph(graph, vertices);
239 
240  ostream << "digraph {" << endl;
241  if (dumpIDs) {
243  ostream << " \"" << vertices[(*iter)->GetTypeName()]
244  << "\" -> \"" << vertices[(*iter)->GetRelatedTypeName()] << "\";" << endl;
245  }
246  }
247  else {
249  ostream << " \"" << (*iter)->GetTypeName()
250  << "\" -> \"" << (*iter)->GetRelatedTypeName() << "\";" << endl;
251  }
252  }
253  ostream << "}" << endl;
254 }
255 
256 // Old Interface
257 //////////////////////////////////////////////////////////////////////////
258 //
259 // converter registration
260 //
261 
262 void CObjectConverter::Register(const CTypeInfo* from_type,
263  const CTypeInfo* to_type,
264  ITypeConverter* cvt)
265 {
266  Register(from_type->GetName(), to_type->GetName(), cvt);
267 }
268 
269 
270 void CObjectConverter::Register(const string& from_type,
271  const CTypeInfo* to_type,
272  ITypeConverter* cvt)
273 {
274  Register(from_type, to_type->GetName(), cvt);
275 }
276 
277 
278 void CObjectConverter::Register(const CTypeInfo* from_type,
279  const string& to_type,
280  ITypeConverter* cvt)
281 {
282  Register(from_type->GetName(), to_type, cvt);
283 }
284 
286 {
287 public:
289  CRelationTypeConverterAdapter(const string& from_type,
290  const string& to_type,
291  ITypeConverter* typeConverter) :
292  m_FromType(from_type),
293  m_ToType(to_type),
294  m_TypeConverter(typeConverter) {}
295 
296  virtual string GetName() const
297  {
298  const CObject& o = m_TypeConverter.GetObject();
299  return typeid(o).name();
300  }
301  virtual string GetDescription() const { return "ITypeConverterAdaptor"; }
302 
303  virtual string GetTypeName() const { return m_FromType; }
304  virtual string GetRelatedTypeName() const { return m_ToType; }
305 
306  virtual void GetRelated(objects::CScope& scope, const CObject& obj,
307  TObjects& related,
308  TFlags flags = eDefault,
309  ICanceled* cancel = NULL) const;
310 
311  virtual void Dump(ostream& ostream) const
312  {
313  const CObject& o = m_TypeConverter.GetObject();
314  ostream << typeid(o).name() << endl;
315  }
316 
317 private:
318  string m_FromType;
319  string m_ToType;
321 };
322 
324  objects::CScope& scope,
325  const CObject& obj,
326  TObjects& related,
327  TFlags flags,
328  ICanceled*) const
329 {
330  ITypeConverter::TObjList obj_list;
331  m_TypeConverter->Convert(scope, obj, obj_list, flags);
332  ITERATE(ITypeConverter::TObjList, iter, obj_list) {
333  related.push_back(SObject(iter->GetObject()));
334  }
335 }
336 
337 void CObjectConverter::Register(const string& from_type,
338  const string& to_type,
339  ITypeConverter* cvt)
340 {
341  Register(new CRelationTypeConverterAdapter(from_type, to_type, cvt));
342 }
343 
344 void CObjectConverter::RegisterTypeAlias(const string& from_type,
345  const string& alias)
346 {
347  CMutexGuard LOCK(s_ObjCvtMutex);
348  sm_TypeAliases[alias] = from_type;
349 }
350 
351 
353 {
355 }
356 
357 
359 {
360  return sm_DefaultFlags;
361 }
362 
363 
364 //////////////////////////////////////////////////////////////////////////
365 //
366 // object conversion
367 //
368 
369 bool CObjectConverter::CanConvert(CScope& scope, const CObject& obj,
370  const CTypeInfo* info)
371 {
372  return CanConvert(scope, obj, info->GetName());
373 }
374 
375 
376 bool CObjectConverter::CanConvert(CScope& scope, const CObject& obj,
377  const string& to_type_in)
378 {
379  TRelationVector relations;
380  FindRelations(scope, obj, to_type_in, relations);
381  return (relations.size() > 0);
382 }
383 
384 
385 void CObjectConverter::Convert(CScope& scope, const CObject& obj,
386  const CTypeInfo* info, TObjList& objs,
387  TFlags flags)
388 {
389  Convert(scope, obj, info->GetName(), objs, flags);
390 }
391 
392 
393 void CObjectConverter::Convert(CScope& scope, const CObject& obj,
394  const string& to_type_in, TObjList& objs,
395  TFlags flags)
396 {
397  TRelationVector relations;
398  FindRelations(scope, obj, to_type_in, relations);
399 
400 #if 0
401  CNcbiOfstream ostr("C:\\temp\\conversions_log.txt", IOS_BASE::out | IOS_BASE::app);
402  ostr << endl << endl;
403 
404  const CSerialObject* so = dynamic_cast<const CSerialObject*>(&obj);
405  string from_type = so ? so->GetThisTypeInfo()->GetName() : typeid(obj).name();
406  ostr << "Conversion: " << from_type << " -- > " << to_type_in << endl << "{" << endl;
407 
408  //int count = min((size_t)3, relations.size());
409  int count = relations.size();
410  if (count == 0)
411  ostr << "*** Conversion not found ***" << endl;
412  else {
413  for (int i = 0; i < count; ++i) {
414  relations[i]->Dump(ostr);
415  ostr << endl;
416  }
417  }
418 
419  ostr << "}" << endl;
420 #endif
421 
422  if (relations.size() == 0)
423  return;
424 
425  CRelation::TObjects related;
426  relations[0]->GetRelated(scope, obj, related, flags);
427 
428  ITERATE(CRelation::TObjects, iter, related) {
429  objs.push_back(ITypeConverter::SObject(iter->GetObject(),
430  iter->GetComment()));
431  }
432 }
433 
435 {
437  size_t from_index, to_index;
438  string from_type = (*iter)->GetTypeName();
439  string to_type = (*iter)->GetRelatedTypeName();
440 
441  map<string, size_t>::const_iterator it = vertices.find(from_type);
442  if (it == vertices.end()) {
443  from_index = vertices.size();
444  vertices[from_type] = from_index;
445  }
446  else
447  from_index = it->second;
448 
449  it = vertices.find(to_type);
450  if (it == vertices.end()) {
451  to_index = vertices.size();
452  vertices[to_type] = to_index;
453  }
454  else
455  to_index = it->second;
456 
457  graph.add_edge(from_index, to_index);
458  }
459 }
460 
461 size_t CObjectConverter::x_FindRelationByName(const string& name)
462 {
464  if ((*iter)->GetName() == name) {
465  return iter - sm_Relations.begin();
466  }
467  }
469 }
470 
471 const string& CObjectConverter::x_NormalizeTypeName(const string& str)
472 {
474  if (iter != sm_TypeAliases.end()) {
475  return iter->second;
476  }
477 
478  return str;
479 }
480 
481 //////////////////////////////////////////////////////////////////////////
482 //
483 // conversion cache
484 //
487  const CObject& obj,
488  const CTypeInfo* info,
490 {
491  if (info) {
492  return Convert(scope, obj, info->GetName(), flags);
493  }
494  return m_EmptyObjList;
495 }
496 
497 
500  const CObject& obj,
501  const string& type_name,
503 {
504  SCacheKey key(scope, obj, type_name);
505 
507  if ((pos = m_ObjCache.find(key)) == m_ObjCache.end()) {
509  CObjectConverter::Convert(scope, obj, type_name, val.second, flags);
510  pair<CConvertCache::TCache::iterator, bool>
512 
513  if (!r.second) {
514  return m_EmptyObjList;
515  }
516  pos = r.first;
517  }
518 
519  return pos->second;
520 }
521 
522 
524  const SCacheKey& key_) const
525 {
526  if (key1.m_Scope.GetPointer() < key_.m_Scope.GetPointer()) {
527  return true;
528  }
529 
530  if (key1.m_Scope.GetPointer() > key_.m_Scope.GetPointer()) {
531  return false;
532  }
533 
534  // key1.m_Scope == key_.m_Scope
535  if (key1.m_Obj.GetPointer() < key_.m_Obj.GetPointer()) {
536  return true;
537  }
538  if (key1.m_Obj.GetPointer() > key_.m_Obj.GetPointer()) {
539  return false;
540  }
541 
542  // (key1.m_Scope == key_.m_Scope) && (key1.m_Obj == key_.m_Obj)
543  return (NStr::CompareCase(key1.m_Type, key_.m_Type) < 0);
544 };
545 
vector< size_t > TPath
void FindPaths(size_t startVertex, size_t endVertex, vector< TPath > &paths) const
size_t add_edge(size_t from, size_t to)
TObjList m_EmptyObjList
virtual const TObjList & Convert(objects::CScope &scope, const CObject &obj, const CTypeInfo *info, CObjectConverter::TFlags flags=CObjectConverter::eDefault)
CObjectConverter::TObjList TObjList
static const char * m_Name
Definition: relation.hpp:183
static void RegisterTypeAlias(const string &real_name, const string &alias)
static TTypeAliases sm_TypeAliases
static void SetDefaultFlags(TFlags flags)
static const CRelation * FindRelationByName(const string &name)
Definition: obj_convert.cpp:65
static void Register(CRelation *rel)
Definition: obj_convert.cpp:58
static const string & x_NormalizeTypeName(const string &str)
static size_t x_FindRelationByName(const string &name)
static void Convert(objects::CScope &scope, const CObject &obj, const CTypeInfo *info, TObjList &objs, TFlags flags=eDefault)
Convert an object of potentially unknown type to a set of objects of known type.
static void x_BuildGraph(CConvGraph &graph, map< string, size_t > &vertices)
vector< TRelation > TRelationVector
static TFlags sm_DefaultFlags
the default conversion flags
static void DumpDotGraph(ostream &ostream, bool dumpIDs=false)
static TFlags GetDefaultFlags(void)
static bool CanConvert(objects::CScope &scope, const CObject &obj, const CTypeInfo *type_info)
Determine whether an indicated conversion can be performed.
static TRelationVector sm_Relations
static void FindRelations(objects::CScope &scope, const CObject &obj, const string &to_type_in, TRelationVector &relations)
CObject –.
Definition: ncbiobj.hpp:180
CRef –.
Definition: ncbiobj.hpp:618
virtual void GetRelated(objects::CScope &scope, const CObject &obj, TObjects &related, TFlags flags=eDefault, ICanceled *cancel=NULL) const
virtual string GetRelatedTypeName() const
virtual string GetDescription() const
virtual void Dump(ostream &ostream) const
virtual string GetTypeName() const
CConstRef< ITypeConverter > m_TypeConverter
virtual string GetName() const
CRelationTypeConverterAdapter(const string &from_type, const string &to_type, ITypeConverter *typeConverter)
vector< SObject > TObjects
Definition: relation.hpp:130
virtual void GetRelated(objects::CScope &scope, const CObject &obj, TObjects &related, TFlags flags=eDefault, ICanceled *cancel=NULL) const =0
int TFlags
Definition: relation.hpp:65
virtual string GetName() const =0
CScope –.
Definition: scope.hpp:92
Base class for all serializable objects.
Definition: serialbase.hpp:150
CTypeInfo class contains all information about C++ types (both basic and classes): members and layout...
Definition: typeinfo.hpp:76
Interface for testing cancellation request in a long lasting operation.
Definition: icanceled.hpp:51
@ eDefault
combined sets of flags
Definition: obj_convert.hpp:64
vector< SObject > TObjList
virtual void Convert(objects::CScope &scope, const CObject &obj, TObjList &objs, TFlags flags=eDefault) const =0
size_type size() const
Definition: map.hpp:148
container_type::const_iterator const_iterator
Definition: map.hpp:53
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: set.hpp:45
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
size_type size() const
Definition: set.hpp:132
static uch flags
std::ofstream out("events_result.xml")
main entry point for tests
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
vector< CRef< CObject > > TObjects
Definition: objects.hpp:63
virtual const CTypeInfo * GetThisTypeInfo(void) const =0
TObjectType * GetPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1684
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
static int CompareCase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-sensitive compare of a substring with another string.
Definition: ncbistr.cpp:135
const string & GetName(void) const
Get name of this type.
Definition: typeinfo.cpp:249
#define NCBI_GUIOBJUTILS_EXPORT
Definition: gui_export.h:512
int i
static MDB_envinfo info
Definition: mdb_load.c:37
constexpr auto sort(_Init &&init)
const struct ncbi::grid::netcache::search::fields::KEY key
Multi-threading – mutexes; rw-locks; semaphore.
T max(T x_, T y_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
USING_SCOPE(objects)
static void x_BuildRelations(const CObjectConverter::TRelationVector &registered, const vector< CConvGraph::TPath > &paths, CObjectConverter::TRelationVector &relations)
Definition: obj_convert.cpp:83
DEFINE_STATIC_MUTEX(s_ObjCvtMutex)
static bool PCompare(const CConvGraph::TPath &p1, const CConvGraph::TPath &p2)
Definition: obj_convert.cpp:77
static const char * str(char *buf, int n)
Definition: stats.c:84
bool operator()(const SCacheKey &key1, const SCacheKey &key2) const
CConstRef< objects::CScope > m_Scope
CConstRef< CObject > m_Obj
struct SObject provides an interface for defining what is returned from object conversion.
Definition: relation.hpp:71
struct SObject provides an interface for defining what is returned from object conversion.
Definition: obj_convert.hpp:72
#define _ASSERT
Modified on Tue Nov 28 02:27:05 2023 by modify_doxy.py rev. 669887