1 /* $Id: User_field.cpp 592620 2019-09-05 00:19:23Z kans $
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 specifications from the data definition file
34  *   'general.asn'.
35  */
36 
37 // standard includes
38 
39 // generated includes
40 #include <ncbi_pch.hpp>
41 #include <objects/general/User_field.hpp>
42 #include <objects/general/User_object.hpp>
43 #include <objects/misc/sequence_util_macros.hpp>
44 
45 // generated classes
46 
47 BEGIN_NCBI_SCOPE
48 
49 BEGIN_objects_SCOPE // namespace ncbi::objects::
50 
51 // destructor
~CUser_field(void)52 CUser_field::~CUser_field(void)
53 {
54 }
55 
56 
57 /// add fields to the current user field
AddField(const string & label,const string & value,EParseField parse)58 CUser_field& CUser_field::AddField(const string& label,
59                                    const string& value,
60                                    EParseField parse)
61 {
62     CRef<CUser_field> field(new CUser_field());
63     field->SetLabel().SetStr(label);
64     field->SetValue(value, parse);
65     SetData().SetFields().push_back(field);
66     return *this;
67 }
68 
69 
AddField(const string & label,const string & value)70 CUser_field& CUser_field::AddField(const string& label,
71                                    const string& value)
72 {
73     return AddField(label, value, eParse_String);
74 }
75 
76 
AddField(const string & label,const char * value)77 CUser_field& CUser_field::AddField(const string& label,
78                                    const char* value)
79 {
80     return AddField(label, string(value), eParse_String);
81 }
82 
83 
AddField(const string & label,const char * value,EParseField parse)84 CUser_field& CUser_field::AddField(const string& label,
85                                    const char* value,
86                                    EParseField parse)
87 {
88     return AddField(label, string(value), parse);
89 }
90 
91 
AddField(const string & label,int value)92 CUser_field& CUser_field::AddField(const string& label, int value)
93 {
94     CRef<CUser_field> field(new CUser_field());
95     field->SetLabel().SetStr(label);
96     field->SetValue(value);
97     SetData().SetFields().push_back(field);
98     return *this;
99 }
100 
101 
AddField(const string & label,Int8 value)102 CUser_field& CUser_field::AddField(const string& label, Int8 value)
103 {
104     CRef<CUser_field> field(new CUser_field());
105     field->SetLabel().SetStr(label);
106     field->SetValue(value);
107     SetData().SetFields().push_back(field);
108     return *this;
109 }
110 
111 
112 #ifdef NCBI_STRICT_GI
AddField(const string & label,TGi value)113 CUser_field& CUser_field::AddField(const string& label, TGi value)
114 {
115     CRef<CUser_field> field(new CUser_field());
116     field->SetLabel().SetStr(label);
117     field->SetValue(value);
118     SetData().SetFields().push_back(field);
119     return *this;
120 }
121 #endif
122 
123 
AddField(const string & label,double value)124 CUser_field& CUser_field::AddField(const string& label, double value)
125 {
126     CRef<CUser_field> field(new CUser_field());
127     field->SetLabel().SetStr(label);
128     field->SetValue(value);
129     SetData().SetFields().push_back(field);
130     return *this;
131 }
132 
133 
AddField(const string & label,bool value)134 CUser_field& CUser_field::AddField(const string& label, bool value)
135 {
136     CRef<CUser_field> field(new CUser_field());
137     field->SetLabel().SetStr(label);
138     field->SetValue(value);
139     SetData().SetFields().push_back(field);
140     return *this;
141 }
142 
AddField(const string & label,const CUser_field_Base::TData::TStrs & value)143 CUser_field& CUser_field::AddField(const string& label,
144                                    const CUser_field_Base::TData::TStrs& value)
145 {
146     CRef<CUser_field> field(new CUser_field());
147     field->SetLabel().SetStr(label);
148     field->SetValue(value);
149     SetData().SetFields().push_back(field);
150     return *this;
151 }
152 
AddField(const string & label,const vector<int> & value)153 CUser_field& CUser_field::AddField(const string& label,
154                                    const vector<int>& value)
155 {
156     CRef<CUser_field> field(new CUser_field());
157     field->SetLabel().SetStr(label);
158     field->SetValue(value);
159     SetData().SetFields().push_back(field);
160     return *this;
161 }
162 
163 
AddField(const string & label,const vector<double> & value)164 CUser_field& CUser_field::AddField(const string& label,
165                                    const vector<double>& value)
166 {
167     CRef<CUser_field> field(new CUser_field());
168     field->SetLabel().SetStr(label);
169     field->SetValue(value);
170     SetData().SetFields().push_back(field);
171     return *this;
172 }
173 
174 
AddField(const string & label,CUser_object & value)175 CUser_field& CUser_field::AddField(const string& label,
176                                    CUser_object& value)
177 {
178     CRef<CUser_field> field(new CUser_field());
179     field->SetLabel().SetStr(label);
180     field->SetValue(value);
181     SetData().SetFields().push_back(field);
182     return *this;
183 }
184 
185 
AddField(const string & label,const vector<CRef<CUser_object>> & value)186 CUser_field& CUser_field::AddField(const string& label,
187                                    const vector< CRef<CUser_object> >& value)
188 {
189     CRef<CUser_field> field(new CUser_field());
190     field->SetLabel().SetStr(label);
191     field->SetValue(value);
192     SetData().SetFields().push_back(field);
193     return *this;
194 }
195 
196 
AddField(const string & label,const vector<CRef<CUser_field>> & value)197 CUser_field& CUser_field::AddField(const string& label,
198                                    const vector< CRef<CUser_field> >& value)
199 {
200     CRef<CUser_field> field(new CUser_field());
201     field->SetLabel().SetStr(label);
202     field->SetValue(value);
203     SetData().SetFields().push_back(field);
204     return *this;
205 }
206 
207 
208 /// Access a named field in this user field.  This will tokenize the
209 /// string 'str' on the delimiters; if the field doesn't exist, an
210 /// exception will be thrown.
GetField(const string & str,const string & delim,NStr::ECase use_case) const211 const CUser_field& CUser_field::GetField(const string& str,
212                                          const string& delim,
213                                          NStr::ECase use_case) const
214 {
215     CConstRef<CUser_field> f = GetFieldRef(str, delim, use_case);
216     if ( !f ) {
217         NCBI_THROW(CException, eUnknown,
218                    "failed to find field named " + str);
219     }
220     return *f;
221 }
222 
223 
224 /// Return a field reference representing the tokenized key, or a
225 /// NULL reference if the key doesn't exist.
GetFieldRef(const string & str,const string & delim,NStr::ECase use_case) const226 CConstRef<CUser_field> CUser_field::GetFieldRef(const string& str,
227                                                 const string& delim,
228                                                 NStr::ECase use_case) const
229 {
230     list<string> toks;
231     NStr::Split(str, delim, toks, NStr::fSplit_Tokenize);
232 
233     CConstRef<CUser_field> f(this);
234     if ( !f->GetData().IsFields() ) {
235         if (toks.size() == 1  &&
236             f->GetLabel().IsStr()  &&
237             NStr::Equal(f->GetLabel().GetStr(), toks.front(), use_case))
238         {
239             return f;
240         } else {
241             return CConstRef<CUser_field>();
242         }
243     }
244 
245     if (toks.size()) {
246         list<string>::const_iterator last = toks.end();
247         --last;
248 
249         ITERATE (list<string>, iter, toks) {
250             CConstRef<CUser_field> new_f;
251 
252             ITERATE (TData::TFields, field_iter, f->GetData().GetFields()) {
253                 const CUser_field& field = **field_iter;
254                 if (field.GetLabel().IsStr()) {
255                     if (NStr::Equal(field.GetLabel().GetStr(), *iter, use_case) ) {
256                         if (iter == last  || field.GetData().IsFields()) {
257                             new_f = *field_iter;
258                             break;
259                         }
260                     }
261                 } else if (field.GetLabel().IsId()) {
262                     if (field.GetLabel().GetId() == NStr::StringToInt(*iter)) {
263                         if (iter == last  || field.GetData().IsFields()) {
264                             new_f = *field_iter;
265                             break;
266                         }
267                     }
268                 }
269             }
270 
271             f = new_f;
272             if ( !f ) {
273                 return f;
274             }
275         }
276     }
277 
278     return f;
279 }
280 
Join(ostream & out_name_strm,const string & delim) const281 void CUser_field::SFieldNameChain::Join(
282     ostream & out_name_strm, const string & delim) const
283 {
284     bool bFirst = true;
285     ITERATE(TFieldNameChainUnderlying, chain_iter, m_FieldNameChain) {
286         if( bFirst ) {
287             bFirst = false;
288         } else {
289             out_name_strm << delim;
290         }
291         out_name_strm << *chain_iter;
292     }
293 }
294 
GetFieldsMap(CUser_field::TMapFieldNameToRef & out_mapFieldNameToRef,TFieldMapFlags fFieldMapFlags,const SFieldNameChain & parent_name) const295 void CUser_field::GetFieldsMap(
296         CUser_field::TMapFieldNameToRef & out_mapFieldNameToRef,
297         TFieldMapFlags fFieldMapFlags,
298         const SFieldNameChain & parent_name) const
299 {
300     // get the label
301     if( ! FIELD_IS_SET_AND_IS(*this, Label, Str) ) {
302         // we might eventually support numeric labels
303         return;
304     }
305 
306     // copying a vector of CTempStrings is much more efficient
307     // than copying strings, so this should be okay.
308     SFieldNameChain field_name_chain = parent_name;
309 
310     if( ! (fFieldMapFlags & fFieldMapFlags_ExcludeThis) ) {
311         field_name_chain += GetLabel().GetStr();
312         out_mapFieldNameToRef.insert(
313             TMapFieldNameToRef::value_type(field_name_chain, ConstRef(this) ) );
314     }
315 
316     // recurse, if applicable
317     if( FIELD_IS_SET_AND_IS(*this, Data, Fields) ) {
318         // some flags do not get passed down recursively
319         TFieldMapFlags fChildFieldMapFlags =
320             ( fFieldMapFlags & ~fFieldMapFlags_ExcludeThis );
321 
322         ITERATE( CUser_field::C_Data::TFields, field_iter,
323             GetData().GetFields() )
324         {
325             (*field_iter)->GetFieldsMap(out_mapFieldNameToRef,
326                 fChildFieldMapFlags,
327                 field_name_chain);
328         }
329     }
330 }
331 
332 /// Access a named field in this user field.  This will tokenize the
333 /// string 'str' on the delimiters and recursively add fields where needed
SetField(const string & str,const string & delim,NStr::ECase use_case)334 CUser_field& CUser_field::SetField(const string& str,
335                                    const string& delim,
336                                    NStr::ECase use_case)
337 {
338     CRef<CUser_field> f = SetFieldRef(str, delim, use_case);
339     return *f;
340 }
341 
342 
343 /// Return a field reference representing the tokenized key, or a
344 /// NULL reference if the key cannot be created for some reason.
SetFieldRef(const string & str,const string & delim,NStr::ECase use_case)345 CRef<CUser_field> CUser_field::SetFieldRef(const string& str,
346                                            const string& delim,
347                                            NStr::ECase use_case)
348 {
349     list<string> toks;
350     NStr::Split(str, delim, toks, NStr::fSplit_Tokenize);
351 
352     CRef<CUser_field> f(this);
353     if ( ! f->GetData().IsFields()  &&  f->GetData().Which() != CUser_field::TData::e_not_set ) {
354         // There is a value here, not a list of User_fields, no place to recurse downward.
355         NCBI_THROW(CException, eUnknown, "Too many parts in key: \"" + str + "\"");
356     }
357     list<string>::const_iterator last = toks.end();
358     --last;
359     ITERATE (list<string>, iter, toks) {
360         CRef<CUser_field> new_f;
361         NON_CONST_ITERATE (TData::TFields, field_iter, f->SetData().SetFields()) {
362             const CUser_field& field = **field_iter;
363             if (NStr::Equal(field.GetLabel().GetStr(), *iter, use_case) )
364             {
365                 if (iter == last) {
366                     new_f = *field_iter;
367                     break;
368                 } else if (field.GetData().IsFields()  ||
369                            field.GetData().Which() == CUser_field::TData::e_not_set) {
370                     new_f = *field_iter;
371                     break;
372                 } else {
373                     // There is a value here, not a list of User_fields, no place to recurse downward.
374                     NCBI_THROW(CException, eUnknown, "Too many parts in key: \"" + str + "\"");
375                 }
376             }
377         }
378 
379         if ( !new_f ) {
380             new_f.Reset(new CUser_field());
381             new_f->SetLabel().SetStr(*iter);
382             f->SetData().SetFields().push_back(new_f);
383         }
384 
385         f = new_f;
386     }
387 
388     return f;
389 }
390 
391 
392 /// Verify that a named field exists
HasField(const string & str,const string & delim,NStr::ECase use_case) const393 bool CUser_field::HasField(const string& str,
394                            const string& delim,
395                            NStr::ECase use_case) const
396 {
397     CConstRef<CUser_field> f = GetFieldRef(str, delim, use_case);
398     return f.GetPointer() != NULL;
399 }
400 
401 
402 
403 /// delete a named field.
DeleteField(const string & str,const string & delim,NStr::ECase use_case)404 bool CUser_field::DeleteField(const string& str,
405                               const string& delim,
406                               NStr::ECase use_case)
407 {
408     list<string> toks;
409     NStr::Split(str, delim, toks, NStr::fSplit_Tokenize);
410 
411     CRef<CUser_field> f(this);
412     list<string>::const_iterator last = toks.end();
413     --last;
414 
415     ITERATE (list<string>, iter, toks) {
416         CRef<CUser_field> new_f;
417         if ( !f->GetData().IsFields() ) {
418             return false;
419         }
420         NON_CONST_ITERATE (TData::TFields, field_iter, f->SetData().SetFields()) {
421             const CUser_field& field = **field_iter;
422             if (field.GetLabel().IsStr()
423                 &&  NStr::Equal(field.GetLabel().GetStr(), *iter, use_case) )
424             {
425                 if (iter != last  &&  field.GetData().IsFields()) {
426                     new_f = *field_iter;
427                     break;
428                 } else if (iter == last) {
429                     // delete this one from f, its parent.
430                     f->SetData().SetFields().erase(field_iter);
431                     return true;
432                 }
433             }
434         }
435         if ( !new_f ) {
436             return false;
437         }
438         f = new_f;
439     }
440     // Never reached.
441     return false;
442 }
443 
444 
SetString(const char * value)445 CUser_field& CUser_field::SetString(const char* value)
446 {
447     return SetValue(string(value));
448 }
449 
450 
SetValue(const string & value,EParseField parse)451 CUser_field& CUser_field::SetValue(const string& value, EParseField parse)
452 {
453     if ( parse == eParse_Number ) {
454         try {
455             return SetValue(NStr::StringToNumeric<TData::TInt>(value));
456         }
457         catch (...) {
458         }
459 
460         try {
461             return SetValue(NStr::StringToDouble(value));
462         }
463         catch (...) {
464         }
465     }
466     return SetValue(value);
467 }
468 
469 
SetValue(const char * value,EParseField parse)470 CUser_field& CUser_field::SetValue(const char* value, EParseField parse)
471 {
472     return SetValue(string(value), parse);
473 }
474 
475 
476 // 15 digits of REAL numbers are preserved in serialization roundtrip
477 // so if the value has 15 digits or less we'll store it in 'real' field
478 static const Int8 kMaxAsReal = NCBI_CONST_INT8(999999999999999);
479 
480 
SetInt8(Int8 value)481 CUser_field& CUser_field::SetInt8(Int8 value)
482 {
483     if ( value == int(value) ) {
484         // value fits in 'int' field
485         return SetInt(int(value));
486     }
487     if ( value >= -kMaxAsReal && value <= kMaxAsReal ) {
488         return SetDouble(double(value));
489     }
490     // otherwise the value is stored into 'str' field
491     return SetString(NStr::NumericToString(value));
492 }
493 
494 
SetValue(const vector<int> & value)495 CUser_field& CUser_field::SetValue(const vector<int>&    value)
496 {
497     SetNum(value.size());
498     SetData().SetInts() = value;
499     return *this;
500 }
501 
502 
SetValue(const vector<double> & value)503 CUser_field& CUser_field::SetValue(const vector<double>& value)
504 {
505     SetNum(value.size());
506     SetData().SetReals() = value;
507     return *this;
508 }
509 
510 
SetValue(const vector<string> & value)511 CUser_field& CUser_field::SetValue(const vector<string>& value)
512 {
513     SetNum(value.size());
514     SetData().SetStrs() = value;
515     return *this;
516 }
517 
518 
SetValue(CUser_object & value)519 CUser_field& CUser_field::SetValue(CUser_object& value)
520 {
521     SetData().SetObject(value);
522     return *this;
523 }
524 
525 
SetValue(const vector<CRef<CUser_object>> & value)526 CUser_field& CUser_field::SetValue(const vector< CRef<CUser_object> >& value)
527 {
528     SetNum(value.size());
529     SetData().SetObjects() = value;
530     return *this;
531 }
532 
533 
SetValue(const vector<CRef<CUser_field>> & value)534 CUser_field& CUser_field::SetValue(const vector< CRef<CUser_field> >& value)
535 {
536     SetNum(value.size());
537     SetData().SetFields() = value;
538     return *this;
539 }
540 
541 
GetInt8(void) const542 Int8 CUser_field::GetInt8(void) const
543 {
544     const C_Data& data = GetData();
545     if ( data.IsInt() ) {
546         return data.GetInt();
547     }
548     if ( data.IsReal() ) {
549         double v = data.GetReal();
550         if ( v >= -kMaxAsReal && v <= kMaxAsReal ) {
551             return Int8(v);
552         }
553     }
554     return NStr::StringToNumeric<Int8>(data.GetStr());
555 }
556 
557 
558 END_objects_SCOPE // namespace ncbi::objects::
559 
560 END_NCBI_SCOPE
561