Aleph-w  1.9
General library for algorithms and data structures
bitArray.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 
28 # ifndef BITARRAY_H
29 # define BITARRAY_H
30 
31 # include <iostream>
32 # include <fstream>
33 # include <aleph.H>
34 # include <tpl_dynArray.H>
35 
36 namespace Aleph {
37 
38 class Byte
39 {
40  unsigned int b0 : 1;
41  unsigned int b1 : 1;
42  unsigned int b2 : 1;
43  unsigned int b3 : 1;
44  unsigned int b4 : 1;
45  unsigned int b5 : 1;
46  unsigned int b6 : 1;
47  unsigned int b7 : 1;
48 
49 public:
50 
51  unsigned int read_bit(const unsigned int i) const noexcept
52  {
53  assert(i < 8);
54 
55  switch (i)
56  {
57  case 0 : return b0;
58  case 1 : return b1;
59  case 2 : return b2;
60  case 3 : return b3;
61  case 4 : return b4;
62  case 5 : return b5;
63  case 6 : return b6;
64  case 7 : return b7;
65  default: assert(false);
66  }
67  return 0; // never reached
68  }
69 
70  void write_bit(const unsigned int i, const unsigned int value) noexcept
71  {
72  assert(i < 8);
73  assert(value <= 1);
74 
75  switch (i)
76  {
77  case 0 : b0 = value; break;
78  case 1 : b1 = value; break;
79  case 2 : b2 = value; break;
80  case 3 : b3 = value; break;
81  case 4 : b4 = value; break;
82  case 5 : b5 = value; break;
83  case 6 : b6 = value; break;
84  case 7 : b7 = value; break;
85  default: assert(false);
86  }
87  }
88 
89  Byte() noexcept : b0(0), b1(0), b2(0), b3(0), b4(0), b5(0), b6(0), b7(0) {}
90 
91  int get_int() const noexcept
92  {
93  const unsigned char * const ptr = (unsigned char*) this;
94  return *ptr;
95  }
96 
97  void set_int(int i) noexcept
98  {
99  unsigned char * ptr = (unsigned char*) this;
100  *ptr = i;
101  }
102 
103  Byte & operator |= (const Byte & rhs)
104  {
105  (unsigned char&) *this |= (unsigned char&) rhs;
106  return *this;
107  }
108 
109  Byte & operator &= (const Byte & rhs)
110  {
111  (unsigned char&) *this &= (unsigned char&) rhs;
112  return *this;
113  }
114 };
115 
135 class BitArray
136 {
137  size_t current_size;
138  DynArray<Byte> array_of_bytes;
139 
140  size_t get_num_bytes() const noexcept
141  {
142  size_t div = current_size/8;
143 
144  return (current_size % 8) != 0 ? div + 1 : div;
145  }
146 
147  class BitProxy
148  {
149  const size_t index;
150  const size_t bit_index;
151  const size_t byte_index;
152  BitArray * array;
153  Byte * byte_ptr;
154 
155  public:
156 
157  BitProxy(BitArray & a, const size_t i) noexcept
158  : index(i), bit_index(i % 8), byte_index(i/8), array(&a)
159  {
160  if (array->array_of_bytes.exist(byte_index))
161  byte_ptr = &array->array_of_bytes.access(byte_index);
162  else
163  byte_ptr = nullptr;
164  }
165 
166  operator int () const
167  {
168  if (index >= array->current_size)
169  throw std::out_of_range("Index out of range");
170 
171  return byte_ptr != nullptr ? byte_ptr->read_bit(bit_index) : 0;
172  }
173 
174  BitProxy & operator = (const size_t value)
175  {
176  assert(value <= 1);
177 
178  if (byte_ptr == nullptr)
179  byte_ptr = &array->array_of_bytes.touch(byte_index);
180 
181  if (index >= array->current_size)
182  array->current_size = index;
183 
184  byte_ptr->write_bit(bit_index, value);
185 
186  return *this;
187  }
188 
189  BitProxy & operator = (const BitProxy & proxy)
190  {
191  if (byte_ptr == nullptr)
192  byte_ptr = &array->array_of_bytes.touch(byte_index);
193 
194  if (index >= array->current_size)
195  array->current_size = index;
196 
197  byte_ptr->write_bit(bit_index, proxy.byte_ptr->read_bit(proxy.bit_index));
198 
199  return *this;
200  }
201  };
202 
203 public:
204 
205  using Item_Type = unsigned char;
206 
213  BitArray(const size_t dim = 0)
214  : current_size(dim), array_of_bytes(get_num_bytes())
215  {
216  array_of_bytes.set_default_initial_value(Byte());
217  }
218 
229  void reserve(size_t dim)
230  {
231  current_size = dim;
232 
233  int num_bytes = dim/8;
234  if (dim % 8)
235  ++num_bytes;
236 
237  array_of_bytes.reserve(num_bytes);
238  }
239 
241  size_t size() const noexcept { return current_size; }
242 
244  void set_size(const size_t sz)
245  {
246  size_t array_size = sz / 8;
247  if (array_size % 8)
248  ++array_size;
249 
250  array_of_bytes.adjust(array_size);
251  current_size = sz;
252  }
253 
254  BitProxy operator [] (const size_t i) const noexcept
255  {
256  return BitProxy(const_cast<BitArray&>(*this), i);
257  }
258 
259  BitProxy operator [] (const size_t i) noexcept { return BitProxy(*this, i); }
260 
261  int read_bit_ne(const size_t i) const noexcept
262  {
263  const int bit_index = i % 8;
264  auto ptr = array_of_bytes.test(i/8);
265  if (ptr)
266  {
267  const Byte & byte = *ptr;
268  return byte.read_bit(bit_index);
269  }
270  else
271  return 0;
272  }
273 
280  int read_bit(const size_t i) const
281  {
282  if (i >= current_size)
283  throw std::out_of_range("index out of range");
284  const int bit_index = i % 8;
285  const Byte byte = array_of_bytes[i/8];
286  return byte.read_bit(bit_index);
287  }
288 
289  int operator () (const size_t i) const { return read_bit(i); }
290 
298  void write_bit(const size_t i, const unsigned int value)
299  {
300  array_of_bytes.touch(i/8).write_bit(i%8, value);
301  if (i >= current_size)
302  current_size = i + 1;
303  }
304 
313  int read(const size_t i) const
314  {
315  if (i >= current_size)
316  throw std::out_of_range("index out of range");
317 
318  const int bit_index = i % 8;
319  return array_of_bytes.access(i/8).read_bit(bit_index);
320  }
321 
329  void write(const size_t i, const unsigned int value)
330  {
331  array_of_bytes.access(i/8).write_bit(i%8, value);
332  if (i >= current_size)
333  current_size = i + 1;
334  }
335 
336  int fast_read(const size_t i) const noexcept
337  {
338  return array_of_bytes.access(i/8).read_bit(i%8);
339  }
340 
341  void fast_write(const size_t i, const unsigned int value)
342  {
343  array_of_bytes.access(i/8).write_bit(i%8, value);
344  }
345 
347  void push(const unsigned int value)
348  {
349  write_bit(current_size, value);
350  }
351 
353  void pop()
354  {
355  current_size--;
356  array_of_bytes.cut(get_num_bytes());
357  }
358 
360  void empty() noexcept
361  {
362  current_size = 0;
363  array_of_bytes.cut();
364  }
365 
374  BitArray(const BitArray & array)
375  : current_size(array.current_size), array_of_bytes (array.array_of_bytes)
376  {
377  // empty
378  }
379 
380  void swap(BitArray & array) noexcept
381  {
382  std::swap(current_size, array.current_size);
383  array_of_bytes.swap(array.array_of_bytes);
384  }
385 
386  BitArray(BitArray && array) noexcept
387  : BitArray()
388  {
389  swap(array);
390  }
391 
392  BitArray & operator = (BitArray && array) noexcept
393  {
394  current_size = 0;
395  array_of_bytes.cut();
396  swap(array);
397  return *this;
398  }
399 
402  {
403  DynList<char> ret_val;
404  for (size_t i = 0; i < current_size; ++i)
405  ret_val.append((char) read_bit(i));
406  return ret_val;
407  }
408 
420  BitArray & operator = (const BitArray & array)
421  {
422  if (this == &array)
423  return *this;
424 
425  current_size = array.current_size;
426  array_of_bytes = array.array_of_bytes;
427 
428  return *this;
429  }
430 
443  void save(std::ostream & output)
444  {
445  const size_t & num_bytes = array_of_bytes.size();
446 
447  output << num_bytes << " " << current_size << endl;
448 
449  for (size_t i = 0; i < num_bytes; i++)
450  if (array_of_bytes.exist(i))
451  {
452  int byte = array_of_bytes.access(i).get_int();
453  output << byte << " ";
454  }
455  else
456  output << "0 ";
457 
458  output << endl;
459  }
460 
471  void load(std::istream & input)
472  {
473  array_of_bytes.cut();
474 
475  // TODO: bound num_bytes to a maximum according to available ram
476  size_t num_bytes = 0;
477  input >> num_bytes >> current_size;
478  for (size_t i = 0; i < num_bytes; i++)
479  {
480  int c;
481  input >> c;
482  array_of_bytes.touch(i).set_int(c);;
483  }
484  }
485 
488  BitArray(std::ifstream & input)
489  {
490  load(input);
491  }
492 
508  void save_in_array_of_chars(const string & name, std::ostream & output)
509  {
510  const size_t & num_bytes = array_of_bytes.size();
511 
512  output << "// " << current_size << " bits declaration" << endl
513  << "const unsigned char " << name << " [" << num_bytes << "] = {"
514  << endl << " ";
515  for (size_t i = 0; i < num_bytes; i++)
516  {
517  if (array_of_bytes.exist(i))
518  {
519  int byte = array_of_bytes.access(i).get_int();
520  output << byte;
521  }
522  else
523  output << "0";
524 
525  if (i != num_bytes - 1)
526  output << ", ";
527 
528  if ((i+1) % 15 == 0)
529  output << endl << " ";
530  }
531  output << endl << "};" << endl << endl;
532  }
533 
545  void load_from_array_of_chars(const unsigned char str[],
546  const size_t num_bits)
547  {
548  array_of_bytes.cut();
549 
550  size_t num_bytes = num_bits/8;
551 
552  if (num_bits % 8 != 0)
553  num_bytes++;
554 
555  for (size_t i = 0; i < num_bytes; i++)
556  array_of_bytes.touch(i).set_int(str[i]);
557 
558  current_size = num_bits;
559  }
560 
568  void left_shift(const size_t n = 1) noexcept
569  {
570  const size_t real_n = std::min <size_t>(n, current_size);
571 
572  for (size_t i = 0; i < current_size - real_n; ++i)
573  write_bit(i, read_bit(i + real_n));
574 
575  for (size_t i = current_size - real_n; i < current_size; ++i)
576  write_bit(i, 0);
577  }
578 
586  void right_shift(const size_t n = 1) noexcept
587  {
588  const size_t real_n = std::min <size_t>(n, current_size);
589 
590  for (size_t i = current_size; i > real_n; --i)
591  write_bit(i - 1, read_bit(i - real_n - 1));
592 
593  for (size_t i = real_n; i > 0; --i)
594  write_bit(i - 1, 0);
595  }
596 
604  void dyn_left_shift(const size_t n = 1)
605  {
606  for (size_t i = 0; i < n; ++i)
607  push(0);
608  }
609 
617  void dyn_right_shift(const size_t n = 1)
618  {
619  if (n >= current_size)
620  {
621  set_size(1);
622  array_of_bytes.set_default_initial_value(Byte());
623  return;
624  }
625 
626  BitArray array(current_size - n);
627 
628  for (size_t i = 0; i < current_size - n; ++i)
629  array.write_bit(i, read_bit(i));
630 
631  *this = array;
632  }
633 
641  void circular_left_shift(const size_t n = 1) noexcept
642  {
643  const size_t real_n = n % current_size;
644 
645  if (real_n == 0)
646  return;
647 
648  BitArray array(real_n);
649 
650  for (size_t i = 0; i < real_n; ++i)
651  array.write_bit(i, read_bit(i));
652 
653  for (size_t i = 0; i < current_size - real_n; ++i)
654  write_bit(i, read_bit(i + real_n));
655 
656  for (size_t i = 0; i < real_n; ++i)
657  write_bit(current_size - real_n + i, array.read_bit(i));
658  }
659 
667  void circular_right_shift(const size_t n = 1) noexcept
668  {
669  const size_t real_n = n % current_size;
670 
671  if (real_n == 0)
672  return;
673 
674  BitArray array(real_n);
675 
676  for (size_t i = current_size - real_n; i < current_size; ++i)
677  array.write_bit(i - (current_size - real_n), read_bit(i));
678 
679  for (size_t i = current_size - 1; i >= real_n; --i)
680  write_bit(i, read_bit(i - real_n));
681 
682  for (size_t i = 0; i < real_n; ++i)
683  write_bit(i, array.read_bit(i));
684  }
685 
686  template <typename T>
687  void set_num(T n) // Paso copia porque es modificado adentro
688  {
689  empty();
690  const size_t num_bits = sizeof(T) * 8;
691  reserve(num_bits);
692  for (size_t i = 0; i < num_bits; ++i)
693  {
694  write_bit(current_size - i - 1, n & 1);
695  n >>= 1;
696  }
697  }
698 
699  void set_num(const char & c)
700  {
701  set_num<char>(c);
702  }
703 
704  void set_num(const short & c)
705  {
706  set_num<short>(c);
707  }
708 
709  void set_num(const int & c)
710  {
711  set_num<int>(c);
712  }
713 
714  void set_num(const long & c)
715  {
716  set_num<long>(c);
717  }
718 
719  long get_num() noexcept
720  {
721  long ret_val = 0;
722  for (size_t i = 0; i < current_size; ++i)
723  ret_val += read_bit(current_size - i - 1) << i;
724  return ret_val;
725  }
726 
727  void set_bit_str(const std::string & str)
728  {
729  empty();
730  const size_t & str_size = str.size();
731 
732  reserve(str_size);
733 
734  for (size_t i = 0; i < str_size; ++i)
735  {
736  char c = str[i];
737  assert(c == '1' or c == '0');
738  write_bit(i, (c == '0' ? 0 : 1));
739  }
740  }
741 
742  std::string get_bit_str() const
743  {
744  std::string ret_val;
745  for (size_t i = 0; i < current_size; ++i)
746  ret_val.append(read_bit(i) == 0 ? "0" : "1");
747 
748  return ret_val;
749  }
750 
751  friend ostream & operator << (ostream & out, const BitArray & array)
752  {
753  for (size_t i = 0; i < array.current_size; ++i)
754  out << array.read_bit(i);
755  return out;
756  }
757 
760  BitArray(const unsigned char str[], const size_t num_bits)
761  {
762  load_from_array_of_chars(str, num_bits);
763  }
764 
765  BitArray & operator |= (const BitArray & rhs)
766  {
767  auto n = std::min(array_of_bytes.size(), rhs.array_of_bytes.size());
768  for (size_t i = 0; i < n; ++i)
769  array_of_bytes(i) |= rhs.array_of_bytes(i);
770 
771  if (size() < n)
772  {
773  auto i = array_of_bytes.size();
774  set_size(rhs.size());
775  for (; i < rhs.array_of_bytes.size(); ++i)
776  array_of_bytes(i) = rhs.array_of_bytes(i);
777  }
778 
779  return *this;
780  }
781 
782  BitArray & operator &= (const BitArray & rhs)
783  {
784  set_size(std::min(size(), rhs.size()));
785  for (size_t i = 0; i < size(); ++i)
786  array_of_bytes(i) &= rhs.array_of_bytes(i);
787 
788  return *this;
789  }
790 
791  friend BitArray operator | (const BitArray & op1, const BitArray & op2)
792  {
793  BitArray ret = op1;
794  ret |= op2;
795  return ret;
796  }
797 
798  friend BitArray operator & (const BitArray & op1, const BitArray & op2)
799  {
800  BitArray ret = op1;
801  ret &= op2;
802  return ret;
803  }
804 
805 private:
806 
807  template <class Operation>
808  bool __traverse(Operation & operation) noexcept(noexcept(operation))
809  {
810  for (size_t i = 0; i < current_size; ++i)
811  if (not operation(read_bit_ne(i)))
812  return false;
813  return true;
814  }
815 
816 public:
817 
818  class Iterator
819  {
820  BitArray * array_ptr = nullptr;
821  long curr_idx = 0;
822 
823  public:
824 
825  Iterator() noexcept { /* empty */ }
826 
827  Iterator(const BitArray & array) noexcept
828  : array_ptr(const_cast<BitArray*>(&array)), curr_idx(0)
829  {
830  // empty
831  }
832 
833  bool has_curr() const noexcept
834  {
835  return curr_idx >= 0 and curr_idx < array_ptr->size();
836  }
837 
838  unsigned int get_curr_ne() const noexcept
839  {
840  return array_ptr->read_bit(curr_idx);
841  }
842 
843  unsigned int get_curr() const
844  {
845  if (not has_curr())
846  throw std::overflow_error("Iterator is at the end of the list");
847  return array_ptr->read_bit(curr_idx);
848  }
849 
850  long get_pos() const noexcept { return curr_idx; }
851 
852  void next_ne() noexcept { ++curr_idx; }
853 
854  void next()
855  {
856  if (curr_idx == array_ptr->size())
857  throw std::overflow_error("not current item in iterator");
858  next_ne();
859  }
860 
861  void prev_ne() noexcept { --curr_idx; }
862  void prev()
863  {
864  if (curr_idx == -1)
865  throw std::underflow_error("not current item in iterator");
866  prev_ne();
867  }
868 
869  void reset_last() noexcept { curr_idx = array_ptr->size() - 1; }
870 
871  void end() noexcept { curr_idx = array_ptr->size(); }
872 
873  void reset_first() noexcept { curr_idx = 0; }
874 
875  void reset() noexcept { reset_first(); }
876  };
877 
878  template <class Operation>
879  bool traverse(Operation & operation) const noexcept(noexcept(operation))
880  {
881  return const_cast<BitArray&>(*this).__traverse(operation);
882  }
883 
884  template <class Operation>
885  bool traverse(Operation & operation) noexcept(noexcept(operation))
886  {
887  return __traverse(operation);
888  }
889 
890  template <class Operation>
891  bool traverse(Operation && operation = Operation()) const
892  noexcept(noexcept(operation))
893  {
894  return traverse<Operation>(operation);
895  }
896 
897  template <class Operation>
898  bool traverse(Operation && operation = Operation())
899  noexcept(noexcept(operation))
900  {
901  return traverse<Operation>(operation);
902  }
903 
904  Functional_Methods(unsigned short);
905 
906  Generic_Items(unsigned char);
907 
908  STL_ALEPH_ITERATOR(BitArray);
909 };
910 
911 } // end namespace Aleph
912 # endif /* BITARRAY_H */
913 
void write_bit(const size_t i, const unsigned int value)
Definition: bitArray.H:298
int read_bit(const size_t i) const
Definition: bitArray.H:280
void reserve(const size_t l, const size_t r)
Definition: tpl_dynArray.H:998
BitArray(const BitArray &array)
Definition: bitArray.H:374
void empty() noexcept
Elimina todos los bits insertados.
Definition: bitArray.H:360
int read(const size_t i) const
Definition: bitArray.H:313
void cut(const size_t new_dim=0)
Definition: tpl_dynArray.H:1104
void reserve(size_t dim)
Definition: bitArray.H:229
Definition: bitArray.H:135
T & access(const size_t i) const noexcept
Definition: tpl_dynArray.H:874
BitArray(const size_t dim=0)
Definition: bitArray.H:213
void dyn_left_shift(const size_t n=1)
Definition: bitArray.H:604
T & touch(const size_t i)
Definition: tpl_dynArray.H:958
size_t size() const noexcept
Retorna la dimensión del arreglo de bits.
Definition: bitArray.H:241
void swap(DynArray< T > &array) noexcept
Definition: tpl_dynArray.H:819
bool exist(const size_t i) const
Definition: tpl_dynArray.H:895
DynList< char > bits_list()
Lo convierte a una lista.
Definition: bitArray.H:401
BitArray(const unsigned char str[], const size_t num_bits)
Definition: bitArray.H:760
void load(std::istream &input)
Definition: bitArray.H:471
Definition: ah-comb.H:35
void dyn_right_shift(const size_t n=1)
Definition: bitArray.H:617
void circular_left_shift(const size_t n=1) noexcept
Definition: bitArray.H:641
void push(const unsigned int value)
Inserta al final del arreglo el valor value.
Definition: bitArray.H:347
T * test(const size_t i) const noexcept
Definition: tpl_dynArray.H:927
void adjust(const size_t dim)
Definition: tpl_dynArray.H:1119
void load_from_array_of_chars(const unsigned char str[], const size_t num_bits)
Definition: bitArray.H:545
void write(const size_t i, const unsigned int value)
Definition: bitArray.H:329
void circular_right_shift(const size_t n=1) noexcept
Definition: bitArray.H:667
void pop()
Elimina el último bit del arreglo.
Definition: bitArray.H:353
void save(std::ostream &output)
Definition: bitArray.H:443
void set_size(const size_t sz)
Reajusta la dimensión del arreglo.
Definition: bitArray.H:244
void save_in_array_of_chars(const string &name, std::ostream &output)
Definition: bitArray.H:508
size_t size() const noexcept
Definition: tpl_dynArray.H:641
void set_default_initial_value(const T &value) noexcept
Definition: tpl_dynArray.H:659
Definition: ahDry.H:41
T & append(const T &item)
Definition: htlist.H:1471
void left_shift(const size_t n=1) noexcept
Definition: bitArray.H:568
BitArray(std::ifstream &input)
Definition: bitArray.H:488
void right_shift(const size_t n=1) noexcept
Definition: bitArray.H:586

Leandro Rabindranath León