Vault  4.1
vstringiterator.h
Go to the documentation of this file.
00001 /*
00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved.
00003 This file is part of the Code Vault version 4.1
00004 http://www.bombaydigital.com/
00005 License: MIT. See LICENSE.md in the Vault top level directory.
00006 */
00007 
00008 #ifndef vstringiterator_h
00009 #define vstringiterator_h
00010 
00013 #include "vtypes.h"
00014 
00015 #include "vcodepoint.h"
00016 
00017 class VString;
00018 
00019 // External linkage so that this header isn't dependent upon vexception.h.
00020 extern void VStringIteratorThrowOutOfBoundsBegin();
00021 extern void VStringIteratorThrowOutOfBoundsEnd();
00022 
00053 template<typename vstring_ref> // vstring_ref may be 'const VString&' or 'VString&'
00054 class VStringIterator {
00055 
00056     public:
00057         VStringIterator(const VStringIterator& iter)
00058             : mSource(iter.mSource)
00059             , mIsForwardIterator(iter.mIsForwardIterator)
00060             , mCurrentCodePointOffset(iter.mCurrentCodePointOffset)
00061             , mSourceLength(iter.mSourceLength)
00062             {
00063         }
00064 
00065         VStringIterator(vstring_ref source, bool isForwardIterator, bool goToEnd=false)
00066             : mSource(source)
00067             , mIsForwardIterator(isForwardIterator)
00068             , mCurrentCodePointOffset(0)
00069             , mSourceLength(source.length())
00070             {
00071             // If going to end on forward iterator, or not going to end on reverse iterator, then seek to end of our data.
00072             if (goToEnd == isForwardIterator) {
00073                 this->_seekToEnd();
00074             }
00075         }
00076 
00077         ~VStringIterator() {}
00078 
00079         VStringIterator& operator=(const VStringIterator& iter) {
00080             if (this != &iter) {
00081                 mSource = iter.mSource;
00082                 mIsForwardIterator = iter.mIsForwardIterator;
00083                 mCurrentCodePointOffset = iter.mCurrentCodePointOffset;
00084                 mSourceLength = iter.mSourceLength;
00085             }
00086             
00087             return *this;
00088         }
00089         
00090         VCodePoint operator*() const {
00091             if (mIsForwardIterator) {
00092                 return VCodePoint(mSource.getDataBufferConst(), mCurrentCodePointOffset);
00093             } else {
00094                 int previousCodePointOffset = VCodePoint::getPreviousUTF8CodePointOffset(mSource.getDataBufferConst(), mCurrentCodePointOffset);
00095                 return VCodePoint(mSource.getDataBufferConst(), previousCodePointOffset);
00096             }
00097         }
00098 
00099         VStringIterator operator+(int n) const {
00100             VStringIterator i(*this);
00101             i += n;
00102             return i;
00103         }
00104         
00105         VStringIterator operator-(int n) const {
00106             VStringIterator i(*this);
00107             i -= n;
00108             return i;
00109         }
00110         
00111         VStringIterator& operator+=(int n) {
00112             this->_increment(n);
00113             return *this;
00114         }
00115 
00116         VStringIterator& operator-=(int n) {
00117             this->_decrement(n);
00118             return *this;
00119         }
00120 
00121         VStringIterator& operator++() {
00122             this->_increment(1);
00123             return *this;
00124         }
00125 
00126         VStringIterator& operator--() {
00127             this->_decrement(1);
00128             return *this;
00129         }
00130         
00131         int getCurrentOffset() const {
00132             return mCurrentCodePointOffset;
00133         }
00134         
00135         friend inline bool operator==(const VStringIterator<vstring_ref>& i1, const VStringIterator<vstring_ref>& i2) {
00136             return (i1.mSource == i2.mSource) && (i1.mCurrentCodePointOffset == i2.mCurrentCodePointOffset);
00137         }
00138 
00139         friend inline bool operator!=(const VStringIterator<vstring_ref>& i1, const VStringIterator<vstring_ref>& i2) {
00140             return !operator==(i1, i2);
00141         }
00142     
00143     private:
00144     
00145         void _seekToEnd() {
00146             mCurrentCodePointOffset = mSourceLength;
00147         }
00148 
00149         void _increment(int n) {
00150             if (mIsForwardIterator) {
00151                 this->_moveOffsetForwardInBuffer(n);
00152             } else {
00153                 this->_moveOffsetBackwardInBuffer(n);
00154             }
00155         }
00156 
00157         void _decrement(int n) {
00158             if (mIsForwardIterator) {
00159                 this->_moveOffsetBackwardInBuffer(n);
00160             } else {
00161                 this->_moveOffsetForwardInBuffer(n);
00162             }
00163         }
00164     
00165         void _moveOffsetForwardInBuffer(int n) {
00166             // If we are at offset -1 (typical for "end" of reverse iterator), there is no valid buffer to examine at [-1],
00167             // so we just move forward to the first byte, at [0]. After that, normal examine-code-point-and-see-how-big-it-is
00168             // incrementing works.
00169             if ((mCurrentCodePointOffset == -1) && (n > 0)) {
00170                 mCurrentCodePointOffset = 0;
00171                 --n;
00172             }
00173 
00174             for (int i = 0; i < n; ++i) {
00175                 if (mCurrentCodePointOffset == mSourceLength) {
00176                     VStringIteratorThrowOutOfBoundsEnd();
00177                 }
00178 
00179                 VCodePoint cp(mSource.getDataBufferConst(), mCurrentCodePointOffset);
00180                 mCurrentCodePointOffset += cp.getUTF8Length();
00181             }
00182         }
00183         
00184         void _moveOffsetBackwardInBuffer(int n) {
00185             // If we are at [0], we just move backwards to [-1], and we never move beyond that. (Iterating off the end of
00186             // a container is undefined behavior. At least)
00187             const Vu8* bufferPtr = mSource.getDataBufferConst() + mCurrentCodePointOffset;
00188             for (int i = 0; i < n; ++i) {
00189             
00190                 do {
00191                     if (mCurrentCodePointOffset == 0) {
00192                         VStringIteratorThrowOutOfBoundsBegin();
00193                     }
00194 
00195                     --bufferPtr;
00196                     --mCurrentCodePointOffset;
00197                 } while (VCodePoint::isUTF8ContinuationByte(*bufferPtr)); 
00198 
00199             }
00200         }
00201     
00202         vstring_ref mSource;                    
00203         bool        mIsForwardIterator;         
00204         int         mCurrentCodePointOffset;    
00205         int         mSourceLength;              
00206 };
00207 
00208 #endif /* vstringiterator_h */

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.