Evo C++ Library v0.5.1
bit_array.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_bit_array_h
9 #define INCL_evo_bit_array_h
10 
11 #include "bits.h"
12 #include "impl/iter.h"
13 #include "impl/str.h"
14 
15 namespace evo {
18 
20 
122 template<class TParent>
124 public:
126  typedef TParent Parent;
127  typedef typename TParent::Size Size;
128  typedef typename TParent::Value Value;
129 
131  BitArraySubsetT() : parent_rd_(NULL), parent_wr_(NULL), offset_(0), bitsize_(0) {
132  }
133 
137  BitArraySubsetT(const Parent& parent) : parent_rd_(&parent), parent_wr_(NULL), offset_(0), bitsize_(parent.bitsize_) {
138  }
139 
143  BitArraySubsetT(Parent& parent) : parent_rd_(&parent), parent_wr_(&parent), offset_(0), bitsize_(parent.bitsize_) {
144  }
145 
151  BitArraySubsetT(const Parent& parent, Size pos, Size count=ALL) {
152  set(parent, pos, count);
153  }
154 
160  BitArraySubsetT(Parent& parent, Size pos, Size count=ALL) {
161  set(parent, pos, count);
162  }
163 
167  BitArraySubsetT(const ThisType& src) : parent_rd_(src.parent_rd_), parent_wr_(src.parent_wr_), offset_(src.offset_), bitsize_(src.bitsize_) {
168  }
169 
170 #if defined(EVO_CPP11)
171 
174  BitArraySubsetT(ThisType&& src) {
175  ::memcpy(this, &src, sizeof(ThisType));
176  ::memset(&src, 0, sizeof(ThisType));
177  }
178 
183  ThisType& operator=(ThisType&& src) {
184  ::memcpy(this, &src, sizeof(ThisType));
185  ::memset(&src, 0, sizeof(ThisType));
186  return *this;
187  }
188 #endif
189 
190  // SET
191 
196  ThisType& operator=(const ThisType& src) {
197  parent_rd_ = src.parent_rd_;
198  parent_wr_ = src.parent_wr_;
199  offset_ = src.offset_;
200  bitsize_ = src.bitsize_;
201  return *this;
202  }
203 
208  ThisType& operator=(const Parent& parent) {
209  parent_rd_ = &parent;
210  parent_wr_ = NULL;
211  offset_ = 0;
212  bitsize_ = parent.size();
213  return *this;
214  }
215 
220  ThisType& operator=(Parent& parent) {
221  parent_rd_ = parent_wr_ = &parent;
222  offset_ = 0;
223  bitsize_ = parent.size();
224  return *this;
225  }
226 
230  ThisType& set() {
231  parent_rd_ = parent_wr_ = NULL;
232  offset_ = 0;
233  bitsize_ = 0;
234  return *this;
235  }
236 
243  ThisType& set(const ThisType& src, Size pos=0, Size count=ALL) {
244  parent_rd_ = src.parent_rd_;
245  parent_wr_ = src.parent_wr_;
246  offset_ = src.offset_ + pos;
247  if (offset_ > src.bitsize_) {
248  offset_ = src.bitsize_;
249  bitsize_ = 0;
250  } else {
251  bitsize_ = src.bitsize_ - offset_;
252  if (bitsize_ > count)
253  bitsize_ = count;
254  }
255  return *this;
256  }
257 
263  ThisType& set(const Parent& parent, Size pos=0, Size count=ALL) {
264  parent_rd_ = &parent;
265  parent_wr_ = NULL;
266  offset_ = pos;
267  if (offset_ > parent.bitsize_) {
268  offset_ = parent.bitsize_;
269  bitsize_ = 0;
270  } else {
271  bitsize_ = parent.bitsize_ - offset_;
272  if (bitsize_ > count)
273  bitsize_ = count;
274  }
275  return *this;
276  }
277 
283  ThisType& set(Parent& parent, Size pos=0, Size count=ALL) {
284  parent_rd_ = parent_wr_ = &parent;
285  offset_ = pos;
286  if (offset_ > parent.bitsize_) {
287  offset_ = parent.bitsize_;
288  bitsize_ = 0;
289  } else {
290  bitsize_ = parent.bitsize_ - offset_;
291  if (bitsize_ > count)
292  bitsize_ = count;
293  }
294  return *this;
295  }
296 
297  // INFO
298 
304  bool null() const {
305  return (parent_rd_ == NULL);
306  }
307 
313  bool empty() const {
314  return (bitsize_ == 0);
315  }
316 
320  Size size() const {
321  return bitsize_;
322  }
323 
327  Size offset() const {
328  return offset_;
329  }
330 
336  bool readonly() const {
337  return (parent_wr_ == NULL);
338  }
339 
343  const Parent* parent() const {
344  return parent_rd_;
345  }
346 
350  Parent* parent_nonconst() {
351  return parent_wr_;
352  }
353 
354  // BITS
355 
363  bool operator[](Size pos) const {
364  return (parent_rd_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_get(parent_rd_->data_, parent_rd_->bitsize_, offset_ + pos));
365  }
366 
374  Size countbits(bool value=true) const {
375  if (parent_rd_ == NULL)
376  return 0;
377  if (value)
378  return Bits<Value,Size>::array_countbits(parent_rd_->data_, parent_rd_->bitsize_, offset_, bitsize_);
379  return bitsize_ - Bits<Value,Size>::array_countbits(parent_rd_->data_, parent_rd_->bitsize_, offset_, bitsize_);
380  }
381 
387  Size checkall() const {
388  return (parent_rd_ == NULL || Bits<Value,Size>::array_checkall(parent_rd_->data_, parent_rd_->bitsize_, offset_, bitsize_));
389  }
390 
396  bool checkany() const {
397  return (parent_rd_ != NULL && Bits<Value,Size>::array_checkany(parent_rd_->data_, parent_rd_->bitsize_, offset_, bitsize_));
398  }
399 
407  bool getbit(Size pos) const {
408  return (parent_rd_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_get(parent_rd_->data_, parent_rd_->bitsize_, offset_ + pos));
409  }
410 
419  bool setbit(Size pos, bool value=true) {
420  return (parent_wr_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_set(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, value));
421  }
422 
432  Size setbits(Size pos=0, Size count=ALL, bool value=true) {
433  if (parent_wr_ != NULL && pos < bitsize_) {
434  const Size maxcount = bitsize_ - pos;
435  if (count > maxcount)
436  count = maxcount;
437  return Bits<Value,Size>::array_set_multi(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, count, value);
438  }
439  return 0;
440  }
441 
449  bool clearbit(Size pos) {
450  return (parent_wr_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_set(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, false));
451  }
452 
461  Size clearbits(Size pos=0, Size count=ALL) const {
462  if (parent_wr_ != NULL && pos < bitsize_) {
463  const Size maxcount = bitsize_ - pos;
464  if (count > maxcount)
465  count = maxcount;
466  return Bits<Value,Size>::array_set_multi(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, count, false);
467  }
468  return 0;
469  }
470 
478  bool togglebit(Size pos) {
479  return (parent_wr_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_toggle(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos));
480  }
481 
490  Size togglebits(Size pos=0, uint count=ALL) {
491  if (parent_wr_ != NULL && pos < bitsize_) {
492  const Size maxcount = bitsize_ - pos;
493  if (count > maxcount)
494  count = maxcount;
495  return Bits<Value,Size>::array_toggle_multi(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, count);
496  }
497  return 0;
498  }
499 
515  template<class U>
516  bool store(Size pos, Size count, U value) {
517  const Size maxcount = bitsize_ - pos;
518  if (count > maxcount)
519  count = maxcount;
520  return (parent_wr_ != NULL && pos < bitsize_ && Bits<Value,Size>::array_store(parent_wr_->data_, parent_wr_->bitsize_, offset_ + pos, count, value));
521  }
522 
535  template<class U EVO_ONCPP11(=ulong)>
536  U extractl(Size pos=0, Size count=ALL) const {
537  if (parent_rd_ != NULL && pos < bitsize_) {
538  const Size maxcount = bitsize_ - pos;
539  if (count > maxcount)
540  count = maxcount;
541  return Bits<Value,Size>::template array_extractl<U>(parent_rd_->data_, parent_rd_->bitsize_, offset_ + pos, count);
542  }
543  return 0;
544  }
545 
561  template<class U EVO_ONCPP11(=ulong)>
562  U extractr(Size pos=0, Size count=ALL) const {
563  if (parent_rd_ != NULL && pos < bitsize_) {
564  const Size maxcount = bitsize_ - pos;
565  if (count > maxcount)
566  count = maxcount;
567  return Bits<Value,Size>::template array_extractr<U>(parent_rd_->data_, parent_rd_->bitsize_, offset_ + pos, count);
568  }
569  return 0;
570  }
571 
585  template<class U>
586  bool format(U& out, int base=fBIN) {
587  if (bitsize_ > 0) {
588  assert( parent_rd_ != NULL );
589  const char* digits;
590  if (base >= 100) {
591  base -= 100;
592  digits = "0123456789abcdefghijklmnopqrstuvwxyz";
593  } else
594  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
595 
596  int bits_per_digit;
597  switch (base) {
598  case 2: bits_per_digit = 1; break;
599  case 4: bits_per_digit = 2; break;
600  case 8: bits_per_digit = 3; break;
601  case 16: bits_per_digit = 4; break;
602  case 32: bits_per_digit = 5; break;
603  default: return false;
604  }
605 
606  typename U::Out& outstream = out.write_out();
607  typename U::Out::Size available = 0;
608 
609  Size outsize = (bitsize_ + bits_per_digit - 1) / bits_per_digit; // round up
610  char* outbuf = outstream.write_direct_multi(available, outsize);
611  if (outbuf == NULL)
612  return false;
613 
614  char* outbuf_start = outbuf;
615  char* outbuf_end = outbuf + available;
616  char* outbuf_write;
617  char* outbuf_next;
618  Size outsize_lastwrite = outsize;
619  Size digit_count;
620 
621  const Value* parent_data = parent_rd_->data_; // local copy of data pointer
622  const Size parent_bitsize = offset_ + bitsize_; // use reduced parent bitsize to exclude ending partial digit bits from extractr()
623 
624  // Use extractr() to extract and format bits
625  const uint digits_per_ulong = IntegerT<ulong>::BITS / bits_per_digit;
626  const uint bits_per_ulong = digits_per_ulong * bits_per_digit;
627  ulong num;
628  outbuf_end -= digits_per_ulong;
629  for (Size p=offset_; outsize > 0; p += bits_per_ulong) {
630  if (outbuf > outbuf_end) {
631  // No room, flush buffer
632  outbuf_start = outbuf = outstream.write_direct_flush(available, (ulong)(outbuf - outbuf_start), outsize);
633  if (outbuf == NULL)
634  return false;
635  outbuf_end = outbuf + available - digits_per_ulong;
636  outsize_lastwrite = outsize;
637  }
638 
639  if (outsize < digits_per_ulong)
640  digit_count = outsize;
641  else
642  digit_count = digits_per_ulong;
643  num = Bits<Value,Size>::template array_extractr<ulong>(parent_data, parent_bitsize, p, digit_count * bits_per_digit);
644 
645  // Format chunk
646  outbuf_next = outbuf_write = outbuf + digit_count;
647  for (; num != 0; num /= (Value)base)
648  *--outbuf_write = digits[num % base];
649  while (outbuf_write > outbuf)
650  *--outbuf_write = '0';
651  outsize -= digit_count;
652  outbuf = outbuf_next;
653  }
654 
655  assert( outsize_lastwrite >= outsize );
656  outstream.write_direct_finish(outsize_lastwrite - outsize);
657  }
658  return true;
659  }
660 
661  // COMPARE
662 
667  bool operator==(const ThisType& data) const {
668  bool result;
669  if (this == &data)
670  result = true;
671  else if (parent_rd_ == NULL)
672  result = (data.parent_rd_ == NULL);
673  else if (data.parent_rd_ == NULL || bitsize_ != data.bitsize_)
674  result = false;
675  else if (bitsize_ == 0)
676  result = true;
677  else {
678  const Size this_index = offset_ / Bits<Value,Size>::BITS;
679  const Size this_offset = offset_ - (this_index * Bits<Value,Size>::BITS);
680  const Value* this_ptr = parent_rd_->data_ + this_index;
681  const Size other_index = data.offset_ / Bits<Value,Size>::BITS;
682  const Size other_offset = data.offset_ - (other_index * Bits<Value,Size>::BITS);
683  Size count = bitsize_;
684  Value maskval;
685  if (this_offset == other_offset) {
686  // Easier to compare with same offsets
687  const Value* other_ptr = data.parent_rd_->data_ + other_index;
688 
689  // Leading partial chunk
690  if (this_offset > 0) {
691  maskval = Bits<Value,Size>::ALLBITS >> this_offset;
692  if ((*this_ptr & maskval) != (*other_ptr & maskval))
693  return false;
694  count -= (Bits<Value, Size>::BITS - this_offset);
695  ++this_ptr;
696  ++other_ptr;
697  }
698 
699  // Compare full chunks
700  while (count >= Bits<Value, Size>::BITS) {
701  count -= Bits<Value, Size>::BITS;
702  if (*this_ptr != *other_ptr)
703  return false;
704  ++this_ptr;
705  ++other_ptr;
706  }
707 
708  // Compare trailing partial chunk
709  if (count > 0) {
710  maskval = ~(Bits<Value,Size>::ALLBITS >> count);
711  if ((*this_ptr & maskval) != (*other_ptr & maskval))
712  return false;
713  }
714  } else {
715  // Trickier to compare with different offsets, use array_extractl() for other data
716  const Value* other_ptr = data.parent_rd_->data_;
717  const Size other_bitsize = data.parent_rd_->bitsize_;
718  Size other_pos = data.offset_;
719 
720  // Leading partial chunk
721  if (this_offset > 0) {
722  maskval = Bits<Value,Size>::ALLBITS >> this_offset;
723  if ( (*this_ptr & maskval) != Bits<Value,Size>::template array_extractr<Value>(other_ptr, other_bitsize, other_pos, (Bits<Value,Size>::BITS - this_offset)) )
724  return false;
725  ++this_ptr;
726  const Size bits = Bits<Value, Size>::BITS - this_offset;
727  count -= bits;
728  other_pos += bits;
729  }
730 
731  // Compare full chunks
732  while (count >= Bits<Value, Size>::BITS) {
733  count -= Bits<Value, Size>::BITS;
734  if (*this_ptr != Bits<Value,Size>::template array_extractl<Value>(other_ptr, other_bitsize, other_pos, Bits<Value,Size>::BITS))
735  return false;
736  ++this_ptr;
737  other_pos += Bits<Value, Size>::BITS;
738  }
739 
740  // Compare trailing partial chunk
741  if (count > 0) {
742  maskval = ~(Bits<Value,Size>::ALLBITS >> count);
743  if ((*this_ptr & maskval) != Bits<Value,Size>::template array_extractl<Value>(other_ptr, other_bitsize, other_pos, count))
744  return false;
745  }
746  }
747  result = true;
748  }
749  return result;
750  }
751 
756  bool operator!=(const ThisType& data) const {
757  return !operator==(data);
758  }
759 
760 private:
761  const Parent* parent_rd_; // reads
762  Parent* parent_wr_; // writes
763  Size offset_;
764  Size bitsize_;
765 };
766 
768 
899 template<class T=ulong,class TSize=SizeT>
900 class BitArrayT {
901 public:
905  typedef TSize Size;
906  typedef T Value;
907 
908  // Iterator support types
910  struct IterKey {
911  Size offset;
912  typename Bits<T,Size>::IterState state;
913  };
914  typedef Size IterItem;
918 
920  BitArrayT() : data_(NULL), size_(0), bitsize_(0) {
921  }
922 
926  BitArrayT(Size bitsize) : data_(NULL), size_(0), bitsize_(0) {
927  resize(bitsize);
928  }
929 
933  BitArrayT(const ThisType& src) {
934  if (src.size_ > 0) {
935  data_ = (Value*)::malloc((size_t)src.size_ * sizeof(Value));
936  memcpy(data_, src.data_, src.size_ * sizeof(Value));
937  } else
938  data_ = src.data_;
939  size_ = src.size_;
940  bitsize_ = src.bitsize_;
941  }
942 
948  BitArrayT(const ThisType& src, Size pos, Size count=ALL) : data_(NULL), size_(0), bitsize_(0) {
949  if (count > src.bitsize_)
950  count = src.bitsize_;
951  if (count > 0) {
952  resize(count);
953  Bits<T,TSize>::array_copy(data_, bitsize_, src.data_, src.bitsize_, pos, count);
954  }
955  }
956 
964  BitArrayT(const Subset& subset, Size pos=0, Size count=ALL) : data_(NULL), size_(0), bitsize_(0) {
965  const ThisType* parent = subset.parent();
966  if (parent != NULL) {
967  const Size subset_bitsize = subset.size();
968  if (count > subset_bitsize)
969  count = subset_bitsize;
970  if (count > 0) {
971  resize(count);
972  Bits<T,TSize>::array_copy(data_, bitsize_, parent->data_, subset_bitsize, subset.offset() + pos, count);
973  }
974  }
975  }
976 
979  if (size_ > 0)
980  ::free(data_);
981  }
982 
983 #if defined(EVO_CPP11)
984 
987  BitArrayT(std::initializer_list<uint32> init) : BitArrayT() {
988  const Size ITEM_BITS = sizeof(uint32) * 8;
989  assert( init.size() < IntegerT<Size>::MAX / ITEM_BITS );
990  resize((Size)init.size() * ITEM_BITS);
991  Size offset = 0;
992  for (auto num : init) {
993  store(offset, ITEM_BITS, num);
994  offset += ITEM_BITS;
995  }
996  }
997 
1001  BitArrayT(ThisType&& src) {
1002  ::memcpy(this, &src, sizeof(ThisType));
1003  ::memset(&src, 0, sizeof(ThisType));
1004  }
1005 
1010  ThisType& operator=(ThisType&& src) {
1011  resize(0);
1012  ::memcpy(this, &src, sizeof(ThisType));
1013  ::memset(&src, 0, sizeof(ThisType));
1014  return *this;
1015  }
1016 #endif
1017 
1023  const ThisType& asconst() const {
1024  return *this;
1025  }
1026 
1027  // SET
1028 
1033  ThisType& operator=(const ThisType& src) {
1034  return set(src);
1035  }
1036 
1042  ThisType& clear() {
1043  if (size_ > 0) {
1044  ::free(data_);
1045  data_ = EVO_PEMPTY;
1046  size_ = 0;
1047  bitsize_ = 0;
1048  }
1049  return *this;
1050  }
1051 
1055  ThisType& set() {
1056  if (size_ > 0) {
1057  ::free(data_);
1058  size_ = 0;
1059  bitsize_ = 0;
1060  }
1061  data_ = NULL;
1062  return *this;
1063  }
1064 
1069  ThisType& set(const ThisType& src) {
1070  if (this != &src) {
1071  if (src.size_ > 0) {
1072  const size_t size_bytes = (size_t)src.size_ * sizeof(Value);
1073  if (size_ == src.size_) {
1074  // Same positive size
1075  memcpy(data_, src.data_, size_bytes);
1076  } else {
1077  // New positive size
1078  if (size_ > 0)
1079  ::free(data_);
1080  size_ = src.size_;
1081  data_ = (Value*)::malloc(size_bytes);
1082  memcpy(data_, src.data_, size_bytes);
1083  }
1084  bitsize_ = src.bitsize_;
1085  } else {
1086  // Null/Empty
1087  if (size_ > 0) {
1088  ::free(data_);
1089  size_ = 0;
1090  }
1091  bitsize_ = 0;
1092  data_ = (src.data_ == NULL ? NULL : EVO_PEMPTY);
1093  }
1094  }
1095  return *this;
1096  }
1097 
1104  ThisType& set(const Subset& src) {
1105  const ThisType* src_parent = src.parent();
1106  if (this == src_parent) {
1107  Bits<T,Size>::array_shiftl(data_, bitsize_, src.offset());
1108  resize(src.size());
1109  } else if (src_parent == NULL) {
1110  set();
1111  } else {
1112  const Size src_size = src.size();
1113  resize(src_size);
1114  Bits<T,TSize>::array_copy(data_, bitsize_, src_parent->data_, src_size);
1115  }
1116  return *this;
1117  }
1118 
1122  ThisType& setempty() {
1123  if (size_ > 0) {
1124  ::free(data_);
1125  size_ = 0;
1126  bitsize_ = 0;
1127  }
1128  data_ = EVO_PEMPTY;
1129  return *this;
1130  }
1131 
1132  // INFO
1133 
1139  bool null() const {
1140  return (data_ == NULL);
1141  }
1142 
1148  bool empty() const {
1149  return (bitsize_ == 0);
1150  }
1151 
1155  Size size() const {
1156  return bitsize_;
1157  }
1158 
1164  bool shared() const {
1165  return false;
1166  }
1167 
1173  const Value* data() const {
1174  return data_;
1175  }
1176 
1184  bool operator[](Size pos) const {
1185  return Bits<T,Size>::array_get(data_, bitsize_, pos);
1186  }
1187 
1192  ulong hash(ulong seed=0) const {
1193  return DataHash<T>::hash(data_, size_, seed);
1194  }
1195 
1196  // BITS
1197 
1199  Iter cbegin() const
1200  { return Iter(*this); }
1201 
1203  Iter cend() const
1204  { return Iter(); }
1205 
1207  Iter begin() const
1208  { return Iter(*this); }
1209 
1211  Iter end() const
1212  { return Iter(); }
1213 
1221  Size countbits(bool value=true) const {
1222  if (value)
1223  return Bits<T,Size>::array_countbits(data_, bitsize_);
1224  return bitsize_ - Bits<T,Size>::array_countbits(data_, bitsize_);
1225  }
1226 
1232  bool checkall() const {
1233  return Bits<T,Size>::array_checkall(data_, bitsize_);
1234  }
1235 
1241  bool checkany() const {
1242  return Bits<T,Size>::array_checkany(data_, bitsize_);
1243  }
1244 
1252  bool getbit(Size pos) const {
1253  return Bits<T,Size>::array_get(data_, bitsize_, pos);
1254  }
1255 
1264  bool setbit(Size pos, bool value=true) {
1265  return Bits<T,Size>::array_set(data_, bitsize_, pos, value);
1266  }
1267 
1277  Size setbits(Size pos=0, Size count=ALL, bool value=true) {
1278  return Bits<T,Size>::array_set_multi(data_, bitsize_, pos, count, value);
1279  }
1280 
1288  bool clearbit(Size pos) {
1289  return Bits<T,Size>::array_set(data_, bitsize_, pos, false);
1290  }
1291 
1300  Size clearbits(Size pos=0, Size count=ALL) const {
1301  return Bits<T,Size>::array_set_multi(data_, bitsize_, pos, count, false);
1302  }
1303 
1311  bool togglebit(Size pos) {
1312  return Bits<T,Size>::array_toggle(data_, bitsize_, pos);
1313  }
1314 
1323  Size togglebits(Size pos=0, uint count=ALL) {
1324  return Bits<T,Size>::array_toggle_multi(data_, bitsize_, pos, count);
1325  }
1326 
1342  template<class U>
1343  bool store(Size pos, Size count, U value) {
1344  return Bits<T,Size>::array_store(data_, bitsize_, pos, count, value);
1345  }
1346 
1359  template<class U EVO_ONCPP11(=uint32)>
1360  U extractl(Size pos=0, Size count=ALL) const {
1361  return Bits<T,Size>::template array_extractl<U>(data_, bitsize_, pos, count);
1362  }
1363 
1379  template<class U EVO_ONCPP11(=uint32)>
1380  U extractr(Size pos=0, Size count=ALL) const {
1381  return Bits<T,Size>::template array_extractr<U>(data_, bitsize_, pos, count);
1382  }
1383 
1389  ThisType& shiftl(uint count) {
1390  Bits<T,Size>::array_shiftl(data_, bitsize_, count);
1391  return *this;
1392  }
1393 
1399  ThisType& shiftr(uint count) {
1400  Bits<T,Size>::array_shiftr(data_, bitsize_, count);
1401  return *this;
1402  }
1403 
1416  Size load(const char* str, Size size, int base=2) {
1417  // Use T or ulong, whichever is larger
1418  typedef typename StaticIf<(sizeof(T) > sizeof(ulong)), T, ulong>::Type TNum;
1419 
1420  int bits_per_digit;
1421  switch (base) {
1422  case 2: bits_per_digit = 1; break;
1423  case 4: bits_per_digit = 2; break;
1424  case 8: bits_per_digit = 3; break;
1425  case 16: bits_per_digit = 4; break;
1426  case 32: bits_per_digit = 5; break;
1427  default: return 0;
1428  }
1429 
1430  uchar ch;
1431  while (size > 0 && ((ch=str[size-1]) == ' ' || ch == '\t'))
1432  --size;
1433  const char* end = str + size;
1434  while (str < end && ((ch=*str) == ' ' || ch == '\t'))
1435  ++str;
1436  if (str >= end)
1437  return 0;
1438 
1439  size = (Size)(end - str) * bits_per_digit; // size is now in bits
1440  resize(size);
1441 
1442  uint bits = 0;
1443  TNum num = 0;
1444  T* p = data_;
1445  for (; str < end; ++str) {
1446  ch = *str;
1447  if (ch >= '0' && ch <= '9')
1448  ch -= '0';
1449  else if (ch >= 'A' && ch <= 'V')
1450  ch = ch - 'A' + 10;
1451  else if (ch >= 'a' && ch <= 'v')
1452  ch = ch - 'a' + 10;
1453  else
1454  return 0; // not a digit
1455  if (ch >= base)
1456  return 0;
1457 
1458  bits += bits_per_digit;
1459  if (bits == Bits<T, Size>::BITS) {
1460  // No overflow
1461  *p = T((num * (uint)base) + ch);
1462  ++p;
1463  num = 0;
1464  bits = 0;
1465  } else if (bits > Bits<T,Size>::BITS) {
1466  // Protect from overflow from extra bits
1467  const uint shift = Bits<T,Size>::BITS - (bits - bits_per_digit);
1468  bits -= Bits<T,Size>::BITS;
1469  *p = T(num << shift) | (T(ch) >> bits);
1470  ++p;
1471  num = T(ch) & ~(Bits<T,Size>::ALLBITS << bits);
1472  } else {
1473  num *= (uint)base;
1474  num += ch;
1475  }
1476  }
1477 
1478  if (bits > 0)
1479  *p = T(num) << (Bits<T,Size>::BITS - bits);
1480  return size;
1481  }
1482 
1497  template<class U>
1498  bool format(U& out, int base=fBIN) {
1499  if (bitsize_ > 0) {
1500  const char* digits;
1501  if (base >= 100) {
1502  base -= 100;
1503  digits = "0123456789abcdefghijklmnopqrstuvwxyz";
1504  } else
1505  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1506 
1507  int bits_per_digit;
1508  switch (base) {
1509  case 2: bits_per_digit = 1; break;
1510  case 4: bits_per_digit = 2; break;
1511  case 8: bits_per_digit = 3; break;
1512  case 16: bits_per_digit = 4; break;
1513  case 32: bits_per_digit = 5; break;
1514  default: return false;
1515  }
1516 
1517  typename U::Out& outstream = out.write_out();
1518  typename U::Out::Size available = 0;
1519 
1520  Size outsize = (bitsize_ + bits_per_digit - 1) / bits_per_digit; // round up
1521  char* outbuf = outstream.write_direct_multi(available, outsize);
1522  if (outbuf == NULL)
1523  return false;
1524 
1525  char* outbuf_start = outbuf;
1526  char* outbuf_end = outbuf + available;
1527  char* outbuf_write;
1528  char* outbuf_next;
1529  Size outsize_lastwrite = outsize, digit_count;
1530 
1531  if (Bits<T,Size>::BITS % bits_per_digit != 0) {
1532  // Use extractr() when bits per digit is not a multiple of bits per chunk
1533  const uint digits_per_ulong = IntegerT<ulong>::BITS / bits_per_digit;
1534  const uint bits_per_ulong = digits_per_ulong * bits_per_digit;
1535  ulong num;
1536  outbuf_end -= digits_per_ulong;
1537  for (Size p=0; outsize > 0; p += bits_per_ulong) {
1538  digit_count = (outsize > digits_per_ulong ? digits_per_ulong : outsize);
1539  num = Bits<T,Size>::template array_extractr<ulong>(data_, bitsize_, p, digit_count * bits_per_digit);
1540  if (outbuf >= outbuf_end) {
1541  // No room, flush buffer
1542  outbuf_start = outbuf = outstream.write_direct_flush(available, (ulong)(outbuf - outbuf_start), outsize);
1543  if (outbuf == NULL)
1544  return false;
1545  outbuf_end = outbuf + available - digits_per_ulong;
1546  outsize_lastwrite = outsize;
1547  }
1548 
1549  // Format chunk
1550  outbuf_next = outbuf_write = outbuf + digit_count;
1551  for (; num != 0; num /= (T)base)
1552  *--outbuf_write = digits[num % base];
1553  while (outbuf_write > outbuf)
1554  *--outbuf_write = '0';
1555  outsize -= digit_count;
1556  outbuf = outbuf_next;
1557  }
1558  } else {
1559  // Easier when bits per digit is a multiple of bits per chunk
1560  const uint digits_per_chunk = Bits<T,Size>::BITS / bits_per_digit;
1561  const T* p = data_;
1562  const T* p_end_rndup = data_ + ((bitsize_ + Bits<T,Size>::BITS - 1) / Bits<T,Size>::BITS); // includes partial chunk at end
1563  const T* p_end = data_ + (bitsize_ / Bits<T,Size>::BITS); // not including partial chunk at end
1564  T num;
1565 
1566  while (outsize > 0) {
1567  if (outsize < digits_per_chunk)
1568  digit_count = outsize;
1569  else
1570  digit_count = digits_per_chunk;
1571 
1572  outbuf_next = outbuf + digit_count;
1573  if (outbuf_next > outbuf_end && outbuf > outbuf_start) {
1574  // No room, flush buffer
1575  outbuf_start = outbuf = outstream.write_direct_flush(available, (ulong)(outbuf - outbuf_start), outsize);
1576  if (outbuf == NULL)
1577  return false;
1578  outbuf_end = outbuf + available;
1579  outbuf_next = outbuf + digit_count;
1580  outsize_lastwrite = outsize;
1581  }
1582 
1583  // Format chunk
1584  outbuf_write = outbuf_next;
1585  if (p < p_end_rndup) {
1586  num = *p;
1587  if (p == p_end)
1588  num >>= Bits<T,Size>::BITS - (outsize * bits_per_digit);
1589  for (; num != 0; num /= (T)base)
1590  *--outbuf_write = digits[num % base];
1591  ++p;
1592  }
1593  while (outbuf_write > outbuf)
1594  *--outbuf_write = '0';
1595  assert( outbuf_next > outbuf );
1596  outsize -= digit_count;
1597  outbuf = outbuf_next;
1598  }
1599  }
1600 
1601  assert( outsize_lastwrite >= outsize );
1602  outstream.write_direct_finish(outsize_lastwrite - outsize);
1603  }
1604  return true;
1605  }
1606 
1607  // COMPARE
1608 
1613  bool operator==(const ThisType& data) const {
1614  bool result;
1615  if (this == &data)
1616  result = true;
1617  else if (data_ == NULL)
1618  result = (data.data_ == NULL);
1619  else if (data.data_ == NULL || size_ != data.size_)
1620  result = false;
1621  else
1622  result = DataEqual<T>::equal(data_, data.data_, data.size_);
1623  return result;
1624  }
1625 
1630  bool operator!=(const ThisType& data) const {
1631  bool result;
1632  if (this == &data)
1633  result = false;
1634  else if (data_ == NULL)
1635  result = (data.data_ != NULL);
1636  else if (data.data_ == NULL || size_ != data.size_)
1637  result = true;
1638  else
1639  result = !DataEqual<T>::equal(data_, data.data_, data.size_);
1640  return result;
1641  }
1642 
1648  ThisType& unshare() {
1649  return *this;
1650  }
1651 
1656  ThisType& resize(Size bitsize) {
1657  Size size = Bits<T,Size>::array_size(bitsize);
1658  if (size == 0) {
1659  // Null/Empty
1660  if (size_ > 0) {
1661  ::free(data_);
1662  data_ = EVO_PEMPTY;
1663  size_ = 0;
1664  bitsize_ = 0;
1665  }
1666  } else if (size_ != size) {
1667  // New positive size
1668  assert( size > 0 );
1669  const size_t size_bytes = (size_t)size * sizeof(Value);
1670  if (size_ > 0) {
1671  // Preserve existing items
1672  Value* const old_data = data_;
1673  data_ = (Value*)::malloc(size_bytes);
1674 
1675  const size_t save_size_bytes = (size_ < size ? size_ : size) * sizeof(Value);
1676  memcpy(data_, old_data, save_size_bytes);
1677  if (size_bytes > save_size_bytes)
1678  memset((char*)data_ + save_size_bytes, 0, size_bytes - save_size_bytes);
1679 
1680  size_ = size;
1681  ::free(old_data);
1682  } else {
1683  // New array
1684  data_ = (T*)::malloc(size_bytes);
1685  memset(data_, 0, size_bytes);
1686  }
1687  size_ = size;
1688  bitsize_ = bitsize;
1689  } else {
1690  // Same array size
1691  if (bitsize < bitsize_) {
1692  // Clear removed bits
1693  const T mask = (Bits<T,Size>::RBIT << (bitsize_ - bitsize)) - 1;
1694  data_[size_ - 1] &= ~mask;
1695  }
1696  bitsize_ = bitsize;
1697  }
1698  return *this;
1699  }
1700 
1708  ThisType& resize_pow2(Size bitsize) {
1709  if (bitsize > 0)
1710  bitsize = size_pow2(bitsize);
1711  resize(bitsize);
1712  return *this;
1713  }
1714 
1715  // INTERNAL
1716 
1717  // Iterator support methods
1719  void iterInitMutable() { }
1720  const IterItem* iterFirst(IterKey& key) const {
1721  const IterItem* result;
1722  if (bitsize_ > 0) {
1723  key.offset = Bits<T,Size>::array_iter(key.state, data_, bitsize_);
1724  if (key.offset == NONE)
1725  result = NULL;
1726  else
1727  result = (const IterItem*)&key.offset;
1728  } else {
1729  key.offset = END;
1730  result = NULL;
1731  }
1732  return result;
1733  }
1734  const IterItem* iterNext(IterKey& key) const {
1735  const IterItem* result = NULL;
1736  if (key.offset != END) {
1737  key.offset = Bits<T,Size>::array_iternext(key.state);
1738  if (key.offset == NONE)
1739  result = NULL;
1740  else
1741  result = (const IterItem*)&key.offset;
1742  }
1743  return result;
1744  }
1747 private:
1748  T* data_;
1749  Size size_;
1750  Size bitsize_;
1751 
1752  template<class> friend class BitArraySubsetT;
1753 };
1754 
1756 
1762 template<class T>
1763 inline bool operator==(const BitArraySubsetT< BitArrayT<T> >& a, const BitArrayT<T>& b) {
1764  return (a == BitArraySubsetT< BitArrayT<T> >(b));
1765 }
1766 
1772 template<class T>
1773 inline bool operator!=(const BitArraySubsetT< BitArrayT<T> >& a, const BitArrayT<T>& b) {
1774  return !(a == BitArraySubsetT< BitArrayT<T> >(b));
1775 }
1776 
1778 
1781 
1783 
1784 }
1785 #endif
ThisType & operator=(ThisType &&src)
Move assignment operator (C++11).
Definition: bit_array.h:1010
Size setbits(Size pos=0, Size count=ALL, bool value=true)
Set or clear count bits at position in bit array.
Definition: bit_array.h:1277
static Size array_set_multi(T *data, Size bitsize, Size pos=0, Size count=ALL, bool value=true)
Set or clear count bits at position in chunked bit array.
Definition: bits.h:746
static Size array_iternext(IterState &state)
Iterate to next set bit in array.
Definition: bits.h:664
static bool array_toggle(T *data, Size bitsize, Size pos)
Toggle bit at position in chunked bit array.
Definition: bits.h:815
U extractl(Size pos=0, Size count=ALL) const
Extract bits from subset.
Definition: bit_array.h:536
static bool array_get(const T *data, Size bitsize, Size pos)
Get bit at position from chunked bit array.
Definition: bits.h:702
static void array_shiftl(T *data, Size bitsize, uint count)
Shift to the left in chunked bit array.
Definition: bits.h:1163
Parent * parent_nonconst()
Get non-const pointer to parent BitArray.
Definition: bit_array.h:350
bool clearbit(Size pos)
Clear bit at position in bit array.
Definition: bit_array.h:1288
Size setbits(Size pos=0, Size count=ALL, bool value=true)
Set or clear count bits at position in subset.
Definition: bit_array.h:432
A subset of a BitArray.
Definition: bit_array.h:123
Static conditional type.
Definition: meta.h:134
Iter cend() const
Get iterator at end (const).
Definition: bit_array.h:1203
BitArrayT BitArray
Default dynamic bit array container – see BitArrayT.
Definition: bit_array.h:1779
ThisType & resize(Size bitsize)
Resize while preserving existing data (modifier).
Definition: bit_array.h:1656
bool clearbit(Size pos)
Clear bit at position in subset.
Definition: bit_array.h:449
bool togglebit(Size pos)
Toggle bit at position in bit array.
Definition: bit_array.h:1311
TParent::Value Value
Chunk value type.
Definition: bit_array.h:128
BitArraySubsetT< TParent > ThisType
This BitArraySubset type.
Definition: bit_array.h:125
#define EVO_CONTAINER_TYPE
Identify current class/struct as an EvoContainer.
Definition: meta.h:482
ThisType & shiftl(uint count)
Shift all bits in bit bit array to the left.
Definition: bit_array.h:1389
static bool array_checkall(const T *data, Size bitsize)
Check if all bits are set in bit array.
Definition: bits.h:486
BitArraySubsetT< ThisType > Subset
Subset type for this bit array type.
Definition: bit_array.h:904
bool format(U &out, int base=fBIN)
Format bits from subset to stream or string using base.
Definition: bit_array.h:586
ThisType & operator=(const ThisType &src)
Assignment operator.
Definition: bit_array.h:1033
bool store(Size pos, Size count, U value)
Stores bits from value in subset.
Definition: bit_array.h:516
U extractl(Size pos=0, Size count=ALL) const
Extract bits from bit array.
Definition: bit_array.h:1360
bool operator[](Size pos) const
Get bit at position in bit array (const).
Definition: bit_array.h:1184
bool operator!=(const ThisType &data) const
Inequality operator.
Definition: bit_array.h:1630
BitArrayT(std::initializer_list< uint32 > init)
Sequence constructor that initializes bits from a list of uint32 values (C++11).
Definition: bit_array.h:987
bool setbit(Size pos, bool value=true)
Set or clear bit at position in bit array.
Definition: bit_array.h:1264
Evo implementation detail: String helpers.
bool operator!=(const ThisType &data) const
Inequality operator.
Definition: bit_array.h:756
bool null() const
Get whether null.
Definition: bit_array.h:1139
bool store(Size pos, Size count, U value)
Stores bits from value in bit array.
Definition: bit_array.h:1343
bool getbit(Size pos) const
Get bit at position in subset (const).
Definition: bit_array.h:407
bool checkany() const
Check if any bits are set in subset (const).
Definition: bit_array.h:396
BitArrayT< T, TSize > ThisType
This bit array type.
Definition: bit_array.h:903
TParent Parent
Parent BitArray type.
Definition: bit_array.h:126
bool operator==(const ThisType &data) const
Equality operator.
Definition: bit_array.h:1613
Size size() const
Get size as number of bits in subset.
Definition: bit_array.h:320
ThisType & resize_pow2(Size bitsize)
Resize as power of 2 while preserving existing data (modifier).
Definition: bit_array.h:1708
Basic integer type.
Definition: type.h:980
bool null() const
Get whether null.
Definition: bit_array.h:304
Size offset() const
Get subset offset position in parent.
Definition: bit_array.h:327
bool empty() const
Get whether empty.
Definition: bit_array.h:1148
bool getbit(Size pos) const
Get bit at position in bit array (const).
Definition: bit_array.h:1252
ThisType & unshare()
Make data unique – no-op.
Definition: bit_array.h:1648
Iter begin() const
Get iterator at first item (const).
Definition: bit_array.h:1207
bool setbit(Size pos, bool value=true)
Set or clear bit at position in subset.
Definition: bit_array.h:419
static Size array_toggle_multi(T *data, Size bitsize, Size pos=0, Size count=ALL)
Toggle count bits at position in chunked bit array.
Definition: bits.h:835
#define EVO_PEMPTY
Special pointer value for empty but not NULL (used in containers).
Definition: type.h:1858
BitArraySubsetT(const ThisType &src)
Copy constructor to reference the same parent and subset.
Definition: bit_array.h:167
BitArraySubsetT< BitArray > BitArraySubset
Default subset of a BitArray – see BitArraySubsetT.
Definition: bit_array.h:1780
BitArrayT(const Subset &subset, Size pos=0, Size count=ALL)
Copy from subset.
Definition: bit_array.h:964
U extractr(Size pos=0, Size count=ALL) const
Extract bits from subset.
Definition: bit_array.h:562
Size clearbits(Size pos=0, Size count=ALL) const
Clear count bits at position in subset.
Definition: bit_array.h:461
ThisType & shiftr(uint count)
Shift all bits in bit bit array to the right.
Definition: bit_array.h:1399
Size load(const char *str, Size size, int base=2)
Parse and load bits from numeric string.
Definition: bit_array.h:1416
static bool array_store(T *data, Size bitsize, Size pos, Size count, U value)
Stores bits in chunked bit array.
Definition: bits.h:895
static Size array_copy(T *data, Size bitsize, T *src_data, Size src_bitsize, Size src_pos=0, Size src_count=ALL)
Copy bits from another array.
Definition: bits.h:1100
Evo implementation detail: Container iterators.
ulong hash(ulong seed=0) const
Get data hash value for whole bit array.
Definition: bit_array.h:1192
Size countbits(bool value=true) const
Count number of bits set or cleared in subset (const).
Definition: bit_array.h:374
Base 2: binary.
Definition: str.h:2321
Size countbits(bool value=true) const
Count number of bits set or cleared (const).
Definition: bit_array.h:1221
BitArraySubsetT(ThisType &&src)
Move constructor (C++11).
Definition: bit_array.h:174
BitArraySubsetT(const Parent &parent)
Constructor to reference a parent BitArray as read-only.
Definition: bit_array.h:137
Size size() const
Get bit size.
Definition: bit_array.h:1155
bool empty() const
Get whether empty.
Definition: bit_array.h:313
bool togglebit(Size pos)
Toggle bit at position in subset.
Definition: bit_array.h:478
Size checkall() const
Check if all bits are set in subset (const).
Definition: bit_array.h:387
static const EndT END
Special integer value for indicating end of items or no item.
Definition: type.h:1846
BitArrayT(ThisType &&src)
Move constructor (C++11).
Definition: bit_array.h:1001
bool format(U &out, int base=fBIN)
Format bits to stream or string using base.
Definition: bit_array.h:1498
static Size array_countbits(const T *data, Size bitsize)
Count number of set bits in bit array.
Definition: bits.h:418
Size togglebits(Size pos=0, uint count=ALL)
Toggle count bits at position in subset.
Definition: bit_array.h:490
BitArraySubsetT()
Constructor sets as null.
Definition: bit_array.h:131
static const EndT ALL
Special integer value for indicating all items or all remaining items.
Definition: type.h:1839
ThisType & clear()
Clear by freeing all values.
Definition: bit_array.h:1042
bool operator==(const ThisType &data) const
Equality operator.
Definition: bit_array.h:667
Forward iterator.
Definition: iter.h:340
ThisType & setempty()
Set as empty but not null.
Definition: bit_array.h:1122
static ulong hash(const T *data, ulong size, ulong seed=0)
Compute hash value from data.
Definition: container.h:899
bool checkany() const
Check if any bits are set in bit array (const).
Definition: bit_array.h:1241
const Value * data() const
Get data pointer (const).
Definition: bit_array.h:1173
Evo C++ Library namespace.
Definition: alg.h:11
static const EndT NONE
Special integer value for indicating no item or unknown item.
Definition: type.h:1832
Size togglebits(Size pos=0, uint count=ALL)
Toggle count bits at position in bit array.
Definition: bit_array.h:1323
IteratorFw< ThisType >::Const Iter
Iterator (const) - IteratorFw.
Definition: bit_array.h:917
static bool equal(const T *data1, const T *data2, ulong size)
Compare array data for equality.
Definition: container.h:721
Size clearbits(Size pos=0, Size count=ALL) const
Clear count bits at position in bit array.
Definition: bit_array.h:1300
Iter end() const
Get iterator at end (const).
Definition: bit_array.h:1211
BitArraySubsetT(const Parent &parent, Size pos, Size count=ALL)
Constructor to reference a subset of parent BitArray as read-only.
Definition: bit_array.h:151
BitArrayT(const ThisType &src)
Copy constructor.
Definition: bit_array.h:933
T Value
Chunk value type for bits.
Definition: bit_array.h:906
TSize Size
Size integer type.
Definition: bit_array.h:905
ThisType & operator=(ThisType &&src)
Move assignment operator (C++11).
Definition: bit_array.h:183
static bool array_set(T *data, Size bitsize, Size pos, bool value=true)
Set or clear bit at position in chunked bit array.
Definition: bits.h:721
const Parent * parent() const
Get pointer to parent BitArray.
Definition: bit_array.h:343
BitArrayT(const ThisType &src, Size pos, Size count=ALL)
Copy from another bit array.
Definition: bit_array.h:948
Evo bit manipulation.
bool readonly() const
Get whether subset is read-only, meaning writes will fail.
Definition: bit_array.h:336
ThisType & operator=(const Parent &parent)
Assignment operator to reference a new parent as read-only.
Definition: bit_array.h:208
static Size array_iter(IterState &state, const T *data, Size bitsize)
Iterate to first set bit in array.
Definition: bits.h:641
bool checkall() const
Check if all bits are set in bit array (const).
Definition: bit_array.h:1232
Bit array iteration state.
Definition: bits.h:615
U extractr(Size pos=0, Size count=ALL) const
Extract bits from bit array.
Definition: bit_array.h:1380
static void array_shiftr(T *data, Size bitsize, uint count)
Shift to the right in chunked bit array.
Definition: bits.h:1210
~BitArrayT()
Destructor.
Definition: bit_array.h:978
const ThisType & asconst() const
Explicitly use a const reference to this.
Definition: bit_array.h:1023
ThisType & operator=(const ThisType &src)
Assignment operator to copy a subset, referencing the same parent.
Definition: bit_array.h:196
BitArraySubsetT(Parent &parent, Size pos, Size count=ALL)
Constructor to reference a subset of parent BitArray.
Definition: bit_array.h:160
ThisType & operator=(Parent &parent)
Assignment operator to reference a new parent.
Definition: bit_array.h:220
static Size array_size(Size bitsize)
Calculate array size in chunks for number of bits.
Definition: bits.h:396
bool shared() const
Get whether shared (false).
Definition: bit_array.h:1164
TParent::Size Size
Size integer type.
Definition: bit_array.h:127
BitArrayT()
Default constructor sets as null.
Definition: bit_array.h:920
BitArraySubsetT(Parent &parent)
Constructor to reference a parent BitArray.
Definition: bit_array.h:143
Dynamic bit array container with similar interface to Array and List.
Definition: bit_array.h:900
BitArrayT(Size bitsize)
Constructor create bit array.
Definition: bit_array.h:926
Traits and helpers for bit manipulation.
Definition: bits.h:309
Size size_pow2(Size size, Size minsize=2)
Get size as power of 2.
Definition: type.h:1951
bool operator[](Size pos) const
Get bit at position in subset (const).
Definition: bit_array.h:363
Iter cbegin() const
Get iterator at first item (const).
Definition: bit_array.h:1199
static bool array_checkany(const T *data, Size bitsize)
Check if any bits are set in bit array.
Definition: bits.h:555