1 /*  $Id: objstack.cpp 570512 2018-09-10 18:52:20Z gouriano $
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 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <serial/impl/objstack.hpp>
35 #include <serial/impl/ptrinfo.hpp>
36 #include <serial/impl/continfo.hpp>
37 #include <serial/impl/classinfob.hpp>
38 
39 BEGIN_NCBI_SCOPE
40 
41 static const size_t KInitialStackSize = 16;
42 
CObjectStack(void)43 CObjectStack::CObjectStack(void)
44 {
45     TFrame* stack = m_Stack = m_StackPtr = new TFrame[KInitialStackSize];
46     m_StackEnd = stack + KInitialStackSize;
47     for ( size_t i = 0; i < KInitialStackSize; ++i ) {
48         m_Stack[i].Reset();
49     }
50     m_WatchPathHooks = m_PathValid = false;
51 }
52 
~CObjectStack(void)53 CObjectStack::~CObjectStack(void)
54 {
55     delete[] m_Stack;
56 }
57 
ResetState(void)58 void CObjectStack::ResetState(void)
59 {
60     m_PathValid = false;
61 }
62 
ResetPathHooks(void)63 void CObjectStack::ResetPathHooks(void)
64 {
65     for (auto& h : m_PathHooks) {
66         h->Erase(this);
67     }
68     m_PathHooks.clear();
69 }
70 
UnendedFrame(void)71 void CObjectStack::UnendedFrame(void)
72 {
73 }
74 
ClearStack(void)75 void CObjectStack::ClearStack(void)
76 {
77     m_StackPtr = m_Stack;
78 }
79 
GetStackTraceASN(void) const80 string CObjectStack::GetStackTraceASN(void) const
81 {
82     if (!GetStackDepth()) {
83         return "stack is empty";
84     }
85 //    _ASSERT(FetchFrameFromBottom(0).m_FrameType == TFrame::eFrameNamed);
86 //    _ASSERT(FetchFrameFromBottom(0).m_TypeInfo);
87     string stack = FetchFrameFromBottom(0).HasTypeInfo() ?
88         FetchFrameFromBottom(0).m_TypeInfo->GetName() : "?";
89     for ( size_t i = 1; i < GetStackDepth(); ++i ) {
90         const TFrame& frame = FetchFrameFromBottom(i);
91         switch ( frame.m_FrameType ) {
92         case TFrame::eFrameClassMember:
93         case TFrame::eFrameChoiceVariant:
94             {
95                 if ( !frame.m_MemberId ) {
96                     _ASSERT(i == GetStackDepth() - 1);
97                 }
98                 else {
99                     const CMemberId& id = *frame.m_MemberId;
100                     stack += '.';
101                     if ( !id.GetName().empty() ) {
102                         stack += id.GetName();
103                     }
104                     else {
105                         stack += '[';
106                         stack += NStr::IntToString(id.GetTag());
107                         stack += ']';
108                     }
109                 }
110             }
111             break;
112         case TFrame::eFrameArrayElement:
113             stack += ".E";
114             break;
115         default:
116             break;
117         }
118     }
119     return stack;
120 }
121 
PushFrameLong(void)122 CObjectStack::TFrame& CObjectStack::PushFrameLong(void)
123 {
124     size_t depth = m_StackPtr - m_Stack;
125     size_t oldSize = m_StackEnd - m_Stack;
126     size_t newSize = oldSize * 2;
127     TFrame* newStack = new TFrame[newSize];
128 
129     {
130         // copy old stack
131         for ( size_t i = 0; i < oldSize; ++i )
132             newStack[i] = m_Stack[i];
133     }
134     {
135         // clear new area of new stack
136         for ( size_t i = oldSize; i < newSize; ++i )
137             newStack[i].Reset();
138     }
139 
140     delete[] m_Stack;
141 
142     m_Stack = newStack;
143     m_StackEnd = newStack + newSize;
144 
145     return *(m_StackPtr = (newStack + depth + 1));
146 }
147 
IsNsQualified(void)148 bool CObjectStack::IsNsQualified(void)
149 {
150     if (StackIsEmpty()) {
151         return true;
152     }
153     ENsQualifiedMode mode;
154     if (TopFrame().HasTypeInfo()) {
155         if (!TopFrame().GetTypeInfo()->GetModuleName().empty()) {
156             return true;
157         }
158     }
159     size_t i, count = GetStackDepth();
160     for (i=0; i<count; ++i) {
161 
162         CObjectStack::TFrame& frame = FetchFrameFromTop(i);
163         mode = frame.IsNsQualified();
164         if (mode != eNSQNotSet) {
165             return mode == eNSQualified;
166         }
167 
168         if (frame.HasTypeInfo()) {
169             mode = frame.GetTypeInfo()->IsNsQualified();
170             if (mode != eNSQNotSet) {
171                 frame.SetNsQualified(mode);
172                 return mode == eNSQualified;
173             }
174         }
175 
176         if (frame.HasMemberId()) {
177             const CMemberId& mem = frame.GetMemberId();
178             mode = mem.IsNsQualified();
179             if (mode != eNSQNotSet) {
180                 frame.SetNsQualified(mode);
181                 return mode == eNSQualified;
182             }
183             if (mem.IsAttlist()) {
184                 frame.SetNsQualified(eNSUnqualified);
185                 return false;
186             }
187         }
188     }
189     TopFrame().SetNsQualified(eNSQualified);
190     return true;
191 }
192 
IsCompressed(void) const193 bool CObjectStack::IsCompressed(void) const
194 {
195     size_t i, count = GetStackDepth();
196     for (i=0; i<count; ++i) {
197         const CObjectStack::TFrame& frame = FetchFrameFromTop(i);
198         if (frame.HasMemberId()) {
199             return frame.GetMemberId().IsCompressed();
200         }
201     }
202     return false;
203 }
204 
x_PushStackPath(void)205 void CObjectStack::x_PushStackPath(void)
206 {
207     if (!m_WatchPathHooks) {
208         m_PathValid = false;
209         return;
210     }
211     if (!m_PathValid) {
212         GetStackPath();
213 #if 0
214         for ( size_t i = 1; i < GetStackDepth(); ++i ) {
215             const TFrame& frame = FetchFrameFromTop(i);
216             if (frame.HasTypeInfo()) {
217                 // there is no "root" symbol
218                 m_MemberPath = frame.GetTypeInfo()->GetName();
219                 break;
220             }
221         }
222 #endif
223     }
224     const CMemberId& mem_id = TopFrame().GetMemberId();
225     if (mem_id.HasNotag() || mem_id.IsAttlist()) {
226         return;
227     }
228     // member separator symbol is '.'
229     m_MemberPath += '.';
230     const string& member = mem_id.GetName();
231     if (!member.empty()) {
232         m_MemberPath += member;
233     } else {
234         m_MemberPath += NStr::IntToString(mem_id.GetTag());
235     }
236     m_PathValid = true;
237     x_SetPathHooks(true);
238 }
239 
x_PopStackPath(void)240 void CObjectStack::x_PopStackPath(void)
241 {
242     if (!m_WatchPathHooks) {
243         m_PathValid = false;
244         return;
245     }
246     if (GetStackDepth() == 1) {
247         x_SetPathHooks(false);
248         m_PathValid = false;
249     } else {
250         const TFrame& top = TopFrame();
251         if (top.HasMemberId()) {
252             const CMemberId& mem_id = top.GetMemberId();
253             if (mem_id.HasNotag() || mem_id.IsAttlist()) {
254                 return;
255             }
256             x_SetPathHooks(false);
257             // member separator symbol is '.'
258             m_MemberPath.erase(m_MemberPath.find_last_of('.'));
259         }
260     }
261 }
262 
GetStackPath(void) const263 const string& CObjectStack::GetStackPath(void) const
264 {
265     if (GetStackDepth()) {
266 //        _ASSERT(FetchFrameFromBottom(0).m_FrameType == TFrame::eFrameNamed);
267 //        _ASSERT(FetchFrameFromBottom(0).m_TypeInfo);
268 //        m_MemberPath = FetchFrameFromBottom(0).GetTypeInfo()->GetName();
269         // there is no "root" symbol
270         string path;
271         path = FetchFrameFromBottom(0).HasTypeInfo() ?
272             FetchFrameFromBottom(0).m_TypeInfo->GetName() : "?";
273         for ( size_t i = 1; i < GetStackDepth(); ++i ) {
274             const TFrame& frame = FetchFrameFromBottom(i);
275             if (frame.HasMemberId()) {
276                 const CMemberId& mem_id = frame.GetMemberId();
277                 if (mem_id.HasNotag() || mem_id.IsAttlist()) {
278                     continue;
279                 }
280                 // member separator symbol is '.'
281                 path += '.';
282                 const string& member = mem_id.GetName();
283                 if (!member.empty()) {
284                     path += member;
285                 } else {
286                     path += NStr::IntToString(mem_id.GetTag());
287                 }
288             }
289         }
290         const_cast<CObjectStack*>(this)->m_PathValid = true;
291         const_cast<CObjectStack*>(this)->m_MemberPath = path;
292     }
293     return m_MemberPath;
294 }
295 
PopErrorFrame(void)296 void CObjectStack::PopErrorFrame(void)
297 {
298     try {
299         UnendedFrame();
300     }
301     catch (...) {
302         PopFrame();
303         throw;
304     }
305     PopFrame();
306 }
307 
IsKnownElement(const CTempString & name) const308 bool CObjectStack::IsKnownElement(const CTempString& name) const
309 {
310     size_t s, depth = GetStackDepth();
311     for (s=1; s < depth; ++s) {
312         const TFrame& frame = FetchFrameFromTop(s);
313         if (frame.GetFrameType() == CObjectStackFrame::eFrameClass ||
314             frame.GetFrameType() == CObjectStackFrame::eFrameChoice) {
315             const CClassTypeInfoBase* type = dynamic_cast<const CClassTypeInfoBase*>(frame.GetTypeInfo());
316             TMemberIndex i = type->GetItems().FindDeep(name);
317             if (i != kInvalidMember) {
318                 return true;
319             }
320         }
321         else if (frame.HasTypeInfo() && !frame.GetTypeInfo()->GetName().empty()) {
322             break;
323         }
324         else if (!frame.GetNotag()) {
325             break;
326         }
327     }
328     return false;
329 }
330 
GetRealTypeInfo(TTypeInfo typeInfo)331 TTypeInfo CObjectStack::GetRealTypeInfo(TTypeInfo typeInfo)
332 {
333     if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) {
334         const CPointerTypeInfo* ptr =
335             dynamic_cast<const CPointerTypeInfo*>(typeInfo);
336         if (ptr) {
337             typeInfo = ptr->GetPointedType();
338         }
339     }
340     return typeInfo;
341 }
342 
GetRealTypeFamily(TTypeInfo typeInfo)343 ETypeFamily CObjectStack::GetRealTypeFamily(TTypeInfo typeInfo)
344 {
345     return GetRealTypeInfo( typeInfo )->GetTypeFamily();
346 }
347 
GetContainerElementTypeInfo(TTypeInfo typeInfo)348 TTypeInfo CObjectStack::GetContainerElementTypeInfo(TTypeInfo typeInfo)
349 {
350     typeInfo = GetRealTypeInfo( typeInfo );
351     _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer);
352     const CContainerTypeInfo* ptr =
353         dynamic_cast<const CContainerTypeInfo*>(typeInfo);
354     return GetRealTypeInfo(ptr->GetElementType());
355 }
356 
GetContainerElementTypeFamily(TTypeInfo typeInfo)357 ETypeFamily CObjectStack::GetContainerElementTypeFamily(TTypeInfo typeInfo)
358 {
359     typeInfo = GetRealTypeInfo( typeInfo );
360     _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer);
361     const CContainerTypeInfo* ptr =
362         dynamic_cast<const CContainerTypeInfo*>(typeInfo);
363     return GetRealTypeFamily(ptr->GetElementType());
364 }
365 
GetFrameTypeName(void) const366 const char* CObjectStackFrame::GetFrameTypeName(void) const
367 {
368     const char* s;
369     switch (GetFrameType())
370     {
371     default:                  s = "UNKNOWN";             break;
372     case eFrameOther:         s = "eFrameOther";         break;
373     case eFrameNamed:         s = "eFrameNamed";         break;
374     case eFrameArray:         s = "eFrameArray";         break;
375     case eFrameArrayElement:  s = "eFrameArrayElement";  break;
376     case eFrameClass:         s = "eFrameClass";         break;
377     case eFrameClassMember:   s = "eFrameClassMember";   break;
378     case eFrameChoice:        s = "eFrameChoice";        break;
379     case eFrameChoiceVariant: s = "eFrameChoiceVariant"; break;
380     }
381     return s;
382 }
383 
384 #if defined(NCBI_SERIAL_IO_TRACE)
385 
TracePushFrame(bool push) const386 void CObjectStack::TracePushFrame(bool push) const
387 {
388     cout << endl ;
389     int depth = (int)GetStackDepth();
390     cout << depth;
391     for (; depth>0; --depth) {
392         cout.put(' ');
393     }
394     cout << (push ? "Enter " : "Leave ") << m_StackPtr->GetFrameTypeName();
395 }
396 
397 #endif
398 
GetFrameInfo(void) const399 string CObjectStackFrame::GetFrameInfo(void) const
400 {
401     string info(" Frame type= ");
402     info += GetFrameTypeName();
403     if (m_TypeInfo) {
404         info += ", Object type= " + m_TypeInfo->GetName();
405     }
406     if (m_MemberId) {
407         info += ", Member name= " + m_MemberId->GetName();
408     }
409     return info;
410 }
411 
412 
GetFrameName(void) const413 string CObjectStackFrame::GetFrameName(void) const
414 {
415     string info;
416     switch ( GetFrameType() ) {
417     case eFrameClassMember:
418     case eFrameChoiceVariant:
419         {
420             if ( m_MemberId ) {
421                 const CMemberId& id = *m_MemberId;
422 //                info = '.';
423                 if ( !id.GetName().empty() ) {
424                     info += id.GetName();
425                 }
426                 else {
427                     info += '[';
428                     info += NStr::IntToString(id.GetTag());
429                     info += ']';
430                 }
431             }
432         }
433         break;
434     case eFrameArrayElement:
435         info = "[]";
436         break;
437     case eFrameArray:
438         info = "[]";
439         break;
440     case eFrameNamed:
441         if (!GetNotag()) {
442             info = GetTypeInfo()->GetName();
443         }
444         break;
445     default:
446         {
447             break;
448         }
449     }
450     return info;
451 }
452 
453 
454 END_NCBI_SCOPE
455