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

Go to the SVN repository for this file.

1 /* $Id: traversal_node.cpp 74404 2016-08-31 12:38:54Z ivanov $
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 * Author: Michael Kornbluh
27 *
28 * File Description:
29 * Represents one node in the traversal code (this gets translated into one function).
30 */
31 
32 #include <ncbi_pch.hpp>
33 
34 #include "aliasstr.hpp"
35 #include "blocktype.hpp"
36 #include "choicetype.hpp"
37 #include "enumtype.hpp"
38 #include "module.hpp"
39 #include "namespace.hpp"
40 #include "reftype.hpp"
41 #include "statictype.hpp"
42 #include "stdstr.hpp"
43 #include "traversal_node.hpp"
44 #include "typestr.hpp"
45 #include "unitype.hpp"
46 
47 #include <serial/typeinfo.hpp>
48 #include <util/static_map.hpp>
49 #include <iterator>
50 
52 
54 // Okay to dynamically allocate and never free, because it's needed for the entire
55 // duration of the program.
58 
59 CRef<CTraversalNode> CTraversalNode::Create( CRef<CTraversalNode> caller, const string &var_name, CDataType *asn_node )
60 {
61  // in the future, maybe a real factory pattern should be done here
62  return CRef<CTraversalNode>( new CTraversalNode( caller, var_name, asn_node ) );
63 }
64 
65 CTraversalNode::CTraversalNode( CRef<CTraversalNode> caller, const string &var_name, CDataType *asn_node )
66 : m_Type(eType_Primitive), m_IsTemplate(false), m_DoStoreArg(false)
67 {
68  if( var_name.empty() ) {
69  throw runtime_error("No var_name given for CTraversalNode");
70  }
71 
72  // If another node was previously constructed from the same asn_node,
73  // grab as much as we can from it to avoid as much work as possible.
74  TASNNodeToNodeMap::iterator similar_node_iter = m_ASNNodeToNodeMap.find( asn_node );
75  if( similar_node_iter == m_ASNNodeToNodeMap.end() ) {
76  x_LoadDataFromASNNode( asn_node );
78  } else {
79  CTraversalNode &other_node = *(similar_node_iter->second);
80  m_TypeName = other_node.m_TypeName;
82  m_IncludePath = other_node.m_IncludePath;
83  m_Type = other_node.m_Type;
84  m_IsTemplate = other_node.m_IsTemplate;
85  }
86 
87  // function name is our caller's function name plus our variable
88  m_FuncName = ( caller ? ( (caller->m_FuncName) + "_" ) : kEmptyStr ) + NStr::Replace(var_name, "-", "_" );
89 
90  // only attach to caller once we've successfully created the object
91  if( caller ) {
92  AddCaller( var_name, caller );
93  }
94 
95  // add it to the list of all constructed nodes
96  ms_EveryNode->insert( this );
97 }
98 
100 : m_Type(eType_Primitive), m_IsTemplate(false), m_DoStoreArg(false)
101 {
102  ms_EveryNode->insert( this );
103 }
104 
106 {
107  // remove it from the list of all constructed nodes
108  ms_EveryNode->erase( this );
109 }
110 
112 {
113  m_TypeName = asn_node->GetFullName();
114 
115  // figure out m_InputClassName
116  AutoPtr<CTypeStrings> c_type = asn_node->GetFullCType();
117  const CNamespace& ns = c_type->GetNamespace();
118  m_InputClassName = c_type->GetCType(ns);
119 
120  // handle inner classes
121  if( (asn_node->IsEnumType() && ! dynamic_cast<CIntEnumDataType*>(asn_node) ) ||
123  {
124  const CDataType *parent_asn_node = asn_node->GetParentType();
125  while( parent_asn_node ) {
126  AutoPtr<CTypeStrings> parent_type_strings = parent_asn_node->GetFullCType();
127  const CNamespace& parent_ns = parent_type_strings->GetNamespace();
128  string parent_class_name = parent_type_strings->GetCType(parent_ns);
129  if( NStr::EndsWith( parent_class_name, m_InputClassName ) ) {
130  break;
131  }
132 
133  m_InputClassName = parent_class_name + "::" + m_InputClassName;
134 
135  parent_asn_node = parent_asn_node->GetParentType();
136  }
137  }
138 
139  if( ! asn_node->IsReference() ) {
141  }
142 
143  if( asn_node->IsReference() ) {
144  CReferenceDataType* ref = dynamic_cast<CReferenceDataType*>(asn_node);
145  // get the module of the symbol we're referencing, not our module
148  } else if( asn_node->IsContainer() ) {
149  if( dynamic_cast<CChoiceDataType*>(asn_node) != 0 ) {
151  } else {
153  }
154  } else if( dynamic_cast<CUniSequenceDataType*>(asn_node) != 0 ) {
156  } else if( dynamic_cast<CEnumDataType*>(asn_node) != 0 ) {
157  m_Type = eType_Enum;
158  } else if( dynamic_cast<CNullDataType *>(asn_node) != 0 ) {
159  m_Type = eType_Null;
160  } else if( asn_node->IsStdType() ) {
161  // nothing to do
162  } else {
163  throw runtime_error("possible bug in code generator: unknown type for '" + m_TypeName + "'");
164  }
165 
166  // since lists and vectors seem to be used interchangeably in
167  // the datatool object code with no discernible pattern, we can't
168  // know at this time what the type will be, so we just use
169  // a template and let the compiler figure it out.
170  if( NStr::Find( m_InputClassName, "std::list" ) != NPOS ) {
171  m_IsTemplate = true;
173  }
174 }
175 
177 {
178  m_Callers.insert( CRef<CNodeCall>( new CNodeCall(var_name, caller ) ) );
179  caller->m_Callees.insert( CRef<CNodeCall>( new CNodeCall(var_name, Ref()) ) );
180 }
181 
182 void CTraversalNode::GenerateCode( const string &func_class_name, CNcbiOstream& traversal_output_file, EGenerateMode generate_mode )
183 {
184  // print start of function
185  if( m_IsTemplate ) {
186  traversal_output_file << "template< typename " << m_InputClassName << " >" << endl;
187  }
188  traversal_output_file << "void ";
189  if( (! func_class_name.empty()) && (generate_mode == eGenerateMode_Definitions) ) {
190  traversal_output_file << func_class_name << "::" ;
191  }
192  switch( m_Type ) {
193  case eType_Null:
194  traversal_output_file << m_FuncName << "( void )";
195  break;
196  default:
197  traversal_output_file << m_FuncName << "( " << m_InputClassName << " & " << ( x_IsSeqFeat() ? "arg0_raw" : "arg0" ) << " )";
198  break;
199  }
200 
201  // if we're just generating the prototypes, we end early
202  if( generate_mode == eGenerateMode_Prototypes ) {
203  traversal_output_file << ";" << endl;
204  return;
205  }
206 
207  traversal_output_file << endl;
208  traversal_output_file << "{ // type " << GetTypeAsString() << endl;
209 
210  // seq-feat functions require a little extra at the top
211  if( x_IsSeqFeat() ) {
212  traversal_output_file << " CRef<CSeq_feat> raw_ref( &arg0_raw );" << endl;
213  traversal_output_file << " CSeq_feat_EditHandle efh;" << endl;
214  traversal_output_file << endl;
215  traversal_output_file << " CRef<CSeq_feat> new_feat;" << endl;
216  traversal_output_file << endl;
217  traversal_output_file << " try {" << endl;
218  traversal_output_file << " // Try to use an edit handle so we can update the object manager" << endl;
219  traversal_output_file << " efh = CSeq_feat_EditHandle( m_Scope.GetSeq_featHandle( arg0_raw ) );" << endl;
220  traversal_output_file << " new_feat.Reset( new CSeq_feat );" << endl;
221  traversal_output_file << " new_feat->Assign( arg0_raw );" << endl;
222  traversal_output_file << " } catch(...) {" << endl;
223  traversal_output_file << " new_feat.Reset( &arg0_raw );" << endl;
224  traversal_output_file << " }" << endl;
225  traversal_output_file << endl;
226  traversal_output_file << " CSeq_feat &arg0 = *new_feat;" << endl;
227  traversal_output_file << endl;
228  }
229 
230  // store our arg if we're one of the functions that are supposed to
231  if( m_DoStoreArg ) {
232  traversal_output_file << " " << GetStoredArgVariable() << " = &arg0;" << endl;
233  traversal_output_file << endl;
234  }
235 
236  // generate calls to pre-callees user functions
238  traversal_output_file << " " << (*func_iter)->GetUserFuncName() << "( arg0";
239  ITERATE( CTraversalNode::TNodeVec, extra_arg_iter, (*func_iter)->GetExtraArgNodes() ) {
240  _ASSERT( (*extra_arg_iter)->GetDoStoreArg() );
241  traversal_output_file << ", *" << (*extra_arg_iter)->GetStoredArgVariable();
242  }
243  ITERATE( vector<string>, constant_arg_iter, (*func_iter)->GetConstantArgs() ) {
244  traversal_output_file << ", " << *constant_arg_iter;
245  }
246  traversal_output_file << " );" << endl;
247  }
248 
249  // generate calls to the contained types
250  if( ! m_Callees.empty() ) {
251  switch( m_Type ) {
252  case eType_Null:
253  case eType_Enum:
254  case eType_Primitive:
255  _ASSERT( m_Callees.empty() );
256  break;
257  case eType_Choice:
258  {
259  traversal_output_file << " switch( arg0.Which() ) {" << endl;
260  ITERATE( TNodeCallSet, child_iter, m_Callees ) {
261  string case_name = (*child_iter)->GetVarName();
262  case_name[0] = (char)toupper(case_name[0]);
263  NStr::ReplaceInPlace( case_name, "-", "_" );
264  traversal_output_file << " case " << m_InputClassName << "::e_" << case_name << ":" << endl;;
265  string argString = string("arg0.Set") + case_name + "()";
266  x_GenerateChildCall( traversal_output_file, (*child_iter)->GetNode(), argString );
267  traversal_output_file << " break;" << endl;
268  }
269  traversal_output_file << " default:" << endl;
270  traversal_output_file << " break;" << endl;
271  traversal_output_file << " }" << endl;
272  }
273  break;
274  case eType_Sequence:
275  {
276  ITERATE( TNodeCallSet, child_iter, m_Callees ) {
277  string case_name = (*child_iter)->GetVarName();
278  case_name[0] = (char)toupper(case_name[0]);
279  NStr::ReplaceInPlace( case_name, "-", "_" );
280  traversal_output_file << " if( arg0.IsSet" << case_name << "() ) {" << endl;;
281  string argString = string("arg0.Set") + case_name + "()";
282  x_GenerateChildCall( traversal_output_file, (*child_iter)->GetNode(), argString );
283  traversal_output_file << " }" << endl;
284  }
285  }
286  break;
287  case eType_Reference:
288  {
289  _ASSERT( m_Callees.size() == 1 );
290  CRef<CNodeCall> child_call = *m_Callees.begin();
291  string case_name = child_call->GetVarName();
292  CRef<CTraversalNode> child = child_call->GetNode();
293  case_name[0] = (char)toupper(case_name[0]);
294  NStr::ReplaceInPlace( case_name, "-", "_" );
295 
296  // some reference functions pass their argument directly and others
297  // have to call .Set() to get to it
298  const bool needs_set = ( (child->m_Type == eType_Primitive) ||
299  (child->m_Type == eType_UniSequence) );
300  const bool needs_isset = ( needs_set &&
301  child->GetInputClassName() != "std::string" );
302 
303  if( needs_isset ) {
304  traversal_output_file << " if( arg0.IsSet() ) {" << endl;
305  }
306 
307  string argString = ( needs_set ? "arg0.Set()" : "arg0" );
308  x_GenerateChildCall( traversal_output_file, child, argString );
309 
310  if( needs_isset ) {
311  traversal_output_file << " }" << endl;
312  }
313  }
314  break;
315  case eType_UniSequence:
316  {
317  _ASSERT( m_Callees.size() == 1 );
318  CRef<CNodeCall> child_call = *m_Callees.begin();
319  string case_name = child_call->GetVarName();
320  CRef<CTraversalNode> child = child_call->GetNode();
321  case_name[0] = (char)toupper(case_name[0]);
322  NStr::ReplaceInPlace( case_name, "-", "_" );
323  const char *input_class_prefix = ( m_IsTemplate ? "typename " : kEmptyCStr );
324  traversal_output_file << " NON_CONST_ITERATE( " << input_class_prefix << m_InputClassName << ", iter, arg0 ) { " << endl;
325 
326  int levelsOfDereference = 1;
327  if( NStr::FindNoCase(m_InputClassName, "CRef") != NPOS ) {
328  ++levelsOfDereference;
329  }
330  if( NStr::FindNoCase(m_InputClassName, "vector") != NPOS ) {
331  ++levelsOfDereference;
332  }
333  string argString = string(levelsOfDereference, '*') + "iter";
334  x_GenerateChildCall( traversal_output_file, child, argString );
335  traversal_output_file << " }" << endl;
336  }
337  break;
338  default:
339  throw runtime_error("Unknown node type. Probably bug in code generator.");
340  }
341  }
342 
343  // generate calls to post-callees user functions
344  ITERATE( TUserCallVec, a_func_iter, m_PostCalleesUserCalls ) {
345  traversal_output_file << " " << (*a_func_iter)->GetUserFuncName() << "( arg0";
346  ITERATE( CTraversalNode::TNodeVec, extra_arg_iter, (*a_func_iter)->GetExtraArgNodes() ) {
347  _ASSERT( (*extra_arg_iter)->GetDoStoreArg() );
348  traversal_output_file << ", *" << (*extra_arg_iter)->GetStoredArgVariable();
349  }
350  ITERATE( vector<string>, constant_arg_iter, (*a_func_iter)->GetConstantArgs() ) {
351  traversal_output_file << ", " << *constant_arg_iter;
352  }
353  traversal_output_file << " );" << endl;
354  }
355 
356  // reset stored arg since it's now invalid
357  if( m_DoStoreArg ) {
358  traversal_output_file << endl;
359  traversal_output_file << " " << GetStoredArgVariable() << " = NULL;" << endl;
360  }
361 
362  // a little extra logic at the end of Seq-feat functions
363  if( x_IsSeqFeat() ) {
364  traversal_output_file << endl;
365  traversal_output_file << " if( efh ) {" << endl;
366  traversal_output_file << " efh.Replace(arg0);" << endl;
367  traversal_output_file << " arg0_raw.Assign( arg0 );" << endl;
368  traversal_output_file << " }" << endl;
369  traversal_output_file << endl;
370  }
371 
372  // end of function
373  traversal_output_file << "} // end of " << m_FuncName << endl;
374  traversal_output_file << endl;
375 }
376 
378 {
379  // create a mapping from var_name to the list of callers who
380  // call us using that var_name
381  typedef map< std::string, TNodeVec > TVarNameToCallersMap;
382  TVarNameToCallersMap var_name_to_callers_map;
383  ITERATE( TNodeCallSet, caller_iter, m_Callers ) {
384  var_name_to_callers_map[(*caller_iter)->GetVarName()].push_back( (*caller_iter)->GetNode() );
385  }
386 
387  // nothing to do if all callers use the same name
388  // (This function should not have been called in this case, since
389  // we just wasted processing time)
390  if( var_name_to_callers_map.size() < 2 ) {
391  return;
392  }
393 
394  ITERATE( TVarNameToCallersMap, mapping_iter, var_name_to_callers_map ) {
395  const string &var_name = mapping_iter->first;
396  const TNodeVec &callers_for_this_var_name = mapping_iter->second;
397 
398  CRef<CTraversalNode> new_node( x_CloneWithoutCallers(var_name) );
399 
400  ITERATE( TNodeVec, caller_to_add_iter, callers_for_this_var_name) {
401  new_node->AddCaller( var_name, *caller_to_add_iter );
402  }
403  }
404 
405  // destroy this node, since we've duplicated its other calling cases
406  Clear();
407 }
408 
410  const std::vector< CRef<CTraversalNode> > &extra_arg_nodes,
411  const vector<string> &constant_args )
412  : m_UserFuncName( user_func_name ), m_ExtraArgNodes(extra_arg_nodes),
413  m_ConstantArgs(constant_args)
414 {
415  NON_CONST_ITERATE( std::vector< CRef<CTraversalNode> >, extra_arg_iter, m_ExtraArgNodes ) {
416  (*extra_arg_iter)->m_ReferencingUserCalls.push_back( CRef<CUserCall>(this) );
417  }
418 }
419 
421 {
422  TNodeVec node_path;
423  TNodeSet nodesSeen;
424  x_DepthFirst( callback, node_path, nodesSeen, traversal_opts );
425 }
426 
427 const string &CTraversalNode::GetTypeAsString(void) const
428 {
429  static const string kSequence = "Sequence";
430  static const string kChoice = "Choice";
431  static const string kPrimitive = "Primitive";
432  static const string kNull = "Null";
433  static const string kEnum = "Enum";
434  static const string kReference = "Reference";
435  static const string kUniSequence = "UniSequence";
436 
437  static const string kUnknown = "???";
438 
439  switch( m_Type ) {
441  return kSequence;
443  return kChoice;
445  return kPrimitive;
447  return kNull;
449  return kEnum;
451  return kReference;
453  return kUniSequence;
454  default:
455  // shouldn't happen
456  return kUnknown;
457  }
458 }
459 
461 {
462  m_PreCalleesUserCalls.push_back( user_call );
463 }
464 
466 {
467  m_PostCalleesUserCalls.push_back( user_call );
468 }
469 
471 {
472  if( NStr::StartsWith(m_FuncName, "x_") ) {
473  m_FuncName = m_FuncName.substr(2);
474  }
475 }
476 
477 bool CTraversalNode::Merge( CRef<CTraversalNode> node_to_merge_into_this,
478  EMergeNameAllowed merge_name_allowed )
479 {
480  // a node can't merge into itself
481  if( this == node_to_merge_into_this.GetPointerOrNull() ) {
482  return false;
483  }
484 
485  // if either had to store the argument, we also have to store our argument
486  m_DoStoreArg = ( m_DoStoreArg || node_to_merge_into_this->m_DoStoreArg );
487 
488  // find any user calls that depended on the other node's value and reassign them to us
490  node_to_merge_into_this->m_ReferencingUserCalls.begin(),
491  node_to_merge_into_this->m_ReferencingUserCalls.end() );
492  NON_CONST_ITERATE( TUserCallVec, call_iter, node_to_merge_into_this->m_ReferencingUserCalls ) {
493  NON_CONST_ITERATE( TNodeVec, node_iter, (*call_iter)->m_ExtraArgNodes ) {
494  if( *node_iter == node_to_merge_into_this->Ref() ) {
495  *node_iter = Ref();
496  }
497  }
498  }
499 
500  // add their callers as our callers
501  NON_CONST_ITERATE( TNodeCallSet, their_caller, node_to_merge_into_this->m_Callers ) {
502  AddCaller( (*their_caller)->GetVarName(), (*their_caller)->GetNode() );
503  }
504 
505  // change our name, if allowed
506  if( merge_name_allowed == eMergeNameAllowed_AllowNameChange ) {
507  x_MergeNames( m_FuncName, m_FuncName, node_to_merge_into_this->m_FuncName );
508  }
509 
510  // wipe out all data in the other node so it becomes a hollow shell and
511  // nothing calls it and it calls nothing. (Possibly garbage
512  // collected after this)
513  node_to_merge_into_this->Clear();
514 
515  return true;
516 }
517 
519 {
520  // don't let anyone call us
521  CRef<CTraversalNode> my_ref = Ref();
522  NON_CONST_ITERATE( TNodeCallSet, caller_iter, m_Callers ) {
523  CRef<CNodeCall> node_ref( new CNodeCall( (*caller_iter)->GetVarName(), my_ref ) );
524  (*caller_iter)->GetNode()->m_Callees.erase( node_ref );
525  }
526  m_Callers.clear();
527 
528  // don't call anyone
529  NON_CONST_ITERATE( TNodeCallSet, callee_iter, m_Callees ) {
530  CRef<CNodeCall> node_ref( new CNodeCall( (*callee_iter)->GetVarName(), my_ref ) );
531  (*callee_iter)->GetNode()->m_Callers.erase( node_ref );
532  }
533  m_Callees.clear();
534 
535  // no user calls
536  m_PreCalleesUserCalls.clear();
537  m_PostCalleesUserCalls.clear();
538 
539  // No one should depend on our value now
540  m_ReferencingUserCalls.clear();
541 }
542 
543 void CTraversalNode::x_DepthFirst( CDepthFirstCallback &callback, TNodeVec &node_path, TNodeSet &nodesSeen,
544  TTraversalOpts traversal_opts )
545 {
546  node_path.push_back( Ref() );
547 
548  const bool post_traversal =
549  ( ( traversal_opts & fTraversalOpts_Post ) != 0);
550  const bool allow_cycles =
551  ( ( traversal_opts & fTraversalOpts_AllowCycles ) != 0 );
552 
553  const bool seen_before = ( nodesSeen.find(Ref()) != nodesSeen.end() );
554  // must avoid cyclic calls on post-traversal or we will get infinite loops
555  // also if the user explicitly forbids it
556  if( seen_before && (post_traversal || ! allow_cycles) ) {
557  node_path.pop_back();
558  return;
559  }
560 
561  const CDepthFirstCallback::ECallType is_cyclic =
563 
564  // call callback before for pre-traversal
565  if( ! post_traversal ) {
566  if( ! callback.Call( *this, node_path, is_cyclic ) ) {
567  node_path.pop_back();
568  return;
569  }
570  }
571 
572  const bool up_callers =
573  ( ( traversal_opts & fTraversalOpts_UpCallers ) != 0 );
574  TNodeCallSet & set_to_traverse = ( up_callers ? m_Callers : m_Callees );
575 
576  // traverse
577  nodesSeen.insert( Ref() );
578  NON_CONST_ITERATE( TNodeCallSet, child_iter, set_to_traverse ) {
579  (*child_iter)->GetNode()->x_DepthFirst( callback, node_path, nodesSeen, traversal_opts );
580  }
581  nodesSeen.erase( Ref() );
582 
583  // call callback after for post-traversal
584  if( post_traversal ) {
585  // ignore return value since we're going to return anyway
586  callback.Call( *this, node_path, is_cyclic );
587  }
588 
589  node_path.pop_back();
590 }
591 
592 void CTraversalNode::x_GenerateChildCall( CNcbiOstream& traversal_output_file, CRef<CTraversalNode> child, const string &arg )
593 {
594  if( child->m_Type == eType_Null ) {
595  // NULL functions take no arguments
596  traversal_output_file << " " << child->m_FuncName << "();" << endl;
597  } else if( child->m_InputClassName == "int" ) {
598  // necessary hack, unfortunately
599  traversal_output_file << " _ASSERT( sizeof(int) == sizeof(" << arg << ") );" << endl;
600  traversal_output_file << " // the casting, etc. is a hack to get around the fact that we sometimes use TSeqPos " << endl;
601  traversal_output_file << " // instead of int, but we can't tell where by looking at the .asn file." << endl;
602  traversal_output_file << " " << child->m_FuncName << "( *(int*)&" << arg << " );" << endl;
603  } else {
604  traversal_output_file << " " << child->m_FuncName << "( " << arg << " );" << endl;
605  }
606 }
607 
608 struct CIsAlnum {
609  bool operator()( const char &ch ) { return isalnum(ch) != 0; }
610 };
611 struct CIsNotAlnum {
612  bool operator()( const char &ch ) { return isalnum(ch) == 0; }
613 };
614 
615 void CTraversalNode::x_TemplatizeType( string &type_name )
616 {
617  NStr::ReplaceInPlace( type_name, "std::list", "container" );
618  string result = "T";
619 
620  // Replace clumps of more than one non-alphanumeric character by one
621  // underscore
622  string::iterator pos = type_name.begin();
623  while( pos != type_name.end() ) {
624  string::iterator next_bad_char = find_if( pos, type_name.end(), CIsNotAlnum() );
625  // add the stuff before the next bad char straight to the result
626  result.insert( result.end(), pos, next_bad_char );
627  if( next_bad_char != type_name.end() ) {
628  result += '_';
629  }
630  // find the next good character after the bad one
631  pos = find_if( next_bad_char, type_name.end(), CIsAlnum() );
632  }
633 
635  result[0] = (char)toupper(result[0]);
636 
637  type_name.swap( result );
638 }
639 
641 {
642  return ( (m_Type != eType_Reference) && (m_InputClassName == "CSeq_feat") );
643 }
644 
645 void
646 CTraversalNode::x_MergeNames(string &result, const string& /*name1*/, const string& /*name2*/)
647 {
648  // the other names are ignored, but maybe in the future, we'll use them
649  if( ! NStr::EndsWith(result, "_ETC" ) ) {
650  result += "_ETC";
651  }
652 }
653 
655 {
657 
658  // This function should only be called before user calls are added
663 
664  result->m_Type = m_Type;
665  result->m_TypeName = m_TypeName;
666  result->m_InputClassName = m_InputClassName;
667  result->m_IncludePath = m_IncludePath;
668  result->m_IsTemplate = m_IsTemplate;
669 
670  result->m_FuncName = m_FuncName;
671 
672  // var_name was given to provide a reasonable name for this func
673  string::size_type last_underscore = result->m_FuncName.find_last_of("_");
674  if( string::npos == last_underscore ) {
675  last_underscore = result->m_FuncName.length();
676  }
677  // chop off underscore and the part after it
678  result->m_FuncName.resize( last_underscore );
679  result->m_FuncName += "_" + NStr::Replace(var_name, "-", "_") + NStr::IntToString(++ms_FuncUniquerInt);
680 
681  ITERATE( TNodeCallSet, callee_iter, m_Callees ) {
682  (*callee_iter)->GetNode()->AddCaller( (*callee_iter)->GetVarName(), result );
683  }
684 
685  return result;
686 }
687 
688 string CTraversalNode::x_ExtractIncludePathFromFileName( const string &asn_file_name )
689 {
690  static const string kObjectsStr = "objects";
691 
692  string::size_type objects_pos = asn_file_name.find( kObjectsStr );
693  string::size_type slash_after_objects = objects_pos + kObjectsStr.length();
694  string::size_type last_backslash_pos = asn_file_name.find_last_of("\\/");
695  if( (objects_pos == string::npos) ||
696  (slash_after_objects >= asn_file_name.length() ) ||
697  ( asn_file_name[slash_after_objects] != '\\' && asn_file_name[slash_after_objects] != '/') ||
698  ( last_backslash_pos == string::npos ) ||
699  ( last_backslash_pos <= slash_after_objects ) )
700  {
701  string msg;
702  msg += "All ASN file names must contain 'objects' in their path so ";
703  msg += "we can extract the location of .hpp files in the ";
704  msg += "include/objects directory. Example: C:/foo/bar/objects/seqloc/seqloc.asn. ";
705  msg += "You gave this file name: '" + asn_file_name + "'";
706  throw runtime_error(msg);
707  }
708 
709  // give the part after objects but before the last [back]slash
710  string result(
711  // The "+1" is to skip any backslash which might be after kObjectsStr
712  asn_file_name.begin() + slash_after_objects + 1,
713  asn_file_name.begin() + last_backslash_pos );
714 
715  // turn backslashes into forward slashes, though
716  NStr::ReplaceInPlace( result, "\\", "/" );
717 
718  return result;
719 }
720 
721 bool
723  const ncbi::CRef<CNodeCall> ref1, const ncbi::CRef<CNodeCall> ref2) const
724 {
725  // We don't check for NULL because they should never be NULL
726  // unless there is a programming bug.
727 
728  int var_comp = NStr::Compare( ref1->GetVarName(), ref2->GetVarName() );
729  if( var_comp != 0 ) {
730  return ( var_comp < 0 );
731  }
732 
733  return ( ref1->GetNode() < ref2->GetNode() );
734 }
735 
#define false
Definition: bool.h:36
bool IsEnumType(void) const
Definition: type.cpp:291
virtual AutoPtr< CTypeStrings > GetFullCType(void) const
Definition: type.cpp:872
string GetFullName(void) const
Definition: type.cpp:973
const CDataType * GetParentType(void) const
Definition: type.hpp:164
bool IsReference(void) const
Definition: type.cpp:938
const string & GetSourceFileName(void) const
Definition: type.cpp:434
bool IsContainer(void) const
Definition: type.cpp:286
bool IsStdType(void) const
Definition: type.cpp:908
virtual const CDataType * Resolve(void) const override
Definition: reftype.cpp:345
virtual bool Call(CTraversalNode &node, const TNodeVec &node_path, ECallType is_cyclic)=0
CUserCall(const std::string &user_func_name, const TNodeVec &extra_arg_nodes, const vector< string > &constant_args)
string x_ExtractIncludePathFromFileName(const string &asn_file_name)
void x_GenerateChildCall(CNcbiOstream &traversal_output_file, CRef< CTraversalNode > child, const string &arg)
std::string m_IncludePath
const string GetStoredArgVariable(void) const
void x_LoadDataFromASNNode(CDataType *asn_node)
static int ms_FuncUniquerInt
TNodeCallSet m_Callers
TUserCallVec m_PostCalleesUserCalls
CRef< CTraversalNode > x_CloneWithoutCallers(const string &var_name) const
const string & GetTypeAsString(void) const
void x_DepthFirst(CDepthFirstCallback &callback, TNodeVec &node_path, TNodeSet &nodesSeen, TTraversalOpts traversal_opts)
void SplitByVarName(void)
static void x_MergeNames(string &result, const string &name1, const string &name2)
TUserCallVec m_PreCalleesUserCalls
std::vector< CRef< CUserCall > > TUserCallVec
std::string m_FuncName
static CRef< CTraversalNode > Create(CRef< CTraversalNode > caller, const string &var_name, CDataType *asn_node)
const std::string & GetInputClassName(void) const
TUserCallVec m_ReferencingUserCalls
std::vector< CRef< CTraversalNode > > TNodeVec
std::string m_InputClassName
void RemoveXFromFuncName(void)
void GenerateCode(const string &func_class_name, CNcbiOstream &traversal_output_file, EGenerateMode generate_mode)
std::set< CRef< CNodeCall >, SRefNodeCallLessthan > TNodeCallSet
void x_TemplatizeType(std::string &type_name)
unsigned int TTraversalOpts
void AddPostCalleesUserCall(CRef< CUserCall > user_call)
void DepthFirst(CDepthFirstCallback &callback, TTraversalOpts traversal_opts=0)
CRef< CTraversalNode > Ref()
std::string m_TypeName
bool x_IsSeqFeat(void)
std::map< CDataType *, CRef< CTraversalNode > > TASNNodeToNodeMap
static TASNNodeToNodeMap m_ASNNodeToNodeMap
void AddPreCalleesUserCall(CRef< CUserCall > user_call)
static set< CTraversalNode * > * ms_EveryNode
std::set< CRef< CTraversalNode > > TNodeSet
void AddCaller(const std::string &var_name, CRef< CTraversalNode > caller)
TNodeCallSet m_Callees
bool Merge(CRef< CTraversalNode > node_to_merge_into_this, EMergeNameAllowed merge_name_allowed=eMergeNameAllowed_AllowNameChange)
virtual string GetCType(const CNamespace &ns) const =0
virtual const CNamespace & GetNamespace(void) const
Definition: typestr.cpp:76
Definition: map.hpp:338
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
void erase(iterator pos)
Definition: set.hpp:151
#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
string
Definition: cgiapp.hpp:687
TObjectType * GetPointerOrNull(void) THROWS_NONE
Get pointer value.
Definition: ncbiobj.hpp:986
#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::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define kEmptyStr
Definition: ncbistr.hpp:123
static SIZE_TYPE FindNoCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case insensitive search.
Definition: ncbistr.cpp:2989
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5429
#define NPOS
Definition: ncbistr.hpp:133
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5083
static SIZE_TYPE Find(const CTempString str, const CTempString pattern, ECase use_case=eCase, EDirection direction=eForwardSearch, SIZE_TYPE occurrence=0)
Find the pattern in the string.
Definition: ncbistr.cpp:2887
static string & Replace(const string &src, const string &search, const string &replace, string &dst, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3310
static int Compare(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2, ECase use_case=eCase)
Compare of a substring with another string.
Definition: ncbistr.hpp:5296
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5411
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3401
const char *const kEmptyCStr
Empty "C" string (points to a '\0').
Definition: ncbistr.cpp:68
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
double value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:228
int isalnum(Uchar c)
Definition: ncbictype.hpp:62
int toupper(Uchar c)
Definition: ncbictype.hpp:73
bool operator()(const char &ch)
bool operator()(const char &ch)
bool operator()(const CRef< CNodeCall > ref1, const CRef< CNodeCall > ref2) const
#define _ASSERT
static const char * kUnknown
else result
Definition: token2.c:20
Modified on Fri Dec 08 08:20:57 2023 by modify_doxy.py rev. 669887