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

Go to the SVN repository for this file.

1 /* $Id: memberlist.cpp 99790 2023-05-10 17:59:02Z vasilche $
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 * !!! PUT YOUR DESCRIPTION HERE !!!
30 *
31 */
32 
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbistd.hpp>
35 #include <serial/exception.hpp>
37 #include <serial/impl/memberid.hpp>
38 #include <serial/impl/member.hpp>
40 #include <serial/impl/continfo.hpp>
41 #include <serial/impl/ptrinfo.hpp>
42 #include <corelib/ncbiutil.hpp>
43 #include <corelib/ncbithr.hpp>
44 
46 
48  : m_ItemsByName(0),
49  m_ZeroTagIndex(kInvalidMember),
50  m_ItemsByTag(0),
51  m_ItemsByOffset(0)
52 {
53 }
54 
56 {
57  ClearIndexes();
58 }
59 
61 {
62  // clear cached maps (byname and bytag)
63  delete m_ItemsByName.exchange(nullptr);
65  delete m_ItemsByTag.exchange(nullptr);
66  delete m_ItemsByOffset.exchange(nullptr);
67 
68 }
69 
71 {
72  ClearIndexes();
73  // add item
74  m_Items.push_back(AutoPtr<CItemInfo>(item));
75  item->m_Index = LastIndex();
76 }
77 
79 {
80  if (containerType != CAsnBinaryDefs::eAutomatic) {
82  CItemInfo* item = it->get();
83  if ( item->GetId().HasTag() && item->GetId().IsTagImplicit()) {
85  }
86  }
87  return;
88  }
91  CItemInfo* item = it->get();
92  // update item's tag
93  if ( item->GetId().HaveParentTag()) {
94  continue;
95  }
96  if ( item->GetId().HasTag()) {
97  tag = item->GetId().GetTag() + 1;
98  continue;
99  }
100  item->GetId().SetTag(tag++);
101  }
102  }
103 
105 {
106  if (spec != EDataSpec::eASN) {
107  for (auto& i : m_Items) {
108  i->GetId().SetNoPrefix();
109  i->UpdateFunctions();
110  }
111  }
112 }
113 
114 DEFINE_STATIC_FAST_MUTEX(s_ItemsMapMutex);
115 
117 {
118  TItemsByName* items = m_ItemsByName.load(memory_order_acquire);
119  if ( !items ) {
120  CFastMutexGuard GUARD(s_ItemsMapMutex);
121  items = m_ItemsByName.load(memory_order_acquire);
122  if ( !items ) {
123  unique_ptr<TItemsByName> keep = make_unique<TItemsByName>();
124  items = keep.get();
125  for ( CIterator i(*this); i.Valid(); ++i ) {
126  const CItemInfo* itemInfo = GetItemInfo(i);
127  const string& name = itemInfo->GetId().GetName();
128  if ( !items->insert(TItemsByName::value_type(name, *i)).second ) {
129  if ( !name.empty() )
130  NCBI_THROW(CSerialException,eInvalidData,
131  string("duplicate member name: ")+name);
132  }
133  }
134  m_ItemsByName.store(items, memory_order_release);
135  keep.release();
136  }
137  }
138  return *items;
139 }
140 
143 {
144  TItemsByOffset* items = m_ItemsByOffset.load(memory_order_acquire);
145  if ( !items ) {
146  CFastMutexGuard GUARD(s_ItemsMapMutex);
147  items = m_ItemsByOffset.load(memory_order_acquire);
148  if ( !items ) {
149  // create map
150  unique_ptr<TItemsByOffset> keep = make_unique<TItemsByOffset>();
151  items = keep.get();
152  // fill map
153  for ( CIterator i(*this); i.Valid(); ++i ) {
154  const CItemInfo* itemInfo = GetItemInfo(i);
155  size_t offset = itemInfo->GetOffset();
156  if ( !items->insert(TItemsByOffset::value_type(offset, *i)).second ) {
157  NCBI_THROW(CSerialException,eInvalidData, "conflict member offset");
158  }
159  }
160 /*
161  // check overlaps
162  size_t nextOffset = 0;
163  for ( TItemsByOffset::const_iterator m = members->begin();
164  m != members->end(); ++m ) {
165  size_t offset = m->first;
166  if ( offset < nextOffset ) {
167  NCBI_THROW(CSerialException,eInvalidData,
168  "overlapping members");
169  }
170  nextOffset = offset + m_Members[m->second]->GetSize();
171  }
172 */
173  m_ItemsByOffset.store(items, memory_order_release);
174  keep.release();
175  }
176  }
177  return *items;
178 }
179 
182 {
183  const CItemInfo* itemInfo = GetItemInfo(i);
184  TTag tag = itemInfo->GetId().GetTag();
185  CAsnBinaryDefs::ETagClass tagclass = itemInfo->GetId().GetTagClass();
186  if (!itemInfo->GetId().HasTag()) {
187  TTypeInfo itemType = itemInfo->GetTypeInfo();
188  while (!itemType->HasTag() && itemType->GetTypeFamily() == eTypeFamilyPointer) {
189  const CPointerTypeInfo* ptr =
190  dynamic_cast<const CPointerTypeInfo*>(itemType);
191  if (ptr) {
192  itemType = ptr->GetPointedType();
193  } else {
194  NCBI_THROW(CSerialException,eInvalidData,
195  string("invalid type info: ") + itemInfo->GetId().GetName());
196  }
197  }
198 
199  if (itemType->HasTag()) {
200  tag = itemType->GetTag();
201  tagclass = itemType->GetTagClass();
202  }
203  }
204  return make_pair(tag, tagclass);
205 }
206 
207 pair<TMemberIndex, const CItemsInfo::TItemsByTag*>
209 {
210  typedef pair<TMemberIndex, const TItemsByTag*> TReturn;
211  TReturn ret(m_ZeroTagIndex.load(memory_order_acquire),
212  m_ItemsByTag.load(memory_order_acquire));
213  if ( ret.first == kInvalidMember && ret.second == 0 ) {
214  CFastMutexGuard GUARD(s_ItemsMapMutex);
215  ret = TReturn(m_ZeroTagIndex.load(memory_order_acquire),
216  m_ItemsByTag.load(memory_order_acquire));
217  if ( ret.first == kInvalidMember && ret.second == 0 ) {
218  {
219  CIterator i(*this);
220  if ( i.Valid() ) {
221  if (GetItemInfo(i)->GetId().HasTag() &&
222  GetItemInfo(i)->GetId().GetTagClass() == CAsnBinaryDefs::eContextSpecific) {
223  ret.first = *i - GetItemInfo(i)->GetId().GetTag();
224  for ( ++i; i.Valid(); ++i ) {
225  if ( ret.first != *i - GetItemInfo(i)->GetId().GetTag() ||
226  GetItemInfo(i)->GetId().GetTagClass() != CAsnBinaryDefs::eContextSpecific) {
227  ret.first = kInvalidMember;
228  break;
229  }
230  }
231  }
232  }
233  }
234  if ( ret.first != kInvalidMember ) {
235  m_ZeroTagIndex.store(ret.first, memory_order_release);
236  }
237  else {
238  unique_ptr<TItemsByTag> items = make_unique<TItemsByTag>();
239  for ( CIterator i(*this); i.Valid(); ++i ) {
241  if (tc.first >= 0) {
242  if ( !items->insert(TItemsByTag::value_type( tc, *i)).second &&
243  GetItemInfo(i)->GetId().HasTag() ) {
244  NCBI_THROW(CSerialException,eInvalidData, "duplicate member tag");
245  }
246  }
247  }
248  ret.second = items.get();
249  m_ItemsByTag.store(items.release(), memory_order_release);
250  }
251  }
252  }
253  return ret;
254 }
255 
257 {
258  const TItemsByName& items = GetItemsByName();
259  TItemsByName::const_iterator i = items.find(name);
260  if ( i == items.end() )
261  return kInvalidMember;
262  return i->second;
263 }
264 
265 TMemberIndex CItemsInfo::FindDeep(const CTempString& name, bool search_attlist,
266  const CClassTypeInfoBase** pclassInfo) const
267 {
268  TMemberIndex ind = Find(name);
269  if (ind != kInvalidMember) {
270  return ind;
271  }
272  for (CIterator item(*this); item.Valid(); ++item) {
273  const CItemInfo* info = GetItemInfo(item);
274  const CMemberId& id = info->GetId();
275  if ((!id.IsAttlist() && id.HasNotag()) ||
276  ( id.IsAttlist() && search_attlist)) {
277  const CClassTypeInfoBase* classType =
278  dynamic_cast<const CClassTypeInfoBase*>(
279  FindRealTypeInfo(info->GetTypeInfo()));
280  if (classType) {
281  if (classType->GetItems().FindDeep(name, search_attlist)
282  != kInvalidMember) {
283  if (pclassInfo) {
284  *pclassInfo = classType;
285  }
286  return *item;
287  }
288  }
289  }
290  }
291  return kInvalidMember;
292 }
293 
295 {
296  TMemberIndex ind = Find(name, pos);
297  if (ind != kInvalidMember) {
298  return ind;
299  }
300  for (CIterator item(*this, pos); item.Valid(); ++item) {
301  const CItemInfo* info = GetItemInfo(item);
302  const CClassTypeInfoBase* classType =
303  dynamic_cast<const CClassTypeInfoBase*>(
304  FindRealTypeInfo(info->GetTypeInfo()));
305  if (classType) {
306  if (classType->GetItems().FindDeep(name)
307  != kInvalidMember) {
308  return *item;
309  }
310  }
311  }
312  return kInvalidMember;
313 }
314 
316 {
317  const CTypeInfo* type;
318  for (type = info;;) {
319  if (type->GetTypeFamily() == eTypeFamilyContainer) {
320  const CContainerTypeInfo* cont =
321  dynamic_cast<const CContainerTypeInfo*>(type);
322  if (cont) {
323  type = cont->GetElementType();
324  }
325  } else if (type->GetTypeFamily() == eTypeFamilyPointer) {
326  const CPointerTypeInfo* ptr =
327  dynamic_cast<const CPointerTypeInfo*>(type);
328  if (ptr) {
329  type = ptr->GetPointedType();
330  }
331  } else {
332  break;
333  }
334  }
335  return type;
336 }
337 
339 {
340  if (!info->GetId().HasNotag() && !info->GetId().IsAttlist()) {
341  return info->Optional() ? 0 : info;
342  }
343  return FindNextMandatory(info->GetTypeInfo());
344 }
345 
347 {
348  const CItemInfo* found = 0;
350  ETypeFamily family = type->GetTypeFamily();
351  if (family == eTypeFamilyClass || family == eTypeFamilyChoice) {
352  const CClassTypeInfoBase* classType =
353  dynamic_cast<const CClassTypeInfoBase*>(type);
354  _ASSERT(classType);
355  const CItemsInfo& items = classType->GetItems();
356  TMemberIndex i;
357  const CItemInfo* found_first = 0;
358  for (i = items.FirstIndex(); i <= items.LastIndex(); ++i) {
359 
360  const CItemInfo* item = classType->GetItems().GetItemInfo(i);
361  if (item->Optional()) {
362  continue;
363  }
364  if (!item->GetId().HasNotag()) {
365  return item;
366  }
367  ETypeFamily item_family = item->GetTypeInfo()->GetTypeFamily();
368  if (item_family == eTypeFamilyPointer) {
369  const CPointerTypeInfo* ptr =
370  dynamic_cast<const CPointerTypeInfo*>(item->GetTypeInfo());
371  if (ptr) {
372  item_family = ptr->GetPointedType()->GetTypeFamily();
373  }
374  }
375  if (item_family == eTypeFamilyContainer) {
376  if (item->NonEmpty()) {
377  found = FindNextMandatory( item );
378  }
379  } else if (item_family == eTypeFamilyPrimitive) {
380  found = item->Optional() ? 0 : item;
381  } else {
382  found = FindNextMandatory( item );
383  }
384  if (family == eTypeFamilyClass) {
385  if (found) {
386  return found;
387  }
388  } else {
389  if (!found) {
390  // this is optional choice variant
391  return 0;
392  }
393  if (!found_first) {
394  found_first = found;
395  }
396  }
397  }
398  return found_first;
399  }
400  return found;
401 }
402 
404 {
405  for (CIterator item(*this); item.Valid(); ++item) {
406  const CItemInfo* info = GetItemInfo(item);
407  if (info->NonEmpty() || info->GetId().IsAttlist()) {
408  continue;
409  }
410  const CTypeInfo* type;
411  for (type = info->GetTypeInfo();;) {
412  if (type->GetTypeFamily() == eTypeFamilyContainer) {
413  // container may be empty
414  return *item;
415  } else if (type->GetTypeFamily() == eTypeFamilyPointer) {
416  const CPointerTypeInfo* ptr =
417  dynamic_cast<const CPointerTypeInfo*>(type);
418  if (ptr) {
419  type = ptr->GetPointedType();
420  }
421  } else {
422  break;
423  }
424  }
425  }
426  return kInvalidMember;
427 }
428 
430 {
431  for ( CIterator i(*this, pos); i.Valid(); ++i ) {
432  if ( name == GetItemInfo(i)->GetId().GetName() )
433  return *i;
434  }
435  return kInvalidMember;
436 }
437 
439 {
440  TMemberIndex zero_index = m_ZeroTagIndex.load(memory_order_acquire);
441  const TItemsByTag* items_by_tag = m_ItemsByTag.load(memory_order_acquire);
442  if ( zero_index == kInvalidMember && !items_by_tag ) {
443  tie(zero_index, items_by_tag) = GetItemsByTagInfo();
444  }
445  if ( zero_index != kInvalidMember ) {
446  TMemberIndex index = tag + zero_index;
447  if ( index < FirstIndex() || index > LastIndex() )
448  return kInvalidMember;
449  return index;
450  }
451  else {
452  TItemsByTag::const_iterator mi = items_by_tag->find( make_pair(tag,tagclass));
453  if ( mi == items_by_tag->end() )
454  return kInvalidMember;
455  return mi->second;
456  }
457 }
458 
460 {
461  TMemberIndex zero_index = m_ZeroTagIndex;
462  if ( zero_index == kInvalidMember && !m_ItemsByTag.load(memory_order_acquire) ) {
463  zero_index = GetItemsByTagInfo().first;
464  }
465  if ( zero_index != kInvalidMember ) {
466  TMemberIndex index = tag + zero_index;
467  if ( index < pos || index > LastIndex() )
468  return kInvalidMember;
469  return index;
470  }
471  else {
472  for ( CIterator i(*this, pos); i.Valid(); ++i ) {
474  if (tc.first == tag && tc.second == tagclass) {
475  return *i;
476  }
477  }
478  if (pos <= LastIndex()) {
479  const CItemInfo* info = GetItemInfo(pos);
480  if (!info->GetId().HasTag()) {
481  const CMemberInfo* mem = dynamic_cast<const CMemberInfo*>(info);
482  if (mem && !mem->Optional()) {
483  return pos;
484  }
485  }
486  }
487  return kInvalidMember;
488  }
489 }
490 
491 
AutoPtr –.
Definition: ncbimisc.hpp:401
Root class for all serialization exceptions.
Definition: exception.hpp:50
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTypeInfo class contains all information about C++ types (both basic and classes): members and layout...
Definition: typeinfo.hpp:76
container_type::const_iterator const_iterator
Definition: map.hpp:53
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
container_type::value_type value_type
Definition: map.hpp:52
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
Include a standard set of the NCBI C++ Toolkit most basic headers.
static int type
Definition: getdata.c:31
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
bool Optional(void) const
static const CItemInfo * FindNextMandatory(const CItemInfo *info)
Definition: memberlist.cpp:338
bool Optional(void) const
atomic< TItemsByOffset * > m_ItemsByOffset
Definition: memberlist.hpp:153
CAsnBinaryDefs::ETagClass GetTagClass(void) const
const CMemberId & GetId(void) const
const string & GetName(void) const
TMemberIndex Find(const CTempString &name) const
Definition: memberlist.cpp:256
CMemberId::TTag TTag
Definition: memberlist.hpp:59
virtual ~CItemsInfo(void)
Definition: memberlist.cpp:55
void DataSpec(EDataSpec spec)
Definition: memberlist.cpp:104
static const CTypeInfo * FindRealTypeInfo(const CTypeInfo *info)
Definition: memberlist.cpp:315
pair< TTag, CAsnBinaryDefs::ETagClass > TTagAndClass
Definition: memberlist.hpp:62
pair< TMemberIndex, const TItemsByTag * > GetItemsByTagInfo(void) const
Definition: memberlist.cpp:208
TItems m_Items
Definition: memberlist.hpp:143
atomic< TMemberIndex > m_ZeroTagIndex
Definition: memberlist.hpp:149
TMemberIndex FindEmpty(void) const
Definition: memberlist.cpp:403
atomic< TItemsByTag * > m_ItemsByTag
Definition: memberlist.hpp:150
TTagAndClass GetTagAndClass(const CIterator &i) const
Definition: memberlist.cpp:181
TMemberIndex m_Index
Definition: item.hpp:120
vector< AutoPtr< CItemInfo > > TItems
Definition: memberlist.hpp:60
bool IsTagImplicit(void) const
CAsnBinaryDefs::ETagConstructed m_TagConstructed
Definition: memberid.hpp:117
void SetTag(TTag tag, CAsnBinaryDefs::ETagClass tagclass=CAsnBinaryDefs::eContextSpecific, CAsnBinaryDefs::ETagType tagtype=CAsnBinaryDefs::eAutomatic)
TMemberIndex FindDeep(const CTempString &name, bool search_attlist=false, const CClassTypeInfoBase **classInfo=nullptr) const
Definition: memberlist.cpp:265
const CItemInfo * GetItemInfo(TMemberIndex index) const
static TMemberIndex FirstIndex(void)
Definition: memberlist.hpp:78
bool HasNotag(void) const
atomic< TItemsByName * > m_ItemsByName
Definition: memberlist.hpp:146
TTag GetTag(void) const
const TItemsByOffset & GetItemsByOffset(void) const
Definition: memberlist.cpp:142
bool Valid(void) const
TPointerOffsetType GetOffset(void) const
bool HaveParentTag(void) const
TTypeInfo GetTypeInfo(void) const
void AddItem(CItemInfo *item)
Definition: memberlist.cpp:70
bool HasTag(void) const
TMemberIndex LastIndex(void) const
Definition: memberlist.hpp:82
const TItemsByName & GetItemsByName(void) const
Definition: memberlist.cpp:116
bool NonEmpty(void) const
void AssignItemsTags(CAsnBinaryDefs::ETagType containerType)
Definition: memberlist.cpp:78
void ClearIndexes()
Definition: memberlist.cpp:60
CItemsInfo(void)
Definition: memberlist.cpp:47
size_t TMemberIndex
Type used for indexing class members and choice variants.
Definition: serialdef.hpp:230
const TMemberIndex kInvalidMember
Special value returned from FindMember.
Definition: serialdef.hpp:237
ETypeFamily
Type family.
Definition: serialdef.hpp:138
EDataSpec
Definition: serialdef.hpp:204
@ eTypeFamilyClass
Definition: serialdef.hpp:140
@ eTypeFamilyContainer
Definition: serialdef.hpp:142
@ eTypeFamilyChoice
Definition: serialdef.hpp:141
@ eTypeFamilyPointer
Definition: serialdef.hpp:143
@ eTypeFamilyPrimitive
Definition: serialdef.hpp:139
const CSeq_id & GetId(const CSeq_loc &loc, CScope *scope)
If all CSeq_ids embedded in CSeq_loc refer to the same CBioseq, returns the first CSeq_id found,...
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
CAsnBinaryDefs::ETagClass GetTagClass(void) const
Definition: typeinfo.hpp:262
CAsnBinaryDefs::ETagConstructed GetTagConstructed(void) const
Definition: typeinfo.hpp:265
bool HasTag(void) const
Definition: typeinfo.hpp:259
const CItemsInfo & GetItems(void) const
ETypeFamily GetTypeFamily(void) const
TTypeInfo GetPointedType(void) const
CAsnBinaryDefs::TLongTag GetTag(void) const
Definition: typeinfo.hpp:256
TTypeInfo GetElementType(void) const
int i
static MDB_envinfo info
Definition: mdb_load.c:37
DEFINE_STATIC_FAST_MUTEX(s_ItemsMapMutex)
const char * tag
Multi-threading – classes, functions, and features.
Useful/utility classes and methods.
int offset
Definition: replacements.h:160
Definition: type.c:6
#define _ASSERT
Modified on Thu Nov 30 04:55:49 2023 by modify_doxy.py rev. 669887