1 /*  $Id: seq_id_mapper.cpp 430230 2014-03-24 20:35:20Z grichenk $
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: Aleksey Grichenko, Eugene Vasilchenko
27 *
28 * File Description:
29 *   Seq-id mapper for Object Manager
30 *
31 */
32 
33 #include <ncbi_pch.hpp>
34 #include <objects/seq/seq_id_mapper.hpp>
35 #include <corelib/ncbimtx.hpp>
36 #include "seq_id_tree.hpp"
37 
38 BEGIN_NCBI_SCOPE
39 BEGIN_SCOPE(objects)
40 
41 ////////////////////////////////////////////////////////////////////
42 //
43 //  CSeq_id_Mapper::
44 //
45 
46 
47 typedef CSeq_id_Mapper TInstance;
48 
49 // slow implementation with mutex
50 static TInstance* s_Instance = 0;
51 DEFINE_STATIC_FAST_MUTEX(s_InstanceMutex);
52 
GetInstance(void)53 CRef<TInstance> TInstance::GetInstance(void)
54 {
55     CRef<TInstance> ret;
56     {{
57         CFastMutexGuard guard(s_InstanceMutex);
58         ret.Reset(s_Instance);
59         if ( !ret || ret->ReferencedOnlyOnce() ) {
60             if ( ret ) {
61                 ret.Release();
62             }
63             ret.Reset(new TInstance);
64             s_Instance = ret;
65         }
66     }}
67     _ASSERT(ret == s_Instance);
68     return ret;
69 }
70 
71 
s_ResetInstance(TInstance * instance)72 static void s_ResetInstance(TInstance* instance)
73 {
74     CFastMutexGuard guard(s_InstanceMutex);
75     if ( s_Instance == instance ) {
76         s_Instance = 0;
77     }
78 }
79 
80 
CSeq_id_Mapper(void)81 CSeq_id_Mapper::CSeq_id_Mapper(void)
82 {
83     CSeq_id_Which_Tree::Initialize(this, m_Trees);
84 }
85 
86 
~CSeq_id_Mapper(void)87 CSeq_id_Mapper::~CSeq_id_Mapper(void)
88 {
89     s_ResetInstance(this);
90     ITERATE ( TTrees, it, m_Trees ) {
91         _ASSERT((*it)->Empty());
92     }
93 }
94 
95 
96 inline
x_GetTree(const CSeq_id_Handle & idh)97 CSeq_id_Which_Tree& CSeq_id_Mapper::x_GetTree(const CSeq_id_Handle& idh)
98 {
99     CSeq_id::E_Choice type;
100     if ( !idh ) {
101         type = CSeq_id::e_not_set;
102     }
103     else if ( idh.IsGi() ) {
104         type = CSeq_id::e_Gi;
105     }
106     else {
107         return idh.m_Info->GetTree();
108     }
109     _ASSERT(size_t(type) < m_Trees.size());
110     return *m_Trees[type];
111 }
112 
113 
GetGiHandle(TGi gi)114 CSeq_id_Handle CSeq_id_Mapper::GetGiHandle(TGi gi)
115 {
116     _ASSERT(size_t(CSeq_id::e_Gi) < m_Trees.size());
117     return m_Trees[CSeq_id::e_Gi]->GetGiHandle(gi);
118 }
119 
120 
GetHandle(const CSeq_id & id,bool do_not_create)121 CSeq_id_Handle CSeq_id_Mapper::GetHandle(const CSeq_id& id, bool do_not_create)
122 {
123     CSeq_id_Which_Tree& tree = x_GetTree(id);
124     return do_not_create? tree.FindInfo(id): tree.FindOrCreate(id);
125 }
126 
127 
HaveMatchingHandles(const CSeq_id_Handle & idh)128 bool CSeq_id_Mapper::HaveMatchingHandles(const CSeq_id_Handle& idh)
129 {
130     return x_GetTree(idh).HaveMatch(idh);
131 }
132 
133 
GetMatchingHandles(const CSeq_id_Handle & idh,TSeq_id_HandleSet & h_set)134 void CSeq_id_Mapper::GetMatchingHandles(const CSeq_id_Handle& idh,
135                                         TSeq_id_HandleSet& h_set)
136 {
137     x_GetTree(idh).FindMatch(idh, h_set);
138 }
139 
140 
HaveReverseMatch(const CSeq_id_Handle & idh)141 bool CSeq_id_Mapper::HaveReverseMatch(const CSeq_id_Handle& idh)
142 {
143     return x_GetTree(idh).HaveReverseMatch(idh);
144 }
145 
146 
GetReverseMatchingHandles(const CSeq_id_Handle & idh,TSeq_id_HandleSet & h_set)147 void CSeq_id_Mapper::GetReverseMatchingHandles(const CSeq_id_Handle& idh,
148                                                TSeq_id_HandleSet& h_set)
149 {
150     x_GetTree(idh).FindReverseMatch(idh, h_set);
151 }
152 
153 
HaveMatchingHandles(const CSeq_id_Handle & idh,EAllowWeakMatch allow_weak_match)154 bool CSeq_id_Mapper::HaveMatchingHandles(const CSeq_id_Handle& idh,
155                                          EAllowWeakMatch allow_weak_match)
156 {
157     if ( HaveMatchingHandles(idh) ) {
158         return true;
159     }
160     if ( allow_weak_match == eNoWeakMatch ) {
161         return false;
162     }
163     const CSeq_id_Which_Tree* base_tree = &x_GetTree(idh);
164     if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(base_tree) ) {
165         return false;
166     }
167     for ( size_t i = 0; i < m_Trees.size(); ++i ) {
168         const CSeq_id_Which_Tree* tree = m_Trees[i];
169         if ( tree == base_tree ) {
170             continue;
171         }
172         if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(tree) ) {
173             continue;
174         }
175         if ( tree == m_Trees[CSeq_id::e_Gi] && i != CSeq_id::e_Gi ) {
176             continue;
177         }
178         if ( tree->HaveMatch(idh) ) {
179             return true;
180         }
181     }
182     return false;
183 }
184 
185 
GetMatchingHandles(const CSeq_id_Handle & idh,TSeq_id_HandleSet & h_set,EAllowWeakMatch allow_weak_match)186 void CSeq_id_Mapper::GetMatchingHandles(const CSeq_id_Handle& idh,
187                                         TSeq_id_HandleSet& h_set,
188                                         EAllowWeakMatch allow_weak_match)
189 {
190     GetMatchingHandles(idh, h_set);
191     if ( allow_weak_match == eNoWeakMatch ) {
192         return;
193     }
194     const CSeq_id_Which_Tree* base_tree = &x_GetTree(idh);
195     if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(base_tree) ) {
196         return;
197     }
198     for ( size_t i = 0; i < m_Trees.size(); ++i ) {
199         const CSeq_id_Which_Tree* tree = m_Trees[i];
200         if ( tree == base_tree ) {
201             continue;
202         }
203         if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(tree) ) {
204             continue;
205         }
206         if ( tree == m_Trees[CSeq_id::e_Gi] && i != CSeq_id::e_Gi ) {
207             continue;
208         }
209         tree->FindMatch(idh, h_set);
210     }
211 }
212 
213 
HaveReverseMatch(const CSeq_id_Handle & idh,EAllowWeakMatch allow_weak_match)214 bool CSeq_id_Mapper::HaveReverseMatch(const CSeq_id_Handle& idh,
215                                       EAllowWeakMatch allow_weak_match)
216 {
217     if ( HaveReverseMatch(idh) ) {
218         return true;
219     }
220     if ( allow_weak_match == eNoWeakMatch ) {
221         return false;
222     }
223     const CSeq_id_Which_Tree* base_tree = &x_GetTree(idh);
224     if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(base_tree) ) {
225         return false;
226     }
227     for ( size_t i = 0; i < m_Trees.size(); ++i ) {
228         const CSeq_id_Which_Tree* tree = m_Trees[i];
229         if ( tree == base_tree ) {
230             continue;
231         }
232         if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(tree) ) {
233             continue;
234         }
235         if ( tree == m_Trees[CSeq_id::e_Gi] && i != CSeq_id::e_Gi ) {
236             continue;
237         }
238         if ( tree->HaveReverseMatch(idh) ) {
239             return true;
240         }
241     }
242     return false;
243 }
244 
245 
GetReverseMatchingHandles(const CSeq_id_Handle & idh,TSeq_id_HandleSet & h_set,EAllowWeakMatch allow_weak_match)246 void CSeq_id_Mapper::GetReverseMatchingHandles(const CSeq_id_Handle& idh,
247                                                TSeq_id_HandleSet& h_set,
248                                                EAllowWeakMatch allow_weak_match)
249 {
250     GetReverseMatchingHandles(idh, h_set);
251     if ( allow_weak_match == eNoWeakMatch ) {
252         return;
253     }
254     const CSeq_id_Which_Tree* base_tree = &x_GetTree(idh);
255     if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(base_tree) ) {
256         return;
257     }
258     for ( size_t i = 0; i < m_Trees.size(); ++i ) {
259         CSeq_id_Which_Tree* tree = m_Trees[i];
260         if ( tree == base_tree ) {
261             continue;
262         }
263         if ( !dynamic_cast<const CSeq_id_Textseq_Tree*>(tree) ) {
264             continue;
265         }
266         if ( tree == m_Trees[CSeq_id::e_Gi] && i != CSeq_id::e_Gi ) {
267             continue;
268         }
269         tree->FindReverseMatch(idh, h_set);
270     }
271 }
272 
273 
GetMatchingHandlesStr(string sid,TSeq_id_HandleSet & h_set)274 void CSeq_id_Mapper::GetMatchingHandlesStr(string sid,
275                                            TSeq_id_HandleSet& h_set)
276 {
277     if (sid.find('|') != string::npos) {
278         NCBI_THROW(CSeq_id_MapperException, eSymbolError,
279                    "Symbol \'|\' is not supported here");
280     }
281 
282     ITERATE(TTrees, tree_it, m_Trees) {
283         (*tree_it)->FindMatchStr(sid, h_set);
284     }
285 }
286 
287 
x_Match(const CSeq_id_Handle & h1,const CSeq_id_Handle & h2)288 bool CSeq_id_Mapper::x_Match(const CSeq_id_Handle& h1,
289                                 const CSeq_id_Handle& h2)
290 {
291     CSeq_id_Which_Tree& tree1 = x_GetTree(h1);
292     CSeq_id_Which_Tree& tree2 = x_GetTree(h2);
293     if ( &tree1 != &tree2 )
294         return false;
295 
296     // Compare versions if any
297     return tree1.Match(h1, h2);
298 }
299 
300 
x_IsBetter(const CSeq_id_Handle & h1,const CSeq_id_Handle & h2)301 bool CSeq_id_Mapper::x_IsBetter(const CSeq_id_Handle& h1,
302                                 const CSeq_id_Handle& h2)
303 {
304     CSeq_id_Which_Tree& tree1 = x_GetTree(h1);
305     CSeq_id_Which_Tree& tree2 = x_GetTree(h2);
306     if ( &tree1 != &tree2 )
307         return false;
308 
309     // Compare versions if any
310     return tree1.IsBetterVersion(h1, h2);
311 }
312 
313 
Dump(CNcbiOstream & out,EDumpDetails details) const314 size_t CSeq_id_Mapper::Dump(CNcbiOstream& out, EDumpDetails details) const
315 {
316     size_t total_bytes = 0;
317     for ( size_t i = 0; i < m_Trees.size(); ++i ) {
318         size_t bytes = m_Trees[i]->Dump(out, CSeq_id::E_Choice(i), details);
319         total_bytes += bytes;
320     }
321     if ( details >= eDumpTotalBytes ) {
322         out << "Total CSeq_id_Mapper bytes: "<<total_bytes<<endl;
323     }
324     return total_bytes;
325 }
326 
327 
328 END_SCOPE(objects)
329 END_NCBI_SCOPE
330