1 #ifndef BMBMATRIX__H__INCLUDED__
2 #define BMBMATRIX__H__INCLUDED__
3 /*
4 Copyright(c) 2002-2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10     http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 For more information please visit:  http://bitmagic.io
19 */
20 
21 /*! \file bmbmatrix.h
22     \brief basic bit-matrix class and utilities
23 */
24 
25 #include <stddef.h>
26 #include "bmconst.h"
27 
28 #ifndef BM_NO_STL
29 #include <stdexcept>
30 #endif
31 
32 #include "bm.h"
33 #include "bmtrans.h"
34 #include "bmdef.h"
35 
36 
37 
38 namespace bm
39 {
40 
41 /**
42     Basic dense bit-matrix class.
43 
44     Container of row-major bit-vectors, forming a bit-matrix.
45     This class uses dense form of row storage.
46     It is applicable as a build block for other sparse containers and
47     succinct data structures, implementing high level abstractions.
48 
49     @ingroup bmagic
50     @internal
51 */
52 template<typename BV>
53 class basic_bmatrix
54 {
55 public:
56     typedef BV                                       bvector_type;
57     typedef bvector_type*                            bvector_type_ptr;
58     typedef const bvector_type*                      bvector_type_const_ptr;
59     typedef typename BV::allocator_type              allocator_type;
60     typedef typename bvector_type::allocation_policy allocation_policy_type;
61     typedef typename allocator_type::allocator_pool_type allocator_pool_type;
62     typedef typename bvector_type::size_type             size_type;
63     typedef typename bvector_type::block_idx_type        block_idx_type;
64     typedef unsigned char                                octet_type;
65 
66 public:
67     // ------------------------------------------------------------
68     /*! @name Construction, assignment                          */
69     ///@{
70 
71     basic_bmatrix(size_type rsize,
72                   allocation_policy_type ap = allocation_policy_type(),
73                   size_type bv_max_size = bm::id_max,
74                   const allocator_type&   alloc  = allocator_type());
75     ~basic_bmatrix() BMNOEXCEPT;
76 
77     /*! copy-ctor */
78     basic_bmatrix(const basic_bmatrix<BV>& bbm);
79     basic_bmatrix<BV>& operator=(const basic_bmatrix<BV>& bbm)
80     {
81         copy_from(bbm);
82         return *this;
83     }
84 
85 #ifndef BM_NO_CXX11
86     /*! move-ctor */
87     basic_bmatrix(basic_bmatrix<BV>&& bbm) BMNOEXCEPT;
88 
89     /*! move assignmment operator */
90     basic_bmatrix<BV>& operator = (basic_bmatrix<BV>&& bbm) BMNOEXCEPT
91     {
92         if (this != &bbm)
93         {
94             free_rows();
95             swap(bbm);
96         }
97         return *this;
98     }
99 #endif
100 
set_allocator_pool(allocator_pool_type * pool_ptr)101     void set_allocator_pool(allocator_pool_type* pool_ptr) BMNOEXCEPT
102     { pool_ = pool_ptr; }
103 
104     ///@}
105 
106     // ------------------------------------------------------------
107     /*! @name content manipulation                                */
108     ///@{
109 
110     /*! Swap content */
111     void swap(basic_bmatrix<BV>& bbm) BMNOEXCEPT;
112 
113     /*! Copy content */
114     void copy_from(const basic_bmatrix<BV>& bbm);
115 
116     ///@}
117 
118     // ------------------------------------------------------------
119     /*! @name row access                                         */
120     ///@{
121 
122     /*! Get row bit-vector. Can return NULL */
123     const bvector_type* row(size_type i) const BMNOEXCEPT;
124 
125     /*! Get row bit-vector. Can return NULL */
126     bvector_type_const_ptr get_row(size_type i) const BMNOEXCEPT;
127 
128     /*! Get row bit-vector. Can return NULL */
129     bvector_type* get_row(size_type i) BMNOEXCEPT;
130 
131     /*! get number of value rows */
rows()132     size_type rows() const BMNOEXCEPT { return rsize_; }
133 
134     /*! Make sure row is constructed, return bit-vector */
135     bvector_type_ptr construct_row(size_type row);
136 
137     /*! Make sure row is copy-constructed, return bit-vector */
138     bvector_type_ptr construct_row(size_type row, const bvector_type& bv);
139 
140     /*! destruct/deallocate row */
141     void destruct_row(size_type row);
142 
143     /*! clear row bit-vector */
144     void clear_row(size_type row, bool free_mem);
145 
146     ///@}
147 
148 
149     // ------------------------------------------------------------
150     /*! @name octet access and transposition                     */
151     ///@{
152 
153     /*!
154         Bit-transpose an octet and assign it to a bit-matrix
155 
156         @param pos - column position in the matrix
157         @param octet_idx - octet based row position (1 octet - 8 rows)
158         @param octet - value to assign
159     */
160     void set_octet(size_type pos, size_type octet_idx, unsigned char octet);
161 
162     /*!
163         Bit-transpose and insert an octet and assign it to a bit-matrix
164 
165         @param pos - column position in the matrix
166         @param octet_idx - octet based row position (1 octet - 8 rows)
167         @param octet - value to assign
168     */
169     void insert_octet(size_type pos, size_type octet_idx, unsigned char octet);
170 
171     /*!
172         return octet from the matrix
173 
174         @param pos - column position in the matrix
175         @param octet_idx - octet based row position (1 octet - 8 rows)
176     */
177     unsigned char get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT;
178 
179     /*!
180         Compare vector[pos] with octet
181 
182         It uses regulat comparison of chars to comply with the (signed)
183         char sort order.
184 
185         @param pos - column position in the matrix
186         @param octet_idx - octet based row position (1 octet - 8 rows)
187         @param octet - octet value to compare
188 
189         @return 0 - equal, -1 - less(vect[pos] < octet), 1 - greater
190     */
191     int compare_octet(size_type pos,
192                       size_type octet_idx, char octet) const BMNOEXCEPT;
193 
194     ///@}
195 
196 public:
197 
198     // ------------------------------------------------------------
199     /*! @name Utility function                                   */
200     ///@{
201 
202     /// Test if 4 rows from i are not NULL
203     bool test_4rows(unsigned i) const BMNOEXCEPT;
204 
205     /// Get low level internal access to
206     const bm::word_t* get_block(size_type p,
207                                 unsigned i, unsigned j) const BMNOEXCEPT;
208 
209     unsigned get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT;
210 
211     /*!
212         \brief run memory optimization for all bit-vector rows
213         \param temp_block - pre-allocated memory block to avoid re-allocs
214         \param opt_mode - requested compression depth
215         \param stat - memory allocation statistics after optimization
216     */
217     void optimize(
218         bm::word_t* temp_block = 0,
219         typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
220         typename bvector_type::statistics* stat = 0);
221 
222     /*! Optimize block in all planes
223         @internal
224     */
225     void optimize_block(block_idx_type nb);
226 
227     ///@}
228 
229 
230 protected:
231     void allocate_rows(size_type rsize);
232     void free_rows() BMNOEXCEPT;
233 
234     bvector_type* construct_bvector(const bvector_type* bv) const;
235     void destruct_bvector(bvector_type* bv) const;
236 
237     static
throw_bad_alloc()238     void throw_bad_alloc() { BV::throw_bad_alloc(); }
239 
240 
241 protected:
242     size_type                bv_size_;
243     allocator_type           alloc_;
244     allocation_policy_type   ap_;
245     allocator_pool_type*     pool_;
246 
247     bvector_type_ptr*        bv_rows_;
248     size_type                rsize_;
249 };
250 
251 /**
252     Base class for bit-transposed sparse vector construction
253 
254     @ingroup bmagic
255     @internal
256 */
257 template<typename Val, typename BV, unsigned MAX_SIZE>
258 class base_sparse_vector
259 {
260 public:
261     enum bit_planes
262     {
263         sv_planes = (sizeof(Val) * 8 * MAX_SIZE + 1),
264         sv_value_planes = (sizeof(Val) * 8 * MAX_SIZE)
265     };
266 
267     enum vector_capacity
268     {
269         max_vector_size = MAX_SIZE
270     };
271 
272     typedef Val                                      value_type;
273     typedef BV                                       bvector_type;
274     typedef typename BV::size_type                   size_type;
275     typedef bvector_type*                            bvector_type_ptr;
276     typedef const bvector_type*                      bvector_type_const_ptr;
277     typedef const value_type&                        const_reference;
278     typedef typename BV::allocator_type              allocator_type;
279     typedef typename bvector_type::allocation_policy allocation_policy_type;
280     typedef typename bvector_type::enumerator        bvector_enumerator_type;
281     typedef typename allocator_type::allocator_pool_type allocator_pool_type;
282     typedef bm::basic_bmatrix<BV>                        bmatrix_type;
283 
284 public:
285     base_sparse_vector();
286 
287     base_sparse_vector(bm::null_support        null_able,
288                        allocation_policy_type  ap,
289                        size_type               bv_max_size,
290                        const allocator_type&   alloc);
291 
292     base_sparse_vector(const base_sparse_vector<Val, BV, MAX_SIZE>& bsv);
293 
294 #ifndef BM_NO_CXX11
295     /*! move-ctor */
base_sparse_vector(base_sparse_vector<Val,BV,MAX_SIZE> && bsv)296     base_sparse_vector(base_sparse_vector<Val, BV, MAX_SIZE>&& bsv) BMNOEXCEPT
297     {
298         bmatr_.swap(bsv.bmatr_);
299         size_ = bsv.size_;
300         effective_planes_ = bsv.effective_plane_;
301         bsv.size_ = 0;
302     }
303 #endif
304 
305     void swap(base_sparse_vector<Val, BV, MAX_SIZE>& bsv) BMNOEXCEPT;
306 
size()307     size_type size() const BMNOEXCEPT { return size_; }
308 
309     void resize(size_type new_size);
310 
311     void clear_range(size_type left, size_type right, bool set_null);
312 
313     void keep_range_no_check(size_type left, size_type right,
314                              bm::null_support splice_null);
315 
316     /*! \brief resize to zero, free memory
317         @param free_mem - fully destroys the plane vectors if true
318     */
319     void clear_all(bool free_mem = true) BMNOEXCEPT;
320 
321     /*! return true if empty */
empty()322     bool empty() const BMNOEXCEPT { return size() == 0; }
323 
324 public:
325 
326     // ------------------------------------------------------------
327     /*! @name Various traits                                     */
328     ///@{
329     /**
330         \brief check if container supports NULL(unassigned) values
331     */
is_nullable()332     bool is_nullable() const BMNOEXCEPT
333         { return bmatr_.get_row(this->null_plane()) != 0; }
334 
335     /**
336         \brief check if container supports NULL(unassigned) values
337     */
get_null_support()338     bm::null_support get_null_support() const BMNOEXCEPT
339         { return is_nullable() ? bm::use_null : bm::no_null; }
340 
341     /**
342         \brief Get bit-vector of assigned values or NULL
343         (if not constructed that way)
344     */
get_null_bvector()345     const bvector_type* get_null_bvector() const BMNOEXCEPT
346         { return bmatr_.get_row(this->null_plane()); }
347 
348     /** \brief test if specified element is NULL
349         \param idx - element index
350         \return true if it is NULL false if it was assigned or container
351         is not configured to support assignment flags
352     */
353     bool is_null(size_type idx) const BMNOEXCEPT;
354 
355 
356     ///@}
357 
358 
359     // ------------------------------------------------------------
360     /*! @name Access to internals                                */
361     ///@{
362 
363     /*!
364         \brief get access to bit-plane, function checks and creates a plane
365         \return bit-vector for the bit plane
366     */
367     bvector_type_ptr get_plane(unsigned i);
368 
369     /*!
370         \brief get read-only access to bit-plane
371         \return bit-vector for the bit plane or NULL
372     */
373     bvector_type_const_ptr
get_plane(unsigned i)374     get_plane(unsigned i) const BMNOEXCEPT { return bmatr_.row(i); }
375 
376     /*!
377         \brief get total number of bit-planes in the vector
378     */
planes()379     static unsigned planes() BMNOEXCEPT { return value_bits(); }
380 
381     /** Number of stored bit-planes (value planes + extra */
stored_planes()382     static unsigned stored_planes() BMNOEXCEPT { return value_bits()+1; }
383 
384 
385     /** Number of effective bit-planes in the value type */
effective_planes()386     unsigned effective_planes() const BMNOEXCEPT
387                                 { return effective_planes_ + 1; }
388 
389     /*!
390         \brief get access to bit-plane as is (can return NULL)
391     */
plane(unsigned i)392     bvector_type_ptr plane(unsigned i) BMNOEXCEPT { return bmatr_.get_row(i); }
plane(unsigned i)393     bvector_type_const_ptr plane(unsigned i) const BMNOEXCEPT
394                                     { return bmatr_.get_row(i); }
395 
get_null_bvect()396     bvector_type* get_null_bvect() { return bmatr_.get_row(this->null_plane());}
397 
398     /*!
399         \brief free memory in bit-plane
400     */
free_plane(unsigned i)401     void free_plane(unsigned i) { bmatr_.destruct_row(i); }
402 
403     /*!
404         return mask of allocated bit-planes
405         1 in the mask - means bit-plane N is present
406         returns 64-bit unsigned mask for sub 64-bit types (like int)
407         unallocated mask bits will be zero extended
408 
409         @return 64-bit mask
410         @internal
411     */
412     bm::id64_t get_planes_mask(unsigned element_idx) const BMNOEXCEPT;
413 
414     /*!
415         get read-only access to inetrnal bit-matrix
416     */
get_bmatrix()417     const bmatrix_type& get_bmatrix() const BMNOEXCEPT { return bmatr_; }
418 
419     /**
420         access to internal bit-matrix
421      */
get_bmatrix()422     bmatrix_type& get_bmatrix() BMNOEXCEPT { return bmatr_; }
423     ///@}
424 
425     /*!
426         \brief run memory optimization for all bit-vector rows
427         \param temp_block - pre-allocated memory block to avoid unnecessary re-allocs
428         \param opt_mode - requested compression depth
429         \param stat - memory allocation statistics after optimization
430     */
431     void optimize(bm::word_t* temp_block = 0,
432                   typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
433                   typename bvector_type::statistics* stat = 0);
434 
435     /*!
436         @brief Calculates memory statistics.
437 
438         Function fills statistics structure containing information about how
439         this vector uses memory and estimation of max. amount of memory
440         bvector needs to serialize itself.
441 
442         @param st - pointer on statistics structure to be filled in.
443 
444         @sa statistics
445     */
446     void calc_stat(typename bvector_type::statistics* st) const BMNOEXCEPT;
447 
448     /*!
449         \brief check if another sparse vector has the same content and size
450 
451         \param sv        - sparse vector for comparison
452         \param null_able - flag to consider NULL vector in comparison (default)
453                            or compare only value content planes
454 
455         \return true, if it is the same
456     */
457     bool equal(const base_sparse_vector<Val, BV, MAX_SIZE>& sv,
458                bm::null_support null_able = bm::use_null) const BMNOEXCEPT;
459 
460 protected:
461     void copy_from(const base_sparse_vector<Val, BV, MAX_SIZE>& bsv);
462 
463     /**
464         Merge plane bvectors from an outside base matrix
465         Note: outside base matrix gets destroyed
466      */
467     void merge_matr(bmatrix_type& bmatr, unsigned psize);
468 
469     /*!
470         clear column in all value planes
471         \param plane_idx - row (plane index to start from)
472         \param idx       - bit (column) to clear
473     */
474     void clear_value_planes_from(unsigned plane_idx, size_type idx);
475 
476     /*!
477         insert false (clear) column in all value planes
478         \param plane_idx - row (plane index to start from)
479         \param idx       - bit (column) to clear insert
480     */
481     void insert_clear_value_planes_from(unsigned plane_idx, size_type idx);
482 
483     /*!
484         erase bit (column) from all planes
485         \param idx - bit (column) to erase
486     */
487     void erase_column(size_type idx);
488 
489     /*!
490         insert (NOT) NULL value
491     */
492     void insert_null(size_type idx, bool not_null);
493 
494 
495 protected:
496     typedef typename bvector_type::block_idx_type block_idx_type;
497 
498     /** Number of total bit-planes in the value type*/
value_bits()499     static unsigned value_bits() BMNOEXCEPT
500     {
501         return base_sparse_vector<Val, BV, MAX_SIZE>::sv_value_planes;
502     }
503 
504     /** plane index for the "NOT NULL" flags plane */
null_plane()505     static unsigned null_plane() BMNOEXCEPT { return value_bits(); }
506 
507     /** optimize block in all matrix planes */
optimize_block(block_idx_type nb)508     void optimize_block(block_idx_type nb)
509     {
510         bmatr_.optimize_block(nb);
511     }
512 
513     /**
514         Perform copy_range() on a set of planes
515     */
516     void copy_range_planes(
517         const base_sparse_vector<Val, BV, MAX_SIZE>& bsv,
518         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
519         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
520         bm::null_support splice_null);
521 
522 protected:
523     bmatrix_type             bmatr_;              ///< bit-transposed matrix
524     size_type                size_;               ///< array size
525     unsigned                 effective_planes_;
526 
527 };
528 
529 //---------------------------------------------------------------------
530 //
531 //---------------------------------------------------------------------
532 
533 template<typename BV>
basic_bmatrix(size_type rsize,allocation_policy_type ap,size_type bv_max_size,const allocator_type & alloc)534 basic_bmatrix<BV>::basic_bmatrix(size_type rsize,
535               allocation_policy_type ap,
536               size_type bv_max_size,
537               const allocator_type&   alloc)
538 : bv_size_(bv_max_size),
539   alloc_(alloc),
540   ap_(ap),
541   pool_(0),
542   bv_rows_(0),
543   rsize_(0)
544 {
545     allocate_rows(rsize);
546 }
547 
548 //---------------------------------------------------------------------
549 
550 template<typename BV>
~basic_bmatrix()551 basic_bmatrix<BV>::~basic_bmatrix() BMNOEXCEPT
552 {
553     free_rows();
554 }
555 
556 //---------------------------------------------------------------------
557 
558 template<typename BV>
basic_bmatrix(const basic_bmatrix<BV> & bbm)559 basic_bmatrix<BV>::basic_bmatrix(const basic_bmatrix<BV>& bbm)
560 : bv_size_(bbm.bv_size_),
561   alloc_(bbm.alloc_),
562   ap_(bbm.ap_),
563   pool_(0),
564   bv_rows_(0),
565   rsize_(0)
566 {
567     copy_from(bbm);
568 }
569 
570 //---------------------------------------------------------------------
571 
572 template<typename BV>
basic_bmatrix(basic_bmatrix<BV> && bbm)573 basic_bmatrix<BV>::basic_bmatrix(basic_bmatrix<BV>&& bbm) BMNOEXCEPT
574 : bv_size_(bbm.bv_size_),
575   alloc_(bbm.alloc_),
576   ap_(bbm.ap_),
577   pool_(0),
578   bv_rows_(0),
579   rsize_(0)
580 {
581     swap(bbm);
582 }
583 
584 //---------------------------------------------------------------------
585 
586 template<typename BV>
587 const typename basic_bmatrix<BV>::bvector_type*
row(size_type i)588 basic_bmatrix<BV>::row(size_type i) const BMNOEXCEPT
589 {
590     BM_ASSERT(i < rsize_);
591     return bv_rows_[i];
592 }
593 
594 //---------------------------------------------------------------------
595 
596 template<typename BV>
597 const typename basic_bmatrix<BV>::bvector_type*
get_row(size_type i)598 basic_bmatrix<BV>::get_row(size_type i) const BMNOEXCEPT
599 {
600     BM_ASSERT(i < rsize_);
601     return bv_rows_[i];
602 }
603 
604 //---------------------------------------------------------------------
605 
606 template<typename BV>
607 typename basic_bmatrix<BV>::bvector_type*
get_row(size_type i)608 basic_bmatrix<BV>::get_row(size_type i) BMNOEXCEPT
609 {
610     BM_ASSERT(i < rsize_);
611     return bv_rows_[i];
612 }
613 
614 //---------------------------------------------------------------------
615 
616 template<typename BV>
test_4rows(unsigned j)617 bool basic_bmatrix<BV>::test_4rows(unsigned j) const BMNOEXCEPT
618 {
619     BM_ASSERT((j + 4) <= rsize_);
620 #if defined(BM64_SSE4)
621         __m128i w0 = _mm_loadu_si128((__m128i*)(bv_rows_ + j));
622         __m128i w1 = _mm_loadu_si128((__m128i*)(bv_rows_ + j + 2));
623         w0 = _mm_or_si128(w0, w1);
624         return !_mm_testz_si128(w0, w0);
625 #elif defined(BM64_AVX2) || defined(BM64_AVX512)
626         __m256i w0 = _mm256_loadu_si256((__m256i*)(bv_rows_ + j));
627         return !_mm256_testz_si256(w0, w0);
628 #else
629         bool b = bv_rows_[j + 0] || bv_rows_[j + 1] ||
630                  bv_rows_[j + 2] || bv_rows_[j + 3];
631         return b;
632 #endif
633 }
634 
635 //---------------------------------------------------------------------
636 
637 template<typename BV>
copy_from(const basic_bmatrix<BV> & bbm)638 void basic_bmatrix<BV>::copy_from(const basic_bmatrix<BV>& bbm)
639 {
640     if (this == &bbm) // nothing to do
641         return;
642     free_rows();
643 
644     bv_size_ = bbm.bv_size_;
645     alloc_ = bbm.alloc_;
646     ap_ = bbm.ap_;
647 
648     size_type rsize = bbm.rsize_;
649     if (rsize)
650     {
651         bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(rsize);
652         if (!bv_rows_)
653             throw_bad_alloc();
654         else
655         {
656             rsize_ = rsize;
657             for (size_type i = 0; i < rsize_; ++i)
658             {
659                 const bvector_type_ptr bv = bbm.bv_rows_[i];
660                 bv_rows_[i] = bv ?  construct_bvector(bv) : 0;
661             }
662         }
663     }
664 
665 }
666 
667 //---------------------------------------------------------------------
668 
669 template<typename BV>
allocate_rows(size_type rsize)670 void basic_bmatrix<BV>::allocate_rows(size_type rsize)
671 {
672     BM_ASSERT(!bv_rows_);
673 
674     if (rsize)
675     {
676         bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(unsigned(rsize));
677         if (!bv_rows_)
678             throw_bad_alloc();
679         else
680         {
681             rsize_ = rsize;
682             for (size_type i = 0; i < rsize; ++i)
683                 bv_rows_[i] = 0;
684         }
685     }
686 }
687 
688 //---------------------------------------------------------------------
689 
690 template<typename BV>
free_rows()691 void basic_bmatrix<BV>::free_rows() BMNOEXCEPT
692 {
693     for (size_type i = 0; i < rsize_; ++i)
694     {
695         bvector_type_ptr bv = bv_rows_[i];
696         if (bv)
697         {
698             destruct_bvector(bv);
699             bv_rows_[i] = 0;
700         }
701     } // for i
702     if (bv_rows_)
703     {
704         alloc_.free_ptr(bv_rows_, unsigned(rsize_));
705     }
706     bv_rows_ = 0;
707 }
708 
709 //---------------------------------------------------------------------
710 
711 template<typename BV>
swap(basic_bmatrix<BV> & bbm)712 void basic_bmatrix<BV>::swap(basic_bmatrix<BV>& bbm) BMNOEXCEPT
713 {
714     if (this == &bbm)
715         return;
716 
717     bm::xor_swap(bv_size_, bbm.bv_size_);
718 
719     allocator_type alloc_tmp = alloc_;
720     alloc_ = bbm.alloc_;
721     bbm.alloc_ = alloc_tmp;
722 
723     allocation_policy_type ap_tmp = ap_;
724     ap_ = bbm.ap_;
725     bbm.ap_ = ap_tmp;
726 
727     allocator_pool_type*     pool_tmp = pool_;
728     pool_ = bbm.pool_;
729     bbm.pool_ = pool_tmp;
730 
731     bm::xor_swap(rsize_, bbm.rsize_);
732 
733     bvector_type_ptr* rtmp = bv_rows_;
734     bv_rows_ = bbm.bv_rows_;
735     bbm.bv_rows_ = rtmp;
736 }
737 
738 //---------------------------------------------------------------------
739 
740 template<typename BV>
741 typename basic_bmatrix<BV>::bvector_type_ptr
construct_row(size_type row)742 basic_bmatrix<BV>::construct_row(size_type row)
743 {
744     BM_ASSERT(row < rsize_);
745     bvector_type_ptr bv = bv_rows_[row];
746     if (!bv)
747     {
748         bv = bv_rows_[row] = construct_bvector(0);
749     }
750     return bv;
751 }
752 
753 //---------------------------------------------------------------------
754 
755 template<typename BV>
756 typename basic_bmatrix<BV>::bvector_type_ptr
construct_row(size_type row,const bvector_type & bv_src)757 basic_bmatrix<BV>::construct_row(size_type row, const bvector_type& bv_src)
758 {
759     BM_ASSERT(row < rsize_);
760     bvector_type_ptr bv = bv_rows_[row];
761     if (bv)
762     {
763         *bv = bv_src;
764     }
765     else
766     {
767         bv = bv_rows_[row] = construct_bvector(&bv_src);
768     }
769     return bv;
770 }
771 
772 
773 //---------------------------------------------------------------------
774 
775 template<typename BV>
destruct_row(size_type row)776 void basic_bmatrix<BV>::destruct_row(size_type row)
777 {
778     BM_ASSERT(row < rsize_);
779     bvector_type_ptr bv = bv_rows_[row];
780     if (bv)
781     {
782         destruct_bvector(bv);
783         bv_rows_[row] = 0;
784     }
785 }
786 
787 //---------------------------------------------------------------------
788 
789 template<typename BV>
clear_row(size_type row,bool free_mem)790 void basic_bmatrix<BV>::clear_row(size_type row, bool free_mem)
791 {
792     BM_ASSERT(row < rsize_);
793     bvector_type_ptr bv = bv_rows_[row];
794     if (bv)
795     {
796         if (free_mem)
797         {
798             destruct_bvector(bv);
799             bv_rows_[row] = 0;
800         }
801         else
802         {
803             bv->clear(true);
804         }
805     }
806 }
807 
808 
809 //---------------------------------------------------------------------
810 
811 template<typename BV>
812 typename basic_bmatrix<BV>::bvector_type*
construct_bvector(const bvector_type * bv)813 basic_bmatrix<BV>::construct_bvector(const bvector_type* bv) const
814 {
815     bvector_type* rbv = 0;
816 #ifdef BM_NO_STL   // C compatibility mode
817     void* mem = ::malloc(sizeof(bvector_type));
818     if (mem == 0)
819     {
820         BM_THROW(false, BM_ERR_BADALLOC);
821     }
822     rbv = bv ? new(mem) bvector_type(*bv)
823              : new(mem) bvector_type(ap_.strat, ap_.glevel_len,
824                                      bv_size_,
825                                      alloc_);
826 #else
827     rbv = bv ? new bvector_type(*bv)
828              : new bvector_type(ap_.strat, ap_.glevel_len,
829                                 bv_size_,
830                                 alloc_);
831 #endif
832     return rbv;
833 }
834 
835 //---------------------------------------------------------------------
836 
837 template<typename BV>
destruct_bvector(bvector_type * bv)838 void basic_bmatrix<BV>::destruct_bvector(bvector_type* bv) const
839 {
840 #ifdef BM_NO_STL   // C compatibility mode
841     bv->~TBM_bvector();
842     ::free((void*)bv);
843 #else
844     delete bv;
845 #endif
846 }
847 
848 //---------------------------------------------------------------------
849 
850 template<typename BV>
851 const bm::word_t*
get_block(size_type p,unsigned i,unsigned j)852 basic_bmatrix<BV>::get_block(size_type p,
853                              unsigned i, unsigned j) const BMNOEXCEPT
854 {
855     bvector_type_const_ptr bv = this->row(p);
856     if (bv)
857     {
858         const typename bvector_type::blocks_manager_type& bman =
859                                             bv->get_blocks_manager();
860         return bman.get_block_ptr(i, j);
861     }
862     return 0;
863 }
864 
865 
866 //---------------------------------------------------------------------
867 
868 template<typename BV>
set_octet(size_type pos,size_type octet_idx,unsigned char octet)869 void basic_bmatrix<BV>::set_octet(size_type pos,
870                                   size_type octet_idx,
871                                   unsigned char octet)
872 {
873     BM_ASSERT(octet_idx * 8u < rsize_);
874 
875     size_type oct = octet;
876     size_type row = octet_idx * 8;
877     size_type row_end = row + 8;
878     for (; row < row_end; ++row)
879     {
880         bvector_type* bv = this->get_row(row);
881         if (oct & 1u)
882         {
883             if (!bv)
884             {
885                 bv = this->construct_row(row);
886                 bv->init();
887             }
888             bv->set_bit_no_check(pos);
889         }
890         else
891         {
892             if (bv)
893                 bv->clear_bit_no_check(pos);
894         }
895         oct >>= 1;
896         if (!oct)
897             break;
898     } // for
899 
900     // clear the tail
901     for (++row; row < row_end; ++row)
902     {
903         bvector_type* bv = this->get_row(row);
904         if (bv)
905             bv->clear_bit_no_check(pos);
906     } // for
907 }
908 
909 //---------------------------------------------------------------------
910 
911 template<typename BV>
insert_octet(size_type pos,size_type octet_idx,unsigned char octet)912 void basic_bmatrix<BV>::insert_octet(size_type pos,
913                                      size_type octet_idx,
914                                      unsigned char octet)
915 {
916     BM_ASSERT(octet_idx * 8u < rsize_);
917 
918     size_type oct = octet;
919     size_type row = octet_idx * 8;
920     size_type row_end = row + 8;
921     for (; row < row_end; ++row)
922     {
923         bvector_type* bv = this->get_row(row);
924         if (oct & 1u)
925         {
926             if (!bv)
927             {
928                 bv = this->construct_row(row);
929                 bv->init();
930                 bv->set_bit_no_check(pos);
931             }
932             else
933             {
934                 bv->insert(pos, true);
935             }
936         }
937         else
938         {
939             if (bv)
940                 bv->insert(pos, false);
941         }
942         oct >>= 1;
943         if (!oct)
944             break;
945     } // for
946 
947     // clear the tail
948     for (++row; row < row_end; ++row)
949     {
950         bvector_type* bv = this->get_row(row);
951         if (bv)
952             bv->insert(pos, false);
953     } // for
954 }
955 
956 
957 //---------------------------------------------------------------------
958 
959 template<typename BV>
960 unsigned char
get_octet(size_type pos,size_type octet_idx)961 basic_bmatrix<BV>::get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT
962 {
963     unsigned v = 0;
964 
965     block_idx_type nb = (pos >>  bm::set_block_shift);
966     unsigned i0 = unsigned(nb >> bm::set_array_shift); // top block address
967     unsigned j0 = unsigned(nb &  bm::set_array_mask);  // address in sub-block
968 
969     const bm::word_t* blk;
970     const bm::word_t* blka[8];
971     unsigned nbit = unsigned(pos & bm::set_block_mask);
972     unsigned nword  = unsigned(nbit >> bm::set_word_shift);
973     unsigned mask0 = 1u << (nbit & bm::set_word_mask);
974 
975     unsigned row_idx = unsigned(octet_idx * 8);
976 
977     blka[0] = get_block(row_idx+0, i0, j0);
978     blka[1] = get_block(row_idx+1, i0, j0);
979     blka[2] = get_block(row_idx+2, i0, j0);
980     blka[3] = get_block(row_idx+3, i0, j0);
981     blka[4] = get_block(row_idx+4, i0, j0);
982     blka[5] = get_block(row_idx+5, i0, j0);
983     blka[6] = get_block(row_idx+6, i0, j0);
984     blka[7] = get_block(row_idx+7, i0, j0);
985     unsigned is_set;
986 
987     if ((blk = blka[0])!=0)
988     {
989         if (blk == FULL_BLOCK_FAKE_ADDR)
990             is_set = 1;
991         else
992             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
993         v |= (unsigned)bool(is_set);
994     }
995     if ((blk = blka[1])!=0)
996     {
997         if (blk == FULL_BLOCK_FAKE_ADDR)
998             is_set = 1;
999         else
1000             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1001         v |= unsigned(bool(is_set)) << 1u;
1002     }
1003     if ((blk = blka[2])!=0)
1004     {
1005         if (blk == FULL_BLOCK_FAKE_ADDR)
1006             is_set = 1;
1007         else
1008             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1009         v |= unsigned(bool(is_set)) << 2u;
1010     }
1011     if ((blk = blka[3])!=0)
1012     {
1013         if (blk == FULL_BLOCK_FAKE_ADDR)
1014             is_set = 1;
1015         else
1016             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1017         v |= unsigned(bool(is_set)) << 3u;
1018     }
1019 
1020 
1021     if ((blk = blka[4])!=0)
1022     {
1023         if (blk == FULL_BLOCK_FAKE_ADDR)
1024             is_set = 1;
1025         else
1026             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1027         v |= unsigned(bool(is_set)) << 4u;
1028     }
1029     if ((blk = blka[5])!=0)
1030     {
1031         if (blk == FULL_BLOCK_FAKE_ADDR)
1032             is_set = 1;
1033         else
1034             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1035         v |= unsigned(bool(is_set)) << 5u;
1036     }
1037     if ((blk = blka[6])!=0)
1038     {
1039         if (blk == FULL_BLOCK_FAKE_ADDR)
1040             is_set = 1;
1041         else
1042             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1043         v |= unsigned(bool(is_set)) << 6u;
1044     }
1045     if ((blk = blka[7])!=0)
1046     {
1047         if (blk == FULL_BLOCK_FAKE_ADDR)
1048             is_set = 1;
1049         else
1050             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1051         v |= unsigned(bool(is_set)) << 7u;
1052     }
1053 
1054     return (unsigned char)v;
1055 }
1056 
1057 //---------------------------------------------------------------------
1058 
1059 template<typename BV>
compare_octet(size_type pos,size_type octet_idx,char octet)1060 int basic_bmatrix<BV>::compare_octet(size_type pos,
1061                                      size_type octet_idx,
1062                                      char      octet) const BMNOEXCEPT
1063 {
1064     char value = char(get_octet(pos, octet_idx));
1065     return (value > octet) - (value < octet);
1066 }
1067 
1068 //---------------------------------------------------------------------
1069 
1070 template<typename BV>
1071 unsigned
get_half_octet(size_type pos,size_type row_idx)1072 basic_bmatrix<BV>::get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT
1073 {
1074     unsigned v = 0;
1075 
1076     block_idx_type nb = (pos >>  bm::set_block_shift);
1077     unsigned i0 = unsigned(nb >> bm::set_array_shift); // top block address
1078     unsigned j0 = unsigned(nb &  bm::set_array_mask);  // address in sub-block
1079 
1080     const bm::word_t* blk;
1081     const bm::word_t* blka[4];
1082     unsigned nbit = unsigned(pos & bm::set_block_mask);
1083     unsigned nword  = unsigned(nbit >> bm::set_word_shift);
1084     unsigned mask0 = 1u << (nbit & bm::set_word_mask);
1085 
1086     blka[0] = get_block(row_idx+0, i0, j0);
1087     blka[1] = get_block(row_idx+1, i0, j0);
1088     blka[2] = get_block(row_idx+2, i0, j0);
1089     blka[3] = get_block(row_idx+3, i0, j0);
1090     unsigned is_set;
1091 
1092     if ((blk = blka[0])!=0)
1093     {
1094         if (blk == FULL_BLOCK_FAKE_ADDR)
1095             is_set = 1;
1096         else
1097             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1098         v |= unsigned(bool(is_set));
1099     }
1100     if ((blk = blka[1])!=0)
1101     {
1102         if (blk == FULL_BLOCK_FAKE_ADDR)
1103             is_set = 1;
1104         else
1105             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1106         v |= unsigned(bool(is_set)) << 1u;
1107     }
1108     if ((blk = blka[2])!=0)
1109     {
1110         if (blk == FULL_BLOCK_FAKE_ADDR)
1111             is_set = 1;
1112         else
1113             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1114         v |= unsigned(bool(is_set)) << 2u;
1115     }
1116     if ((blk = blka[3])!=0)
1117     {
1118         if (blk == FULL_BLOCK_FAKE_ADDR)
1119             is_set = 1;
1120         else
1121             is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1122         v |= unsigned(bool(is_set)) << 3u;
1123     }
1124     return v;
1125 }
1126 
1127 //---------------------------------------------------------------------
1128 
1129 template<typename BV>
optimize(bm::word_t * temp_block,typename bvector_type::optmode opt_mode,typename bvector_type::statistics * st)1130 void basic_bmatrix<BV>::optimize(bm::word_t* temp_block,
1131                   typename bvector_type::optmode opt_mode,
1132                   typename bvector_type::statistics* st)
1133 {
1134     if (st)
1135         st->reset();
1136 
1137     BM_DECLARE_TEMP_BLOCK(tb)
1138     if (!temp_block)
1139         temp_block = tb;
1140 
1141     for (unsigned k = 0; k < rsize_; ++k)
1142     {
1143         bvector_type* bv = get_row(k);
1144         if (bv)
1145         {
1146             typename bvector_type::statistics stbv;
1147             stbv.reset();
1148             bv->optimize(temp_block, opt_mode, st ? &stbv : 0);
1149             if (st)
1150             {
1151                 st->add(stbv);
1152             }
1153         }
1154     } // for k
1155 }
1156 
1157 //---------------------------------------------------------------------
1158 
1159 template<typename BV>
optimize_block(block_idx_type nb)1160 void basic_bmatrix<BV>::optimize_block(block_idx_type nb)
1161 {
1162     for (unsigned k = 0; k < rsize_; ++k)
1163     {
1164         bvector_type* bv = get_row(k);
1165         if (bv)
1166         {
1167             unsigned i, j;
1168             bm::get_block_coord(nb, i, j);
1169             typename bvector_type::blocks_manager_type& bman =
1170                                                 bv->get_blocks_manager();
1171             bman.optimize_bit_block(i, j);
1172         }
1173     } // for k
1174 
1175 }
1176 
1177 //---------------------------------------------------------------------
1178 //---------------------------------------------------------------------
1179 
1180 
1181 
1182 template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector()1183 base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector()
1184 : bmatr_(sv_planes, allocation_policy_type(), bm::id_max, allocator_type()),
1185   size_(0),
1186   effective_planes_(0)
1187 {
1188 }
1189 
1190 //---------------------------------------------------------------------
1191 
1192 template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector(bm::null_support null_able,allocation_policy_type ap,size_type bv_max_size,const allocator_type & alloc)1193 base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector(
1194         bm::null_support        null_able,
1195         allocation_policy_type  ap,
1196         size_type               bv_max_size,
1197         const allocator_type&       alloc)
1198 : bmatr_(sv_planes, ap, bv_max_size, alloc),
1199   size_(0),
1200   effective_planes_(0)
1201 {
1202     if (null_able == bm::use_null)
1203     {
1204         unsigned i = null_plane();
1205         bmatr_.construct_row(i)->init();
1206     }
1207 }
1208 
1209 //---------------------------------------------------------------------
1210 
1211 template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector(const base_sparse_vector<Val,BV,MAX_SIZE> & bsv)1212 base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector(
1213                         const base_sparse_vector<Val, BV, MAX_SIZE>& bsv)
1214 : bmatr_(bsv.bmatr_),
1215   size_(bsv.size_),
1216   effective_planes_(bsv.effective_planes_)
1217 {
1218 }
1219 
1220 //---------------------------------------------------------------------
1221 
1222 template<class Val, class BV, unsigned MAX_SIZE>
copy_from(const base_sparse_vector<Val,BV,MAX_SIZE> & bsv)1223 void base_sparse_vector<Val, BV, MAX_SIZE>::copy_from(
1224                 const base_sparse_vector<Val, BV, MAX_SIZE>& bsv)
1225 {
1226     resize(bsv.size());
1227     effective_planes_ = bsv.effective_planes_;
1228 
1229     unsigned ni = this->null_plane();
1230     unsigned planes = bsv.stored_planes();
1231     for (size_type i = 0; i < planes; ++i)
1232     {
1233         bvector_type* bv = bmatr_.get_row(i);
1234         const bvector_type* bv_src = bsv.bmatr_.row(i);
1235 
1236         if (i == ni) // NULL plane copy
1237         {
1238             if (bv && !bv_src) // special case (copy from not NULL)
1239             {
1240                 if (size_)
1241                     bv->set_range(0, size_-1);
1242                 continue;
1243             }
1244         }
1245 
1246         if (bv)
1247             bmatr_.destruct_row(i);
1248         if (bv_src)
1249             bmatr_.construct_row(i, *bv_src);
1250     } // for i
1251 }
1252 
1253 //---------------------------------------------------------------------
1254 
1255 template<class Val, class BV, unsigned MAX_SIZE>
merge_matr(bmatrix_type & bmatr,unsigned psize)1256 void base_sparse_vector<Val, BV, MAX_SIZE>::merge_matr(
1257                             bmatrix_type& bmatr, unsigned psize)
1258 {
1259     for (unsigned j = 0; j < psize; ++j)
1260     {
1261         bvector_type* arg_bv = bmatr.get_row(j);
1262         if (arg_bv)
1263         {
1264             bvector_type* bv = this->bmatr_.get_row(j);
1265             if (!bv) // TODO: borrow the whole arg_bv vector
1266                 bv = this->get_plane(j);
1267             bv->merge(*arg_bv);
1268         }
1269     } // for j
1270 }
1271 
1272 //---------------------------------------------------------------------
1273 
1274 template<class Val, class BV, unsigned MAX_SIZE>
swap(base_sparse_vector<Val,BV,MAX_SIZE> & bsv)1275 void base_sparse_vector<Val, BV, MAX_SIZE>::swap(
1276                  base_sparse_vector<Val, BV, MAX_SIZE>& bsv) BMNOEXCEPT
1277 {
1278     if (this != &bsv)
1279     {
1280         bmatr_.swap(bsv.bmatr_);
1281 
1282         bm::xor_swap(size_, bsv.size_);
1283         bm::xor_swap(effective_planes_, bsv.effective_planes_);
1284     }
1285 }
1286 
1287 //---------------------------------------------------------------------
1288 
1289 template<class Val, class BV, unsigned MAX_SIZE>
clear_all(bool free_mem)1290 void base_sparse_vector<Val, BV, MAX_SIZE>::clear_all(bool free_mem) BMNOEXCEPT
1291 {
1292     unsigned planes = value_bits();
1293     for (size_type i = 0; i < planes; ++i)
1294         bmatr_.clear_row(i, free_mem);
1295     size_ = 0;
1296     bvector_type* bv_null = get_null_bvect();
1297     if (bv_null)
1298         bv_null->clear(true);
1299 }
1300 
1301 //---------------------------------------------------------------------
1302 
1303 template<class Val, class BV, unsigned MAX_SIZE>
clear_range(typename base_sparse_vector<Val,BV,MAX_SIZE>::size_type left,typename base_sparse_vector<Val,BV,MAX_SIZE>::size_type right,bool set_null)1304 void base_sparse_vector<Val, BV, MAX_SIZE>::clear_range(
1305         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
1306         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
1307         bool set_null)
1308 {
1309     if (right < left)
1310     {
1311         return clear_range(right, left, set_null);
1312     }
1313     unsigned planes = value_bits();
1314     for (unsigned i = 0; i < planes; ++i)
1315     {
1316         bvector_type* bv = this->bmatr_.get_row(i);
1317         if (bv)
1318             bv->set_range(left, right, false);
1319     } // for i
1320 
1321     if (set_null)
1322     {
1323         bvector_type* bv_null = this->get_null_bvect();
1324         if (bv_null)
1325             bv_null->set_range(left, right, false);
1326     }
1327 }
1328 
1329 //---------------------------------------------------------------------
1330 
1331 template<class Val, class BV, unsigned MAX_SIZE>
keep_range_no_check(size_type left,size_type right,bm::null_support splice_null)1332 void base_sparse_vector<Val, BV, MAX_SIZE>::keep_range_no_check(
1333                         size_type left, size_type right,
1334                         bm::null_support splice_null)
1335 {
1336     if (left)
1337         this->clear_range(0, left-1, (splice_null == bm::use_null));
1338     size_type sz = size();
1339     if (right < sz)
1340         this->clear_range(right + 1, sz, (splice_null == bm::use_null));
1341 }
1342 
1343 //---------------------------------------------------------------------
1344 
1345 template<class Val, class BV, unsigned MAX_SIZE>
resize(size_type sz)1346 void base_sparse_vector<Val, BV, MAX_SIZE>::resize(size_type sz)
1347 {
1348     if (sz == size())  // nothing to do
1349         return;
1350     if (!sz) // resize to zero is an equivalent of non-destructive deallocation
1351     {
1352         clear_all();
1353         return;
1354     }
1355     if (sz < size()) // vector shrink
1356         clear_range(sz, this->size_-1, true);   // clear the tails and NULL vect
1357     size_ = sz;
1358 }
1359 
1360 
1361 //---------------------------------------------------------------------
1362 
1363 template<class Val, class BV, unsigned MAX_SIZE>
is_null(size_type idx)1364 bool base_sparse_vector<Val, BV, MAX_SIZE>::is_null(
1365                                     size_type idx) const BMNOEXCEPT
1366 {
1367     const bvector_type* bv_null = get_null_bvector();
1368     return (bv_null) ? (!bv_null->test(idx)) : false;
1369 }
1370 
1371 //---------------------------------------------------------------------
1372 
1373 template<class Val, class BV, unsigned MAX_SIZE>
insert_null(size_type idx,bool not_null)1374 void base_sparse_vector<Val, BV, MAX_SIZE>::insert_null(size_type idx,
1375                                                         bool      not_null)
1376 {
1377     bvector_type* bv_null = this->get_null_bvect();
1378     if (bv_null)
1379         bv_null->insert(idx, not_null);
1380 }
1381 
1382 //---------------------------------------------------------------------
1383 
1384 template<class Val, class BV, unsigned MAX_SIZE>
1385 typename base_sparse_vector<Val, BV, MAX_SIZE>::bvector_type_ptr
get_plane(unsigned i)1386                 base_sparse_vector<Val, BV, MAX_SIZE>::get_plane(unsigned i)
1387 {
1388     bvector_type_ptr bv = bmatr_.get_row(i);
1389     if (!bv)
1390     {
1391         bv = bmatr_.construct_row(i);
1392         bv->init();
1393         if (i > effective_planes_ && i < value_bits())
1394             effective_planes_ = i;
1395     }
1396     return bv;
1397 }
1398 
1399 //---------------------------------------------------------------------
1400 
1401 template<class Val, class BV, unsigned MAX_SIZE>
get_planes_mask(unsigned element_idx)1402 bm::id64_t base_sparse_vector<Val, BV, MAX_SIZE>::get_planes_mask(
1403                                         unsigned element_idx) const BMNOEXCEPT
1404 {
1405     BM_ASSERT(element_idx < MAX_SIZE);
1406     bm::id64_t mask = 0;
1407     bm::id64_t mask1 = 1;
1408     const unsigned planes = sizeof(value_type) * 8;
1409     unsigned bidx = 0;
1410     for (unsigned i = element_idx * planes; i < (element_idx+1) * planes; i+=4)
1411     {
1412         mask |= get_plane(i+0) ? (mask1 << (bidx+0)) : 0ull;
1413         mask |= get_plane(i+1) ? (mask1 << (bidx+1)) : 0ull;
1414         mask |= get_plane(i+2) ? (mask1 << (bidx+2)) : 0ull;
1415         mask |= get_plane(i+3) ? (mask1 << (bidx+3)) : 0ull;
1416         bidx += 4;
1417     } // for i
1418     return mask;
1419 }
1420 
1421 //---------------------------------------------------------------------
1422 
1423 template<class Val, class BV, unsigned MAX_SIZE>
optimize(bm::word_t * temp_block,typename bvector_type::optmode opt_mode,typename bvector_type::statistics * st)1424 void base_sparse_vector<Val, BV, MAX_SIZE>::optimize(bm::word_t* temp_block,
1425                                     typename bvector_type::optmode opt_mode,
1426                                     typename bvector_type::statistics* st)
1427 {
1428     typename bvector_type::statistics stbv;
1429     bmatr_.optimize(temp_block, opt_mode, &stbv);
1430     if (st)
1431         st->add(stbv);
1432 
1433     bvector_type* bv_null = this->get_null_bvect();
1434 
1435     unsigned stored_planes = this->stored_planes();
1436     for (unsigned j = 0; j < stored_planes; ++j)
1437     {
1438         bvector_type* bv = this->bmatr_.get_row(j);
1439         if (bv && (bv != bv_null)) // protect the NULL vector from de-allocation
1440         {
1441             // TODO: check if this can be done within optimize loop
1442             if (!bv->any())  // empty vector?
1443             {
1444                 this->bmatr_.destruct_row(j);
1445                 continue;
1446             }
1447         }
1448     } // for j
1449 }
1450 
1451 //---------------------------------------------------------------------
1452 
1453 template<class Val, class BV, unsigned MAX_SIZE>
calc_stat(typename bvector_type::statistics * st)1454 void base_sparse_vector<Val, BV, MAX_SIZE>::calc_stat(
1455                     typename bvector_type::statistics* st) const BMNOEXCEPT
1456 {
1457     BM_ASSERT(st);
1458 
1459     st->reset();
1460 
1461     unsigned stored_planes = this->stored_planes();
1462     for (unsigned j = 0; j < stored_planes; ++j)
1463     {
1464         const bvector_type* bv = this->bmatr_.row(j);
1465         if (bv)
1466         {
1467             typename bvector_type::statistics stbv;
1468             bv->calc_stat(&stbv);
1469             st->add(stbv);
1470         }
1471         else
1472         {
1473             st->max_serialize_mem += 8;
1474         }
1475     } // for j
1476 
1477     // header accounting
1478     st->max_serialize_mem += 1 + 1 + 1 + 1 + 8 + (8 * this->stored_planes());
1479     st->max_serialize_mem += 1 + 8; // extra header fields for large bit-matrixes
1480 }
1481 
1482 //---------------------------------------------------------------------
1483 
1484 template<class Val, class BV, unsigned MAX_SIZE>
clear_value_planes_from(unsigned plane_idx,size_type idx)1485 void base_sparse_vector<Val, BV, MAX_SIZE>::clear_value_planes_from(
1486                                     unsigned plane_idx, size_type idx)
1487 {
1488     for (unsigned i = plane_idx; i < sv_value_planes; ++i)
1489     {
1490         bvector_type* bv = this->bmatr_.get_row(i);
1491         if (bv)
1492             bv->clear_bit_no_check(idx);
1493     }
1494 }
1495 
1496 //---------------------------------------------------------------------
1497 
1498 template<class Val, class BV, unsigned MAX_SIZE>
insert_clear_value_planes_from(unsigned plane_idx,size_type idx)1499 void base_sparse_vector<Val, BV, MAX_SIZE>::insert_clear_value_planes_from(
1500                                         unsigned plane_idx, size_type idx)
1501 {
1502     for (unsigned i = plane_idx; i < sv_value_planes; ++i)
1503     {
1504         bvector_type* bv = this->bmatr_.get_row(i);
1505         if (bv)
1506             bv->insert(idx, false);
1507     }
1508 }
1509 
1510 //---------------------------------------------------------------------
1511 
1512 template<class Val, class BV, unsigned MAX_SIZE>
erase_column(size_type idx)1513 void base_sparse_vector<Val, BV, MAX_SIZE>::erase_column(size_type idx)
1514 {
1515     for (unsigned i = 0; i < sv_value_planes; ++i)
1516     {
1517         bvector_type* bv = this->bmatr_.get_row(i);
1518         if (bv)
1519             bv->erase(idx);
1520     }
1521 }
1522 
1523 //---------------------------------------------------------------------
1524 
1525 template<class Val, class BV, unsigned MAX_SIZE>
equal(const base_sparse_vector<Val,BV,MAX_SIZE> & sv,bm::null_support null_able)1526 bool base_sparse_vector<Val, BV, MAX_SIZE>::equal(
1527             const base_sparse_vector<Val, BV, MAX_SIZE>& sv,
1528              bm::null_support null_able) const BMNOEXCEPT
1529 {
1530     size_type arg_size = sv.size();
1531     if (this->size_ != arg_size)
1532     {
1533         return false;
1534     }
1535     unsigned planes = this->planes();
1536     for (unsigned j = 0; j < planes; ++j)
1537     {
1538         const bvector_type* bv = this->bmatr_.get_row(j);
1539         const bvector_type* arg_bv = sv.bmatr_.get_row(j);
1540         if (bv == arg_bv) // same NULL
1541             continue;
1542         // check if any not NULL and not empty
1543         if (!bv && arg_bv)
1544         {
1545             if (arg_bv->any())
1546                 return false;
1547             continue;
1548         }
1549         if (bv && !arg_bv)
1550         {
1551             if (bv->any())
1552                 return false;
1553             continue;
1554         }
1555         // both not NULL
1556         bool eq = bv->equal(*arg_bv);
1557         if (!eq)
1558             return false;
1559     } // for j
1560 
1561     if (null_able == bm::use_null)
1562     {
1563         const bvector_type* bv_null = this->get_null_bvector();
1564         const bvector_type* bv_null_arg = sv.get_null_bvector();
1565 
1566         // check the NULL vectors
1567         if (bv_null == bv_null_arg)
1568             return true;
1569         if (!bv_null || !bv_null_arg)
1570         {
1571             return false; // TODO: this may need an improvement when one is null, others not null
1572         }
1573         BM_ASSERT(bv_null);
1574         BM_ASSERT(bv_null_arg);
1575         bool eq = bv_null->equal(*bv_null_arg);
1576         if (!eq)
1577             return false;
1578     }
1579     return true;
1580 }
1581 
1582 //---------------------------------------------------------------------
1583 
1584 template<class Val, class BV, unsigned MAX_SIZE>
copy_range_planes(const base_sparse_vector<Val,BV,MAX_SIZE> & bsv,typename base_sparse_vector<Val,BV,MAX_SIZE>::size_type left,typename base_sparse_vector<Val,BV,MAX_SIZE>::size_type right,bm::null_support splice_null)1585 void base_sparse_vector<Val, BV, MAX_SIZE>::copy_range_planes(
1586         const base_sparse_vector<Val, BV, MAX_SIZE>& bsv,
1587         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
1588         typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
1589         bm::null_support splice_null)
1590 {
1591     bvector_type* bv_null = get_null_bvect();
1592     const bvector_type* bv_null_arg = bsv.get_null_bvector();
1593     unsigned planes;
1594     if (bv_null)
1595     {
1596         planes = this->stored_planes();
1597         if (bv_null_arg && (splice_null == bm::use_null))
1598             bv_null->copy_range(*bv_null_arg, left, right);
1599         --planes;
1600     }
1601     else
1602         planes = this->planes();
1603 
1604     for (unsigned j = 0; j < planes; ++j)
1605     {
1606         const bvector_type* arg_bv = bsv.bmatr_.row(j);
1607         if (arg_bv)
1608         {
1609             bvector_type* bv = this->bmatr_.get_row(j);
1610             if (!bv)
1611                 bv = this->get_plane(j);
1612             bv->copy_range(*arg_bv, left, right);
1613         }
1614     } // for j
1615 
1616 }
1617 
1618 //---------------------------------------------------------------------
1619 
1620 } // namespace
1621 
1622 #endif
1623