Nugget
bitvector.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // Implements a bit vector, which is essentially a vector of bool but which
7 // uses bits instead of bytes. It is thus similar to the original std::vector<bool>.
9 
11 // Note: This code is not yet complete: it isn't tested and doesn't yet
12 // support containers other than vector.
14 
15 
16 #ifndef EASTL_BITVECTOR_H
17 #define EASTL_BITVECTOR_H
18 
19 
20 #include <EASTL/internal/config.h>
21 #include <EASTL/vector.h>
22 #include <EASTL/algorithm.h>
23 #include <EASTL/bitset.h>
24 
25 EA_DISABLE_VC_WARNING(4480); // nonstandard extension used: specifying underlying type for enum
26 
27 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
28  #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
29 #endif
30 
31 
32 
33 namespace eastl
34 {
35 
40  #ifndef EASTL_BITVECTOR_DEFAULT_NAME
41  #define EASTL_BITVECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " bitvector" // Unless the user overrides something, this is "EASTL bitvector".
42  #endif
43 
46  #ifndef EASTL_BITVECTOR_DEFAULT_ALLOCATOR
47  #define EASTL_BITVECTOR_DEFAULT_ALLOCATOR allocator_type(EASTL_BITVECTOR_DEFAULT_NAME)
48  #endif
49 
50 
51 
54  typedef EASTL_BITSET_WORD_TYPE_DEFAULT BitvectorWordType;
55 
56 
57  template <typename Element>
59 
60 
61  template <typename Element>
63  {
64  public:
65  typedef eastl_size_t size_type;
66  bitvector_reference(Element* ptr, eastl_size_t i);
67 
68  bitvector_reference& operator=(bool value);
69  bitvector_reference& operator=(const bitvector_reference& rhs);
70 
71  operator bool() const // Defined here because some compilers fail otherwise.
72  { return (*mpBitWord & (Element(1) << mnBitIndex)) != 0; }
73 
74  protected:
75  friend class bitvector_const_iterator<Element>;
76 
77  Element* mpBitWord;
78  size_type mnBitIndex;
79 
81  void CopyFrom(const bitvector_reference& rhs);
82  };
83 
84 
85 
86  template <typename Element>
88  {
89  public:
90  typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category;
92  typedef bool value_type;
94  typedef ptrdiff_t difference_type;
95  typedef Element element_type;
96  typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit.
97  typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit.
98  typedef eastl_size_t size_type;
99 
100  protected:
101  reference_type mReference;
102 
103  enum
104  {
105  kBitCount = (8 * sizeof(Element))
106  };
107 
108  public:
109  bool operator*() const;
110  bool operator[](difference_type n) const;
111 
113  bitvector_const_iterator(const element_type* p, eastl_size_t i);
114  bitvector_const_iterator(const reference_type& referenceType);
115 
116  bitvector_const_iterator& operator++();
117  bitvector_const_iterator operator++(int);
118  bitvector_const_iterator& operator--();
119  bitvector_const_iterator operator--(int);
120 
121  bitvector_const_iterator& operator+=(difference_type dist);
122  bitvector_const_iterator& operator-=(difference_type dist);
123  bitvector_const_iterator operator+ (difference_type dist) const;
124  bitvector_const_iterator operator- (difference_type dist) const;
125 
126  difference_type operator-(const this_type& rhs) const;
127 
128  bitvector_const_iterator& operator= (const this_type& rhs);
129 
130  bool operator==(const this_type& rhs) const;
131  bool operator!=(const this_type& rhs) const;
132 
133  bool operator< (const this_type& rhs) const;
134  bool operator<=(const this_type& rhs) const;
135  bool operator> (const this_type& rhs) const;
136  bool operator>=(const this_type& rhs) const;
137 
138  int validate(const element_type* pStart, const element_type* pEnd, eastl_size_t nExtraBits) const;
139 
140  protected:
141  template <typename, typename, typename>
142  friend class bitvector;
143 
144  reference_type& get_reference_type() { return mReference; }
145  };
146 
147 
148 
149  template <typename Element>
151  {
152  public:
153  typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category;
156  typedef bool value_type;
158  typedef ptrdiff_t difference_type;
159  typedef Element element_type;
160  typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit.
161  typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit.
162 
163  public:
164  reference_type operator*() const;
165  reference_type operator[](difference_type n) const;
166 
168  bitvector_iterator(element_type* p, eastl_size_t i);
169  bitvector_iterator(reference_type& referenceType);
170 
171  bitvector_iterator& operator++() { base_type::operator++(); return *this; }
172  bitvector_iterator& operator--() { base_type::operator--(); return *this; }
173  bitvector_iterator operator++(int);
174  bitvector_iterator operator--(int);
175 
176  bitvector_iterator& operator+=(difference_type dist) { base_type::operator+=(dist); return *this; }
177  bitvector_iterator& operator-=(difference_type dist) { base_type::operator-=(dist); return *this; }
178  bitvector_iterator operator+ (difference_type dist) const;
179  bitvector_iterator operator- (difference_type dist) const;
180 
181  // We need this here because we are overloading operator-, so for some reason the
182  // other overload of the function can't be found unless it's explicitly specified.
183  difference_type operator-(const base_type& rhs) const { return base_type::operator-(rhs); }
184  };
185 
186 
187 
199  template <typename Allocator = EASTLAllocatorType,
200  typename Element = BitvectorWordType,
201  typename Container = eastl::vector<Element, Allocator> >
202  class bitvector
203  {
204  public:
206  typedef bool value_type;
208  typedef bool const_reference;
213  typedef Allocator allocator_type;
214  typedef Element element_type;
215  typedef Container container_type;
216  typedef eastl_size_t size_type;
217  typedef ptrdiff_t difference_type;
218 
219  #if defined(_MSC_VER) && (_MSC_VER >= 1400) && (_MSC_VER <= 1600) && !EASTL_STD_CPP_ONLY // _MSC_VER of 1400 means VS2005, 1600 means VS2010. VS2012 generates errors with usage of enum:size_type.
220  enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this.
221  npos = container_type::npos,
222  kMaxSize = container_type::kMaxSize
223  };
224  #else
225  static const size_type npos = container_type::npos;
226  static const size_type kMaxSize = container_type::kMaxSize;
227  #endif
228 
229  enum
230  {
231  kBitCount = 8 * sizeof(Element)
232  };
233 
234  protected:
235  container_type mContainer;
236  size_type mFreeBitCount; // Unused bits in the last word of mContainer.
237 
238  public:
239  bitvector();
240  explicit bitvector(const allocator_type& allocator);
241  explicit bitvector(size_type n, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR);
242  bitvector(size_type n, value_type value, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR);
243  bitvector(const bitvector& copy);
244 
245  template <typename InputIterator>
246  bitvector(InputIterator first, InputIterator last);
247 
248  bitvector& operator=(const bitvector& x);
249  void swap(this_type& x);
250 
251  template <typename InputIterator>
252  void assign(InputIterator first, InputIterator last);
253 
254  iterator begin() EA_NOEXCEPT;
255  const_iterator begin() const EA_NOEXCEPT;
256  const_iterator cbegin() const EA_NOEXCEPT;
257 
258  iterator end() EA_NOEXCEPT;
259  const_iterator end() const EA_NOEXCEPT;
260  const_iterator cend() const EA_NOEXCEPT;
261 
262  reverse_iterator rbegin() EA_NOEXCEPT;
263  const_reverse_iterator rbegin() const EA_NOEXCEPT;
264  const_reverse_iterator crbegin() const EA_NOEXCEPT;
265 
266  reverse_iterator rend() EA_NOEXCEPT;
267  const_reverse_iterator rend() const EA_NOEXCEPT;
268  const_reverse_iterator crend() const EA_NOEXCEPT;
269 
270  bool empty() const EA_NOEXCEPT;
271  size_type size() const EA_NOEXCEPT;
272  size_type capacity() const EA_NOEXCEPT;
273 
274  void resize(size_type n, value_type value);
275  void resize(size_type n);
276  void reserve(size_type n);
277  void set_capacity(size_type n = npos); // Revises the capacity to the user-specified value. Resizes the container to match the capacity if the requested capacity n is less than the current size. If n == npos then the capacity is reallocated (if necessary) such that capacity == size.
278 
279  void push_back();
280  void push_back(value_type value);
281  void pop_back();
282 
283  reference front();
284  const_reference front() const;
285  reference back();
286  const_reference back() const;
287 
288  bool test(size_type n, bool defaultValue) const; // Returns true if the bit index is < size() and set. Returns defaultValue if the bit is >= size().
289  void set(size_type n, bool value); // Resizes the container to accomodate n if necessary.
290 
291  reference at(size_type n); // throws an out_of_range exception if n is invalid.
292  const_reference at(size_type n) const;
293 
294  reference operator[](size_type n); // behavior is undefined if n is invalid.
295  const_reference operator[](size_type n) const;
296 
297  /*
298  Work in progress:
299  template <bool value = true> iterator find_first(); // Finds the lowest "on" bit.
300  template <bool value = true> iterator find_next(const_iterator it); // Finds the next lowest "on" bit after it.
301  template <bool value = true> iterator find_last(); // Finds the index of the last "on" bit, returns size if none are set.
302  template <bool value = true> iterator find_prev(const_iterator it); // Finds the index of the last "on" bit before last_find, returns size if none are set.
303 
304  template <bool value = true> const_iterator find_first() const; // Finds the lowest "on" bit.
305  template <bool value = true> const_iterator find_next(const_iterator it) const; // Finds the next lowest "on" bit after it.
306  template <bool value = true> const_iterator find_last() const; // Finds the index of the last "on" bit, returns size if none are set.
307  template <bool value = true> const_iterator find_prev(const_iterator it) const; // Finds the index of the last "on" bit before last_find, returns size if none are set.
308  */
309 
310  element_type* data() EA_NOEXCEPT;
311  const element_type* data() const EA_NOEXCEPT;
312 
313  iterator insert(const_iterator position, value_type value);
314  void insert(const_iterator position, size_type n, value_type value);
315 
316  // template <typename InputIterator> Not yet implemented. See below for disabled definition.
317  // void insert(const_iterator position, InputIterator first, InputIterator last);
318 
319  iterator erase(const_iterator position);
320  iterator erase(const_iterator first, const_iterator last);
321 
322  reverse_iterator erase(const_reverse_iterator position);
323  reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last);
324 
325  void clear();
326  void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
327 
328  container_type& get_container();
329  const container_type& get_container() const;
330 
331  bool validate() const;
332  int validate_iterator(const_iterator i) const;
333  };
334 
335 
336 
337 
339  // bitvector_reference
341 
342  template <typename Element>
343  bitvector_reference<Element>::bitvector_reference(Element* p, eastl_size_t i)
344  : mpBitWord(p),
345  mnBitIndex(i)
346  {
347  }
348 
349 
350  template <typename Element>
351  bitvector_reference<Element>&
352  bitvector_reference<Element>::operator=(bool value)
353  {
354  const Element mask = (Element)(Element(1) << mnBitIndex);
355 
356  if(value)
357  *mpBitWord |= mask;
358  else
359  *mpBitWord &= ~mask;
360 
361  return *this;
362  }
363 
364 
365  template <typename Element>
366  bitvector_reference<Element>&
367  bitvector_reference<Element>::operator=(const bitvector_reference& rhs)
368  {
369  return (*this = (bool)rhs);
370  }
371 
372 
373  template <typename Element>
374  void bitvector_reference<Element>::CopyFrom(const bitvector_reference& rhs)
375  {
376  mpBitWord = rhs.mpBitWord;
377  mnBitIndex = rhs.mnBitIndex;
378  }
379 
380 
381 
382 
384  // bitvector_const_iterator
386 
387  template <typename Element>
388  bitvector_const_iterator<Element>::bitvector_const_iterator()
389  : mReference(0, 0)
390  {
391  }
392 
393 
394  template <typename Element>
395  bitvector_const_iterator<Element>::bitvector_const_iterator(const Element* p, eastl_size_t i)
396  : mReference(const_cast<Element*>(p), i) // const_cast is safe here because we never let mReference leak and we don't modify it.
397  {
398  }
399 
400 
401  template <typename Element>
402  bitvector_const_iterator<Element>::bitvector_const_iterator(const reference_type& reference)
403  : mReference(reference)
404  {
405  }
406 
407 
408  template <typename Element>
409  bitvector_const_iterator<Element>&
410  bitvector_const_iterator<Element>::operator++()
411  {
412  ++mReference.mnBitIndex;
413 
414  if(mReference.mnBitIndex == kBitCount)
415  {
416  ++mReference.mpBitWord;
417  mReference.mnBitIndex = 0;
418  }
419 
420  return *this;
421  }
422 
423 
424  template <typename Element>
425  bitvector_const_iterator<Element>&
426  bitvector_const_iterator<Element>::operator--()
427  {
428  if(mReference.mnBitIndex == 0)
429  {
430  --mReference.mpBitWord;
431  mReference.mnBitIndex = kBitCount;
432  }
433 
434  --mReference.mnBitIndex;
435  return *this;
436  }
437 
438 
439  template <typename Element>
440  bitvector_const_iterator<Element>
441  bitvector_const_iterator<Element>::operator++(int)
442  {
443  bitvector_const_iterator copy(*this);
444  ++*this;
445  return copy;
446  }
447 
448 
449  template <typename Element>
450  bitvector_const_iterator<Element>
451  bitvector_const_iterator<Element>::operator--(int)
452  {
453  bitvector_const_iterator copy(*this);
454  --*this;
455  return copy;
456  }
457 
458 
459  template <typename Element>
460  bitvector_const_iterator<Element>&
461  bitvector_const_iterator<Element>::operator+=(difference_type n)
462  {
463  n += mReference.mnBitIndex;
464 
465  if(n >= difference_type(0))
466  {
467  mReference.mpBitWord += n / kBitCount;
468  mReference.mnBitIndex = (size_type)(n % kBitCount);
469  }
470  else
471  {
472  // backwards is tricky
473  // figure out how many full words backwards we need to move
474  // n = [-1..-32] => 1
475  // n = [-33..-64] => 2
476  const size_type backwards = (size_type)(-n + kBitCount - 1);
477  mReference.mpBitWord -= backwards / kBitCount;
478 
479  // -1 => 31; backwards = 32; 31 - (backwards % 32) = 31
480  // -2 => 30; backwards = 33; 31 - (backwards % 32) = 30
481  // -3 => 29; backwards = 34
482  // ..
483  // -32 => 0; backwards = 63; 31 - (backwards % 32) = 0
484  // -33 => 31; backwards = 64; 31 - (backwards % 32) = 31
485  mReference.mnBitIndex = (kBitCount - 1) - (backwards % kBitCount);
486  }
487 
488  return *this;
489  }
490 
491 
492  template <typename Element>
493  bitvector_const_iterator<Element>&
494  bitvector_const_iterator<Element>::operator-=(difference_type n)
495  {
496  return (*this += -n);
497  }
498 
499 
500  template <typename Element>
501  bitvector_const_iterator<Element>
502  bitvector_const_iterator<Element>::operator+(difference_type n) const
503  {
504  bitvector_const_iterator copy(*this);
505  copy += n;
506  return copy;
507  }
508 
509 
510  template <typename Element>
511  bitvector_const_iterator<Element>
512  bitvector_const_iterator<Element>::operator-(difference_type n) const
513  {
514  bitvector_const_iterator copy(*this);
515  copy -= n;
516  return copy;
517  }
518 
519 
520  template <typename Element>
521  typename bitvector_const_iterator<Element>::difference_type
522  bitvector_const_iterator<Element>::operator-(const this_type& rhs) const
523  {
524  return ((mReference.mpBitWord - rhs.mReference.mpBitWord) * kBitCount) + mReference.mnBitIndex - rhs.mReference.mnBitIndex;
525  }
526 
527 
528  template <typename Element>
529  bool bitvector_const_iterator<Element>::operator==(const this_type& rhs) const
530  {
531  return (mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex == rhs.mReference.mnBitIndex);
532  }
533 
534 
535  template <typename Element>
536  bool bitvector_const_iterator<Element>::operator!=(const this_type& rhs) const
537  {
538  return !(*this == rhs);
539  }
540 
541 
542  template <typename Element>
543  bool bitvector_const_iterator<Element>::operator<(const this_type& rhs) const
544  {
545  return (mReference.mpBitWord < rhs.mReference.mpBitWord) ||
546  ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex < rhs.mReference.mnBitIndex));
547  }
548 
549 
550  template <typename Element>
551  bool bitvector_const_iterator<Element>::operator<=(const this_type& rhs) const
552  {
553  return (mReference.mpBitWord < rhs.mReference.mpBitWord) ||
554  ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex <= rhs.mReference.mnBitIndex));
555  }
556 
557 
558  template <typename Element>
559  bool bitvector_const_iterator<Element>::operator>(const this_type& rhs) const
560  {
561  return !(*this <= rhs);
562  }
563 
564 
565  template <typename Element>
566  bool bitvector_const_iterator<Element>::operator>=(const this_type& rhs) const
567  {
568  return !(*this < rhs);
569  }
570 
571 
572  template <typename Element>
573  bool bitvector_const_iterator<Element>::operator*() const
574  {
575  return mReference;
576  }
577 
578 
579  template <typename Element>
580  bool bitvector_const_iterator<Element>::operator[](difference_type n) const
581  {
582  return *(*this + n);
583  }
584 
585 
586  template <typename Element>
587  bitvector_const_iterator<Element>& bitvector_const_iterator<Element>::operator= (const this_type& rhs)
588  {
589  mReference.CopyFrom(rhs.mReference);
590  return *this;
591  }
592 
593 
594  template <typename Element>
595  int bitvector_const_iterator<Element>::validate(const Element* pStart, const Element* pEnd, eastl_size_t nExtraBits) const
596  {
597  const Element* const pCurrent = mReference.mpBitWord;
598 
599  if(pCurrent >= pStart)
600  {
601  if(nExtraBits == 0)
602  {
603  if(pCurrent == pEnd && mReference)
605  else if(pCurrent < pEnd)
607  }
608  else if(pCurrent == (pEnd - 1))
609  {
610  const size_type bit = mReference.mnBitIndex;
611  const size_type lastbit = kBitCount - nExtraBits;
612 
613  if(bit == lastbit)
615  else if(bit < lastbit)
617  }
618  else if(pCurrent < pEnd)
619  {
621  }
622  }
623 
624  return eastl::isf_none;
625  }
626 
627 
628 
630  // bitvector_iterator
632 
633  template <typename Element>
634  bitvector_iterator<Element>::bitvector_iterator()
635  : base_type()
636  {
637  }
638 
639  template <typename Element>
640  bitvector_iterator<Element>::bitvector_iterator(Element* p, eastl_size_t i)
641  : base_type(p, i)
642  {
643  }
644 
645 
646  template <typename Element>
647  bitvector_iterator<Element>::bitvector_iterator(reference_type& reference)
648  : base_type(reference)
649  {
650  }
651 
652 
653  template <typename Element>
654  typename bitvector_iterator<Element>::reference_type
655  bitvector_iterator<Element>::operator*() const
656  {
657  return base_type::mReference;
658  }
659 
660 
661  template <typename Element>
662  typename bitvector_iterator<Element>::reference_type
663  bitvector_iterator<Element>::operator[](difference_type n) const
664  {
665  return *(*this + n);
666  }
667 
668 
669  template <typename Element>
670  void MoveBits(bitvector_iterator<Element> start,
671  bitvector_iterator<Element> end,
672  bitvector_iterator<Element> dest)
673  {
674  // Slow implemenation; could optimize by moving a word at a time.
675  if(dest <= start)
676  {
677  while(start != end)
678  {
679  *dest = *start;
680  ++dest;
681  ++start;
682  }
683  }
684  else
685  {
686  // Need to move backwards
687  dest += (end - start);
688 
689  while(start != end)
690  {
691  --dest;
692  --end;
693  *dest = *end;
694  }
695  }
696  }
697 
698 
699  template <typename Element>
700  bitvector_iterator<Element>
701  bitvector_iterator<Element>::operator++(int)
702  {
703  bitvector_iterator copy(*this);
704  ++*this;
705  return copy;
706  }
707 
708 
709  template <typename Element>
710  bitvector_iterator<Element>
711  bitvector_iterator<Element>::operator--(int)
712  {
713  bitvector_iterator copy(*this);
714  --*this;
715  return copy;
716  }
717 
718 
719  template <typename Element>
720  bitvector_iterator<Element>
721  bitvector_iterator<Element>::operator+(difference_type n) const
722  {
723  bitvector_iterator copy(*this);
724  copy += n;
725  return copy;
726  }
727 
728 
729  template <typename Element>
730  bitvector_iterator<Element>
731  bitvector_iterator<Element>::operator-(difference_type n) const
732  {
733  bitvector_iterator copy(*this);
734  copy -= n;
735  return copy;
736  }
737 
738 
739 
740 
742  // bitvector
744 
745  template <typename Allocator, typename Element, typename Container>
746  template <typename InputIterator>
747  void bitvector<Allocator, Element, Container>::assign(InputIterator first, InputIterator last)
748  {
749  // To consider: We can maybe specialize this on bitvector_iterator to do a fast bitwise copy.
750  // We can also specialize for random access iterators to figure out the size & reserve first.
751 
752  clear();
753 
754  while(first != last)
755  {
756  push_back(*first);
757  ++first;
758  }
759  }
760 
761 
762  template <typename Allocator, typename Element, typename Container>
763  typename bitvector<Allocator, Element, Container>::iterator
764  bitvector<Allocator, Element, Container>::begin() EA_NOEXCEPT
765  {
766  return iterator(mContainer.begin(), 0);
767  }
768 
769 
770  template <typename Allocator, typename Element, typename Container>
771  typename bitvector<Allocator, Element, Container>::const_iterator
772  bitvector<Allocator, Element, Container>::begin() const EA_NOEXCEPT
773  {
774  return const_iterator(mContainer.begin(), 0);
775  }
776 
777 
778  template <typename Allocator, typename Element, typename Container>
779  typename bitvector<Allocator, Element, Container>::const_iterator
780  bitvector<Allocator, Element, Container>::cbegin() const EA_NOEXCEPT
781  {
782  return const_iterator(mContainer.begin(), 0);
783  }
784 
785 
786  template <typename Allocator, typename Element, typename Container>
787  typename bitvector<Allocator, Element, Container>::iterator
788  bitvector<Allocator, Element, Container>::end() EA_NOEXCEPT
789  {
790  return iterator(mContainer.end(), 0) - mFreeBitCount;
791  }
792 
793 
794  template <typename Allocator, typename Element, typename Container>
795  typename bitvector<Allocator, Element, Container>::const_iterator
796  bitvector<Allocator, Element, Container>::end() const EA_NOEXCEPT
797  {
798  return const_iterator(mContainer.end(), 0) - mFreeBitCount;
799  }
800 
801 
802  template <typename Allocator, typename Element, typename Container>
803  typename bitvector<Allocator, Element, Container>::const_iterator
804  bitvector<Allocator, Element, Container>::cend() const EA_NOEXCEPT
805  {
806  return const_iterator(mContainer.end(), 0) - mFreeBitCount;
807  }
808 
809 
810  template <typename Allocator, typename Element, typename Container>
811  bool bitvector<Allocator, Element, Container>::empty() const EA_NOEXCEPT
812  {
813  return mContainer.empty();
814  }
815 
816 
817  template <typename Allocator, typename Element, typename Container>
818  typename bitvector<Allocator, Element, Container>::size_type
819  bitvector<Allocator, Element, Container>::size() const EA_NOEXCEPT
820  {
821  return (mContainer.size() * kBitCount) - mFreeBitCount;
822  }
823 
824 
825  template <typename Allocator, typename Element, typename Container>
826  typename bitvector<Allocator, Element, Container>::size_type
827  bitvector<Allocator, Element, Container>::capacity() const EA_NOEXCEPT
828  {
829  return mContainer.capacity() * kBitCount;
830  }
831 
832 
833  template <typename Allocator, typename Element, typename Container>
834  void bitvector<Allocator, Element, Container>::set_capacity(size_type n)
835  {
836  if(n == npos)
837  mContainer.set_capacity(npos);
838  else
839  mContainer.set_capacity((n + kBitCount - 1) / kBitCount);
840  }
841 
842 
843  template <typename Allocator, typename Element, typename Container>
844  typename bitvector<Allocator, Element, Container>::reverse_iterator
845  bitvector<Allocator, Element, Container>::rbegin() EA_NOEXCEPT
846  {
847  return reverse_iterator(end());
848  }
849 
850 
851  template <typename Allocator, typename Element, typename Container>
852  typename bitvector<Allocator, Element, Container>::const_reverse_iterator
853  bitvector<Allocator, Element, Container>::rbegin() const EA_NOEXCEPT
854  {
855  return const_reverse_iterator(end());
856  }
857 
858 
859  template <typename Allocator, typename Element, typename Container>
860  typename bitvector<Allocator, Element, Container>::const_reverse_iterator
861  bitvector<Allocator, Element, Container>::crbegin() const EA_NOEXCEPT
862  {
863  return const_reverse_iterator(end());
864  }
865 
866 
867  template <typename Allocator, typename Element, typename Container>
868  typename bitvector<Allocator, Element, Container>::reverse_iterator
869  bitvector<Allocator, Element, Container>::rend() EA_NOEXCEPT
870  {
871  return reverse_iterator(begin());
872  }
873 
874 
875  template <typename Allocator, typename Element, typename Container>
876  typename bitvector<Allocator, Element, Container>::const_reverse_iterator
877  bitvector<Allocator, Element, Container>::rend() const EA_NOEXCEPT
878  {
879  return const_reverse_iterator(begin());
880  }
881 
882 
883  template <typename Allocator, typename Element, typename Container>
884  typename bitvector<Allocator, Element, Container>::const_reverse_iterator
885  bitvector<Allocator, Element, Container>::crend() const EA_NOEXCEPT
886  {
887  return const_reverse_iterator(begin());
888  }
889 
890 
891  template <typename Allocator, typename Element, typename Container>
892  typename bitvector<Allocator, Element, Container>::reference
893  bitvector<Allocator, Element, Container>::front()
894  {
895  EASTL_ASSERT(!empty());
896  return reference(&mContainer[0], 0);
897  }
898 
899 
900  template <typename Allocator, typename Element, typename Container>
901  typename bitvector<Allocator, Element, Container>::const_reference
902  bitvector<Allocator, Element, Container>::front() const
903  {
904  EASTL_ASSERT(!empty());
905 
906  // To consider: make a better solution to this than const_cast.
907  return reference(const_cast<Element*>(&mContainer[0]), 0);
908  }
909 
910 
911  template <typename Allocator, typename Element, typename Container>
912  typename bitvector<Allocator, Element, Container>::reference
913  bitvector<Allocator, Element, Container>::back()
914  {
915  EASTL_ASSERT(!empty());
916  return *(--end());
917  }
918 
919 
920  template <typename Allocator, typename Element, typename Container>
921  typename bitvector<Allocator, Element, Container>::const_reference
922  bitvector<Allocator, Element, Container>::back() const
923  {
924  EASTL_ASSERT(!empty());
925  return *(--end());
926  }
927 
928 
929  template <typename Allocator, typename Element, typename Container>
930  void bitvector<Allocator, Element, Container>::push_back()
931  {
932  if(!mFreeBitCount)
933  {
934  mContainer.push_back();
935  mFreeBitCount = kBitCount;
936  }
937 
938  --mFreeBitCount;
939  }
940 
941 
942  template <typename Allocator, typename Element, typename Container>
943  void bitvector<Allocator, Element, Container>::push_back(value_type value)
944  {
945  push_back();
946  *--end() = value;
947  }
948 
949 
950  template <typename Allocator, typename Element, typename Container>
951  void bitvector<Allocator, Element, Container>::pop_back()
952  {
953  EASTL_ASSERT(!empty());
954 
955  if(++mFreeBitCount == kBitCount)
956  {
957  mContainer.pop_back();
958  mFreeBitCount = 0;
959  }
960  }
961 
962 
963  template <typename Allocator, typename Element, typename Container>
964  void bitvector<Allocator, Element, Container>::reserve(size_type n)
965  {
966  const size_type wordCount = (n + kBitCount - 1) / kBitCount;
967  mContainer.reserve(wordCount);
968  }
969 
970 
971  template <typename Allocator, typename Element, typename Container>
972  void bitvector<Allocator, Element, Container>::resize(size_type n)
973  {
974  const size_type wordCount = (n + kBitCount - 1) / kBitCount;
975  const size_type extra = (wordCount * kBitCount) - n;
976 
977  mContainer.resize(wordCount);
978  mFreeBitCount = extra;
979  }
980 
981 
982  template <typename Allocator, typename Element, typename Container>
983  void bitvector<Allocator, Element, Container>::resize(size_type n, value_type value)
984  {
985  const size_type s = size();
986  if(n < s)
987  resize(n);
988 
989  // Fill up to the end of a word
990  size_type newbits = n - s;
991 
992  while(mFreeBitCount && newbits)
993  {
994  push_back(value);
995  --newbits;
996  }
997 
998  // Fill the rest a word at a time
999  if(newbits)
1000  {
1001  element_type element(0);
1002  if(value)
1003  element = ~element;
1004 
1005  const size_type words = (n + kBitCount - 1) / kBitCount;
1006  const size_type extra = words * kBitCount - n;
1007  mContainer.resize(words, element);
1008  mFreeBitCount = extra;
1009  }
1010  }
1011 
1012 
1013  template <typename Allocator, typename Element, typename Container>
1014  bool bitvector<Allocator, Element, Container>::test(size_type n, bool defaultValue) const
1015  {
1016  if(n < size())
1017  return *(begin() + (difference_type)n);
1018 
1019  return defaultValue;
1020  }
1021 
1022 
1023  template <typename Allocator, typename Element, typename Container>
1024  void bitvector<Allocator, Element, Container>::set(size_type n, bool value)
1025  {
1026  if(EASTL_UNLIKELY(n >= size()))
1027  resize(n + 1);
1028 
1029  *(begin() + (difference_type)n) = value;
1030  }
1031 
1032 
1033  template <typename Allocator, typename Element, typename Container>
1034  typename bitvector<Allocator, Element, Container>::reference
1035  bitvector<Allocator, Element, Container>::at(size_type n)
1036  {
1037  // The difference between at and operator[] is that at signals
1038  // if the requested position is out of range by throwing an
1039  // out_of_range exception.
1040 
1041  #if EASTL_EXCEPTIONS_ENABLED
1042  if(EASTL_UNLIKELY(n >= size()))
1043  throw std::out_of_range("bitvector::at -- out of range");
1044  #elif EASTL_ASSERT_ENABLED
1045  if(EASTL_UNLIKELY(n >= size()))
1046  EASTL_FAIL_MSG("bitvector::at -- out of range");
1047  #endif
1048 
1049  return *(begin() + (difference_type)n);
1050  }
1051 
1052 
1053  template <typename Allocator, typename Element, typename Container>
1054  typename bitvector<Allocator, Element, Container>::const_reference
1055  bitvector<Allocator, Element, Container>::at(size_type n) const
1056  {
1057  #if EASTL_EXCEPTIONS_ENABLED
1058  if(EASTL_UNLIKELY(n >= size()))
1059  throw std::out_of_range("bitvector::at -- out of range");
1060  #elif EASTL_ASSERT_ENABLED
1061  if(EASTL_UNLIKELY(n >= size()))
1062  EASTL_FAIL_MSG("bitvector::at -- out of range");
1063  #endif
1064 
1065  return *(begin() + (difference_type)n);
1066  }
1067 
1068 
1069  template <typename Allocator, typename Element, typename Container>
1070  typename bitvector<Allocator, Element, Container>::reference
1071  bitvector<Allocator, Element, Container>::operator[](size_type n)
1072  {
1073  return *(begin() + (difference_type)n);
1074  }
1075 
1076 
1077  template <typename Allocator, typename Element, typename Container>
1078  typename bitvector<Allocator, Element, Container>::const_reference
1079  bitvector<Allocator, Element, Container>::operator[](size_type n) const
1080  {
1081  return *(begin() + (difference_type)n);
1082  }
1083 
1084 
1085 /*
1086  template <typename Allocator, typename Element, typename Container>
1087  template <bool value>
1088  typename bitvector<Allocator, Element, Container>::iterator
1089  bitvector<Allocator, Element, Container>::find_first()
1090  {
1091  return begin();
1092  }
1093 
1094  template <bool value> iterator find_next(const_iterator it);
1095  template <bool value> iterator find_last();
1096  template <bool value> iterator find_prev(const_iterator it);
1097 
1098  template <bool value> const_iterator find_first() const;
1099  template <bool value> const_iterator find_next(const_iterator it) const;
1100  template <bool value> const_iterator find_last() const;
1101  template <bool value> const_iterator find_prev(const_iterator it) const;
1102 */
1103 
1104 
1105 
1106 
1107  template <typename Allocator, typename Element, typename Container>
1108  inline typename bitvector<Allocator, Element, Container>::container_type&
1109  bitvector<Allocator, Element, Container>::get_container()
1110  {
1111  return mContainer;
1112  }
1113 
1114 
1115  template <typename Allocator, typename Element, typename Container>
1116  inline const typename bitvector<Allocator, Element, Container>::container_type&
1117  bitvector<Allocator, Element, Container>::get_container() const
1118  {
1119  return mContainer;
1120  }
1121 
1122 
1123  template <typename Allocator, typename Element, typename Container>
1124  bool bitvector<Allocator, Element, Container>::validate() const
1125  {
1126  if(!mContainer.validate())
1127  return false;
1128 
1129  if((unsigned)mFreeBitCount >= kBitCount)
1130  return false;
1131 
1132  return true;
1133  }
1134 
1135 
1136  template <typename Allocator, typename Element, typename Container>
1137  int bitvector<Allocator, Element, Container>::validate_iterator(const_iterator i) const
1138  {
1139  return i.validate(mContainer.begin(), mContainer.end(), mFreeBitCount);
1140  }
1141 
1142 
1143  template <typename Allocator, typename Element, typename Container>
1144  typename bitvector<Allocator, Element, Container>::element_type*
1145  bitvector<Allocator, Element, Container>::data() EA_NOEXCEPT
1146  {
1147  return mContainer.data();
1148  }
1149 
1150 
1151  template <typename Allocator, typename Element, typename Container>
1152  const typename bitvector<Allocator, Element, Container>::element_type*
1153  bitvector<Allocator, Element, Container>::data() const EA_NOEXCEPT
1154  {
1155  return mContainer.data();
1156  }
1157 
1158 
1159  template <typename Allocator, typename Element, typename Container>
1160  typename bitvector<Allocator, Element, Container>::iterator
1161  bitvector<Allocator, Element, Container>::insert(const_iterator position, value_type value)
1162  {
1163  iterator iPosition(position.get_reference_type()); // This is just a non-const version of position.
1164 
1165  #if EASTL_ASSERT_ENABLED
1166  if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0)
1167  EASTL_FAIL_MSG("bitvector::insert -- invalid iterator");
1168  #endif
1169 
1170  // Save because we might reallocate
1171  const typename iterator::difference_type n = iPosition - begin();
1172  push_back();
1173  iPosition = begin() + n;
1174 
1175  MoveBits(iPosition, --end(), ++iterator(iPosition));
1176  *iPosition = value;
1177 
1178  return iPosition;
1179  }
1180 
1181 
1182  template <typename Allocator, typename Element, typename Container>
1183  void bitvector<Allocator, Element, Container>::insert(const_iterator position, size_type n, value_type value)
1184  {
1185  iterator iPosition(position.get_reference_type()); // This is just a non-const version of position.
1186 
1187  #if EASTL_ASSERT_ENABLED
1188  if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0)
1189  EASTL_FAIL_MSG("bitvector::insert -- invalid iterator");
1190  #endif
1191 
1192  // Save because we might reallocate.
1193  const typename iterator::difference_type p = iPosition - begin();
1194  resize(size() + n);
1195  iPosition = begin() + p;
1196 
1197  iterator insert_end = iPosition + n;
1198  MoveBits(iPosition, end() - n, insert_end);
1199 
1200  // To do: Optimize this to word-at-a-time for large inserts
1201  while(iPosition != insert_end)
1202  {
1203  *iPosition = value;
1204  ++iPosition;
1205  }
1206  }
1207 
1208 
1209  /*
1210  The following is a placeholder for a future implementation. It turns out that a correct implementation of
1211  insert(pos, first, last) is a non-trivial exercise that would take a few hours to implement and test.
1212  The reasons why involve primarily the problem of handling the case where insertion source comes from
1213  within the container itself, and the case that first and last (note they are templated) might not refer
1214  to iterators might refer to a value/count pair. The C++ Standard requires you to handle this case and
1215  I (Paul Pedriana) believe that it applies even for a bitvector, given that bool is an integral type.
1216  So you have to set up a compile-time type traits function chooser. See vector, for example.
1217 
1218  template <typename Allocator, typename Element, typename Container>
1219  template <typename InputIterator>
1220  void bitvector<Allocator, Element, Container>::insert(const_iterator position, InputIterator first, InputIterator last)
1221  {
1222  iterator iPosition(position.get_reference_type()); // This is just a non-const version of position.
1223 
1224  // This implementation is probably broken due to not handling insertion into self.
1225  // To do: Make a more efficient version of this.
1226  difference_type distance = (iPosition - begin());
1227 
1228  while(first != last)
1229  {
1230  insert(iPosition, *first);
1231  iPosition = begin() + ++distance;
1232  ++first;
1233  }
1234  }
1235  */
1236 
1237 
1238  template <typename Allocator, typename Element, typename Container>
1239  typename bitvector<Allocator, Element, Container>::iterator
1240  bitvector<Allocator, Element, Container>::erase(const_iterator position)
1241  {
1242  iterator iPosition(position.get_reference_type()); // This is just a non-const version of position.
1243 
1244  #if EASTL_ASSERT_ENABLED
1245  if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_can_dereference) == 0)
1246  EASTL_FAIL_MSG("bitvector::erase -- invalid iterator");
1247  #endif
1248 
1249  MoveBits(++iterator(iPosition), end(), iPosition);
1250  resize(size() - 1);
1251 
1252  // Verify that no reallocation occurred.
1253  EASTL_ASSERT(validate_iterator(iPosition) & eastl::isf_valid);
1254  return iPosition;
1255  }
1256 
1257 
1258  template <typename Allocator, typename Element, typename Container>
1259  typename bitvector<Allocator, Element, Container>::iterator
1260  bitvector<Allocator, Element, Container>::erase(const_iterator first, const_iterator last)
1261  {
1262  iterator iFirst(first.get_reference_type()); // This is just a non-const version of first.
1263  iterator iLast(last.get_reference_type()); // This is just a non-const version of last.
1264 
1265  #if EASTL_ASSERT_ENABLED
1266  if(EASTL_UNLIKELY(validate_iterator(iLast) & eastl::isf_valid) == 0)
1267  EASTL_FAIL_MSG("bitvector::erase -- invalid iterator");
1268  #endif
1269 
1270  if(!(iFirst == iLast))
1271  {
1272  #if EASTL_ASSERT_ENABLED
1273  if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_can_dereference) == 0)
1274  EASTL_FAIL_MSG("bitvector::erase -- invalid iterator");
1275  #endif
1276 
1277  const size_type eraseCount = (size_type)(iLast - iFirst);
1278  MoveBits(iLast, end(), iFirst);
1279  resize(size() - eraseCount);
1280 
1281  // Verify that no reallocation occurred.
1282  #if EASTL_ASSERT_ENABLED
1283  if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_valid) == 0)
1284  EASTL_FAIL_MSG("bitvector::erase -- invalid iterator");
1285  #endif
1286  }
1287 
1288  return iFirst;
1289  }
1290 
1291 
1292  template <typename Allocator, typename Element, typename Container>
1293  typename bitvector<Allocator, Element, Container>::reverse_iterator
1294  bitvector<Allocator, Element, Container>::erase(const_reverse_iterator position)
1295  {
1296  return reverse_iterator(erase((++position).base()));
1297  }
1298 
1299 
1300  template <typename Allocator, typename Element, typename Container>
1301  typename bitvector<Allocator, Element, Container>::reverse_iterator
1302  bitvector<Allocator, Element, Container>::erase(const_reverse_iterator first, const_reverse_iterator last)
1303  {
1304  // Version which erases in order from first to last.
1305  // difference_type i(first.base() - last.base());
1306  // while(i--)
1307  // first = erase(first);
1308  // return first;
1309 
1310  // Version which erases in order from last to first, but is slightly more efficient:
1311  return reverse_iterator(erase(last.base(), first.base()));
1312  }
1313 
1314 
1315  template <typename Allocator, typename Element, typename Container>
1316  void bitvector<Allocator, Element, Container>::swap(this_type& rhs)
1317  {
1318  mContainer.swap(rhs.mContainer);
1319  eastl::swap(mFreeBitCount, rhs.mFreeBitCount);
1320  }
1321 
1322 
1323  template <typename Allocator, typename Element, typename Container>
1324  void bitvector<Allocator, Element, Container>::reset_lose_memory()
1325  {
1326  mContainer.reset_lose_memory(); // intentional memory leak.
1327  mFreeBitCount = 0;
1328  }
1329 
1330 
1331  template <typename Allocator, typename Element, typename Container>
1332  void bitvector<Allocator, Element, Container>::clear()
1333  {
1334  mContainer.clear();
1335  mFreeBitCount = 0;
1336  }
1337 
1338 
1339  template <typename Allocator, typename Element, typename Container>
1340  bitvector<Allocator, Element, Container>&
1341  bitvector<Allocator, Element, Container>::operator=(const bitvector& rhs)
1342  {
1343  // The following is OK if (&rhs == this)
1344  mContainer = rhs.mContainer;
1345  mFreeBitCount = rhs.mFreeBitCount;
1346 
1347  return *this;
1348  }
1349 
1350 
1351  template <typename Allocator, typename Element, typename Container>
1352  bitvector<Allocator, Element, Container>::bitvector()
1353  : mContainer(),
1354  mFreeBitCount(0)
1355  {
1356  }
1357 
1358 
1359  template <typename Allocator, typename Element, typename Container>
1360  bitvector<Allocator, Element, Container>::bitvector(const allocator_type& allocator)
1361  : mContainer(allocator),
1362  mFreeBitCount(0)
1363  {
1364  }
1365 
1366 
1367  template <typename Allocator, typename Element, typename Container>
1368  bitvector<Allocator, Element, Container>::bitvector(size_type n, const allocator_type& allocator)
1369  : mContainer((n + kBitCount - 1) / kBitCount, allocator)
1370  {
1371  mFreeBitCount = kBitCount - (n % kBitCount);
1372 
1373  if(mFreeBitCount == kBitCount)
1374  mFreeBitCount = 0;
1375  }
1376 
1377 
1378  template <typename Allocator, typename Element, typename Container>
1379  bitvector<Allocator, Element, Container>::bitvector(size_type n, value_type value, const allocator_type& allocator)
1380  : mContainer((n + kBitCount - 1) / kBitCount, value ? ~element_type(0) : element_type(0), allocator)
1381  {
1382  mFreeBitCount = kBitCount - (n % kBitCount);
1383 
1384  if(mFreeBitCount == kBitCount)
1385  mFreeBitCount = 0;
1386  }
1387 
1388 
1389  template <typename Allocator, typename Element, typename Container>
1390  bitvector<Allocator, Element, Container>::bitvector(const bitvector& copy)
1391  : mContainer(copy.mContainer),
1392  mFreeBitCount(copy.mFreeBitCount)
1393  {
1394  }
1395 
1396 
1397  template <typename Allocator, typename Element, typename Container>
1398  template <typename InputIterator>
1399  bitvector<Allocator, Element, Container>::bitvector(InputIterator first, InputIterator last)
1400  : mContainer(),
1401  mFreeBitCount(0)
1402  {
1403  assign(first, last);
1404  }
1405 
1406 
1407 
1409  // global operators
1411 
1412  template <typename Allocator, typename Element, typename Container>
1413  inline bool operator==(const bitvector<Allocator, Element, Container>& a,
1414  const bitvector<Allocator, Element, Container>& b)
1415  {
1416  // To do: Replace this with a smart compare implementation. This is much slower than it needs to be.
1417  return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin()));
1418  }
1419 
1420 
1421  template <typename Allocator, typename Element, typename Container>
1422  inline bool operator!=(const bitvector<Allocator, Element, Container>& a,
1423  const bitvector<Allocator, Element, Container>& b)
1424  {
1425  return !operator==(a, b);
1426  }
1427 
1428 
1429  template <typename Allocator, typename Element, typename Container>
1430  inline bool operator<(const bitvector<Allocator, Element, Container>& a,
1431  const bitvector<Allocator, Element, Container>& b)
1432  {
1433  // To do: Replace this with a smart compare implementation. This is much slower than it needs to be.
1434  return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
1435  }
1436 
1437 
1438  template <typename Allocator, typename Element, typename Container>
1439  inline bool operator>(const bitvector<Allocator, Element, Container>& a,
1440  const bitvector<Allocator, Element, Container>& b)
1441  {
1442  return b < a;
1443  }
1444 
1445 
1446  template <typename Allocator, typename Element, typename Container>
1447  inline bool operator<=(const bitvector<Allocator, Element, Container>& a,
1448  const bitvector<Allocator, Element, Container>& b)
1449  {
1450  return !(b < a);
1451  }
1452 
1453 
1454  template <typename Allocator, typename Element, typename Container>
1455  inline bool operator>=(const bitvector<Allocator, Element, Container>& a,
1456  const bitvector<Allocator, Element, Container>& b)
1457  {
1458  return !(a < b);
1459  }
1460 
1461  template <typename Allocator, typename Element, typename Container>
1462  inline void swap(bitvector<Allocator, Element, Container>& a,
1463  bitvector<Allocator, Element, Container>& b)
1464  {
1465  a.swap(b);
1466  }
1467 
1468 
1469 } // namespace eastl
1470 
1471 
1472 EA_RESTORE_VC_WARNING();
1473 
1474 #endif // Header include guard
Definition: allocator.h:52
Definition: bitvector.h:88
Definition: bitvector.h:151
Definition: bitvector.h:63
Definition: bitvector.h:203
static const size_type kMaxSize
'npos' means non-valid position or simply non-position.
Definition: bitvector.h:226
Definition: iterator.h:224
Definition: set.h:85
Definition: vector.h:178
EA Standard Template Library.
Definition: algorithm.h:288
EASTL_BITSET_WORD_TYPE_DEFAULT BitvectorWordType
Definition: bitvector.h:54
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:191
EA_CPP14_CONSTEXPR bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2)
Definition: algorithm.h:1856
@ isf_valid
This is called none and not called invalid because it is not strictly the opposite of invalid.
Definition: iterator.h:56
@ isf_can_dereference
The iterator is valid and points to the same element it did when created. For example,...
Definition: iterator.h:58
@ isf_current
The iterator is valid, which means it is in the range of [begin, end].
Definition: iterator.h:57
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
Definition: algorithm.h:1996
Definition: iterator.h:86