~ubuntu-branches/ubuntu/intrepid/bmagic/intrepid

« back to all changes in this revision

Viewing changes to src/bmalgo.h

  • Committer: Bazaar Package Importer
  • Author(s): Andres Salomon
  • Date: 2008-01-05 23:58:56 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080105235856-2kmxhxkz14qjy9ia
Tags: 3.5.0-1
* New upstream release.
* Add tcpp.dpatch.  This stops tests/stress/t.cpp from including
  ncbi_pch.hpp.  As far as I can tell, NCBI is not used at all, I have
  no idea where that came from..
* Silence some lintian warnings; binary-arch-rules-but-pkg-is-arch-indep
  and ancient-standards-version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright(c) 2002-2005 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
3
 
 
4
 
Permission is hereby granted, free of charge, to any person 
5
 
obtaining a copy of this software and associated documentation 
6
 
files (the "Software"), to deal in the Software without restriction, 
7
 
including without limitation the rights to use, copy, modify, merge, 
8
 
publish, distribute, sublicense, and/or sell copies of the Software, 
9
 
and to permit persons to whom the Software is furnished to do so, 
10
 
subject to the following conditions:
11
 
 
12
 
The above copyright notice and this permission notice shall be included 
13
 
in all copies or substantial portions of the Software.
14
 
 
15
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
16
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
17
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
18
 
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
19
 
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
20
 
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
21
 
OTHER DEALINGS IN THE SOFTWARE.
22
 
 
23
 
For more information please visit:  http://bmagic.sourceforge.net
24
 
 
25
 
*/
26
 
 
27
 
#ifndef BMALGO__H__INCLUDED__
28
 
#define BMALGO__H__INCLUDED__
29
 
 
30
 
#include "bm.h"
31
 
#include "bmfunc.h"
32
 
#include "bmdef.h"
33
 
 
34
 
namespace bm
35
 
