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

Go to the SVN repository for this file.

1 /* $Id: Comment_rule.cpp 96878 2022-05-20 15:00:53Z ludwigf $
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: .......
27  *
28  * File Description:
29  * .......
30  *
31  * Remark:
32  * This code was originally generated by application DATATOOL
33  * using the following specifications:
34  * 'valid.asn'.
35  */
36 
37 // standard includes
38 #include <ncbi_pch.hpp>
39 
40 #include <util/static_set.hpp>
41 
43 
44 // generated includes
52 // generated classes
53 
55 
56 BEGIN_objects_SCOPE // namespace ncbi::objects::
57 
58 // destructor
60 {
61 }
62 
63 
65 {
66  if (!NStr::IsBlank(prefix)) {
67  while (NStr::StartsWith(prefix, "#")) {
68  prefix = prefix.substr(1);
69  }
70  while (NStr::EndsWith(prefix, "#")) {
71  prefix = prefix.substr(0, prefix.length() - 1);
72  }
73  if (NStr::EndsWith(prefix, "-START", NStr::eNocase)) {
74  prefix = prefix.substr(0, prefix.length() - 6);
75  } else if (NStr::EndsWith(prefix, "-END", NStr::eNocase)) {
76  prefix = prefix.substr(0, prefix.length() - 4);
77  }
78  }
79 }
80 
81 
82 static const char* kStructuredComment = "StructuredComment";
83 static const char* kStructuredCommentPrefix = "StructuredCommentPrefix";
84 static const char* kStructuredCommentSuffix = "StructuredCommentSuffix";
85 
87 {
88  if (user.IsSetType()
89  && user.GetType().IsStr()
91  return true;
92  } else {
93  return false;
94  }
95 }
96 
97 
98 string CComment_rule::GetStructuredCommentPrefix (const CUser_object& user, bool normalize)
99 {
100  if (!IsStructuredComment(user) || !user.IsSetData()) {
101  return "";
102  }
103  string prefix = "";
104  ITERATE(CUser_object::TData, it, user.GetData()) {
105  if ((*it)->IsSetData() && (*it)->GetData().IsStr()
106  && (*it)->IsSetLabel() && (*it)->GetLabel().IsStr()
107  && (NStr::Equal((*it)->GetLabel().GetStr(), kStructuredCommentPrefix)
108  || NStr::Equal((*it)->GetLabel().GetStr(), kStructuredCommentSuffix))) {
109  prefix = (*it)->GetData().GetStr();
110  break;
111  }
112  }
113  if (normalize) {
115  }
116  return prefix;
117 }
118 
119 
120 string CComment_rule::MakePrefixFromRoot(const string& root)
121 {
122  string prefix = root;
124  prefix = "##" + prefix + "-START##";
125  return prefix;
126 }
127 
128 
129 string CComment_rule::MakeSuffixFromRoot(const string& root)
130 {
131  string suffix = root;
133  suffix = "##" + suffix + "-END##";
134  return suffix;
135 }
136 
137 
139 
141  {"GSC:MIGS:2.1", "MIGS-Data"},
142  {"GSC:MIMS:2.1", "MIMS-Data"},
143  {"GSC:MIENS:2.1", "MIENS-Data"},
144  {"GSC:MIxS;MIGS:3.0", "MIGS:3.0-Data"},
145  {"GSC:MIxS;MIMS:3.0", "MIMS:3.0-Data"},
146  {"GSC:MIxS;MIMARKS:3.0", "MIMARKS:3.0-Data"} };
147 
149 
151 {
152  size_t i;
153  string compare = prefix;
155 
156  for (i = 0; i < k_NumStructuredCommentKeywords; i++) {
157  if (NStr::Equal(compare.c_str(), s_StructuredCommentKeywords[i].second)) {
159  }
160  }
161  return "";
162 }
163 
164 
165 string CComment_rule::PrefixForKeyword(const string& keyword)
166 {
167  size_t i;
168 
169  for (i = 0; i < k_NumStructuredCommentKeywords; i++) {
170  if (NStr::Equal(keyword.c_str(), s_StructuredCommentKeywords[i].first)) {
172  }
173  }
174  return "";
175 }
176 
177 
179 {
180  vector<string> keywords;
181 
182  size_t i;
183 
184  for (i = 0; i < k_NumStructuredCommentKeywords; i++) {
185  keywords.push_back(s_StructuredCommentKeywords[i].first);
186  }
187  return keywords;
188 }
189 
190 
192 {
194  CConstRef<CField_rule> p_field_rule = *it;
195  if (NStr::Equal(p_field_rule->GetField_name(), field_name)) {
196  return p_field_rule;
197  }
198  }
199  return CConstRef<CField_rule>();
200 }
201 
202 
204 {
205  if (NStr::IsBlank(label)) {
206  errors.push_back(TError(eSeverity_level_error,
207  "Structured Comment contains field without label"));
208  }
209 
210  if (NStr::Find(label, "::") != string::npos) {
211  errors.push_back(TError(eSeverity_level_reject, "Structured comment field '" + label + "' contains double colons"));
212  }
213 }
214 
215 
217 {
218  if (NStr::Find(value, "::") != string::npos) {
219  errors.push_back(TError(eSeverity_level_reject, "Structured comment value '" + value + "' contains double colons"));
220  }
221 }
222 
223 
225 {
226  string label = "";
227 
228  if (field.IsSetLabel()) {
229  if (field.GetLabel().IsStr()) {
230  label = field.GetLabel().GetStr();
231  } else {
232  label = NStr::IntToString(field.GetLabel().GetId());
233  }
234  }
235  CheckGeneralFieldName(label, errors);
236 
237  string value = "";
238  if (field.GetData().IsStr()) {
239  value = (field.GetData().GetStr());
240  } else if (field.GetData().IsInt()) {
241  value = NStr::IntToString(field.GetData().GetInt());
242  }
243  CheckGeneralFieldValue(value, errors);
244 }
245 
246 
247 void CComment_rule::CheckFieldValue(CConstRef<CField_rule> field_rule, const string& value, TErrorList& errors) const
248 {
249  if (field_rule) {
250  if (!field_rule->DoesStringMatchRuleExpression(value)) {
251  // post error about not matching format
252  CField_rule::TSeverity sev = field_rule->GetSeverity();
253  if (NStr::EqualNocase(field_rule->GetField_name(), "Finishing Goal")
254  && NStr::EqualNocase(GetPrefix(), "##Genome-Assembly-Data-START##")) {
255  sev = eSeverity_level_error;
256  } else if (NStr::EqualNocase(field_rule->GetField_name(), "Current Finishing Status")
257  && NStr::EqualNocase(GetPrefix(), "##Genome-Assembly-Data-START##")) {
258  sev = eSeverity_level_error;
259  }
260  errors.push_back(TError(sev, value + " is not a valid value for " + field_rule->GetField_name()));
261  }
262  }
263  if (IsSetForbidden_phrases()) {
265  if (NStr::FindNoCase(value, *it) != string::npos) {
266  errors.push_back(TError(eSeverity_level_error, "'" + value + "' is inappropriate for a GenBank submisison"));
267  }
268  }
269  }
270  CheckGeneralFieldValue(value, errors);
271 }
272 
273 
275 {
276  string value = "";
277  if (field.GetData().IsStr()) {
278  value = (field.GetData().GetStr());
279  } else if (field.GetData().IsInt()) {
280  value = NStr::IntToString(field.GetData().GetInt());
281  }
282  CheckFieldValue(rule, value, errors);
283 }
284 
285 
287 {
288  TErrorList errors;
289 
290  CField_set::Tdata::const_iterator field_rule = GetFields().Get().begin();
291  CUser_object::TData::const_iterator field = user.GetData().begin();
292  while (field_rule != GetFields().Get().end()
293  && field != user.GetData().end()) {
294  string encountered_field = kEmptyStr;
295  if ((*field)->IsSetLabel()) {
296  if ((*field)->GetLabel().IsStr()) {
297  encountered_field = (*field)->GetLabel().GetStr();
298  } else {
299  encountered_field = NStr::IntToString((*field)->GetLabel().GetId());
300  }
301  }
302  // skip suffix and prefix
303  if (NStr::Equal(encountered_field, "StructuredCommentPrefix")
304  || NStr::Equal(encountered_field, "StructuredCommentSuffix")) {
305  ++field;
306  continue;
307  } else if (NStr::IsBlank(encountered_field)) {
308  CheckGeneralField(**field, errors);
309  ++field;
310  }
311 
312  const string & expected_field = (*field_rule)->GetField_name();
313  if (NStr::Equal(expected_field, encountered_field)) {
314  // field in correct order
315  // is value correct?
316  CheckFieldValue(*field_rule, **field, errors);
317  ++field;
318  ++field_rule;
319  } else {
320  // find field for this rule and validate it
321  CConstRef<CUser_field> p_other_field = user.GetFieldRef(expected_field);
322  if( ! p_other_field ) {
323  if ((*field_rule)->IsSetRequired() && (*field_rule)->GetRequired()) {
324  errors.push_back(TError((*field_rule)->GetSeverity(),
325  "Required field " + (*field_rule)->GetField_name() + " is missing"));
326  }
327  } else {
328  const CUser_field& other_field = *p_other_field;
329  if (GetRequire_order()) {
330  errors.push_back(TError((*field_rule)->GetSeverity(),
331  expected_field + " field is out of order"));
332  }
333  CheckFieldValue(*field_rule, other_field, errors);
334 
335  }
336  ++field_rule;
337 
338  // find rule for this field
339  CConstRef<CField_rule> real_field_rule = FindFieldRuleRef(encountered_field);
340  if (!real_field_rule) {
341  if (!GetAllow_unlisted()) {
342  // field not found, not legitimate field name
343  errors.push_back(TError(eSeverity_level_error,
344  encountered_field + " is not a valid field name"));
345  }
346  CheckGeneralField(**field, errors);
347  ++field;
348  }
349  }
350  }
351 
352  while (field_rule != GetFields().Get().end()) {
353  if ((*field_rule)->IsSetRequired() && (*field_rule)->GetRequired()) {
354  errors.push_back(TError((*field_rule)->GetSeverity(),
355  "Required field " + (*field_rule)->GetField_name() + " is missing"));
356  }
357  ++field_rule;
358  }
359 
360  while (field != user.GetData().end()) {
361  // skip suffix and prefix
362  if ((*field)->IsSetLabel()) {
363  string label = "";
364  if ((*field)->GetLabel().IsStr()) {
365  label = (*field)->GetLabel().GetStr();
366  } else {
367  label = NStr::IntToString((*field)->GetLabel().GetId());
368  }
369  if (NStr::Equal(label, "StructuredCommentPrefix")
370  || NStr::Equal(label, "StructuredCommentSuffix")) {
371  ++field;
372  continue;
373  }
374 
376  CConstRef<CUser_field> p_other_field;
377  if( p_field_rule ) {
378  p_other_field = user.GetFieldRef(label);
379  }
380  if( p_field_rule && p_other_field ) {
381  if (p_other_field.GetPointer() != (*field)) {
382  errors.push_back(TError(p_field_rule->GetSeverity(),
383  "Multiple values for " + label + " field"));
384  }
385  } else {
386  if (!GetAllow_unlisted()) {
387  // field not found, not legitimate field name
388  errors.push_back(TError(eSeverity_level_error,
389  label + " is not a valid field name"));
390  }
391  CheckGeneralField(**field, errors);
392  }
393  } else {
394  CheckGeneralField(**field, errors);
395  }
396  ++field;
397  }
398 
399  // now look at dependent rules
400  if (IsSetDependent_rules()) {
402  if( ! (*depend_rule)->IsSetMatch_name() ) {
403  continue;
404  }
405  const string & depend_field_name = (*depend_rule)->GetMatch_name();
406  CConstRef<CUser_field> p_depend_field = user.GetFieldRef(depend_field_name);
407  if( ! p_depend_field ) {
408  continue;
409  }
410  string value = "";
411  if (p_depend_field->GetData().IsStr()) {
412  value = (p_depend_field->GetData().GetStr());
413  } else if (p_depend_field->GetData().IsInt()) {
414  value = NStr::IntToString(p_depend_field->GetData().GetInt());
415  }
416 
417  bool is_invert_match = (*depend_rule)->IsSetInvert_match() && (*depend_rule)->GetInvert_match();
418  bool does_match_rule_expression = (*depend_rule)->DoesStringMatchRuleExpression(value);
419  if ( is_invert_match != does_match_rule_expression) {
420  // other rules apply
421  if ((*depend_rule)->IsSetOther_fields()) {
422  ITERATE (CField_set::Tdata, other_rule, (*depend_rule)->GetOther_fields().Get()) {
423 
424  const string & other_field_name = (*other_rule)->GetField_name();
425  CConstRef<CUser_field> p_other_field = user.GetFieldRef(other_field_name);
426  if( ! p_other_field ) {
427  // unable to find field
428  if ((*other_rule)->IsSetRequired() && (*other_rule)->GetRequired()) {
429  errors.push_back(TError((*other_rule)->GetSeverity(),
430  "Required field " + (*other_rule)->GetField_name() + " is missing when "
431  + depend_field_name + " has value '" + value + "'"));
432  }
433  continue;
434  }
435 
436  string other_value = "";
437  if (p_other_field->GetData().IsStr()) {
438  other_value = (p_other_field->GetData().GetStr());
439  } else if (p_other_field->GetData().IsInt()) {
440  other_value = NStr::IntToString(p_other_field->GetData().GetInt());
441  }
442  if (!(*other_rule)->DoesStringMatchRuleExpression(other_value)) {
443  // post error about not matching format
444  errors.push_back(TError((*other_rule)->GetSeverity(),
445  other_value + " is not a valid value for " + other_field_name
446  + " when " + depend_field_name + " has value '" + value + "'"));
447  }
448  }
449  }
450  if ((*depend_rule)->IsSetDisallowed_fields()) {
451  ITERATE (CField_set::Tdata, other_rule, (*depend_rule)->GetDisallowed_fields().Get()) {
452  if( (*other_rule)->IsSetField_name() ) {
453  const string & other_field_name = (*other_rule)->GetField_name();
454  // found field that should not be present
455  errors.push_back(TError((*other_rule)->GetSeverity(),
456  other_field_name + " is not a valid field name when " + depend_field_name + " has value '" + value + "'"));
457  }
458  }
459  }
460  }
461  }
462  }
463 
464  return errors;
465 }
466 
467 
469 {
470  if (!IsSetFields() || !user.IsSetData()) {
471  return false;
472  }
473  bool any_change = false;
474  CField_set::Tdata::const_iterator field_rule = GetFields().Get().begin();
475  CUser_object::TData::iterator unchecked_fields = user.SetData().begin();
476  while (field_rule != GetFields().Get().end() && unchecked_fields != user.SetData().end()) {
477  CUser_object::TData::iterator field = unchecked_fields;
478  while (field != user.SetData().end()) {
479  if ((*field)->IsSetLabel()
480  && (*field)->GetLabel().IsStr()) {
481  string label = (*field)->GetLabel().GetStr();
483  // push to beginning if not already there
484  if (field == user.SetData().begin()) {
485  // already in position, just increment
486  ++unchecked_fields;
487  ++field;
488  } else {
489  CRef<CUser_field> new_field(new CUser_field());
490  new_field->Assign(**field);
491  user.SetData().erase(field);
492  user.SetData().insert(user.SetData().begin(), new_field);
493  unchecked_fields = user.SetData().begin();
494  unchecked_fields++;
495  field = unchecked_fields;
496  field_rule = GetFields().Get().begin();
497  any_change = true;
498  }
500  // TODO: move to end if not already there
501  // for now just skip
502  if (*field == user.SetData().back()) {
503  // already at the end, just skip
504  ++field;
505  } else {
506  CRef<CUser_field> new_field(new CUser_field());
507  new_field->Assign(**field);
508  user.SetData().erase(field);
509  user.SetData().push_back(new_field);
510  unchecked_fields = user.SetData().begin();
511  field = unchecked_fields;
512  field_rule = GetFields().Get().begin();
513  any_change = true;
514  }
515  } else if (NStr::Equal(label, (*field_rule)->GetField_name())) {
516  if (field == unchecked_fields) {
517  // already in position, just increment
518  ++unchecked_fields;
519  ++field;
520  } else {
521  CRef<CUser_field> new_field(new CUser_field());
522  new_field->Assign(**field);
523  user.SetData().erase(field);
524  user.SetData().insert(unchecked_fields, new_field);
525  unchecked_fields = user.SetData().begin();
526  field = unchecked_fields;
527  field_rule = GetFields().Get().begin();
528  any_change = true;
529  }
530  } else {
531  ++field;
532  }
533  } else {
534  ++field;
535  }
536  }
537  ++field_rule;
538  }
539  return any_change;
540 }
541 
542 
544 {
545  TErrorList errors;
546 
547  if (!user.IsSetData()) {
548  return errors;
549  }
550 
551  ITERATE(CUser_object::TData, it, user.GetData()) {
552  CheckGeneralField(**it, errors);
553  }
554  return errors;
555 }
556 
557 
558 END_objects_SCOPE // namespace ncbi::objects::
559 
561 
562 /* Original file checksum: lines: 57, chars: 1729, CRC32: 46a495ac */
const TKeywordPrefix s_StructuredCommentKeywords[]
static const char * kStructuredCommentPrefix
static const char * kStructuredCommentSuffix
static const char * kStructuredComment
SStaticPair< const char *, const char * > TKeywordPrefix
static size_t k_NumStructuredCommentKeywords
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
static void CheckGeneralFieldValue(const string &value, TErrorList &errors)
static TErrorList CheckGeneralStructuredComment(const CUser_object &user)
static void CheckGeneralFieldName(const string &label, TErrorList &errors)
vector< TError > TErrorList
~CComment_rule(void)
static string KeywordForPrefix(const string &prefix)
static string MakeSuffixFromRoot(const string &root)
static string MakePrefixFromRoot(const string &root)
static vector< string > GetKeywordList()
pair< CField_rule::TSeverity, string > TError
void CheckFieldValue(CConstRef< CField_rule > field_rule, const string &value, TErrorList &errors) const
TErrorList IsValid(const CUser_object &user) const
static string PrefixForKeyword(const string &keyword)
bool ReorderFields(CUser_object &user) const
static void NormalizePrefix(string &prefix)
static string GetStructuredCommentPrefix(const CUser_object &user, bool normalize=true)
static bool IsStructuredComment(const CUser_object &user)
CConstRef< CField_rule > FindFieldRuleRef(const string &field_name) const
static void CheckGeneralField(const CUser_field &field, TErrorList &errors)
CConstRef –.
Definition: ncbiobj.hpp:1266
CConstRef< CUser_field > GetFieldRef(const string &str, const string &delim=".", NStr::ECase use_case=NStr::eCase) const
Definition: User_object.cpp:84
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
virtual void Assign(const CSerialObject &source, ESerialRecursionMode how=eRecursive)
Set object to copy of another one.
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
#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:2993
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:5430
static bool IsBlank(const CTempString str, SIZE_TYPE pos=0)
Check if a string is blank (has no text).
Definition: ncbistr.cpp:106
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
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:2891
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:5412
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5353
static bool Equal(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2, ECase use_case=eCase)
Test for equality of a substring with another string.
Definition: ncbistr.hpp:5384
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
static const char label[]
const TStr & GetStr(void) const
Get the variant data.
bool IsSetData(void) const
the object itself Check if a value has been assigned to Data data member.
bool IsStr(void) const
Check if variant Str is selected.
Definition: Object_id_.hpp:291
bool IsSetType(void) const
type of object within class Check if a value has been assigned to Type data member.
const TData & GetData(void) const
Get the Data member data.
bool IsInt(void) const
Check if variant Int is selected.
bool IsStr(void) const
Check if variant Str is selected.
bool IsSetLabel(void) const
field label Check if a value has been assigned to Label data member.
TData & SetData(void)
Assign a value to Data data member.
const TStr & GetStr(void) const
Get the variant data.
Definition: Object_id_.hpp:297
TInt GetInt(void) const
Get the variant data.
const TData & GetData(void) const
Get the Data member data.
const TLabel & GetLabel(void) const
Get the Label member data.
const TType & GetType(void) const
Get the Type member data.
vector< CRef< CUser_field > > TData
TId GetId(void) const
Get the variant data.
Definition: Object_id_.hpp:270
const TPrefix & GetPrefix(void) const
Get the Prefix member data.
list< string > Tdata
const TDependent_rules & GetDependent_rules(void) const
Get the Dependent_rules member data.
list< CRef< CField_rule > > Tdata
Definition: Field_set_.hpp:89
const TFields & GetFields(void) const
Get the Fields member data.
TRequire_order GetRequire_order(void) const
Get the Require_order member data.
list< CRef< CDependent_field_rule > > Tdata
const TForbidden_phrases & GetForbidden_phrases(void) const
Get the Forbidden_phrases member data.
bool IsSetDependent_rules(void) const
Check if a value has been assigned to Dependent_rules data member.
const Tdata & Get(void) const
Get the member data.
Definition: Field_set_.hpp:164
bool IsSetForbidden_phrases(void) const
Check if a value has been assigned to Forbidden_phrases data member.
ESeverity_level
Access to ESeverity_level's attributes (values, names) as defined in spec.
TAllow_unlisted GetAllow_unlisted(void) const
Get the Allow_unlisted member data.
bool IsSetFields(void) const
Check if a value has been assigned to Fields data member.
@ eSeverity_level_error
@ eSeverity_level_reject
int i
const TYPE & Get(const CNamedParameterList *param)
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
static const char * suffix[]
Definition: pcregrep.c:408
static const char * prefix[]
Definition: pcregrep.c:405
Generic utility macros and templates for exploring NCBI objects.
Template structure SStaticPair is simlified replacement of STL pair<> Main reason of introducing this...
Definition: static_set.hpp:60
first_type first
Definition: static_set.hpp:64
second_type second
Definition: static_set.hpp:65
Modified on Wed Apr 17 13:08:49 2024 by modify_doxy.py rev. 669887