///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Implements a bit vector, which is essentially a vector of bool but which // uses bits instead of bytes. It is thus similar to the original std::vector. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Note: This code is not yet complete: it isn't tested and doesn't yet // support containers other than vector. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_BITVECTOR_H #define EASTL_BITVECTOR_H #include #include #include #include EA_DISABLE_VC_WARNING(4480); // nonstandard extension used: specifying underlying type for enum #if defined(EA_PRAGMA_ONCE_SUPPORTED) #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. #endif namespace eastl { /// EASTL_BITVECTOR_DEFAULT_NAME /// /// Defines a default container name in the absence of a user-provided name. /// #ifndef EASTL_BITVECTOR_DEFAULT_NAME #define EASTL_BITVECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " bitvector" // Unless the user overrides something, this is "EASTL bitvector". #endif /// EASTL_BITVECTOR_DEFAULT_ALLOCATOR /// #ifndef EASTL_BITVECTOR_DEFAULT_ALLOCATOR #define EASTL_BITVECTOR_DEFAULT_ALLOCATOR allocator_type(EASTL_BITVECTOR_DEFAULT_NAME) #endif /// BitvectorWordType /// Defines the integral data type used by bitvector. typedef EASTL_BITSET_WORD_TYPE_DEFAULT BitvectorWordType; template class bitvector_const_iterator; template class bitvector_reference { public: typedef eastl_size_t size_type; bitvector_reference(Element* ptr, eastl_size_t i); bitvector_reference& operator=(bool value); bitvector_reference& operator=(const bitvector_reference& rhs); operator bool() const // Defined here because some compilers fail otherwise. { return (*mpBitWord & (Element(1) << mnBitIndex)) != 0; } protected: friend class bitvector_const_iterator; Element* mpBitWord; size_type mnBitIndex; bitvector_reference() {} void CopyFrom(const bitvector_reference& rhs); }; template class bitvector_const_iterator { public: typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; typedef bitvector_const_iterator this_type; typedef bool value_type; typedef bitvector_reference reference_type; typedef ptrdiff_t difference_type; typedef Element element_type; typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit. typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit. typedef eastl_size_t size_type; protected: reference_type mReference; enum { kBitCount = (8 * sizeof(Element)) }; public: bool operator*() const; bool operator[](difference_type n) const; bitvector_const_iterator(); bitvector_const_iterator(const element_type* p, eastl_size_t i); bitvector_const_iterator(const reference_type& referenceType); bitvector_const_iterator& operator++(); bitvector_const_iterator operator++(int); bitvector_const_iterator& operator--(); bitvector_const_iterator operator--(int); bitvector_const_iterator& operator+=(difference_type dist); bitvector_const_iterator& operator-=(difference_type dist); bitvector_const_iterator operator+ (difference_type dist) const; bitvector_const_iterator operator- (difference_type dist) const; difference_type operator-(const this_type& rhs) const; bitvector_const_iterator& operator= (const this_type& rhs); bool operator==(const this_type& rhs) const; bool operator!=(const this_type& rhs) const; bool operator< (const this_type& rhs) const; bool operator<=(const this_type& rhs) const; bool operator> (const this_type& rhs) const; bool operator>=(const this_type& rhs) const; int validate(const element_type* pStart, const element_type* pEnd, eastl_size_t nExtraBits) const; protected: template friend class bitvector; reference_type& get_reference_type() { return mReference; } }; template class bitvector_iterator : public bitvector_const_iterator { public: typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; typedef bitvector_iterator this_type; typedef bitvector_const_iterator base_type; typedef bool value_type; typedef bitvector_reference reference_type; typedef ptrdiff_t difference_type; typedef Element element_type; typedef element_type* pointer; // This is wrong. It needs to be someting that acts as a pointer to a bit. typedef element_type& reference; // This is not right. It needs to be someting that acts as a pointer to a bit. public: reference_type operator*() const; reference_type operator[](difference_type n) const; bitvector_iterator(); bitvector_iterator(element_type* p, eastl_size_t i); bitvector_iterator(reference_type& referenceType); bitvector_iterator& operator++() { base_type::operator++(); return *this; } bitvector_iterator& operator--() { base_type::operator--(); return *this; } bitvector_iterator operator++(int); bitvector_iterator operator--(int); bitvector_iterator& operator+=(difference_type dist) { base_type::operator+=(dist); return *this; } bitvector_iterator& operator-=(difference_type dist) { base_type::operator-=(dist); return *this; } bitvector_iterator operator+ (difference_type dist) const; bitvector_iterator operator- (difference_type dist) const; // We need this here because we are overloading operator-, so for some reason the // other overload of the function can't be found unless it's explicitly specified. difference_type operator-(const base_type& rhs) const { return base_type::operator-(rhs); } }; /// bitvector /// /// Implements an array of bits treated as boolean values. /// bitvector is similar to vector but uses bits instead of bytes and /// allows the user to use other containers such as deque instead of vector. /// bitvector is different from bitset in that bitset is less flexible but /// uses less memory and has higher performance. /// /// To consider: Rename the Element template parameter to WordType, for /// consistency with bitset. /// template > class bitvector { public: typedef bitvector this_type; typedef bool value_type; typedef bitvector_reference reference; typedef bool const_reference; typedef bitvector_iterator iterator; typedef bitvector_const_iterator const_iterator; typedef eastl::reverse_iterator reverse_iterator; typedef eastl::reverse_iterator const_reverse_iterator; typedef Allocator allocator_type; typedef Element element_type; typedef Container container_type; typedef eastl_size_t size_type; typedef ptrdiff_t difference_type; #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. enum : size_type { // Use Microsoft enum language extension, allowing for smaller debug symbols than using a static const. Users have been affected by this. npos = container_type::npos, kMaxSize = container_type::kMaxSize }; #else static const size_type npos = container_type::npos; /// 'npos' means non-valid position or simply non-position. static const size_type kMaxSize = container_type::kMaxSize; /// -1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less than -1, as it helps us deal with potential integer wraparound issues. #endif enum { kBitCount = 8 * sizeof(Element) }; protected: container_type mContainer; size_type mFreeBitCount; // Unused bits in the last word of mContainer. public: bitvector(); explicit bitvector(const allocator_type& allocator); explicit bitvector(size_type n, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR); bitvector(size_type n, value_type value, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR); bitvector(const bitvector& copy); template bitvector(InputIterator first, InputIterator last); bitvector& operator=(const bitvector& x); void swap(this_type& x); template void assign(InputIterator first, InputIterator last); iterator begin() EA_NOEXCEPT; const_iterator begin() const EA_NOEXCEPT; const_iterator cbegin() const EA_NOEXCEPT; iterator end() EA_NOEXCEPT; const_iterator end() const EA_NOEXCEPT; const_iterator cend() const EA_NOEXCEPT; reverse_iterator rbegin() EA_NOEXCEPT; const_reverse_iterator rbegin() const EA_NOEXCEPT; const_reverse_iterator crbegin() const EA_NOEXCEPT; reverse_iterator rend() EA_NOEXCEPT; const_reverse_iterator rend() const EA_NOEXCEPT; const_reverse_iterator crend() const EA_NOEXCEPT; bool empty() const EA_NOEXCEPT; size_type size() const EA_NOEXCEPT; size_type capacity() const EA_NOEXCEPT; void resize(size_type n, value_type value); void resize(size_type n); void reserve(size_type n); 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. void push_back(); void push_back(value_type value); void pop_back(); reference front(); const_reference front() const; reference back(); const_reference back() const; 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(). void set(size_type n, bool value); // Resizes the container to accomodate n if necessary. reference at(size_type n); // throws an out_of_range exception if n is invalid. const_reference at(size_type n) const; reference operator[](size_type n); // behavior is undefined if n is invalid. const_reference operator[](size_type n) const; /* Work in progress: template iterator find_first(); // Finds the lowest "on" bit. template iterator find_next(const_iterator it); // Finds the next lowest "on" bit after it. template iterator find_last(); // Finds the index of the last "on" bit, returns size if none are set. template iterator find_prev(const_iterator it); // Finds the index of the last "on" bit before last_find, returns size if none are set. template const_iterator find_first() const; // Finds the lowest "on" bit. template const_iterator find_next(const_iterator it) const; // Finds the next lowest "on" bit after it. template const_iterator find_last() const; // Finds the index of the last "on" bit, returns size if none are set. template 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. */ element_type* data() EA_NOEXCEPT; const element_type* data() const EA_NOEXCEPT; iterator insert(const_iterator position, value_type value); void insert(const_iterator position, size_type n, value_type value); // template Not yet implemented. See below for disabled definition. // void insert(const_iterator position, InputIterator first, InputIterator last); iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); reverse_iterator erase(const_reverse_iterator position); reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last); void clear(); void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs. container_type& get_container(); const container_type& get_container() const; bool validate() const; int validate_iterator(const_iterator i) const; }; /////////////////////////////////////////////////////////////////////// // bitvector_reference /////////////////////////////////////////////////////////////////////// template bitvector_reference::bitvector_reference(Element* p, eastl_size_t i) : mpBitWord(p), mnBitIndex(i) { } template bitvector_reference& bitvector_reference::operator=(bool value) { const Element mask = (Element)(Element(1) << mnBitIndex); if(value) *mpBitWord |= mask; else *mpBitWord &= ~mask; return *this; } template bitvector_reference& bitvector_reference::operator=(const bitvector_reference& rhs) { return (*this = (bool)rhs); } template void bitvector_reference::CopyFrom(const bitvector_reference& rhs) { mpBitWord = rhs.mpBitWord; mnBitIndex = rhs.mnBitIndex; } /////////////////////////////////////////////////////////////////////// // bitvector_const_iterator /////////////////////////////////////////////////////////////////////// template bitvector_const_iterator::bitvector_const_iterator() : mReference(0, 0) { } template bitvector_const_iterator::bitvector_const_iterator(const Element* p, eastl_size_t i) : mReference(const_cast(p), i) // const_cast is safe here because we never let mReference leak and we don't modify it. { } template bitvector_const_iterator::bitvector_const_iterator(const reference_type& reference) : mReference(reference) { } template bitvector_const_iterator& bitvector_const_iterator::operator++() { ++mReference.mnBitIndex; if(mReference.mnBitIndex == kBitCount) { ++mReference.mpBitWord; mReference.mnBitIndex = 0; } return *this; } template bitvector_const_iterator& bitvector_const_iterator::operator--() { if(mReference.mnBitIndex == 0) { --mReference.mpBitWord; mReference.mnBitIndex = kBitCount; } --mReference.mnBitIndex; return *this; } template bitvector_const_iterator bitvector_const_iterator::operator++(int) { bitvector_const_iterator copy(*this); ++*this; return copy; } template bitvector_const_iterator bitvector_const_iterator::operator--(int) { bitvector_const_iterator copy(*this); --*this; return copy; } template bitvector_const_iterator& bitvector_const_iterator::operator+=(difference_type n) { n += mReference.mnBitIndex; if(n >= difference_type(0)) { mReference.mpBitWord += n / kBitCount; mReference.mnBitIndex = (size_type)(n % kBitCount); } else { // backwards is tricky // figure out how many full words backwards we need to move // n = [-1..-32] => 1 // n = [-33..-64] => 2 const size_type backwards = (size_type)(-n + kBitCount - 1); mReference.mpBitWord -= backwards / kBitCount; // -1 => 31; backwards = 32; 31 - (backwards % 32) = 31 // -2 => 30; backwards = 33; 31 - (backwards % 32) = 30 // -3 => 29; backwards = 34 // .. // -32 => 0; backwards = 63; 31 - (backwards % 32) = 0 // -33 => 31; backwards = 64; 31 - (backwards % 32) = 31 mReference.mnBitIndex = (kBitCount - 1) - (backwards % kBitCount); } return *this; } template bitvector_const_iterator& bitvector_const_iterator::operator-=(difference_type n) { return (*this += -n); } template bitvector_const_iterator bitvector_const_iterator::operator+(difference_type n) const { bitvector_const_iterator copy(*this); copy += n; return copy; } template bitvector_const_iterator bitvector_const_iterator::operator-(difference_type n) const { bitvector_const_iterator copy(*this); copy -= n; return copy; } template typename bitvector_const_iterator::difference_type bitvector_const_iterator::operator-(const this_type& rhs) const { return ((mReference.mpBitWord - rhs.mReference.mpBitWord) * kBitCount) + mReference.mnBitIndex - rhs.mReference.mnBitIndex; } template bool bitvector_const_iterator::operator==(const this_type& rhs) const { return (mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex == rhs.mReference.mnBitIndex); } template bool bitvector_const_iterator::operator!=(const this_type& rhs) const { return !(*this == rhs); } template bool bitvector_const_iterator::operator<(const this_type& rhs) const { return (mReference.mpBitWord < rhs.mReference.mpBitWord) || ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex < rhs.mReference.mnBitIndex)); } template bool bitvector_const_iterator::operator<=(const this_type& rhs) const { return (mReference.mpBitWord < rhs.mReference.mpBitWord) || ((mReference.mpBitWord == rhs.mReference.mpBitWord) && (mReference.mnBitIndex <= rhs.mReference.mnBitIndex)); } template bool bitvector_const_iterator::operator>(const this_type& rhs) const { return !(*this <= rhs); } template bool bitvector_const_iterator::operator>=(const this_type& rhs) const { return !(*this < rhs); } template bool bitvector_const_iterator::operator*() const { return mReference; } template bool bitvector_const_iterator::operator[](difference_type n) const { return *(*this + n); } template bitvector_const_iterator& bitvector_const_iterator::operator= (const this_type& rhs) { mReference.CopyFrom(rhs.mReference); return *this; } template int bitvector_const_iterator::validate(const Element* pStart, const Element* pEnd, eastl_size_t nExtraBits) const { const Element* const pCurrent = mReference.mpBitWord; if(pCurrent >= pStart) { if(nExtraBits == 0) { if(pCurrent == pEnd && mReference) return eastl::isf_valid | eastl::isf_current; else if(pCurrent < pEnd) return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; } else if(pCurrent == (pEnd - 1)) { const size_type bit = mReference.mnBitIndex; const size_type lastbit = kBitCount - nExtraBits; if(bit == lastbit) return eastl::isf_valid | eastl::isf_current; else if(bit < lastbit) return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; } else if(pCurrent < pEnd) { return eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference; } } return eastl::isf_none; } /////////////////////////////////////////////////////////////////////// // bitvector_iterator /////////////////////////////////////////////////////////////////////// template bitvector_iterator::bitvector_iterator() : base_type() { } template bitvector_iterator::bitvector_iterator(Element* p, eastl_size_t i) : base_type(p, i) { } template bitvector_iterator::bitvector_iterator(reference_type& reference) : base_type(reference) { } template typename bitvector_iterator::reference_type bitvector_iterator::operator*() const { return base_type::mReference; } template typename bitvector_iterator::reference_type bitvector_iterator::operator[](difference_type n) const { return *(*this + n); } template void MoveBits(bitvector_iterator start, bitvector_iterator end, bitvector_iterator dest) { // Slow implemenation; could optimize by moving a word at a time. if(dest <= start) { while(start != end) { *dest = *start; ++dest; ++start; } } else { // Need to move backwards dest += (end - start); while(start != end) { --dest; --end; *dest = *end; } } } template bitvector_iterator bitvector_iterator::operator++(int) { bitvector_iterator copy(*this); ++*this; return copy; } template bitvector_iterator bitvector_iterator::operator--(int) { bitvector_iterator copy(*this); --*this; return copy; } template bitvector_iterator bitvector_iterator::operator+(difference_type n) const { bitvector_iterator copy(*this); copy += n; return copy; } template bitvector_iterator bitvector_iterator::operator-(difference_type n) const { bitvector_iterator copy(*this); copy -= n; return copy; } /////////////////////////////////////////////////////////////////////// // bitvector /////////////////////////////////////////////////////////////////////// template template void bitvector::assign(InputIterator first, InputIterator last) { // To consider: We can maybe specialize this on bitvector_iterator to do a fast bitwise copy. // We can also specialize for random access iterators to figure out the size & reserve first. clear(); while(first != last) { push_back(*first); ++first; } } template typename bitvector::iterator bitvector::begin() EA_NOEXCEPT { return iterator(mContainer.begin(), 0); } template typename bitvector::const_iterator bitvector::begin() const EA_NOEXCEPT { return const_iterator(mContainer.begin(), 0); } template typename bitvector::const_iterator bitvector::cbegin() const EA_NOEXCEPT { return const_iterator(mContainer.begin(), 0); } template typename bitvector::iterator bitvector::end() EA_NOEXCEPT { return iterator(mContainer.end(), 0) - mFreeBitCount; } template typename bitvector::const_iterator bitvector::end() const EA_NOEXCEPT { return const_iterator(mContainer.end(), 0) - mFreeBitCount; } template typename bitvector::const_iterator bitvector::cend() const EA_NOEXCEPT { return const_iterator(mContainer.end(), 0) - mFreeBitCount; } template bool bitvector::empty() const EA_NOEXCEPT { return mContainer.empty(); } template typename bitvector::size_type bitvector::size() const EA_NOEXCEPT { return (mContainer.size() * kBitCount) - mFreeBitCount; } template typename bitvector::size_type bitvector::capacity() const EA_NOEXCEPT { return mContainer.capacity() * kBitCount; } template void bitvector::set_capacity(size_type n) { if(n == npos) mContainer.set_capacity(npos); else mContainer.set_capacity((n + kBitCount - 1) / kBitCount); } template typename bitvector::reverse_iterator bitvector::rbegin() EA_NOEXCEPT { return reverse_iterator(end()); } template typename bitvector::const_reverse_iterator bitvector::rbegin() const EA_NOEXCEPT { return const_reverse_iterator(end()); } template typename bitvector::const_reverse_iterator bitvector::crbegin() const EA_NOEXCEPT { return const_reverse_iterator(end()); } template typename bitvector::reverse_iterator bitvector::rend() EA_NOEXCEPT { return reverse_iterator(begin()); } template typename bitvector::const_reverse_iterator bitvector::rend() const EA_NOEXCEPT { return const_reverse_iterator(begin()); } template typename bitvector::const_reverse_iterator bitvector::crend() const EA_NOEXCEPT { return const_reverse_iterator(begin()); } template typename bitvector::reference bitvector::front() { EASTL_ASSERT(!empty()); return reference(&mContainer[0], 0); } template typename bitvector::const_reference bitvector::front() const { EASTL_ASSERT(!empty()); // To consider: make a better solution to this than const_cast. return reference(const_cast(&mContainer[0]), 0); } template typename bitvector::reference bitvector::back() { EASTL_ASSERT(!empty()); return *(--end()); } template typename bitvector::const_reference bitvector::back() const { EASTL_ASSERT(!empty()); return *(--end()); } template void bitvector::push_back() { if(!mFreeBitCount) { mContainer.push_back(); mFreeBitCount = kBitCount; } --mFreeBitCount; } template void bitvector::push_back(value_type value) { push_back(); *--end() = value; } template void bitvector::pop_back() { EASTL_ASSERT(!empty()); if(++mFreeBitCount == kBitCount) { mContainer.pop_back(); mFreeBitCount = 0; } } template void bitvector::reserve(size_type n) { const size_type wordCount = (n + kBitCount - 1) / kBitCount; mContainer.reserve(wordCount); } template void bitvector::resize(size_type n) { const size_type wordCount = (n + kBitCount - 1) / kBitCount; const size_type extra = (wordCount * kBitCount) - n; mContainer.resize(wordCount); mFreeBitCount = extra; } template void bitvector::resize(size_type n, value_type value) { const size_type s = size(); if(n < s) resize(n); // Fill up to the end of a word size_type newbits = n - s; while(mFreeBitCount && newbits) { push_back(value); --newbits; } // Fill the rest a word at a time if(newbits) { element_type element(0); if(value) element = ~element; const size_type words = (n + kBitCount - 1) / kBitCount; const size_type extra = words * kBitCount - n; mContainer.resize(words, element); mFreeBitCount = extra; } } template bool bitvector::test(size_type n, bool defaultValue) const { if(n < size()) return *(begin() + (difference_type)n); return defaultValue; } template void bitvector::set(size_type n, bool value) { if(EASTL_UNLIKELY(n >= size())) resize(n + 1); *(begin() + (difference_type)n) = value; } template typename bitvector::reference bitvector::at(size_type n) { // The difference between at and operator[] is that at signals // if the requested position is out of range by throwing an // out_of_range exception. #if EASTL_EXCEPTIONS_ENABLED if(EASTL_UNLIKELY(n >= size())) throw std::out_of_range("bitvector::at -- out of range"); #elif EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(n >= size())) EASTL_FAIL_MSG("bitvector::at -- out of range"); #endif return *(begin() + (difference_type)n); } template typename bitvector::const_reference bitvector::at(size_type n) const { #if EASTL_EXCEPTIONS_ENABLED if(EASTL_UNLIKELY(n >= size())) throw std::out_of_range("bitvector::at -- out of range"); #elif EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(n >= size())) EASTL_FAIL_MSG("bitvector::at -- out of range"); #endif return *(begin() + (difference_type)n); } template typename bitvector::reference bitvector::operator[](size_type n) { return *(begin() + (difference_type)n); } template typename bitvector::const_reference bitvector::operator[](size_type n) const { return *(begin() + (difference_type)n); } /* template template typename bitvector::iterator bitvector::find_first() { return begin(); } template iterator find_next(const_iterator it); template iterator find_last(); template iterator find_prev(const_iterator it); template const_iterator find_first() const; template const_iterator find_next(const_iterator it) const; template const_iterator find_last() const; template const_iterator find_prev(const_iterator it) const; */ template inline typename bitvector::container_type& bitvector::get_container() { return mContainer; } template inline const typename bitvector::container_type& bitvector::get_container() const { return mContainer; } template bool bitvector::validate() const { if(!mContainer.validate()) return false; if((unsigned)mFreeBitCount >= kBitCount) return false; return true; } template int bitvector::validate_iterator(const_iterator i) const { return i.validate(mContainer.begin(), mContainer.end(), mFreeBitCount); } template typename bitvector::element_type* bitvector::data() EA_NOEXCEPT { return mContainer.data(); } template const typename bitvector::element_type* bitvector::data() const EA_NOEXCEPT { return mContainer.data(); } template typename bitvector::iterator bitvector::insert(const_iterator position, value_type value) { iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0) EASTL_FAIL_MSG("bitvector::insert -- invalid iterator"); #endif // Save because we might reallocate const typename iterator::difference_type n = iPosition - begin(); push_back(); iPosition = begin() + n; MoveBits(iPosition, --end(), ++iterator(iPosition)); *iPosition = value; return iPosition; } template void bitvector::insert(const_iterator position, size_type n, value_type value) { iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_valid) == 0) EASTL_FAIL_MSG("bitvector::insert -- invalid iterator"); #endif // Save because we might reallocate. const typename iterator::difference_type p = iPosition - begin(); resize(size() + n); iPosition = begin() + p; iterator insert_end = iPosition + n; MoveBits(iPosition, end() - n, insert_end); // To do: Optimize this to word-at-a-time for large inserts while(iPosition != insert_end) { *iPosition = value; ++iPosition; } } /* The following is a placeholder for a future implementation. It turns out that a correct implementation of insert(pos, first, last) is a non-trivial exercise that would take a few hours to implement and test. The reasons why involve primarily the problem of handling the case where insertion source comes from within the container itself, and the case that first and last (note they are templated) might not refer to iterators might refer to a value/count pair. The C++ Standard requires you to handle this case and I (Paul Pedriana) believe that it applies even for a bitvector, given that bool is an integral type. So you have to set up a compile-time type traits function chooser. See vector, for example. template template void bitvector::insert(const_iterator position, InputIterator first, InputIterator last) { iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. // This implementation is probably broken due to not handling insertion into self. // To do: Make a more efficient version of this. difference_type distance = (iPosition - begin()); while(first != last) { insert(iPosition, *first); iPosition = begin() + ++distance; ++first; } } */ template typename bitvector::iterator bitvector::erase(const_iterator position) { iterator iPosition(position.get_reference_type()); // This is just a non-const version of position. #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iPosition) & eastl::isf_can_dereference) == 0) EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); #endif MoveBits(++iterator(iPosition), end(), iPosition); resize(size() - 1); // Verify that no reallocation occurred. EASTL_ASSERT(validate_iterator(iPosition) & eastl::isf_valid); return iPosition; } template typename bitvector::iterator bitvector::erase(const_iterator first, const_iterator last) { iterator iFirst(first.get_reference_type()); // This is just a non-const version of first. iterator iLast(last.get_reference_type()); // This is just a non-const version of last. #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iLast) & eastl::isf_valid) == 0) EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); #endif if(!(iFirst == iLast)) { #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_can_dereference) == 0) EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); #endif const size_type eraseCount = (size_type)(iLast - iFirst); MoveBits(iLast, end(), iFirst); resize(size() - eraseCount); // Verify that no reallocation occurred. #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(validate_iterator(iFirst) & eastl::isf_valid) == 0) EASTL_FAIL_MSG("bitvector::erase -- invalid iterator"); #endif } return iFirst; } template typename bitvector::reverse_iterator bitvector::erase(const_reverse_iterator position) { return reverse_iterator(erase((++position).base())); } template typename bitvector::reverse_iterator bitvector::erase(const_reverse_iterator first, const_reverse_iterator last) { // Version which erases in order from first to last. // difference_type i(first.base() - last.base()); // while(i--) // first = erase(first); // return first; // Version which erases in order from last to first, but is slightly more efficient: return reverse_iterator(erase(last.base(), first.base())); } template void bitvector::swap(this_type& rhs) { mContainer.swap(rhs.mContainer); eastl::swap(mFreeBitCount, rhs.mFreeBitCount); } template void bitvector::reset_lose_memory() { mContainer.reset_lose_memory(); // intentional memory leak. mFreeBitCount = 0; } template void bitvector::clear() { mContainer.clear(); mFreeBitCount = 0; } template bitvector& bitvector::operator=(const bitvector& rhs) { // The following is OK if (&rhs == this) mContainer = rhs.mContainer; mFreeBitCount = rhs.mFreeBitCount; return *this; } template bitvector::bitvector() : mContainer(), mFreeBitCount(0) { } template bitvector::bitvector(const allocator_type& allocator) : mContainer(allocator), mFreeBitCount(0) { } template bitvector::bitvector(size_type n, const allocator_type& allocator) : mContainer((n + kBitCount - 1) / kBitCount, allocator) { mFreeBitCount = kBitCount - (n % kBitCount); if(mFreeBitCount == kBitCount) mFreeBitCount = 0; } template bitvector::bitvector(size_type n, value_type value, const allocator_type& allocator) : mContainer((n + kBitCount - 1) / kBitCount, value ? ~element_type(0) : element_type(0), allocator) { mFreeBitCount = kBitCount - (n % kBitCount); if(mFreeBitCount == kBitCount) mFreeBitCount = 0; } template bitvector::bitvector(const bitvector& copy) : mContainer(copy.mContainer), mFreeBitCount(copy.mFreeBitCount) { } template template bitvector::bitvector(InputIterator first, InputIterator last) : mContainer(), mFreeBitCount(0) { assign(first, last); } /////////////////////////////////////////////////////////////////////// // global operators /////////////////////////////////////////////////////////////////////// template inline bool operator==(const bitvector& a, const bitvector& b) { // To do: Replace this with a smart compare implementation. This is much slower than it needs to be. return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin())); } template inline bool operator!=(const bitvector& a, const bitvector& b) { return !operator==(a, b); } template inline bool operator<(const bitvector& a, const bitvector& b) { // To do: Replace this with a smart compare implementation. This is much slower than it needs to be. return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); } template inline bool operator>(const bitvector& a, const bitvector& b) { return b < a; } template inline bool operator<=(const bitvector& a, const bitvector& b) { return !(b < a); } template inline bool operator>=(const bitvector& a, const bitvector& b) { return !(a < b); } template inline void swap(bitvector& a, bitvector& b) { a.swap(b); } } // namespace eastl EA_RESTORE_VC_WARNING(); #endif // Header include guard