BitMagic-C++
bmbmatrix.h
Go to the documentation of this file.
1#ifndef BMBMATRIX__H__INCLUDED__
2#define BMBMATRIX__H__INCLUDED__
3/*
4Copyright(c) 2002-2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18For 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 <type_traits>
27
28#include "bmconst.h"
29
30#ifndef BM_NO_STL
31#include <stdexcept>
32#endif
33
34#include "bm.h"
35#include "bmtrans.h"
36#include "bmdef.h"
37
38
39
40namespace bm
41{
42
43/**
44 Basic dense bit-matrix class.
45
46 Container of row-major bit-vectors, forming a bit-matrix.
47 This class uses dense form of row storage.
48 It is applicable as a build block for other sparse containers and
49 succinct data structures, implementing high level abstractions.
50
51 @ingroup bmagic
52 @internal
53*/
54template<typename BV>
56{
57public:
58 typedef BV bvector_type;
61 typedef typename BV::allocator_type allocator_type;
63 typedef typename allocator_type::allocator_pool_type allocator_pool_type;
66 typedef unsigned char octet_type;
67
68public:
69 // ------------------------------------------------------------
70 /*! @name Construction, assignment */
71 ///@{
72
75 size_type bv_max_size = bm::id_max,
76 const allocator_type& alloc = allocator_type());
78
79 /*! copy-ctor */
80 basic_bmatrix(const basic_bmatrix<BV>& bbm);
81 basic_bmatrix<BV>& operator=(const basic_bmatrix<BV>& bbm)
82 {
83 copy_from(bbm);
84 return *this;
85 }
86
87#ifndef BM_NO_CXX11
88 /*! move-ctor */
90
91 /*! move assignmment operator */
93 {
94 if (this != &bbm)
95 {
96 free_rows();
97 swap(bbm);
98 }
99 return *this;
100 }
101
102#endif
103
106 { return pool_; }
107
108 ///@}
109
110 // ------------------------------------------------------------
111 /*! @name content manipulation */
112 ///@{
113
114 /*! Swap content */
116
117 /*! Copy content */
118 void copy_from(const basic_bmatrix<BV>& bbm);
119
120 /*! Freeze content into read-only mode drop editing overhead */
121 void freeze();
122
123 ///@}
124
125 // ------------------------------------------------------------
126 /*! @name row access */
127 ///@{
128
129 /*! Get row bit-vector. Can return NULL */
130 const bvector_type* row(size_type i) const BMNOEXCEPT;
131
132 /*! Get row bit-vector. Can return NULL */
134
135 /*! Get row bit-vector. Can return NULL */
137
138 /*! get number of value rows */
139 size_type rows() const BMNOEXCEPT { return rsize_; }
140
141 /*! get number of value rows without (not) NULLs bvector */
143
144 /*! get number of assigned avlue rows without \ NULLs bvector */
146
147
148 /*! Make sure row is constructed, return bit-vector */
150
151 /*! Make sure row is copy-constructed, return bit-vector */
153
154 /*! destruct/deallocate row */
156
157 /*! clear row bit-vector */
158 void clear_row(size_type row, bool free_mem);
159
160 /** return index of the NULL vector */
162
163 /** set index of the NULL vector */
164 void set_null_idx(size_type null_idx) BMNOEXCEPT;
165
166 /** allocate matrix rows of bit-vectors (new rows are NULLs) */
167 void allocate_rows(size_type rsize);
168
169 /** Free all rows */
170 void free_rows() BMNOEXCEPT;
171
172 ///@}
173
174
175 // ------------------------------------------------------------
176 /*! @name octet access and transposition */
177 ///@{
178
179 /*!
180 Bit-transpose an octet and assign it to a bit-matrix
181
182 @param pos - column position in the matrix
183 @param octet_idx - octet based row position (1 octet - 8 rows)
184 @param octet - value to assign
185 */
186 void set_octet(size_type pos, size_type octet_idx, unsigned char octet);
187
188 /*!
189 Bit-transpose and insert an octet and assign it to a bit-matrix
190
191 @param pos - column position in the matrix
192 @param octet_idx - octet based row position (1 octet - 8 rows)
193 @param octet - value to assign
194 */
195 void insert_octet(size_type pos, size_type octet_idx, unsigned char octet);
196
197 /*!
198 return octet from the matrix
199
200 @param pos - column position in the matrix
201 @param octet_idx - octet based row position (1 octet - 8 rows)
202 */
203 unsigned char get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT;
204
205 /*!
206 Compare vector[pos] with octet
207
208 It uses regulat comparison of chars to comply with the (signed)
209 char sort order.
210
211 @param pos - column position in the matrix
212 @param octet_idx - octet based row position (1 octet - 8 rows)
213 @param octet - octet value to compare
214
215 @return 0 - equal, -1 - less(vect[pos] < octet), 1 - greater
216 */
217 int compare_octet(size_type pos,
218 size_type octet_idx, char octet) const BMNOEXCEPT;
219
220 /*!
221 Return number of octet currently allocated rows in the matrix
222 */
224
225 ///@}
226
227
228 // ------------------------------------------------------------
229 /*! @name Utility functions */
230 ///@{
231
232
233 /// Get low level internal access to
234 const bm::word_t* get_block(size_type p,
235 unsigned i, unsigned j) const BMNOEXCEPT;
236
237 /**
238 Clear bit-planes bit
239 @param slice_from - clear from [from, until)
240 @param slice_until - clear until (open interval!)
241 @param idx - bit index
242 */
243 void clear_slices_range(unsigned slice_from, unsigned slize_until,
244 size_type idx);
245
246 unsigned get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT;
247
248 /*!
249 \brief run memory optimization for all bit-vector rows
250 \param temp_block - pre-allocated memory block to avoid re-allocs
251 \param opt_mode - requested compression depth
252 \param stat - memory allocation statistics after optimization
253 */
254 void optimize(
255 bm::word_t* temp_block = 0,
256 typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
257 typename bvector_type::statistics* stat = 0);
258
259 /*! Optimize block in all planes
260 @internal
261 */
262 void optimize_block(block_idx_type nb, typename BV::optmode opt_mode);
263
264 /*! Compute memory statistics
265 @param st [out] - statistics object
266 @param rsize - row size (for cases when operation is limited not to touch the NULL bit-vector)
267 */
268 void calc_stat(typename bvector_type::statistics& st,
269 size_type rsize) const BMNOEXCEPT;
270
271 /*! Erase column/element
272 @param idx - index (of column) / element of bit-vectors to erase
273 @param erase_null - erase all including NULL vector (true)
274 */
275 void erase_column(size_type idx, bool erase_null);
276
277 /*! Insert value 0 into a range of rows
278 @param idx - index (of column) / element of bit-vectors to erase
279 @param row_from - row to start from
280 */
281 void insert_column(size_type idx, size_type row_from);
282
283 /*! Clear value (set 0) into a range of rows
284 @param idx - index (of column) / element of bit-vectors
285 @param row_from - row to start from
286 */
287 void clear_column(size_type idx, size_type row_from);
288
289 /**
290 Set SUB (MINUS) operation on all existing rows
291 @param bv - argument vector row[i] -= bv
292 @param use_null - if true clear the NULL vector as well
293 */
294 void bit_sub_rows(const bvector_type& bv, bool use_null);
295
296 /**
297 Set AND (intersect) operation on all existing rows
298 @param bv - argument vector row[i] &= bv
299 */
300 void bit_and_rows(const bvector_type& bv);
301
302
303 ///@}
304
305protected:
306
308 void destruct_bvector(bvector_type* bv) const;
309
310 static
311 void throw_bad_alloc() { BV::throw_bad_alloc(); }
312
313 template<typename Val, typename BVect, unsigned MAX_SIZE>
314 friend class base_sparse_vector;
315
316protected:
321
324 size_type null_idx_; ///< Index of the NULL row
325};
326
327/**
328 Base class for bit-transposed(bit-sliced) sparse vector construction.
329 Keeps the basic housekeeping lements like matrix of sparse elements
330
331 @ingroup bmagic
332 @internal
333*/
334template<typename Val, typename BV, unsigned MAX_SIZE>
336{
337public:
339 {
340 sv_slices = (sizeof(Val) * 8 * MAX_SIZE + 1),
341 sv_value_slices = (sizeof(Val) * 8 * MAX_SIZE)
342 };
343
345 {
346 max_vector_size = MAX_SIZE
347 };
348
349 typedef Val value_type;
350 typedef BV bvector_type;
351 typedef typename BV::size_type size_type;
355 typedef typename BV::allocator_type allocator_type;
358 typedef typename allocator_type::allocator_pool_type allocator_pool_type;
360 typedef typename std::make_unsigned<value_type>::type unsigned_value_type;
361
362public:
364
367 size_type bv_max_size = bm::id_max,
368 const allocator_type& alloc = allocator_type());
369
371
372#ifndef BM_NO_CXX11
373 /*! move-ctor */
375 {
376 bmatr_.swap(bsv.bmatr_);
377 size_ = bsv.size_;
378 effective_slices_ = bsv.effective_slices_;
379 bsv.size_ = 0;
380 }
381#endif
382
384
385 size_type size() const BMNOEXCEPT { return size_; }
386
387 void resize(size_type new_size, bool set_null);
388
389 void clear_range(size_type left, size_type right, bool set_null);
390
392 bm::null_support slice_null);
393
394 /*! \brief resize to zero, free memory
395 @param free_mem - fully destroys the plane vectors if true
396 */
397 void clear_all(bool free_mem = true) BMNOEXCEPT;
398
399 /*! return true if empty */
400 bool empty() const BMNOEXCEPT { return size() == 0; }
401
402public:
403
404 // ------------------------------------------------------------
405 /*! @name Various traits */
406 ///@{
407 ///
408
409 /**
410 \brief returns true if value type is signed integral type
411 */
412 static constexpr bool is_signed() BMNOEXCEPT
413 { return std::is_signed<value_type>::value; }
414
415 /**
416 \brief check if container supports NULL(unassigned) values
417 */
418 bool is_nullable() const BMNOEXCEPT { return bmatr_.get_null_idx(); }
419
420 /**
421 \brief check if container supports NULL (unassigned) values
422 */
424 { return is_nullable() ? bm::use_null : bm::no_null; }
425
426 /**
427 \brief Get bit-vector of assigned values or NULL
428 (if not constructed that way)
429 */
431 {
432 if (size_type null_idx = bmatr_.get_null_idx())
433 return bmatr_.get_row(null_idx);
434 return 0;
435 }
436
437 /** \brief test if specified element is NULL
438 \param idx - element index
439 \return true if it is NULL false if it was assigned or container
440 is not configured to support assignment flags
441 */
442 bool is_null(size_type idx) const BMNOEXCEPT;
443
444 /**
445 Set allocation pool
446 */
448 { bmatr_.set_allocator_pool(pool_ptr); }
449
450 /**
451 Get allocation pool
452 */
454 { return bmatr_.get_allocator_pool(); }
455
456 ///@}
457
458
459 // ------------------------------------------------------------
460 /*! @name Access to internals */
461 ///@{
462
463 /*!
464 \brief get access to bit-plain, function checks and creates a plane
465 \return bit-vector for the bit plain
466 @internal
467 */
469
470 /*!
471 \brief get read-only access to bit-plane
472 \return bit-vector for the bit plane or NULL
473 @internal
474 */
476 get_slice(unsigned i) const BMNOEXCEPT { return bmatr_.row(i); }
477
478 /*!
479 \brief get total number of bit-planes in the vector
480 @internal
481 */
482 static unsigned slices() BMNOEXCEPT { return value_bits(); }
483
484 /** Number of stored bit-planes (value planes + extra
485 @internal
486 */
487 static unsigned stored_slices() BMNOEXCEPT { return value_bits()+1; }
488
489
490 /** Number of effective bit-planes in the value type
491 @internal
492 */
494 { return effective_slices_ + 1; }
495
496 /*!
497 \brief get access to bit-plane as is (can return NULL)
498 @internal
499 */
500 bvector_type_ptr slice(unsigned i) BMNOEXCEPT { return bmatr_.get_row(i); }
502 { return bmatr_.get_row(i); }
503
505 {
506 if (size_type null_idx = bmatr_.get_null_idx())
507 return bmatr_.get_row(null_idx);
508 return 0;
509 }
510
511 /*!
512 \brief free memory in bit-plane
513 @internal
514 */
515 void free_slice(unsigned i) { bmatr_.destruct_row(i); }
516
517 /*!
518 return mask of allocated bit-planes
519 1 in the mask - means bit-plane N is present
520 returns 64-bit unsigned mask for sub 64-bit types (like int)
521 unallocated mask bits will be zero extended
522
523 @return 64-bit mask
524 @internal
525 */
526 bm::id64_t get_slice_mask(unsigned element_idx) const BMNOEXCEPT;
527
528 /*!
529 get read-only access to inetrnal bit-matrix
530 @internal
531 */
532 const bmatrix_type& get_bmatrix() const BMNOEXCEPT { return bmatr_; }
533
534 /**
535 access to internal bit-matrix
536 @internal
537 */
539
540 /**
541 Set NULL plain index
542 @internal
543 */
544 void mark_null_idx(unsigned null_idx) BMNOEXCEPT
545 { bmatr_.null_idx_ = null_idx; }
546 /**
547 Convert signed value type to unsigned representation
548 @internal
549 */
550 static
552
553 /**
554 Convert unsigned value type to signed representation
555 @internal
556 */
557 static
559
560
561 ///@}
562 ///
563 // -------------------------------------------------------------------
564
565 /*!
566 \brief run memory optimization for all bit-vector rows
567 \param temp_block - pre-allocated memory block to avoid unnecessary re-allocs
568 \param opt_mode - requested compression depth
569 \param stat - memory allocation statistics after optimization
570 */
571 void optimize(bm::word_t* temp_block = 0,
573 typename bvector_type::statistics* stat = 0);
574
575 /*!
576 @brief Calculates memory statistics.
577
578 Function fills statistics structure containing information about how
579 this vector uses memory and estimation of max. amount of memory
580 bvector needs to serialize itself.
581
582 @param st - pointer on statistics structure to be filled in.
583
584 @sa statistics
585 */
587
588 /*!
589 \brief check if another sparse vector has the same content and size
590
591 \param sv - sparse vector for comparison
592 \param null_able - flag to consider NULL vector in comparison (default)
593 or compare only value content planes
594
595 \return true, if it is the same
596 */
598 bm::null_support null_able = bm::use_null) const BMNOEXCEPT;
599
600protected:
602
603 /**
604 Merge plane bvectors from an outside base matrix
605 Note: outside base matrix gets destroyed
606 */
608
609 /**
610 Turn on RO mode
611 */
612 void freeze_matr() { bmatr_.freeze(); is_ro_ = true; }
613
614 /*!
615 clear column in all value planes
616 \param plane_idx - row (plane index to start from)
617 \param idx - bit (column) to clear
618 */
619 void clear_value_planes_from(unsigned plane_idx, size_type idx);
620
621 /*!
622 insert false (clear) column in all value planes
623 \param plane_idx - row (plane index to start from)
624 \param idx - bit (column) to clear insert
625 */
626 void insert_clear_value_planes_from(unsigned plane_idx, size_type idx);
627
628 /*!
629 erase bit (column) from all planes
630 \param idx - bit (column) to erase
631 \param erase_null - erase the NULL vector
632 */
633 void erase_column(size_type idx, bool erase_null);
634
635 /*!
636 insert (NOT) NULL value
637 */
638 void insert_null(size_type idx, bool not_null);
639
640 /**
641 Set SUB (MINUS) operation on all existing bit-slices
642 @param bv - argument vector row[i] -= bv
643 */
644 void bit_sub_rows(const bvector_type& bv, bool use_null)
646
647 /**
648 Set AND (intersect) operation on all existing bit-slices
649 @param bv - argument vector row[i] -= bv
650 */
652
653protected:
655
656 /** Number of total bit-planes in the value type*/
657 static constexpr unsigned value_bits() BMNOEXCEPT
659
660 /** plane index for the "NOT NULL" flags plane */
661 //static constexpr unsigned null_plane() BMNOEXCEPT { return value_bits(); }
662
663 /** optimize block in all matrix planes */
664 void optimize_block(block_idx_type nb, typename BV::optmode opt_mode)
665 { bmatr_.optimize_block(nb, opt_mode); }
666
667 /**
668 Perform copy_range() on a set of planes
669 */
674 bm::null_support slice_null);
675
676protected:
677 bmatrix_type bmatr_; ///< bit-transposed matrix
678 unsigned_value_type slice_mask_ = 0; ///< slice presence bit-mask
679 size_type size_ = 0; ///< array size
680 unsigned effective_slices_=0; ///< number of bit slices actually allocated
681 bool is_ro_=false; ///< read-only
682};
683
684//---------------------------------------------------------------------
685//
686//---------------------------------------------------------------------
687
688#ifdef _MSC_VER
689#pragma warning( push )
690#pragma warning( disable : 4146 )
691#endif
692
693template<typename BV>
696 size_type bv_max_size,
697 const allocator_type& alloc)
698: bv_size_(bv_max_size),
699 alloc_(alloc),
700 ap_(ap),
701 pool_(0),
702 bv_rows_(0),
703 rsize_(0),
704 null_idx_(0)
705{
706 allocate_rows(rsize);
707}
708
709//---------------------------------------------------------------------
710
711template<typename BV>
713{
714 free_rows();
715}
716
717//---------------------------------------------------------------------
718
719template<typename BV>
721: bv_size_(bbm.bv_size_),
722 alloc_(bbm.alloc_),
723 ap_(bbm.ap_),
724 pool_(0),
725 bv_rows_(0),
726 rsize_(0),
727 null_idx_(0)
728{
729 copy_from(bbm);
730}
731
732//---------------------------------------------------------------------
733
734template<typename BV>
736: bv_size_(bbm.bv_size_),
737 alloc_(bbm.alloc_),
738 ap_(bbm.ap_),
739 pool_(0),
740 bv_rows_(0),
741 rsize_(0),
742 null_idx_(0)
743{
744 swap(bbm);
745}
746
747//---------------------------------------------------------------------
748
749template<typename BV>
752{
753 BM_ASSERT(i < rsize_);
754 return bv_rows_[i];
755}
756
757//---------------------------------------------------------------------
758
759template<typename BV>
762{
763 BM_ASSERT(i < rsize_);
764 return bv_rows_[i];
765}
766
767//---------------------------------------------------------------------
768
769template<typename BV>
772{
773 BM_ASSERT(i < rsize_);
774 return bv_rows_[i];
775}
776
777//---------------------------------------------------------------------
778
779template<typename BV>
781{
782 BM_ASSERT(null_idx);
783 BM_ASSERT(get_row(null_idx));
784 null_idx_ = null_idx;
785}
786
787//---------------------------------------------------------------------
788
789template<typename BV>
791{
792 if (this == &bbm) // nothing to do
793 return;
794 free_rows();
795
796 bv_size_ = bbm.bv_size_;
797 alloc_ = bbm.alloc_;
798 ap_ = bbm.ap_;
799
800 null_idx_ = bbm.null_idx_;
801
802 size_type rsize = bbm.rsize_;
803 if (rsize)
804 {
805 bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(rsize);
806 if (!bv_rows_)
807 throw_bad_alloc();
808 rsize_ = rsize;
809 for (size_type i = 0; i < rsize_; ++i)
810 {
811 const bvector_type_ptr bv = bbm.bv_rows_[i];
812 bv_rows_[i] = bv ? construct_bvector(bv) : 0;
813 }
814 }
815}
816
817//---------------------------------------------------------------------
818
819template<typename BV>
821{
822 // relies that NULL bvector is the last
823 size_type r_to = (!erase_null && null_idx_) ? null_idx_ : rsize_;
824 for (size_type i = 0; i < r_to; ++i)
825 if (bvector_type* bv = get_row(i))
826 bv->erase(idx);
827}
828
829//---------------------------------------------------------------------
830
831template<typename BV>
833 size_type row_from)
834{
835 for (size_type i = row_from; i < rsize_; ++i)
836 if (bvector_type* bv = get_row(i))
837 bv->insert(idx, false);
838}
839
840//---------------------------------------------------------------------
841
842template<typename BV>
844 size_type row_from)
845{
846 for (size_type i = row_from; i < rsize_; ++i)
847 if (bvector_type* bv = get_row(i))
848 bv->clear_bit_no_check(idx);
849}
850
851//---------------------------------------------------------------------
852
853template<typename BV>
855{
856 size_type rsize_prev(rsize_);
857 if (rsize <= rsize_prev)
858 return; // nothing to do
859 bvector_type_ptr* bv_rows_prev(bv_rows_);
860
861 BM_ASSERT(rsize);
862 bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(unsigned(rsize));
863 if (!bv_rows_)
864 throw_bad_alloc();
865 rsize_ = rsize;
866 BM_ASSERT((!null_idx_) || (rsize & 1u));
867 ::memset(&bv_rows_[0], 0, rsize * sizeof(bv_rows_[0]));
868 if (bv_rows_prev) // deallocate prev, reset NULL
869 {
870 for (size_type i = 0; i < rsize_prev; ++i)
871 bv_rows_[i] = bv_rows_prev[i];
872 alloc_.free_ptr(bv_rows_prev, unsigned(rsize_prev));
873 if (null_idx_) // shift-up the NULL row
874 {
875 bv_rows_[rsize-1] = bv_rows_[null_idx_];
876 bv_rows_[null_idx_] = 0;
877 null_idx_ = rsize-1;
878 }
879 }
880}
881
882//---------------------------------------------------------------------
883
884template<typename BV>
887{
888 size_type osize = (7 + rows_not_null()) / 8;
889 return osize;
890}
891
892
893//---------------------------------------------------------------------
894
895template<typename BV>
897{
898 for (size_type i = 0; i < rsize_; ++i)
899 {
900 if (bvector_type_ptr bv = bv_rows_[i])
901 {
902 destruct_bvector(bv);
903 bv_rows_[i] = 0;
904 }
905 } // for i
906 if (bv_rows_)
907 alloc_.free_ptr(bv_rows_, unsigned(rsize_));
908 bv_rows_ = 0;
909}
910
911//---------------------------------------------------------------------
912
913template<typename BV>
915{
916 if (pool_ != pool_ptr)
917 {
918 for (size_type i = 0; i < rsize_; ++i)
919 if (bvector_type_ptr bv = bv_rows_[i])
920 bv->set_allocator_pool(pool_ptr);
921 }
922 pool_ = pool_ptr;
923}
924
925
926//---------------------------------------------------------------------
927
928template<typename BV>
931{
932 // TODO: SIMD
933 auto i = rows_not_null();
934 for (--i; i > 0; --i)
935 {
936 if (bv_rows_[i])
937 {
938 ++i;
939 break;
940 }
941 }
942 return i;
943}
944
945//---------------------------------------------------------------------
946
947template<typename BV>
949{
950 size_type sz = use_null ? rsize_: calc_effective_rows_not_null();
951 for (size_type i = 0; i < sz; ++i)
952 {
953 if (bvector_type_ptr bv_r = bv_rows_[i])
954 bv_r->bit_sub(bv);
955 } // for i
956}
957
958//---------------------------------------------------------------------
959
960template<typename BV>
962{
963 for (size_type i = 0; i < rsize_; ++i)
964 {
965 if (bvector_type_ptr bv_r = bv_rows_[i])
966 bv_r->bit_and(bv);
967 } // for i
968}
969
970//---------------------------------------------------------------------
971
972template<typename BV>
974{
975 if (this == &bbm)
976 return;
977
978 bm::xor_swap(bv_size_, bbm.bv_size_);
979
980 allocator_type alloc_tmp = alloc_;
981 alloc_ = bbm.alloc_;
982 bbm.alloc_ = alloc_tmp;
983
984 allocation_policy_type ap_tmp = ap_;
985 ap_ = bbm.ap_;
986 bbm.ap_ = ap_tmp;
987
988 allocator_pool_type* pool_tmp = pool_;
989 pool_ = bbm.pool_;
990 bbm.pool_ = pool_tmp;
991
992 bm::xor_swap(rsize_, bbm.rsize_);
993 bm::xor_swap(null_idx_, bbm.null_idx_);
994
995 bvector_type_ptr* rtmp = bv_rows_;
996 bv_rows_ = bbm.bv_rows_;
997 bbm.bv_rows_ = rtmp;
998}
999
1000//---------------------------------------------------------------------
1001
1002template<typename BV>
1005{
1006 if (row > rsize_)
1007 allocate_rows(row + 8);
1008 BM_ASSERT(row < rsize_);
1009 bvector_type_ptr bv = bv_rows_[row];
1010 if (!bv)
1011 bv = bv_rows_[row] = construct_bvector(0);
1012 return bv;
1013}
1014
1015//---------------------------------------------------------------------
1016
1017template<typename BV>
1020{
1021 if (row > rsize_)
1022 allocate_rows(row + 8);
1023 BM_ASSERT(row < rsize_);
1024 bvector_type_ptr bv = bv_rows_[row];
1025 if (bv)
1026 *bv = bv_src;
1027 else
1028 bv = bv_rows_[row] = construct_bvector(&bv_src);
1029 return bv;
1030}
1031
1032
1033//---------------------------------------------------------------------
1034
1035template<typename BV>
1037{
1038 BM_ASSERT(row < rsize_);
1039 if (bvector_type_ptr bv = bv_rows_[row])
1040 {
1041 destruct_bvector(bv);
1042 bv_rows_[row] = 0;
1043 }
1044}
1045
1046//---------------------------------------------------------------------
1047
1048template<typename BV>
1050{
1051 BM_ASSERT(row < rsize_);
1052 if (bvector_type_ptr bv = bv_rows_[row])
1053 {
1054 if (free_mem)
1055 {
1056 destruct_bvector(bv);
1057 bv_rows_[row] = 0;
1058 }
1059 else
1060 bv->clear(true);
1061 }
1062}
1063
1064//---------------------------------------------------------------------
1065
1066template<typename BV>
1069{
1070 bvector_type* rbv = 0;
1071#ifdef BM_NO_STL // C compatibility mode
1072 void* mem = ::malloc(sizeof(bvector_type));
1073 if (mem == 0)
1074 {
1075 BM_THROW(false, BM_ERR_BADALLOC);
1076 }
1077 if (bv)
1078 rbv = new(mem) bvector_type(*bv);
1079 else
1080 {
1081 rbv = new(mem) bvector_type(ap_.strat, ap_.glevel_len, bv_size_, alloc_);
1082 rbv->init();
1083 }
1084#else
1085 if (bv)
1086 rbv = new bvector_type(*bv);
1087 else
1088 {
1089 rbv = new bvector_type(ap_.strat, ap_.glevel_len, bv_size_, alloc_);
1090 rbv->init();
1091 }
1092#endif
1093 if (pool_)
1094 rbv->set_allocator_pool(pool_);
1095 return rbv;
1096}
1097
1098//---------------------------------------------------------------------
1099
1100template<typename BV>
1102{
1103#ifdef BM_NO_STL // C compatibility mode
1104 bv->~TBM_bvector();
1105 ::free((void*)bv);
1106#else
1107 delete bv;
1108#endif
1109}
1110
1111//---------------------------------------------------------------------
1112
1113template<typename BV>
1114const bm::word_t*
1116 unsigned i, unsigned j) const BMNOEXCEPT
1117{
1118 if (bvector_type_const_ptr bv = this->row(p))
1119 return bv->get_blocks_manager().get_block_ptr(i, j);
1120 return 0;
1121}
1122
1123//---------------------------------------------------------------------
1124
1125template<typename BV>
1127 unsigned slice_from, unsigned slice_until,
1128 size_type idx)
1129{
1130 for (unsigned p = slice_from; p < slice_until; ++p)
1131 if (bvector_type* bv = this->get_row(p)) // TODO: optimize cleaning
1132 bv->clear_bit_no_check(idx);
1133}
1134
1135
1136//---------------------------------------------------------------------
1137
1138template<typename BV>
1140 size_type octet_idx,
1141 unsigned char octet)
1142{
1143 if (7u + octet_idx * 8u > rsize_)
1144 allocate_rows(rsize_ + 16);
1145
1146 size_type row = octet_idx * 8;
1147 size_type row_end = row + 8;
1148 for (; row < row_end; ++row)
1149 {
1150 bvector_type* bv = (row < rsize_) ? this->get_row(row) : 0;
1151 if (octet & 1u)
1152 {
1153 if (!bv)
1154 bv = this->construct_row(row);
1155 bv->set_bit_no_check(pos);
1156 }
1157 else
1158 {
1159 if (bv)
1160 bv->clear_bit_no_check(pos);
1161 }
1162 octet >>= 1;
1163 if (!octet)
1164 break;
1165 } // for
1166
1167 // clear the tail
1168 if (row_end > rsize_)
1169 row_end = rsize_;
1170 for (++row; row < row_end; ++row)
1171 if (bvector_type* bv = this->get_row(row))
1172 bv->clear_bit_no_check(pos);
1173}
1174
1175//---------------------------------------------------------------------
1176
1177template<typename BV>
1179 size_type octet_idx,
1180 unsigned char octet)
1181{
1182 BM_ASSERT(octet_idx * 8u < rsize_);
1183
1184 size_type oct = octet;
1185 size_type row = octet_idx * 8;
1186 size_type row_end = row + 8;
1187 for (; row < row_end; ++row)
1188 {
1189 bvector_type* bv = (row < rsize_) ? this->get_row(row) : 0;
1190 if (oct & 1u)
1191 {
1192 if (!bv)
1193 {
1194 bv = this->construct_row(row);
1195 bv->set_bit_no_check(pos);
1196 }
1197 else
1198 {
1199 bv->insert(pos, true);
1200 }
1201 }
1202 else
1203 {
1204 if (bv)
1205 bv->insert(pos, false);
1206 }
1207 oct >>= 1;
1208 if (!oct)
1209 break;
1210 } // for
1211
1212 // clear the tail
1213 if (row_end > rsize_)
1214 row_end = rsize_;
1215 for (++row; row < row_end; ++row)
1216 if (bvector_type* bv = this->get_row(row))
1217 bv->insert(pos, false);
1218}
1219
1220
1221//---------------------------------------------------------------------
1222
1223template<typename BV>
1224unsigned char
1226{
1227 unsigned v = 0;
1228
1229 block_idx_type nb = (pos >> bm::set_block_shift);
1230 unsigned i0 = unsigned(nb >> bm::set_array_shift); // top block address
1231 unsigned j0 = unsigned(nb & bm::set_array_mask); // address in sub-block
1232
1233 const bm::word_t* blk;
1234 const bm::word_t* blka[8];
1235 unsigned nbit = unsigned(pos & bm::set_block_mask);
1236 unsigned nword = unsigned(nbit >> bm::set_word_shift);
1237 unsigned mask0 = 1u << (nbit & bm::set_word_mask);
1238
1239 unsigned row_idx = unsigned(octet_idx * 8);
1240 if (row_idx + 7 >= rsize_ ||
1241 (null_idx_ && (row_idx + 7 > null_idx_))) // out of bounds request?
1242 return (unsigned char)v;
1243
1244 blka[0] = get_block(row_idx+0, i0, j0);
1245 blka[1] = get_block(row_idx+1, i0, j0);
1246 blka[2] = get_block(row_idx+2, i0, j0);
1247 blka[3] = get_block(row_idx+3, i0, j0);
1248 blka[4] = get_block(row_idx+4, i0, j0);
1249 blka[5] = get_block(row_idx+5, i0, j0);
1250 blka[6] = get_block(row_idx+6, i0, j0);
1251 blka[7] = get_block(row_idx+7, i0, j0);
1252 unsigned is_set;
1253
1254 if ((blk = blka[0])!=0)
1255 {
1256 if (blk == FULL_BLOCK_FAKE_ADDR)
1257 is_set = 1;
1258 else
1259 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1260 v |= (unsigned)bool(is_set);
1261 }
1262 if ((blk = blka[1])!=0)
1263 {
1264 if (blk == FULL_BLOCK_FAKE_ADDR)
1265 is_set = 1;
1266 else
1267 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1268 v |= unsigned(bool(is_set)) << 1u;
1269 }
1270 if ((blk = blka[2])!=0)
1271 {
1272 if (blk == FULL_BLOCK_FAKE_ADDR)
1273 is_set = 1;
1274 else
1275 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1276 v |= unsigned(bool(is_set)) << 2u;
1277 }
1278 if ((blk = blka[3])!=0)
1279 {
1280 if (blk == FULL_BLOCK_FAKE_ADDR)
1281 is_set = 1;
1282 else
1283 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1284 v |= unsigned(bool(is_set)) << 3u;
1285 }
1286
1287
1288 if ((blk = blka[4])!=0)
1289 {
1290 if (blk == FULL_BLOCK_FAKE_ADDR)
1291 is_set = 1;
1292 else
1293 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1294 v |= unsigned(bool(is_set)) << 4u;
1295 }
1296 if ((blk = blka[5])!=0)
1297 {
1298 if (blk == FULL_BLOCK_FAKE_ADDR)
1299 is_set = 1;
1300 else
1301 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1302 v |= unsigned(bool(is_set)) << 5u;
1303 }
1304 if ((blk = blka[6])!=0)
1305 {
1306 if (blk == FULL_BLOCK_FAKE_ADDR)
1307 is_set = 1;
1308 else
1309 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1310 v |= unsigned(bool(is_set)) << 6u;
1311 }
1312 if ((blk = blka[7])!=0)
1313 {
1314 if (blk == FULL_BLOCK_FAKE_ADDR)
1315 is_set = 1;
1316 else
1317 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1318 v |= unsigned(bool(is_set)) << 7u;
1319 }
1320
1321 return (unsigned char)v;
1322}
1323
1324//---------------------------------------------------------------------
1325
1326template<typename BV>
1328 size_type octet_idx,
1329 char octet) const BMNOEXCEPT
1330{
1331 char value = char(get_octet(pos, octet_idx));
1332 return (value > octet) - (value < octet);
1333}
1334
1335//---------------------------------------------------------------------
1336
1337/**
1338 Test 4 pointers are all marked as GAPs
1339 @internal
1340 */
1341inline
1342bool test_4gaps(const bm::word_t* p0, const bm::word_t* p1,
1343 const bm::word_t* p2, const bm::word_t* p3) BMNOEXCEPT
1344{
1345 uintptr_t p
1346 = uintptr_t(p0) | uintptr_t(p1) | uintptr_t(p2) | uintptr_t(p3);
1347 return (p & 1);
1348}
1349/**
1350 Test 4 pointers are not NULL and not marked as FULLBLOCK
1351 @internal
1352*/
1353inline
1354bool test_4bits(const bm::word_t* p0, const bm::word_t* p1,
1355 const bm::word_t* p2, const bm::word_t* p3) BMNOEXCEPT
1356{
1357 return p0 && p0!=FULL_BLOCK_FAKE_ADDR &&
1358 p1 && p1!=FULL_BLOCK_FAKE_ADDR &&
1359 p2 && p2!=FULL_BLOCK_FAKE_ADDR &&
1360 p3 && p3!=FULL_BLOCK_FAKE_ADDR;
1361}
1362
1363
1364template<typename BV>
1365unsigned
1367{
1368 unsigned v = 0;
1369
1370 block_idx_type nb = (pos >> bm::set_block_shift);
1371 unsigned i0 = unsigned(nb >> bm::set_array_shift); // top block address
1372 unsigned j0 = unsigned(nb & bm::set_array_mask); // address in sub-block
1373
1374 const bm::word_t* blk;
1375 const bm::word_t* blka[4];
1376 unsigned nbit = unsigned(pos & bm::set_block_mask);
1377
1378 blka[0] = get_block(row_idx+0, i0, j0);
1379 blka[1] = get_block(row_idx+1, i0, j0);
1380 blka[2] = get_block(row_idx+2, i0, j0);
1381 blka[3] = get_block(row_idx+3, i0, j0);
1382 unsigned is_set;
1383
1384
1385 unsigned nword = unsigned(nbit >> bm::set_word_shift);
1386 unsigned mask0 = 1u << (nbit & bm::set_word_mask);
1387
1388 // speculative assumption that nibble is often 4 bit-blocks
1389 // and we will be able to extract it faster with less mispredicts
1390 //
1391 if (!test_4gaps(blka[0], blka[1], blka[2], blka[3]))
1392 {
1393 if (test_4bits(blka[0], blka[1], blka[2], blka[3]))
1394 {
1395 v = unsigned(bool((blka[0][nword] & mask0))) |
1396 unsigned(bool((blka[1][nword] & mask0)) << 1u) |
1397 unsigned(bool((blka[2][nword] & mask0)) << 2u) |
1398 unsigned(bool((blka[3][nword] & mask0)) << 3u);
1399 return v;
1400 }
1401 }
1402 // hypothesis above didn't work out extract the regular way
1403 unsigned i = 0;
1404 do
1405 {
1406 if ((blk = blka[i])!=0)
1407 {
1408 if (blk == FULL_BLOCK_FAKE_ADDR)
1409 is_set = 1;
1410 else
1411 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1412 v |= unsigned(bool(is_set)) << i;
1413 }
1414 if ((blk = blka[++i])!=0)
1415 {
1416 if (blk == FULL_BLOCK_FAKE_ADDR)
1417 is_set = 1;
1418 else
1419 is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
1420 v |= unsigned(bool(is_set)) << i;
1421 }
1422 } while(++i < 4);
1423 return v;
1424}
1425
1426//---------------------------------------------------------------------
1427
1428template<typename BV>
1430 typename bvector_type::optmode opt_mode,
1431 typename bvector_type::statistics* st)
1432{
1433 if (st)
1434 st->reset();
1435
1437 if (!temp_block)
1438 temp_block = tb;
1439
1440 for (unsigned k = 0; k < rsize_; ++k)
1441 {
1442 if (bvector_type* bv = get_row(k))
1443 {
1444 typename bvector_type::statistics stbv;
1445 stbv.reset();
1446 bv->optimize(temp_block, opt_mode, st ? &stbv : 0);
1447 if (st)
1448 st->add(stbv);
1449 }
1450 } // for k
1451}
1452
1453//---------------------------------------------------------------------
1454
1455template<typename BV>
1457{
1458 for (unsigned k = 0; k < rsize_; ++k)
1459 if (bvector_type* bv = get_row(k))
1460 bv->freeze();
1461}
1462
1463//---------------------------------------------------------------------
1464
1465template<typename BV>
1467 size_type rsize) const BMNOEXCEPT
1468{
1469 for (size_type i = 0; i < rsize; ++i)
1470 if (const bvector_type* bv = row(i))
1471 {
1472 typename bvector_type::statistics stbv;
1473 bv->calc_stat(&stbv);
1474 st.add(stbv);
1475 }
1476 else
1477 st.max_serialize_mem += 8;
1478}
1479
1480//---------------------------------------------------------------------
1481
1482template<typename BV>
1484 typename BV::optmode opt_mode)
1485{
1486 for (unsigned k = 0; k < rsize_; ++k)
1487 {
1488 if (bvector_type* bv = get_row(k))
1489 {
1490 unsigned i, j;
1491 bm::get_block_coord(nb, i, j);
1492 typename bvector_type::blocks_manager_type& bman =
1493 bv->get_blocks_manager();
1494 bman.optimize_bit_block(i, j, opt_mode);
1495 }
1496 } // for k
1497
1498}
1499
1500//---------------------------------------------------------------------
1501//---------------------------------------------------------------------
1502
1503
1504
1505template<class Val, class BV, unsigned MAX_SIZE>
1507: bmatr_(sv_slices, allocation_policy_type(), bm::id_max, allocator_type())
1508{}
1509
1510//---------------------------------------------------------------------
1511
1512template<class Val, class BV, unsigned MAX_SIZE>
1514 bm::null_support null_able,
1516 size_type bv_max_size,
1517 const allocator_type& alloc)
1518: bmatr_(sv_slices, ap, bv_max_size, alloc)
1519{
1520 if (null_able == bm::use_null)
1521 {
1522 size_type null_idx = (MAX_SIZE * sizeof(Val) * 8);
1523 bmatr_.construct_row(null_idx)->init();
1524 bmatr_.set_null_idx(null_idx);
1525 slice_mask_ |= unsigned_value_type(1) << null_idx;
1526 }
1527}
1528
1529//---------------------------------------------------------------------
1530
1531template<class Val, class BV, unsigned MAX_SIZE>
1534: bmatr_(bsv.bmatr_),
1535 slice_mask_(bsv.slice_mask_),
1536 size_(bsv.size_),
1537 effective_slices_(bsv.effective_slices_)
1538{}
1539
1540//---------------------------------------------------------------------
1541
1542template<class Val, class BV, unsigned MAX_SIZE>
1545{
1546 resize(bsv.size(), true);
1547 effective_slices_ = bsv.effective_slices_;
1548
1549 size_type arg_null_idx = bsv.bmatr_.get_null_idx();
1550 if (arg_null_idx)
1551 bmatr_.null_idx_ = arg_null_idx;
1552
1553 size_type slices = bsv.get_bmatrix().rows(); //stored_slices();
1554 bmatr_.allocate_rows(slices);
1555 for (size_type i = 0; i < slices; ++i)
1556 {
1557 bvector_type* bv = bmatr_.get_row(i);
1558 const bvector_type* bv_src = bsv.bmatr_.row(i);
1559
1560 if (i && (i == arg_null_idx)) // NULL plane copy
1561 {
1562 if (bv && !bv_src) // special case (copy from not NULL)
1563 {
1564 if (size_)
1565 bv->set_range(0, size_-1);
1566 continue;
1567 }
1568 }
1569 if (bv)
1570 {
1571 bmatr_.destruct_row(i);
1572 slice_mask_ &= ~(unsigned_value_type(1) << i);
1573 }
1574 if (bv_src)
1575 {
1576 bmatr_.construct_row(i, *bv_src);
1577 slice_mask_ |= (unsigned_value_type(1) << i);
1578 }
1579 } // for i
1580}
1581
1582//---------------------------------------------------------------------
1583
1584template<class Val, class BV, unsigned MAX_SIZE>
1586 bmatrix_type& bmatr)
1587{
1588 size_type rows = this->bmatr_.rows();
1589 const size_type arg_rows = bmatr.rows();
1590 if (rows < arg_rows)
1591 {
1592 rows = arg_rows;
1593 bmatr_.allocate_rows(rows);
1594 BM_ASSERT(this->bmatr_.rows() == arg_rows);
1595 }
1596
1597 bvector_type* bv_null_arg = 0;
1598 size_type null_idx = bmatr.get_null_idx();
1599 if (null_idx)
1600 bv_null_arg = bmatr.get_row(null_idx);
1601
1602 if (bvector_type* bv_null = get_null_bvect())
1603 {
1604 BM_ASSERT(bv_null_arg);
1605 bv_null->merge(*bv_null_arg);
1606 }
1607 if (rows > arg_rows)
1608 rows = arg_rows; // min
1609 for (unsigned j = 0; j < rows; ++j)
1610 {
1611 bvector_type* arg_bv = bmatr.get_row(j);
1612 if (arg_bv && arg_bv != bv_null_arg)
1613 {
1614 bvector_type* bv = this->get_create_slice(j);
1615 slice_mask_ |= (unsigned_value_type(1) << j);
1616 bv->merge(*arg_bv);
1617 }
1618 } // for j
1619}
1620
1621//---------------------------------------------------------------------
1622
1623template<class Val, class BV, unsigned MAX_SIZE>
1626{
1627 if (this != &bsv)
1628 {
1629 bmatr_.swap(bsv.bmatr_);
1630 bm::xor_swap(slice_mask_, bsv.slice_mask_);
1631 bm::xor_swap(size_, bsv.size_);
1632 bm::xor_swap(effective_slices_, bsv.effective_slices_);
1633 }
1634}
1635
1636//---------------------------------------------------------------------
1637
1638template<class Val, class BV, unsigned MAX_SIZE>
1640{
1641 auto slices = bmatr_.rows();
1642 bvector_type* bv_null = this->get_null_bvect();
1643 for (size_type i = 0; i < slices; ++i)
1644 if (bvector_type* bv = this->bmatr_.get_row(i))
1645 if (bv != bv_null)
1646 bmatr_.clear_row(i, free_mem);
1647 slice_mask_ = 0; size_ = 0;
1648 if (bv_null)
1649 bv_null->clear(true);
1650}
1651
1652//---------------------------------------------------------------------
1653
1654template<class Val, class BV, unsigned MAX_SIZE>
1658 bool set_null)
1659{
1660 if (right < left)
1661 return clear_range(right, left, set_null);
1662 auto planes = bmatr_.rows();
1663 bvector_type* bv_null = this->get_null_bvect();
1664 for (unsigned i = 0; i < planes; ++i)
1665 {
1666 if (bvector_type* bv = this->bmatr_.get_row(i))
1667 if (bv != bv_null)
1668 bv->clear_range_no_check(left, right);
1669 }
1670 if (set_null && bv_null)
1671 bv_null->clear_range_no_check(left, right);
1672}
1673
1674//---------------------------------------------------------------------
1675
1676template<class Val, class BV, unsigned MAX_SIZE>
1678 size_type left, size_type right,
1679 bm::null_support slice_null)
1680{
1681 if (left)
1682 this->clear_range(0, left-1, (slice_null == bm::use_null));
1683 size_type sz = size();
1684 if (right < sz)
1685 this->clear_range(right + 1, sz, (slice_null == bm::use_null));
1686}
1687
1688//---------------------------------------------------------------------
1689
1690template<class Val, class BV, unsigned MAX_SIZE>
1692{
1693 if (sz == size()) // nothing to do
1694 return;
1695 if (!sz) // resize to zero is an equivalent of non-destructive deallocation
1696 {
1697 clear_all();
1698 return;
1699 }
1700 if (sz < size()) // vector shrink
1701 clear_range(sz, this->size_, set_null); // clear the tails and NULL
1702 size_ = sz;
1703}
1704
1705
1706//---------------------------------------------------------------------
1707
1708template<class Val, class BV, unsigned MAX_SIZE>
1710 size_type idx) const BMNOEXCEPT
1711{
1712 const bvector_type* bv_null = get_null_bvector();
1713 return (bv_null) ? (!bv_null->test(idx)) : false;
1714}
1715
1716//---------------------------------------------------------------------
1717
1718template<class Val, class BV, unsigned MAX_SIZE>
1720 bool not_null)
1721{
1722 if (bvector_type* bv_null = this->get_null_bvect())
1723 bv_null->insert(idx, not_null);
1724}
1725
1726//---------------------------------------------------------------------
1727
1728template<class Val, class BV, unsigned MAX_SIZE>
1731{
1732 bvector_type_ptr bv = bmatr_.construct_row(i);
1733
1734 // slice mask or efective_slices does not extend beyond the natural size
1735 // (in bits)
1736 if (i < (sizeof(value_type) * 8))
1737 {
1738 // note: unsigned int shift by << 32 is UNDEFINED behav.
1739 slice_mask_ |= (unsigned_value_type(1) << i);
1740 if (i > effective_slices_)
1741 effective_slices_ = i;
1742 }
1743 return bv;
1744}
1745
1746//---------------------------------------------------------------------
1747
1748template<class Val, class BV, unsigned MAX_SIZE>
1750 unsigned element_idx) const BMNOEXCEPT
1751{
1752 bm::id64_t mask = 0;
1753 bm::id64_t mask1 = 1;
1754 const unsigned planes = sizeof(value_type) * 8;
1755 unsigned bidx = 0;
1756 unsigned slice_size = (element_idx+1) * planes;
1757 if (slice_size > this->bmatr_.rows())
1758 slice_size = (unsigned) this->bmatr_.rows();
1759 for (unsigned i = element_idx * planes; i < slice_size; ++i, ++bidx)
1760 mask |= get_slice(i) ? (mask1 << bidx) : 0ull;
1761 return mask;
1762}
1763
1764//---------------------------------------------------------------------
1765
1766template<class Val, class BV, unsigned MAX_SIZE>
1768 typename bvector_type::optmode opt_mode,
1769 typename bvector_type::statistics* st)
1770{
1771 typename bvector_type::statistics stbv;
1772 bmatr_.optimize(temp_block, opt_mode, &stbv);
1773 if (st)
1774 st->add(stbv);
1775
1776 bvector_type* bv_null = this->get_null_bvect();
1777 unsigned slices = (unsigned)this->bmatr_.rows();
1778 for (unsigned j = 0; j < slices; ++j)
1779 {
1780 bvector_type* bv = this->bmatr_.get_row(j);
1781 if (bv && (bv != bv_null)) // protect the NULL vector from de-allocation
1782 {
1783 // TODO: check if this can be done within optimize loop
1784 if (!bv->any()) // empty vector?
1785 {
1786 this->bmatr_.destruct_row(j);
1787 slice_mask_ &= ~(unsigned_value_type(1) << j);
1788 continue;
1789 }
1790 }
1791 } // for j
1792}
1793
1794//---------------------------------------------------------------------
1795
1796template<class Val, class BV, unsigned MAX_SIZE>
1798 typename bvector_type::statistics* st) const BMNOEXCEPT
1799{
1800 BM_ASSERT(st);
1801 st->reset();
1802 size_type slices = this->get_bmatrix().rows();//stored_slices();
1803 bmatr_.calc_stat(*st, slices);
1804
1805 // header accounting
1806 st->max_serialize_mem += 1 + 1 + 1 + 1 + 8 + (8 * slices);
1807 st->max_serialize_mem += 1 + 8; // extra header fields for large bit-matrixes
1808}
1809
1810//---------------------------------------------------------------------
1811
1812template<class Val, class BV, unsigned MAX_SIZE>
1814 unsigned plane_idx, size_type idx)
1815{
1816 bmatr_.clear_column(idx, plane_idx);
1817}
1818
1819//---------------------------------------------------------------------
1820
1821template<class Val, class BV, unsigned MAX_SIZE>
1823 unsigned plane_idx, size_type idx)
1824{
1825 bmatr_.insert_column(idx, plane_idx);
1826}
1827
1828//---------------------------------------------------------------------
1829
1830template<class Val, class BV, unsigned MAX_SIZE>
1832 size_type idx, bool erase_null)
1833{
1834 bmatr_.erase_column(idx, erase_null);
1835}
1836
1837//---------------------------------------------------------------------
1838
1839template<class Val, class BV, unsigned MAX_SIZE>
1842 bm::null_support null_able) const BMNOEXCEPT
1843{
1844 if (size_type arg_size = sv.size(); this->size_ != arg_size)
1845 return false;
1846
1847 unsigned slices = (unsigned) this->bmatr_.rows();
1848 unsigned arg_slices = (unsigned) sv.bmatr_.rows();
1849 unsigned max_slices(slices);
1850 if (max_slices < arg_slices)
1851 max_slices = arg_slices;
1852
1853 const bvector_type* bv_null = this->get_null_bvector();
1854 const bvector_type* bv_null_arg = sv.get_null_bvector();
1855
1856 for (unsigned j = 0; j < max_slices; ++j)
1857 {
1858 const bvector_type* bv;
1859 const bvector_type* arg_bv;
1860
1861 bv = (j < slices) ? this->bmatr_.get_row(j) : 0;
1862 arg_bv = (j < arg_slices) ? sv.bmatr_.get_row(j) : 0;
1863 if (bv == bv_null)
1864 bv = 0; // NULL vector compare postponed for later
1865 if (arg_bv == bv_null_arg)
1866 arg_bv = 0;
1867 if (bv == arg_bv) // same NULL
1868 continue;
1869
1870 // check if any not NULL and not empty
1871 if (!bv && arg_bv)
1872 {
1873 if (arg_bv->any())
1874 return false;
1875 continue;
1876 }
1877 if (bv && !arg_bv)
1878 {
1879 if (bv->any())
1880 return false;
1881 continue;
1882 }
1883 // both not NULL
1884 bool eq = bv->equal(*arg_bv);
1885 if (!eq)
1886 return false;
1887 } // for j
1888
1889 if (null_able == bm::use_null)
1890 {
1891 // check the NULL vectors
1892 if (bv_null == bv_null_arg)
1893 return true;
1894 if (!bv_null || !bv_null_arg)
1895 return false; // TODO: this may need an improvement when one is null, others not null
1896
1897 BM_ASSERT(bv_null);
1898 BM_ASSERT(bv_null_arg);
1899 bool eq = bv_null->equal(*bv_null_arg);
1900 if (!eq)
1901 return false;
1902 }
1903 return true;
1904}
1905
1906//---------------------------------------------------------------------
1907
1908template<class Val, class BV, unsigned MAX_SIZE>
1913 bm::null_support slice_null)
1914{
1915 if (bmatr_.rows() < bsv.bmatr_.rows())
1916 bmatr_.allocate_rows(bsv.bmatr_.rows());
1917
1918 size_type spli;
1919 const bvector_type* bv_null_arg = bsv.get_null_bvector();
1920 if (bvector_type* bv_null = get_null_bvect())
1921 {
1922 spli = this->bmatr_.rows(); //stored_slices();
1923 if (bv_null_arg && (slice_null == bm::use_null))
1924 bv_null->copy_range(*bv_null_arg, left, right);
1925 --spli;
1926 }
1927 else
1928 spli = this->bmatr_.rows();
1929
1930 for (size_type j = 0; j < spli; ++j)
1931 {
1932 if (const bvector_type* arg_bv = bsv.bmatr_.row(j))
1933 {
1934 if (arg_bv == bv_null_arg)
1935 continue;
1936 bvector_type* bv = this->get_create_slice(unsigned(j));
1937 bv->copy_range(*arg_bv, left, right);
1938 }
1939 } // for j
1940
1941}
1942
1943//---------------------------------------------------------------------
1944
1945template<class Val, class BV, unsigned MAX_SIZE>
1948{
1949 if constexpr (is_signed())
1950 {
1951 if (v < 0)
1952 {
1953 // the +1 trick is to get abs of INT_MIN without overflowing
1954 // https://stackoverflow.com/questions/22268815/absolute-value-of-int-min
1955 value_type uv = -(v+1);
1956 return 1u | unsigned_value_type((unsigned_value_type(uv) << 1u));
1957 }
1959 }
1960 else
1961 return v;
1962}
1963
1964//---------------------------------------------------------------------
1965
1966template<class Val, class BV, unsigned MAX_SIZE>
1969{
1970 if constexpr (is_signed())
1971 {
1972 if (uv & 1u) // signed
1973 {
1974 value_type s = (-(uv >> 1u)) - 1;
1975 return s;
1976 }
1977 return value_type(uv >> 1u);
1978 }
1979 else
1980 return uv;
1981}
1982#ifdef _MSC_VER
1983#pragma warning( pop )
1984#endif
1985
1986
1987} // namespace
1988
1989#endif
Compressed bit-vector bvector<> container, set algebraic methods, traversal iterators.
#define BM_DECLARE_TEMP_BLOCK(x)
Definition: bm.h:47
Constants, lookup tables and typedefs.
Definitions(internal)
#define BMNOEXCEPT
Definition: bmdef.h:82
#define BMGAP_PTR(ptr)
Definition: bmdef.h:189
#define BM_IS_GAP(ptr)
Definition: bmdef.h:191
#define BM_ASSERT
Definition: bmdef.h:139
#define FULL_BLOCK_FAKE_ADDR
Definition: bmdef.h:158
Utilities for bit transposition (internal) (experimental!)
Base class for bit-transposed(bit-sliced) sparse vector construction.
Definition: bmbmatrix.h:336
void freeze_matr()
Turn on RO mode.
Definition: bmbmatrix.h:612
bvector_type_const_ptr get_slice(unsigned i) const BMNOEXCEPT
get read-only access to bit-plane
Definition: bmbmatrix.h:476
void swap(base_sparse_vector< Val, BV, MAX_SIZE > &bsv) BMNOEXCEPT
Definition: bmbmatrix.h:1624
void resize(size_type new_size, bool set_null)
Definition: bmbmatrix.h:1691
bm::null_support get_null_support() const BMNOEXCEPT
check if container supports NULL (unassigned) values
Definition: bmbmatrix.h:423
unsigned effective_slices() const BMNOEXCEPT
Number of effective bit-planes in the value type.
Definition: bmbmatrix.h:493
unsigned_value_type slice_mask_
slice presence bit-mask
Definition: bmbmatrix.h:678
const bvector_type * bvector_type_const_ptr
Definition: bmbmatrix.h:353
void merge_matr(bmatrix_type &bmatr)
Merge plane bvectors from an outside base matrix Note: outside base matrix gets destroyed.
Definition: bmbmatrix.h:1585
static unsigned slices() BMNOEXCEPT
get total number of bit-planes in the vector
Definition: bmbmatrix.h:482
static value_type u2s(unsigned_value_type v) BMNOEXCEPT
Convert unsigned value type to signed representation.
Definition: bmbmatrix.h:1968
bvector_type * bvector_type_ptr
Definition: bmbmatrix.h:352
const value_type & const_reference
Definition: bmbmatrix.h:354
bmatrix_type & get_bmatrix() BMNOEXCEPT
access to internal bit-matrix
Definition: bmbmatrix.h:538
bvector_type_ptr slice(unsigned i) BMNOEXCEPT
get access to bit-plane as is (can return NULL)
Definition: bmbmatrix.h:500
void copy_from(const base_sparse_vector< Val, BV, MAX_SIZE > &bsv)
Definition: bmbmatrix.h:1543
static unsigned_value_type s2u(value_type v) BMNOEXCEPT
Convert signed value type to unsigned representation.
Definition: bmbmatrix.h:1947
bvector_type::allocation_policy allocation_policy_type
Definition: bmbmatrix.h:356
void set_allocator_pool(allocator_pool_type *pool_ptr) BMNOEXCEPT
Set allocation pool.
Definition: bmbmatrix.h:447
void clear_range(size_type left, size_type right, bool set_null)
Definition: bmbmatrix.h:1655
bvector_type_ptr get_create_slice(unsigned i)
get access to bit-plain, function checks and creates a plane
Definition: bmbmatrix.h:1730
size_type size() const BMNOEXCEPT
Definition: bmbmatrix.h:385
base_sparse_vector(const base_sparse_vector< Val, BV, MAX_SIZE > &bsv)
Definition: bmbmatrix.h:1532
bool empty() const BMNOEXCEPT
Definition: bmbmatrix.h:400
const bmatrix_type & get_bmatrix() const BMNOEXCEPT
Definition: bmbmatrix.h:532
void free_slice(unsigned i)
free memory in bit-plane
Definition: bmbmatrix.h:515
void optimize_block(block_idx_type nb, typename BV::optmode opt_mode)
plane index for the "NOT NULL" flags plane
Definition: bmbmatrix.h:664
unsigned effective_slices_
number of bit slices actually allocated
Definition: bmbmatrix.h:680
bmatrix_type bmatr_
bit-transposed matrix
Definition: bmbmatrix.h:677
void erase_column(size_type idx, bool erase_null)
Definition: bmbmatrix.h:1831
allocator_type::allocator_pool_type allocator_pool_type
Definition: bmbmatrix.h:358
base_sparse_vector(bm::null_support null_able, allocation_policy_type ap=allocation_policy_type(), size_type bv_max_size=bm::id_max, const allocator_type &alloc=allocator_type())
Definition: bmbmatrix.h:1513
bool is_ro_
read-only
Definition: bmbmatrix.h:681
void copy_range_slices(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 slice_null)
Perform copy_range() on a set of planes.
Definition: bmbmatrix.h:1909
base_sparse_vector(base_sparse_vector< Val, BV, MAX_SIZE > &&bsv) BMNOEXCEPT
Definition: bmbmatrix.h:374
bm::id64_t get_slice_mask(unsigned element_idx) const BMNOEXCEPT
Definition: bmbmatrix.h:1749
static unsigned stored_slices() BMNOEXCEPT
Number of stored bit-planes (value planes + extra.
Definition: bmbmatrix.h:487
static constexpr unsigned value_bits() BMNOEXCEPT
Number of total bit-planes in the value type.
Definition: bmbmatrix.h:657
bool is_null(size_type idx) const BMNOEXCEPT
test if specified element is NULL
Definition: bmbmatrix.h:1709
const bvector_type * get_null_bvector() const BMNOEXCEPT
Get bit-vector of assigned values or NULL (if not constructed that way)
Definition: bmbmatrix.h:430
size_type size_
array size
Definition: bmbmatrix.h:679
void bit_and_rows(const bvector_type &bv)
Set AND (intersect) operation on all existing bit-slices.
Definition: bmbmatrix.h:651
void keep_range_no_check(size_type left, size_type right, bm::null_support slice_null)
Definition: bmbmatrix.h:1677
std::make_unsigned< value_type >::type unsigned_value_type
Definition: bmbmatrix.h:360
void mark_null_idx(unsigned null_idx) BMNOEXCEPT
Set NULL plain index.
Definition: bmbmatrix.h:544
bvector_type_const_ptr slice(unsigned i) const BMNOEXCEPT
Definition: bmbmatrix.h:501
BV::size_type size_type
Definition: bmbmatrix.h:351
allocator_pool_type * get_allocator_pool() const BMNOEXCEPT
Get allocation pool.
Definition: bmbmatrix.h:453
bvector_type::enumerator bvector_enumerator_type
Definition: bmbmatrix.h:357
void bit_sub_rows(const bvector_type &bv, bool use_null)
Set SUB (MINUS) operation on all existing bit-slices.
Definition: bmbmatrix.h:644
void clear_all(bool free_mem=true) BMNOEXCEPT
resize to zero, free memory
Definition: bmbmatrix.h:1639
bm::basic_bmatrix< BV > bmatrix_type
Definition: bmbmatrix.h:359
bvector_type * get_null_bvect() BMNOEXCEPT
Definition: bmbmatrix.h:504
BV::allocator_type allocator_type
Definition: bmbmatrix.h:355
static constexpr bool is_signed() BMNOEXCEPT
returns true if value type is signed integral type
Definition: bmbmatrix.h:412
void optimize(bm::word_t *temp_block=0, typename bvector_type::optmode opt_mode=bvector_type::opt_compress, typename bvector_type::statistics *stat=0)
run memory optimization for all bit-vector rows
Definition: bmbmatrix.h:1767
void insert_null(size_type idx, bool not_null)
Definition: bmbmatrix.h:1719
void clear_value_planes_from(unsigned plane_idx, size_type idx)
Definition: bmbmatrix.h:1813
void calc_stat(typename bvector_type::statistics *st) const BMNOEXCEPT
Calculates memory statistics.
Definition: bmbmatrix.h:1797
bool is_nullable() const BMNOEXCEPT
check if container supports NULL(unassigned) values
Definition: bmbmatrix.h:418
bool equal(const base_sparse_vector< Val, BV, MAX_SIZE > &sv, bm::null_support null_able=bm::use_null) const BMNOEXCEPT
check if another sparse vector has the same content and size
Definition: bmbmatrix.h:1840
void insert_clear_value_planes_from(unsigned plane_idx, size_type idx)
Definition: bmbmatrix.h:1822
bvector_type::block_idx_type block_idx_type
Definition: bmbmatrix.h:654
Basic dense bit-matrix class.
Definition: bmbmatrix.h:56
void insert_octet(size_type pos, size_type octet_idx, unsigned char octet)
Definition: bmbmatrix.h:1178
void insert_column(size_type idx, size_type row_from)
Definition: bmbmatrix.h:832
bvector_type::block_idx_type block_idx_type
Definition: bmbmatrix.h:65
void swap(basic_bmatrix< BV > &bbm) BMNOEXCEPT
Definition: bmbmatrix.h:973
~basic_bmatrix() BMNOEXCEPT
Definition: bmbmatrix.h:712
basic_bmatrix< BV > & operator=(const basic_bmatrix< BV > &bbm)
Definition: bmbmatrix.h:81
bvector_type * bvector_type_ptr
Definition: bmbmatrix.h:59
bvector_type_ptr * bv_rows_
Definition: bmbmatrix.h:322
allocator_type alloc_
Definition: bmbmatrix.h:318
void set_allocator_pool(allocator_pool_type *pool_ptr) BMNOEXCEPT
Definition: bmbmatrix.h:914
void set_null_idx(size_type null_idx) BMNOEXCEPT
set index of the NULL vector
Definition: bmbmatrix.h:780
bvector_type_ptr construct_row(size_type row)
Definition: bmbmatrix.h:1004
unsigned get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT
Definition: bmbmatrix.h:1366
BV::allocator_type allocator_type
Definition: bmbmatrix.h:61
bvector_type::allocation_policy allocation_policy_type
Definition: bmbmatrix.h:62
size_type null_idx_
Index of the NULL row.
Definition: bmbmatrix.h:324
allocator_type::allocator_pool_type allocator_pool_type
Definition: bmbmatrix.h:63
size_type get_null_idx() const BMNOEXCEPT
return index of the NULL vector
Definition: bmbmatrix.h:161
void destruct_row(size_type row)
Definition: bmbmatrix.h:1036
const bvector_type * bvector_type_const_ptr
Definition: bmbmatrix.h:60
bvector_type * construct_bvector(const bvector_type *bv) const
Definition: bmbmatrix.h:1068
const bm::word_t * get_block(size_type p, unsigned i, unsigned j) const BMNOEXCEPT
Get low level internal access to.
Definition: bmbmatrix.h:1115
void bit_and_rows(const bvector_type &bv)
Set AND (intersect) operation on all existing rows.
Definition: bmbmatrix.h:961
void calc_stat(typename bvector_type::statistics &st, size_type rsize) const BMNOEXCEPT
Definition: bmbmatrix.h:1466
allocator_pool_type * get_allocator_pool() const BMNOEXCEPT
Definition: bmbmatrix.h:105
int compare_octet(size_type pos, size_type octet_idx, char octet) const BMNOEXCEPT
Definition: bmbmatrix.h:1327
size_type rows_not_null() const BMNOEXCEPT
Definition: bmbmatrix.h:142
size_type rsize_
Definition: bmbmatrix.h:323
allocator_pool_type * pool_
Definition: bmbmatrix.h:320
void copy_from(const basic_bmatrix< BV > &bbm)
Definition: bmbmatrix.h:790
static void throw_bad_alloc()
Definition: bmbmatrix.h:311
void optimize(bm::word_t *temp_block=0, typename bvector_type::optmode opt_mode=bvector_type::opt_compress, typename bvector_type::statistics *stat=0)
run memory optimization for all bit-vector rows
Definition: bmbmatrix.h:1429
void clear_slices_range(unsigned slice_from, unsigned slize_until, size_type idx)
Clear bit-planes bit.
Definition: bmbmatrix.h:1126
unsigned char octet_type
Definition: bmbmatrix.h:66
void clear_column(size_type idx, size_type row_from)
Definition: bmbmatrix.h:843
size_type bv_size_
Definition: bmbmatrix.h:317
void clear_row(size_type row, bool free_mem)
Definition: bmbmatrix.h:1049
const bvector_type * row(size_type i) const BMNOEXCEPT
Definition: bmbmatrix.h:751
void allocate_rows(size_type rsize)
allocate matrix rows of bit-vectors (new rows are NULLs)
Definition: bmbmatrix.h:854
void optimize_block(block_idx_type nb, typename BV::optmode opt_mode)
Definition: bmbmatrix.h:1483
allocation_policy_type ap_
Definition: bmbmatrix.h:319
size_type rows() const BMNOEXCEPT
Definition: bmbmatrix.h:139
void destruct_bvector(bvector_type *bv) const
Definition: bmbmatrix.h:1101
size_type calc_effective_rows_not_null() const BMNOEXCEPT
Definition: bmbmatrix.h:930
void set_octet(size_type pos, size_type octet_idx, unsigned char octet)
Definition: bmbmatrix.h:1139
void erase_column(size_type idx, bool erase_null)
Definition: bmbmatrix.h:820
basic_bmatrix(size_type rsize, allocation_policy_type ap=allocation_policy_type(), size_type bv_max_size=bm::id_max, const allocator_type &alloc=allocator_type())
Definition: bmbmatrix.h:694
void bit_sub_rows(const bvector_type &bv, bool use_null)
Set SUB (MINUS) operation on all existing rows.
Definition: bmbmatrix.h:948
size_type octet_size() const BMNOEXCEPT
Definition: bmbmatrix.h:886
void free_rows() BMNOEXCEPT
Free all rows.
Definition: bmbmatrix.h:896
unsigned char get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT
Definition: bmbmatrix.h:1225
bvector_type::size_type size_type
Definition: bmbmatrix.h:64
bvector_type_const_ptr get_row(size_type i) const BMNOEXCEPT
Definition: bmbmatrix.h:761
Constant iterator designed to enumerate "ON" bits.
Definition: bm.h:603
Bitvector Bit-vector container with runtime compression of bits.
Definition: bm.h:115
optmode
Optimization mode Every next level means additional checks (better compression vs time)
Definition: bm.h:133
@ opt_compress
compress blocks when possible (GAP/prefix sum)
Definition: bm.h:137
blocks_manager< Alloc > blocks_manager_type
Definition: bm.h:119
bvector_size_type size_type
Definition: bm.h:121
void init()
Explicit post-construction initialization. Must be caled to make sure safe use of *_no_check() method...
Definition: bm.h:2258
blocks_manager_type::block_idx_type block_idx_type
Definition: bm.h:120
null_support
NULL-able value support.
Definition: bmconst.h:228
@ use_null
support "non-assigned" or "NULL" logic
Definition: bmconst.h:229
@ no_null
do not support NULL values
Definition: bmconst.h:230
unsigned gap_test_unr(const T *BMRESTRICT buf, const unsigned pos) BMNOEXCEPT
Tests if bit = pos is true. Analog of bm::gap_test with SIMD unrolling.
Definition: bmfunc.h:1784
Definition: bm.h:78
const unsigned set_array_mask
Definition: bmconst.h:97
const unsigned id_max
Definition: bmconst.h:109
unsigned int word_t
Definition: bmconst.h:39
bool test_4bits(const bm::word_t *p0, const bm::word_t *p1, const bm::word_t *p2, const bm::word_t *p3) BMNOEXCEPT
Test 4 pointers are not NULL and not marked as FULLBLOCK.
Definition: bmbmatrix.h:1354
const unsigned set_block_mask
Definition: bmconst.h:57
BMFORCEINLINE void get_block_coord(BI_TYPE nb, unsigned &i, unsigned &j) BMNOEXCEPT
Recalc linear bvector block index into 2D matrix coordinates.
Definition: bmfunc.h:172
const unsigned set_word_shift
Definition: bmconst.h:72
BMFORCEINLINE void xor_swap(W &x, W &y) BMNOEXCEPT
XOR swap two variables.
Definition: bmutil.h:534
unsigned long long int id64_t
Definition: bmconst.h:35
const unsigned set_array_shift
Definition: bmconst.h:96
const unsigned set_block_shift
Definition: bmconst.h:56
const unsigned set_word_mask
Definition: bmconst.h:73
bool test_4gaps(const bm::word_t *p0, const bm::word_t *p1, const bm::word_t *p2, const bm::word_t *p3) BMNOEXCEPT
Test 4 pointers are all marked as GAPs.
Definition: bmbmatrix.h:1342
void reset() BMNOEXCEPT
Reset statisctics.
Definition: bmfunc.h:92
void add(const bv_statistics &st) BMNOEXCEPT
Sum data from another sttructure.
Definition: bmfunc.h:101
memory allocation policy
Definition: bm.h:805
Statistical information about bitset's memory allocation details.
Definition: bm.h:125
static TBVector * construct_bvector()
Definition: xsample01.cpp:101
bm::bvector bvector_type
Definition: xsample07a.cpp:94