Back to index

lightning-sunbird  0.9+nobinonly
nsScannerString.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla.
00017  *
00018  * The Initial Developer of the Original Code is IBM Corporation.
00019  * Portions created by IBM Corporation are Copyright (C) 2003
00020  * IBM Corporation. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifndef nsScannerString_h___
00040 #define nsScannerString_h___
00041 
00042 #include "nsString.h"
00043 #include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator
00044 #include "prclist.h"
00045 
00046 
00062 class nsScannerIterator;
00063 class nsScannerSubstring;
00064 class nsScannerString;
00065 
00066 
00086 class nsScannerBufferList
00087   {
00088     public:
00089 
00095       class Buffer : public PRCList
00096         {
00097           public:
00098 
00099             void IncrementUsageCount() { ++mUsageCount; }
00100             void DecrementUsageCount() { --mUsageCount; }
00101 
00102             PRBool IsInUse() const { return mUsageCount != 0; }
00103 
00104             const PRUnichar* DataStart() const { return (const PRUnichar*) (this+1); }
00105                   PRUnichar* DataStart()       { return (      PRUnichar*) (this+1); }
00106 
00107             const PRUnichar* DataEnd() const { return mDataEnd; }
00108                   PRUnichar* DataEnd()       { return mDataEnd; }
00109 
00110             const Buffer* Next() const { return NS_STATIC_CAST(const Buffer*, next); }
00111                   Buffer* Next()       { return NS_STATIC_CAST(      Buffer*, next); }
00112 
00113             const Buffer* Prev() const { return NS_STATIC_CAST(const Buffer*, prev); }
00114                   Buffer* Prev()       { return NS_STATIC_CAST(      Buffer*, prev); }
00115 
00116             PRUint32 DataLength() const { return mDataEnd - DataStart(); }
00117             void SetDataLength(PRUint32 len) { mDataEnd = DataStart() + len; }
00118 
00119           private:
00120 
00121             friend class nsScannerBufferList;
00122 
00123             PRInt32    mUsageCount;
00124             PRUnichar* mDataEnd;
00125         };
00126 
00132       class Position
00133         {
00134           public:
00135 
00136             Position() {}
00137             
00138             Position( Buffer* buffer, PRUnichar* position )
00139               : mBuffer(buffer)
00140               , mPosition(position)
00141               {}
00142             
00143             inline
00144             Position( const nsScannerIterator& aIter );
00145 
00146             inline
00147             Position& operator=( const nsScannerIterator& aIter );
00148 
00149             static size_t Distance( const Position& p1, const Position& p2 );
00150 
00151             Buffer*    mBuffer;
00152             PRUnichar* mPosition;
00153         };
00154 
00155       static Buffer* AllocBufferFromString( const nsAString& );
00156       static Buffer* AllocBuffer( PRUint32 capacity ); // capacity = number of chars
00157 
00158       nsScannerBufferList( Buffer* buf )
00159         : mRefCnt(0)
00160         {
00161           PR_INIT_CLIST(&mBuffers);
00162           PR_APPEND_LINK(buf, &mBuffers);
00163         }
00164 
00165       void  AddRef()  { ++mRefCnt; }
00166       void  Release() { if (--mRefCnt == 0) delete this; }
00167 
00168       void  Append( Buffer* buf ) { PR_APPEND_LINK(buf, &mBuffers); } 
00169       void  InsertAfter( Buffer* buf, Buffer* prev ) { PR_INSERT_AFTER(buf, prev); }
00170       void  SplitBuffer( const Position& );
00171       void  DiscardUnreferencedPrefix( Buffer* );
00172 
00173             Buffer* Head()       { return NS_STATIC_CAST(      Buffer*, PR_LIST_HEAD(&mBuffers)); }
00174       const Buffer* Head() const { return NS_STATIC_CAST(const Buffer*, PR_LIST_HEAD(&mBuffers)); }
00175 
00176             Buffer* Tail()       { return NS_STATIC_CAST(      Buffer*, PR_LIST_TAIL(&mBuffers)); }
00177       const Buffer* Tail() const { return NS_STATIC_CAST(const Buffer*, PR_LIST_TAIL(&mBuffers)); }
00178 
00179     private:
00180 
00181       friend class nsScannerSubstring;
00182 
00183       ~nsScannerBufferList() { ReleaseAll(); }
00184       void ReleaseAll();
00185 
00186       PRInt32 mRefCnt;
00187       PRCList mBuffers;
00188   };
00189 
00190 
00194 struct nsScannerFragment
00195   {
00196     typedef nsScannerBufferList::Buffer Buffer;
00197 
00198     const Buffer*    mBuffer;
00199     const PRUnichar* mFragmentStart;
00200     const PRUnichar* mFragmentEnd;
00201   };
00202 
00203 
00211 class nsScannerSubstring
00212   {
00213     public:
00214       typedef nsScannerBufferList::Buffer      Buffer;
00215       typedef nsScannerBufferList::Position    Position;
00216       typedef PRUint32                         size_type;
00217 
00218       nsScannerSubstring();
00219       nsScannerSubstring( const nsAString& s );
00220 
00221       ~nsScannerSubstring();
00222 
00223       nsScannerIterator& BeginReading( nsScannerIterator& iter ) const;
00224       nsScannerIterator& EndReading( nsScannerIterator& iter ) const;
00225 
00226       size_type Length() const { return mLength; }
00227 
00228       PRInt32 CountChar( PRUnichar ) const;
00229 
00230       void Rebind( const nsScannerSubstring&, const nsScannerIterator&, const nsScannerIterator& );
00231       void Rebind( const nsAString& );
00232 
00233       const nsSubstring& AsString() const;
00234 
00235       PRBool GetNextFragment( nsScannerFragment& ) const;
00236       PRBool GetPrevFragment( nsScannerFragment& ) const;
00237 
00238       static inline Buffer* AllocBufferFromString( const nsAString& aStr ) { return nsScannerBufferList::AllocBufferFromString(aStr); }
00239       static inline Buffer* AllocBuffer( size_type aCapacity )             { return nsScannerBufferList::AllocBuffer(aCapacity); }
00240 
00241     protected:
00242 
00243       void acquire_ownership_of_buffer_list() const
00244         {
00245           mBufferList->AddRef();
00246           mStart.mBuffer->IncrementUsageCount();
00247         }
00248 
00249       void release_ownership_of_buffer_list()
00250         {
00251           if (mBufferList)
00252             {
00253               mStart.mBuffer->DecrementUsageCount();
00254               mBufferList->DiscardUnreferencedPrefix(mStart.mBuffer);
00255               mBufferList->Release();
00256             }
00257         }
00258       
00259       void init_range_from_buffer_list()
00260         {
00261           mStart.mBuffer = mBufferList->Head();
00262           mStart.mPosition = mStart.mBuffer->DataStart();
00263 
00264           mEnd.mBuffer = mBufferList->Tail();
00265           mEnd.mPosition = mEnd.mBuffer->DataEnd();
00266 
00267           mLength = Position::Distance(mStart, mEnd);
00268         }
00269 
00270       Position             mStart;
00271       Position             mEnd;
00272       nsScannerBufferList *mBufferList;
00273       size_type            mLength;
00274 
00275       // these fields are used to implement AsString
00276       nsDependentSubstring mFlattenedRep;
00277       PRBool               mIsDirty;
00278 
00279       friend class nsScannerSharedSubstring;
00280   };
00281 
00282 
00286 class nsScannerString : public nsScannerSubstring
00287   {
00288     public:
00289 
00290       nsScannerString( Buffer* );
00291 
00292         // you are giving ownership to the string, it takes and keeps your
00293         // buffer, deleting it when done.
00294         // Use AllocBuffer or AllocBufferFromString to create a Buffer object
00295         // for use with this function.
00296       void AppendBuffer( Buffer* );
00297 
00298       void DiscardPrefix( const nsScannerIterator& );
00299         // any other way you want to do this?
00300 
00301       void UngetReadable(const nsAString& aReadable, const nsScannerIterator& aCurrentPosition);
00302       void ReplaceCharacter(nsScannerIterator& aPosition, PRUnichar aChar);
00303   };
00304 
00305 
00313 class nsScannerSharedSubstring
00314   {
00315     public:
00316       nsScannerSharedSubstring()
00317         : mBuffer(nsnull), mBufferList(nsnull) { }
00318 
00319       ~nsScannerSharedSubstring()
00320         {
00321           if (mBufferList)
00322             ReleaseBuffer();
00323         }
00324 
00325         // Acquire a copy-on-write reference to the given substring.
00326       NS_HIDDEN_(void) Rebind(const nsScannerIterator& aStart,
00327                               const nsScannerIterator& aEnd);
00328 
00329        // Get a mutable reference to this string
00330       nsSubstring& writable()
00331         {
00332           if (mBufferList)
00333             MakeMutable();
00334 
00335           return mString;
00336         }
00337 
00338         // Get a const reference to this string
00339       const nsSubstring& str() const { return mString; }
00340 
00341     private:
00342       typedef nsScannerBufferList::Buffer Buffer;
00343 
00344       NS_HIDDEN_(void) ReleaseBuffer();
00345       NS_HIDDEN_(void) MakeMutable();
00346 
00347       nsDependentSubstring  mString;
00348       Buffer               *mBuffer;
00349       nsScannerBufferList  *mBufferList;
00350   };
00351 
00356 class nsScannerIterator
00357   {
00358     public:
00359       typedef nsScannerIterator             self_type;
00360       typedef ptrdiff_t                     difference_type;
00361       typedef PRUnichar                     value_type;
00362       typedef const PRUnichar*              pointer;
00363       typedef const PRUnichar&              reference;
00364       typedef nsScannerSubstring::Buffer    Buffer;
00365 
00366     protected:
00367 
00368       nsScannerFragment         mFragment;
00369       const PRUnichar*          mPosition;
00370       const nsScannerSubstring* mOwner;
00371 
00372       friend class nsScannerSubstring;
00373       friend class nsScannerSharedSubstring;
00374 
00375     public:
00376       nsScannerIterator() {}
00377       // nsScannerIterator( const nsScannerIterator& );             // auto-generated copy-constructor OK
00378       // nsScannerIterator& operator=( const nsScannerIterator& );  // auto-generated copy-assignment operator OK
00379 
00380       inline void normalize_forward();
00381       inline void normalize_backward();
00382 
00383       pointer get() const
00384         {
00385           return mPosition;
00386         }
00387       
00388       PRUnichar operator*() const
00389         {
00390           return *get();
00391         }
00392 
00393       const nsScannerFragment& fragment() const
00394         {
00395           return mFragment;
00396         }
00397 
00398       const Buffer* buffer() const
00399         {
00400           return mFragment.mBuffer;
00401         }
00402 
00403       self_type& operator++()
00404         {
00405           ++mPosition;
00406           normalize_forward();
00407           return *this;
00408         }
00409 
00410       self_type operator++( int )
00411         {
00412           self_type result(*this);
00413           ++mPosition;
00414           normalize_forward();
00415           return result;
00416         }
00417 
00418       self_type& operator--()
00419         {
00420           normalize_backward();
00421           --mPosition;
00422           return *this;
00423         }
00424 
00425       self_type operator--( int )
00426         {
00427           self_type result(*this);
00428           normalize_backward();
00429           --mPosition;
00430           return result;
00431         }
00432 
00433       difference_type size_forward() const
00434         {
00435           return mFragment.mFragmentEnd - mPosition;
00436         }
00437 
00438       difference_type size_backward() const
00439         {
00440           return mPosition - mFragment.mFragmentStart;
00441         }
00442 
00443       self_type& advance( difference_type n )
00444         {
00445           while ( n > 0 )
00446             {
00447               difference_type one_hop = NS_MIN(n, size_forward());
00448 
00449               NS_ASSERTION(one_hop>0, "Infinite loop: can't advance a reading iterator beyond the end of a string");
00450                 // perhaps I should |break| if |!one_hop|?
00451 
00452               mPosition += one_hop;
00453               normalize_forward();
00454               n -= one_hop;
00455             }
00456 
00457           while ( n < 0 )
00458             {
00459               normalize_backward();
00460               difference_type one_hop = NS_MAX(n, -size_backward());
00461 
00462               NS_ASSERTION(one_hop<0, "Infinite loop: can't advance (backward) a reading iterator beyond the end of a string");
00463                 // perhaps I should |break| if |!one_hop|?
00464 
00465               mPosition += one_hop;
00466               n -= one_hop;
00467             }
00468 
00469           return *this;
00470         }
00471   };
00472 
00473 
00474 inline
00475 PRBool
00476 SameFragment( const nsScannerIterator& a, const nsScannerIterator& b )
00477   {
00478     return a.fragment().mFragmentStart == b.fragment().mFragmentStart;
00479   }
00480 
00481 
00485 NS_SPECIALIZE_TEMPLATE
00486 struct nsCharSourceTraits<nsScannerIterator>
00487   {
00488     typedef nsScannerIterator::difference_type difference_type;
00489 
00490     static
00491     PRUint32
00492     readable_distance( const nsScannerIterator& first, const nsScannerIterator& last )
00493       {
00494         return PRUint32(SameFragment(first, last) ? last.get() - first.get() : first.size_forward());
00495       }
00496 
00497     static
00498     const nsScannerIterator::value_type*
00499     read( const nsScannerIterator& iter )
00500       {
00501         return iter.get();
00502       }
00503     
00504     static
00505     void
00506     advance( nsScannerIterator& s, difference_type n )
00507       {
00508         s.advance(n);
00509       }
00510   };
00511 
00512 
00517 inline
00518 void
00519 nsScannerIterator::normalize_forward()
00520   {
00521     while (mPosition == mFragment.mFragmentEnd && mOwner->GetNextFragment(mFragment))
00522       mPosition = mFragment.mFragmentStart;
00523   }
00524 
00525 inline
00526 void
00527 nsScannerIterator::normalize_backward()
00528   {
00529     while (mPosition == mFragment.mFragmentStart && mOwner->GetPrevFragment(mFragment))
00530       mPosition = mFragment.mFragmentEnd;
00531   }
00532 
00533 inline
00534 PRBool
00535 operator==( const nsScannerIterator& lhs, const nsScannerIterator& rhs )
00536   {
00537     return lhs.get() == rhs.get();
00538   }
00539 
00540 inline
00541 PRBool
00542 operator!=( const nsScannerIterator& lhs, const nsScannerIterator& rhs )
00543   {
00544     return lhs.get() != rhs.get();
00545   }
00546 
00547 
00548 inline
00549 nsScannerBufferList::Position::Position(const nsScannerIterator& aIter)
00550   : mBuffer(NS_CONST_CAST(Buffer*, aIter.buffer()))
00551   , mPosition(NS_CONST_CAST(PRUnichar*, aIter.get()))
00552   {}
00553 
00554 inline
00555 nsScannerBufferList::Position&
00556 nsScannerBufferList::Position::operator=(const nsScannerIterator& aIter)
00557   {
00558     mBuffer   = NS_CONST_CAST(Buffer*, aIter.buffer());
00559     mPosition = NS_CONST_CAST(PRUnichar*, aIter.get());
00560     return *this;
00561   }
00562 
00563 
00571 inline
00572 size_t
00573 Distance( const nsScannerIterator& aStart, const nsScannerIterator& aEnd )
00574   {
00575     typedef nsScannerBufferList::Position Position;
00576     return Position::Distance(Position(aStart), Position(aEnd));
00577   }
00578 
00579 void
00580 CopyUnicodeTo( const nsScannerIterator& aSrcStart,
00581                const nsScannerIterator& aSrcEnd,
00582                nsAString& aDest );
00583 
00584 inline
00585 void
00586 CopyUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
00587   {
00588     nsScannerIterator begin, end;
00589     CopyUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
00590   }
00591 
00592 void
00593 AppendUnicodeTo( const nsScannerIterator& aSrcStart,
00594                  const nsScannerIterator& aSrcEnd,
00595                  nsAString& aDest );
00596 
00597 inline
00598 void
00599 AppendUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
00600   {
00601     nsScannerIterator begin, end;
00602     AppendUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
00603   }
00604 
00605 void
00606 AppendUnicodeTo( const nsScannerIterator& aSrcStart,
00607                  const nsScannerIterator& aSrcEnd,
00608                  nsScannerSharedSubstring& aDest );
00609 
00610 PRBool
00611 FindCharInReadable( PRUnichar aChar,
00612                     nsScannerIterator& aStart,
00613                     const nsScannerIterator& aEnd );
00614 
00615 PRBool
00616 FindInReadable( const nsAString& aPattern,
00617                 nsScannerIterator& aStart,
00618                 nsScannerIterator& aEnd,
00619                 const nsStringComparator& = nsDefaultStringComparator() );
00620 
00621 PRBool
00622 RFindInReadable( const nsAString& aPattern,
00623                  nsScannerIterator& aStart,
00624                  nsScannerIterator& aEnd,
00625                  const nsStringComparator& = nsDefaultStringComparator() );
00626 
00627 inline
00628 PRBool
00629 CaseInsensitiveFindInReadable( const nsAString& aPattern, 
00630                                nsScannerIterator& aStart,
00631                                nsScannerIterator& aEnd )
00632   {
00633     return FindInReadable(aPattern, aStart, aEnd,
00634                           nsCaseInsensitiveStringComparator());
00635   }
00636 
00637 #endif // !defined(nsScannerString_h___)