michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsStringIterator_h___ michael@0: #define nsStringIterator_h___ michael@0: michael@0: #include "nsCharTraits.h" michael@0: #include "nsAlgorithm.h" michael@0: #include "nsDebug.h" michael@0: michael@0: /** michael@0: * @see nsTAString michael@0: */ michael@0: michael@0: template michael@0: class nsReadingIterator michael@0: { michael@0: public: michael@0: typedef nsReadingIterator self_type; michael@0: typedef ptrdiff_t difference_type; michael@0: typedef CharT value_type; michael@0: typedef const CharT* pointer; michael@0: typedef const CharT& reference; michael@0: michael@0: private: michael@0: friend class nsAString; michael@0: friend class nsACString; michael@0: michael@0: // unfortunately, the API for nsReadingIterator requires that the michael@0: // iterator know its start and end positions. this was needed when michael@0: // we supported multi-fragment strings, but now it is really just michael@0: // extra baggage. we should remove mStart and mEnd at some point. michael@0: michael@0: const CharT* mStart; michael@0: const CharT* mEnd; michael@0: const CharT* mPosition; michael@0: michael@0: public: michael@0: nsReadingIterator() { } michael@0: // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK michael@0: // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK michael@0: michael@0: inline void normalize_forward() {} michael@0: inline void normalize_backward() {} michael@0: michael@0: pointer michael@0: start() const michael@0: { michael@0: return mStart; michael@0: } michael@0: michael@0: pointer michael@0: end() const michael@0: { michael@0: return mEnd; michael@0: } michael@0: michael@0: pointer michael@0: get() const michael@0: { michael@0: return mPosition; michael@0: } michael@0: michael@0: CharT michael@0: operator*() const michael@0: { michael@0: return *get(); michael@0: } michael@0: michael@0: #if 0 michael@0: // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) michael@0: // don't like this when |CharT| is a type without members. michael@0: pointer michael@0: operator->() const michael@0: { michael@0: return get(); michael@0: } michael@0: #endif michael@0: michael@0: self_type& michael@0: operator++() michael@0: { michael@0: ++mPosition; michael@0: return *this; michael@0: } michael@0: michael@0: self_type michael@0: operator++( int ) michael@0: { michael@0: self_type result(*this); michael@0: ++mPosition; michael@0: return result; michael@0: } michael@0: michael@0: self_type& michael@0: operator--() michael@0: { michael@0: --mPosition; michael@0: return *this; michael@0: } michael@0: michael@0: self_type michael@0: operator--( int ) michael@0: { michael@0: self_type result(*this); michael@0: --mPosition; michael@0: return result; michael@0: } michael@0: michael@0: difference_type michael@0: size_forward() const michael@0: { michael@0: return mEnd - mPosition; michael@0: } michael@0: michael@0: difference_type michael@0: size_backward() const michael@0: { michael@0: return mPosition - mStart; michael@0: } michael@0: michael@0: self_type& michael@0: advance( difference_type n ) michael@0: { michael@0: if (n > 0) michael@0: { michael@0: difference_type step = XPCOM_MIN(n, size_forward()); michael@0: michael@0: NS_ASSERTION(step>0, "can't advance a reading iterator beyond the end of a string"); michael@0: michael@0: mPosition += step; michael@0: } michael@0: else if (n < 0) michael@0: { michael@0: difference_type step = XPCOM_MAX(n, -size_backward()); michael@0: michael@0: NS_ASSERTION(step<0, "can't advance (backward) a reading iterator beyond the end of a string"); michael@0: michael@0: mPosition += step; michael@0: } michael@0: return *this; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * @see nsTAString michael@0: */ michael@0: michael@0: template michael@0: class nsWritingIterator michael@0: { michael@0: public: michael@0: typedef nsWritingIterator self_type; michael@0: typedef ptrdiff_t difference_type; michael@0: typedef CharT value_type; michael@0: typedef CharT* pointer; michael@0: typedef CharT& reference; michael@0: michael@0: private: michael@0: friend class nsAString; michael@0: friend class nsACString; michael@0: michael@0: // unfortunately, the API for nsWritingIterator requires that the michael@0: // iterator know its start and end positions. this was needed when michael@0: // we supported multi-fragment strings, but now it is really just michael@0: // extra baggage. we should remove mStart and mEnd at some point. michael@0: michael@0: CharT* mStart; michael@0: CharT* mEnd; michael@0: CharT* mPosition; michael@0: michael@0: public: michael@0: nsWritingIterator() { } michael@0: // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK michael@0: // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK michael@0: michael@0: inline void normalize_forward() {} michael@0: inline void normalize_backward() {} michael@0: michael@0: pointer michael@0: start() const michael@0: { michael@0: return mStart; michael@0: } michael@0: michael@0: pointer michael@0: end() const michael@0: { michael@0: return mEnd; michael@0: } michael@0: michael@0: pointer michael@0: get() const michael@0: { michael@0: return mPosition; michael@0: } michael@0: michael@0: reference michael@0: operator*() const michael@0: { michael@0: return *get(); michael@0: } michael@0: michael@0: #if 0 michael@0: // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) michael@0: // don't like this when |CharT| is a type without members. michael@0: pointer michael@0: operator->() const michael@0: { michael@0: return get(); michael@0: } michael@0: #endif michael@0: michael@0: self_type& michael@0: operator++() michael@0: { michael@0: ++mPosition; michael@0: return *this; michael@0: } michael@0: michael@0: self_type michael@0: operator++( int ) michael@0: { michael@0: self_type result(*this); michael@0: ++mPosition; michael@0: return result; michael@0: } michael@0: michael@0: self_type& michael@0: operator--() michael@0: { michael@0: --mPosition; michael@0: return *this; michael@0: } michael@0: michael@0: self_type michael@0: operator--( int ) michael@0: { michael@0: self_type result(*this); michael@0: --mPosition; michael@0: return result; michael@0: } michael@0: michael@0: difference_type michael@0: size_forward() const michael@0: { michael@0: return mEnd - mPosition; michael@0: } michael@0: michael@0: difference_type michael@0: size_backward() const michael@0: { michael@0: return mPosition - mStart; michael@0: } michael@0: michael@0: self_type& michael@0: advance( difference_type n ) michael@0: { michael@0: if (n > 0) michael@0: { michael@0: difference_type step = XPCOM_MIN(n, size_forward()); michael@0: michael@0: NS_ASSERTION(step>0, "can't advance a writing iterator beyond the end of a string"); michael@0: michael@0: mPosition += step; michael@0: } michael@0: else if (n < 0) michael@0: { michael@0: difference_type step = XPCOM_MAX(n, -size_backward()); michael@0: michael@0: NS_ASSERTION(step<0, "can't advance (backward) a writing iterator beyond the end of a string"); michael@0: michael@0: mPosition += step; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: void michael@0: write( const value_type* s, uint32_t n ) michael@0: { michael@0: NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); michael@0: michael@0: nsCharTraits::move(mPosition, s, n); michael@0: advance( difference_type(n) ); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) michael@0: { michael@0: return lhs.get() == rhs.get(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) michael@0: { michael@0: return lhs.get() != rhs.get(); michael@0: } michael@0: michael@0: michael@0: // michael@0: // |nsWritingIterator|s michael@0: // michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) michael@0: { michael@0: return lhs.get() == rhs.get(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: bool michael@0: operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) michael@0: { michael@0: return lhs.get() != rhs.get(); michael@0: } michael@0: michael@0: #endif /* !defined(nsStringIterator_h___) */