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

Go to the SVN repository for this file.

1 /* $Id: enumtype.cpp 92634 2021-02-02 14:31:09Z 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: Eugene Vasilchenko
27 *
28 * File Description:
29 * Type description for enumerated types
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include "enumtype.hpp"
34 #include "blocktype.hpp"
35 #include "value.hpp"
36 #include "enumstr.hpp"
37 #include "module.hpp"
38 #include "srcutil.hpp"
40 #include "stdstr.hpp"
41 #include <common/ncbi_sanitizers.h>
42 
43 
45 
46 
48 {
49 }
50 
51 const char* CEnumDataType::GetASNKeyword(void) const
52 {
53  return "ENUMERATED";
54 }
55 
56 const char* CEnumDataType::GetDEFKeyword(void) const
57 {
58  return "_ENUMERATED_";
59 }
60 
62 {
63  string content("\n");
64  ITERATE ( TValues, i, m_Values ) {
65  if (i != m_Values.begin()) {
66  content += " |\n";
67  }
68  content += " " + i->GetName();
69  }
70  return content;
71 }
72 
73 bool CEnumDataType::IsInteger(void) const
74 {
75  return false;
76 }
77 
80 {
81  m_Values.push_back(TValue(valueName, value));
82  return m_Values.back();
83 }
84 
86 {
88  out << GetASNKeyword() << " {";
89  ++indent;
90  ITERATE ( TValues, i, m_Values ) {
93  bool last = ++next == m_Values.end();
94 
95  bool oneLineComment = i->GetComments().OneLine();
96  if ( !oneLineComment )
97  i->GetComments().PrintASN(out, indent);
98  out << CDataTypeModule::ToAsnId(i->GetName()) << " (" << i->GetValue() << ")";
99  if ( !last )
100  out << ',';
101  if ( oneLineComment ) {
102  out << ' ';
103  i->GetComments().PrintASN(out, indent, CComments::eOneLine);
104  }
105  }
106  --indent;
109  out << "}";
110 }
111 
113 {
114  ++indent;
115  ITERATE ( TValues, i, m_Values ) {
117  out << "V," << i->GetSourceLine() << ',';
118  out << GetFullName() << ':' << i->GetName() << ',' << i->GetValue();
119  i->GetComments().PrintASN(out, indent, CComments::eNoEOL);
120  }
121 }
122 
123 void CEnumDataType::PrintJSONSchema(CNcbiOstream& out, int indent, list<string>& required, bool) const
124 {
125  PrintASNNewLine(out, indent) << "\"type\": " << (IsInteger() ? "\"integer\"" : "\"string\"") << ',';
126  PrintASNNewLine(out, indent) << "\"enum\": [";
127 
128 #if 0
129  bool first = true;
130  ITERATE ( TValues, i, m_Values ) {
131  if (!first) {
132  out << ", ";
133  } else {
134  first = false;
135  }
136  if (IsInteger()) {
137  out << i->GetValue();
138  } else {
139  out << "\"" << i->GetName() << "\"";
140  }
141  }
142 #else
143  if (IsInteger()) {
144  copy( m_Values.begin(), m_Values.end(), Dt_ostream_iterator<TValue>(out, ", ",
145  [](ostream& ostm, const TValue& e) {
146  ostm << e.GetValue();
147  }));
148  } else {
149  copy( m_Values.begin(), m_Values.end(), Dt_ostream_iterator<TValue>(out, ", ",
150  [](ostream& ostm, const TValue& e) {
151  ostm << "\"" << e.GetName() << "\"";
152  }));
153  }
154 #endif
155 
156  const CDataMember* mem = GetDataMember();
157  if (mem && !mem->Optional()) {
158  required.push_back(mem->GetName());
159  }
160  out << ']';
161 }
162 
163 // XML schema generator submitted by
164 // Marc Dumontier, Blueprint initiative, dumontier@mshri.on.ca
165 // modified by Andrei Gourianov, gouriano@ncbi
166 void CEnumDataType::PrintXMLSchema(CNcbiOstream& out, int indent, bool /*contents_only*/) const
167 {
168  string tag(XmlTagName());
169  string use("required");
170  string value("value");
171  string form;
172  bool inAttlist= false;
173  bool isGlobalType = GetGlobalType() == CDataType::eType;
174  list<string> opentag, closetag;
175 
176  if (GetEnforcedStdXml() &&
177  GetParentType() &&
179  GetParentType()->GetDataMember()->Attlist()) {
180  const CDataMember* mem = GetDataMember();
181  inAttlist = true;
182  value = tag;
183  if (mem->Optional()) {
184  use = "optional";
185  if (mem->GetDefault()) {
186  use += "\" default=\"" + GetXmlValueName(mem->GetDefault()->GetXmlString());
187  }
188  } else {
189  use = "required";
190  }
191  if (IsNsQualified() == eNSQualified) {
192  form = " form=\"qualified\"";
193  }
194  }
195  if (!inAttlist && !isGlobalType) {
196  const CDataMember* mem = GetDataMember();
197  string tmp = "<xs:element name=\"" + tag + "\"";
198  if (mem && mem->Optional()) {
199  tmp += " minOccurs=\"0\"";
200  if (mem->GetDefault()) {
201  use = "optional";
202  }
203  }
204 #if _DATATOOL_USE_SCHEMA_STYLE_COMMENTS
206  if (!Comments().PrintSchemaComments(out, indent+1)) {
207  out << '>';
208  }
209  ++indent;
210 #else
211  opentag.push_back(tmp + ">");
212 #endif
213  closetag.push_front("</xs:element>");
214  if (IsASNDataSpec()) {
215  opentag.push_back("<xs:complexType>");
216  closetag.push_front("</xs:complexType>");
217  if(IsInteger()) {
218  opentag.push_back("<xs:simpleContent>");
219  closetag.push_front("</xs:simpleContent>");
220  opentag.push_back("<xs:extension base=\"xs:integer\">");
221  closetag.push_front("</xs:extension>");
222  use = "optional";
223  }
224  }
225  }
226  if (IsASNDataSpec()) {
227  string tmp = "<xs:attribute name=\"" + value + "\" use=\"" + use + "\"" + form;
228  const CDataMember* mem = GetDataMember();
229  if (!inAttlist) {
230  if (mem && mem->Optional() && mem->GetDefault()) {
231  tmp += " default=\"" + GetXmlValueName(mem->GetDefault()->GetXmlString()) + "\"";
232  }
233  }
234  opentag.push_back(tmp + ">");
235  closetag.push_front("</xs:attribute>");
236  }
237  if (isGlobalType) {
238  string tmp = "<xs:simpleType name=\"" + tag + "\">";
239  opentag.push_back(tmp);
240  } else {
241  opentag.push_back("<xs:simpleType>");
242  }
243  closetag.push_front("</xs:simpleType>");
244  if (IsASNDataSpec() || !IsInteger()) {
245  opentag.push_back("<xs:restriction base=\"xs:string\">");
246  } else {
247  opentag.push_back("<xs:restriction base=\"xs:integer\">");
248  }
249  closetag.push_front("</xs:restriction>");
250 
251  ITERATE ( list<string>, s, opentag ) {
252  PrintASNNewLine(out, indent++) << *s;
253  }
254  bool haveComments = false;
255  ITERATE ( TValues, i, m_Values ) {
256  if ( !i->GetComments().Empty() ) {
257  haveComments = true;
258  break;
259  }
260  }
261  if ( haveComments ) {
262 #if _DATATOOL_USE_SCHEMA_STYLE_COMMENTS
263  PrintASNNewLine(out, indent) << "<xs:annotation><xs:documentation>";
264  ITERATE ( TValues, i, m_Values ) {
265  if ( !i->GetComments().Empty() ) {
266  i->GetComments().Print(out, "\n "+i->GetName()+"\t- ",
267  "\n ", "");
268  }
269  }
270  PrintASNNewLine(out, indent) << "</xs:documentation></xs:annotation>";
271 #else
272  out << "\n<!--";
273  ITERATE ( TValues, i, m_Values ) {
274  if ( !i->GetComments().Empty() ) {
275  i->GetComments().Print(out, "\n "+i->GetName()+"\t- ",
276  "\n ", "");
277  }
278  }
279  out << "\n-->";
280 #endif
281  }
282  ITERATE ( TValues, i, m_Values ) {
283  PrintASNNewLine(out, indent) <<
284  "<xs:enumeration value=\"" << i->GetName() << "\"";
285  if (IsASNDataSpec() && IsInteger()) {
286  out << " ncbi:intvalue=\"" << i->GetValue() << "\"";
287  }
288  out << "/>";
289  }
290  ITERATE ( list<string>, s, closetag ) {
291  PrintASNNewLine(out, --indent) << *s;
292  }
293  m_LastComments.PrintDTD(out, CComments::eMultiline);
294 }
295 
296 void CEnumDataType::PrintDTDElement(CNcbiOstream& out, bool /*contents_only*/) const
297 {
298  string tag(XmlTagName());
299  string content(GetXMLContents());
300  if (GetParentType() &&
301  GetParentType()->GetDataMember() &&
302  GetParentType()->GetDataMember()->Attlist()) {
303  const CDataMember* mem = GetDataMember();
304  out << "\n " << tag << " (" << content << ") ";
305  if (mem->GetDefault()) {
306  out << "\"" << GetXmlValueName(mem->GetDefault()->GetXmlString()) << "\"";
307  } else {
308  if (mem->Optional()) {
309  out << "#IMPLIED";
310  } else {
311  out << "#REQUIRED";
312  }
313  }
314  } else {
315  out <<
316  "\n<!ELEMENT " << tag << " ";
317  if ( IsInteger() ) {
318  if (DTDEntitiesEnabled()) {
319  out << "(%INTEGER;)>";
320  } else {
321  out << "(#PCDATA)>";
322  }
323  } else {
324  if (DTDEntitiesEnabled()) {
325  out << "%ENUM;>";
326  } else {
327  out << "EMPTY>";
328  }
329  }
330  }
331 }
332 
333 void CEnumDataType::PrintDTDExtra(CNcbiOstream& out) const
334 {
335  bool haveComments = false;
336  ITERATE ( TValues, i, m_Values ) {
337  if ( !i->GetComments().Empty() ) {
338  haveComments = true;
339  break;
340  }
341  }
342  if ( haveComments ) {
343  out << "\n\n<!--\n";
344  ITERATE ( TValues, i, m_Values ) {
345  if ( !i->GetComments().Empty() ) {
346  i->GetComments().Print(out, " "+i->GetName()+"\t- ",
347  "\n ", "\n");
348  }
349  }
350  out << "-->";
351  }
352  out <<
353  "\n<!ATTLIST "<<XmlTagName()<<" value (\n";
354  ITERATE ( TValues, i, m_Values ) {
355  if ( i != m_Values.begin() )
356  out << " |\n";
357  out << " " << i->GetName();
358  }
359  out << "\n ) ";
360  if ( IsInteger() )
361  out << "#IMPLIED";
362  else
363  out << "#REQUIRED";
364  out << " >\n";
365  m_LastComments.PrintDTD(out, CComments::eMultiline);
366 }
367 
368 bool CEnumDataType::CheckValue(const CDataValue& value) const
369 {
370  const CIdDataValue* id = dynamic_cast<const CIdDataValue*>(&value);
371  if ( id ) {
372  ITERATE ( TValues, i, m_Values ) {
373  if ( i->GetName() == id->GetValue() )
374  return true;
375  }
376  value.Warning("illegal ENUMERATED value: " + id->GetValue(), 12);
377  return false;
378  }
379 
380  const CIntDataValue* intValue =
381  dynamic_cast<const CIntDataValue*>(&value);
382  if ( !intValue ) {
383  value.Warning("ENUMERATED or INTEGER value expected", 13);
384  return false;
385  }
386 
387  if ( !IsInteger() ) {
388  ITERATE ( TValues, i, m_Values ) {
389  if ( i->GetValue() == intValue->GetValue() )
390  return true;
391  }
392  value.Warning("illegal INTEGER value: " + NStr::NumericToString(intValue->GetValue()), 14);
393  return false;
394  }
395 
396  return true;
397 }
398 
399 TObjectPtr CEnumDataType::CreateDefault(const CDataValue& value) const
400 {
401  const CIdDataValue* id = dynamic_cast<const CIdDataValue*>(&value);
402  if ( id == 0 ) {
403  return new TEnumValueType((TEnumValueType)dynamic_cast<const CIntDataValue&>(value).GetValue());
404  }
405  ITERATE ( TValues, i, m_Values ) {
406  if ( i->GetName() == id->GetValue() )
407  return new TEnumValueType(i->GetValue());
408  }
409  value.Warning("illegal ENUMERATED value: " + id->GetValue(), 15);
410  return 0;
411 }
412 
413 string CEnumDataType::GetDefaultString(const CDataValue& value) const
414 {
415  CTypeStrings::EKind kind = GetFullCType()->GetKind();
416  const CIdDataValue* id = dynamic_cast<const CIdDataValue*>(&value);
417  if (kind == CTypeStrings::eKindEnum) {
418  if ( id ) {
419  return GetEnumCInfo().valuePrefix + Identifier(id->GetValue(), false);
420  }
421  else {
422  const CIntDataValue* intValue =
423  dynamic_cast<const CIntDataValue*>(&value);
424  return NStr::Int8ToString(intValue->GetValue());
425  }
426  }
427  string val;
428  if ( id ) {
429  val = id->GetValue();
430  }
431  else {
432  const CIntDataValue* intValue =
433  dynamic_cast<const CIntDataValue*>(&value);
434  val = NStr::Int8ToString(intValue->GetValue());
435  }
436  if (kind == CTypeStrings::eKindString) {
437  return string("\"") + val + "\"";
438  }
439  return val;
440 }
441 
442 string CEnumDataType::GetXmlValueName(const string& value) const
443 {
444  return value;
445 }
446 
447 CTypeInfo* CEnumDataType::CreateTypeInfo(void)
448 {
449  NCBI_LSAN_DISABLE_GUARD;
450  AutoPtr<CEnumeratedTypeValues>
451  info(new CEnumeratedTypeValues(GlobalName(), IsInteger()));
452  ITERATE ( TValues, i, m_Values ) {
453  info->AddValue(i->GetName(), i->GetValue());
454  }
455  if ( HaveModuleName() )
456  info->SetModuleName(GetModule()->GetName());
457  return new CEnumeratedTypeInfo(sizeof(TEnumValueType), info.release());
458 }
459 
460 string CEnumDataType::DefaultEnumName(void) const
461 {
462  // generate enum name from ASN type or field name
463  if ( !GetParentType() ) {
464  // root enum
465  return 'E' + Identifier(IdName());
466  }
467  else {
468  // internal enum
469  return 'E' + Identifier(GetKeyPrefix());
470  }
471 }
472 
473 CEnumDataType::SEnumCInfo CEnumDataType::GetEnumCInfo(void) const
474 {
475  string typeName = GetAndVerifyVar("_type");
476  string enumName;
477  if ( !typeName.empty() && typeName[0] == 'E' ) {
478  enumName = typeName;
479  }
480  else {
481  // make C++ type name
482  enumName = DefaultEnumName();
483  if ( typeName.empty() ) {
484  if ( IsInteger() )
485  typeName = "int";
486  else
487  typeName = enumName;
488  }
489  }
490  string prefix = GetVar("_prefix");
491  if ( prefix.empty() ) {
492  prefix = char(tolower((unsigned char) enumName[0])) + enumName.substr(1) + '_';
493  }
494  return SEnumCInfo(enumName, typeName, prefix);
495 }
496 
497 AutoPtr<CTypeStrings> CEnumDataType::GetRefCType(void) const
498 {
499  SEnumCInfo enumInfo = GetEnumCInfo();
500  return AutoPtr<CTypeStrings>(new CEnumRefTypeStrings(enumInfo.enumName,
501  enumInfo.cType,
502  Namespace(),
503  FileName(),
504  Comments()));
505 }
506 
507 AutoPtr<CTypeStrings> CEnumDataType::GetFullCType(void) const
508 {
509  ITERATE ( TValues, i, m_Values ) {
510  string id(Identifier( i->GetEnumId(), false ));
511  string value;
512  value = GetVar(id + "._hidename", false);
513  if (!value.empty()) {
514  if (NStr::StringToBool(value)) {
515  i->SetFlag(CEnumDataTypeValue::eHideName);
516  }
517  }
518  value = GetVar( id, false);
519  if (!value.empty()) {
520  i->SetEnumId(value);
521  }
522  }
523 // in case client wants std type instead of enum.
524 // I must be accurate here to not to mess with GetEnumCInfo()
525  string type = GetAndVerifyVar("_type");
526  if (!type.empty()) {
527  if (NStr::EndsWith(type, "string")) {
528  return AutoPtr<CTypeStrings>(
529  new CStringTypeStrings("NCBI_NS_STD::string",Comments(),true));
530  } else if (NStr::EndsWith(type, "CStringUTF8")) {
531  return AutoPtr<CTypeStrings>(
532  new CStringTypeStrings("NCBI_NS_NCBI::CStringUTF8",Comments(),true));
533  } else if (type == "double") {
534  return AutoPtr<CTypeStrings>(
535  new CStdTypeStrings(type,Comments(),true));
536  }
537  }
538 
539  SEnumCInfo enumInfo = GetEnumCInfo();
540  AutoPtr<CEnumTypeStrings>
541  e(new CEnumTypeStrings(GlobalName(), enumInfo.enumName,
542  GetVar("_packedtype"),
543  enumInfo.cType, IsInteger(),
544  m_Values, enumInfo.valuePrefix,
545  GetNamespaceName(), this, Comments()));
546 
547  string extra = GetVar("_type_extra");
548  if (NStr::CompareNocase(extra, "bitset") == 0) {
549  e->SetBitset(true);
550  }
551  return AutoPtr<CTypeStrings>(e.release());
552 }
553 
554 AutoPtr<CTypeStrings> CEnumDataType::GenerateCode(void) const
555 {
556  return GetFullCType();
557 }
558 
559 const char* CIntEnumDataType::GetASNKeyword(void) const
560 {
561  return "INTEGER";
562 }
563 
564 const char* CIntEnumDataType::GetDEFKeyword(void) const
565 {
566  return "_INTEGER_ENUM_";
567 }
568 
569 bool CIntEnumDataType::IsInteger(void) const
570 {
571  return true;
572 }
573 
574 string CIntEnumDataType::GetXmlValueName(const string& value) const
575 {
576  try {
577 // in case of named integers, value can be a name, not an integer
578  TEnumValueType d = (TEnumValueType)NStr::StringToInt(value);
579  ITERATE(TValues, v, GetValues()) {
580  if (v->GetValue() == d) {
581  return v->GetName();
582  }
583  }
584  } catch (...) {
585  }
586  return value;
587 }
588 
589 const char* CBigIntEnumDataType::GetASNKeyword(void) const
590 {
591  return "BigInt";
592 }
593 
594 const char* CBigIntEnumDataType::GetDEFKeyword(void) const
595 {
596  return "_BigInt_ENUM_";
597 }
598 
599 END_NCBI_SCOPE
@ eMultiline
Definition: comments.hpp:57
CNcbiOstream & PrintASN(CNcbiOstream &out, int indent, int flags=0) const
Definition: comments.cpp:156
bool Optional(void) const
Definition: blocktype.hpp:68
const string & GetName(void) const
Definition: blocktype.hpp:56
const CDataValue * GetDefault(void) const
Definition: blocktype.hpp:88
static string ToAsnId(const string &name)
Definition: module.cpp:673
EGlobalType GetGlobalType(void) const
Definition: type.hpp:431
const CDataMember * GetDataMember(void) const
Definition: type.hpp:307
CNcbiOstream & PrintASNTag(CNcbiOstream &out) const
Definition: type.cpp:123
CComments & Comments(void)
Definition: type.hpp:294
@ eType
Definition: type.hpp:425
string GetFullName(void) const
Definition: type.cpp:973
const CDataType * GetParentType(void) const
Definition: type.hpp:164
static bool GetEnforcedStdXml(void)
Definition: type.hpp:376
ENsQualifiedMode IsNsQualified(void) const
Definition: type.hpp:411
string XmlTagName(void) const
Definition: type.cpp:462
virtual string GetXmlString(void) const =0
virtual string GetXmlValueName(const string &value) const
Definition: enumtype.cpp:442
virtual void PrintASN(CNcbiOstream &out, int indent) const override
Definition: enumtype.cpp:85
CEnumDataTypeValue TValue
Definition: enumtype.hpp:107
virtual const char * GetDEFKeyword(void) const override
Definition: enumtype.cpp:56
virtual void PrintXMLSchema(CNcbiOstream &out, int indent, bool contents_only=false) const override
Definition: enumtype.cpp:166
TValue & AddValue(const string &name, TEnumValueType value)
Definition: enumtype.cpp:78
list< TValue > TValues
Definition: enumtype.hpp:108
virtual string GetXMLContents(void) const
Definition: enumtype.cpp:61
virtual void PrintJSONSchema(CNcbiOstream &out, int indent, list< string > &required, bool contents_only=false) const override
Definition: enumtype.cpp:123
CEnumDataType(void)
Definition: enumtype.cpp:47
virtual void PrintSpecDumpExtra(CNcbiOstream &out, int indent) const override
Definition: enumtype.cpp:112
TValues m_Values
Definition: enumtype.hpp:162
virtual const char * GetASNKeyword(void) const override
Definition: enumtype.cpp:51
CComments m_LastComments
Definition: enumtype.hpp:163
virtual bool IsInteger(void) const
Definition: enumtype.cpp:73
#define _(proto)
Definition: ct_nlmzip_i.h:78
std::ofstream out("events_result.xml")
main entry point for tests
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
static char tmp[3200]
Definition: utf8.c:42
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
int TEnumValueType
Definition: serialdef.hpp:232
@ eNSQualified
Definition: serialdef.hpp:201
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
int i
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
Common macro to detect used sanitizers and suppress memory leaks if run under LeakSanitizer.
const char * tag
const double E
void copy(Njn::Matrix< S > *matrix_, const Njn::Matrix< T > &matrix0_)
Definition: njn_matrix.hpp:613
string indent(" ")
CNcbiOstream & PrintASNNewLine(CNcbiOstream &out, int indent)
Definition: srcutil.cpp:130
Modified on Fri Apr 12 17:21:31 2024 by modify_doxy.py rev. 669887