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