{
36
 
 
37
 
/*! \defgroup setalgo Set algorithms 
38
 
 *  Set algorithms 
39
 
 *  \ingroup bmagic
40
 
 */
41
 
 
42
 
/*! \defgroup distance Distance metrics 
43
 
 *  Algorithms to compute binary distance metrics
44
 
 *  \ingroup setalgo
45
 
 */
46
 
 
47
 
 
48
 
/*! 
49
 
    \brief    Distance metrics codes defined for vectors A and B
50
 
    \ingroup  distance
51
 
*/
52
 
enum distance_metric
53
 
{
54
 
    COUNT_AND,       //!< (A & B).count()
55
 
    COUNT_XOR,       //!< (A ^ B).count()
56
 
    COUNT_OR,        //!< (A | B).count()
57
 
    COUNT_SUB_AB,    //!< (A - B).count()
58
 
    COUNT_SUB_BA,    //!< (B - A).count()
59
 
    COUNT_A,         //!< A.count()
60
 
    COUNT_B          //!< B.count()
61
 
};
62
 
 
63
 
/*! 
64
 
    \brief Distance metric descriptor, holds metric code and result.
65
 
    \sa distance_operation
66
 
*/
67
 
 
68
 
struct distance_metric_descriptor
69
 
{
70
 
     distance_metric   metric;
71
 
     bm::id_t          result;
72
 
     
73
 
     distance_metric_descriptor(distance_metric m)
74
 
     : metric(m),
75
 
       result(0)
76
 
    {}
77
 
    distance_metric_descriptor()
78
 
    : metric(bm::COUNT_XOR),
79
 
      result(0)
80
 
    {}
81
 
    
82
 
    /*! 
83
 
        \brief Sets metric result to 0
84
 
    */
85
 
    void reset()
86
 
    {
87
 
        result = 0;
88
 
    }
89
 
};
90
 
 
91
 
 
92
 
/*!
93
 
    \brief Internal function computes different distance metrics.
94
 
    \internal 
95
 
    \ingroup  distance
96
 
     
97
 
*/
98
 
inline
99
 
void combine_count_operation_with_block(const bm::word_t* blk,
100
 
                                        unsigned gap,
101
 
                                        const bm::word_t* arg_blk,
102
 
                                        int arg_gap,
103
 
                                        bm::word_t* temp_blk,
104
 
                                        distance_metric_descriptor* dmit,
105
 
                                        distance_metric_descriptor* dmit_end)
106
 
                                            
107
 
{
108
 
     gap_word_t* res=0;
109
 
     
110
 
     gap_word_t* g1 = BMGAP_PTR(blk);
111
 
     gap_word_t* g2 = BMGAP_PTR(arg_blk);
112
 
     
113
 
     if (gap) // first block GAP-type
114
 
     {
115
 
         if (arg_gap)  // both blocks GAP-type
116
 
         {
117
 
             gap_word_t tmp_buf[bm::gap_max_buff_len * 3]; // temporary result
118
 
             
119
 
             for (distance_metric_descriptor* it = dmit;it < dmit_end; ++it)
120
 
             {
121
 
                 distance_metric_descriptor& dmd = *it;
122
 
                 
123
 
                 switch (dmd.metric)
124
 
                 {
125
 
                 case bm::COUNT_AND:
126
 
                     res = gap_operation_and(g1, g2, tmp_buf);
127
 
                     break;
128
 
                 case bm::COUNT_OR:
129
 
                     res = gap_operation_or(g1, g2, tmp_buf);
130
 
                     break;
131
 
                 case bm::COUNT_SUB_AB:
132
 
                     res = gap_operation_sub(g1, g2, tmp_buf); 
133
 
                     break;
134
 
                 case bm::COUNT_SUB_BA:
135
 
                     res = gap_operation_sub(g2, g1, tmp_buf); 
136
 
                     break;
137
 
                 case bm::COUNT_XOR:
138
 
                     res = gap_operation_xor(g1, g2, tmp_buf); 
139
 
                    break;
140
 
                 case bm::COUNT_A:
141
 
                    res = g1;
142
 
                    break;
143
 
                 case bm::COUNT_B:
144
 
                    res = g2;
145
 
                    break;
146
 
                 } // switch
147
 
                 
148
 
                 if (res)
149
 
                     dmd.result += gap_bit_count(res);
150
 
                    
151
 
             } // for it
152
 
             
153
 
             return;
154
 
 
155
 
         }
156
 
         else // first block - GAP, argument - BITSET
157
 
         {
158
 
             for (distance_metric_descriptor* it = dmit;it < dmit_end; ++it)
159
 
             {
160
 
                 distance_metric_descriptor& dmd = *it;
161
 
                 
162
 
                 switch (dmd.metric)
163
 
                 {
164
 
                 case bm::COUNT_AND:
165
 
                     if (arg_blk)
166
 
                        dmd.result += gap_bitset_and_count(arg_blk, g1);
167
 
                     break;
168
 
                 case bm::COUNT_OR:
169
 
                     if (!arg_blk)
170
 
                        dmd.result += gap_bit_count(g1);
171
 
                     else
172
 
                        dmd.result += gap_bitset_or_count(arg_blk, g1); 
173
 
                     break;
174
 
                 case bm::COUNT_SUB_AB:
175
 
                     gap_convert_to_bitset((bm::word_t*) temp_blk, g1);
176
 
                     dmd.result += 
177
 
                       bit_operation_sub_count((bm::word_t*)temp_blk, 
178
 
                          ((bm::word_t*)temp_blk) + bm::set_block_size,
179
 
                           arg_blk);
180
 
                 
181
 
                     break;
182
 
                 case bm::COUNT_SUB_BA:
183
 
                     dmd.metric = bm::COUNT_SUB_AB; // recursive call to SUB_AB
184
 
                     combine_count_operation_with_block(arg_blk,
185
 
                                                        arg_gap,
186
 
                                                        blk,
187
 
                                                        gap,
188
 
                                                        temp_blk,
189
 
                                                        it, it+1);
190
 
                     dmd.metric = bm::COUNT_SUB_BA; // restore status quo
191
 
                     break;
192
 
                 case bm::COUNT_XOR:
193
 
                     if (!arg_blk)
194
 
                        dmd.result += gap_bit_count(g1);
195
 
                     else
196
 
                        dmd.result += gap_bitset_xor_count(arg_blk, g1);
197
 
                     break;
198
 
                 case bm::COUNT_A:
199
 
                    if (g1)
200
 
                        dmd.result += gap_bit_count(g1);
201
 
                    break;
202
 
                 case bm::COUNT_B:
203
 
                    if (arg_blk)
204
 
                    {
205
 
                        dmd.result += 
206
 
                          bit_block_calc_count(arg_blk, 
207
 
                                               arg_blk + bm::set_block_size);
208
 
                    }
209
 
                    break;
210
 
                 } // switch
211
 
                                     
212
 
             } // for it
213
 
             
214
 
             return;
215
 
         
216
 
         }
217
 
     } 
218
 
     else // first block is BITSET-type
219
 
     {     
220
 
         if (arg_gap) // second argument block is GAP-type
221
 
         {
222
 
             for (distance_metric_descriptor* it = dmit;it < dmit_end; ++it)
223
 
             {
224
 
                 distance_metric_descriptor& dmd = *it;
225
 
                 
226
 
                 switch (dmd.metric)
227
 
                 {
228
 
                 case bm::COUNT_AND:
229
 
                     if (blk) 
230
 
                        dmd.result += gap_bitset_and_count(blk, g2);                         
231
 
                     break;
232
 
                 case bm::COUNT_OR:
233
 
                     if (!blk)
234
 
                        dmd.result += gap_bit_count(g2);
235
 
                     else
236
 
                        dmd.result += gap_bitset_or_count(blk, g2);
237
 
                     break;
238
 
                 case bm::COUNT_SUB_AB:
239
 
                     if (blk)
240
 
                        dmd.result += gap_bitset_sub_count(blk, g2);
241
 
                     break;
242
 
                 case bm::COUNT_SUB_BA:
243
 
                     dmd.metric = bm::COUNT_SUB_AB; // recursive call to SUB_AB
244
 
                     combine_count_operation_with_block(arg_blk,
245
 
                                                        arg_gap,
246
 
                                                        blk,
247
 
                                                        gap,
248
 
                                                        temp_blk,
249
 
                                                        it, it+1);
250
 
                     dmd.metric = bm::COUNT_SUB_BA; // restore status quo
251
 
                     break;
252
 
                 case bm::COUNT_XOR:
253
 
                     if (!blk)
254
 
                        dmd.result += gap_bit_count(g2);
255
 
                     else
256
 
                        dmd.result += gap_bitset_xor_count(blk, g2); 
257
 
                    break;
258
 
                 case bm::COUNT_A:
259
 
                    if (blk)
260
 
                    {
261
 
                        dmd.result += 
262
 
                            bit_block_calc_count(blk, 
263
 
                                                 blk + bm::set_block_size);
264
 
                    }
265
 
                    break;
266
 
                 case bm::COUNT_B:
267
 
                    if (g2)
268
 
                        dmd.result += gap_bit_count(g2);
269
 
                    break;
270
 
                 } // switch
271
 
                                     
272
 
             } // for it
273
 
             
274
 
             return;
275
 
         }
276
 
     }
277
 
 
278
 
     // --------------------------------------------
279
 
     //
280
 
     // Here we combine two plain bitblocks 
281
 
 
282
 
     const bm::word_t* blk_end;
283
 
     const bm::word_t* arg_end;
284
 
 
285
 
     blk_end = blk + (bm::set_block_size);
286
 
     arg_end = arg_blk + (bm::set_block_size);
287
 
 
288
 
 
289
 
     for (distance_metric_descriptor* it = dmit; it < dmit_end; ++it)
290
 
     {
291
 
         distance_metric_descriptor& dmd = *it;
292
 
 
293
 
         switch (dmd.metric)
294
 
         {
295
 
         case bm::COUNT_AND:
296
 
             dmd.result += 
297
 
                bit_operation_and_count(blk, blk_end, arg_blk);
298
 
             break;
299
 
         case bm::COUNT_OR:
300
 
             dmd.result += 
301
 
                bit_operation_or_count(blk, blk_end, arg_blk);
302
 
             break;
303
 
         case bm::COUNT_SUB_AB:
304
 
             dmd.result += 
305
 
                bit_operation_sub_count(blk, blk_end, arg_blk);
306
 
             break;
307
 
         case bm::COUNT_SUB_BA:
308
 
             dmd.result += 
309
 
                bit_operation_sub_count(arg_blk, arg_end, blk);
310
 
             break;
311
 
         case bm::COUNT_XOR:
312
 
             dmd.result += 
313
 
                bit_operation_xor_count(blk, blk_end, arg_blk);
314
 
             break;
315
 
         case bm::COUNT_A:
316
 
            if (blk)
317
 
                dmd.result += bit_block_calc_count(blk, blk_end);
318
 
            break;
319
 
         case bm::COUNT_B:
320
 
            if (arg_blk)
321
 
                dmd.result += bit_block_calc_count(arg_blk, arg_end);
322
 
            break;
323
 
         } // switch
324
 
 
325
 
     } // for it
326
 
     
327
 
     
328
 
 
329
 
}
330
 
 
331
 
/*!
332
 
    \brief Distance computing template function.
333
 
 
334
 
    Function receives two bitvectors and an array of distance metrics
335
 
    (metrics pipeline). Function computes all metrics saves result into
336
 
    corresponding pipeline results (distance_metric_descriptor::result)
337
 
    An important detail is that function reuses metric descriptors, 
338
 
    incrementing received values. It allows you to accumulate results 
339
 
    from different calls in the pipeline.
340
 
    
341
 
    \param bv1      - argument bitvector 1 (A)
342
 
    \param bv2      - argument bitvector 2 (B)
343
 
    \param dmit     - pointer to first element of metric descriptors array
344
 
                      Input-Output parameter, receives metric code as input,
345
 
                      computation is added to "result" field
346
 
    \param dmit_end - pointer to (last+1) element of metric descriptors array
347
 
    \ingroup  distance
348
 
    
349
 
*/
350
 
 
351
 
template<class BV>
352
 
void distance_operation(const BV& bv1, 
353
 
                        const BV& bv2, 
354
 
                        distance_metric_descriptor* dmit,
355
 
                        distance_metric_descriptor* dmit_end)
356
 
{
357
 
    const typename BV::blocks_manager_type& bman1 = bv1.get_blocks_manager();
358
 
    const typename BV::blocks_manager_type& bman2 = bv2.get_blocks_manager();
359
 
    
360
 
    bm::word_t* temp_blk = 0;
361
 
    
362
 
    {
363
 
        for (distance_metric_descriptor* it = dmit; it < dmit_end; ++it)
364
 
        {
365
 
            if (it->metric == bm::COUNT_SUB_AB || 
366
 
                it->metric == bm::COUNT_SUB_BA)
367
 
            {
368
 
                temp_blk = bv1.allocate_tempblock();
369
 
                break;
370
 
            }
371
 
        }
372
 
    }
373
 
    
374
 
  
375
 
    bm::word_t*** blk_root = bman1.get_rootblock();
376
 
    unsigned block_idx = 0;
377
 
    unsigned i, j;
378
 
    
379
 
    const bm::word_t* blk;
380
 
    const bm::word_t* arg_blk;
381
 
    bool  blk_gap;
382
 
    bool  arg_gap;
383
 
 
384
 
    BM_SET_MMX_GUARD
385
 
 
386
 
    for (i = 0; i < bman1.top_block_size(); ++i)
387
 
    {
388
 
        bm::word_t** blk_blk = blk_root[i];
389
 
 
390
 
        if (blk_blk == 0) // not allocated
391
 
        {
392
 
            const bm::word_t* const* bvbb = bman2.get_topblock(i);
393
 
            if (bvbb == 0) 
394
 
            {
395
 
                block_idx += bm::set_array_size;
396
 
                continue;
397
 
            }
398
 
 
399
 
            blk = 0;
400
 
            blk_gap = false;
401
 
 
402
 
            for (j = 0; j < bm::set_array_size; ++j,++block_idx)
403
 
            {                
404
 
                arg_blk = bman2.get_block(i, j);
405
 
                arg_gap = BM_IS_GAP(bman2, arg_blk, block_idx);
406
 
 
407
 
                if (!arg_blk) 
408
 
                    continue;
409
 
                combine_count_operation_with_block(blk, blk_gap,
410
 
                                                   arg_blk, arg_gap,
411
 
                                                   temp_blk,
412
 
                                                   dmit, dmit_end);
413
 
            } // for j
414
 
            continue;
415
 
        }
416
 
 
417
 
        for (j = 0; j < bm::set_array_size; ++j, ++block_idx)
418
 
        {
419
 
            blk = blk_blk[j];
420
 
            arg_blk = bman2.get_block(i, j);
421
 
 
422
 
            if (blk == 0 && arg_blk == 0)
423
 
                continue;
424
 
                
425
 
            arg_gap = BM_IS_GAP(bman2, arg_blk, block_idx);
426
 
            blk_gap = BM_IS_GAP(bman1, blk, block_idx);
427
 
            
428
 
            combine_count_operation_with_block(blk, blk_gap,
429
 
                                               arg_blk, arg_gap,
430
 
                                               temp_blk,
431
 
                                               dmit, dmit_end);
432
 
            
433
 
 
434
 
        } // for j
435
 
 
436
 
    } // for i
437
 
    
438
 
    if (temp_blk)
439
 
    {
440
 
        bv1.free_tempblock(temp_blk);
441
 
    }
442
 
 
443
 
}
444
 
 
445
 
 
446
 
 
447
 
/*!
448
 
   \brief Computes bitcount of AND operation of two bitsets
449
 
   \param bv1 - Argument bit-vector.
450
 
   \param bv2 - Argument bit-vector.
451
 
   \return bitcount of the result
452
 
   \ingroup  distance
453
 
*/
454
 
template<class BV>
455
 
bm::id_t count_and(const BV& bv1, const BV& bv2)
456
 
{
457
 
    distance_metric_descriptor dmd(bm::COUNT_AND);
458
 
    
459
 
    distance_operation(bv1, bv2, &dmd, &dmd+1);
460
 
    return dmd.result;
461
 
}
462
 
 
463
 
 
464
 
/*!
465
 
   \brief Computes bitcount of XOR operation of two bitsets
466
 
   \param bv1 - Argument bit-vector.
467
 
   \param bv2 - Argument bit-vector.
468
 
   \return bitcount of the result
469
 
   \ingroup  distance
470
 
*/
471
 
template<class BV>
472
 
bm::id_t count_xor(const BV& bv1, const BV& bv2)
473
 
{
474
 
    distance_metric_descriptor dmd(bm::COUNT_XOR);
475
 
    
476
 
    distance_operation(bv1, bv2, &dmd, &dmd+1);
477
 
    return dmd.result;
478
 
}
479
 
 
480
 
 
481
 
/*!
482
 
   \brief Computes bitcount of SUB operation of two bitsets
483
 
   \param bv1 - Argument bit-vector.
484
 
   \param bv2 - Argument bit-vector.
485
 
   \return bitcount of the result
486
 
   \ingroup  distance
487
 
*/
488
 
template<class BV>
489
 
bm::id_t count_sub(const BV& bv1, const BV& bv2)
490
 
{
491
 
    distance_metric_descriptor dmd(bm::COUNT_SUB_AB);
492
 
    
493
 
    distance_operation(bv1, bv2, &dmd, &dmd+1);
494
 
    return dmd.result;
495
 
}
496
 
 
497
 
 
498
 
/*!    
499
 
   \brief Computes bitcount of OR operation of two bitsets
500
 
   \param bv1 - Argument bit-vector.
501
 
   \param bv2 - Argument bit-vector.
502
 
   \return bitcount of the result
503
 
   \ingroup  distance
504
 
*/
505
 
template<class BV>
506
 
bm::id_t count_or(const BV& bv1, const BV& bv2)
507
 
{
508
 
    distance_metric_descriptor dmd(bm::COUNT_OR);
509
 
    
510
 
    distance_operation(bv1, bv2, &dmd, &dmd+1);
511
 
    return dmd.result;
512
 
}
513
 
 
514
 
 
515
 
/**
516
 
    \brief Internal algorithms scans the input for the block range limit
517
 
    \internal
518
 
*/
519
 
template<class It>
520
 
It block_range_scan(It  first, It last, unsigned nblock, unsigned* max_id)
521
 
{
522
 
    It right;
523
 
    for (right = first; right != last; ++right)
524
 
    {
525
 
        unsigned v = unsigned(*right);
526
 
        BM_ASSERT(v < bm::id_max);
527
 
        if (v >= *max_id)
528
 
            *max_id = v;
529
 
        unsigned nb = v >> bm::set_block_shift;
530
 
        if (nb != nblock)
531
 
            break;
532
 
    }
533
 
    return right;
534
 
}
535
 
 
536
 
/**
537
 
    \brief OR Combine bitvector and the iterable sequence 
538
 
 
539
 
    Algorithm combines bvector with sequence of integers 
540
 
    (represents another set). When the agrument set is sorted 
541
 
    this method can give serious increase in performance.
542
 
    
543
 
    \param bv     - destination bitvector
544
 
    \param first  - first element of the iterated sequence
545
 
    \param last   - last element of the iterated sequence
546
 
    
547
 
    \ingroup setalgo
548
 
*/
549
 
template<class BV, class It>
550
 
void combine_or(BV& bv, It  first, It last)
551
 
{
552
 
    typename BV::blocks_manager_type& bman = bv.get_blocks_manager();
553
 
    unsigned max_id = bv.size();
554
 
 
555
 
    while (first < last)
556
 
    {
557
 
        unsigned nblock = unsigned((*first) >> bm::set_block_shift);     
558
 
        It right = block_range_scan(first, last, nblock, &max_id);
559
 
 
560
 
        if (max_id >= bv.size())
561
 
            bv.resize(max_id + 1);
562
 
 
563
 
        // now we have one in-block array of bits to set
564
 
        
565
 
        label1:
566
 
        
567
 
        int block_type;
568
 
        bm::word_t* blk = 
569
 
            bman.check_allocate_block(nblock, 
570
 
                                      true, 
571
 
                                      bv.get_new_blocks_strat(), 
572
 
                                      &block_type);
573
 
        if (!blk) 
574
 
            continue;
575
 
                        
576
 
        if (block_type == 1) // gap
577
 
        {            
578
 
            bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
579
 
            unsigned threshold = bm::gap_limit(gap_blk, bman.glen());
580
 
            
581
 
            for (; first < right; ++first)
582
 
            {
583
 
                unsigned is_set;
584
 
                unsigned nbit   = (*first) & bm::set_block_mask; 
585
 
                
586
 
                unsigned new_block_len =
587
 
                    gap_set_value(true, gap_blk, nbit, &is_set);
588
 
                if (new_block_len > threshold) 
589
 
                {
590
 
                    bman.extend_gap_block(nblock, gap_blk);
591
 
                    ++first;
592
 
                    goto label1;  // block pointer changed - goto reset
593
 
                }
594
 
            }
595
 
        }
596
 
        else // bit block
597
 
        {
598
 
            for (; first < right; ++first)
599
 
            {
600
 
                unsigned nbit   = unsigned(*first & bm::set_block_mask); 
601
 
                unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
602
 
                nbit &= bm::set_word_mask;
603
 
                blk[nword] |= (bm::word_t)1 << nbit;
604
 
            } // for
605
 
        }
606
 
    } // while
607
 
    
608
 
    bv.forget_count();
609
 
}
610
 
 
611
 
 
612
 
/**
613
 
    \brief XOR Combine bitvector and the iterable sequence 
614
 
 
615
 
    Algorithm combines bvector with sequence of integers 
616
 
    (represents another set). When the agrument set is sorted 
617
 
    this method can give serious increase in performance.
618
 
    
619
 
    \param bv     - destination bitvector
620
 
    \param first  - first element of the iterated sequence
621
 
    \param last   - last element of the iterated sequence
622
 
    
623
 
    \ingroup setalgo
624
 
*/
625
 
template<class BV, class It>
626
 
void combine_xor(BV& bv, It  first, It last)
627
 
{
628
 
    typename BV::blocks_manager_type& bman = bv.get_blocks_manager();
629
 
    unsigned max_id = bv.size();
630
 
 
631
 
    while (first < last)
632
 
    {
633
 
        unsigned nblock = unsigned((*first) >> bm::set_block_shift);     
634
 
        It right = block_range_scan(first, last, nblock, &max_id);
635
 
 
636
 
        if (max_id >= bv.size())
637
 
            bv.resize(max_id + 1);
638
 
 
639
 
        // now we have one in-block array of bits to set
640
 
        
641
 
        label1:
642
 
        
643
 
        int block_type;
644
 
        bm::word_t* blk = 
645
 
            bman.check_allocate_block(nblock, 
646
 
                                      true, 
647
 
                                      bv.get_new_blocks_strat(), 
648
 
                                      &block_type,
649
 
                                      false /* no null return */);
650
 
        BM_ASSERT(blk); 
651
 
                        
652
 
        if (block_type == 1) // gap
653
 
        {
654
 
            bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
655
 
            unsigned threshold = bm::gap_limit(gap_blk, bman.glen());
656
 
            
657
 
            for (; first < right; ++first)
658
 
            {
659
 
                unsigned is_set;
660
 
                unsigned nbit   = (*first) & bm::set_block_mask; 
661
 
                
662
 
                is_set = gap_test(gap_blk, nbit);
663
 
                BM_ASSERT(is_set <= 1);
664
 
                is_set ^= 1; 
665
 
                
666
 
                unsigned new_block_len =
667
 
                    gap_set_value(is_set, gap_blk, nbit, &is_set);
668
 
                if (new_block_len > threshold) 
669
 
                {
670
 
                    bman.extend_gap_block(nblock, gap_blk);
671
 
                    ++first;
672
 
                    goto label1;  // block pointer changed - goto reset
673
 
                }
674
 
            }
675
 
        }
676
 
        else // bit block
677
 
        {
678
 
            for (; first < right; ++first)
679
 
            {
680
 
                unsigned nbit   = unsigned(*first & bm::set_block_mask); 
681
 
                unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
682
 
                nbit &= bm::set_word_mask;
683
 
                blk[nword] ^= (bm::word_t)1 << nbit;
684
 
            } // for
685
 
        }
686
 
    } // while
687
 
    
688
 
    bv.forget_count();
689
 
}
690
 
 
691
 
 
692
 
 
693
 
/**
694
 
    \brief SUB Combine bitvector and the iterable sequence 
695
 
 
696
 
    Algorithm combines bvector with sequence of integers 
697
 
    (represents another set). When the agrument set is sorted 
698
 
    this method can give serious increase in performance.
699
 
    
700
 
    \param bv     - destination bitvector
701
 
    \param first  - first element of the iterated sequence
702
 
    \param last   - last element of the iterated sequence
703
 
    
704
 
    \ingroup setalgo
705
 
*/
706
 
template<class BV, class It>
707
 
void combine_sub(BV& bv, It  first, It last)
708
 
{
709
 
    typename BV::blocks_manager_type& bman = bv.get_blocks_manager();
710
 
    unsigned max_id = bv.size();
711
 
 
712
 
    while (first < last)
713
 
    {
714
 
        unsigned nblock = unsigned((*first) >> bm::set_block_shift);     
715
 
        It right = block_range_scan(first, last, nblock, &max_id);
716
 
 
717
 
        if (max_id >= bv.size())
718
 
            bv.resize(max_id + 1);
719
 
 
720
 
        // now we have one in-block array of bits to set
721
 
        
722
 
        label1:
723
 
        
724
 
        int block_type;
725
 
        bm::word_t* blk = 
726
 
            bman.check_allocate_block(nblock, 
727
 
                                      false, 
728
 
                                      bv.get_new_blocks_strat(), 
729
 
                                      &block_type);
730
 
 
731
 
        if (!blk)
732
 
            continue;
733
 
                        
734
 
        if (block_type == 1) // gap
735
 
        {
736
 
            bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
737
 
            unsigned threshold = bm::gap_limit(gap_blk, bman.glen());
738
 
            
739
 
            for (; first < right; ++first)
740
 
            {
741
 
                unsigned is_set;
742
 
                unsigned nbit   = (*first) & bm::set_block_mask; 
743
 
                
744
 
                is_set = gap_test(gap_blk, nbit);
745
 
                if (!is_set)
746
 
                    continue;
747
 
                
748
 
                unsigned new_block_len =
749
 
                    gap_set_value(false, gap_blk, nbit, &is_set);
750
 
                if (new_block_len > threshold) 
751
 
                {
752
 
                    bman.extend_gap_block(nblock, gap_blk);
753
 
                    ++first;
754
 
                    goto label1;  // block pointer changed - goto reset
755
 
                }
756
 
            }
757
 
        }
758
 
        else // bit block
759
 
        {
760
 
            for (; first < right; ++first)
761
 
            {
762
 
                unsigned nbit   = unsigned(*first & bm::set_block_mask); 
763
 
                unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
764
 
                nbit &= bm::set_word_mask;
765
 
                blk[nword] &= ~((bm::word_t)1 << nbit);
766
 
            } // for
767
 
        }
768
 
    } // while
769
 
    
770
 
    bv.forget_count();
771
 
}
772
 
 
773
 
/**
774
 
    \brief AND Combine bitvector and the iterable sequence 
775
 
 
776
 
    Algorithm combines bvector with sequence of integers 
777
 
    (represents another set). When the agrument set is sorted 
778
 
    this method can give serious increase in performance.
779
 
    
780
 
    \param bv     - destination bitvector
781
 
    \param first  - first element of the iterated sequence
782
 
    \param last   - last element of the iterated sequence
783
 
    
784
 
    \ingroup setalgo
785
 
*/
786
 
template<class BV, class It>
787
 
void combine_and(BV& bv, It  first, It last)
788
 
{
789
 
    BV bv_tmp;
790
 
    combine_or(bv_tmp, first, last);
791
 
    bv &= bv_tmp;
792
 
}
793
 
 
794
 
/*!
795
 
    \brief Compute number of bit intervals (GAPs) in the bitvector
796
 
    
797
 
    Algorithm traverses bit vector and count number of uninterrupted
798
 
    intervals of 1s and 0s.
799
 
    <pre>
800
 
    For example: 
801
 
      00001111100000 - gives us 3 intervals
802
 
      10001111100000 - 4 intervals
803
 
      00000000000000 - 1 interval
804
 
      11111111111111 - 1 interval
805
 
    </pre>
806
 
    \return Number of intervals
807
 
    \ingroup setalgo
808
 
*/
809
 
template<class BV>
810
 
bm::id_t count_intervals(const BV& bv)
811
 
{
812
 
    const typename BV::blocks_manager_type& bman = bv.get_blocks_manager();
813
 
 
814
 
    bm::word_t*** blk_root = bman.get_rootblock();
815
 
    typename BV::blocks_manager_type::block_count_change_func func(bman);
816
 
    for_each_block(blk_root, bman.top_block_size(), bm::set_array_size, func);
817
 
 
818
 
    return func.count();        
819
 
}
820
 
 
821
 
/*!
822
 
    \brief Export bitset from an array of binary data representing
823
 
    the bit vector. 
824
 
 
825
 
    Input array can be array of ints, chars or other native C types.
826
 
    Method works with iterators, which makes it compatible with 
827
 
    STL containers and C arrays
828
 
 
829
 
    \param bv     - destination bitvector
830
 
    \param first  - first element of the iterated sequence
831
 
    \param last   - last element of the iterated sequence
832
 
 
833
 
    \ingroup setalgo
834
 
*/
835
 
template<class BV, class It>
836
 
void export_array(BV& bv, It first, It last)
837
 
{
838
 
    typename BV::blocks_manager_type& bman = bv.get_blocks_manager();
839
 
    unsigned inp_word_size = sizeof(*first);
840
 
    size_t array_size = last - first;
841
 
    size_t bit_cnt = array_size * inp_word_size * 8;
842
 
    int block_type;
843
 
    bm::word_t tmp;
844
 
    unsigned b1, b2, b3, b4;
845
 
 
846
 
    if (bit_cnt >= bv.size())
847
 
                bv.resize((bm::id_t)bit_cnt + 1);
848
 
    else 
849
 
                bv.set_range((bm::id_t)bit_cnt, bv.size() - 1, false);
850
 
    
851
 
    switch (inp_word_size)
852
 
    {
853
 
    case 1:
854
 
        {
855
 
            size_t word_cnt = array_size / 4;
856
 
            for (unsigned i = 0; i < bm::set_total_blocks; ++i)
857
 
            {
858
 
                bm::word_t* blk = 
859
 
                    bman.check_allocate_block(i, 
860
 
                                              false, 
861
 
                                              BM_BIT, 
862
 
                                              &block_type,
863
 
                                              false /*no NULL ret*/);
864
 
                if (block_type == 1) // gap
865
 
                {
866
 
                    blk = bman.convert_gap2bitset(i, BMGAP_PTR(blk));
867
 
                }
868
 
                
869
 
                bm::word_t* wrd_ptr = blk;
870
 
                if (word_cnt >= bm::set_block_size) {
871
 
                    bm::word_t* wrd_end = blk + bm::set_block_size;
872
 
                    do {
873
 
                        b1 = *first++; b2 = *first++;
874
 
                        b3 = *first++; b4 = *first++;
875
 
                        tmp = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
876
 
                        *wrd_ptr++ = tmp;
877
 
                    } while (wrd_ptr < wrd_end);
878
 
                    word_cnt -= bm::set_block_size;
879
 
                } 
880
 
                else 
881
 
                {
882
 
                    size_t to_convert = last - first;
883
 
                    for (size_t j = 0; j < to_convert / 4; ++j)
884
 
                    {
885
 
                        b1 = *first++; b2 = *first++;
886
 
                        b3 = *first++; b4 = *first++;
887
 
                        tmp = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
888
 
                        *wrd_ptr++ = tmp;
889
 
                    }
890
 
                    while (1)
891
 
                    {
892
 
                        if (first == last) break;
893
 
                        *wrd_ptr = *first++;
894
 
                        if (first == last) break;
895
 
                        *wrd_ptr |= (*first++) << 8;
896
 
                        if (first == last) break;
897
 
                        *wrd_ptr |= (*first++) << 16;
898
 
                        if (first == last) break;
899
 
                        *wrd_ptr |= (*first++) << 24;
900
 
                        ++wrd_ptr;
901
 
                    }
902
 
                }
903
 
                if (first == last) break;
904
 
            } // for
905
 
        }
906
 
        break;
907
 
    case 2:
908
 
        {
909
 
            size_t word_cnt = array_size / 2;
910
 
            for (unsigned i = 0; i < bm::set_total_blocks; ++i)
911
 
            {
912
 
                bm::word_t* blk = 
913
 
                    bman.check_allocate_block(i, 
914
 
                                              false, 
915
 
                                              BM_BIT, 
916
 
                                              &block_type,
917
 
                                              false /*no NULL ret*/);
918
 
                if (block_type == 1) // gap
919
 
                {
920
 
                    blk = bman.convert_gap2bitset(i, BMGAP_PTR(blk));
921
 
                }
922
 
                
923
 
                bm::word_t* wrd_ptr = blk;
924
 
                if (word_cnt >= bm::set_block_size) {
925
 
                    bm::word_t* wrd_end = blk + bm::set_block_size;
926
 
                    do {
927
 
                        b1 = *first++; b2 = *first++;
928
 
                        tmp = b1 | (b2 << 16);
929
 
                        *wrd_ptr++ = tmp;
930
 
                    } while (wrd_ptr < wrd_end);
931
 
                    word_cnt -= bm::set_block_size;
932
 
                } 
933
 
                else 
934
 
                {
935
 
                    size_t to_convert = last - first;
936
 
                    for (unsigned j = 0; j < to_convert / 2; ++j)
937
 
                    {
938
 
                        b1 = *first++; b2 = *first++;
939
 
                        tmp = b1 | (b2 << 16);
940
 
                        *wrd_ptr++ = tmp;
941
 
                    }
942
 
                    while (1)
943
 
                    {
944
 
                        if (first == last) break;
945
 
                        *wrd_ptr = *first++;
946
 
                        if (first == last) break;
947
 
                        *wrd_ptr |= (*first++) << 16;
948
 
                        ++wrd_ptr;
949
 
                    }
950
 
                }
951
 
                if (first == last) break;
952
 
            } // for
953
 
        }
954
 
        break;
955
 
    case 4:
956
 
        {
957
 
            size_t word_cnt = array_size;
958
 
            for (unsigned i = 0; i < bm::set_total_blocks; ++i)
959
 
            {
960
 
                bm::word_t* blk = 
961
 
                    bman.check_allocate_block(i, 
962
 
                                              false, 
963
 
                                              BM_BIT, 
964
 
                                              &block_type,
965
 
                                              false /*no NULL ret*/);
966
 
                if (block_type == 1) // gap
967
 
                {
968
 
                    blk = bman.convert_gap2bitset(i, BMGAP_PTR(blk));
969
 
                }
970
 
                
971
 
                bm::word_t* wrd_ptr = blk;
972
 
                if (word_cnt >= bm::set_block_size) {
973
 
                    bm::word_t* wrd_end = blk + bm::set_block_size;
974
 
                    do {
975
 
                        *wrd_ptr++ = *first++;
976
 
                    } while (wrd_ptr < wrd_end);
977
 
                    word_cnt -= bm::set_block_size;
978
 
                } 
979
 
                else 
980
 
                {
981
 
                    while (1)
982
 
                    {
983
 
                        if (first == last) break;
984
 
                        *wrd_ptr = *first++;
985
 
                        ++wrd_ptr;
986
 
                    }
987
 
                }
988
 
                if (first == last) break;
989
 
            } // for
990
 
        }
991
 
        break;
992
 
    default:
993
 
        BM_ASSERT(0);
994
 
    } // switch
995
 
 
996
 
}
997
 
 
998
 
 
999
 
} // namespace bm
1000
 
 
1001
 
#include "bmundef.h"
1002
 
 
1003
 
#endif
 
1
/*
 
2
Copyright(c) 2002-2005 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
 
3
 
 
4
Permission is hereby granted, free of charge, to any person 
 
5
obtaining a copy of this software and associated documentation 
 
6
files (the "Software"), to deal in the Software without restriction, 
 
7
including without limitation the rights to use, copy, modify, merge, 
 
8
publish, distribute, sublicense, and/or sell copies of the Software, 
 
9
and to permit persons to whom the Software is furnished to do so, 
 
10
subject to the following conditions:
 
11
 
 
12
The above copyright notice and this permission notice shall be included 
 
13
in all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 
16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 
17
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 
18
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 
19
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 
21
OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
For more information please visit:  http://bmagic.sourceforge.net
 
24
 
 
25
*/
 
26
 
 
27
#ifndef BMALGO__H__INCLUDED__
 
28
#define BMALGO__H__INCLUDED__
 
29
 
 
30
#include "bm.h"
 
31
#include "bmfunc.h"
 
32
#include "bmdef.h"
 
33
 
 
34
#include "bmalgo_impl.h"
 
35
 
 
36
#include "bmundef.h"
 
37
 
 
38
#endif