1 /* $Id: SeqTable_sparse_index.cpp 616043 2020-09-09 15:14:11Z ucko $
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  *   Support for SeqTable-sparse-index ASN.1 type
30  *   API to work with different representations of sparse index
31  *
32  * Remark:
33  *   This code was originally generated by application DATATOOL
34  *   using the following specifications:
35  *   'seqtable.asn'.
36  */
37 
38 // standard includes
39 #include <ncbi_pch.hpp>
40 
41 // generated includes
42 #include <objects/seqtable/SeqTable_sparse_index.hpp>
43 
44 #include <objects/seqtable/seq_table_exception.hpp>
45 #include <util/bitset/bmfunc.h>
46 #include <util/bitset/bmserial.h>
47 
48 #include <objects/seqtable/impl/delta_cache.hpp>
49 
50 // generated classes
51 
52 BEGIN_NCBI_SCOPE
53 
54 BEGIN_objects_SCOPE // namespace ncbi::objects::
55 
56 // destructor
~CSeqTable_sparse_index(void)57 CSeqTable_sparse_index::~CSeqTable_sparse_index(void)
58 {
59 }
60 
61 
62 #ifdef NCBI_COMPILER_GCC
63 const size_t CSeqTable_sparse_index::kInvalidRow;
64 const size_t CSeqTable_sparse_index::kSkipped;
65 #endif
66 
67 DEFINE_STATIC_MUTEX(sx_PrepareMutex_sparse_index);
68 
69 
sx_CalcByteBitCount(Uint4 word)70 static inline size_t sx_CalcByteBitCount(Uint4 word)
71 {
72     return bm::word_bitcount(word);
73 }
74 
75 
sx_CalcByteBitCount(Uint1 byte)76 static inline size_t sx_CalcByteBitCount(Uint1 byte)
77 {
78     return bm::bit_count_table<true>::_count[byte];
79 }
80 
81 
sx_CalcBlockBitCount(const char * block,size_t size)82 static inline size_t sx_CalcBlockBitCount(const char* block, size_t size)
83 {
84     const bm::word_t* word_block = reinterpret_cast<const bm::word_t*>(block);
85     const bm::word_t* word_block_end = word_block + size/sizeof(bm::word_t);
86     size_t ret = bm::bit_count_min_unroll(word_block, word_block_end);
87 
88     const char* tail_ptr = reinterpret_cast<const char*>(word_block_end);
89     const char* block_end = block + size;
90     for ( ; tail_ptr != block_end; ++tail_ptr ) {
91         ret += sx_CalcByteBitCount(Uint1(*tail_ptr));
92     }
93 
94     return ret;
95 }
96 
97 
98 // return number of the first set bit in a byte
99 // bit 0x80 - 0
100 // bit 0x40 - 1
101 // ...
102 // bit 0x01 - 7
103 // if there are no set bits return kInvalidRow
sx_FindFirstNonZeroBit(Uint1 b)104 static inline size_t sx_FindFirstNonZeroBit(Uint1 b)
105 {
106     for ( size_t i = 0; i < 8; ++i, b <<= 1 ) {
107         if ( b&0x80 ) {
108             return i;
109         }
110     }
111     return CSeqTable_sparse_index::kInvalidRow;
112 }
113 
114 
115 // return number of the next set bit in a byte starting with bit prev_i
116 // bit 0x80 - 0
117 // bit 0x40 - 1
118 // ...
119 // bit 0x01 - 7
120 // if there are no more set bits return kInvalidRow
sx_FindNextNonZeroBit(Uint1 b,size_t prev_i)121 static inline size_t sx_FindNextNonZeroBit(Uint1 b, size_t prev_i)
122 {
123     b <<= prev_i+1;
124     for ( size_t i = prev_i+1; i < 8; ++i, b <<= 1 ) {
125         if ( b&0x80 ) {
126             return i;
127         }
128     }
129     return CSeqTable_sparse_index::kInvalidRow;
130 }
131 
132 
133 // return number of the first non-zero byte in a range
134 // if there are no non-zero bytes return kInvalidRow
sx_FindFirstNonZeroByte(const char * beg,const char * end)135 static inline size_t sx_FindFirstNonZeroByte(const char* beg,
136                                              const char* end)
137 {
138     typedef Uint8 TBig; // faster scan using bigger type than char
139     const char* ptr = beg;
140     // align to bigger type
141     for ( ; ptr != end && reinterpret_cast<size_t>(ptr)%sizeof(TBig); ++ptr ) {
142         if ( *ptr ) {
143             return ptr - beg;
144         }
145     }
146     // scan using bigger type
147     for ( ; ptr+sizeof(TBig) <= end; ptr += sizeof(TBig) ) {
148         if ( *reinterpret_cast<const TBig*>(ptr) != 0 ) {
149             break;
150         }
151     }
152     // scan for exact char position
153     for ( ; ptr != end; ++ptr ) {
154         if ( *ptr ) {
155             return ptr - beg;
156         }
157     }
158     return CSeqTable_sparse_index::kInvalidRow;
159 }
160 
161 
162 // return number of the first non-zero byte in a vector, starting with index
163 // if there are no more non-zero bytes return kInvalidRow
sx_FindFirstNonZeroByte(const vector<char> & bytes,size_t index)164 static inline size_t sx_FindFirstNonZeroByte(const vector<char>& bytes,
165                                              size_t index)
166 {
167     size_t size = bytes.size();
168     const char* ptr = &bytes[0];
169     size_t offset = sx_FindFirstNonZeroByte(ptr+index, ptr+size);
170     if ( offset == CSeqTable_sparse_index::kInvalidRow ) {
171         return CSeqTable_sparse_index::kInvalidRow;
172     }
173     return index + offset;
174 }
175 
176 
177 const size_t CSeqTable_sparse_index::SBitsInfo::kBlockSize = 256;
178 
179 
x_GetBitSetCache(size_t byte_count) const180 size_t CSeqTable_sparse_index::x_GetBitSetCache(size_t byte_count) const
181 {
182     const TBit_set& bytes = GetBit_set();
183     size_t size = bytes.size();
184     CMutexGuard guard(sx_PrepareMutex_sparse_index);
185     if ( !m_Cache ) {
186         m_Cache.Reset(new SBitsInfo);
187     }
188     SBitsInfo& info= dynamic_cast<SBitsInfo&>(*m_Cache);
189     static const size_t kBlockSize = SBitsInfo::kBlockSize;
190     size_t block_index  = byte_count / kBlockSize;
191     size_t block_offset = byte_count % kBlockSize;
192     for ( ; block_index > info.m_BlocksFilled; ) {
193         if ( !info.m_Blocks ) {
194             size_t block_count = size / kBlockSize;
195             info.m_Blocks.reset(new size_t[block_count]);
196         }
197         size_t next_index = info.m_BlocksFilled;
198         size_t count = sx_CalcBlockBitCount(&bytes[next_index*kBlockSize],
199                                             kBlockSize);
200         if ( next_index > 0 ) {
201             count += info.m_Blocks[next_index-1];
202         }
203         info.m_Blocks[next_index] = count;
204         info.m_BlocksFilled = next_index+1;
205     }
206     size_t ret = block_index? info.m_Blocks[block_index-1]: 0;
207     if ( block_offset ) {
208         if ( block_index != info.m_CacheBlockIndex ) {
209             if ( !info.m_CacheBlockInfo ) {
210                 info.m_CacheBlockInfo.reset(new size_t[kBlockSize]);
211             }
212             size_t count = 0;
213             size_t block_pos = block_index*kBlockSize;
214             size_t block_size = min(kBlockSize, size-block_pos);
215             const char* block = &bytes[block_pos];
216             for ( size_t i = 0; i < block_size; ++i ) {
217                 count += sx_CalcByteBitCount(Uint1(block[i]));
218                 info.m_CacheBlockInfo[i] = count;
219             }
220             info.m_CacheBlockIndex = block_index;
221         }
222         ret += info.m_CacheBlockInfo[block_offset-1];
223     }
224     return ret;
225 }
226 
227 
228 /////////////////////////////////////////////////////////////////////////////
229 // CIndexDeltaSumCache
230 /////////////////////////////////////////////////////////////////////////////
231 
232 //#define USE_DELTA_CACHE
233 const size_t CIndexDeltaSumCache::kBlockSize = 128;
234 const size_t CIndexDeltaSumCache::kInvalidRow = CSeqTable_sparse_index::kInvalidRow;
235 const size_t CIndexDeltaSumCache::kBlockTooLow = CIndexDeltaSumCache::kInvalidRow-1;
236 
237 
CIndexDeltaSumCache(size_t size)238 CIndexDeltaSumCache::CIndexDeltaSumCache(size_t size)
239     : m_Blocks(new TValue[(size+kBlockSize-1)/kBlockSize]),
240       m_BlocksFilled(0),
241 #ifdef USE_DELTA_CACHE
242       m_CacheBlockInfo(new TValue[kBlockSize]),
243 #endif
244       m_CacheBlockIndex(size_t(0)-1)
245 {
246 }
247 
248 
~CIndexDeltaSumCache(void)249 CIndexDeltaSumCache::~CIndexDeltaSumCache(void)
250 {
251 }
252 
253 
254 inline
255 CIndexDeltaSumCache::TValue
x_GetDeltaSum2(const TDeltas & deltas,size_t block_index,size_t block_offset)256 CIndexDeltaSumCache::x_GetDeltaSum2(const TDeltas& deltas,
257                                     size_t block_index,
258                                     size_t block_offset)
259 {
260 #ifdef USE_DELTA_CACHE
261     _ASSERT(block_index <= m_BlocksFilled);
262     if ( block_index != m_CacheBlockIndex ) {
263         size_t size = deltas.size();
264         size_t block_pos = block_index*kBlockSize;
265         _ASSERT(block_pos < size);
266         size_t block_size = min(kBlockSize, size-block_pos);
267         _ASSERT(block_offset < block_size);
268         TValue sum = block_index == 0? 0: m_Blocks[block_index-1];
269         const TDeltas::value_type* block = &deltas[block_pos];
270         for ( size_t i = 0; i < block_size; ++i ) {
271             sum += block[i];
272             m_CacheBlockInfo[i] = sum;
273         }
274         m_CacheBlockIndex = block_index;
275         if ( block_index == m_BlocksFilled ) {
276             m_Blocks[block_index] = sum;
277             m_BlocksFilled = block_index+1;
278         }
279     }
280     return m_CacheBlockInfo[block_offset];
281 #else
282     size_t size = deltas.size();
283     size_t block_pos = block_index*kBlockSize;
284     _ASSERT(block_pos < size);
285     size_t block_size = min(kBlockSize, size-block_pos);
286     _ASSERT(block_offset < block_size);
287     TValue sum = block_index == 0? 0: m_Blocks[block_index-1];
288     const TDeltas::value_type* block = &deltas[block_pos];
289     for ( size_t i = 0; i <= block_offset; ++i ) {
290         sum += block[i];
291     }
292     if ( block_index == m_BlocksFilled ) {
293         TValue sum2 = sum;
294         for ( size_t i = block_offset+1; i < block_size; ++i ) {
295             sum2 += block[i];
296         }
297         m_Blocks[block_index] = sum2;
298         m_BlocksFilled = block_index+1;
299     }
300     return sum;
301 #endif
302 }
303 
304 
305 inline
x_FindDeltaSum2(const TDeltas & deltas,size_t block_index,TValue find_sum)306 size_t CIndexDeltaSumCache::x_FindDeltaSum2(const TDeltas& deltas,
307                                             size_t block_index,
308                                             TValue find_sum)
309 {
310     _ASSERT(block_index<=m_BlocksFilled);
311     _ASSERT(block_index==m_BlocksFilled || find_sum<=m_Blocks[block_index]);
312     _ASSERT(block_index==0 || find_sum>m_Blocks[block_index-1]);
313     size_t size = deltas.size();
314     size_t block_pos = block_index*kBlockSize;
315     _ASSERT(block_pos < size);
316     size_t block_size = min(kBlockSize, size-block_pos);
317 #ifdef USE_DELTA_CACHE
318     if ( block_index < m_BlocksFilled && find_sum > m_Blocks[block_index] ) {
319         return kBlockTooLow;
320     }
321     x_GetDeltaSum2(deltas, block_index, 0);
322     _ASSERT(block_index < m_BlocksFilled);
323     if ( find_sum > m_Blocks[block_index] ) {
324         return kBlockTooLow;
325     }
326     _ASSERT(find_sum <= m_Blocks[block_index]);
327     size_t value_index = lower_bound(&m_CacheBlockInfo[0],
328                                      &m_CacheBlockInfo[block_size],
329                                      find_sum) - &m_CacheBlockInfo[0];
330     _ASSERT(value_index < block_size);
331     _ASSERT(find_sum <= m_CacheBlockInfo[value_index]);
332     _ASSERT(value_index==0 || find_sum > m_CacheBlockInfo[value_index-1]);
333     if ( find_sum != m_CacheBlockInfo[value_index] ) {
334         return kInvalidRow;
335     }
336     return block_pos + value_index;
337 #else
338     TValue sum = block_index == 0? 0: m_Blocks[block_index-1];
339     const TDeltas::value_type* block = &deltas[block_pos];
340     for ( size_t i = 0; i < block_size; ++i ) {
341         sum += block[i];
342         if ( sum >= find_sum ) {
343             if ( block_index == m_BlocksFilled ) {
344                 TValue sum2 = sum;
345                 for ( size_t j = i+1; j < block_size; ++j ) {
346                     sum2 += block[j];
347                 }
348                 m_Blocks[block_index] = sum2;
349                 m_BlocksFilled = block_index+1;
350             }
351             return sum > find_sum? kInvalidRow: block_pos+i;
352         }
353     }
354     if ( block_index == m_BlocksFilled ) {
355         m_Blocks[block_index] = sum;
356         m_BlocksFilled = block_index+1;
357     }
358     return kBlockTooLow;
359 #endif
360 }
361 
362 
363 CIndexDeltaSumCache::TValue
GetDeltaSum(const TDeltas & deltas,size_t index)364 CIndexDeltaSumCache::GetDeltaSum(const TDeltas& deltas,
365                                  size_t index)
366 {
367     _ASSERT(index < deltas.size());
368     size_t block_index  = index / kBlockSize;
369     size_t block_offset = index % kBlockSize;
370     while ( block_index >= m_BlocksFilled ) {
371         x_GetDeltaSum2(deltas, m_BlocksFilled, 0);
372     }
373     return x_GetDeltaSum2(deltas, block_index, block_offset);
374 }
375 
376 
FindDeltaSum(const TDeltas & deltas,TValue find_sum)377 size_t CIndexDeltaSumCache::FindDeltaSum(const TDeltas& deltas,
378                                          TValue find_sum)
379 {
380     size_t size = deltas.size();
381     size_t block_index;
382     if ( m_BlocksFilled > 0 && find_sum <= m_Blocks[m_BlocksFilled-1] ) {
383         // sum is within already preprocessed block, locate the block
384         block_index = lower_bound(&m_Blocks[0],
385                                   &m_Blocks[m_BlocksFilled],
386                                   find_sum) - &m_Blocks[0];
387         size_t row = x_FindDeltaSum2(deltas, block_index, find_sum);
388         _ASSERT(row != kBlockTooLow);
389         return row;
390     }
391     else {
392         // preprocess blocks sequentially until row will be within block range
393         for ( ;; ) {
394             block_index = m_BlocksFilled;
395             if ( block_index*kBlockSize >= size ) {
396                 // last block is processed but the required sum is still bigger
397                 return kInvalidRow;
398             }
399             size_t row = x_FindDeltaSum2(deltas, block_index, find_sum);
400             if ( row != kBlockTooLow ) {
401                 return row;
402             }
403         }
404     }
405 }
406 
407 /////////////////////////////////////////////////////////////////////////////
408 
409 
x_GetDeltaCache(void) const410 CIndexDeltaSumCache& CSeqTable_sparse_index::x_GetDeltaCache(void) const
411 {
412     CIndexDeltaSumCache* info =
413         dynamic_cast<CIndexDeltaSumCache*>(m_Cache.GetNCPointerOrNull());
414     if ( !info ) {
415         m_Cache = info = new CIndexDeltaSumCache(GetIndexes_delta().size());
416     }
417     return *info;
418 }
419 
420 
421 inline
x_GetDeltaSum(size_t index) const422 size_t CSeqTable_sparse_index::x_GetDeltaSum(size_t index) const
423 {
424     CMutexGuard guard(sx_PrepareMutex_sparse_index);
425     return x_GetDeltaCache().GetDeltaSum(GetIndexes_delta(), index);
426 }
427 
428 
429 inline
x_FindDeltaSum(size_t sum) const430 size_t CSeqTable_sparse_index::x_FindDeltaSum(size_t sum) const
431 {
432     CMutexGuard guard(sx_PrepareMutex_sparse_index);
433     return x_GetDeltaCache().FindDeltaSum(GetIndexes_delta(), sum);
434 }
435 
436 
GetSize(void) const437 size_t CSeqTable_sparse_index::GetSize(void) const
438 {
439     switch ( Which() ) {
440     case e_Indexes:
441     {
442         const TIndexes& indexes = GetIndexes();
443         return indexes.empty()? 0: indexes.back()+1;
444     }
445     case e_Indexes_delta:
446     {
447         const TIndexes_delta& deltas = GetIndexes_delta();
448         return deltas.empty()? 0: x_GetDeltaSum(deltas.size()-1)+1;
449     }
450     case e_Bit_set:
451         return GetBit_set().size()*8;
452     case e_Bit_set_bvector:
453         return GetBit_set_bvector().GetSize();
454     default:
455         return 0;
456     }
457 }
458 
459 
x_GetFirstRowWithValue(void) const460 size_t CSeqTable_sparse_index::x_GetFirstRowWithValue(void) const
461 {
462     switch ( Which() ) {
463     case e_Indexes:
464     {
465         const TIndexes& indexes = GetIndexes();
466         return indexes.empty()? kInvalidRow: indexes.front();
467     }
468     case e_Indexes_delta:
469     {
470         const TIndexes_delta& deltas = GetIndexes_delta();
471         return deltas.empty()? kInvalidRow: deltas.front();
472     }
473     case e_Bit_set:
474     {
475         const TBit_set& bytes = GetBit_set();
476         size_t byte_index = sx_FindFirstNonZeroByte(bytes, 0);
477         if ( byte_index == kInvalidRow ) {
478             return kInvalidRow;
479         }
480         return byte_index*8 + sx_FindFirstNonZeroBit(Uint1(bytes[byte_index]));
481     }
482     case e_Bit_set_bvector:
483         return GetBit_set_bvector().GetBitVector().get_first();
484     default:
485         return kInvalidRow;
486     }
487 }
488 
489 
x_GetNextRowWithValue(size_t row,size_t value_index) const490 size_t CSeqTable_sparse_index::x_GetNextRowWithValue(size_t row,
491                                                      size_t value_index) const
492 {
493     switch ( Which() ) {
494     case e_Indexes:
495     {
496         const TIndexes& indexes = GetIndexes();
497         return ++value_index >= indexes.size()?
498             kInvalidRow: indexes[value_index];
499     }
500     case e_Indexes_delta:
501     {
502         const TIndexes_delta& deltas = GetIndexes_delta();
503         return ++value_index >= deltas.size()?
504             kInvalidRow: row + deltas[value_index];
505     }
506     case e_Bit_set:
507     {
508         const TBit_set& bytes = GetBit_set();
509         size_t byte_index = row / 8;
510         size_t bit_index = row % 8;
511         bit_index = sx_FindNextNonZeroBit(Uint1(bytes[byte_index]), bit_index);
512         if ( bit_index != kInvalidRow ) {
513             return byte_index*8 + bit_index;
514         }
515         byte_index = sx_FindFirstNonZeroByte(bytes, byte_index + 1);
516         if ( byte_index == kInvalidRow ) {
517             return kInvalidRow;
518         }
519         return byte_index*8 + sx_FindFirstNonZeroBit(Uint1(bytes[byte_index]));
520     }
521     case e_Bit_set_bvector:
522     {
523         row = GetBit_set_bvector().GetBitVector().get_next(row);
524         return row == 0? kInvalidRow: row;
525     }
526     default:
527         return kInvalidRow;
528     };
529 }
530 
531 
GetIndexAt(size_t row) const532 size_t CSeqTable_sparse_index::GetIndexAt(size_t row) const
533 {
534     switch ( Which() ) {
535     case e_Indexes:
536     {
537         const TIndexes& indexes = GetIndexes();
538         TIndexes::const_iterator iter =
539             lower_bound(indexes.begin(), indexes.end(), row);
540         if ( iter != indexes.end() && *iter == row ) {
541             return iter - indexes.begin();
542         }
543         else {
544             return kSkipped;
545         }
546     }
547     case e_Indexes_delta:
548         return x_FindDeltaSum(row);
549     case e_Bit_set:
550     {
551         const TBit_set& bytes = GetBit_set();
552         size_t byte_index = row/8;
553         if ( byte_index >= bytes.size() ) {
554             return kSkipped;
555         }
556         Uint1 byte = bytes[byte_index];
557         size_t bit_index = row%8; // most significant bit has index 0
558         if ( !((byte<<bit_index)&0x80) ) {
559             return kSkipped;
560         }
561         size_t count = sx_CalcByteBitCount(Uint1(byte>>(8-bit_index)));
562         if ( byte_index ) {
563             count += x_GetBitSetCache(byte_index);
564         }
565         return count;
566     }
567     case e_Bit_set_bvector:
568     {
569         const bm::bvector<>& bv = GetBit_set_bvector().GetBitVector();
570         if ( row >= bv.size() || !bv.get_bit(row) ) {
571             return kSkipped;
572         }
573         return row == 0? 0: bv.count_range(0, row-1);
574     }
575     default:
576         return kSkipped;
577     }
578 }
579 
580 
HasValueAt(size_t row) const581 bool CSeqTable_sparse_index::HasValueAt(size_t row) const
582 {
583     switch ( Which() ) {
584     case e_Indexes:
585     {
586         const TIndexes& indexes = GetIndexes();
587         TIndexes::const_iterator iter =
588             lower_bound(indexes.begin(), indexes.end(), row);
589         return iter != indexes.end() && *iter == row;
590     }
591     case e_Indexes_delta:
592         return x_FindDeltaSum(row) != kInvalidRow;
593     case e_Bit_set:
594     {
595         const TBit_set& bits = GetBit_set();
596         size_t i = row/8, j = row%8;
597         return i < bits.size() && ((bits[i]<<j)&0x80) != 0;
598     }
599     case e_Bit_set_bvector:
600     {
601         const bm::bvector<>& bv = GetBit_set_bvector().GetBitVector();
602         return row < bv.size() && bv.get_bit(row);
603     }
604     default:
605         return false;
606     }
607 }
608 
609 
ChangeTo(E_Choice type)610 void CSeqTable_sparse_index::ChangeTo(E_Choice type)
611 {
612     if ( Which() == type ) {
613         return;
614     }
615     switch ( type ) {
616     case e_Indexes:
617         ChangeToIndexes();
618         break;
619     case e_Indexes_delta:
620         ChangeToIndexes_delta();
621         break;
622     case e_Bit_set:
623         ChangeToBit_set();
624         break;
625     case e_Bit_set_bvector:
626         ChangeToBit_set_bvector();
627         break;
628     default:
629         NCBI_THROW(CSeqTableException, eIncompatibleValueType,
630                    "CSeqTable_sparse_index::ChangeTo(): "
631                    "requested sparse index type is invalid");
632     }
633 }
634 
635 
ChangeToIndexes(void)636 void CSeqTable_sparse_index::ChangeToIndexes(void)
637 {
638     if ( IsIndexes() ) {
639         return;
640     }
641     TIndexes indexes;
642     if ( IsIndexes_delta() ) {
643         // convert delta to running sum
644         indexes.swap(SetIndexes_delta());
645         size_t row = 0;
646         NON_CONST_ITERATE ( TIndexes, it, indexes ) {
647             row += *it;
648             *it = row;
649         }
650     }
651     else {
652         for ( const_iterator it = begin(); it; ++it ) {
653             indexes.push_back(it.GetRow());
654         }
655     }
656     SetIndexes().swap(indexes);
657 }
658 
659 
ChangeToIndexes_delta(void)660 void CSeqTable_sparse_index::ChangeToIndexes_delta(void)
661 {
662     if ( IsIndexes_delta() ) {
663         return;
664     }
665     TIndexes_delta indexes;
666     if ( IsIndexes() ) {
667         // convert to delta
668         indexes.swap(SetIndexes());
669         size_t prev_row = 0;
670         NON_CONST_ITERATE ( TIndexes_delta, it, indexes ) {
671             size_t row = *it;
672             *it = row - prev_row;
673             prev_row = row;
674         }
675     }
676     else {
677         size_t prev_row = 0;
678         for ( const_iterator it = begin(); it; ++it ) {
679             size_t row = it.GetRow();
680             indexes.push_back(row-prev_row);
681             prev_row = row;
682         }
683     }
684     SetIndexes_delta().swap(indexes);
685 }
686 
687 
688 
ChangeToBit_set(void)689 void CSeqTable_sparse_index::ChangeToBit_set(void)
690 {
691     if ( IsBit_set() ) {
692         return;
693     }
694     TBit_set bytes;
695     size_t size = GetSize();
696     if ( size != kInvalidRow ) {
697         bytes.reserve((GetSize()+7)/8);
698     }
699     size_t last_byte_index = 0;
700     Uint1 last_byte = 0;
701     for ( const_iterator it = begin(); it; ++it ) {
702         size_t row = it.GetRow();
703         size_t byte_index = row / 8;
704         if ( byte_index != last_byte_index ) {
705             if ( bytes.capacity() < byte_index+1 ) {
706                 bytes.reserve(max(bytes.capacity(), byte_index+1)*2);
707             }
708             bytes.resize(last_byte_index);
709             bytes.push_back(last_byte);
710             last_byte_index = byte_index;
711             last_byte = 0;
712         }
713         size_t bit_index = row % 8;
714         last_byte |= 0x80 >> bit_index;
715     }
716     if ( last_byte ) {
717         bytes.reserve(last_byte_index+1);
718         bytes.resize(last_byte_index);
719         bytes.push_back(last_byte);
720     }
721     SetBit_set().swap(bytes);
722 }
723 
724 
725 
ChangeToBit_set_bvector(void)726 void CSeqTable_sparse_index::ChangeToBit_set_bvector(void)
727 {
728     if ( IsBit_set_bvector() ) {
729         return;
730     }
731     AutoPtr<bm::bvector<> > bv(new bm::bvector<>(GetSize()));
732     for ( const_iterator it = begin(); it; ++it ) {
733         size_t row = it.GetRow();
734         bv->set_bit(row);
735     }
736     bv->optimize();
737     SetBit_set_bvector().SetBitVector(bv.release());
738 }
739 
740 
741 END_objects_SCOPE // namespace ncbi::objects::
742 
743 END_NCBI_SCOPE
744