Files
Mozilla/mozilla/parser/htmlparser/public/nsScannerString.h
darin%meer.net d3609ac18f new scanner string implementation
git-svn-id: svn://10.0.0.236/branches/STRING_20040119_BRANCH@151562 18797224-902f-48f8-a5cc-f745e15eee43
2004-01-19 22:04:47 +00:00

501 lines
13 KiB
C++

#ifndef nsScannerString_h___
#define nsScannerString_h___
#include "nsString.h"
#include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator
#include "prclist.h"
/**
* no relation to nsAString ;-)
*/
class nsScannerIterator;
class nsScannerSubstring;
class nsScannerString;
/**
* XXX
*/
class nsScannerBufferList
{
public:
/**
* XXX
*/
class Buffer : public PRCList
{
public:
void IncrementUsageCount() { ++mUsageCount; }
void DecrementUsageCount() { --mUsageCount; }
PRBool IsInUse() const { return mUsageCount != 0; }
const PRUnichar* DataStart() const { return (const PRUnichar*) (this+1); }
PRUnichar* DataStart() { return ( PRUnichar*) (this+1); }
const PRUnichar* DataEnd() const { return mDataEnd; }
PRUnichar* DataEnd() { return mDataEnd; }
const Buffer* Next() const { return NS_STATIC_CAST(const Buffer*, next); }
Buffer* Next() { return NS_STATIC_CAST( Buffer*, next); }
const Buffer* Prev() const { return NS_STATIC_CAST(const Buffer*, prev); }
Buffer* Prev() { return NS_STATIC_CAST( Buffer*, prev); }
PRUint32 DataLength() const { return mDataEnd - DataStart(); }
void SetDataLength(PRUint32 len) { mDataEnd = DataStart() + len; }
private:
friend class nsScannerBufferList;
PRInt32 mUsageCount;
PRUnichar* mDataEnd;
};
/**
* XXX
*/
class Position
{
public:
Position() {}
Position( Buffer* buffer, PRUnichar* position )
: mBuffer(buffer)
, mPosition(position)
{}
inline
Position( const nsScannerIterator& aIter );
inline
Position& operator=(const nsScannerIterator& aIter);
static size_t Distance( const Position& p1, const Position& p2 );
Buffer* mBuffer;
PRUnichar* mPosition;
};
static Buffer* AllocBufferFromString( const nsAString& );
static Buffer* AllocBuffer( PRUint32 capacity ); // capacity = number of chars
nsScannerBufferList( Buffer* buf )
: mRefCnt(0)
{
PR_INIT_CLIST(&mBuffers);
PR_APPEND_LINK(buf, &mBuffers);
}
void AddRef() { ++mRefCnt; }
void Release() { if (--mRefCnt == 0) delete this; }
void Append( Buffer* buf ) { PR_APPEND_LINK(buf, &mBuffers); }
void InsertAfter( Buffer* buf, Buffer* prev ) { PR_INSERT_AFTER(buf, prev); }
void SplitBuffer( const Position& );
void DiscardUnreferencedPrefix( Buffer* );
Buffer* Head() { return NS_STATIC_CAST( Buffer*, PR_LIST_HEAD(&mBuffers)); }
const Buffer* Head() const { return NS_STATIC_CAST(const Buffer*, PR_LIST_HEAD(&mBuffers)); }
Buffer* Tail() { return NS_STATIC_CAST( Buffer*, PR_LIST_TAIL(&mBuffers)); }
const Buffer* Tail() const { return NS_STATIC_CAST(const Buffer*, PR_LIST_TAIL(&mBuffers)); }
private:
friend class nsScannerSubstring;
~nsScannerBufferList() { ReleaseAll(); }
void ReleaseAll();
PRInt32 mRefCnt;
PRCList mBuffers;
};
struct nsScannerFragment
{
typedef nsScannerBufferList::Buffer Buffer;
const Buffer* mBuffer;
const PRUnichar* mFragmentStart;
const PRUnichar* mFragmentEnd;
};
/**
* nsScannerSubstring
*/
class nsScannerSubstring
{
public:
typedef nsScannerBufferList::Buffer Buffer;
typedef nsScannerBufferList::Position Position;
typedef PRUint32 size_type;
nsScannerSubstring();
nsScannerSubstring( const nsAString& s );
~nsScannerSubstring();
nsScannerIterator& BeginReading( nsScannerIterator& iter ) const;
nsScannerIterator& EndReading( nsScannerIterator& iter ) const;
size_type Length() const { return mLength; }
PRInt32 CountChar( PRUnichar ) const;
void Rebind( const nsScannerSubstring&, const nsScannerIterator&, const nsScannerIterator& );
void Rebind( const nsAString& );
const nsString& AsString() const;
PRBool GetNextFragment( nsScannerFragment& ) const;
PRBool GetPrevFragment( nsScannerFragment& ) const;
static inline Buffer* AllocBufferFromString( const nsAString& aStr ) { return nsScannerBufferList::AllocBufferFromString(aStr); }
static inline Buffer* AllocBuffer( size_type aCapacity ) { return nsScannerBufferList::AllocBuffer(aCapacity); }
protected:
void acquire_ownership_of_buffer_list() const
{
mBufferList->AddRef();
mStart.mBuffer->IncrementUsageCount();
}
void release_ownership_of_buffer_list()
{
if (mBufferList)
{
mStart.mBuffer->DecrementUsageCount();
mBufferList->DiscardUnreferencedPrefix(mStart.mBuffer);
mBufferList->Release();
}
}
void init_range_from_buffer_list()
{
mStart.mBuffer = mBufferList->Head();
mStart.mPosition = mStart.mBuffer->DataStart();
mEnd.mBuffer = mBufferList->Tail();
mEnd.mPosition = mEnd.mBuffer->DataEnd();
mLength = Position::Distance(mStart, mEnd);
}
Position mStart;
Position mEnd;
nsScannerBufferList *mBufferList;
size_type mLength;
// these fields are used to implement AsString
nsString mFlattenedRep;
PRBool mIsDirty;
};
/**
* nsScannerString
*/
class nsScannerString : public nsScannerSubstring
{
public:
nsScannerString( Buffer* );
// you are giving ownership to the string, it takes and keeps your buffer, deleting it (with |nsMemory::Free|) when done
void AppendBuffer( Buffer* );
// void Append( ... ); do you want some |Append|s that copy the supplied data?
void DiscardPrefix( const nsScannerIterator& );
// any other way you want to do this?
void UngetReadable(const nsAString& aReadable, const nsScannerIterator& aCurrentPosition);
void ReplaceCharacter(nsScannerIterator& aPosition, PRUnichar aChar);
};
/**
* nsScannerIterator
*/
class nsScannerIterator
{
public:
typedef nsScannerIterator self_type;
typedef ptrdiff_t difference_type;
typedef PRUnichar value_type;
typedef const PRUnichar* pointer;
typedef const PRUnichar& reference;
typedef nsScannerSubstring::Buffer Buffer;
protected:
nsScannerFragment mFragment;
const PRUnichar* mPosition;
const nsScannerSubstring* mOwner;
friend class nsScannerSubstring;
public:
nsScannerIterator() {}
// nsScannerIterator( const nsScannerIterator& ); // auto-generated copy-constructor OK
// nsScannerIterator<CharT>& operator=( const nsScannerIterator& ); // auto-generated copy-assignment operator OK
inline void normalize_forward();
inline void normalize_backward();
pointer get() const
{
return mPosition;
}
PRUnichar operator*() const
{
return *get();
}
const nsScannerFragment& fragment() const
{
return mFragment;
}
const Buffer* buffer() const
{
return mFragment.mBuffer;
}
self_type& operator++()
{
++mPosition;
normalize_forward();
return *this;
}
self_type operator++( int )
{
self_type result(*this);
++mPosition;
normalize_forward();
return result;
}
self_type& operator--()
{
normalize_backward();
--mPosition;
return *this;
}
self_type operator--( int )
{
self_type result(*this);
normalize_backward();
--mPosition;
return result;
}
difference_type size_forward() const
{
return mFragment.mFragmentEnd - mPosition;
}
difference_type size_backward() const
{
return mPosition - mFragment.mFragmentStart;
}
self_type& advance( difference_type n )
{
while ( n > 0 )
{
difference_type one_hop = NS_MIN(n, size_forward());
NS_ASSERTION(one_hop>0, "Infinite loop: can't advance a reading iterator beyond the end of a string");
// perhaps I should |break| if |!one_hop|?
mPosition += one_hop;
normalize_forward();
n -= one_hop;
}
while ( n < 0 )
{
normalize_backward();
difference_type one_hop = NS_MAX(n, -size_backward());
NS_ASSERTION(one_hop<0, "Infinite loop: can't advance (backward) a reading iterator beyond the end of a string");
// perhaps I should |break| if |!one_hop|?
mPosition += one_hop;
n -= one_hop;
}
return *this;
}
};
inline
PRBool
SameFragment( const nsScannerIterator& a, const nsScannerIterator& b )
{
return a.fragment().mFragmentStart == b.fragment().mFragmentStart;
}
/**
* this class is needed in order to make use of the methods in nsAlgorithm.h
*/
NS_SPECIALIZE_TEMPLATE
struct nsCharSourceTraits<nsScannerIterator>
{
typedef nsScannerIterator::difference_type difference_type;
static
PRUint32
readable_distance( const nsScannerIterator& first, const nsScannerIterator& last )
{
return PRUint32(SameFragment(first, last) ? last.get() - first.get() : first.size_forward());
}
static
const nsScannerIterator::value_type*
read( const nsScannerIterator& iter )
{
return iter.get();
}
static
void
advance( nsScannerIterator& s, difference_type n )
{
s.advance(n);
}
};
inline
void
nsScannerIterator::normalize_forward()
{
while (mPosition == mFragment.mFragmentEnd && mOwner->GetNextFragment(mFragment))
mPosition = mFragment.mFragmentStart;
}
inline
void
nsScannerIterator::normalize_backward()
{
while (mPosition == mFragment.mFragmentStart && mOwner->GetPrevFragment(mFragment))
mPosition = mFragment.mFragmentEnd;
}
inline
PRBool
operator==( const nsScannerIterator& lhs, const nsScannerIterator& rhs )
{
return lhs.get() == rhs.get();
}
inline
PRBool
operator!=( const nsScannerIterator& lhs, const nsScannerIterator& rhs )
{
return lhs.get() != rhs.get();
}
inline
nsScannerBufferList::Position::Position(const nsScannerIterator& aIter)
: mBuffer(NS_CONST_CAST(Buffer*, aIter.buffer()))
, mPosition(NS_CONST_CAST(PRUnichar*, aIter.get()))
{}
inline
nsScannerBufferList::Position&
nsScannerBufferList::Position::operator=(const nsScannerIterator& aIter)
{
mBuffer = NS_CONST_CAST(Buffer*, aIter.buffer());
mPosition = NS_CONST_CAST(PRUnichar*, aIter.get());
return *this;
}
/**
* scanner string utils
*/
inline
size_t
Distance( const nsScannerIterator& aStart, const nsScannerIterator& aEnd )
{
typedef nsScannerBufferList::Position Position;
return Position::Distance(Position(aStart), Position(aEnd));
}
void
CopyUnicodeTo( const nsScannerIterator& aSrcStart,
const nsScannerIterator& aSrcEnd,
nsAString& aDest );
inline
void
CopyUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
{
nsScannerIterator begin, end;
CopyUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
}
void
AppendUnicodeTo( const nsScannerIterator& aSrcStart,
const nsScannerIterator& aSrcEnd,
nsAString& aDest );
inline
void
AppendUnicodeTo( const nsScannerSubstring& aSrc, nsAString& aDest )
{
nsScannerIterator begin, end;
AppendUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
}
PRBool
FindCharInReadable( PRUnichar aChar,
nsScannerIterator& aStart,
const nsScannerIterator& aEnd );
PRBool
FindInReadable( const nsAString& aPattern,
nsScannerIterator& aStart,
nsScannerIterator& aEnd,
const nsStringComparator& = nsDefaultStringComparator() );
PRBool
RFindInReadable( const nsAString& aPattern,
nsScannerIterator& aStart,
nsScannerIterator& aEnd,
const nsStringComparator& = nsDefaultStringComparator() );
inline
PRBool
CaseInsensitiveFindInReadable( const nsAString& aPattern,
nsScannerIterator& aStart,
nsScannerIterator& aEnd )
{
return FindInReadable(aPattern, aStart, aEnd,
nsCaseInsensitiveStringComparator());
}
#endif // !defined(nsScannerString_h___)