diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a14ccf59b6c8..23395f005774 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -904,7 +904,7 @@ NS_IMETHODIMP nsDocument::SetDocumentCharacterSet(const nsAReadableString& aChar for (PRInt32 i = 0; i < n; i++) { nsIObserver* observer = (nsIObserver*) mCharSetObservers.ElementAt(i); observer->Observe((nsIDocument*) this, NS_LITERAL_STRING("charset").get(), - nsPromiseFlatString(aCharSetID).get()); + PromiseFlatString(aCharSetID).get()); } } return NS_OK; diff --git a/content/base/src/nsDocumentEncoder.cpp b/content/base/src/nsDocumentEncoder.cpp index 4dbe81487b27..6256e49745b8 100644 --- a/content/base/src/nsDocumentEncoder.cpp +++ b/content/base/src/nsDocumentEncoder.cpp @@ -383,7 +383,7 @@ ConvertAndWrite(nsAReadableString& aString, NS_ENSURE_ARG_POINTER(aEncoder); nsresult rv; PRInt32 charLength, startCharLength; - nsPromiseFlatString flat(aString); + const nsPromiseFlatString& flat = PromiseFlatString(aString); const PRUnichar* unicodeBuf = flat.get(); PRInt32 unicodeLength = aString.Length(); PRInt32 startLength = unicodeLength; diff --git a/content/base/src/nsNodeInfo.cpp b/content/base/src/nsNodeInfo.cpp index bae5d9c904d2..dfddcbfe2239 100644 --- a/content/base/src/nsNodeInfo.cpp +++ b/content/base/src/nsNodeInfo.cpp @@ -347,7 +347,7 @@ nsNodeInfo::NamespaceEquals(const nsAReadableString& aNamespaceURI) NS_IMETHODIMP_(PRBool) nsNodeInfo::QualifiedNameEquals(const nsAReadableString& aQualifiedName) { - nsPromiseFlatString flatName(aQualifiedName); + const nsPromiseFlatString& flatName = PromiseFlatString(aQualifiedName); const PRUnichar *qname = flatName.get(); PRUint32 i = 0; diff --git a/content/html/content/src/nsHTMLAnchorElement.cpp b/content/html/content/src/nsHTMLAnchorElement.cpp index 2db1d4edcc04..bf8740adb6a2 100644 --- a/content/html/content/src/nsHTMLAnchorElement.cpp +++ b/content/html/content/src/nsHTMLAnchorElement.cpp @@ -369,7 +369,7 @@ nsHTMLAnchorElement::StringToAttribute(nsIAtom* aAttribute, } } else if (aAttribute == nsHTMLAtoms::suppress) { - if (nsCRT::strcasecmp(nsPromiseFlatString(aValue).get(), + if (nsCRT::strcasecmp(PromiseFlatString(aValue).get(), NS_LITERAL_STRING("true").get())) { aResult.SetEmptyValue(); // XXX? shouldn't just leave "true" return NS_CONTENT_ATTR_HAS_VALUE; diff --git a/content/xbl/src/nsBindingManager.cpp b/content/xbl/src/nsBindingManager.cpp index f558f5105ce9..89a19b19b608 100644 --- a/content/xbl/src/nsBindingManager.cpp +++ b/content/xbl/src/nsBindingManager.cpp @@ -122,7 +122,7 @@ nsXBLDocumentInfo::GetPrototypeBinding(const nsAReadableCString& aRef, nsIXBLPro if (!mBindingTable) return NS_OK; - nsPromiseFlatCString flat(aRef); + const nsPromiseFlatCString& flat = PromiseFlatCString(aRef); nsCStringKey key(flat.get()); *aResult = NS_STATIC_CAST(nsIXBLPrototypeBinding*, mBindingTable->Get(&key)); // Addref happens here. @@ -135,7 +135,7 @@ nsXBLDocumentInfo::SetPrototypeBinding(const nsAReadableCString& aRef, nsIXBLPro if (!mBindingTable) mBindingTable = new nsSupportsHashtable(); - nsPromiseFlatCString flat(aRef); + const nsPromiseFlatCString& flat = PromiseFlatCString(aRef); nsCStringKey key(flat.get()); mBindingTable->Put(&key, aBinding); @@ -870,7 +870,7 @@ NS_IMETHODIMP nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc, const nsAReadableString& aURL, nsIDocument** aResult) { - nsCAutoString url; url.AssignWithConversion(nsPromiseFlatString(aURL).get()); + nsCAutoString url; url.AssignWithConversion(PromiseFlatString(aURL).get()); nsCOMPtr uri; nsComponentManager::CreateInstance("@mozilla.org/network/standard-url;1", diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index b208ed7c7a35..91c9f9b9efef 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -633,7 +633,7 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsAReadableString& aURL, // See if the URIs match. nsCAutoString uri; styleBinding->GetBindingURI(uri); - if (uri.EqualsWithConversion((const PRUnichar *) nsPromiseFlatString(aURL).get())) + if (uri.EqualsWithConversion((const PRUnichar *) PromiseFlatString(aURL).get())) return NS_OK; else { FlushStyleBindings(aContent); diff --git a/content/xbl/src/nsXBLWindowHandler.cpp b/content/xbl/src/nsXBLWindowHandler.cpp index 1b95d6e3f409..ca3ae24cbfa4 100644 --- a/content/xbl/src/nsXBLWindowHandler.cpp +++ b/content/xbl/src/nsXBLWindowHandler.cpp @@ -143,7 +143,7 @@ nsXBLSpecialDocInfo::GetHandlers(nsIXBLDocumentInfo* aInfo, root->ChildAt(i, *getter_AddRefs(child)); nsAutoString id; child->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, id); - if (id.EqualsWithConversion(nsPromiseFlatCString(aRef).get())) { + if (id.EqualsWithConversion(PromiseFlatCString(aRef).get())) { NS_NewXBLPrototypeBinding(aRef, child, aInfo, getter_AddRefs(binding)); aInfo->SetPrototypeBinding(aRef, binding); break; diff --git a/content/xul/document/src/nsElementMap.cpp b/content/xul/document/src/nsElementMap.cpp index fa1e62210670..addfe0d6c14f 100644 --- a/content/xul/document/src/nsElementMap.cpp +++ b/content/xul/document/src/nsElementMap.cpp @@ -152,7 +152,7 @@ nsElementMap::Add(const nsAReadableString& aID, nsIContent* aContent) if (! mMap) return NS_ERROR_NOT_INITIALIZED; - nsPromiseFlatString flatID(aID); + const nsPromiseFlatString& flatID = PromiseFlatString(aID); const PRUnichar *id = flatID.get(); ContentListItem* head = @@ -251,7 +251,7 @@ nsElementMap::Remove(const nsAReadableString& aID, nsIContent* aContent) if (! mMap) return NS_ERROR_NOT_INITIALIZED; - nsPromiseFlatString flatID(aID); + const nsPromiseFlatString& flatID = PromiseFlatString(aID); const PRUnichar *id = flatID.get(); #ifdef PR_LOGGING @@ -331,7 +331,7 @@ nsElementMap::Find(const nsAReadableString& aID, nsISupportsArray* aResults) aResults->Clear(); ContentListItem* item = - NS_REINTERPRET_CAST(ContentListItem*, PL_HashTableLookup(mMap, (const PRUnichar *)nsPromiseFlatString(aID).get())); + NS_REINTERPRET_CAST(ContentListItem*, PL_HashTableLookup(mMap, (const PRUnichar *)PromiseFlatString(aID).get())); while (item) { aResults->AppendElement(item->mContent); @@ -349,7 +349,7 @@ nsElementMap::FindFirst(const nsAReadableString& aID, nsIContent** aResult) return NS_ERROR_NOT_INITIALIZED; ContentListItem* item = - NS_REINTERPRET_CAST(ContentListItem*, PL_HashTableLookup(mMap, (const PRUnichar *)nsPromiseFlatString(aID).get())); + NS_REINTERPRET_CAST(ContentListItem*, PL_HashTableLookup(mMap, (const PRUnichar *)PromiseFlatString(aID).get())); if (item) { *aResult = item->mContent; diff --git a/content/xul/document/src/nsXULCommandDispatcher.cpp b/content/xul/document/src/nsXULCommandDispatcher.cpp index 30416f5ad7a8..a0d61e1c1d1b 100644 --- a/content/xul/document/src/nsXULCommandDispatcher.cpp +++ b/content/xul/document/src/nsXULCommandDispatcher.cpp @@ -378,7 +378,7 @@ nsXULCommandDispatcher::Matches(const nsString& aList, if (aList.Equals(NS_LITERAL_STRING("*"))) return PR_TRUE; // match _everything_! - PRInt32 indx = aList.Find((const PRUnichar *)nsPromiseFlatString(aElement).get()); + PRInt32 indx = aList.Find((const PRUnichar *)PromiseFlatString(aElement).get()); if (indx == -1) return PR_FALSE; // not in the list at all diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index bef0acafd5f9..a14b31be05fd 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -815,7 +815,7 @@ nsXULDocument::SetDocumentCharacterSet(const nsAReadableString& aCharSetID) for (PRInt32 i = 0; i < n; i++) { nsIObserver* observer = (nsIObserver*) mCharSetObservers.ElementAt(i); observer->Observe((nsIDocument*) this, NS_LITERAL_STRING("charset").get(), - nsPromiseFlatString(aCharSetID).get()); + PromiseFlatString(aCharSetID).get()); } } return NS_OK; diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index aa8f6e76a8f2..db2732f0e3e8 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -1140,7 +1140,7 @@ nsXULTemplateBuilder::SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, if (aVariable == NS_LITERAL_STRING("rdf:*")) var = c->match.mRule->GetMemberVariable(); else - var = aThis->mRules.LookupSymbol(nsPromiseFlatString(aVariable).get()); + var = aThis->mRules.LookupSymbol(PromiseFlatString(aVariable).get()); // No variable; treat as a variable with no substitution. (This // shouldn't ever happen, really...) @@ -1204,7 +1204,7 @@ nsXULTemplateBuilder::IsVarInSet(nsXULTemplateBuilder* aThis, IsVarInSetClosure* c = NS_STATIC_CAST(IsVarInSetClosure*, aClosure); PRInt32 var = - aThis->mRules.LookupSymbol(nsPromiseFlatString(aVariable).get()); + aThis->mRules.LookupSymbol(PromiseFlatString(aVariable).get()); // No variable; treat as a variable with no substitution. (This // shouldn't ever happen, really...) @@ -2354,7 +2354,7 @@ nsXULTemplateBuilder::AddBindingsFor(nsXULTemplateBuilder* aThis, nsTemplateRule* rule = NS_STATIC_CAST(nsTemplateRule*, aClosure); // Lookup the variable symbol - PRInt32 var = aThis->mRules.LookupSymbol(nsPromiseFlatString(aVariable).get(), PR_TRUE); + PRInt32 var = aThis->mRules.LookupSymbol(PromiseFlatString(aVariable).get(), PR_TRUE); // Strip it down to the raw RDF property by clobbering the "rdf:" // prefix diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index 91421bdf58e2..7f0e86918a53 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -1206,7 +1206,7 @@ nsWebShell :: IsCommandEnabled ( const nsAReadableString & inCommand, PRBool* ou nsCOMPtr controller; rv = GetControllerForCommand ( inCommand, getter_AddRefs(controller) ); if ( controller ) - rv = controller->IsCommandEnabled(nsPromiseFlatString(inCommand).get(), outEnabled); + rv = controller->IsCommandEnabled(PromiseFlatString(inCommand).get(), outEnabled); return rv; } @@ -1220,7 +1220,7 @@ nsWebShell :: DoCommand ( const nsAReadableString & inCommand ) nsCOMPtr controller; rv = GetControllerForCommand ( inCommand, getter_AddRefs(controller) ); if ( controller ) - rv = controller->DoCommand(nsPromiseFlatString(inCommand).get()); + rv = controller->DoCommand(PromiseFlatString(inCommand).get()); return rv; } diff --git a/dom/src/base/nsDOMWindowList.cpp b/dom/src/base/nsDOMWindowList.cpp index c0715ad6aae7..ed8fdea8f97f 100644 --- a/dom/src/base/nsDOMWindowList.cpp +++ b/dom/src/base/nsDOMWindowList.cpp @@ -146,7 +146,7 @@ nsDOMWindowList::NamedItem(const nsAReadableString& aName, nsIDOMWindow** aRetur } } - mDocShellNode->FindChildWithName(nsPromiseFlatString(aName).get(), + mDocShellNode->FindChildWithName(PromiseFlatString(aName).get(), PR_FALSE, PR_FALSE, nsnull, getter_AddRefs(item)); diff --git a/dom/src/base/nsFocusController.cpp b/dom/src/base/nsFocusController.cpp index 4e09c63efd50..0da7d68d1756 100644 --- a/dom/src/base/nsFocusController.cpp +++ b/dom/src/base/nsFocusController.cpp @@ -265,7 +265,7 @@ nsFocusController::GetParentWindowFromDocument(nsIDOMDocument* aDocument, nsIDOM NS_IMETHODIMP nsFocusController::GetControllerForCommand(const nsAReadableString& aCommand, nsIController** _retval) { - nsPromiseFlatString flatCommand(aCommand); + const nsPromiseFlatString& flatCommand = PromiseFlatString(aCommand); const PRUnichar *command = flatCommand.get(); *_retval = nsnull; diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index eeaba5f27363..1e095319f67d 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -1017,7 +1017,7 @@ NS_IMETHODIMP GlobalWindowImpl::SetStatus(const nsAReadableString& aStatus) nsCOMPtr browserChrome; GetWebBrowserChrome(getter_AddRefs(browserChrome)); if(browserChrome) - browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT, nsPromiseFlatString(aStatus).get()); + browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT, PromiseFlatString(aStatus).get()); return NS_OK; } @@ -1035,7 +1035,7 @@ NS_IMETHODIMP GlobalWindowImpl::SetDefaultStatus(const nsAReadableString& aDefau nsCOMPtr browserChrome; GetWebBrowserChrome(getter_AddRefs(browserChrome)); if(browserChrome) - browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT, nsPromiseFlatString(aDefaultStatus).get()); + browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT, PromiseFlatString(aDefaultStatus).get()); return NS_OK; } @@ -1056,7 +1056,7 @@ NS_IMETHODIMP GlobalWindowImpl::SetName(const nsAReadableString& aName) nsresult result = NS_OK; nsCOMPtr docShellAsItem(do_QueryInterface(mDocShell)); if (docShellAsItem) - result = docShellAsItem->SetName(nsPromiseFlatString(aName).get()); + result = docShellAsItem->SetName(PromiseFlatString(aName).get()); return result; } @@ -1136,7 +1136,7 @@ GlobalWindowImpl::SetTitle(const nsAReadableString& aTitle) if(type == nsIDocShellTreeItem::typeChrome) { nsCOMPtr docShellAsWin(do_QueryInterface(mDocShell)); if(docShellAsWin) { - docShellAsWin->SetTitle(nsPromiseFlatString(mTitle).get()); + docShellAsWin->SetTitle(PromiseFlatString(mTitle).get()); } } } @@ -2190,7 +2190,7 @@ NS_IMETHODIMP GlobalWindowImpl::Escape(const nsAReadableString& aStr, nsAWritabl PRInt32 maxByteLen, srcLen; srcLen = aStr.Length(); - nsPromiseFlatString flatSrc(aStr); + const nsPromiseFlatString& flatSrc = PromiseFlatString(aStr); const PRUnichar* src = flatSrc.get(); // Get the expected length of result string diff --git a/dom/src/base/nsJSEnvironment.cpp b/dom/src/base/nsJSEnvironment.cpp index 6f7da752db0a..51a2f2846557 100644 --- a/dom/src/base/nsJSEnvironment.cpp +++ b/dom/src/base/nsJSEnvironment.cpp @@ -486,7 +486,7 @@ nsJSContext::EvaluateStringWithValue(const nsAReadableString& aScript, ok = ::JS_EvaluateUCScriptForPrincipals(mContext, (JSObject *)aScopeObject, jsprin, - (jschar*)(const PRUnichar*)nsPromiseFlatString(aScript).get(), + (jschar*)(const PRUnichar*)PromiseFlatString(aScript).get(), aScript.Length(), aURL, aLineNo, @@ -602,7 +602,7 @@ nsJSContext::EvaluateString(const nsAReadableString& aScript, ok = ::JS_EvaluateUCScriptForPrincipals(mContext, (JSObject *)aScopeObject, jsprin, - (jschar*)(const PRUnichar*)nsPromiseFlatString(aScript).get(), + (jschar*)(const PRUnichar*)PromiseFlatString(aScript).get(), aScript.Length(), aURL, aLineNo, @@ -834,7 +834,7 @@ nsJSContext::CompileEventHandler(void *aTarget, nsIAtom *aName, JSFunction* fun = ::JS_CompileUCFunctionForPrincipals(mContext, target, jsprin, charName, 1, gEventArgv, - (jschar*)(const PRUnichar*)nsPromiseFlatString(aBody).get(), + (jschar*)(const PRUnichar*)PromiseFlatString(aBody).get(), aBody.Length(), //XXXbe filename, lineno: nsnull, 0); @@ -884,7 +884,7 @@ nsJSContext::CompileFunction(void* aTarget, JSFunction* fun = ::JS_CompileUCFunctionForPrincipals(mContext, target, jsprin, aName, aArgCount, aArgArray, - (jschar*)(const PRUnichar*)nsPromiseFlatString(aBody).get(), + (jschar*)(const PRUnichar*)PromiseFlatString(aBody).get(), aBody.Length(), aURL, aLineNo); diff --git a/editor/base/nsEditorShell.cpp b/editor/base/nsEditorShell.cpp index a6a50f3cffeb..48fa00f06816 100644 --- a/editor/base/nsEditorShell.cpp +++ b/editor/base/nsEditorShell.cpp @@ -2965,7 +2965,7 @@ void nsEditorShell::GetBundleString(const nsAReadableString &stringName, nsAWrit outString.Truncate(); nsXPIDLString tempString; - if (NS_SUCCEEDED(GetString(nsPromiseFlatString(stringName).get(), getter_Copies(tempString))) && tempString) + if (NS_SUCCEEDED(GetString(PromiseFlatString(stringName).get(), getter_Copies(tempString))) && tempString) outString = tempString.get(); } diff --git a/editor/base/nsInternetCiter.cpp b/editor/base/nsInternetCiter.cpp index 4e6813b7f263..97fd76cdb09b 100644 --- a/editor/base/nsInternetCiter.cpp +++ b/editor/base/nsInternetCiter.cpp @@ -289,7 +289,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, nextNewline-posInString)); printf("Unquoted: appending '%s'\n", debug.ToNewCString()); #endif - aOutString.Append(nsPromiseSubstring(aInString, posInString, + aOutString.Append(nsPromiseSubstring(aInString, posInString, nextNewline-posInString)); outStringCol += nextNewline - posInString; if (nextNewline != (PRInt32)length) @@ -324,7 +324,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, nsAutoString debug (nsPromiseSubstring(aInString, posInString, nextNewline - posInString)); printf("Short line: '%s'\n", debug.ToNewCString()); #endif - aOutString += nsPromiseSubstring(aInString, + aOutString += nsPromiseSubstring(aInString, posInString, nextNewline - posInString); outStringCol += nextNewline - posInString; posInString = nextNewline + 1; @@ -365,7 +365,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, printf("breakPt = %d\n", breakPt); #endif - aOutString += nsPromiseSubstring(aInString, posInString, breakPt); + aOutString += nsPromiseSubstring(aInString, posInString, breakPt); posInString += breakPt; outStringCol += breakPt; diff --git a/editor/composer/src/nsEditorShell.cpp b/editor/composer/src/nsEditorShell.cpp index a6a50f3cffeb..48fa00f06816 100644 --- a/editor/composer/src/nsEditorShell.cpp +++ b/editor/composer/src/nsEditorShell.cpp @@ -2965,7 +2965,7 @@ void nsEditorShell::GetBundleString(const nsAReadableString &stringName, nsAWrit outString.Truncate(); nsXPIDLString tempString; - if (NS_SUCCEEDED(GetString(nsPromiseFlatString(stringName).get(), getter_Copies(tempString))) && tempString) + if (NS_SUCCEEDED(GetString(PromiseFlatString(stringName).get(), getter_Copies(tempString))) && tempString) outString = tempString.get(); } diff --git a/editor/libeditor/text/nsInternetCiter.cpp b/editor/libeditor/text/nsInternetCiter.cpp index 4e6813b7f263..97fd76cdb09b 100644 --- a/editor/libeditor/text/nsInternetCiter.cpp +++ b/editor/libeditor/text/nsInternetCiter.cpp @@ -289,7 +289,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, nextNewline-posInString)); printf("Unquoted: appending '%s'\n", debug.ToNewCString()); #endif - aOutString.Append(nsPromiseSubstring(aInString, posInString, + aOutString.Append(nsPromiseSubstring(aInString, posInString, nextNewline-posInString)); outStringCol += nextNewline - posInString; if (nextNewline != (PRInt32)length) @@ -324,7 +324,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, nsAutoString debug (nsPromiseSubstring(aInString, posInString, nextNewline - posInString)); printf("Short line: '%s'\n", debug.ToNewCString()); #endif - aOutString += nsPromiseSubstring(aInString, + aOutString += nsPromiseSubstring(aInString, posInString, nextNewline - posInString); outStringCol += nextNewline - posInString; posInString = nextNewline + 1; @@ -365,7 +365,7 @@ nsInternetCiter::Rewrap(const nsString& aInString, printf("breakPt = %d\n", breakPt); #endif - aOutString += nsPromiseSubstring(aInString, posInString, breakPt); + aOutString += nsPromiseSubstring(aInString, posInString, breakPt); posInString += breakPt; outStringCol += breakPt; diff --git a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp index 9467b8923b89..2d2830b25b14 100644 --- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp @@ -1058,7 +1058,7 @@ ChromeTooltipListener :: ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, con // do the work to call the client nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); if ( tooltipListener ) { - rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, nsPromiseFlatString(inTipText).get() ); + rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); if ( NS_SUCCEEDED(rv) ) mShowingTooltip = PR_TRUE; } diff --git a/extensions/wallet/src/wallet.cpp b/extensions/wallet/src/wallet.cpp index 2fb1c56b4a1d..c9d21b5d8c9c 100644 --- a/extensions/wallet/src/wallet.cpp +++ b/extensions/wallet/src/wallet.cpp @@ -1047,7 +1047,7 @@ wallet_WriteToList( added_to_list = PR_TRUE; break; } - } else if((mapElementPtr->item1.Compare(item1))>=0) { + } else if(Compare(mapElementPtr->item1,item1)>=0) { list->InsertElementAt(mapElement, i); added_to_list = PR_TRUE; break; diff --git a/htmlparser/src/nsHTMLContentSinkStream.cpp b/htmlparser/src/nsHTMLContentSinkStream.cpp index ceca3c146929..ee2eab6fef08 100644 --- a/htmlparser/src/nsHTMLContentSinkStream.cpp +++ b/htmlparser/src/nsHTMLContentSinkStream.cpp @@ -289,7 +289,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) { nsresult res; PRUnichar *encodedBuffer = nsnull; - res = mEntityConverter->ConvertToEntities(nsPromiseFlatString(aString).get(), + res = mEntityConverter->ConvertToEntities(PromiseFlatString(aString).get(), nsIEntityConverter::html40Latin1, &encodedBuffer); if (NS_SUCCEEDED(res) && encodedBuffer) @@ -328,7 +328,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) { // Call the converter to convert to the target charset. // Convert() takes a char* output param even though it's writing unicode. - res = mCharsetEncoder->Convert(nsPromiseFlatString(aString).get(), &encodedBuffer); + res = mCharsetEncoder->Convert(PromiseFlatString(aString).get(), &encodedBuffer); if (NS_SUCCEEDED(res) && encodedBuffer) { charsWritten = nsCRT::strlen(encodedBuffer); @@ -340,7 +340,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) else { charsWritten = aString.Length(); - out.write(nsPromiseFlatString(aString).get(), charsWritten); + out.write(PromiseFlatString(aString).get(), charsWritten); } } @@ -348,7 +348,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) else { charsWritten = aString.Length(); - out.write(nsPromiseFlatString(aString).get(), charsWritten); + out.write(PromiseFlatString(aString).get(), charsWritten); } return charsWritten; diff --git a/htmlparser/src/nsLoggingSink.cpp b/htmlparser/src/nsLoggingSink.cpp index 39fcbd135908..2d96fb141d8c 100644 --- a/htmlparser/src/nsLoggingSink.cpp +++ b/htmlparser/src/nsLoggingSink.cpp @@ -711,7 +711,7 @@ nsLoggingSink::QuoteText(const nsAReadableString& aValue, nsString& aResult) { /* if you're stepping through the string anyway, why not use iterators instead of forcing the string to copy? */ - nsPromiseFlatString flat(aValue); + const nsPromiseFlatString& flat = PromiseFlatString(aValue); const PRUnichar* cp = flat.get(); const PRUnichar* end = cp + aValue.Length(); while (cp < end) { diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index 99096970dbd9..1cb1dfd94a56 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -1219,13 +1219,13 @@ private: }; // class to export a JSString as an nsAReadableString, including refcounting -class XPCReadableJSStringWrapper : public nsLiteralString +class XPCReadableJSStringWrapper : public nsLocalString { public: XPCReadableJSStringWrapper(JSString *str) : - nsLiteralString(NS_REINTERPRET_CAST(PRUnichar *, - JS_GetStringChars(str)), - JS_GetStringLength(str)), + nsLocalString(NS_REINTERPRET_CAST(PRUnichar *, + JS_GetStringChars(str)), + JS_GetStringLength(str)), mStr(str), mBufferHandle(0), mHandleIsShared(JS_FALSE) { } diff --git a/mailnews/import/oexpress/nsOEScanBoxes.cpp b/mailnews/import/oexpress/nsOEScanBoxes.cpp index f29516e1a269..7e0ee433d97b 100644 --- a/mailnews/import/oexpress/nsOEScanBoxes.cpp +++ b/mailnews/import/oexpress/nsOEScanBoxes.cpp @@ -280,7 +280,7 @@ PRBool nsOEScanBoxes::FindMailBoxes( nsIFileSpec* descFile) #endif pEntry->fileName.Right( ext, 4); - if (ext.Compare( mbxExt)) + if (Compare(ext, mbxExt)) pEntry->fileName.Append( ".mbx"); m_entryArray.AppendElement( pEntry); diff --git a/parser/htmlparser/src/nsHTMLContentSinkStream.cpp b/parser/htmlparser/src/nsHTMLContentSinkStream.cpp index ceca3c146929..ee2eab6fef08 100644 --- a/parser/htmlparser/src/nsHTMLContentSinkStream.cpp +++ b/parser/htmlparser/src/nsHTMLContentSinkStream.cpp @@ -289,7 +289,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) { nsresult res; PRUnichar *encodedBuffer = nsnull; - res = mEntityConverter->ConvertToEntities(nsPromiseFlatString(aString).get(), + res = mEntityConverter->ConvertToEntities(PromiseFlatString(aString).get(), nsIEntityConverter::html40Latin1, &encodedBuffer); if (NS_SUCCEEDED(res) && encodedBuffer) @@ -328,7 +328,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) { // Call the converter to convert to the target charset. // Convert() takes a char* output param even though it's writing unicode. - res = mCharsetEncoder->Convert(nsPromiseFlatString(aString).get(), &encodedBuffer); + res = mCharsetEncoder->Convert(PromiseFlatString(aString).get(), &encodedBuffer); if (NS_SUCCEEDED(res) && encodedBuffer) { charsWritten = nsCRT::strlen(encodedBuffer); @@ -340,7 +340,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) else { charsWritten = aString.Length(); - out.write(nsPromiseFlatString(aString).get(), charsWritten); + out.write(PromiseFlatString(aString).get(), charsWritten); } } @@ -348,7 +348,7 @@ PRInt32 nsHTMLContentSinkStream::Write(const nsAReadableString& aString) else { charsWritten = aString.Length(); - out.write(nsPromiseFlatString(aString).get(), charsWritten); + out.write(PromiseFlatString(aString).get(), charsWritten); } return charsWritten; diff --git a/parser/htmlparser/src/nsLoggingSink.cpp b/parser/htmlparser/src/nsLoggingSink.cpp index 39fcbd135908..2d96fb141d8c 100644 --- a/parser/htmlparser/src/nsLoggingSink.cpp +++ b/parser/htmlparser/src/nsLoggingSink.cpp @@ -711,7 +711,7 @@ nsLoggingSink::QuoteText(const nsAReadableString& aValue, nsString& aResult) { /* if you're stepping through the string anyway, why not use iterators instead of forcing the string to copy? */ - nsPromiseFlatString flat(aValue); + const nsPromiseFlatString& flat = PromiseFlatString(aValue); const PRUnichar* cp = flat.get(); const PRUnichar* end = cp + aValue.Length(); while (cp < end) { diff --git a/string/README.html b/string/README.html index c042892a33ec..eb54a3df1946 100644 --- a/string/README.html +++ b/string/README.html @@ -21,11 +21,9 @@ - Scott Collins (original author) --> -

string code will be moving here soon

+

managing sequences of characters

- The string code will be moving here soon; - in the meantime, you can find the bulk of it in - mozilla/xpcom/ds. +

diff --git a/string/doc/README.html b/string/doc/README.html index af9eee88be5a..e9a28f949ae5 100644 --- a/string/doc/README.html +++ b/string/doc/README.html @@ -21,7 +21,7 @@ - Scott Collins (original author) --> -

string doc will be moving here soon

+

documentation aimed at programmers who are clients of the string library

diff --git a/string/macbuild/string.mcp b/string/macbuild/string.mcp index b37d99192d8e..4c5de2c6d35a 100644 Binary files a/string/macbuild/string.mcp and b/string/macbuild/string.mcp differ diff --git a/string/obsolete/nsStr.cpp b/string/obsolete/nsStr.cpp index 87bf47bcdfb6..d35159aeb276 100644 --- a/string/obsolete/nsStr.cpp +++ b/string/obsolete/nsStr.cpp @@ -17,10 +17,8 @@ * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Original Author: - * Rick Gessner - * * Contributor(s): + * Rick Gessner (original author) * Scott Collins */ diff --git a/string/obsolete/nsString.cpp b/string/obsolete/nsString.cpp index d8c2f865bc1e..2bad4c8dbb6e 100644 --- a/string/obsolete/nsString.cpp +++ b/string/obsolete/nsString.cpp @@ -42,6 +42,11 @@ static const char* kPossibleNull = "Error: possible unintended null in string"; static const char* kNullPointerError = "Error: unexpected null ptr"; static const char* kWhitespace="\b\t\r\n "; +const nsBufferHandle* +nsCString::GetFlatBufferHandle() const + { + return NS_REINTERPRET_CAST(const nsBufferHandle*, 1); + } static void CSubsume(nsStr& aDest,nsStr& aSource){ if(aSource.mStr && aSource.mLength) { @@ -165,7 +170,7 @@ char* nsCString::GetWritableFragment( nsWritableFragment& aFragment, nsFra } } -nsCString::nsCString( const nsAReadableCString& aReadable ) { +nsCString::nsCString( const nsACString& aReadable ) { Initialize(*this,eOneByte); Assign(aReadable); } @@ -774,7 +779,7 @@ void nsCString::AssignWithConversion( const nsString& aString ) { AssignWithConversion(aString.GetUnicode(), aString.Length()); } -void nsCString::AssignWithConversion( const nsAReadableString& aString ) { +void nsCString::AssignWithConversion( const nsAString& aString ) { nsStr::StrTruncate(*this,0); PRInt32 count = aString.Length(); @@ -792,13 +797,13 @@ void nsCString::AssignWithConversion( const nsAReadableString& aString ) { temp.mLength=fraglen; StrAppend(*this,temp,0,fraglen); - - start += fraglen; + + start.advance(fraglen); } } } -void nsCString::AppendWithConversion( const nsAReadableString& aString ) { +void nsCString::AppendWithConversion( const nsAString& aString ) { PRInt32 count = aString.Length(); if(count){ @@ -816,7 +821,7 @@ void nsCString::AppendWithConversion( const nsAReadableString& aString ) { StrAppend(*this,temp,0,fraglen); - start += fraglen; + start.advance(fraglen); } } } @@ -832,14 +837,6 @@ void nsCString::AssignWithConversion(PRUnichar aChar) { AppendWithConversion(aChar); } -void nsCString::do_AppendFromReadable( const nsAReadableCString& aReadable ) - { - if ( SameImplementation( NS_STATIC_CAST(const nsAReadableCString&, *this), aReadable) ) - StrAppend(*this, NS_STATIC_CAST(const nsCString&, aReadable), 0, aReadable.Length()); - else - nsAWritableCString::do_AppendFromReadable(aReadable); - } - /** * append given char to this string @@ -962,14 +959,6 @@ void nsCString::InsertWithConversion(PRUnichar aChar,PRUint32 anOffset){ StrInsert(*this,anOffset,temp,0,1); } -void nsCString::do_InsertFromReadable( const nsAReadableCString& aReadable, PRUint32 atPosition ) - { - if ( SameImplementation( NS_STATIC_CAST(const nsAReadableCString&, *this), aReadable) ) - StrInsert(*this, atPosition, NS_STATIC_CAST(const nsCString&, aReadable), 0, aReadable.Length()); - else - nsAWritableCString::do_InsertFromReadable(aReadable, atPosition); - } - @@ -1382,7 +1371,7 @@ void nsCString::DebugDump(void) const { //---------------------------------------------------------------------- -NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAReadableString& aString ) +NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAString& aString ) { nsReadingIterator start; aString.BeginReading(start); nsReadingIterator end; aString.EndReading(end); @@ -1390,7 +1379,7 @@ NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAReadableString& aString ) while (start != end) { nsReadableFragment frag(start.fragment()); Append(frag.mStart, frag.mEnd - frag.mStart); - start += start.size_forward(); + start.advance(start.size_forward()); } } @@ -1511,7 +1500,7 @@ nsCAutoString::nsCAutoString( const nsCString& aString ) : nsCString(){ Append(aString); } -nsCAutoString::nsCAutoString( const nsAReadableCString& aString ) : nsCString(){ +nsCAutoString::nsCAutoString( const nsACString& aString ) : nsCString(){ Initialize(*this,mBuffer,sizeof(mBuffer)-1,0,eOneByte,PR_FALSE); AddNullTerminator(*this); Append(aString); diff --git a/string/obsolete/nsString.h b/string/obsolete/nsString.h index 42496342a17e..9bf13d1f692d 100644 --- a/string/obsolete/nsString.h +++ b/string/obsolete/nsString.h @@ -50,17 +50,27 @@ #include "nsStr.h" #include "nsIAtom.h" +#include "nsAString.h" + +/* this file will one day be _only_ a compatibility header for clients using the names + |ns[C]String| et al ... which we probably want to support forever. + In the mean time, people are used to getting the names |nsAReadable[C]String| and friends + from here as well; so we must continue to include the other compatibility headers + even though we don't use them ourself. + */ + #include "nsAWritableString.h" + // for compatibility class NS_COM nsSubsumeCStr; class NS_COM nsCString : - public nsAWritableCString, + public nsAFlatCString, public nsStr { protected: - virtual const void* Implementation() const { return "nsCString"; } + virtual const nsBufferHandle* GetFlatBufferHandle() const; virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); @@ -79,7 +89,7 @@ public: */ nsCString(const nsCString& aString); - explicit nsCString( const nsAReadableCString& ); + explicit nsCString( const nsACString& ); explicit nsCString(const char*); nsCString(const char*, PRInt32); @@ -298,14 +308,14 @@ public: */ nsCString& operator=( const nsCString& aString ) { Assign(aString); return *this; } - nsCString& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsCString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsCString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +//nsCString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsCString& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsCString& operator=( char aChar ) { Assign(aChar); return *this; } void AssignWithConversion(const PRUnichar*,PRInt32=-1); void AssignWithConversion( const nsString& aString ); - void AssignWithConversion( const nsAReadableString& aString ); + void AssignWithConversion( const nsAString& aString ); void AssignWithConversion(PRUnichar); /* @@ -320,18 +330,20 @@ public: void AppendWithConversion(const nsString&, PRInt32=-1); void AppendWithConversion(PRUnichar aChar); - void AppendWithConversion( const nsAReadableString& aString ); + void AppendWithConversion( const nsAString& aString ); void AppendWithConversion(const PRUnichar*, PRInt32=-1); // Why no |AppendWithConversion(const PRUnichar*, PRInt32)|? --- now I know, because implicit construction hid the need for this routine void AppendInt(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16 void AppendFloat( double aFloat ); - virtual void do_AppendFromReadable( const nsAReadableCString& ); void InsertWithConversion(PRUnichar aChar,PRUint32 anOffset); // Why no |InsertWithConversion(PRUnichar*)|? - virtual void do_InsertFromReadable( const nsAReadableCString&, PRUint32 ); +#if 0 + virtual void do_AppendFromReadable( const nsACString& ); + virtual void do_InsertFromReadable( const nsACString&, PRUint32 ); +#endif /********************************************************************** @@ -446,7 +458,7 @@ private: }; // NS_DEF_STRING_COMPARISON_OPERATORS(nsCString, char) -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCString, char) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCString, char) extern NS_COM int fputs(const nsCString& aString, FILE* out); //ostream& operator<<(ostream& aStream,const nsCString& aString); @@ -466,7 +478,7 @@ public: nsCAutoString(); explicit nsCAutoString(const nsCString& ); - explicit nsCAutoString(const nsAReadableCString& aString); + explicit nsCAutoString(const nsACString& aString); explicit nsCAutoString(const char* aString); nsCAutoString(const char* aString,PRInt32 aLength); explicit nsCAutoString(const CBufDescriptor& aBuffer); @@ -482,8 +494,8 @@ public: private: void operator=( PRUnichar ); // NOT TO BE IMPLEMENTED public: - nsCAutoString& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsCAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsCAutoString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +// nsCAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsCAutoString& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsCAutoString& operator=( char aChar ) { Assign(aChar); return *this; } @@ -496,7 +508,7 @@ public: char mBuffer[kDefaultStringSize]; }; -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCAutoString, char) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCAutoString, char) /** * A helper class that converts a UCS2 string to UTF8 @@ -525,7 +537,7 @@ class NS_COM NS_ConvertUCS2toUTF8 Append( &aChar, 1 ); } - explicit NS_ConvertUCS2toUTF8( const nsAReadableString& aString ); + explicit NS_ConvertUCS2toUTF8( const nsAString& aString ); protected: void Append( const PRUnichar* aString, PRUint32 aLength ); @@ -533,7 +545,7 @@ class NS_COM NS_ConvertUCS2toUTF8 private: // NOT TO BE IMPLEMENTED NS_ConvertUCS2toUTF8( char ); - operator const char*() const; // use |get()| + operator const char*() const; // use |get()| }; @@ -557,8 +569,8 @@ public: nsSubsumeCStr(char* aString,PRBool assumeOwnership,PRInt32 aLength=-1); nsSubsumeCStr& operator=( const nsSubsumeCStr& aString ) { Assign(aString); return *this; } - nsSubsumeCStr& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsSubsumeCStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsSubsumeCStr& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +//nsSubsumeCStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsSubsumeCStr& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsSubsumeCStr& operator=( char aChar ) { Assign(aChar); return *this; } private: diff --git a/string/obsolete/nsString2.cpp b/string/obsolete/nsString2.cpp index b85fdbe9af10..b6d9a0d3dd98 100644 --- a/string/obsolete/nsString2.cpp +++ b/string/obsolete/nsString2.cpp @@ -39,6 +39,13 @@ static const char* kPossibleNull = "Error: possible unintended null in string"; static const char* kNullPointerError = "Error: unexpected null ptr"; static const char* kWhitespace="\b\t\r\n "; +const nsBufferHandle* +nsString::GetFlatBufferHandle() const + { + return NS_REINTERPRET_CAST(const nsBufferHandle*, 1); + } + + static void Subsume(nsStr& aDest,nsStr& aSource){ if(aSource.mStr && aSource.mLength) { @@ -165,7 +172,7 @@ nsString::do_AppendFromElement( PRUnichar inChar ) } -nsString::nsString( const nsAReadableString& aReadable ) { +nsString::nsString( const nsAString& aReadable ) { Initialize(*this,eTwoByte); Assign(aReadable); } @@ -1647,7 +1654,7 @@ nsAutoString::nsAutoString( const nsString& aString ) Append(aString); } -nsAutoString::nsAutoString( const nsAReadableString& aString ) +nsAutoString::nsAutoString( const nsAString& aString ) : nsString() { Initialize(*this, mBuffer, (sizeof(mBuffer)>>eTwoByte)-1, 0, eTwoByte, PR_FALSE); diff --git a/string/obsolete/nsString2.h b/string/obsolete/nsString2.h index f2ae0dbca658..d7698322cd22 100644 --- a/string/obsolete/nsString2.h +++ b/string/obsolete/nsString2.h @@ -52,11 +52,12 @@ #include "nsStr.h" #include "nsCRT.h" -#include "nsAWritableString.h" +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif #ifdef STANDALONE_MI_STRING_TESTS - class nsAReadableString { public: virtual ~nsAReadableString() { } }; - class nsAWritableString : public nsAReadableString { public: virtual ~nsAWritableString() { } }; + class nsAFlatString { public: virtual ~nsAString() { } }; #endif class nsISizeOfHandler; @@ -68,11 +69,11 @@ class nsISizeOfHandler; class NS_COM nsSubsumeStr; class NS_COM nsString : - public nsAWritableString, + public nsAFlatString, public nsStr { protected: - virtual const void* Implementation() const { return "nsString"; } + virtual const nsBufferHandle* GetFlatBufferHandle() const; virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); @@ -91,7 +92,7 @@ public: */ nsString(const nsString& aString); - explicit nsString(const nsAReadableString&); + explicit nsString(const nsAString&); explicit nsString(const PRUnichar*); nsString(const PRUnichar*, PRInt32); @@ -342,8 +343,8 @@ public: */ nsString& operator=( const nsString& aString ) { Assign(aString); return *this; } - nsString& operator=( const nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - nsString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +//nsString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsString& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } @@ -526,7 +527,7 @@ private: }; // NS_DEF_STRING_COMPARISON_OPERATORS(nsString, PRUnichar) -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsString, PRUnichar) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsString, PRUnichar) extern NS_COM int fputs(const nsString& aString, FILE* out); //ostream& operator<<(ostream& aStream,const nsString& aString); @@ -544,7 +545,7 @@ public: virtual ~nsAutoString(); nsAutoString(); nsAutoString(const nsAutoString& aString); - explicit nsAutoString(const nsAReadableString& aString); + explicit nsAutoString(const nsAString& aString); explicit nsAutoString(const nsString& aString); explicit nsAutoString(const PRUnichar* aString); nsAutoString(const PRUnichar* aString,PRInt32 aLength); @@ -562,8 +563,8 @@ public: private: void operator=( char ); // NOT TO BE IMPLEMENTED public: - nsAutoString& operator=( const nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - nsAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsAutoString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +// nsAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsAutoString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsAutoString& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } @@ -576,7 +577,7 @@ public: char mBuffer[kDefaultStringSize<& aReadable ) { Assign(aReadable); return *this; } + nsSubsumeStr& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +//nsSubsumeStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsSubsumeStr& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsSubsumeStr& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } private: diff --git a/string/public/MANIFEST b/string/public/MANIFEST index 6a48cc1b8c08..cb9a692fd76b 100644 --- a/string/public/MANIFEST +++ b/string/public/MANIFEST @@ -21,15 +21,29 @@ # +nsAFlatString.h nsAlgorithm.h +nsAPromiseString.h nsAReadableString.h +nsAString.h nsAWritableString.h nsBufferHandle.h nsBufferHandleUtils.h nsCharTraits.h +nsCommonString.h nsFragmentedString.h +nsLiteralString.h +nsLocalString.h nsPrintfCString.h nsPrivateSharableString.h +nsPromiseConcatenation.h +nsPromiseFlatString.h +nsPromiseSubstring.h nsReadableUtils.h nsSharedBufferList.h nsSlidingString.h +nsStringFragment.h +nsStringFwd.h +nsStringIterator.h +nsStringIteratorUtils.h +nsStringTraits.h diff --git a/string/public/Makefile.in b/string/public/Makefile.in index 3fd4a987aafc..8d13477a3b6e 100644 --- a/string/public/Makefile.in +++ b/string/public/Makefile.in @@ -18,6 +18,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH = ../.. @@ -30,18 +31,32 @@ include $(DEPTH)/config/autoconf.mk MODULE = string EXPORTS = \ + nsAFlatString.h \ nsAlgorithm.h \ - nsBufferHandle.h \ - nsBufferHandleUtils.h \ - nsPrivateSharableString.h \ + nsAPromiseString.h \ + nsAReadableString.h \ + nsAString.h \ + nsAWritableString.h \ + nsBufferHandle.h \ + nsBufferHandleUtils.h \ nsCharTraits.h \ - nsAReadableString.h \ - nsAWritableString.h \ - nsReadableUtils.h \ - nsSharedBufferList.h \ - nsSlidingString.h \ - nsFragmentedString.h \ - nsPrintfCString.h \ + nsCommonString.h \ + nsFragmentedString.h \ + nsLiteralString.h \ + nsLocalString.h \ + nsPrintfCString.h \ + nsPrivateSharableString.h \ + nsPromiseConcatenation.h \ + nsPromiseFlatString.h \ + nsPromiseSubstring.h \ + nsReadableUtils.h \ + nsSharedBufferList.h \ + nsSlidingString.h \ + nsStringFragment.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsStringIteratorUtils.h \ + nsStringTraits.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/string/public/makefile.win b/string/public/makefile.win index 3d819cedb8da..37f2222ac6cc 100644 --- a/string/public/makefile.win +++ b/string/public/makefile.win @@ -19,23 +19,38 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH=..\.. EXPORTS = \ + nsAFlatString.h \ nsAlgorithm.h \ + nsAPromiseString.h \ nsAReadableString.h \ + nsAString.h \ nsAWritableString.h \ nsBufferHandle.h \ nsBufferHandleUtils.h \ nsCharTraits.h \ + nsCommonString.h \ nsFragmentedString.h \ + nsLiteralString.h \ + nsLocalString.h \ nsPrintfCString.h \ nsPrivateSharableString.h \ + nsPromiseConcatenation.h \ + nsPromiseFlatString.h \ + nsPromiseSubstring.h \ nsReadableUtils.h \ nsSharedBufferList.h \ nsSlidingString.h \ + nsStringFragment.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsStringIteratorUtils.h \ + nsStringTraits.h \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/string/public/nsAFlatString.h b/string/public/nsAFlatString.h new file mode 100644 index 000000000000..6cb6d9f4a655 --- /dev/null +++ b/string/public/nsAFlatString.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsAFlatString.h --- */ + +#ifndef nsAFlatString_h___ +#define nsAFlatString_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +class NS_COM nsAFlatString + : public nsAString + { + public: + // don't really want this to be virtual, and won't after |obsolete_nsString| is really dead + virtual const PRUnichar* get() const { return GetBufferHandle()->DataStart(); } + PRUnichar operator[]( PRUint32 i ) const { return get()[ i ]; } + PRUnichar CharAt( PRUint32 ) const; + + virtual PRUint32 Length() const { return PRUint32(GetBufferHandle()->DataLength()); } + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + }; + +class NS_COM nsAFlatCString + : public nsACString + { + public: + // don't really want this to be virtual, and won't after |obsolete_nsCString| is really dead + virtual const char* get() const { return GetBufferHandle()->DataStart(); } + char operator[]( PRUint32 i ) const { return get()[ i ]; } + char CharAt( PRUint32 ) const; + + virtual PRUint32 Length() const { return PRUint32(GetBufferHandle()->DataLength()); } + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + }; + +inline +PRUnichar +nsAFlatString::CharAt( PRUint32 i ) const + { + NS_ASSERTION(i (original author) + */ + +/* nsAPromiseString.h --- abstract base class for strings don't actually own their own characters, but proxy data from other strings */ + +#ifndef nsAPromiseString_h___ +#define nsAPromiseString_h___ + + /** + * Don't |#include| this file yourself. You will get it automatically if you need it. + * + * Why is it a separate file? To make it easier to find the classes in your local tree. + */ + +class NS_COM nsAPromiseString : public nsAString { }; +class NS_COM nsAPromiseCString : public nsACString { }; + +#endif /* !defined(nsAPromiseString_h___) */ diff --git a/string/public/nsAReadableString.h b/string/public/nsAReadableString.h index ffe22945c360..67663b505c13 100644 --- a/string/public/nsAReadableString.h +++ b/string/public/nsAReadableString.h @@ -21,1550 +21,34 @@ * Scott Collins (original author) */ +/* nsAReadableString.h --- a compatibility header for clients still using the names |nsAReadable[C]String| et al */ + #ifndef nsAReadableString_h___ #define nsAReadableString_h___ -#ifndef nscore_h___ -#include "nscore.h" - // for |PRUnichar| +#ifndef nsAString_h___ +#include "nsAString.h" #endif -#ifndef nsCharTraits_h___ -#include "nsCharTraits.h" +typedef const nsAString nsAReadableString; +typedef const nsACString nsAReadableCString; + +#ifndef nsLiteralString_h___ +#include "nsLiteralString.h" #endif -#ifndef nsAlgorithm_h___ -#include "nsAlgorithm.h" - // for |NS_MIN|, |NS_MAX|, and |NS_COUNT|... +#ifndef nsPromiseSubstring_h___ +#include "nsPromiseSubstring.h" #endif -#ifndef nsPrivateSharableString_h___ -#include "nsPrivateSharableString.h" +#ifndef nsPromiseFlatString_h___ +#include "nsPromiseFlatString.h" #endif -#include "nsMemory.h" - -/* - This file defines the abstract interfaces |nsAReadableString| and - |nsAReadableCString| (the 'A' is for 'abstract', as opposed to the 'I' in - [XP]COM interface names). - - These types are intended to be as source compatible as possible with the original - definitions of |const nsString&| and |const nsCString&|, respectively. In otherwords, - these interfaces provide only non-mutating access to the underlying strings. We - split the these interfaces out from the mutating parts (see - "nsAWritableString.h") because tests showed that we could exploit specialized - implementations in some areas; we need an abstract interface to bring the whole - family of strings together. - - |nsAReadableString| is a string of |PRUnichar|s. |nsAReadableCString| (note the - 'C') is a string of |char|s. -*/ - -enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; - -template -struct nsReadableFragment - { - const CharT* mStart; - const CharT* mEnd; - const void* mFragmentIdentifier; - - nsReadableFragment() - : mStart(0), mEnd(0), mFragmentIdentifier(0) - { - // nothing else to do here - } - }; - -template class basic_nsAReadableString; - -template class basic_nsAWritableString; - // ...because we sometimes use them as `out' params - -#ifdef _MSC_VER - // Under VC++, at the highest warning level, we are overwhelmed with warnings - // about a possible error when |operator->()| is used against something that - // doesn't have members, e.g., a |PRUnichar|. This is to be expected with - // templates, so we disable the warning. - #pragma warning( disable: 4284 ) -#endif - -template -class nsReadingIterator -// : public bidirectional_iterator_tag - { - public: - typedef ptrdiff_t difference_type; - typedef CharT value_type; - typedef const CharT* pointer; - typedef const CharT& reference; -// typedef bidirectional_iterator_tag iterator_category; - - private: - friend class basic_nsAReadableString; - - nsReadableFragment mFragment; - const CharT* mPosition; - const basic_nsAReadableString* mOwningString; - - nsReadingIterator( const nsReadableFragment& aFragment, - const CharT* aStartingPosition, - const basic_nsAReadableString& aOwningString ) - : mFragment(aFragment), - mPosition(aStartingPosition), - mOwningString(&aOwningString) - { - // nothing else to do here - } - - public: - nsReadingIterator() { } - // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK - // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK - - inline void normalize_forward(); - inline void normalize_backward(); - - pointer - get() const - { - return mPosition; - } - - CharT - operator*() const - { - return *get(); - } - -#if 0 - // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) - // don't like this when |CharT| is a type without members. - pointer - operator->() const - { - return get(); - } -#endif - - nsReadingIterator& - operator++() - { - ++mPosition; - normalize_forward(); - return *this; - } - - nsReadingIterator - operator++( int ) - { - nsReadingIterator result(*this); - ++mPosition; - normalize_forward(); - return result; - } - - nsReadingIterator& - operator--() - { - normalize_backward(); - --mPosition; - return *this; - } - - nsReadingIterator - operator--( int ) - { - nsReadingIterator result(*this); - normalize_backward(); - --mPosition; - return result; - } - - const nsReadableFragment& - fragment() const - { - return mFragment; - } - - const basic_nsAReadableString& - string() const - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - difference_type - size_forward() const - { - return mFragment.mEnd - mPosition; - } - - difference_type - size_backward() const - { - return mPosition - mFragment.mStart; - } - - nsReadingIterator& - 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; - } - - /** - * Really don't want to call these two operations |+=| and |-=|. - * Would prefer a single function, e.g., |advance|, which doesn't imply a constant time operation. - * - * We'll get rid of these as soon as we can. - */ - nsReadingIterator& - operator+=( difference_type n ) // deprecated - { - return advance(n); - } - - nsReadingIterator& - operator-=( difference_type n ) // deprecated - { - return advance(-n); - } - }; - -#if 0 -template -nsReadingIterator& -nsReadingIterator::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; - } -#endif - - // NOTE: need to break iterators out into their own file (as with many classes here), need - // these routines, but can't currently |#include "nsReadableUtils.h"|, this hack is bad - // but we need it to get OS2 building again. Fix by splitting things into different files. -NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); -NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); - -template -inline -PRBool -SameFragment( const Iterator& lhs, const Iterator& rhs ) - { - return lhs.fragment().mStart == rhs.fragment().mStart; - } - - - // - // nsAReadable[C]String - // - -template -class basic_nsAReadableString - : public nsPrivateSharableString - { - public: - typedef CharT char_type; - typedef PRUint32 size_type; - typedef PRUint32 index_type; - - typedef nsReadingIterator const_iterator; - - - // basic_nsAReadableString(); // auto-generated default constructor OK (we're abstract anyway) - // basic_nsAReadableString( const basic_nsAReadableString& ); // auto-generated copy-constructor OK (again, only because we're abstract) - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsAReadableString& ); // but assignment is _not_ OK (we're immutable) so make it impossible - - public: - virtual ~basic_nsAReadableString() { } - // ...yes, I expect to be sub-classed. - - nsReadingIterator& BeginReading( nsReadingIterator& ) const; - nsReadingIterator& EndReading( nsReadingIterator& ) const; - - virtual PRUint32 Length() const = 0; - PRBool IsEmpty() const; - - /** - * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. - * These signatures should be pushed down into interfaces that guarantee flat allocation. - * Clients at _this_ level should always use iterators. - */ - CharT CharAt( PRUint32 ) const; - CharT operator[]( PRUint32 ) const; - CharT First() const; - CharT Last() const; - - PRUint32 CountChar( CharT ) const; - - - /* - |Left|, |Mid|, and |Right| are annoying signatures that seem better almost - any _other_ way than they are now. Consider these alternatives - - aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| - aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| - Left(aReadable, 17, aWritable); // ...a global function that does the assignment - - as opposed to the current signature - - aReadable.Left(aWritable, 17); // ...a member function that does the assignment - - or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality - - aWritable = Substring(aReadable, 0, 17); - */ - - PRUint32 Left( basic_nsAWritableString&, PRUint32 ) const; - PRUint32 Mid( basic_nsAWritableString&, PRUint32, PRUint32 ) const; - PRUint32 Right( basic_nsAWritableString&, PRUint32 ) const; - - // Find( ... ) const; - PRInt32 FindChar( CharT, PRUint32 aOffset = 0 ) const; - // FindCharInSet( ... ) const; - // RFind( ... ) const; - // RFindChar( ... ) const; - // RFindCharInSet( ... ) const; - - - int Compare( const basic_nsAReadableString& rhs ) const; - int Compare( const CharT* ) const; -// int Compare( const CharT*, PRUint32 ) const; -// int Compare( CharT ) const; - - // |Equals()| is a synonym for |Compare()| - PRBool Equals( const basic_nsAReadableString& rhs ) const; - PRBool Equals( const CharT* ) const; -// PRBool Equals( const CharT*, PRUint32 ) const; -// PRBool Equals( CharT ) const; - - // Comparison operators are all synonyms for |Compare()| - PRBool operator!=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)!=0; } - PRBool operator< ( const basic_nsAReadableString& rhs ) const { return Compare(rhs)< 0; } - PRBool operator<=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)<=0; } - PRBool operator==( const basic_nsAReadableString& rhs ) const { return Compare(rhs)==0; } - PRBool operator>=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)>=0; } - PRBool operator> ( const basic_nsAReadableString& rhs ) const { return Compare(rhs)> 0; } - - - /* - Shouldn't be implemented because they're i18n sensitive. - Let's leave them in |nsString| for now. - */ - - // ToLowerCase - // ToUpperCase - // EqualsIgnoreCase - // IsASCII - // IsSpace - // IsAlpha - // IsDigit - // ToFloat - // ToInteger - - // char* ToNewCString() const; - // char* ToNewUTF8String() const; - // PRUnichar* ToNewUnicode() const; - // char* ToCString( char*, PRUint32, PRUint32 ) const; - - - /* - Shouldn't be implemented because it's wrong duplication. - Let's leave it in |nsString| for now. - */ - - // nsString* ToNewString() const; - // NO! The right way to say this is |new nsString( fromAReadableString )| - - - /* - Shouldn't be implemented because they're not generally applicable. - Let's leave them in |nsString| for now. - */ - - // IsOrdered - // BinarySearch - - // protected: - virtual const void* Implementation() const; - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; - virtual PRBool Promises( const basic_nsAReadableString& aString ) const { return &aString == this; } -// virtual PRBool PromisesExactly( const basic_nsAReadableString& aString ) const { return false; } - - private: - // NOT TO BE IMPLEMENTED - typedef typename nsCharTraits::incompatible_char_type incompatible_char_type; - PRUint32 CountChar( incompatible_char_type ) const; -// in Compare( incompatible_char_type ) const; -// PRBool Equals( incompatible_char_type ) const; - }; - - /* - The following macro defines a cast that helps us solve type-unification error problems on compilers - with poor template support. String clients probably _never_ need to use it. String implementors - sometimes will. - */ - #ifdef NEED_CPP_TEMPLATE_CAST_TO_BASE -#define NS_READABLE_CAST(CharT, expr) (NS_STATIC_CAST(const basic_nsAReadableString&, (expr))) +#define NS_READABLE_CAST(CharT, expr) (NS_STATIC_CAST(const nsStringTraits::abstract_string_type&, (expr))) #else #define NS_READABLE_CAST(CharT, expr) (expr) #endif -template -inline -void -nsReadingIterator::normalize_forward() - { - while ( mPosition == mFragment.mEnd - && mOwningString->GetReadableFragment(mFragment, kNextFragment) ) - mPosition = mFragment.mStart; - } - -template -inline -void -nsReadingIterator::normalize_backward() - { - while ( mPosition == mFragment.mStart - && mOwningString->GetReadableFragment(mFragment, kPrevFragment) ) - mPosition = mFragment.mEnd; - } - - /** - * Note: measure -- should the |BeginReading| and |EndReading| be |inline|? - */ -template -inline -nsReadingIterator& -basic_nsAReadableString::BeginReading( nsReadingIterator& aResult ) const - { - aResult.mOwningString = this; - GetReadableFragment(aResult.mFragment, kFirstFragment); - aResult.mPosition = aResult.mFragment.mStart; - aResult.normalize_forward(); - return aResult; - } - -template -inline -nsReadingIterator& -basic_nsAReadableString::EndReading( nsReadingIterator& aResult ) const - { - aResult.mOwningString = this; - GetReadableFragment(aResult.mFragment, kLastFragment); - aResult.mPosition = aResult.mFragment.mEnd; - // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| - return aResult; - } - -template -inline -PRBool -basic_nsAReadableString::IsEmpty() const - { - return Length() == 0; - } - -template -inline -PRBool -basic_nsAReadableString::Equals( const basic_nsAReadableString& rhs ) const - { - return Length() == rhs.Length() && Compare(rhs) == 0; - } - -template -inline -PRBool -operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) - { - return lhs.get() == rhs.get(); - } - -template -inline -PRBool -operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) - { - return lhs.get() != rhs.get(); - } - - -#define NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _StringT& lhs, const _CharT* rhs ) \ - { \ - return PRBool(Compare(NS_READABLE_CAST(_CharT, lhs), rhs) comp 0); \ - } - -#define NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _CharT* lhs, const _StringT& rhs ) \ - { \ - return PRBool(Compare(lhs, NS_READABLE_CAST(_CharT, rhs)) comp 0); \ - } - -#define NS_DEF_1_STRING_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _StringT& lhs, const _StringT& rhs ) \ - { \ - return PRBool(Compare(NS_READABLE_CAST(_CharT, lhs), NS_READABLE_CAST(_CharT, rhs)) comp 0); \ - } - -#define NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(comp, _StringT, _CharT) \ - template NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - template NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) - -#define NS_DEF_3_STRING_COMPARISON_OPERATORS(comp, _StringT, _CharT) \ - NS_DEF_1_STRING_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) - -#define NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(_StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(!=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(< , _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(<=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(==, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(>=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(> , _StringT, _CharT) - -#define NS_DEF_STRING_COMPARISON_OPERATORS(_StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(!=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(< , _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(<=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(==, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(>=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(> , _StringT, _CharT) - - -NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsAReadableString, CharT) - - - -template -const void* -basic_nsAReadableString::Implementation() const - { - return 0; - } - - - -template -CharT -basic_nsAReadableString::CharAt( PRUint32 aIndex ) const - { - NS_ASSERTION(aIndex iter; - return *(BeginReading(iter).advance(PRInt32(aIndex))); - } - -template -inline -CharT -basic_nsAReadableString::operator[]( PRUint32 aIndex ) const - { - return CharAt(aIndex); - } - -template -CharT -basic_nsAReadableString::First() const - { - NS_ASSERTION(Length()>0, "|First()| on an empty string"); - - nsReadingIterator iter; - return *BeginReading(iter); - } - -template -CharT -basic_nsAReadableString::Last() const - { - NS_ASSERTION(Length()>0, "|Last()| on an empty string"); - - nsReadingIterator iter; - EndReading(iter); - - if ( !IsEmpty() ) - iter.advance(-1); - - return *iter; // Note: this has undefined results if |IsEmpty()| - } - -template -PRUint32 -basic_nsAReadableString::CountChar( CharT c ) const - { -#if 0 - nsReadingIterator countBegin, countEnd; - return PRUint32(NS_COUNT(BeginReading(countBegin), EndReading(countEnd), c)); -#else - PRUint32 result = 0; - PRUint32 lengthToExamine = Length(); - - nsReadingIterator iter; - for ( BeginReading(iter); ; ) - { - PRInt32 lengthToExamineInThisFragment = iter.size_forward(); - const CharT* fromBegin = iter.get(); - result += PRUint32(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); - if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) - return result; - iter.advance(lengthToExamineInThisFragment); - } - // never reached; quiets warnings - return 0; -#endif - } - -#if 0 - // had to move these definitions into "nsAWritableString.h" -template -PRUint32 -basic_nsAReadableString::Mid( basic_nsAWritableString& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const - { - // If we're just assigning our entire self, give |aResult| the opportunity to share - if ( aStartPos == 0 && aLengthToCopy >= Length() ) - aResult = *this; - else - aResult = Substring(*this, aStartPos, aLengthToCopy); - - return aResult.Length(); - } - -template -inline -PRUint32 -basic_nsAReadableString::Left( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - return Mid(aResult, 0, aLengthToCopy); - } - -template -PRUint32 -basic_nsAReadableString::Right( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - PRUint32 myLength = Length(); - aLengthToCopy = NS_MIN(myLength, aLengthToCopy); - return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); - } -#endif - -template -PRInt32 -basic_nsAReadableString::FindChar( CharT aChar, PRUint32 aOffset ) const - { - nsReadingIterator iter, done_searching; - BeginReading(iter).advance( PRInt32(aOffset) ); - EndReading(done_searching); - - PRUint32 lengthSearched = 0; - while ( iter != done_searching ) - { - PRInt32 fragmentLength = iter.size_forward(); - const CharT* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); - if ( charFoundAt ) - return lengthSearched + (charFoundAt-iter.get()) + aOffset; - - lengthSearched += fragmentLength; - iter.advance(fragmentLength); - } - - return -1; - } - - - - - - - // - // nsLiteral[C]String - // - -template -class basic_nsLiteralString - : public basic_nsAReadableString - /* - ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. - - Use it like this: - - SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); - - With some tweaking, I think I can make this work as well... - - SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); - - This class just holds a pointer. If you don't supply the length, it must calculate it. - No copying or allocations are performed. - - |const basic_nsLiteralString&| appears frequently in interfaces because it - allows the automatic conversion of a |CharT*|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - - explicit - basic_nsLiteralString( const CharT* aLiteral ) - : mStart(aLiteral), - mEnd(mStart ? (mStart + nsCharTraits::length(mStart)) : mStart) - { - // nothing else to do here - } - - basic_nsLiteralString( const CharT* aLiteral, PRUint32 aLength ) - : mStart(aLiteral), - mEnd(mStart + aLength) - { - // This is an annoying hack. Callers should be fixed to use the other - // constructor if they don't really know the length. - if ( aLength == PRUint32(-1) ) - { -// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); - mEnd = mStart ? (mStart + nsCharTraits::length(mStart)) : mStart; - } - } - - // basic_nsLiteralString( const basic_nsLiteralString& ); // auto-generated copy-constructor OK - // ~basic_nsLiteralString(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsLiteralString& ); // we're immutable - - public: - - virtual PRUint32 Length() const; - - const CharT* get() const { return mStart; } - - // operator const CharT*() const; // use |get()| - - private: - const CharT* mStart; - const CharT* mEnd; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsLiteralString, CharT) - -template -const CharT* -basic_nsLiteralString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mStart = mStart; - aFragment.mEnd = mEnd; - return mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - -template -PRUint32 -basic_nsLiteralString::Length() const - { - return PRUint32(mEnd - mStart); - } - - -#if 0 -template -inline -PRBool -basic_nsAReadableString::Equals( const CharT* rhs, PRUint32 rhs_length ) const - { - return Compare(basic_nsLiteralString(rhs, rhs_length)) == 0; - } -#endif - -#if 0 -template -inline -int -basic_nsAReadableString::Compare( const CharT* rhs, PRUint32 rhs_length ) const - { - return ::Compare(*this, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs, rhs_length))); - } -#endif - - - // - // nsLiteralChar, nsLiteralPRUnichar - // - -template -class basic_nsLiteralChar - : public basic_nsAReadableString - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - - explicit - basic_nsLiteralChar( CharT aChar ) - : mChar(aChar) - { - // nothing else to do here - } - - // basic_nsLiteralChar( const basic_nsLiteralString& ); // auto-generated copy-constructor OK - // ~basic_nsLiteralChar(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsLiteralChar& ); // we're immutable - - public: - - virtual - PRUint32 - Length() const - { - return 1; - } - - private: - CharT mChar; - }; - -template -const CharT* -basic_nsLiteralChar::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mEnd = (aFragment.mStart = &mChar) + 1; - return aFragment.mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - - - - - - - // - // nsPromiseConcatenation - // - -template class nsPromiseReadable : public basic_nsAReadableString { }; - -template -class nsPromiseConcatenation - : public nsPromiseReadable - /* - NOT FOR USE BY HUMANS - - Instances of this class only exist as anonymous temporary results from |operator+()|. - This is the machinery that makes string concatenation efficient. No allocations or - character copies are required unless and until a final assignment is made. It works - its magic by overriding and forwarding calls to |GetReadableFragment()|. - - Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. - - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| - - left to right evaluation is required ... do not use parentheses to override this - - In practice, neither of these is onerous. Parentheses do not change the semantics of the - concatenation, only the order in which the result is assembled ... so there's no reason - for a user to need to control it. Too many strings summed together can easily be worked - around with an intermediate assignment. I wouldn't have the parentheses limitation if I - assigned the identifier mask starting at the top, the first time anybody called - |GetReadableFragment()|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - enum { kLeftString, kRightString }; - - int - GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const - { - return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; - } - - int - SetLeftStringInFragment( nsReadableFragment& aFragment ) const - { - aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); - return kLeftString; - } - - int - SetRightStringInFragment( nsReadableFragment& aFragment ) const - { - aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); - return kRightString; - } - - public: - nsPromiseConcatenation( const basic_nsAReadableString& aLeftString, const basic_nsAReadableString& aRightString, PRUint32 aMask = 1 ) - : mFragmentIdentifierMask(aMask) - { - mStrings[kLeftString] = &aLeftString; - mStrings[kRightString] = &aRightString; - } - - nsPromiseConcatenation( const nsPromiseConcatenation& aLeftString, const basic_nsAReadableString& aRightString ) - : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) - { - mStrings[kLeftString] = &aLeftString; - mStrings[kRightString] = &aRightString; - } - - // nsPromiseConcatenation( const nsPromiseConcatenation& ); // auto-generated copy-constructor should be OK - // ~nsPromiseConcatenation(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const nsPromiseConcatenation& ); // we're immutable, you can't assign into a concatenation - - public: - - virtual PRUint32 Length() const; - virtual PRBool Promises( const basic_nsAReadableString& ) const; -// virtual PRBool PromisesExactly( const basic_nsAReadableString& ) const; - -// nsPromiseConcatenation operator+( const basic_nsAReadableString& rhs ) const; - - PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } - - private: - void operator+( const nsPromiseConcatenation& ); // NOT TO BE IMPLEMENTED - // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| - // which would break the algorithm for distributing bits in the fragment identifier - - private: - const basic_nsAReadableString* mStrings[2]; - PRUint32 mFragmentIdentifierMask; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(nsPromiseConcatenation, CharT) - -template -PRUint32 -nsPromiseConcatenation::Length() const - { - return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); - } - -template -PRBool -nsPromiseConcatenation::Promises( const basic_nsAReadableString& aString ) const - { - return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); - } - -#if 0 -PRBool -nsPromiseConcatenation::PromisesExactly( const basic_nsAReadableString& aString ) const - { - // Not really like this, test for the empty string, etc - return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; - } -#endif - -template -const CharT* -nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const - { - int whichString; - - // based on the request, pick which string we will forward the |GetReadableFragment()| call into - - switch ( aRequest ) - { - case kPrevFragment: - case kNextFragment: - whichString = GetCurrentStringFromFragment(aFragment); - break; - - case kFirstFragment: - whichString = SetLeftStringInFragment(aFragment); - break; - - case kLastFragment: - whichString = SetRightStringInFragment(aFragment); - break; - - case kFragmentAt: - PRUint32 leftLength = mStrings[kLeftString]->Length(); - if ( aPosition < leftLength ) - whichString = SetLeftStringInFragment(aFragment); - else - { - whichString = SetRightStringInFragment(aFragment); - aPosition -= leftLength; - } - break; - - } - - const CharT* result; - PRBool done; - do - { - done = PR_TRUE; - result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); - - if ( !result ) - { - done = PR_FALSE; - if ( aRequest == kNextFragment && whichString == kLeftString ) - { - aRequest = kFirstFragment; - whichString = SetRightStringInFragment(aFragment); - } - else if ( aRequest == kPrevFragment && whichString == kRightString ) - { - aRequest = kLastFragment; - whichString = SetLeftStringInFragment(aFragment); - } - else - done = PR_TRUE; - } - } - while ( !done ); - return result; - } - -#if 0 -template -inline -nsPromiseConcatenation -nsPromiseConcatenation::operator+( const basic_nsAReadableString& rhs ) const - { - return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); - } -#endif - - - - - - // - // nsPromiseSubstring - // - -template -class nsPromiseSubstring - : public nsPromiseReadable - /* - NOT FOR USE BY HUMANS (mostly) - - ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous - temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only - holds a pointer, no string data of its own. It does its magic by overriding and forwarding - calls to |GetReadableFragment()|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - nsPromiseSubstring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aLength ) - : mString(aString), - mStartPos( NS_MIN(aStartPos, aString.Length()) ), - mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) - { - // nothing else to do here - } - - nsPromiseSubstring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - : mString(aStart.string()) - { - nsReadingIterator zeroPoint; - mString.BeginReading(zeroPoint); - mStartPos = Distance(zeroPoint, aStart); - mLength = Distance(aStart, aEnd); - } - - // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK - // ~nsPromiseSubstring(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring - - public: - virtual PRUint32 Length() const; - virtual PRBool Promises( const basic_nsAReadableString& aString ) const { return mString.Promises(aString); } - - private: - const basic_nsAReadableString& mString; - PRUint32 mStartPos; - PRUint32 mLength; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(nsPromiseSubstring, CharT) - -template -PRUint32 -nsPromiseSubstring::Length() const - { - return mLength; - } - -template -const CharT* -nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const - { - // Offset any request for a specific position (First, Last, At) by our - // substrings startpos within the owning string - - if ( aRequest == kFirstFragment ) - { - aPosition = mStartPos; - aRequest = kFragmentAt; - } - else if ( aRequest == kLastFragment ) - { - aPosition = mStartPos + mLength; - aRequest = kFragmentAt; - } - else if ( aRequest == kFragmentAt ) - aPosition += mStartPos; - - // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing - - const CharT* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); - - // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the - // fragment are garbage. - - // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null - if ( position_ptr ) - { - // if there's more physical data in the returned fragment than I logically have left... - size_t logical_size_backward = aPosition - mStartPos; - if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) - aFragment.mStart = position_ptr - logical_size_backward; - - size_t logical_size_forward = mLength - logical_size_backward; - if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) - aFragment.mEnd = position_ptr + logical_size_forward; - } - - return position_ptr; - } - - - - -#ifdef NEED_CPP_DERIVED_TEMPLATE_OPERATORS - - #define NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T) \ - template \ - inline \ - nsPromiseConcatenation \ - operator+( const _String1T& lhs, const _String2T& rhs ) \ - { \ - return nsPromiseConcatenation(lhs, rhs); \ - } - - NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseSubstring, nsPromiseSubstring) - NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseConcatenation, nsPromiseSubstring) - -#endif // NEED_CPP_DERIVED_TEMPLATE_OPERATORS - - - // - // Global functions - // - -template -inline -PRBool -SameImplementation( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - const void* imp_tag = lhs.Implementation(); - return imp_tag && (imp_tag==rhs.Implementation()); - } - -inline -nsPromiseSubstring -Substring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) - { - return nsPromiseSubstring(aString, aStartPos, aSubstringLength); - } - -inline -nsPromiseSubstring -Substring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) - { - return nsPromiseSubstring(aString, aStartPos, aSubstringLength); - } - -inline -nsPromiseSubstring -Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - { - return nsPromiseSubstring(aStart, aEnd); - } - -inline -nsPromiseSubstring -Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - { - return nsPromiseSubstring(aStart, aEnd); - } - -template -int -Compare( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - if ( &lhs == &rhs ) - return 0; - - PRUint32 lLength = lhs.Length(); - PRUint32 rLength = rhs.Length(); - PRUint32 lengthToCompare = NS_MIN(lLength, rLength); - - nsReadingIterator leftIter, rightIter; - lhs.BeginReading(leftIter); - rhs.BeginReading(rightIter); - - int result; - - for (;;) - { - PRUint32 lengthAvailable = PRUint32( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); - - if ( lengthAvailable > lengthToCompare ) - lengthAvailable = lengthToCompare; - - // Note: |result| should be declared in this |if| expression, but some compilers don't like that - if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) - return result; - - if ( !(lengthToCompare -= lengthAvailable) ) - break; - - leftIter.advance( PRInt32(lengthAvailable) ); - rightIter.advance( PRInt32(lengthAvailable) ); - } - - if ( lLength < rLength ) - return -1; - else if ( rLength < lLength ) - return 1; - else - return 0; - } - -template -inline -int -Compare( const basic_nsAReadableString& lhs, const CharT* rhs ) - { - return Compare(lhs, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs))); - } - -template -inline -int -Compare( const CharT* lhs, const basic_nsAReadableString& rhs ) - { - return Compare(NS_READABLE_CAST(CharT, basic_nsLiteralString(lhs)), rhs); - } - -// XXX Note that these are located here because some compilers are -// sensitive to the ordering of declarations with regard to templates. -template -inline -int -basic_nsAReadableString::Compare( const basic_nsAReadableString& rhs ) const - { - return ::Compare(*this, rhs); - } - -template -inline -PRBool -basic_nsAReadableString::Equals( const CharT* rhs ) const - { - return Compare(basic_nsLiteralString(rhs)) == 0; - } - -template -inline -int -basic_nsAReadableString::Compare( const CharT* rhs ) const - { - return ::Compare(*this, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs))); - } - - - - /* - How shall we provide |operator+()|? - - What would it return? It has to return a stack based object, because the client will - not be given an opportunity to handle memory management in an expression like - - myWritableString = stringA + stringB + stringC; - - ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could - return an |nsString|, if that name were in scope here, though there's no telling what the client - will really want to do with the result. What might be better, though, - is to return a `promise' to concatenate some strings... - - By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle - assignment and other interesting uses within writable strings, plus we drastically reduce - the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings - in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work - to implement the virtual functions of readables. - */ - -template -inline -nsPromiseConcatenation -operator+( const nsPromiseConcatenation& lhs, const basic_nsAReadableString& rhs ) - { - return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); - } - -template -inline -nsPromiseConcatenation -operator+( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - return nsPromiseConcatenation(lhs, rhs); - } - - - -#ifdef NEED_CPP_DERIVED_TEMPLATE_OPERATORS - #define NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - inline \ - nsPromiseConcatenation<_CharT> \ - operator+( const _String1T& lhs, const _String2T& rhs ) \ - { \ - return nsPromiseConcatenation<_CharT>(lhs, rhs); \ - } - - #define NS_DEF_DERIVED_STRING_OPERATOR_PLUS(_StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_StringT, _StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseSubstring<_CharT>, _StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_StringT, nsPromiseSubstring<_CharT>, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseConcatenation<_CharT>, _StringT, _CharT) - - #define NS_DEF_2_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String2T, _String1T, _CharT) - -#else - #define NS_DEF_DERIVED_STRING_OPERATOR_PLUS(_StringT, _CharT) - #define NS_DEF_2_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) -#endif - - -#define kDefaultFlatStringSize 64 - -template -class basic_nsPromiseFlatString - : public basic_nsAReadableString - { - public: - explicit basic_nsPromiseFlatString( const basic_nsAReadableString& ); - - virtual - ~basic_nsPromiseFlatString( ) - { - if (mOwnsBuffer) - nsMemory::Free((void*)mBuffer); - } - - virtual PRUint32 Length() const { return mLength; } - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const; - - const CharT* get() const { return mBuffer; } - - // operator const CharT*() const; // use |get()| - - protected: - PRUint32 mLength; - const CharT* mBuffer; - PRBool mOwnsBuffer; - CharT mInlineBuffer[kDefaultFlatStringSize]; - }; - -template -basic_nsPromiseFlatString::basic_nsPromiseFlatString( const basic_nsAReadableString& aString ) - : mLength(aString.Length()), - mOwnsBuffer(PR_FALSE) - { - typedef nsReadingIterator iterator; - - iterator start; - iterator end; - - aString.BeginReading(start); - aString.EndReading(end); - - // First count the number of buffers - PRInt32 buffer_count = 0; - while ( start != end ) - { - buffer_count++; - start += start.size_forward(); - } - - // Now figure out what we want to do with the string - aString.BeginReading(start); - // XXX Not guaranteed null-termination in the first case - // If it's a single buffer, we just use the implementation's buffer - if ( buffer_count == 1 ) - mBuffer = start.get(); - // If it's too big for our inline buffer, we allocate a new one - else if ( mLength > kDefaultFlatStringSize-1 ) - { - CharT* result = NS_STATIC_CAST(CharT*, nsMemory::Alloc((mLength+1) * sizeof(CharT))); - CharT* toBegin = result; - *copy_string(start, end, toBegin) = CharT(0); - - mBuffer = result; - mOwnsBuffer = PR_TRUE; - } - // Otherwise copy into our internal buffer - else - { - mBuffer = mInlineBuffer; - CharT* toBegin = &mInlineBuffer[0]; - copy_string( start, end, toBegin); - mInlineBuffer[mLength] = 0; - } - } - - -template -const CharT* -basic_nsPromiseFlatString::GetReadableFragment( nsReadableFragment& aFragment, - nsFragmentRequest aRequest, - PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mEnd = (aFragment.mStart = mBuffer) + mLength; - return aFragment.mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - - -typedef basic_nsAReadableString nsAReadableString; -typedef basic_nsAReadableString nsAReadableCString; - -typedef basic_nsLiteralString nsLiteralString; -typedef basic_nsLiteralString nsLiteralCString; - -typedef basic_nsPromiseFlatString nsPromiseFlatString; -typedef basic_nsPromiseFlatString nsPromiseFlatCString; - - -#ifdef HAVE_CPP_2BYTE_WCHAR_T - #define NS_L(s) L##s - #define NS_MULTILINE_LITERAL_STRING(s) nsLiteralString(s, (sizeof(s)/sizeof(wchar_t))-1) - #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) nsLiteralString n(s, (sizeof(s)/sizeof(wchar_t))-1) -#else - #define NS_L(s) s - #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUCS2(s, sizeof(s)-1) - #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) NS_ConvertASCIItoUCS2 n(s, sizeof(s)-1) -#endif - -#define NS_LITERAL_STRING(s) NS_MULTILINE_LITERAL_STRING(NS_L(s)) -#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n,NS_L(s)) - -#define NS_LITERAL_CSTRING(s) nsLiteralCString(s, sizeof(s)-1) -#define NS_NAMED_LITERAL_CSTRING(n,s) nsLiteralCString n(s, sizeof(s)-1) - -typedef basic_nsLiteralChar nsLiteralChar; -typedef basic_nsLiteralChar nsLiteralPRUnichar; - - #endif // !defined(nsAReadableString_h___) diff --git a/string/public/nsAString.h b/string/public/nsAString.h new file mode 100644 index 000000000000..a6fb0361ef48 --- /dev/null +++ b/string/public/nsAString.h @@ -0,0 +1,772 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsAString_h___ +#define nsAString_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nsPrivateSharableString_h___ +#include "nsPrivateSharableString.h" +#endif + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsStringIterator_h___ +#include "nsStringIterator.h" +#endif + + + /** + * + */ + +class NS_COM nsAString + : public nsPrivateSharableString + { + public: + typedef nsAString self_type; + typedef nsAPromiseString promise_type; + typedef PRUnichar char_type; + typedef char incompatible_char_type; + + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + + + + // nsAString(); // auto-generated default constructor OK (we're abstract anyway) + // nsAString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract) + virtual ~nsAString() { } // ...yes, I expect to be sub-classed + + inline const_iterator& BeginReading( const_iterator& ) const; + inline const_iterator& EndReading( const_iterator& ) const; + + inline iterator& BeginWriting( iterator& ); + inline iterator& EndWriting( iterator& ); + + virtual size_type Length() const = 0; + PRBool IsEmpty() const { return Length() == 0; } + + inline PRBool Equals( const self_type& ) const; + PRBool Equals( const char_type* ) const; + + + /** + * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. + * These signatures should be pushed down into interfaces that guarantee flat allocation. + * Clients at _this_ level should always use iterators. + */ + char_type First() const; + char_type Last() const; + + size_type CountChar( char_type ) const; + + + /* + |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + any _other_ way than they are now. Consider these alternatives + + aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + Left(aReadable, 17, aWritable); // ...a global function that does the assignment + + as opposed to the current signature + + aReadable.Left(aWritable, 17); // ...a member function that does the assignment + + or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + + aWritable = Substring(aReadable, 0, 17); + */ + + size_type Left( self_type&, size_type ) const; + size_type Mid( self_type&, PRUint32, PRUint32 ) const; + size_type Right( self_type&, size_type ) const; + + // Find( ... ) const; + PRInt32 FindChar( char_type, index_type aOffset = 0 ) const; + // FindCharInSet( ... ) const; + // RFind( ... ) const; + // RFindChar( ... ) const; + // RFindCharInSet( ... ) const; + + /** + * |SetCapacity| is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * |SetCapacity(0)| is a suggestion to discard all associated storage. + */ + virtual void SetCapacity( size_type ) { } + + /** + * |SetLength| is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| is this latter capacity. + * Should this really be a public operation? + * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you + * override the |do_...| routines to not need this facility. + * + * This distinction makes me think the two different uses should be split into + * two distinct functions. + */ + virtual void SetLength( size_type ) { } + + + void + Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); + + if ( aNewLength < this->Length() ) + SetLength(aNewLength); + } + + + // PRBool SetCharAt( char_type, index_type ) = 0; + + + + // void ToLowerCase(); + // void ToUpperCase(); + + // void StripChars( const char_type* aSet ); + // void StripChar( ... ); + // void StripWhitespace(); + // void ReplaceChar( ... ); + // void ReplaceSubstring( ... ); + // void Trim( ... ); + // void CompressSet( ... ); + // void CompressWhitespace( ... ); + + + + // + // |Assign()|, |operator=()| + // + + void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); } + inline void Assign( const promise_type& aReadable ); + void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } + void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } + void Assign( char_type aChar ) { do_AssignFromElement(aChar); } + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; } + + self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; } + self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; } + self_type& operator=( char_type aChar ) { Assign(aChar); return *this; } + + + + // + // |Append()|, |operator+=()| + // + + void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); } + inline void Append( const promise_type& aReadable ); + void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } + void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } + void Append( char_type aChar ) { do_AppendFromElement(aChar); } + + self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; } + self_type& operator+=( char_type aChar ) { Append(aChar); return *this; } + + + + /** + * The following index based routines need to be recast with iterators. + */ + + // + // |Insert()| + // Note: I would really like to move the |atPosition| parameter to the front of the argument list + // + + void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); } + inline void Insert( const promise_type& aReadable, index_type atPosition ); + void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } + void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } + void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); } + + + + virtual void Cut( index_type cutStart, size_type cutLength ); + + + + void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } +// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } + + private: + // NOT TO BE IMPLEMENTED + index_type CountChar( incompatible_char_type ) const; + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + + + protected: + void AssignFromReadable( const self_type& ); + void AssignFromPromise( const self_type& ); + virtual void do_AssignFromReadable( const self_type& ); + virtual void do_AssignFromElementPtr( const char_type* ); + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ); + virtual void do_AssignFromElement( char_type ); + + void AppendFromReadable( const self_type& ); + void AppendFromPromise( const self_type& ); + virtual void do_AppendFromReadable( const self_type& ); + virtual void do_AppendFromElementPtr( const char_type* ); + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ); + virtual void do_AppendFromElement( char_type ); + + void InsertFromReadable( const self_type&, index_type ); + void InsertFromPromise( const self_type&, index_type ); + virtual void do_InsertFromReadable( const self_type&, index_type ); + virtual void do_InsertFromElementPtr( const char_type*, index_type ); + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ); + virtual void do_InsertFromElement( char_type, index_type ); + + void ReplaceFromReadable( index_type, size_type, const self_type& ); + void ReplaceFromPromise( index_type, size_type, const self_type& ); + virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& ); + + +// protected: + public: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; + virtual PRBool Promises( const self_type& aString ) const { return &aString == this; } + }; + +class NS_COM nsACString + : public nsPrivateSharableCString + { + public: + typedef nsACString self_type; + typedef nsAPromiseCString promise_type; + typedef char char_type; + typedef PRUnichar incompatible_char_type; + + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + + + + // nsACString(); // auto-generated default constructor OK (we're abstract anyway) + // nsACString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract) + virtual ~nsACString() { } // ...yes, I expect to be sub-classed + + inline const_iterator& BeginReading( const_iterator& ) const; + inline const_iterator& EndReading( const_iterator& ) const; + + inline iterator& BeginWriting( iterator& ); + inline iterator& EndWriting( iterator& ); + + virtual size_type Length() const = 0; + PRBool IsEmpty() const { return Length() == 0; } + + inline PRBool Equals( const self_type& ) const; + PRBool Equals( const char_type* ) const; + + + /** + * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. + * These signatures should be pushed down into interfaces that guarantee flat allocation. + * Clients at _this_ level should always use iterators. + */ + char_type First() const; + char_type Last() const; + + size_type CountChar( char_type ) const; + + + /* + |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + any _other_ way than they are now. Consider these alternatives + + aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + Left(aReadable, 17, aWritable); // ...a global function that does the assignment + + as opposed to the current signature + + aReadable.Left(aWritable, 17); // ...a member function that does the assignment + + or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + + aWritable = Substring(aReadable, 0, 17); + */ + + size_type Left( self_type&, size_type ) const; + size_type Mid( self_type&, PRUint32, PRUint32 ) const; + size_type Right( self_type&, size_type ) const; + + // Find( ... ) const; + PRInt32 FindChar( char_type, PRUint32 aOffset = 0 ) const; + // FindCharInSet( ... ) const; + // RFind( ... ) const; + // RFindChar( ... ) const; + // RFindCharInSet( ... ) const; + + /** + * |SetCapacity| is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * |SetCapacity(0)| is a suggestion to discard all associated storage. + */ + virtual void SetCapacity( size_type ) { } + + /** + * |SetLength| is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| is this latter capacity. + * Should this really be a public operation? + * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you + * override the |do_...| routines to not need this facility. + * + * This distinction makes me think the two different uses should be split into + * two distinct functions. + */ + virtual void SetLength( size_type ) { } + + + void + Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); + + if ( aNewLength < this->Length() ) + SetLength(aNewLength); + } + + + // PRBool SetCharAt( char_type, index_type ) = 0; + + + + // void ToLowerCase(); + // void ToUpperCase(); + + // void StripChars( const char_type* aSet ); + // void StripChar( ... ); + // void StripWhitespace(); + // void ReplaceChar( ... ); + // void ReplaceSubstring( ... ); + // void Trim( ... ); + // void CompressSet( ... ); + // void CompressWhitespace( ... ); + + + + // + // |Assign()|, |operator=()| + // + + void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); } + inline void Assign( const promise_type& aReadable ); + void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } + void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } + void Assign( char_type aChar ) { do_AssignFromElement(aChar); } + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; } + + self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; } + self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; } + self_type& operator=( char_type aChar ) { Assign(aChar); return *this; } + + + + // + // |Append()|, |operator+=()| + // + + void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); } + inline void Append( const promise_type& aReadable ); + void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } + void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } + void Append( char_type aChar ) { do_AppendFromElement(aChar); } + + self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; } + self_type& operator+=( char_type aChar ) { Append(aChar); return *this; } + + + + /** + * The following index based routines need to be recast with iterators. + */ + + // + // |Insert()| + // Note: I would really like to move the |atPosition| parameter to the front of the argument list + // + + void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); } + inline void Insert( const promise_type& aReadable, index_type atPosition ); + void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } + void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } + void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); } + + + + virtual void Cut( index_type cutStart, size_type cutLength ); + + + + void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } +// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } + + private: + // NOT TO BE IMPLEMENTED + index_type CountChar( incompatible_char_type ) const; + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + + + protected: + void AssignFromReadable( const self_type& ); + void AssignFromPromise( const self_type& ); + virtual void do_AssignFromReadable( const self_type& ); + virtual void do_AssignFromElementPtr( const char_type* ); + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ); + virtual void do_AssignFromElement( char_type ); + + void AppendFromReadable( const self_type& ); + void AppendFromPromise( const self_type& ); + virtual void do_AppendFromReadable( const self_type& ); + virtual void do_AppendFromElementPtr( const char_type* ); + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ); + virtual void do_AppendFromElement( char_type ); + + void InsertFromReadable( const self_type&, index_type ); + void InsertFromPromise( const self_type&, index_type ); + virtual void do_InsertFromReadable( const self_type&, index_type ); + virtual void do_InsertFromElementPtr( const char_type*, index_type ); + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ); + virtual void do_InsertFromElement( char_type, index_type ); + + void ReplaceFromReadable( index_type, size_type, const self_type& ); + void ReplaceFromPromise( index_type, size_type, const self_type& ); + virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& ); + + +// protected: + public: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; + virtual PRBool Promises( const self_type& aString ) const { return &aString == this; } + }; + +#include "nsAPromiseString.h" + +inline +void +nsAString::Assign( const nsAPromiseString& aReadable ) + { + AssignFromPromise(aReadable); + } + +inline +void +nsAString::Append( const nsAPromiseString& aReadable ) + { + AppendFromPromise(aReadable); + } + +inline +void +nsAString::Insert( const nsAPromiseString& aReadable, index_type atPosition ) + { + InsertFromPromise(aReadable, atPosition); + } + +inline +void +nsACString::Assign( const nsAPromiseCString& aReadable ) + { + AssignFromPromise(aReadable); + } + +inline +void +nsACString::Append( const nsAPromiseCString& aReadable ) + { + AppendFromPromise(aReadable); + } + +inline +void +nsACString::Insert( const nsAPromiseCString& aReadable, index_type atPosition ) + { + InsertFromPromise(aReadable, atPosition); + } + + + /** + * Note: measure -- should the |Begin...| and |End...| be |inline|? + */ +inline +nsAString::const_iterator& +nsAString::BeginReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + +inline +nsAString::const_iterator& +nsAString::EndReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +inline +nsAString::iterator& +nsAString::BeginWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + + +inline +nsAString::iterator& +nsAString::EndWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +NS_COM int Compare( const nsAString& lhs, const nsAString& rhs ); + +inline +PRBool +nsAString::Equals( const self_type& rhs ) const + { + return Length()==rhs.Length() && Compare(*this, rhs)==0; + } + +inline +PRBool +operator!=( const nsAString& lhs, const nsAString& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool +operator< ( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool +operator<=( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool +operator==( const nsAString& lhs, const nsAString& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool +operator>=( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool +operator> ( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)> 0; + } + +inline +nsAString::size_type +nsAString::Left( nsAString& aResult, size_type aLengthToCopy ) const + { + return Mid(aResult, 0, aLengthToCopy); + } + + + /** + * + */ + +inline +nsACString::const_iterator& +nsACString::BeginReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + +inline +nsACString::const_iterator& +nsACString::EndReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +inline +nsACString::iterator& +nsACString::BeginWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + + +inline +nsACString::iterator& +nsACString::EndWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +NS_COM int Compare( const nsACString& lhs, const nsACString& rhs ); + +inline +PRBool +nsACString::Equals( const self_type& rhs ) const + { + return Length()==rhs.Length() && Compare(*this, rhs)==0; + } + +inline +PRBool +operator!=( const nsACString& lhs, const nsACString& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool +operator< ( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool +operator<=( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool +operator==( const nsACString& lhs, const nsACString& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool +operator>=( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool +operator> ( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)> 0; + } + +inline +nsACString::size_type +nsACString::Left( nsACString& aResult, size_type aLengthToCopy ) const + { + return Mid(aResult, 0, aLengthToCopy); + } + + // Once you've got strings, you shouldn't need to do anything else to have concatenation +#ifndef nsPromiseConcatenation_h___ +#include "nsPromiseConcatenation.h" +#endif + +#endif // !defined(nsAString_h___) diff --git a/string/public/nsAWritableString.h b/string/public/nsAWritableString.h index 209e4ff8766c..04024d8a0354 100644 --- a/string/public/nsAWritableString.h +++ b/string/public/nsAWritableString.h @@ -21,866 +21,16 @@ * Scott Collins (original author) */ +/* nsAWritableString.h --- a compatibility header for clients still using the names |nsAWritable[C]String| */ + #ifndef nsAWritableString_h___ #define nsAWritableString_h___ - // See also... #ifndef nsAReadableString_h___ #include "nsAReadableString.h" #endif - -template -struct nsWritableFragment - { - CharT* mStart; - CharT* mEnd; - void* mFragmentIdentifier; - - nsWritableFragment() - : mStart(0), mEnd(0), mFragmentIdentifier(0) - { - // nothing else to do here - } - }; - -template class basic_nsAWritableString; - -template -class nsWritingIterator -// : public bidirectional_iterator_tag - { - public: - typedef ptrdiff_t difference_type; - typedef CharT value_type; - typedef CharT* pointer; - typedef CharT& reference; -// typedef bidirectional_iterator_tag iterator_category; - - private: - friend class basic_nsAWritableString; - - nsWritableFragment mFragment; - CharT* mPosition; - basic_nsAWritableString* mOwningString; - - nsWritingIterator( nsWritableFragment& aFragment, - CharT* aStartingPosition, - basic_nsAWritableString& aOwningString ) - : mFragment(aFragment), - mPosition(aStartingPosition), - mOwningString(&aOwningString) - { - // nothing else to do here - } - - public: - nsWritingIterator() { } - // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK - // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK - - inline void normalize_forward(); - inline void normalize_backward(); - - pointer - get() const - { - return mPosition; - } - - reference - operator*() const - { - return *get(); - } - -#if 0 - // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) - // don't like this when |CharT| is a type without members. - pointer - operator->() const - { - return get(); - } -#endif - - nsWritingIterator& - operator++() - { - ++mPosition; - normalize_forward(); - return *this; - } - - nsWritingIterator - operator++( int ) - { - nsWritingIterator result(*this); - ++mPosition; - normalize_forward(); - return result; - } - - nsWritingIterator& - operator--() - { - normalize_backward(); - --mPosition; - return *this; - } - - nsWritingIterator - operator--( int ) - { - nsWritingIterator result(*this); - normalize_backward(); - --mPosition; - return result; - } - - const nsWritableFragment& - fragment() const - { - return mFragment; - } - - nsWritableFragment& - fragment() - { - return mFragment; - } - - const basic_nsAWritableString& - string() const - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - basic_nsAWritableString& - string() - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - difference_type - size_forward() const - { - return mFragment.mEnd - mPosition; - } - - difference_type - size_backward() const - { - return mPosition - mFragment.mStart; - } - - nsWritingIterator& - 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 writing 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 writing iterator beyond the end of a string"); - // perhaps I should |break| if |!one_hop|? - - mPosition += one_hop; - n -= one_hop; - } - - return *this; - } - - /** - * Really don't want to call these two operations |+=| and |-=|. - * Would prefer a single function, e.g., |advance|, which doesn't imply a constant time operation. - * - * We'll get rid of these as soon as we can. - */ - nsWritingIterator& - operator+=( difference_type n ) // deprecated - { - return advance(n); - } - - nsWritingIterator& - operator-=( difference_type n ) // deprecated - { - return advance(-n); - } - - PRUint32 - write( const value_type* s, PRUint32 n ) - { - NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); - - n = NS_MIN(n, PRUint32(size_forward())); - nsCharTraits::move(mPosition, s, n); - advance( difference_type(n) ); - return n; - } - }; - -#if 0 -template -nsWritingIterator& -nsWritingIterator::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 writing 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 writing iterator beyond the end of a string"); - // perhaps I should |break| if |!one_hop|? - - mPosition += one_hop; - n -= one_hop; - } - - return *this; - } -#endif - -/* - This file defines the abstract interfaces |nsAWritableString| and - |nsAWritableCString|. - - |nsAWritableString| is a string of |PRUnichar|s. |nsAWritableCString| (note the - 'C') is a string of |char|s. -*/ - -template -class basic_nsAWritableString - : public basic_nsAReadableString - /* - ... - */ - { - // friend class nsWritingIterator; - - public: - typedef CharT char_type; - typedef PRUint32 size_type; - typedef PRUint32 index_type; - - typedef nsWritingIterator iterator; - - // basic_nsAWritableString(); // auto-generated default constructor OK (we're abstract anyway) - // basic_nsAWritableString( const basic_nsAWritableString& ); // auto-generated copy-constructor OK (again, only because we're abstract) - // ~basic_nsAWritableString(); // auto-generated destructor OK - // see below for copy-assignment operator - - virtual CharT* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; - - /** - * Note: measure -- should the |BeginWriting| and |EndWriting| be |inline|? - */ - nsWritingIterator& - BeginWriting( nsWritingIterator& aResult ) - { - aResult.mOwningString = this; - GetWritableFragment(aResult.mFragment, kFirstFragment); - aResult.mPosition = aResult.mFragment.mStart; - aResult.normalize_forward(); - return aResult; - } - - - nsWritingIterator& - EndWriting( nsWritingIterator& aResult ) - { - aResult.mOwningString = this; - GetWritableFragment(aResult.mFragment, kLastFragment); - aResult.mPosition = aResult.mFragment.mEnd; - // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| - return aResult; - } - - - /** - * |SetCapacity| is not required to do anything; however, it can be used - * as a hint to the implementation to reduce allocations. - * |SetCapacity(0)| is a suggestion to discard all associated storage. - */ - virtual void SetCapacity( PRUint32 ) { } - - /** - * |SetLength| is used in two ways: - * 1) to |Cut| a suffix of the string; - * 2) to prepare to |Append| or move characters around. - * - * External callers are not allowed to use |SetLength| is this latter capacity. - * Should this really be a public operation? - * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you - * override the |do_...| routines to not need this facility. - * - * This distinction makes me think the two different uses should be split into - * two distinct functions. - */ - virtual void SetLength( PRUint32 ) = 0; - - - void - Truncate( PRUint32 aNewLength=0 ) - { - NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); - - if ( aNewLength < this->Length() ) - SetLength(aNewLength); - } - - - // PRBool SetCharAt( char_type, index_type ) = 0; - - - - // void ToLowerCase(); - // void ToUpperCase(); - - // void StripChars( const CharT* aSet ); - // void StripChar( ... ); - // void StripWhitespace(); - // void ReplaceChar( ... ); - // void ReplaceSubstring( ... ); - // void Trim( ... ); - // void CompressSet( ... ); - // void CompressWhitespace( ... ); - - - - // - // |Assign()|, |operator=()| - // - - void Assign( const basic_nsAReadableString& aReadable ) { AssignFromReadable(aReadable); } - void Assign( const nsPromiseReadable& aReadable ) { AssignFromPromise(aReadable); } - void Assign( const CharT* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } - void Assign( const CharT* aPtr, PRUint32 aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } - void Assign( CharT aChar ) { do_AssignFromElement(aChar); } - - // copy-assignment operator. I must define my own if I don't want the compiler to make me one - basic_nsAWritableString& operator=( const basic_nsAWritableString& aWritable ) { Assign(aWritable); return *this; } - - basic_nsAWritableString& operator=( const basic_nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - basic_nsAWritableString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } - basic_nsAWritableString& operator=( const CharT* aPtr ) { Assign(aPtr); return *this; } - basic_nsAWritableString& operator=( CharT aChar ) { Assign(aChar); return *this; } - - - - // - // |Append()|, |operator+=()| - // - - void Append( const basic_nsAReadableString& aReadable ) { AppendFromReadable(aReadable); } - void Append( const nsPromiseReadable& aReadable ) { AppendFromPromise(aReadable); } - void Append( const CharT* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } - void Append( const CharT* aPtr, PRUint32 aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } - void Append( CharT aChar ) { do_AppendFromElement(aChar); } - - basic_nsAWritableString& operator+=( const basic_nsAReadableString& aReadable ) { Append(aReadable); return *this; } - basic_nsAWritableString& operator+=( const nsPromiseReadable& aReadable ) { Append(aReadable); return *this; } - basic_nsAWritableString& operator+=( const CharT* aPtr ) { Append(aPtr); return *this; } - basic_nsAWritableString& operator+=( CharT aChar ) { Append(aChar); return *this; } - - - - /** - * The following index based routines need to be recast with iterators. - */ - - // - // |Insert()| - // Note: I would really like to move the |atPosition| parameter to the front of the argument list - // - - void Insert( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) { InsertFromReadable(aReadable, atPosition); } - void Insert( const nsPromiseReadable& aReadable, PRUint32 atPosition ) { InsertFromPromise(aReadable, atPosition); } - void Insert( const CharT* aPtr, PRUint32 atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } - void Insert( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } - void Insert( CharT aChar, PRUint32 atPosition ) { do_InsertFromElement(aChar, atPosition); } - - - - virtual void Cut( PRUint32 cutStart, PRUint32 cutLength ); - - - - void Replace( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } - void Replace( PRUint32 cutStart, PRUint32 cutLength, const nsPromiseReadable& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } - - private: - typedef typename nsCharTraits::incompatible_char_type incompatible_char_type; - - // NOT TO BE IMPLEMENTED - void operator= ( incompatible_char_type ); - void Assign ( incompatible_char_type ); - void operator+= ( incompatible_char_type ); - void Append ( incompatible_char_type ); - void Insert ( incompatible_char_type, PRUint32 ); - - - protected: - void AssignFromReadable( const basic_nsAReadableString& ); - void AssignFromPromise( const basic_nsAReadableString& ); - virtual void do_AssignFromReadable( const basic_nsAReadableString& ); - virtual void do_AssignFromElementPtr( const CharT* ); - virtual void do_AssignFromElementPtrLength( const CharT*, PRUint32 ); - virtual void do_AssignFromElement( CharT ); - - void AppendFromReadable( const basic_nsAReadableString& ); - void AppendFromPromise( const basic_nsAReadableString& ); - virtual void do_AppendFromReadable( const basic_nsAReadableString& ); - virtual void do_AppendFromElementPtr( const CharT* ); - virtual void do_AppendFromElementPtrLength( const CharT*, PRUint32 ); - virtual void do_AppendFromElement( CharT ); - - void InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - void InsertFromPromise( const basic_nsAReadableString&, PRUint32 ); - virtual void do_InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - virtual void do_InsertFromElementPtr( const CharT*, PRUint32 ); - virtual void do_InsertFromElementPtrLength( const CharT*, PRUint32, PRUint32 ); - virtual void do_InsertFromElement( CharT, PRUint32 ); - - void ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); - void ReplaceFromPromise( PRUint32, PRUint32, const basic_nsAReadableString& ); - virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); - }; - - - - // - // |nsWritingIterator|s - // - -template -inline -void -nsWritingIterator::normalize_forward() - { - while ( mPosition == mFragment.mEnd - && mOwningString->GetWritableFragment(mFragment, kNextFragment) ) - mPosition = mFragment.mStart; - } - -template -inline -void -nsWritingIterator::normalize_backward() - { - while ( mPosition == mFragment.mStart - && mOwningString->GetWritableFragment(mFragment, kPrevFragment) ) - mPosition = mFragment.mEnd; - } - -template -inline -PRBool -operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) - { - return lhs.get() == rhs.get(); - } - -template -inline -PRBool -operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) - { - return lhs.get() != rhs.get(); - } - - - - // - // |Assign()| - // - -template -void -basic_nsAWritableString::AssignFromReadable( const basic_nsAReadableString& rhs ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &rhs ) - do_AssignFromReadable(rhs); - // else, self-assign is a no-op - } - -template -void -basic_nsAWritableString::AssignFromPromise( const basic_nsAReadableString& aReadable ) - /* - ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. - E.g., - - ... writable& w ... - ... readable& r ... - - w = r + w; - - In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before - anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents - of |r| before being retrieved to be appended. - - We could have a really tricky solution where we tell the promise to resolve _just_ the data promised - by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., - in the case above, |Insert| could have special behavior with significantly better performance. Since - it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the - entire promise. If we measure and this turns out to show up on performance radar, we then have the - option to fix either the callers or this mechanism. - */ - { - if ( !aReadable.Promises(*this) ) - do_AssignFromReadable(aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - // Note: not exception safe. We need something to manage temporary buffers like this - - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_AssignFromElementPtrLength(buffer, length); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_AssignFromReadable( const basic_nsAReadableString& aReadable ) - { - SetLength(0); - SetLength(aReadable.Length()); - // first setting the length to |0| avoids copying characters only to be overwritten later - // in the case where the implementation decides to re-allocate - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); - } - -template -void -basic_nsAWritableString::do_AssignFromElementPtr( const CharT* aPtr ) - { - do_AssignFromReadable(basic_nsLiteralString(aPtr)); - } - -template -void -basic_nsAWritableString::do_AssignFromElementPtrLength( const CharT* aPtr, PRUint32 aLength ) - { - do_AssignFromReadable(basic_nsLiteralString(aPtr, aLength)); - } - -template -void -basic_nsAWritableString::do_AssignFromElement( CharT aChar ) - { - do_AssignFromReadable(basic_nsLiteralChar(aChar)); - } - - - - // - // |Append()| - // - -template -void -basic_nsAWritableString::AppendFromReadable( const basic_nsAReadableString& aReadable ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReadable ) - do_AppendFromReadable(aReadable); - else - AppendFromPromise(aReadable); - } - -template -void -basic_nsAWritableString::AppendFromPromise( const basic_nsAReadableString& aReadable ) - { - if ( !aReadable.Promises(*this) ) - do_AppendFromReadable(aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_AppendFromElementPtrLength(buffer, length); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_AppendFromReadable( const basic_nsAReadableString& aReadable ) - { - PRUint32 oldLength = this->Length(); - SetLength(oldLength + aReadable.Length()); - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); - } - -template -void -basic_nsAWritableString::do_AppendFromElementPtr( const CharT* aChar ) - { - do_AppendFromReadable(basic_nsLiteralString(aChar)); - } - -template -void -basic_nsAWritableString::do_AppendFromElementPtrLength( const CharT* aChar, PRUint32 aLength ) - { - do_AppendFromReadable(basic_nsLiteralString(aChar, aLength)); - } - -template -void -basic_nsAWritableString::do_AppendFromElement( CharT aChar ) - { - do_AppendFromReadable(basic_nsLiteralChar(aChar)); - } - - - - // - // |Insert()| - // - -template -void -basic_nsAWritableString::InsertFromReadable( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReadable ) - do_InsertFromReadable(aReadable, atPosition); - else - InsertFromPromise(aReadable, atPosition); - } - -template -void -basic_nsAWritableString::InsertFromPromise( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - if ( !aReadable.Promises(*this) ) - do_InsertFromReadable(aReadable, atPosition); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_InsertFromElementPtrLength(buffer, atPosition, length); - delete buffer; - } - // else assert - } - } - -template -void -basic_nsAWritableString::do_InsertFromReadable( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - PRUint32 oldLength = this->Length(); - SetLength(oldLength + aReadable.Length()); - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( atPosition < oldLength ) - copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); - else - atPosition = oldLength; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); - } - -template -void -basic_nsAWritableString::do_InsertFromElementPtr( const CharT* aPtr, PRUint32 atPosition ) - { - do_InsertFromReadable(basic_nsLiteralString(aPtr), atPosition); - } - -template -void -basic_nsAWritableString::do_InsertFromElementPtrLength( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) - { - do_InsertFromReadable(basic_nsLiteralString(aPtr, aLength), atPosition); - } - -template -void -basic_nsAWritableString::do_InsertFromElement( CharT aChar, PRUint32 atPosition ) - { - do_InsertFromReadable(basic_nsLiteralChar(aChar), atPosition); - } - - - - // - // |Cut()| - // - -template -void -basic_nsAWritableString::Cut( PRUint32 cutStart, PRUint32 cutLength ) - { - PRUint32 myLength = this->Length(); - cutLength = NS_MIN(cutLength, myLength-cutStart); - PRUint32 cutEnd = cutStart + cutLength; - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( cutEnd < myLength ) - copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); - SetLength(myLength-cutLength); - } - - - - // - // |Replace()| - // - -template -void -basic_nsAWritableString::ReplaceFromReadable( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReplacement ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReplacement ) - do_ReplaceFromReadable(cutStart, cutLength, aReplacement); - else - ReplaceFromPromise(cutStart, cutLength, aReplacement); - } - -template -void -basic_nsAWritableString::ReplaceFromPromise( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReadable ) - { - if ( !aReadable.Promises(*this) ) - do_ReplaceFromReadable(cutStart, cutLength, aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_ReplaceFromReadable(cutStart, cutLength, basic_nsLiteralString(buffer, length)); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_ReplaceFromReadable( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReplacement ) - { - PRUint32 oldLength = this->Length(); - - cutStart = NS_MIN(cutStart, oldLength); - cutLength = NS_MIN(cutLength, oldLength-cutStart); - PRUint32 cutEnd = cutStart + cutLength; - - PRUint32 replacementLength = aReplacement.Length(); - PRUint32 replacementEnd = cutStart + replacementLength; - - PRUint32 newLength = oldLength - cutLength + replacementLength; - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( cutLength > replacementLength ) - copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); - SetLength(newLength); - if ( cutLength < replacementLength ) - copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); - - copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); - } - - -template -PRUint32 -basic_nsAReadableString::Mid( basic_nsAWritableString& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const - { - // If we're just assigning our entire self, give |aResult| the opportunity to share - if ( aStartPos == 0 && aLengthToCopy >= Length() ) - aResult = *this; - else - aResult = Substring(*this, aStartPos, aLengthToCopy); - - return aResult.Length(); - } - -template -inline -PRUint32 -basic_nsAReadableString::Left( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - return Mid(aResult, 0, aLengthToCopy); - } - -template -PRUint32 -basic_nsAReadableString::Right( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - PRUint32 myLength = Length(); - aLengthToCopy = NS_MIN(myLength, aLengthToCopy); - return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); - } - - - - - // - // Types - // - -typedef basic_nsAWritableString nsAWritableString; -typedef basic_nsAWritableString nsAWritableCString; +typedef nsAString nsAWritableString; +typedef nsACString nsAWritableCString; #endif // !defined(nsAWritableString_h___) diff --git a/string/public/nsBufferHandle.h b/string/public/nsBufferHandle.h index a2b290334fc8..0cd7e1d547e7 100755 --- a/string/public/nsBufferHandle.h +++ b/string/public/nsBufferHandle.h @@ -163,13 +163,14 @@ class nsSharedBufferHandle protected: enum { - kIsShared = 1<<31, - kIsSingleAllocationWithBuffer = 1<<30, // handle and buffer are one piece, no separate deallocation is possible for the buffer - kIsStorageDefinedSeparately = 1<<29, // i.e., we're using the ``flex'' structure defined below - kIsUserAllocator = 1<<28, // can't |delete|, call a hook instead + kIsShared = 0x8000000, + kIsSingleAllocationWithBuffer = 0x4000000, // handle and buffer are one piece, no separate deallocation is possible for the buffer + kIsStorageDefinedSeparately = 0x2000000, // i.e., we're using the ``flex'' structure defined below + kIsUserAllocator = 0x1000000, // can't |delete|, call a hook instead - kFlagsMask = kIsShared | kIsSingleAllocationWithBuffer | kIsStorageDefinedSeparately | kIsUserAllocator, - kRefCountMask = ~kFlagsMask + kImplementationFlagsMask = 0x0F00000, + kFlagsMask = 0xFF00000, + kRefCountMask = 0x00FFFFF }; public: @@ -179,6 +180,14 @@ class nsSharedBufferHandle mFlags = kIsShared; } + nsSharedBufferHandle( CharT* aDataStart, CharT* aDataEnd, CharT*, CharT*, PRBool isSingleAllocation ) + : nsBufferHandle(aDataStart, aDataEnd) + { + mFlags = kIsShared; + if ( isSingleAllocation ) + mFlags |= kIsSingleAllocationWithBuffer; + } + ~nsSharedBufferHandle(); void @@ -203,6 +212,18 @@ class nsSharedBufferHandle return get_refcount() != 0; } + PRUint32 + GetImplementationFlags() const + { + return mFlags & kImplementationFlagsMask; + } + + void + SetImplementationFlags( PRUint32 aNewFlags ) + { + mFlags = (mFlags & ~kImplementationFlagsMask) | (aNewFlags & kImplementationFlagsMask); + } + protected: PRUint32 mFlags; diff --git a/string/public/nsBufferHandleUtils.h b/string/public/nsBufferHandleUtils.h index 6f05fabe22ab..565ac3b64f07 100644 --- a/string/public/nsBufferHandleUtils.h +++ b/string/public/nsBufferHandleUtils.h @@ -25,15 +25,83 @@ #ifndef nsBufferHandleUtils_h___ #define nsBufferHandleUtils_h___ -#ifndef nsAReadableString_h___ -#include "nsAReadableString.h" - // for |basic_nsAReadableString|... +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" #endif #include // for placement |new| +template +class nsAutoBufferHandle + { + public: + nsAutoBufferHandle() : mHandle(0) { } + + nsAutoBufferHandle( const nsAutoBufferHandle& aOther ) + : mHandle(aOther.get()) + { + if ( mHandle) + mHandle->AcquireReference(); + } + + explicit + nsAutoBufferHandle( const nsSharedBufferHandle* aHandle ) + : mHandle(aHandle) + { + if ( mHandle) + mHandle->AcquireReference(); + } + + ~nsAutoBufferHandle() + { + if ( mHandle ) + mHandle->ReleaseReference(); + } + + nsAutoBufferHandle& + operator=( const nsSharedBufferHandle* rhs ) + { + nsSharedBufferHandle* old_handle = mHandle; + if ( (mHandle = NS_CONST_CAST(nsSharedBufferHandle*, rhs)) ) + mHandle->AcquireReference(); + if ( old_handle ) + old_handle->ReleaseReference(); + return *this; + } + + nsAutoBufferHandle& + operator=( const nsAutoBufferHandle& rhs ) + { + return operator=(rhs.get()); + } + + nsSharedBufferHandle* + get() const + { + return mHandle; + } + + operator nsSharedBufferHandle*() const + { + return get(); + } + + nsSharedBufferHandle* + operator->() const + { + return get(); + } + + private: + nsSharedBufferHandle* mHandle; + }; + template inline @@ -62,21 +130,22 @@ NS_DataAfterHandle( HandleT* aHandlePtr, const CharT* aDummyCharTPtr ) return CharT_ptr(NS_STATIC_CAST(unsigned char*, aHandlePtr) + NS_AlignedHandleSize(aHandlePtr, aDummyCharTPtr)); } -template +template HandleT* -NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const basic_nsAReadableString& aDataSource, PRUint32 aAdditionalCapacity ) +NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const StringT& aDataSource, PRUint32 aAdditionalCapacity ) { - typedef CharT* CharT_ptr; + typedef typename StringT::char_type char_type; + typedef char_type* char_ptr; // figure out the number of bytes needed the |HandleT| part, including padding to correctly align the data part - size_t handle_size = NS_AlignedHandleSize(aDummyHandlePtr, CharT_ptr(0)); + size_t handle_size = NS_AlignedHandleSize(aDummyHandlePtr, char_ptr(0)); - // figure out how many |CharT|s wee need to fit in the data part + // figure out how many |char_type|s wee need to fit in the data part size_t data_length = aDataSource.Length(); size_t buffer_length = data_length + aAdditionalCapacity; // how many bytes is that (including a zero-terminator so we can claim to be flat)? - size_t buffer_size = buffer_length * sizeof(CharT); + size_t buffer_size = buffer_length * sizeof(char_type); HandleT* result = 0; @@ -84,17 +153,17 @@ NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const basic if ( handle_ptr ) { - CharT* data_start_ptr = CharT_ptr(NS_STATIC_CAST(unsigned char*, handle_ptr) + handle_size); - CharT* data_end_ptr = data_start_ptr + data_length; - CharT* buffer_end_ptr = data_start_ptr + buffer_length; + char_ptr data_start_ptr = char_ptr(NS_STATIC_CAST(unsigned char*, handle_ptr) + handle_size); + char_ptr data_end_ptr = data_start_ptr + data_length; + char_ptr buffer_end_ptr = data_start_ptr + buffer_length; - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = data_start_ptr; + typename StringT::const_iterator fromBegin, fromEnd; + char_ptr toBegin = data_start_ptr; copy_string(aDataSource.BeginReading(fromBegin), aDataSource.EndReading(fromEnd), toBegin); // and if the caller bothered asking for a buffer bigger than their string, we'll zero-terminate if ( aAdditionalCapacity > 0 ) - *toBegin = CharT(0); + *toBegin = char_type(0); result = new (handle_ptr) HandleT(data_start_ptr, data_end_ptr, data_start_ptr, buffer_end_ptr, PR_TRUE); } diff --git a/string/public/nsCharTraits.h b/string/public/nsCharTraits.h index dc4b681a1f5e..32f0fb58c4ec 100644 --- a/string/public/nsCharTraits.h +++ b/string/public/nsCharTraits.h @@ -35,6 +35,9 @@ // for |PRUnichar| #endif +#ifndef nsStringIteratorUtils_h___ +#include "nsStringIteratorUtils.h" +#endif #ifdef HAVE_CPP_BOOL typedef bool nsCharTraits_bool; @@ -45,8 +48,8 @@ template struct nsCharTraits { - typedef CharT char_type; - typedef char incompatible_char_type; + typedef CharT char_type; + typedef char incompatible_char_type; static void @@ -210,8 +213,8 @@ struct nsCharTraits NS_SPECIALIZE_TEMPLATE struct nsCharTraits { - typedef char char_type; - typedef PRUnichar incompatible_char_type; + typedef char char_type; + typedef PRUnichar incompatible_char_type; static void @@ -337,7 +340,7 @@ struct nsCharTraits NS_SPECIALIZE_TEMPLATE struct nsCharTraits { - typedef wchar_t char_type; + typedef wchar_t char_type; static void @@ -460,7 +463,6 @@ struct nsCharTraits }; #endif - template struct nsCharSourceTraits { diff --git a/string/public/nsCommonString.h b/string/public/nsCommonString.h new file mode 100644 index 000000000000..64a5f9e438da --- /dev/null +++ b/string/public/nsCommonString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsCommonString.h --- a string implementation that shares its underlying storage */ + + +#ifndef nsCommonString_h___ +#define nsCommonString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + +#ifndef nsBufferHandleUtils_h___ +#include "nsBufferHandleUtils.h" +#endif + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + /** + * Not yet ready for non-|const| access + */ + +class NS_COM nsCommonString + : public nsAFlatString + { + public: + typedef nsCommonString self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + + public: + nsCommonString() { } + nsCommonString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +class NS_COM nsCommonCString + : public nsAFlatCString + { + public: + typedef nsCommonCString self_type; + typedef char char_type; + typedef nsACString string_type; + + public: + nsCommonCString() { } + nsCommonCString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonCString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +#endif /* !defined(nsCommonString_h___) */ diff --git a/string/public/nsDependentConcatenation.h b/string/public/nsDependentConcatenation.h new file mode 100644 index 000000000000..3339087112f8 --- /dev/null +++ b/string/public/nsDependentConcatenation.h @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsPromiseConcatenation.h --- string concatenation machinery lives here, but don't include this file + directly, always get it by including either "nsAString.h" or one of the compatibility headers */ + +#ifndef nsPromiseConcatenation_h___ +#define nsPromiseConcatenation_h___ + + /** + NOT FOR USE BY HUMANS + + Instances of this class only exist as anonymous temporary results from |operator+()|. + This is the machinery that makes string concatenation efficient. No allocations or + character copies are required unless and until a final assignment is made. It works + its magic by overriding and forwarding calls to |GetReadableFragment()|. + + Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. + - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| + - left to right evaluation is required ... do not use parentheses to override this + + In practice, neither of these is onerous. Parentheses do not change the semantics of the + concatenation, only the order in which the result is assembled ... so there's no reason + for a user to need to control it. Too many strings summed together can easily be worked + around with an intermediate assignment. I wouldn't have the parentheses limitation if I + assigned the identifier mask starting at the top, the first time anybody called + |GetReadableFragment()|. + */ + +class NS_COM nsPromiseConcatenation + : public nsAPromiseString + { + public: + typedef nsPromiseConcatenation self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + +class NS_COM nsPromiseCConcatenation + : public nsAPromiseCString + { + public: + typedef nsPromiseCConcatenation self_type; + typedef char char_type; + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseCConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + + /* + How shall we provide |operator+()|? + + What would it return? It has to return a stack based object, because the client will + not be given an opportunity to handle memory management in an expression like + + myWritableString = stringA + stringB + stringC; + + ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could + return an |nsString|, if that name were in scope here, though there's no telling what the client + will really want to do with the result. What might be better, though, + is to return a `promise' to concatenate some strings... + + By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle + assignment and other interesting uses within writable strings, plus we drastically reduce + the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings + in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work + to implement the virtual functions of readables. + */ + +inline +const nsPromiseConcatenation +operator+( const nsPromiseConcatenation& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseCConcatenation +operator+( const nsPromiseCConcatenation& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseConcatenation +operator+( const nsAString& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs); + } + +inline +const nsPromiseCConcatenation +operator+( const nsACString& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs); + } + +#if 0 +inline +const nsPromiseConcatenation +nsPromiseConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } + +inline +const nsPromiseCConcatenation +nsPromiseCConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseCConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } +#endif + + +#endif /* !defined(nsPromiseConcatenation_h___) */ diff --git a/string/public/nsDependentString.h b/string/public/nsDependentString.h new file mode 100644 index 000000000000..59bc4a94b3b5 --- /dev/null +++ b/string/public/nsDependentString.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLocalString_h___ +#define nsLocalString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + + /* + ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. + + Use it like this: + + SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); + + With some tweaking, I think I can make this work as well... + + SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); + + This class just holds a pointer. If you don't supply the length, it must calculate it. + No copying or allocations are performed. + + |const nsLocalString&| appears frequently in interfaces because it + allows the automatic conversion of a |PRUnichar*|. + */ + +class NS_COM nsLocalString + : public nsAFlatString + { + public: + + explicit + nsLocalString( const PRUnichar* aLiteral ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)) + { + // nothing else to do here + } + + nsLocalString( const PRUnichar* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), NS_CONST_CAST(PRUnichar*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)); + } + } + + // nsLocalString( const nsLocalString& ); // auto-generated copy-constructor OK + // ~nsLocalString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalString& ); // we're immutable + }; + + + +class NS_COM nsLocalCString + : public nsAFlatCString + { + public: + + explicit + nsLocalCString( const char* aLiteral ) + : mHandle(NS_CONST_CAST(char*, aLiteral), aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)) + { + // nothing else to do here + } + + nsLocalCString( const char* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(char*, aLiteral), NS_CONST_CAST(char*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)); + } + } + + // nsLocalCString( const nsLocalCString& ); // auto-generated copy-constructor OK + // ~nsLocalCString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalCString& ); // we're immutable + }; + +#endif /* !defined(nsLocalString_h___) */ diff --git a/string/public/nsDependentSubstring.h b/string/public/nsDependentSubstring.h new file mode 100644 index 000000000000..afbe0890f598 --- /dev/null +++ b/string/public/nsDependentSubstring.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseSubstring_h___ +#define nsPromiseSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + + + + // + // nsPromiseSubstring + // + +class NS_COM nsPromiseSubstring + : public nsAPromiseString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + +class NS_COM nsPromiseCSubstring + : public nsAPromiseCString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseCSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseCSubstring( const nsPromiseCSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseCSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + + + + + + + +inline +const nsPromiseCSubstring +Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseCSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseSubstring +Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseCSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseCSubstring(aStart, aEnd); + } + +inline +const nsPromiseSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseSubstring(aStart, aEnd); + } + + +#endif /* !defined(nsPromiseSubstring_h___) */ diff --git a/string/public/nsFragmentedString.h b/string/public/nsFragmentedString.h index e5348b42f48a..3201a699d63f 100644 --- a/string/public/nsFragmentedString.h +++ b/string/public/nsFragmentedString.h @@ -27,8 +27,8 @@ // WORK IN PROGRESS -#ifndef nsAWritableString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" #endif #ifndef nsSharedBufferList_h___ @@ -37,7 +37,7 @@ class nsFragmentedString - : public basic_nsAWritableString + : public nsAString /* ... */ @@ -57,10 +57,10 @@ class nsFragmentedString // virtual void Cut( PRUint32 cutStart, PRUint32 cutLength ); protected: - // virtual void do_AssignFromReadable( const basic_nsAReadableString& ); - // virtual void do_AppendFromReadable( const basic_nsAReadableString& ); - // virtual void do_InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - // virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); + // virtual void do_AssignFromReadable( const nsAString& ); + // virtual void do_AppendFromReadable( const nsAString& ); + // virtual void do_InsertFromReadable( const nsAString&, PRUint32 ); + // virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const nsAString& ); private: nsSharedBufferList mBufferList; diff --git a/string/public/nsLiteralString.h b/string/public/nsLiteralString.h new file mode 100644 index 000000000000..b5d30e01baa2 --- /dev/null +++ b/string/public/nsLiteralString.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLiteralString_h___ +#define nsLiteralString_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsLocalString_h___ +#include "nsLocalString.h" +#endif + +typedef const nsLocalString nsLiteralString; +typedef const nsLocalCString nsLiteralCString; + +#if 0 +inline +const nsLocalString +literal_string( const PRUnichar* aPtr ) + { + return nsLocalString(aPtr); + } + +inline +const nsLocalString +literal_string( const PRUnichar* aPtr, PRUint32 aLength ) + { + return nsLocalString(aPtr, aLength); + } + +inline +const nsLocalCString +literal_string( const char* aPtr ) + { + return nsLocalCString(aPtr); + } + +inline +const nsLocalCString +literal_string( const char* aPtr, PRUint32 aLength ) + { + return nsLocalCString(aPtr, aLength); + } +#endif + +#ifdef HAVE_CPP_2BYTE_WCHAR_T + #define NS_L(s) L##s + #define NS_MULTILINE_LITERAL_STRING(s) nsLiteralString(s, (sizeof(s)/sizeof(wchar_t))-1) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) nsLiteralString n(s, (sizeof(s)/sizeof(wchar_t))-1) +#else + #define NS_L(s) s + #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUCS2(s, sizeof(s)-1) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) NS_ConvertASCIItoUCS2 n(s, sizeof(s)-1) +#endif + +#define NS_LITERAL_STRING(s) NS_MULTILINE_LITERAL_STRING(NS_L(s)) +#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n,NS_L(s)) + +#define NS_LITERAL_CSTRING(s) nsLiteralCString(s, sizeof(s)-1) +#define NS_NAMED_LITERAL_CSTRING(n,s) nsLiteralCString n(s, sizeof(s)-1) + +#endif /* !defined(nsLiteralString_h___) */ diff --git a/string/public/nsLocalString.h b/string/public/nsLocalString.h new file mode 100644 index 000000000000..59bc4a94b3b5 --- /dev/null +++ b/string/public/nsLocalString.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLocalString_h___ +#define nsLocalString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + + /* + ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. + + Use it like this: + + SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); + + With some tweaking, I think I can make this work as well... + + SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); + + This class just holds a pointer. If you don't supply the length, it must calculate it. + No copying or allocations are performed. + + |const nsLocalString&| appears frequently in interfaces because it + allows the automatic conversion of a |PRUnichar*|. + */ + +class NS_COM nsLocalString + : public nsAFlatString + { + public: + + explicit + nsLocalString( const PRUnichar* aLiteral ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)) + { + // nothing else to do here + } + + nsLocalString( const PRUnichar* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), NS_CONST_CAST(PRUnichar*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)); + } + } + + // nsLocalString( const nsLocalString& ); // auto-generated copy-constructor OK + // ~nsLocalString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalString& ); // we're immutable + }; + + + +class NS_COM nsLocalCString + : public nsAFlatCString + { + public: + + explicit + nsLocalCString( const char* aLiteral ) + : mHandle(NS_CONST_CAST(char*, aLiteral), aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)) + { + // nothing else to do here + } + + nsLocalCString( const char* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(char*, aLiteral), NS_CONST_CAST(char*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)); + } + } + + // nsLocalCString( const nsLocalCString& ); // auto-generated copy-constructor OK + // ~nsLocalCString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalCString& ); // we're immutable + }; + +#endif /* !defined(nsLocalString_h___) */ diff --git a/string/public/nsPrintfCString.h b/string/public/nsPrintfCString.h index e434c8c8230f..9f3a3d1b4316 100755 --- a/string/public/nsPrintfCString.h +++ b/string/public/nsPrintfCString.h @@ -38,7 +38,9 @@ #ifndef nsPrintfCString_h___ #define nsPrintfCString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" +#endif /** @@ -66,7 +68,7 @@ */ class nsPrintfCString - : public nsAReadableCString + : public nsACString { enum { kLocalBufferSize=15 }; // ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask) @@ -81,7 +83,8 @@ class nsPrintfCString virtual PRUint32 Length() const; protected: - virtual const char* GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const; + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } // virtual PRBool GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest ) const; private: diff --git a/string/public/nsPrivateSharableString.h b/string/public/nsPrivateSharableString.h index 0c34d60d3f4c..6bf03dc0872a 100755 --- a/string/public/nsPrivateSharableString.h +++ b/string/public/nsPrivateSharableString.h @@ -30,39 +30,53 @@ #endif /** - * This class is (will be) part of the machinery that makes + * This class is part of the machinery that makes * most string implementations in this family share their underlying buffers * when convenient. It is _not_ part of the abstract string interface, * though other machinery interested in sharing buffers will know about it. + * + * Normal string clients must _never_ call routines from this interface. */ -template -class nsPrivateSharableString +class NS_COM nsPrivateSharableString { public: - virtual const nsBufferHandle* GetBufferHandle() const; - virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + typedef PRUnichar char_type; + + public: + virtual ~nsPrivateSharableString() {} + + virtual PRUint32 GetImplementationFlags() const; + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; /** - * |GetBufferHandle()| will return either |0|, |1|, or a reasonable pointer. + * |GetBufferHandle()| will return either |0|, or a reasonable pointer. * The meaning of |0| is that the string points to a non-contiguous or else empty representation. - * The meaning of |1| is implementation dependant. - * Otherwise |GetBufferHandle()| returns a pointer to the single contiguous hunk of characters - * that makes up this string. + * Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters + * that make up this string. */ }; -template -const nsSharedBufferHandle* -nsPrivateSharableString::GetSharedBufferHandle() const +class NS_COM nsPrivateSharableCString { - return 0; - } + public: + typedef char char_type; -template -const nsBufferHandle* -nsPrivateSharableString::GetBufferHandle() const - { - return GetSharedBufferHandle(); - } + public: + virtual ~nsPrivateSharableCString() {} + + virtual PRUint32 GetImplementationFlags() const; + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + /** + * |GetBufferHandle()| will return either |0|, or a reasonable pointer. + * The meaning of |0| is that the string points to a non-contiguous or else empty representation. + * Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters + * that make up this string. + */ + }; #endif // !defined(nsPrivateSharableString_h___) diff --git a/string/public/nsPromiseConcatenation.h b/string/public/nsPromiseConcatenation.h new file mode 100644 index 000000000000..3339087112f8 --- /dev/null +++ b/string/public/nsPromiseConcatenation.h @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsPromiseConcatenation.h --- string concatenation machinery lives here, but don't include this file + directly, always get it by including either "nsAString.h" or one of the compatibility headers */ + +#ifndef nsPromiseConcatenation_h___ +#define nsPromiseConcatenation_h___ + + /** + NOT FOR USE BY HUMANS + + Instances of this class only exist as anonymous temporary results from |operator+()|. + This is the machinery that makes string concatenation efficient. No allocations or + character copies are required unless and until a final assignment is made. It works + its magic by overriding and forwarding calls to |GetReadableFragment()|. + + Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. + - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| + - left to right evaluation is required ... do not use parentheses to override this + + In practice, neither of these is onerous. Parentheses do not change the semantics of the + concatenation, only the order in which the result is assembled ... so there's no reason + for a user to need to control it. Too many strings summed together can easily be worked + around with an intermediate assignment. I wouldn't have the parentheses limitation if I + assigned the identifier mask starting at the top, the first time anybody called + |GetReadableFragment()|. + */ + +class NS_COM nsPromiseConcatenation + : public nsAPromiseString + { + public: + typedef nsPromiseConcatenation self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + +class NS_COM nsPromiseCConcatenation + : public nsAPromiseCString + { + public: + typedef nsPromiseCConcatenation self_type; + typedef char char_type; + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseCConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + + /* + How shall we provide |operator+()|? + + What would it return? It has to return a stack based object, because the client will + not be given an opportunity to handle memory management in an expression like + + myWritableString = stringA + stringB + stringC; + + ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could + return an |nsString|, if that name were in scope here, though there's no telling what the client + will really want to do with the result. What might be better, though, + is to return a `promise' to concatenate some strings... + + By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle + assignment and other interesting uses within writable strings, plus we drastically reduce + the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings + in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work + to implement the virtual functions of readables. + */ + +inline +const nsPromiseConcatenation +operator+( const nsPromiseConcatenation& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseCConcatenation +operator+( const nsPromiseCConcatenation& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseConcatenation +operator+( const nsAString& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs); + } + +inline +const nsPromiseCConcatenation +operator+( const nsACString& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs); + } + +#if 0 +inline +const nsPromiseConcatenation +nsPromiseConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } + +inline +const nsPromiseCConcatenation +nsPromiseCConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseCConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } +#endif + + +#endif /* !defined(nsPromiseConcatenation_h___) */ diff --git a/string/public/nsPromiseFlatString.h b/string/public/nsPromiseFlatString.h new file mode 100644 index 000000000000..1c23bd05945b --- /dev/null +++ b/string/public/nsPromiseFlatString.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseFlatString_h___ +#define nsPromiseFlatString_h___ + +#ifndef nsCommonString_h___ +#include "nsCommonString.h" +#endif + + /** + * WARNING: + * + * Try to avoid flat strings. |PromiseFlat[C]String| will help you as a last resort, + * and this may be necessary when dealing with legacy or OS calls, but in general, + * requiring a zero-terminated contiguous hunk of characters kills many of the performance + * wins the string classes offer. Write your own code to use |nsA[C]String&|s for parameters. + * Write your string proccessing algorithms to exploit iterators. If you do this, you + * will benefit from being able to chain operations without copying or allocating and your + * code will be significantly more efficient. Remember, a function that takes an + * |const nsA[C]String&| can always be passed a raw character pointer by wrapping it (for free) + * in a |nsLocal[C]String|. But a function that takes a character pointer always has the + * potential to force allocation and copying. + * + * + * How to use it: + * + * Like all `promises', a |nsPromiseFlat[C]String| doesn't own the characters it promises. + * You must never use it to promise characters out of a string with a shorter lifespan. + * The typical use will be something like this + * + * SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD + * + * Here's a BAD use: + * + * const char* buffer = PromiseFlatCString(aCString).get(); + * SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer + * + * A |nsPromiseFlat[C]String| doesn't support non-|const| access (you can't use it to make + * changes back into the original string). To help you avoid that, the only way to make + * one is with the function |PromiseFlat[C]String|, which produce a |const| instance. + * ``What if I need to keep a promise around for a little while?'' you might ask. + * In that case, you can keep a reference, like so + * + * const nsPromiseFlatString& flat = PromiseFlatString(aString); + * // this reference holds the anonymous temporary alive, but remember, it must _still_ + * // have a lifetime shorter than that of |aString| + * + * SomeOSFunction(flat.get()); + * SomeOtherOSFunction(flat.get()); + * + * + * How does it work? + * + * A |nsPromiseFlat[C]String| is just a wrapper for another string. If you apply it to + * a string that happens to be flat, your promise is just a reference to that other string + * and all calls are forwarded through to it. If you apply it to a non-flat string, + * then a temporary flat string is created for you, by allocating and copying. In the unlikely + * event that you end up assigning the result into a sharing string (e.g., |nsCommon[C]String|), + * the right thing happens. + */ + +class NS_COM nsPromiseFlatString + : public nsAFlatString /* , public nsAPromiseString */ + { + friend const nsPromiseFlatString PromiseFlatString( const nsAString& ); + + public: + nsPromiseFlatString( const nsPromiseFlatString& ); + virtual const PRUnichar* get() const; // this will be gone after we fix obsolete/nsString + + protected: + nsPromiseFlatString() : mPromisedString(&mFlattenedString) { } + explicit nsPromiseFlatString( const nsAString& aString ); + + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseFlatString& ); + + private: + nsCommonString mFlattenedString; + const nsAFlatString* mPromisedString; + }; + +class NS_COM nsPromiseFlatCString + : public nsAFlatCString /* , public nsAPromiseCString */ + { + friend const nsPromiseFlatCString PromiseFlatCString( const nsACString& ); + + public: + nsPromiseFlatCString( const nsPromiseFlatCString& ); + virtual const char* get() const; // this will be gone after we fix obsolete/nsString + + protected: + nsPromiseFlatCString() : mPromisedString(&mFlattenedString) { } + explicit nsPromiseFlatCString( const nsACString& aString ); + + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseFlatCString& ); + + private: + nsCommonCString mFlattenedString; + const nsAFlatCString* mPromisedString; + }; + + +inline +const nsPromiseFlatString +PromiseFlatString( const nsAString& aString ) + { + return nsPromiseFlatString(aString); + } + +inline +const nsPromiseFlatCString +PromiseFlatCString( const nsACString& aString ) + { + return nsPromiseFlatCString(aString); + } + +#endif /* !defined(nsPromiseFlatString_h___) */ diff --git a/string/public/nsPromiseSubstring.h b/string/public/nsPromiseSubstring.h new file mode 100644 index 000000000000..afbe0890f598 --- /dev/null +++ b/string/public/nsPromiseSubstring.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseSubstring_h___ +#define nsPromiseSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + + + + // + // nsPromiseSubstring + // + +class NS_COM nsPromiseSubstring + : public nsAPromiseString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + +class NS_COM nsPromiseCSubstring + : public nsAPromiseCString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseCSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseCSubstring( const nsPromiseCSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseCSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + + + + + + + +inline +const nsPromiseCSubstring +Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseCSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseSubstring +Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseCSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseCSubstring(aStart, aEnd); + } + +inline +const nsPromiseSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseSubstring(aStart, aEnd); + } + + +#endif /* !defined(nsPromiseSubstring_h___) */ diff --git a/string/public/nsReadableUtils.h b/string/public/nsReadableUtils.h index 1e64cd951f7e..1057153ce72d 100755 --- a/string/public/nsReadableUtils.h +++ b/string/public/nsReadableUtils.h @@ -31,16 +31,16 @@ * According to our conventions, they should be |NS_xxx|. */ -#ifndef nsAWritableString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" #endif NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); -NS_COM void CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ); -NS_COM void CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ); +NS_COM void CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ); /** * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. @@ -53,7 +53,7 @@ NS_COM void CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableStrin * @param aSource a 16-bit wide string * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewCString( const nsAReadableString& aSource ); +NS_COM char* ToNewCString( const nsAString& aSource ); /** @@ -65,7 +65,7 @@ NS_COM char* ToNewCString( const nsAReadableString& aSource ); * @param aSource an 8-bit wide string * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewCString( const nsAReadableCString& aSource ); +NS_COM char* ToNewCString( const nsACString& aSource ); /** * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. @@ -78,7 +78,7 @@ NS_COM char* ToNewCString( const nsAReadableCString& aSource ); * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewUTF8String( const nsAReadableString& aSource ); +NS_COM char* ToNewUTF8String( const nsAString& aSource ); /** @@ -90,7 +90,7 @@ NS_COM char* ToNewUTF8String( const nsAReadableString& aSource ); * @param aSource a 16-bit wide string * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. */ -NS_COM PRUnichar* ToNewUnicode( const nsAReadableString& aSource ); +NS_COM PRUnichar* ToNewUnicode( const nsAString& aSource ); /** @@ -104,7 +104,7 @@ NS_COM PRUnichar* ToNewUnicode( const nsAReadableString& aSource ); * @param aSource an 8-bit wide string * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. */ -NS_COM PRUnichar* ToNewUnicode( const nsAReadableCString& aSource ); +NS_COM PRUnichar* ToNewUnicode( const nsACString& aSource ); /** * Copies |aLength| 16-bit characters from the start of |aSource| to the @@ -118,7 +118,7 @@ NS_COM PRUnichar* ToNewUnicode( const nsAReadableCString& aSource ); * @param aLength the number of 16-bit characters to copy * @return pointer to destination buffer - identical to |aDest| */ -NS_COM PRUnichar* CopyUnicodeTo( const nsAReadableString& aSource, +NS_COM PRUnichar* CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ); @@ -137,7 +137,7 @@ NS_COM PRUnichar* CopyUnicodeTo( const nsAReadableString& aSource, */ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ); + nsAString& aDest ); /** * Appends 16-bit characters between iterators |aSrcStart| and @@ -151,25 +151,25 @@ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, */ NS_COM void AppendUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ); + nsAString& aDest ); /** * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). * * @param aString a 16-bit wide string to scan */ -NS_COM PRBool IsASCII( const nsAReadableString& aString ); +NS_COM PRBool IsASCII( const nsAString& aString ); /** * Converts case in place in the argument string. */ -NS_COM void ToUpperCase( nsAWritableString& ); -NS_COM void ToUpperCase( nsAWritableCString& ); +NS_COM void ToUpperCase( nsAString& ); +NS_COM void ToUpperCase( nsACString& ); -NS_COM void ToLowerCase( nsAWritableString& ); -NS_COM void ToLowerCase( nsAWritableCString& ); +NS_COM void ToLowerCase( nsAString& ); +NS_COM void ToLowerCase( nsACString& ); /** * Finds the leftmost occurance of |aPattern|, if any in the range |aSearchStart|..|aSearchEnd|. @@ -180,8 +180,8 @@ NS_COM void ToLowerCase( nsAWritableCString& ); * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. * If we need something faster; we can implement that later. */ -NS_COM PRBool FindInReadable( const nsAReadableString& aPattern, nsReadingIterator&, nsReadingIterator& ); -NS_COM PRBool FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool FindInReadable( const nsAString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool FindInReadable( const nsACString& aPattern, nsReadingIterator&, nsReadingIterator& ); /** @@ -192,8 +192,8 @@ NS_COM PRBool FindInReadable( const nsAReadableCString& aPattern, nsReadingItera * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. * If we need something faster; we can implement that later. */ -NS_COM PRBool RFindInReadable( const nsAReadableString& aPattern, nsReadingIterator&, nsReadingIterator& ); -NS_COM PRBool RFindInReadable( const nsAReadableCString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool RFindInReadable( const nsAString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool RFindInReadable( const nsACString& aPattern, nsReadingIterator&, nsReadingIterator& ); /** * Finds the leftmost occurance of |aChar|, if any in the range @@ -209,9 +209,9 @@ NS_COM PRBool FindCharInReadable( char aChar, nsReadingIterator& aSearchSt /** * Finds the number of occurences of |aChar| in the string |aStr| */ -NS_COM PRUint32 CountCharInReadable( const nsAReadableString& aStr, +NS_COM PRUint32 CountCharInReadable( const nsAString& aStr, PRUnichar aChar ); -NS_COM PRUint32 CountCharInReadable( const nsAReadableCString& aStr, +NS_COM PRUint32 CountCharInReadable( const nsACString& aStr, char aChar ); #endif // !defined(nsReadableUtils_h___) diff --git a/string/public/nsSharableString.h b/string/public/nsSharableString.h new file mode 100644 index 000000000000..64a5f9e438da --- /dev/null +++ b/string/public/nsSharableString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsCommonString.h --- a string implementation that shares its underlying storage */ + + +#ifndef nsCommonString_h___ +#define nsCommonString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + +#ifndef nsBufferHandleUtils_h___ +#include "nsBufferHandleUtils.h" +#endif + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + /** + * Not yet ready for non-|const| access + */ + +class NS_COM nsCommonString + : public nsAFlatString + { + public: + typedef nsCommonString self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + + public: + nsCommonString() { } + nsCommonString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +class NS_COM nsCommonCString + : public nsAFlatCString + { + public: + typedef nsCommonCString self_type; + typedef char char_type; + typedef nsACString string_type; + + public: + nsCommonCString() { } + nsCommonCString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonCString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +#endif /* !defined(nsCommonString_h___) */ diff --git a/string/public/nsSharedBufferList.h b/string/public/nsSharedBufferList.h index a97c2af1ec60..4fda3118cb82 100755 --- a/string/public/nsSharedBufferList.h +++ b/string/public/nsSharedBufferList.h @@ -35,9 +35,12 @@ // for |PRUnichar| #endif -#ifndef nsAReadableString_h___ -#include "nsAReadableString.h" - // for |nsReadingIterator| +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsLocalString_h___ +#include "nsLocalString.h" #endif #ifndef nsBufferHandleUtils_h___ @@ -180,12 +183,12 @@ class NS_COM nsSharedBufferList NewSingleAllocationBuffer( const PRUnichar* aData, PRUint32 aDataLength, PRUint32 aAdditionalCapacity = 1 ) { typedef Buffer* Buffer_ptr; - return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), NS_READABLE_CAST(PRUnichar, nsLiteralString(aData, aDataLength)), aAdditionalCapacity); + return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), nsLocalString(aData, aDataLength), aAdditionalCapacity); } static Buffer* - NewSingleAllocationBuffer( const nsAReadableString& aReadable, PRUint32 aAdditionalCapacity = 1 ) + NewSingleAllocationBuffer( const nsAString& aReadable, PRUint32 aAdditionalCapacity = 1 ) { typedef Buffer* Buffer_ptr; return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), aReadable, aAdditionalCapacity); diff --git a/string/public/nsSlidingString.h b/string/public/nsSlidingString.h index 079e7e2f1eb3..abe764b04135 100755 --- a/string/public/nsSlidingString.h +++ b/string/public/nsSlidingString.h @@ -25,8 +25,13 @@ #ifndef nsSlidingString_h___ #define nsSlidingString_h___ -#include "nsAReadableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsSharedBufferList_h___ #include "nsSharedBufferList.h" +#endif /** @@ -69,7 +74,7 @@ class nsSlidingString; * a substring over a buffer list, this */ class NS_COM nsSlidingSubstring - : virtual public nsPromiseReadable + : virtual public nsAPromiseString { friend class nsSlidingString; @@ -90,14 +95,14 @@ class NS_COM nsSlidingSubstring nsSlidingSubstring( const nsSlidingSubstring& aString, const nsReadingIterator& aStart, const nsReadingIterator& aEnd ); nsSlidingSubstring( const nsSlidingString& ); nsSlidingSubstring( const nsSlidingString& aString, const nsReadingIterator& aStart, const nsReadingIterator& aEnd ); - explicit nsSlidingSubstring( const nsAReadableString& ); + explicit nsSlidingSubstring( const nsAString& ); // copy the supplied string into a new buffer ... there will be no modifying instance over this buffer list void Rebind( const nsSlidingSubstring& ); void Rebind( const nsSlidingSubstring&, const nsReadingIterator&, const nsReadingIterator& ); void Rebind( const nsSlidingString& ); void Rebind( const nsSlidingString&, const nsReadingIterator&, const nsReadingIterator& ); - void Rebind( const nsAReadableString& ); + void Rebind( const nsAString& ); ~nsSlidingSubstring(); @@ -106,6 +111,7 @@ class NS_COM nsSlidingSubstring protected: nsSlidingSubstring( nsSlidingSharedBufferList* aBufferList ); virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } private: // can't assign into me, I'm a read-only reference @@ -154,7 +160,7 @@ class NS_COM nsSlidingSubstring * */ class NS_COM nsSlidingString - : virtual public nsPromiseReadable, + : virtual public nsAPromiseString, private nsSlidingSubstring { friend class nsSlidingSubstring; @@ -176,8 +182,9 @@ class NS_COM nsSlidingString protected: virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } - void InsertReadable( const nsAReadableString&, const nsReadingIterator& ); // ...to implement |nsScannerString::UngetReadable| + void InsertReadable( const nsAString&, const nsReadingIterator& ); // ...to implement |nsScannerString::UngetReadable| private: diff --git a/string/public/nsStringFragment.h b/string/public/nsStringFragment.h new file mode 100644 index 000000000000..0a8238023e91 --- /dev/null +++ b/string/public/nsStringFragment.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringFragment.h --- machinery that makes string iterators work */ + +#ifndef nsStringFragment_h___ +#define nsStringFragment_h___ + + + + /** + * An |nsFragmentRequest| is used to tell |GetReadableFragment| and + * |GetWritableFragment| what to do. + * + * @see GetReadableFragment + */ + +enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; + + + /** + * A |nsReadableFragment| provides |const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsReadableFragment| is the underlying machinery that lets + * |nsReadingIterator|s work. + * + * @see nsReadingIterator + */ + +template +struct nsReadableFragment + { + const CharT* mStart; + const CharT* mEnd; + const void* mFragmentIdentifier; + + nsReadableFragment() + : mStart(0), mEnd(0), mFragmentIdentifier(0) + { + // nothing else to do here + } + }; + + + /** + * A |nsWritableFragment| provides non-|const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsWritableFragment| is the underlying machinery that lets + * |nsWritingIterator|s work. + * + * @see nsWritingIterator + */ + +template +struct nsWritableFragment + { + CharT* mStart; + CharT* mEnd; + void* mFragmentIdentifier; + + nsWritableFragment() + : mStart(0), mEnd(0), mFragmentIdentifier(0) + { + // nothing else to do here + } + }; + +#endif /* !defined(nsStringFragment_h___) */ diff --git a/string/public/nsStringFwd.h b/string/public/nsStringFwd.h new file mode 100644 index 000000000000..b1caa033c51a --- /dev/null +++ b/string/public/nsStringFwd.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringFwd.h --- forward declarations for string classes */ + +#ifndef nsStringFwd_h___ +#define nsStringFwd_h___ + + + /** + * @see nsAString.h + */ + +class nsAString; +class nsACString; + + + /** + * @see nsAPromiseString.h + */ + +class nsAPromiseString; +class nsAPromiseCString; + + + /** + * @see nsAFlatString.h + */ + +class nsAFlatString; +class nsAFlatCString; + + + /** + * @see nsLocalString.h + */ + +class nsLocalString; +class nsLocalCString; + +#endif /* !defined(nsStringFwd_h___) */ diff --git a/string/public/nsStringIterator.h b/string/public/nsStringIterator.h new file mode 100644 index 000000000000..2305e232dc4b --- /dev/null +++ b/string/public/nsStringIterator.h @@ -0,0 +1,436 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsStringIterator_h___ +#define nsStringIterator_h___ + +#ifndef nsStringFragment_h___ +#include "nsStringFragment.h" +#endif + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + +#ifndef nsAlgorithm_h___ +#include "nsAlgorithm.h" + // for |NS_MIN|, |NS_MAX|, and |NS_COUNT|... +#endif + + + + + + + /** + * + * @see nsReadableFragment + * @see nsAString + */ + +template +class nsReadingIterator +// : public bidirectional_iterator_tag + { + public: + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef const CharT* pointer; + typedef const CharT& reference; +// typedef bidirectional_iterator_tag iterator_category; + + private: + friend class nsAString; + friend class nsACString; + typedef typename nsStringTraits::abstract_string_type string_type; + + nsReadableFragment mFragment; + const CharT* mPosition; + const string_type* mOwningString; + + public: + nsReadingIterator() { } + // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK + // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward(); + inline void normalize_backward(); + + pointer + get() const + { + return mPosition; + } + + CharT + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + nsReadingIterator& + operator++() + { + ++mPosition; + normalize_forward(); + return *this; + } + + nsReadingIterator + operator++( int ) + { + nsReadingIterator result(*this); + ++mPosition; + normalize_forward(); + return result; + } + + nsReadingIterator& + operator--() + { + normalize_backward(); + --mPosition; + return *this; + } + + nsReadingIterator + operator--( int ) + { + nsReadingIterator result(*this); + normalize_backward(); + --mPosition; + return result; + } + + const nsReadableFragment& + fragment() const + { + return mFragment; + } + + const string_type& + string() const + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + difference_type + size_forward() const + { + return mFragment.mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mFragment.mStart; + } + + nsReadingIterator& + 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; + } + }; + +template +class nsWritingIterator +// : public nsReadingIterator + { + public: + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef CharT* pointer; + typedef CharT& reference; +// typedef bidirectional_iterator_tag iterator_category; + + private: + friend class nsAString; + friend class nsACString; + typedef typename nsStringTraits::abstract_string_type string_type; + + nsWritableFragment mFragment; + CharT* mPosition; + string_type* mOwningString; + + public: + nsWritingIterator() { } + // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK + // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward(); + inline void normalize_backward(); + + pointer + get() const + { + return mPosition; + } + + reference + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + nsWritingIterator& + operator++() + { + ++mPosition; + normalize_forward(); + return *this; + } + + nsWritingIterator + operator++( int ) + { + nsWritingIterator result(*this); + ++mPosition; + normalize_forward(); + return result; + } + + nsWritingIterator& + operator--() + { + normalize_backward(); + --mPosition; + return *this; + } + + nsWritingIterator + operator--( int ) + { + nsWritingIterator result(*this); + normalize_backward(); + --mPosition; + return result; + } + + const nsWritableFragment& + fragment() const + { + return mFragment; + } + + nsWritableFragment& + fragment() + { + return mFragment; + } + + const string_type& + string() const + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + string_type& + string() + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + difference_type + size_forward() const + { + return mFragment.mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mFragment.mStart; + } + + nsWritingIterator& + 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 writing 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 writing iterator beyond the end of a string"); + // perhaps I should |break| if |!one_hop|? + + mPosition += one_hop; + n -= one_hop; + } + + return *this; + } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); + + n = NS_MIN(n, PRUint32(size_forward())); + nsCharTraits::move(mPosition, s, n); + advance( difference_type(n) ); + return n; + } + }; + +template +inline +void +nsReadingIterator::normalize_forward() + { + while ( mPosition == mFragment.mEnd + && mOwningString->GetReadableFragment(mFragment, kNextFragment) ) + mPosition = mFragment.mStart; + } + +template +inline +void +nsReadingIterator::normalize_backward() + { + while ( mPosition == mFragment.mStart + && mOwningString->GetReadableFragment(mFragment, kPrevFragment) ) + mPosition = mFragment.mEnd; + } + +template +inline +PRBool +operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + + + // + // |nsWritingIterator|s + // + +template +inline +void +nsWritingIterator::normalize_forward() + { + while ( mPosition == mFragment.mEnd + && mOwningString->GetWritableFragment(mFragment, kNextFragment) ) + mPosition = mFragment.mStart; + } + +template +inline +void +nsWritingIterator::normalize_backward() + { + while ( mPosition == mFragment.mStart + && mOwningString->GetWritableFragment(mFragment, kPrevFragment) ) + mPosition = mFragment.mEnd; + } + +template +inline +PRBool +operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + +#endif /* !defined(nsStringIterator_h___) */ diff --git a/string/public/nsStringIteratorUtils.h b/string/public/nsStringIteratorUtils.h new file mode 100644 index 000000000000..0d74365c1eb0 --- /dev/null +++ b/string/public/nsStringIteratorUtils.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsStringIteratorUtils_h___ +#define nsStringIteratorUtils_h___ + +template +inline +PRBool +SameFragment( const Iterator& lhs, const Iterator& rhs ) + { + return lhs.fragment().mStart == rhs.fragment().mStart; + } + +template class nsReadingIterator; + + // NOTE: need to break iterators out into their own file (as with many classes here), need + // these routines, but can't currently |#include "nsReadableUtils.h"|, this hack is bad + // but we need it to get OS2 building again. Fix by splitting things into different files. +NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); +NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); + + +#endif /* !defined(nsStringIteratorUtils_h___) */ diff --git a/string/public/nsStringTraits.h b/string/public/nsStringTraits.h new file mode 100644 index 000000000000..1f41b5b596b5 --- /dev/null +++ b/string/public/nsStringTraits.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringTraits.h --- declares specialized ``traits'' classes which allow templatized functions and classes to select appropriate non-template types */ + +#ifndef nsStringTraits_h___ +#define nsStringTraits_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + + + + /** + * + */ + +template +struct nsStringTraits + { + typedef nsAString abstract_string_type; + typedef nsAPromiseString abstract_promise_type; + typedef nsAFlatString abstract_flat_type; + typedef const nsLocalString literal_string_type; + }; + +#if 0 + // for lame compilers, put these declarations into the general case + // so we only need to specialize for |char| +NS_SPECIALIZE_TEMPLATE +struct nsStringTraits + { + typedef nsAString abstract_string_type; + typedef nsAPromiseString abstract_promise_type; + typedef nsAFlatString abstract_flat_type; + typedef const nsLocalString literal_string_type; + }; +#endif + +NS_SPECIALIZE_TEMPLATE +struct nsStringTraits + { + typedef nsACString abstract_string_type; + typedef nsAPromiseCString abstract_promise_type; + typedef nsAFlatCString abstract_flat_type; + typedef const nsLocalCString literal_string_type; + }; + + +#endif /* !defined(nsStringTraits_h___) */ diff --git a/string/src/Makefile.in b/string/src/Makefile.in index fdec9c555597..8ca522cde25e 100644 --- a/string/src/Makefile.in +++ b/string/src/Makefile.in @@ -18,6 +18,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH = ../.. @@ -33,8 +34,16 @@ LIBRARY_NAME = string_s REQUIRES = xpcom CPPSRCS = \ + nsAFlatString.cpp \ + nsAString.cpp \ + nsCommonString.cpp \ nsFragmentedString.cpp \ + nsLocalString.cpp \ nsPrintfCString.cpp \ + nsPrivateSharableString.cpp \ + nsPromiseConcatenation.cpp \ + nsPromiseFlatString.cpp \ + nsPromiseSubstring.cpp \ nsReadableUtils.cpp \ nsSharedBufferList.cpp \ nsSlidingString.cpp \ diff --git a/string/src/makefile.win b/string/src/makefile.win index 4442c23ef74a..608ec516b6a5 100644 --- a/string/src/makefile.win +++ b/string/src/makefile.win @@ -19,6 +19,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH=..\.. @@ -28,8 +29,16 @@ LIBRARY_NAME=string_s LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN CPP_OBJS = \ + .\$(OBJDIR)\nsAFlatString.obj \ + .\$(OBJDIR)\nsAString.obj \ + .\$(OBJDIR)\nsCommonString.obj \ .\$(OBJDIR)\nsFragmentedString.obj \ + .\$(OBJDIR)\nsLocalString.obj \ .\$(OBJDIR)\nsPrintfCString.obj \ + .\$(OBJDIR)\nsPrivateSharableString.obj \ + .\$(OBJDIR)\nsPromiseConcatenation.obj \ + .\$(OBJDIR)\nsPromiseFlatString.obj \ + .\$(OBJDIR)\nsPromiseSubstring.obj \ .\$(OBJDIR)\nsReadableUtils.obj \ .\$(OBJDIR)\nsSharedBufferList.obj \ .\$(OBJDIR)\nsSlidingString.obj \ diff --git a/string/src/nsAFlatString.cpp b/string/src/nsAFlatString.cpp new file mode 100644 index 000000000000..143f2c419f58 --- /dev/null +++ b/string/src/nsAFlatString.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsAFlatString.h" + +const PRUnichar* +nsAFlatString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + const nsBufferHandle* buffer = GetBufferHandle(); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +PRUnichar* +nsAFlatString::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + nsBufferHandle* buffer = NS_CONST_CAST(nsBufferHandle*, GetBufferHandle()); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +const char* +nsAFlatCString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + const nsBufferHandle* buffer = GetBufferHandle(); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +char* +nsAFlatCString::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + nsBufferHandle* buffer = NS_CONST_CAST(nsBufferHandle*, GetBufferHandle()); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } diff --git a/string/src/nsAString.cpp b/string/src/nsAString.cpp new file mode 100644 index 000000000000..d08cc12796a7 --- /dev/null +++ b/string/src/nsAString.cpp @@ -0,0 +1,921 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsAString.h" +#include "nsPromiseSubstring.h" +#include "nsLocalString.h" + + +NS_COM +int +Compare( const nsAString& lhs, const nsAString& rhs ) + { + typedef nsAString::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + size_type lLength = lhs.Length(); + size_type rLength = rhs.Length(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + nsAString::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + int result; + + for (;;) + { + size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); + + if ( lengthAvailable > lengthToCompare ) + lengthAvailable = lengthToCompare; + + // Note: |result| should be declared in this |if| expression, but some compilers don't like that + if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) + return result; + + if ( !(lengthToCompare -= lengthAvailable) ) + break; + + leftIter.advance( PRInt32(lengthAvailable) ); + rightIter.advance( PRInt32(lengthAvailable) ); + } + + if ( lLength < rLength ) + return -1; + else if ( rLength < lLength ) + return 1; + else + return 0; + } + +PRBool +nsAString::Equals( const char_type* rhs ) const + { + return Equals(nsLocalString(rhs)); + } + + + +nsAString::char_type +nsAString::First() const + { + NS_ASSERTION(Length()>0, "|First()| on an empty string"); + + const_iterator iter; + return *BeginReading(iter); + } + +nsAString::char_type +nsAString::Last() const + { + NS_ASSERTION(Length()>0, "|Last()| on an empty string"); + + const_iterator iter; + + if ( !IsEmpty() ) + { + EndReading(iter); + iter.advance(-1); + } + + return *iter; // Note: this has undefined results if |IsEmpty()| + } + +nsAString::size_type +nsAString::CountChar( char_type c ) const + { + /* + re-write this to use a counting sink + */ + + size_type result = 0; + size_type lengthToExamine = Length(); + + const_iterator iter; + for ( BeginReading(iter); ; ) + { + PRInt32 lengthToExamineInThisFragment = iter.size_forward(); + const char_type* fromBegin = iter.get(); + result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); + if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) + return result; + iter.advance(lengthToExamineInThisFragment); + } + // never reached; quiets warnings + return 0; + } + +nsAString::size_type +nsAString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + // If we're just assigning our entire self, give |aResult| the opportunity to share + if ( aStartPos == 0 && aLengthToCopy >= Length() ) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.Length(); + } + +nsAString::size_type +nsAString::Right( self_type& aResult, size_type aLengthToCopy ) const + { + size_type myLength = Length(); + aLengthToCopy = NS_MIN(myLength, aLengthToCopy); + return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); + } + +PRInt32 +nsAString::FindChar( char_type aChar, PRUint32 aOffset ) const + { + const_iterator iter, done_searching; + BeginReading(iter).advance( PRInt32(aOffset) ); + EndReading(done_searching); + + size_type lengthSearched = 0; + while ( iter != done_searching ) + { + PRInt32 fragmentLength = iter.size_forward(); + const char_type* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); + if ( charFoundAt ) + return lengthSearched + (charFoundAt-iter.get()) + aOffset; + + lengthSearched += fragmentLength; + iter.advance(fragmentLength); + } + + return -1; + } + + + // + // |Assign()| + // + +void +nsAString::AssignFromReadable( const self_type& rhs ) + { + if ( this != &rhs ) + do_AssignFromReadable(rhs); + // else, self-assign is a no-op + } + +void +nsAString::AssignFromPromise( const self_type& aReadable ) + /* + ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. + E.g., + + ... writable& w ... + ... readable& r ... + + w = r + w; + + In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before + anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents + of |r| before being retrieved to be appended. + + We could have a really tricky solution where we tell the promise to resolve _just_ the data promised + by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., + in the case above, |Insert| could have special behavior with significantly better performance. Since + it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the + entire promise. If we measure and this turns out to show up on performance radar, we then have the + option to fix either the callers or this mechanism. + */ + { + if ( !aReadable.Promises(*this) ) + do_AssignFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + // Note: not exception safe. We need something to manage temporary buffers like this + + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AssignFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_AssignFromReadable( const self_type& aReadable ) + { + SetLength(0); + SetLength(aReadable.Length()); + // first setting the length to |0| avoids copying characters only to be overwritten later + // in the case where the implementation decides to re-allocate + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); + } + +void +nsAString::do_AssignFromElementPtr( const char_type* aPtr ) + { + do_AssignFromReadable(nsLocalString(aPtr)); + } + +void +nsAString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength ) + { + do_AssignFromReadable(nsLocalString(aPtr, aLength)); + } + +void +nsAString::do_AssignFromElement( char_type aChar ) + { + do_AssignFromReadable(nsLocalString(&aChar, 1)); + } + + + + // + // |Append()| + // + +void +nsAString::AppendFromReadable( const self_type& aReadable ) + { + if ( this != &aReadable ) + do_AppendFromReadable(aReadable); + else + AppendFromPromise(aReadable); + } + +void +nsAString::AppendFromPromise( const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_AppendFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AppendFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_AppendFromReadable( const self_type& aReadable ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); + } + +void +nsAString::do_AppendFromElementPtr( const char_type* aChar ) + { + do_AppendFromReadable(nsLocalString(aChar)); + } + +void +nsAString::do_AppendFromElementPtrLength( const char_type* aChar, size_type aLength ) + { + do_AppendFromReadable(nsLocalString(aChar, aLength)); + } + +void +nsAString::do_AppendFromElement( char_type aChar ) + { + do_AppendFromReadable(nsLocalString(&aChar, 1)); + } + + + + // + // |Insert()| + // + +void +nsAString::InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + if ( this != &aReadable ) + do_InsertFromReadable(aReadable, atPosition); + else + InsertFromPromise(aReadable, atPosition); + } + +void +nsAString::InsertFromPromise( const self_type& aReadable, index_type atPosition ) + { + if ( !aReadable.Promises(*this) ) + do_InsertFromReadable(aReadable, atPosition); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_InsertFromElementPtrLength(buffer, atPosition, length); + delete buffer; + } + // else assert + } + } + +void +nsAString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( atPosition < oldLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); + else + atPosition = oldLength; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); + } + +void +nsAString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition ) + { + do_InsertFromReadable(nsLocalString(aPtr), atPosition); + } + +void +nsAString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength ) + { + do_InsertFromReadable(nsLocalString(aPtr, aLength), atPosition); + } + +void +nsAString::do_InsertFromElement( char_type aChar, index_type atPosition ) + { + do_InsertFromReadable(nsLocalString(&aChar, 1), atPosition); + } + + + + // + // |Cut()| + // + +void +nsAString::Cut( index_type cutStart, size_type cutLength ) + { + size_type myLength = this->Length(); + cutLength = NS_MIN(cutLength, myLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutEnd < myLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + SetLength(myLength-cutLength); + } + + + + // + // |Replace()| + // + +void +nsAString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + if ( this != &aReplacement ) + do_ReplaceFromReadable(cutStart, cutLength, aReplacement); + else + ReplaceFromPromise(cutStart, cutLength, aReplacement); + } + +void +nsAString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_ReplaceFromReadable(cutStart, cutLength, aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_ReplaceFromReadable(cutStart, cutLength, nsLocalString(buffer, length)); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + size_type oldLength = this->Length(); + + cutStart = NS_MIN(cutStart, oldLength); + cutLength = NS_MIN(cutLength, oldLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + size_type replacementLength = aReplacement.Length(); + index_type replacementEnd = cutStart + replacementLength; + + size_type newLength = oldLength - cutLength + replacementLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutLength > replacementLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + SetLength(newLength); + if ( cutLength < replacementLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + + copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + } + + + + +NS_COM +int +Compare( const nsACString& lhs, const nsACString& rhs ) + { + typedef nsACString::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + size_type lLength = lhs.Length(); + size_type rLength = rhs.Length(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + nsACString::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + int result; + + for (;;) + { + size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); + + if ( lengthAvailable > lengthToCompare ) + lengthAvailable = lengthToCompare; + + // Note: |result| should be declared in this |if| expression, but some compilers don't like that + if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) + return result; + + if ( !(lengthToCompare -= lengthAvailable) ) + break; + + leftIter.advance( PRInt32(lengthAvailable) ); + rightIter.advance( PRInt32(lengthAvailable) ); + } + + if ( lLength < rLength ) + return -1; + else if ( rLength < lLength ) + return 1; + else + return 0; + } + +PRBool +nsACString::Equals( const char_type* rhs ) const + { + return Equals(nsLocalCString(rhs)); + } + +nsACString::char_type +nsACString::First() const + { + NS_ASSERTION(Length()>0, "|First()| on an empty string"); + + const_iterator iter; + return *BeginReading(iter); + } + +nsACString::char_type +nsACString::Last() const + { + NS_ASSERTION(Length()>0, "|Last()| on an empty string"); + + const_iterator iter; + + if ( !IsEmpty() ) + { + EndReading(iter); + iter.advance(-1); + } + + return *iter; // Note: this has undefined results if |IsEmpty()| + } + +nsACString::size_type +nsACString::CountChar( char_type c ) const + { + /* + re-write this to use a counting sink + */ + + size_type result = 0; + size_type lengthToExamine = Length(); + + const_iterator iter; + for ( BeginReading(iter); ; ) + { + PRInt32 lengthToExamineInThisFragment = iter.size_forward(); + const char_type* fromBegin = iter.get(); + result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); + if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) + return result; + iter.advance(lengthToExamineInThisFragment); + } + // never reached; quiets warnings + return 0; + } + +nsACString::size_type +nsACString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + // If we're just assigning our entire self, give |aResult| the opportunity to share + if ( aStartPos == 0 && aLengthToCopy >= Length() ) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.Length(); + } + +nsACString::size_type +nsACString::Right( self_type& aResult, size_type aLengthToCopy ) const + { + size_type myLength = Length(); + aLengthToCopy = NS_MIN(myLength, aLengthToCopy); + return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); + } + +PRInt32 +nsACString::FindChar( char_type aChar, PRUint32 aOffset ) const + { + const_iterator iter, done_searching; + BeginReading(iter).advance( PRInt32(aOffset) ); + EndReading(done_searching); + + size_type lengthSearched = 0; + while ( iter != done_searching ) + { + PRInt32 fragmentLength = iter.size_forward(); + const char_type* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); + if ( charFoundAt ) + return lengthSearched + (charFoundAt-iter.get()) + aOffset; + + lengthSearched += fragmentLength; + iter.advance(fragmentLength); + } + + return -1; + } + + + // + // |Assign()| + // + +void +nsACString::AssignFromReadable( const self_type& rhs ) + { + if ( this != &rhs ) + do_AssignFromReadable(rhs); + // else, self-assign is a no-op + } + +void +nsACString::AssignFromPromise( const self_type& aReadable ) + /* + ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. + E.g., + + ... writable& w ... + ... readable& r ... + + w = r + w; + + In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before + anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents + of |r| before being retrieved to be appended. + + We could have a really tricky solution where we tell the promise to resolve _just_ the data promised + by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., + in the case above, |Insert| could have special behavior with significantly better performance. Since + it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the + entire promise. If we measure and this turns out to show up on performance radar, we then have the + option to fix either the callers or this mechanism. + */ + { + if ( !aReadable.Promises(*this) ) + do_AssignFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + // Note: not exception safe. We need something to manage temporary buffers like this + + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AssignFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_AssignFromReadable( const self_type& aReadable ) + { + SetLength(0); + SetLength(aReadable.Length()); + // first setting the length to |0| avoids copying characters only to be overwritten later + // in the case where the implementation decides to re-allocate + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); + } + +void +nsACString::do_AssignFromElementPtr( const char_type* aPtr ) + { + do_AssignFromReadable(nsLocalCString(aPtr)); + } + +void +nsACString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength ) + { + do_AssignFromReadable(nsLocalCString(aPtr, aLength)); + } + +void +nsACString::do_AssignFromElement( char_type aChar ) + { + do_AssignFromReadable(nsLocalCString(&aChar, 1)); + } + + + + // + // |Append()| + // + +void +nsACString::AppendFromReadable( const self_type& aReadable ) + { + if ( this != &aReadable ) + do_AppendFromReadable(aReadable); + else + AppendFromPromise(aReadable); + } + +void +nsACString::AppendFromPromise( const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_AppendFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AppendFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_AppendFromReadable( const self_type& aReadable ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); + } + +void +nsACString::do_AppendFromElementPtr( const char_type* aChar ) + { + do_AppendFromReadable(nsLocalCString(aChar)); + } + +void +nsACString::do_AppendFromElementPtrLength( const char_type* aChar, size_type aLength ) + { + do_AppendFromReadable(nsLocalCString(aChar, aLength)); + } + +void +nsACString::do_AppendFromElement( char_type aChar ) + { + do_AppendFromReadable(nsLocalCString(&aChar, 1)); + } + + + + // + // |Insert()| + // + +void +nsACString::InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + if ( this != &aReadable ) + do_InsertFromReadable(aReadable, atPosition); + else + InsertFromPromise(aReadable, atPosition); + } + +void +nsACString::InsertFromPromise( const self_type& aReadable, index_type atPosition ) + { + if ( !aReadable.Promises(*this) ) + do_InsertFromReadable(aReadable, atPosition); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_InsertFromElementPtrLength(buffer, atPosition, length); + delete buffer; + } + // else assert + } + } + +void +nsACString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( atPosition < oldLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); + else + atPosition = oldLength; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); + } + +void +nsACString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition ) + { + do_InsertFromReadable(nsLocalCString(aPtr), atPosition); + } + +void +nsACString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength ) + { + do_InsertFromReadable(nsLocalCString(aPtr, aLength), atPosition); + } + +void +nsACString::do_InsertFromElement( char_type aChar, index_type atPosition ) + { + do_InsertFromReadable(nsLocalCString(&aChar, 1), atPosition); + } + + + + // + // |Cut()| + // + +void +nsACString::Cut( index_type cutStart, size_type cutLength ) + { + size_type myLength = this->Length(); + cutLength = NS_MIN(cutLength, myLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutEnd < myLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + SetLength(myLength-cutLength); + } + + + + // + // |Replace()| + // + +void +nsACString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + if ( this != &aReplacement ) + do_ReplaceFromReadable(cutStart, cutLength, aReplacement); + else + ReplaceFromPromise(cutStart, cutLength, aReplacement); + } + +void +nsACString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_ReplaceFromReadable(cutStart, cutLength, aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_ReplaceFromReadable(cutStart, cutLength, nsLocalCString(buffer, length)); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + size_type oldLength = this->Length(); + + cutStart = NS_MIN(cutStart, oldLength); + cutLength = NS_MIN(cutLength, oldLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + size_type replacementLength = aReplacement.Length(); + index_type replacementEnd = cutStart + replacementLength; + + size_type newLength = oldLength - cutLength + replacementLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutLength > replacementLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + SetLength(newLength); + if ( cutLength < replacementLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + + copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + } + diff --git a/string/src/nsCommonString.cpp b/string/src/nsCommonString.cpp new file mode 100644 index 000000000000..fefbba159171 --- /dev/null +++ b/string/src/nsCommonString.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsCommonString.h" +// #include "nsBufferHandleUtils.h" + +void +nsCommonString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + +void +nsCommonCString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonCString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + diff --git a/string/src/nsDependentConcatenation.cpp b/string/src/nsDependentConcatenation.cpp new file mode 100644 index 000000000000..ed1bd50b6c7a --- /dev/null +++ b/string/src/nsDependentConcatenation.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsAString.h" + // remember, no one should include "nsPromiseConcatenation.h" themselves + // one always gets it through "nsAString.h" + +PRUint32 +nsPromiseConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const PRUnichar* +nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } + + +PRUint32 +nsPromiseCConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseCConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseCConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const char* +nsPromiseCConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } diff --git a/string/src/nsDependentString.cpp b/string/src/nsDependentString.cpp new file mode 100644 index 000000000000..5c046c264ffa --- /dev/null +++ b/string/src/nsDependentString.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsLocalString.h" + diff --git a/string/src/nsDependentSubstring.cpp b/string/src/nsDependentSubstring.cpp new file mode 100644 index 000000000000..563cd3b48d4a --- /dev/null +++ b/string/src/nsDependentSubstring.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseSubstring.h" + +PRUint32 +nsPromiseSubstring::Length() const + { + return mLength; + } + +const PRUnichar* +nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const PRUnichar* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } + + + + +PRUint32 +nsPromiseCSubstring::Length() const + { + return mLength; + } + +const char* +nsPromiseCSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const char* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } diff --git a/string/src/nsLocalString.cpp b/string/src/nsLocalString.cpp new file mode 100644 index 000000000000..5c046c264ffa --- /dev/null +++ b/string/src/nsLocalString.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsLocalString.h" + diff --git a/string/src/nsPrivateSharableString.cpp b/string/src/nsPrivateSharableString.cpp new file mode 100644 index 000000000000..70fcbaa4e93e --- /dev/null +++ b/string/src/nsPrivateSharableString.cpp @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPrivateSharableString.h" + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + +const nsSharedBufferHandle* +nsPrivateSharableString::GetSharedBufferHandle() const + { + return 0; + } + +const nsBufferHandle* +nsPrivateSharableString::GetFlatBufferHandle() const + { + return GetSharedBufferHandle(); + } + +const nsBufferHandle* +nsPrivateSharableString::GetBufferHandle() const + { + return GetSharedBufferHandle(); + } + +PRUint32 +nsPrivateSharableString::GetImplementationFlags() const + { + PRUint32 flags = 0; + const nsSharedBufferHandle* handle = GetSharedBufferHandle(); + if ( handle ) + flags = handle->GetImplementationFlags(); + return flags; + } + + + +const nsSharedBufferHandle* +nsPrivateSharableCString::GetSharedBufferHandle() const + { + return 0; + } + +const nsBufferHandle* +nsPrivateSharableCString::GetFlatBufferHandle() const + { + return GetSharedBufferHandle(); + } + +const nsBufferHandle* +nsPrivateSharableCString::GetBufferHandle() const + { + return GetSharedBufferHandle(); + } + +PRUint32 +nsPrivateSharableCString::GetImplementationFlags() const + { + PRUint32 flags = 0; + const nsSharedBufferHandle* handle = GetSharedBufferHandle(); + if ( handle ) + flags = handle->GetImplementationFlags(); + return flags; + } diff --git a/string/src/nsPromiseConcatenation.cpp b/string/src/nsPromiseConcatenation.cpp new file mode 100644 index 000000000000..ed1bd50b6c7a --- /dev/null +++ b/string/src/nsPromiseConcatenation.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsAString.h" + // remember, no one should include "nsPromiseConcatenation.h" themselves + // one always gets it through "nsAString.h" + +PRUint32 +nsPromiseConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const PRUnichar* +nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } + + +PRUint32 +nsPromiseCConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseCConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseCConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const char* +nsPromiseCConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } diff --git a/string/src/nsPromiseFlatString.cpp b/string/src/nsPromiseFlatString.cpp new file mode 100644 index 000000000000..4dbc38862a0c --- /dev/null +++ b/string/src/nsPromiseFlatString.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseFlatString.h" + + +nsPromiseFlatString::nsPromiseFlatString( const nsPromiseFlatString& aOther ) + : mFlattenedString(aOther.mFlattenedString) + { + if ( aOther.mPromisedString == &aOther.mFlattenedString ) + mPromisedString = &mFlattenedString; + else + mPromisedString = aOther.mPromisedString; + } + +nsPromiseFlatString::nsPromiseFlatString( const nsAString& aString ) + { + if ( aString.GetFlatBufferHandle() ) + mPromisedString = NS_STATIC_CAST(const nsAFlatString*, &aString); + else + { + mFlattenedString = aString; // flatten |aString| + mPromisedString = &mFlattenedString; + } + } + +const PRUnichar* +nsPromiseFlatString::get() const + { + return mPromisedString->get(); + } + +const nsBufferHandle* +nsPromiseFlatString::GetFlatBufferHandle() const + { + return mPromisedString->GetFlatBufferHandle(); + } + +const nsBufferHandle* +nsPromiseFlatString::GetBufferHandle() const + { + return mPromisedString->GetBufferHandle(); + } + +const nsSharedBufferHandle* +nsPromiseFlatString::GetSharedBufferHandle() const + { + return mPromisedString->GetSharedBufferHandle(); + } + + + + +nsPromiseFlatCString::nsPromiseFlatCString( const nsPromiseFlatCString& aOther ) + : mFlattenedString(aOther.mFlattenedString) + { + if ( aOther.mPromisedString == &aOther.mFlattenedString ) + mPromisedString = &mFlattenedString; + else + mPromisedString = aOther.mPromisedString; + } + +nsPromiseFlatCString::nsPromiseFlatCString( const nsACString& aString ) + { + if ( aString.GetFlatBufferHandle() ) + mPromisedString = NS_STATIC_CAST(const nsAFlatCString*, &aString); + else + { + mFlattenedString = aString; // flatten |aString| + mPromisedString = &mFlattenedString; + } + } + +const char* +nsPromiseFlatCString::get() const + { + return mPromisedString->get(); + } + +const nsBufferHandle* +nsPromiseFlatCString::GetFlatBufferHandle() const + { + return mPromisedString->GetFlatBufferHandle(); + } + +const nsBufferHandle* +nsPromiseFlatCString::GetBufferHandle() const + { + return mPromisedString->GetBufferHandle(); + } + +const nsSharedBufferHandle* +nsPromiseFlatCString::GetSharedBufferHandle() const + { + return mPromisedString->GetSharedBufferHandle(); + } diff --git a/string/src/nsPromiseSubstring.cpp b/string/src/nsPromiseSubstring.cpp new file mode 100644 index 000000000000..563cd3b48d4a --- /dev/null +++ b/string/src/nsPromiseSubstring.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseSubstring.h" + +PRUint32 +nsPromiseSubstring::Length() const + { + return mLength; + } + +const PRUnichar* +nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const PRUnichar* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } + + + + +PRUint32 +nsPromiseCSubstring::Length() const + { + return mLength; + } + +const char* +nsPromiseCSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const char* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } diff --git a/string/src/nsReadableUtils.cpp b/string/src/nsReadableUtils.cpp index 19f12776d4a4..94823b2ad8e1 100755 --- a/string/src/nsReadableUtils.cpp +++ b/string/src/nsReadableUtils.cpp @@ -26,6 +26,9 @@ #include "nsString.h" #include "nsCRT.h" +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif /** * this allocator definition, and the global functions to access it need to move @@ -142,7 +145,7 @@ class LossyConvertEncoding NS_COM void -CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ) +CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ) { // right now, this won't work on multi-fragment destinations aDest.SetLength(aSource.Length()); @@ -157,7 +160,7 @@ CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ) NS_COM void -CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ) +CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ) { // right now, this won't work on multi-fragment destinations aDest.SetLength(aSource.Length()); @@ -178,10 +181,10 @@ CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ) * @return a new buffer (of the type specified by the second parameter) which you must free with |nsMemory::Free|. * */ -template +template inline ToCharT* -AllocateStringCopy( const basic_nsAReadableString& aSource, ToCharT* ) +AllocateStringCopy( const FromStringT& aSource, ToCharT* ) { return NS_STATIC_CAST(ToCharT*, nsMemory::Alloc((aSource.Length()+1) * sizeof(ToCharT))); } @@ -189,7 +192,7 @@ AllocateStringCopy( const basic_nsAReadableString& aSource, ToCharT* NS_COM char* -ToNewCString( const nsAReadableString& aSource ) +ToNewCString( const nsAString& aSource ) { char* result = AllocateStringCopy(aSource, (char*)0); @@ -201,7 +204,7 @@ ToNewCString( const nsAReadableString& aSource ) NS_COM char* -ToNewUTF8String( const nsAReadableString& aSource ) +ToNewUTF8String( const nsAString& aSource ) { NS_ConvertUCS2toUTF8 temp(aSource); @@ -225,7 +228,7 @@ ToNewUTF8String( const nsAReadableString& aSource ) NS_COM char* -ToNewCString( const nsAReadableCString& aSource ) +ToNewCString( const nsACString& aSource ) { // no conversion needed, just allocate a buffer of the correct length and copy into it @@ -239,7 +242,7 @@ ToNewCString( const nsAReadableCString& aSource ) NS_COM PRUnichar* -ToNewUnicode( const nsAReadableString& aSource ) +ToNewUnicode( const nsAString& aSource ) { // no conversion needed, just allocate a buffer of the correct length and copy into it @@ -253,7 +256,7 @@ ToNewUnicode( const nsAReadableString& aSource ) NS_COM PRUnichar* -ToNewUnicode( const nsAReadableCString& aSource ) +ToNewUnicode( const nsACString& aSource ) { PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); @@ -265,7 +268,7 @@ ToNewUnicode( const nsAReadableCString& aSource ) NS_COM PRUnichar* -CopyUnicodeTo( const nsAReadableString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) +CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) { nsReadingIterator fromBegin, fromEnd; PRUnichar* toBegin = aDest; @@ -277,7 +280,7 @@ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ) + nsAString& aDest ) { nsWritingIterator writer; aDest.SetLength(Distance(aSrcStart, aSrcEnd)); @@ -291,7 +294,7 @@ NS_COM void AppendUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ) + nsAString& aDest ) { nsWritingIterator writer; PRUint32 oldLength = aDest.Length(); @@ -304,7 +307,7 @@ AppendUnicodeTo( const nsReadingIterator& aSrcStart, NS_COM PRBool -IsASCII( const nsAReadableString& aString ) +IsASCII( const nsAString& aString ) { static const PRUnichar NOT_ASCII = PRUnichar(~0x007F); @@ -354,18 +357,18 @@ class ConvertToUpperCase NS_COM void -ToUpperCase( nsAWritableString& aString ) +ToUpperCase( nsAString& aString ) { - nsAWritableString::iterator fromBegin, fromEnd; + nsAString::iterator fromBegin, fromEnd; ConvertToUpperCase converter; copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); } NS_COM void -ToUpperCase( nsAWritableCString& aCString ) +ToUpperCase( nsACString& aCString ) { - nsAWritableCString::iterator fromBegin, fromEnd; + nsACString::iterator fromBegin, fromEnd; ConvertToUpperCase converter; copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); } @@ -391,18 +394,18 @@ class ConvertToLowerCase NS_COM void -ToLowerCase( nsAWritableString& aString ) +ToLowerCase( nsAString& aString ) { - nsAWritableString::iterator fromBegin, fromEnd; + nsAString::iterator fromBegin, fromEnd; ConvertToLowerCase converter; copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); } NS_COM void -ToLowerCase( nsAWritableCString& aCString ) +ToLowerCase( nsACString& aCString ) { - nsAWritableCString::iterator fromBegin, fromEnd; + nsACString::iterator fromBegin, fromEnd; ConvertToLowerCase converter; copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); } @@ -411,7 +414,7 @@ ToLowerCase( nsAWritableCString& aCString ) template inline // probably wishful thinking PRBool -FindInReadable_Impl( const basic_nsAReadableString& aPattern, +FindInReadable_Impl( const typename nsStringTraits::abstract_string_type& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { @@ -479,14 +482,14 @@ FindInReadable_Impl( const basic_nsAReadableString& aPattern, NS_COM PRBool -FindInReadable( const nsAReadableString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +FindInReadable( const nsAString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } NS_COM PRBool -FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +FindInReadable( const nsACString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } @@ -499,7 +502,7 @@ FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSe template inline // probably wishful thinking PRBool -RFindInReadable_Impl( const basic_nsAReadableString& aPattern, +RFindInReadable_Impl( const typename nsStringTraits::abstract_string_type& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { @@ -535,14 +538,14 @@ RFindInReadable_Impl( const basic_nsAReadableString& aPattern, NS_COM PRBool -RFindInReadable( const nsAReadableString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +RFindInReadable( const nsAString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } NS_COM PRBool -RFindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +RFindInReadable( const nsACString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } @@ -593,7 +596,7 @@ FindCharInReadable( char aChar, nsReadingIterator& aSearchStart, const nsR template PRUint32 -CountCharInReadable_Impl( const basic_nsAReadableString& aStr, +CountCharInReadable_Impl( const typename nsStringTraits::abstract_string_type& aStr, CharT aChar ) { PRUint32 count = 0; @@ -614,7 +617,7 @@ CountCharInReadable_Impl( const basic_nsAReadableString& aStr, NS_COM PRUint32 -CountCharInReadable( const nsAReadableString& aStr, +CountCharInReadable( const nsAString& aStr, PRUnichar aChar ) { return CountCharInReadable_Impl(aStr, aChar); @@ -622,7 +625,7 @@ CountCharInReadable( const nsAReadableString& aStr, NS_COM PRUint32 -CountCharInReadable( const nsAReadableCString& aStr, +CountCharInReadable( const nsACString& aStr, char aChar ) { return CountCharInReadable_Impl(aStr, aChar); diff --git a/string/src/nsSharableString.cpp b/string/src/nsSharableString.cpp new file mode 100644 index 000000000000..fefbba159171 --- /dev/null +++ b/string/src/nsSharableString.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsCommonString.h" +// #include "nsBufferHandleUtils.h" + +void +nsCommonString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + +void +nsCommonCString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonCString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + diff --git a/string/src/nsSlidingString.cpp b/string/src/nsSlidingString.cpp index f574779c281b..51a5842581d7 100755 --- a/string/src/nsSlidingString.cpp +++ b/string/src/nsSlidingString.cpp @@ -99,7 +99,7 @@ nsSlidingSubstring::nsSlidingSubstring( nsSlidingSharedBufferList* aBufferList ) typedef const nsSharedBufferList::Buffer* Buffer_ptr; static nsSharedBufferList::Buffer* -AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAReadableString& aDataSource ) +AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAString& aDataSource ) { typedef const PRUnichar* PRUnichar_ptr; @@ -131,7 +131,7 @@ AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAReadableS return result; } -nsSlidingSubstring::nsSlidingSubstring( const nsAReadableString& aSourceString ) +nsSlidingSubstring::nsSlidingSubstring( const nsAString& aSourceString ) : mBufferList(new nsSlidingSharedBufferList(AllocateContiguousHandleWithData(Buffer_ptr(0), aSourceString))) { init_range_from_buffer_list(); @@ -189,7 +189,7 @@ nsSlidingSubstring::Rebind( const nsSlidingString& aString, const nsReadingItera } void -nsSlidingSubstring::Rebind( const nsAReadableString& aSourceString ) +nsSlidingSubstring::Rebind( const nsAString& aSourceString ) { release_ownership_of_buffer_list(); mBufferList = new nsSlidingSharedBufferList(AllocateContiguousHandleWithData(Buffer_ptr(0), aSourceString)); @@ -291,7 +291,7 @@ nsSlidingString::AppendBuffer( PRUnichar* aStorageStart, PRUnichar* aDataEnd, PR } void -nsSlidingString::InsertReadable( const nsAReadableString& aReadable, const nsReadingIterator& aInsertPoint ) +nsSlidingString::InsertReadable( const nsAString& aReadable, const nsReadingIterator& aInsertPoint ) /* * Warning: this routine manipulates the shared buffer list in an unexpected way. * The original design did not really allow for insertions, but this call promises diff --git a/widget/src/windows/nsDataObj.cpp b/widget/src/windows/nsDataObj.cpp index 3bbed00fe9a4..64f7eb7391c1 100644 --- a/widget/src/windows/nsDataObj.cpp +++ b/widget/src/windows/nsDataObj.cpp @@ -364,7 +364,7 @@ nsDataObj :: GetDib ( nsAReadableCString& inFlavor, FORMATETC &, STGMEDIUM & aST PRUint32 len = 0; nsCOMPtr genericDataWrapper; - mTransferable->GetTransferData(nsPromiseFlatCString(inFlavor).get(), getter_AddRefs(genericDataWrapper), &len); + mTransferable->GetTransferData(PromiseFlatCString(inFlavor).get(), getter_AddRefs(genericDataWrapper), &len); nsCOMPtr image ( do_QueryInterface(genericDataWrapper) ); if ( image ) { // use a the helper class to build up a bitmap. We now own the bits, @@ -574,7 +574,7 @@ HRESULT nsDataObj::GetText(nsAReadableCString & aDataFlavor, FORMATETC& aFE, STG // if someone asks for text/plain, look up text/unicode instead in the transferable. const char* flavorStr; - nsPromiseFlatCString flat(aDataFlavor); + const nsPromiseFlatCString& flat = PromiseFlatCString(aDataFlavor); if ( aDataFlavor.Equals("text/plain") ) flavorStr = kUnicodeMime; else diff --git a/xpcom/ds/nsAtomTable.cpp b/xpcom/ds/nsAtomTable.cpp index 47ee91d4e181..5b2c973a508e 100644 --- a/xpcom/ds/nsAtomTable.cpp +++ b/xpcom/ds/nsAtomTable.cpp @@ -169,7 +169,7 @@ NS_COM nsIAtom* NS_NewAtom( const nsAReadableString& aString ) (PLHashComparator)CompareKeys, (PLHashComparator)0, 0, 0); - nsPromiseFlatString flat(aString); + const nsPromiseFlatString& flat = PromiseFlatString(aString); const PRUnichar *str = flat.get(); PRUint32 hashCode = HashKey(str); diff --git a/xpcom/ds/nsHashtable.cpp b/xpcom/ds/nsHashtable.cpp index 442fe1aa184f..d6f2133018cf 100644 --- a/xpcom/ds/nsHashtable.cpp +++ b/xpcom/ds/nsHashtable.cpp @@ -457,7 +457,7 @@ nsCStringKey::Clone() const //////////////////////////////////////////////////////////////////////////////// nsStringKey::nsStringKey(const nsAReadableString& str) - : mStr(NS_CONST_CAST(PRUnichar*, NS_STATIC_CAST(const PRUnichar *, nsPromiseFlatString(str).get()))), mStrLen(str.Length()), mOwnership(OWN_CLONE) + : mStr(NS_CONST_CAST(PRUnichar*, NS_STATIC_CAST(const PRUnichar *, PromiseFlatString(str).get()))), mStrLen(str.Length()), mOwnership(OWN_CLONE) { NS_ASSERTION(mStr, "null string key"); #ifdef DEBUG diff --git a/xpcom/string/README.html b/xpcom/string/README.html index c042892a33ec..eb54a3df1946 100644 --- a/xpcom/string/README.html +++ b/xpcom/string/README.html @@ -21,11 +21,9 @@ - Scott Collins (original author) --> -

string code will be moving here soon

+

managing sequences of characters

- The string code will be moving here soon; - in the meantime, you can find the bulk of it in - mozilla/xpcom/ds. +

diff --git a/xpcom/string/doc/README.html b/xpcom/string/doc/README.html index af9eee88be5a..e9a28f949ae5 100644 --- a/xpcom/string/doc/README.html +++ b/xpcom/string/doc/README.html @@ -21,7 +21,7 @@ - Scott Collins (original author) --> -

string doc will be moving here soon

+

documentation aimed at programmers who are clients of the string library

diff --git a/xpcom/string/macbuild/string.mcp b/xpcom/string/macbuild/string.mcp index b37d99192d8e..4c5de2c6d35a 100644 Binary files a/xpcom/string/macbuild/string.mcp and b/xpcom/string/macbuild/string.mcp differ diff --git a/xpcom/string/obsolete/nsStr.cpp b/xpcom/string/obsolete/nsStr.cpp index 87bf47bcdfb6..d35159aeb276 100644 --- a/xpcom/string/obsolete/nsStr.cpp +++ b/xpcom/string/obsolete/nsStr.cpp @@ -17,10 +17,8 @@ * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Original Author: - * Rick Gessner - * * Contributor(s): + * Rick Gessner (original author) * Scott Collins */ diff --git a/xpcom/string/obsolete/nsString.cpp b/xpcom/string/obsolete/nsString.cpp index d8c2f865bc1e..2bad4c8dbb6e 100644 --- a/xpcom/string/obsolete/nsString.cpp +++ b/xpcom/string/obsolete/nsString.cpp @@ -42,6 +42,11 @@ static const char* kPossibleNull = "Error: possible unintended null in string"; static const char* kNullPointerError = "Error: unexpected null ptr"; static const char* kWhitespace="\b\t\r\n "; +const nsBufferHandle* +nsCString::GetFlatBufferHandle() const + { + return NS_REINTERPRET_CAST(const nsBufferHandle*, 1); + } static void CSubsume(nsStr& aDest,nsStr& aSource){ if(aSource.mStr && aSource.mLength) { @@ -165,7 +170,7 @@ char* nsCString::GetWritableFragment( nsWritableFragment& aFragment, nsFra } } -nsCString::nsCString( const nsAReadableCString& aReadable ) { +nsCString::nsCString( const nsACString& aReadable ) { Initialize(*this,eOneByte); Assign(aReadable); } @@ -774,7 +779,7 @@ void nsCString::AssignWithConversion( const nsString& aString ) { AssignWithConversion(aString.GetUnicode(), aString.Length()); } -void nsCString::AssignWithConversion( const nsAReadableString& aString ) { +void nsCString::AssignWithConversion( const nsAString& aString ) { nsStr::StrTruncate(*this,0); PRInt32 count = aString.Length(); @@ -792,13 +797,13 @@ void nsCString::AssignWithConversion( const nsAReadableString& aString ) { temp.mLength=fraglen; StrAppend(*this,temp,0,fraglen); - - start += fraglen; + + start.advance(fraglen); } } } -void nsCString::AppendWithConversion( const nsAReadableString& aString ) { +void nsCString::AppendWithConversion( const nsAString& aString ) { PRInt32 count = aString.Length(); if(count){ @@ -816,7 +821,7 @@ void nsCString::AppendWithConversion( const nsAReadableString& aString ) { StrAppend(*this,temp,0,fraglen); - start += fraglen; + start.advance(fraglen); } } } @@ -832,14 +837,6 @@ void nsCString::AssignWithConversion(PRUnichar aChar) { AppendWithConversion(aChar); } -void nsCString::do_AppendFromReadable( const nsAReadableCString& aReadable ) - { - if ( SameImplementation( NS_STATIC_CAST(const nsAReadableCString&, *this), aReadable) ) - StrAppend(*this, NS_STATIC_CAST(const nsCString&, aReadable), 0, aReadable.Length()); - else - nsAWritableCString::do_AppendFromReadable(aReadable); - } - /** * append given char to this string @@ -962,14 +959,6 @@ void nsCString::InsertWithConversion(PRUnichar aChar,PRUint32 anOffset){ StrInsert(*this,anOffset,temp,0,1); } -void nsCString::do_InsertFromReadable( const nsAReadableCString& aReadable, PRUint32 atPosition ) - { - if ( SameImplementation( NS_STATIC_CAST(const nsAReadableCString&, *this), aReadable) ) - StrInsert(*this, atPosition, NS_STATIC_CAST(const nsCString&, aReadable), 0, aReadable.Length()); - else - nsAWritableCString::do_InsertFromReadable(aReadable, atPosition); - } - @@ -1382,7 +1371,7 @@ void nsCString::DebugDump(void) const { //---------------------------------------------------------------------- -NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAReadableString& aString ) +NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAString& aString ) { nsReadingIterator start; aString.BeginReading(start); nsReadingIterator end; aString.EndReading(end); @@ -1390,7 +1379,7 @@ NS_ConvertUCS2toUTF8::NS_ConvertUCS2toUTF8( const nsAReadableString& aString ) while (start != end) { nsReadableFragment frag(start.fragment()); Append(frag.mStart, frag.mEnd - frag.mStart); - start += start.size_forward(); + start.advance(start.size_forward()); } } @@ -1511,7 +1500,7 @@ nsCAutoString::nsCAutoString( const nsCString& aString ) : nsCString(){ Append(aString); } -nsCAutoString::nsCAutoString( const nsAReadableCString& aString ) : nsCString(){ +nsCAutoString::nsCAutoString( const nsACString& aString ) : nsCString(){ Initialize(*this,mBuffer,sizeof(mBuffer)-1,0,eOneByte,PR_FALSE); AddNullTerminator(*this); Append(aString); diff --git a/xpcom/string/obsolete/nsString.h b/xpcom/string/obsolete/nsString.h index 42496342a17e..9bf13d1f692d 100644 --- a/xpcom/string/obsolete/nsString.h +++ b/xpcom/string/obsolete/nsString.h @@ -50,17 +50,27 @@ #include "nsStr.h" #include "nsIAtom.h" +#include "nsAString.h" + +/* this file will one day be _only_ a compatibility header for clients using the names + |ns[C]String| et al ... which we probably want to support forever. + In the mean time, people are used to getting the names |nsAReadable[C]String| and friends + from here as well; so we must continue to include the other compatibility headers + even though we don't use them ourself. + */ + #include "nsAWritableString.h" + // for compatibility class NS_COM nsSubsumeCStr; class NS_COM nsCString : - public nsAWritableCString, + public nsAFlatCString, public nsStr { protected: - virtual const void* Implementation() const { return "nsCString"; } + virtual const nsBufferHandle* GetFlatBufferHandle() const; virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); @@ -79,7 +89,7 @@ public: */ nsCString(const nsCString& aString); - explicit nsCString( const nsAReadableCString& ); + explicit nsCString( const nsACString& ); explicit nsCString(const char*); nsCString(const char*, PRInt32); @@ -298,14 +308,14 @@ public: */ nsCString& operator=( const nsCString& aString ) { Assign(aString); return *this; } - nsCString& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsCString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsCString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +//nsCString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsCString& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsCString& operator=( char aChar ) { Assign(aChar); return *this; } void AssignWithConversion(const PRUnichar*,PRInt32=-1); void AssignWithConversion( const nsString& aString ); - void AssignWithConversion( const nsAReadableString& aString ); + void AssignWithConversion( const nsAString& aString ); void AssignWithConversion(PRUnichar); /* @@ -320,18 +330,20 @@ public: void AppendWithConversion(const nsString&, PRInt32=-1); void AppendWithConversion(PRUnichar aChar); - void AppendWithConversion( const nsAReadableString& aString ); + void AppendWithConversion( const nsAString& aString ); void AppendWithConversion(const PRUnichar*, PRInt32=-1); // Why no |AppendWithConversion(const PRUnichar*, PRInt32)|? --- now I know, because implicit construction hid the need for this routine void AppendInt(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16 void AppendFloat( double aFloat ); - virtual void do_AppendFromReadable( const nsAReadableCString& ); void InsertWithConversion(PRUnichar aChar,PRUint32 anOffset); // Why no |InsertWithConversion(PRUnichar*)|? - virtual void do_InsertFromReadable( const nsAReadableCString&, PRUint32 ); +#if 0 + virtual void do_AppendFromReadable( const nsACString& ); + virtual void do_InsertFromReadable( const nsACString&, PRUint32 ); +#endif /********************************************************************** @@ -446,7 +458,7 @@ private: }; // NS_DEF_STRING_COMPARISON_OPERATORS(nsCString, char) -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCString, char) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCString, char) extern NS_COM int fputs(const nsCString& aString, FILE* out); //ostream& operator<<(ostream& aStream,const nsCString& aString); @@ -466,7 +478,7 @@ public: nsCAutoString(); explicit nsCAutoString(const nsCString& ); - explicit nsCAutoString(const nsAReadableCString& aString); + explicit nsCAutoString(const nsACString& aString); explicit nsCAutoString(const char* aString); nsCAutoString(const char* aString,PRInt32 aLength); explicit nsCAutoString(const CBufDescriptor& aBuffer); @@ -482,8 +494,8 @@ public: private: void operator=( PRUnichar ); // NOT TO BE IMPLEMENTED public: - nsCAutoString& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsCAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsCAutoString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +// nsCAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsCAutoString& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsCAutoString& operator=( char aChar ) { Assign(aChar); return *this; } @@ -496,7 +508,7 @@ public: char mBuffer[kDefaultStringSize]; }; -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCAutoString, char) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCAutoString, char) /** * A helper class that converts a UCS2 string to UTF8 @@ -525,7 +537,7 @@ class NS_COM NS_ConvertUCS2toUTF8 Append( &aChar, 1 ); } - explicit NS_ConvertUCS2toUTF8( const nsAReadableString& aString ); + explicit NS_ConvertUCS2toUTF8( const nsAString& aString ); protected: void Append( const PRUnichar* aString, PRUint32 aLength ); @@ -533,7 +545,7 @@ class NS_COM NS_ConvertUCS2toUTF8 private: // NOT TO BE IMPLEMENTED NS_ConvertUCS2toUTF8( char ); - operator const char*() const; // use |get()| + operator const char*() const; // use |get()| }; @@ -557,8 +569,8 @@ public: nsSubsumeCStr(char* aString,PRBool assumeOwnership,PRInt32 aLength=-1); nsSubsumeCStr& operator=( const nsSubsumeCStr& aString ) { Assign(aString); return *this; } - nsSubsumeCStr& operator=( const nsAReadableCString& aReadable ) { Assign(aReadable); return *this; } - nsSubsumeCStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsSubsumeCStr& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; } +//nsSubsumeCStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsSubsumeCStr& operator=( const char* aPtr ) { Assign(aPtr); return *this; } nsSubsumeCStr& operator=( char aChar ) { Assign(aChar); return *this; } private: diff --git a/xpcom/string/obsolete/nsString2.cpp b/xpcom/string/obsolete/nsString2.cpp index b85fdbe9af10..b6d9a0d3dd98 100644 --- a/xpcom/string/obsolete/nsString2.cpp +++ b/xpcom/string/obsolete/nsString2.cpp @@ -39,6 +39,13 @@ static const char* kPossibleNull = "Error: possible unintended null in string"; static const char* kNullPointerError = "Error: unexpected null ptr"; static const char* kWhitespace="\b\t\r\n "; +const nsBufferHandle* +nsString::GetFlatBufferHandle() const + { + return NS_REINTERPRET_CAST(const nsBufferHandle*, 1); + } + + static void Subsume(nsStr& aDest,nsStr& aSource){ if(aSource.mStr && aSource.mLength) { @@ -165,7 +172,7 @@ nsString::do_AppendFromElement( PRUnichar inChar ) } -nsString::nsString( const nsAReadableString& aReadable ) { +nsString::nsString( const nsAString& aReadable ) { Initialize(*this,eTwoByte); Assign(aReadable); } @@ -1647,7 +1654,7 @@ nsAutoString::nsAutoString( const nsString& aString ) Append(aString); } -nsAutoString::nsAutoString( const nsAReadableString& aString ) +nsAutoString::nsAutoString( const nsAString& aString ) : nsString() { Initialize(*this, mBuffer, (sizeof(mBuffer)>>eTwoByte)-1, 0, eTwoByte, PR_FALSE); diff --git a/xpcom/string/obsolete/nsString2.h b/xpcom/string/obsolete/nsString2.h index f2ae0dbca658..d7698322cd22 100644 --- a/xpcom/string/obsolete/nsString2.h +++ b/xpcom/string/obsolete/nsString2.h @@ -52,11 +52,12 @@ #include "nsStr.h" #include "nsCRT.h" -#include "nsAWritableString.h" +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif #ifdef STANDALONE_MI_STRING_TESTS - class nsAReadableString { public: virtual ~nsAReadableString() { } }; - class nsAWritableString : public nsAReadableString { public: virtual ~nsAWritableString() { } }; + class nsAFlatString { public: virtual ~nsAString() { } }; #endif class nsISizeOfHandler; @@ -68,11 +69,11 @@ class nsISizeOfHandler; class NS_COM nsSubsumeStr; class NS_COM nsString : - public nsAWritableString, + public nsAFlatString, public nsStr { protected: - virtual const void* Implementation() const { return "nsString"; } + virtual const nsBufferHandle* GetFlatBufferHandle() const; virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); @@ -91,7 +92,7 @@ public: */ nsString(const nsString& aString); - explicit nsString(const nsAReadableString&); + explicit nsString(const nsAString&); explicit nsString(const PRUnichar*); nsString(const PRUnichar*, PRInt32); @@ -342,8 +343,8 @@ public: */ nsString& operator=( const nsString& aString ) { Assign(aString); return *this; } - nsString& operator=( const nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - nsString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +//nsString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsString& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } @@ -526,7 +527,7 @@ private: }; // NS_DEF_STRING_COMPARISON_OPERATORS(nsString, PRUnichar) -NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsString, PRUnichar) +// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsString, PRUnichar) extern NS_COM int fputs(const nsString& aString, FILE* out); //ostream& operator<<(ostream& aStream,const nsString& aString); @@ -544,7 +545,7 @@ public: virtual ~nsAutoString(); nsAutoString(); nsAutoString(const nsAutoString& aString); - explicit nsAutoString(const nsAReadableString& aString); + explicit nsAutoString(const nsAString& aString); explicit nsAutoString(const nsString& aString); explicit nsAutoString(const PRUnichar* aString); nsAutoString(const PRUnichar* aString,PRInt32 aLength); @@ -562,8 +563,8 @@ public: private: void operator=( char ); // NOT TO BE IMPLEMENTED public: - nsAutoString& operator=( const nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - nsAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } + nsAutoString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +// nsAutoString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsAutoString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsAutoString& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } @@ -576,7 +577,7 @@ public: char mBuffer[kDefaultStringSize<& aReadable ) { Assign(aReadable); return *this; } + nsSubsumeStr& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; } +//nsSubsumeStr& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } nsSubsumeStr& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; } nsSubsumeStr& operator=( PRUnichar aChar ) { Assign(aChar); return *this; } private: diff --git a/xpcom/string/public/MANIFEST b/xpcom/string/public/MANIFEST index 6a48cc1b8c08..cb9a692fd76b 100644 --- a/xpcom/string/public/MANIFEST +++ b/xpcom/string/public/MANIFEST @@ -21,15 +21,29 @@ # +nsAFlatString.h nsAlgorithm.h +nsAPromiseString.h nsAReadableString.h +nsAString.h nsAWritableString.h nsBufferHandle.h nsBufferHandleUtils.h nsCharTraits.h +nsCommonString.h nsFragmentedString.h +nsLiteralString.h +nsLocalString.h nsPrintfCString.h nsPrivateSharableString.h +nsPromiseConcatenation.h +nsPromiseFlatString.h +nsPromiseSubstring.h nsReadableUtils.h nsSharedBufferList.h nsSlidingString.h +nsStringFragment.h +nsStringFwd.h +nsStringIterator.h +nsStringIteratorUtils.h +nsStringTraits.h diff --git a/xpcom/string/public/Makefile.in b/xpcom/string/public/Makefile.in index 3fd4a987aafc..8d13477a3b6e 100644 --- a/xpcom/string/public/Makefile.in +++ b/xpcom/string/public/Makefile.in @@ -18,6 +18,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH = ../.. @@ -30,18 +31,32 @@ include $(DEPTH)/config/autoconf.mk MODULE = string EXPORTS = \ + nsAFlatString.h \ nsAlgorithm.h \ - nsBufferHandle.h \ - nsBufferHandleUtils.h \ - nsPrivateSharableString.h \ + nsAPromiseString.h \ + nsAReadableString.h \ + nsAString.h \ + nsAWritableString.h \ + nsBufferHandle.h \ + nsBufferHandleUtils.h \ nsCharTraits.h \ - nsAReadableString.h \ - nsAWritableString.h \ - nsReadableUtils.h \ - nsSharedBufferList.h \ - nsSlidingString.h \ - nsFragmentedString.h \ - nsPrintfCString.h \ + nsCommonString.h \ + nsFragmentedString.h \ + nsLiteralString.h \ + nsLocalString.h \ + nsPrintfCString.h \ + nsPrivateSharableString.h \ + nsPromiseConcatenation.h \ + nsPromiseFlatString.h \ + nsPromiseSubstring.h \ + nsReadableUtils.h \ + nsSharedBufferList.h \ + nsSlidingString.h \ + nsStringFragment.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsStringIteratorUtils.h \ + nsStringTraits.h \ $(NULL) EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) diff --git a/xpcom/string/public/makefile.win b/xpcom/string/public/makefile.win index 3d819cedb8da..37f2222ac6cc 100644 --- a/xpcom/string/public/makefile.win +++ b/xpcom/string/public/makefile.win @@ -19,23 +19,38 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH=..\.. EXPORTS = \ + nsAFlatString.h \ nsAlgorithm.h \ + nsAPromiseString.h \ nsAReadableString.h \ + nsAString.h \ nsAWritableString.h \ nsBufferHandle.h \ nsBufferHandleUtils.h \ nsCharTraits.h \ + nsCommonString.h \ nsFragmentedString.h \ + nsLiteralString.h \ + nsLocalString.h \ nsPrintfCString.h \ nsPrivateSharableString.h \ + nsPromiseConcatenation.h \ + nsPromiseFlatString.h \ + nsPromiseSubstring.h \ nsReadableUtils.h \ nsSharedBufferList.h \ nsSlidingString.h \ + nsStringFragment.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsStringIteratorUtils.h \ + nsStringTraits.h \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/xpcom/string/public/nsAFlatString.h b/xpcom/string/public/nsAFlatString.h new file mode 100644 index 000000000000..6cb6d9f4a655 --- /dev/null +++ b/xpcom/string/public/nsAFlatString.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsAFlatString.h --- */ + +#ifndef nsAFlatString_h___ +#define nsAFlatString_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +class NS_COM nsAFlatString + : public nsAString + { + public: + // don't really want this to be virtual, and won't after |obsolete_nsString| is really dead + virtual const PRUnichar* get() const { return GetBufferHandle()->DataStart(); } + PRUnichar operator[]( PRUint32 i ) const { return get()[ i ]; } + PRUnichar CharAt( PRUint32 ) const; + + virtual PRUint32 Length() const { return PRUint32(GetBufferHandle()->DataLength()); } + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + }; + +class NS_COM nsAFlatCString + : public nsACString + { + public: + // don't really want this to be virtual, and won't after |obsolete_nsCString| is really dead + virtual const char* get() const { return GetBufferHandle()->DataStart(); } + char operator[]( PRUint32 i ) const { return get()[ i ]; } + char CharAt( PRUint32 ) const; + + virtual PRUint32 Length() const { return PRUint32(GetBufferHandle()->DataLength()); } + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + }; + +inline +PRUnichar +nsAFlatString::CharAt( PRUint32 i ) const + { + NS_ASSERTION(i (original author) + */ + +/* nsAPromiseString.h --- abstract base class for strings don't actually own their own characters, but proxy data from other strings */ + +#ifndef nsAPromiseString_h___ +#define nsAPromiseString_h___ + + /** + * Don't |#include| this file yourself. You will get it automatically if you need it. + * + * Why is it a separate file? To make it easier to find the classes in your local tree. + */ + +class NS_COM nsAPromiseString : public nsAString { }; +class NS_COM nsAPromiseCString : public nsACString { }; + +#endif /* !defined(nsAPromiseString_h___) */ diff --git a/xpcom/string/public/nsAReadableString.h b/xpcom/string/public/nsAReadableString.h index ffe22945c360..67663b505c13 100644 --- a/xpcom/string/public/nsAReadableString.h +++ b/xpcom/string/public/nsAReadableString.h @@ -21,1550 +21,34 @@ * Scott Collins (original author) */ +/* nsAReadableString.h --- a compatibility header for clients still using the names |nsAReadable[C]String| et al */ + #ifndef nsAReadableString_h___ #define nsAReadableString_h___ -#ifndef nscore_h___ -#include "nscore.h" - // for |PRUnichar| +#ifndef nsAString_h___ +#include "nsAString.h" #endif -#ifndef nsCharTraits_h___ -#include "nsCharTraits.h" +typedef const nsAString nsAReadableString; +typedef const nsACString nsAReadableCString; + +#ifndef nsLiteralString_h___ +#include "nsLiteralString.h" #endif -#ifndef nsAlgorithm_h___ -#include "nsAlgorithm.h" - // for |NS_MIN|, |NS_MAX|, and |NS_COUNT|... +#ifndef nsPromiseSubstring_h___ +#include "nsPromiseSubstring.h" #endif -#ifndef nsPrivateSharableString_h___ -#include "nsPrivateSharableString.h" +#ifndef nsPromiseFlatString_h___ +#include "nsPromiseFlatString.h" #endif -#include "nsMemory.h" - -/* - This file defines the abstract interfaces |nsAReadableString| and - |nsAReadableCString| (the 'A' is for 'abstract', as opposed to the 'I' in - [XP]COM interface names). - - These types are intended to be as source compatible as possible with the original - definitions of |const nsString&| and |const nsCString&|, respectively. In otherwords, - these interfaces provide only non-mutating access to the underlying strings. We - split the these interfaces out from the mutating parts (see - "nsAWritableString.h") because tests showed that we could exploit specialized - implementations in some areas; we need an abstract interface to bring the whole - family of strings together. - - |nsAReadableString| is a string of |PRUnichar|s. |nsAReadableCString| (note the - 'C') is a string of |char|s. -*/ - -enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; - -template -struct nsReadableFragment - { - const CharT* mStart; - const CharT* mEnd; - const void* mFragmentIdentifier; - - nsReadableFragment() - : mStart(0), mEnd(0), mFragmentIdentifier(0) - { - // nothing else to do here - } - }; - -template class basic_nsAReadableString; - -template class basic_nsAWritableString; - // ...because we sometimes use them as `out' params - -#ifdef _MSC_VER - // Under VC++, at the highest warning level, we are overwhelmed with warnings - // about a possible error when |operator->()| is used against something that - // doesn't have members, e.g., a |PRUnichar|. This is to be expected with - // templates, so we disable the warning. - #pragma warning( disable: 4284 ) -#endif - -template -class nsReadingIterator -// : public bidirectional_iterator_tag - { - public: - typedef ptrdiff_t difference_type; - typedef CharT value_type; - typedef const CharT* pointer; - typedef const CharT& reference; -// typedef bidirectional_iterator_tag iterator_category; - - private: - friend class basic_nsAReadableString; - - nsReadableFragment mFragment; - const CharT* mPosition; - const basic_nsAReadableString* mOwningString; - - nsReadingIterator( const nsReadableFragment& aFragment, - const CharT* aStartingPosition, - const basic_nsAReadableString& aOwningString ) - : mFragment(aFragment), - mPosition(aStartingPosition), - mOwningString(&aOwningString) - { - // nothing else to do here - } - - public: - nsReadingIterator() { } - // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK - // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK - - inline void normalize_forward(); - inline void normalize_backward(); - - pointer - get() const - { - return mPosition; - } - - CharT - operator*() const - { - return *get(); - } - -#if 0 - // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) - // don't like this when |CharT| is a type without members. - pointer - operator->() const - { - return get(); - } -#endif - - nsReadingIterator& - operator++() - { - ++mPosition; - normalize_forward(); - return *this; - } - - nsReadingIterator - operator++( int ) - { - nsReadingIterator result(*this); - ++mPosition; - normalize_forward(); - return result; - } - - nsReadingIterator& - operator--() - { - normalize_backward(); - --mPosition; - return *this; - } - - nsReadingIterator - operator--( int ) - { - nsReadingIterator result(*this); - normalize_backward(); - --mPosition; - return result; - } - - const nsReadableFragment& - fragment() const - { - return mFragment; - } - - const basic_nsAReadableString& - string() const - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - difference_type - size_forward() const - { - return mFragment.mEnd - mPosition; - } - - difference_type - size_backward() const - { - return mPosition - mFragment.mStart; - } - - nsReadingIterator& - 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; - } - - /** - * Really don't want to call these two operations |+=| and |-=|. - * Would prefer a single function, e.g., |advance|, which doesn't imply a constant time operation. - * - * We'll get rid of these as soon as we can. - */ - nsReadingIterator& - operator+=( difference_type n ) // deprecated - { - return advance(n); - } - - nsReadingIterator& - operator-=( difference_type n ) // deprecated - { - return advance(-n); - } - }; - -#if 0 -template -nsReadingIterator& -nsReadingIterator::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; - } -#endif - - // NOTE: need to break iterators out into their own file (as with many classes here), need - // these routines, but can't currently |#include "nsReadableUtils.h"|, this hack is bad - // but we need it to get OS2 building again. Fix by splitting things into different files. -NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); -NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); - -template -inline -PRBool -SameFragment( const Iterator& lhs, const Iterator& rhs ) - { - return lhs.fragment().mStart == rhs.fragment().mStart; - } - - - // - // nsAReadable[C]String - // - -template -class basic_nsAReadableString - : public nsPrivateSharableString - { - public: - typedef CharT char_type; - typedef PRUint32 size_type; - typedef PRUint32 index_type; - - typedef nsReadingIterator const_iterator; - - - // basic_nsAReadableString(); // auto-generated default constructor OK (we're abstract anyway) - // basic_nsAReadableString( const basic_nsAReadableString& ); // auto-generated copy-constructor OK (again, only because we're abstract) - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsAReadableString& ); // but assignment is _not_ OK (we're immutable) so make it impossible - - public: - virtual ~basic_nsAReadableString() { } - // ...yes, I expect to be sub-classed. - - nsReadingIterator& BeginReading( nsReadingIterator& ) const; - nsReadingIterator& EndReading( nsReadingIterator& ) const; - - virtual PRUint32 Length() const = 0; - PRBool IsEmpty() const; - - /** - * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. - * These signatures should be pushed down into interfaces that guarantee flat allocation. - * Clients at _this_ level should always use iterators. - */ - CharT CharAt( PRUint32 ) const; - CharT operator[]( PRUint32 ) const; - CharT First() const; - CharT Last() const; - - PRUint32 CountChar( CharT ) const; - - - /* - |Left|, |Mid|, and |Right| are annoying signatures that seem better almost - any _other_ way than they are now. Consider these alternatives - - aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| - aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| - Left(aReadable, 17, aWritable); // ...a global function that does the assignment - - as opposed to the current signature - - aReadable.Left(aWritable, 17); // ...a member function that does the assignment - - or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality - - aWritable = Substring(aReadable, 0, 17); - */ - - PRUint32 Left( basic_nsAWritableString&, PRUint32 ) const; - PRUint32 Mid( basic_nsAWritableString&, PRUint32, PRUint32 ) const; - PRUint32 Right( basic_nsAWritableString&, PRUint32 ) const; - - // Find( ... ) const; - PRInt32 FindChar( CharT, PRUint32 aOffset = 0 ) const; - // FindCharInSet( ... ) const; - // RFind( ... ) const; - // RFindChar( ... ) const; - // RFindCharInSet( ... ) const; - - - int Compare( const basic_nsAReadableString& rhs ) const; - int Compare( const CharT* ) const; -// int Compare( const CharT*, PRUint32 ) const; -// int Compare( CharT ) const; - - // |Equals()| is a synonym for |Compare()| - PRBool Equals( const basic_nsAReadableString& rhs ) const; - PRBool Equals( const CharT* ) const; -// PRBool Equals( const CharT*, PRUint32 ) const; -// PRBool Equals( CharT ) const; - - // Comparison operators are all synonyms for |Compare()| - PRBool operator!=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)!=0; } - PRBool operator< ( const basic_nsAReadableString& rhs ) const { return Compare(rhs)< 0; } - PRBool operator<=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)<=0; } - PRBool operator==( const basic_nsAReadableString& rhs ) const { return Compare(rhs)==0; } - PRBool operator>=( const basic_nsAReadableString& rhs ) const { return Compare(rhs)>=0; } - PRBool operator> ( const basic_nsAReadableString& rhs ) const { return Compare(rhs)> 0; } - - - /* - Shouldn't be implemented because they're i18n sensitive. - Let's leave them in |nsString| for now. - */ - - // ToLowerCase - // ToUpperCase - // EqualsIgnoreCase - // IsASCII - // IsSpace - // IsAlpha - // IsDigit - // ToFloat - // ToInteger - - // char* ToNewCString() const; - // char* ToNewUTF8String() const; - // PRUnichar* ToNewUnicode() const; - // char* ToCString( char*, PRUint32, PRUint32 ) const; - - - /* - Shouldn't be implemented because it's wrong duplication. - Let's leave it in |nsString| for now. - */ - - // nsString* ToNewString() const; - // NO! The right way to say this is |new nsString( fromAReadableString )| - - - /* - Shouldn't be implemented because they're not generally applicable. - Let's leave them in |nsString| for now. - */ - - // IsOrdered - // BinarySearch - - // protected: - virtual const void* Implementation() const; - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; - virtual PRBool Promises( const basic_nsAReadableString& aString ) const { return &aString == this; } -// virtual PRBool PromisesExactly( const basic_nsAReadableString& aString ) const { return false; } - - private: - // NOT TO BE IMPLEMENTED - typedef typename nsCharTraits::incompatible_char_type incompatible_char_type; - PRUint32 CountChar( incompatible_char_type ) const; -// in Compare( incompatible_char_type ) const; -// PRBool Equals( incompatible_char_type ) const; - }; - - /* - The following macro defines a cast that helps us solve type-unification error problems on compilers - with poor template support. String clients probably _never_ need to use it. String implementors - sometimes will. - */ - #ifdef NEED_CPP_TEMPLATE_CAST_TO_BASE -#define NS_READABLE_CAST(CharT, expr) (NS_STATIC_CAST(const basic_nsAReadableString&, (expr))) +#define NS_READABLE_CAST(CharT, expr) (NS_STATIC_CAST(const nsStringTraits::abstract_string_type&, (expr))) #else #define NS_READABLE_CAST(CharT, expr) (expr) #endif -template -inline -void -nsReadingIterator::normalize_forward() - { - while ( mPosition == mFragment.mEnd - && mOwningString->GetReadableFragment(mFragment, kNextFragment) ) - mPosition = mFragment.mStart; - } - -template -inline -void -nsReadingIterator::normalize_backward() - { - while ( mPosition == mFragment.mStart - && mOwningString->GetReadableFragment(mFragment, kPrevFragment) ) - mPosition = mFragment.mEnd; - } - - /** - * Note: measure -- should the |BeginReading| and |EndReading| be |inline|? - */ -template -inline -nsReadingIterator& -basic_nsAReadableString::BeginReading( nsReadingIterator& aResult ) const - { - aResult.mOwningString = this; - GetReadableFragment(aResult.mFragment, kFirstFragment); - aResult.mPosition = aResult.mFragment.mStart; - aResult.normalize_forward(); - return aResult; - } - -template -inline -nsReadingIterator& -basic_nsAReadableString::EndReading( nsReadingIterator& aResult ) const - { - aResult.mOwningString = this; - GetReadableFragment(aResult.mFragment, kLastFragment); - aResult.mPosition = aResult.mFragment.mEnd; - // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| - return aResult; - } - -template -inline -PRBool -basic_nsAReadableString::IsEmpty() const - { - return Length() == 0; - } - -template -inline -PRBool -basic_nsAReadableString::Equals( const basic_nsAReadableString& rhs ) const - { - return Length() == rhs.Length() && Compare(rhs) == 0; - } - -template -inline -PRBool -operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) - { - return lhs.get() == rhs.get(); - } - -template -inline -PRBool -operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) - { - return lhs.get() != rhs.get(); - } - - -#define NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _StringT& lhs, const _CharT* rhs ) \ - { \ - return PRBool(Compare(NS_READABLE_CAST(_CharT, lhs), rhs) comp 0); \ - } - -#define NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _CharT* lhs, const _StringT& rhs ) \ - { \ - return PRBool(Compare(lhs, NS_READABLE_CAST(_CharT, rhs)) comp 0); \ - } - -#define NS_DEF_1_STRING_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - inline \ - PRBool \ - operator comp( const _StringT& lhs, const _StringT& rhs ) \ - { \ - return PRBool(Compare(NS_READABLE_CAST(_CharT, lhs), NS_READABLE_CAST(_CharT, rhs)) comp 0); \ - } - -#define NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(comp, _StringT, _CharT) \ - template NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - template NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) - -#define NS_DEF_3_STRING_COMPARISON_OPERATORS(comp, _StringT, _CharT) \ - NS_DEF_1_STRING_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - NS_DEF_1_STRING_PTR_COMPARISON_OPERATOR(comp, _StringT, _CharT) \ - NS_DEF_1_PTR_STRING_COMPARISON_OPERATOR(comp, _StringT, _CharT) - -#define NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(_StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(!=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(< , _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(<=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(==, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(>=, _StringT, _CharT) \ - NS_DEF_2_TEMPLATE_STRING_COMPARISON_OPERATORS(> , _StringT, _CharT) - -#define NS_DEF_STRING_COMPARISON_OPERATORS(_StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(!=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(< , _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(<=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(==, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(>=, _StringT, _CharT) \ - NS_DEF_3_STRING_COMPARISON_OPERATORS(> , _StringT, _CharT) - - -NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsAReadableString, CharT) - - - -template -const void* -basic_nsAReadableString::Implementation() const - { - return 0; - } - - - -template -CharT -basic_nsAReadableString::CharAt( PRUint32 aIndex ) const - { - NS_ASSERTION(aIndex iter; - return *(BeginReading(iter).advance(PRInt32(aIndex))); - } - -template -inline -CharT -basic_nsAReadableString::operator[]( PRUint32 aIndex ) const - { - return CharAt(aIndex); - } - -template -CharT -basic_nsAReadableString::First() const - { - NS_ASSERTION(Length()>0, "|First()| on an empty string"); - - nsReadingIterator iter; - return *BeginReading(iter); - } - -template -CharT -basic_nsAReadableString::Last() const - { - NS_ASSERTION(Length()>0, "|Last()| on an empty string"); - - nsReadingIterator iter; - EndReading(iter); - - if ( !IsEmpty() ) - iter.advance(-1); - - return *iter; // Note: this has undefined results if |IsEmpty()| - } - -template -PRUint32 -basic_nsAReadableString::CountChar( CharT c ) const - { -#if 0 - nsReadingIterator countBegin, countEnd; - return PRUint32(NS_COUNT(BeginReading(countBegin), EndReading(countEnd), c)); -#else - PRUint32 result = 0; - PRUint32 lengthToExamine = Length(); - - nsReadingIterator iter; - for ( BeginReading(iter); ; ) - { - PRInt32 lengthToExamineInThisFragment = iter.size_forward(); - const CharT* fromBegin = iter.get(); - result += PRUint32(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); - if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) - return result; - iter.advance(lengthToExamineInThisFragment); - } - // never reached; quiets warnings - return 0; -#endif - } - -#if 0 - // had to move these definitions into "nsAWritableString.h" -template -PRUint32 -basic_nsAReadableString::Mid( basic_nsAWritableString& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const - { - // If we're just assigning our entire self, give |aResult| the opportunity to share - if ( aStartPos == 0 && aLengthToCopy >= Length() ) - aResult = *this; - else - aResult = Substring(*this, aStartPos, aLengthToCopy); - - return aResult.Length(); - } - -template -inline -PRUint32 -basic_nsAReadableString::Left( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - return Mid(aResult, 0, aLengthToCopy); - } - -template -PRUint32 -basic_nsAReadableString::Right( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - PRUint32 myLength = Length(); - aLengthToCopy = NS_MIN(myLength, aLengthToCopy); - return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); - } -#endif - -template -PRInt32 -basic_nsAReadableString::FindChar( CharT aChar, PRUint32 aOffset ) const - { - nsReadingIterator iter, done_searching; - BeginReading(iter).advance( PRInt32(aOffset) ); - EndReading(done_searching); - - PRUint32 lengthSearched = 0; - while ( iter != done_searching ) - { - PRInt32 fragmentLength = iter.size_forward(); - const CharT* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); - if ( charFoundAt ) - return lengthSearched + (charFoundAt-iter.get()) + aOffset; - - lengthSearched += fragmentLength; - iter.advance(fragmentLength); - } - - return -1; - } - - - - - - - // - // nsLiteral[C]String - // - -template -class basic_nsLiteralString - : public basic_nsAReadableString - /* - ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. - - Use it like this: - - SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); - - With some tweaking, I think I can make this work as well... - - SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); - - This class just holds a pointer. If you don't supply the length, it must calculate it. - No copying or allocations are performed. - - |const basic_nsLiteralString&| appears frequently in interfaces because it - allows the automatic conversion of a |CharT*|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - - explicit - basic_nsLiteralString( const CharT* aLiteral ) - : mStart(aLiteral), - mEnd(mStart ? (mStart + nsCharTraits::length(mStart)) : mStart) - { - // nothing else to do here - } - - basic_nsLiteralString( const CharT* aLiteral, PRUint32 aLength ) - : mStart(aLiteral), - mEnd(mStart + aLength) - { - // This is an annoying hack. Callers should be fixed to use the other - // constructor if they don't really know the length. - if ( aLength == PRUint32(-1) ) - { -// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); - mEnd = mStart ? (mStart + nsCharTraits::length(mStart)) : mStart; - } - } - - // basic_nsLiteralString( const basic_nsLiteralString& ); // auto-generated copy-constructor OK - // ~basic_nsLiteralString(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsLiteralString& ); // we're immutable - - public: - - virtual PRUint32 Length() const; - - const CharT* get() const { return mStart; } - - // operator const CharT*() const; // use |get()| - - private: - const CharT* mStart; - const CharT* mEnd; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsLiteralString, CharT) - -template -const CharT* -basic_nsLiteralString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mStart = mStart; - aFragment.mEnd = mEnd; - return mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - -template -PRUint32 -basic_nsLiteralString::Length() const - { - return PRUint32(mEnd - mStart); - } - - -#if 0 -template -inline -PRBool -basic_nsAReadableString::Equals( const CharT* rhs, PRUint32 rhs_length ) const - { - return Compare(basic_nsLiteralString(rhs, rhs_length)) == 0; - } -#endif - -#if 0 -template -inline -int -basic_nsAReadableString::Compare( const CharT* rhs, PRUint32 rhs_length ) const - { - return ::Compare(*this, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs, rhs_length))); - } -#endif - - - // - // nsLiteralChar, nsLiteralPRUnichar - // - -template -class basic_nsLiteralChar - : public basic_nsAReadableString - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - - explicit - basic_nsLiteralChar( CharT aChar ) - : mChar(aChar) - { - // nothing else to do here - } - - // basic_nsLiteralChar( const basic_nsLiteralString& ); // auto-generated copy-constructor OK - // ~basic_nsLiteralChar(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const basic_nsLiteralChar& ); // we're immutable - - public: - - virtual - PRUint32 - Length() const - { - return 1; - } - - private: - CharT mChar; - }; - -template -const CharT* -basic_nsLiteralChar::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mEnd = (aFragment.mStart = &mChar) + 1; - return aFragment.mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - - - - - - - // - // nsPromiseConcatenation - // - -template class nsPromiseReadable : public basic_nsAReadableString { }; - -template -class nsPromiseConcatenation - : public nsPromiseReadable - /* - NOT FOR USE BY HUMANS - - Instances of this class only exist as anonymous temporary results from |operator+()|. - This is the machinery that makes string concatenation efficient. No allocations or - character copies are required unless and until a final assignment is made. It works - its magic by overriding and forwarding calls to |GetReadableFragment()|. - - Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. - - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| - - left to right evaluation is required ... do not use parentheses to override this - - In practice, neither of these is onerous. Parentheses do not change the semantics of the - concatenation, only the order in which the result is assembled ... so there's no reason - for a user to need to control it. Too many strings summed together can easily be worked - around with an intermediate assignment. I wouldn't have the parentheses limitation if I - assigned the identifier mask starting at the top, the first time anybody called - |GetReadableFragment()|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - enum { kLeftString, kRightString }; - - int - GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const - { - return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; - } - - int - SetLeftStringInFragment( nsReadableFragment& aFragment ) const - { - aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); - return kLeftString; - } - - int - SetRightStringInFragment( nsReadableFragment& aFragment ) const - { - aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); - return kRightString; - } - - public: - nsPromiseConcatenation( const basic_nsAReadableString& aLeftString, const basic_nsAReadableString& aRightString, PRUint32 aMask = 1 ) - : mFragmentIdentifierMask(aMask) - { - mStrings[kLeftString] = &aLeftString; - mStrings[kRightString] = &aRightString; - } - - nsPromiseConcatenation( const nsPromiseConcatenation& aLeftString, const basic_nsAReadableString& aRightString ) - : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) - { - mStrings[kLeftString] = &aLeftString; - mStrings[kRightString] = &aRightString; - } - - // nsPromiseConcatenation( const nsPromiseConcatenation& ); // auto-generated copy-constructor should be OK - // ~nsPromiseConcatenation(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const nsPromiseConcatenation& ); // we're immutable, you can't assign into a concatenation - - public: - - virtual PRUint32 Length() const; - virtual PRBool Promises( const basic_nsAReadableString& ) const; -// virtual PRBool PromisesExactly( const basic_nsAReadableString& ) const; - -// nsPromiseConcatenation operator+( const basic_nsAReadableString& rhs ) const; - - PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } - - private: - void operator+( const nsPromiseConcatenation& ); // NOT TO BE IMPLEMENTED - // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| - // which would break the algorithm for distributing bits in the fragment identifier - - private: - const basic_nsAReadableString* mStrings[2]; - PRUint32 mFragmentIdentifierMask; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(nsPromiseConcatenation, CharT) - -template -PRUint32 -nsPromiseConcatenation::Length() const - { - return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); - } - -template -PRBool -nsPromiseConcatenation::Promises( const basic_nsAReadableString& aString ) const - { - return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); - } - -#if 0 -PRBool -nsPromiseConcatenation::PromisesExactly( const basic_nsAReadableString& aString ) const - { - // Not really like this, test for the empty string, etc - return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; - } -#endif - -template -const CharT* -nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const - { - int whichString; - - // based on the request, pick which string we will forward the |GetReadableFragment()| call into - - switch ( aRequest ) - { - case kPrevFragment: - case kNextFragment: - whichString = GetCurrentStringFromFragment(aFragment); - break; - - case kFirstFragment: - whichString = SetLeftStringInFragment(aFragment); - break; - - case kLastFragment: - whichString = SetRightStringInFragment(aFragment); - break; - - case kFragmentAt: - PRUint32 leftLength = mStrings[kLeftString]->Length(); - if ( aPosition < leftLength ) - whichString = SetLeftStringInFragment(aFragment); - else - { - whichString = SetRightStringInFragment(aFragment); - aPosition -= leftLength; - } - break; - - } - - const CharT* result; - PRBool done; - do - { - done = PR_TRUE; - result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); - - if ( !result ) - { - done = PR_FALSE; - if ( aRequest == kNextFragment && whichString == kLeftString ) - { - aRequest = kFirstFragment; - whichString = SetRightStringInFragment(aFragment); - } - else if ( aRequest == kPrevFragment && whichString == kRightString ) - { - aRequest = kLastFragment; - whichString = SetLeftStringInFragment(aFragment); - } - else - done = PR_TRUE; - } - } - while ( !done ); - return result; - } - -#if 0 -template -inline -nsPromiseConcatenation -nsPromiseConcatenation::operator+( const basic_nsAReadableString& rhs ) const - { - return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); - } -#endif - - - - - - // - // nsPromiseSubstring - // - -template -class nsPromiseSubstring - : public nsPromiseReadable - /* - NOT FOR USE BY HUMANS (mostly) - - ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous - temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only - holds a pointer, no string data of its own. It does its magic by overriding and forwarding - calls to |GetReadableFragment()|. - */ - { - protected: - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; - - public: - nsPromiseSubstring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aLength ) - : mString(aString), - mStartPos( NS_MIN(aStartPos, aString.Length()) ), - mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) - { - // nothing else to do here - } - - nsPromiseSubstring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - : mString(aStart.string()) - { - nsReadingIterator zeroPoint; - mString.BeginReading(zeroPoint); - mStartPos = Distance(zeroPoint, aStart); - mLength = Distance(aStart, aEnd); - } - - // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK - // ~nsPromiseSubstring(); // auto-generated destructor OK - - private: - // NOT TO BE IMPLEMENTED - void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring - - public: - virtual PRUint32 Length() const; - virtual PRBool Promises( const basic_nsAReadableString& aString ) const { return mString.Promises(aString); } - - private: - const basic_nsAReadableString& mString; - PRUint32 mStartPos; - PRUint32 mLength; - }; - -// NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(nsPromiseSubstring, CharT) - -template -PRUint32 -nsPromiseSubstring::Length() const - { - return mLength; - } - -template -const CharT* -nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const - { - // Offset any request for a specific position (First, Last, At) by our - // substrings startpos within the owning string - - if ( aRequest == kFirstFragment ) - { - aPosition = mStartPos; - aRequest = kFragmentAt; - } - else if ( aRequest == kLastFragment ) - { - aPosition = mStartPos + mLength; - aRequest = kFragmentAt; - } - else if ( aRequest == kFragmentAt ) - aPosition += mStartPos; - - // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing - - const CharT* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); - - // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the - // fragment are garbage. - - // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null - if ( position_ptr ) - { - // if there's more physical data in the returned fragment than I logically have left... - size_t logical_size_backward = aPosition - mStartPos; - if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) - aFragment.mStart = position_ptr - logical_size_backward; - - size_t logical_size_forward = mLength - logical_size_backward; - if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) - aFragment.mEnd = position_ptr + logical_size_forward; - } - - return position_ptr; - } - - - - -#ifdef NEED_CPP_DERIVED_TEMPLATE_OPERATORS - - #define NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T) \ - template \ - inline \ - nsPromiseConcatenation \ - operator+( const _String1T& lhs, const _String2T& rhs ) \ - { \ - return nsPromiseConcatenation(lhs, rhs); \ - } - - NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseSubstring, nsPromiseSubstring) - NS_DEF_TEMPLATE_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseConcatenation, nsPromiseSubstring) - -#endif // NEED_CPP_DERIVED_TEMPLATE_OPERATORS - - - // - // Global functions - // - -template -inline -PRBool -SameImplementation( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - const void* imp_tag = lhs.Implementation(); - return imp_tag && (imp_tag==rhs.Implementation()); - } - -inline -nsPromiseSubstring -Substring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) - { - return nsPromiseSubstring(aString, aStartPos, aSubstringLength); - } - -inline -nsPromiseSubstring -Substring( const basic_nsAReadableString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) - { - return nsPromiseSubstring(aString, aStartPos, aSubstringLength); - } - -inline -nsPromiseSubstring -Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - { - return nsPromiseSubstring(aStart, aEnd); - } - -inline -nsPromiseSubstring -Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) - { - return nsPromiseSubstring(aStart, aEnd); - } - -template -int -Compare( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - if ( &lhs == &rhs ) - return 0; - - PRUint32 lLength = lhs.Length(); - PRUint32 rLength = rhs.Length(); - PRUint32 lengthToCompare = NS_MIN(lLength, rLength); - - nsReadingIterator leftIter, rightIter; - lhs.BeginReading(leftIter); - rhs.BeginReading(rightIter); - - int result; - - for (;;) - { - PRUint32 lengthAvailable = PRUint32( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); - - if ( lengthAvailable > lengthToCompare ) - lengthAvailable = lengthToCompare; - - // Note: |result| should be declared in this |if| expression, but some compilers don't like that - if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) - return result; - - if ( !(lengthToCompare -= lengthAvailable) ) - break; - - leftIter.advance( PRInt32(lengthAvailable) ); - rightIter.advance( PRInt32(lengthAvailable) ); - } - - if ( lLength < rLength ) - return -1; - else if ( rLength < lLength ) - return 1; - else - return 0; - } - -template -inline -int -Compare( const basic_nsAReadableString& lhs, const CharT* rhs ) - { - return Compare(lhs, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs))); - } - -template -inline -int -Compare( const CharT* lhs, const basic_nsAReadableString& rhs ) - { - return Compare(NS_READABLE_CAST(CharT, basic_nsLiteralString(lhs)), rhs); - } - -// XXX Note that these are located here because some compilers are -// sensitive to the ordering of declarations with regard to templates. -template -inline -int -basic_nsAReadableString::Compare( const basic_nsAReadableString& rhs ) const - { - return ::Compare(*this, rhs); - } - -template -inline -PRBool -basic_nsAReadableString::Equals( const CharT* rhs ) const - { - return Compare(basic_nsLiteralString(rhs)) == 0; - } - -template -inline -int -basic_nsAReadableString::Compare( const CharT* rhs ) const - { - return ::Compare(*this, NS_READABLE_CAST(CharT, basic_nsLiteralString(rhs))); - } - - - - /* - How shall we provide |operator+()|? - - What would it return? It has to return a stack based object, because the client will - not be given an opportunity to handle memory management in an expression like - - myWritableString = stringA + stringB + stringC; - - ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could - return an |nsString|, if that name were in scope here, though there's no telling what the client - will really want to do with the result. What might be better, though, - is to return a `promise' to concatenate some strings... - - By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle - assignment and other interesting uses within writable strings, plus we drastically reduce - the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings - in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work - to implement the virtual functions of readables. - */ - -template -inline -nsPromiseConcatenation -operator+( const nsPromiseConcatenation& lhs, const basic_nsAReadableString& rhs ) - { - return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); - } - -template -inline -nsPromiseConcatenation -operator+( const basic_nsAReadableString& lhs, const basic_nsAReadableString& rhs ) - { - return nsPromiseConcatenation(lhs, rhs); - } - - - -#ifdef NEED_CPP_DERIVED_TEMPLATE_OPERATORS - #define NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - inline \ - nsPromiseConcatenation<_CharT> \ - operator+( const _String1T& lhs, const _String2T& rhs ) \ - { \ - return nsPromiseConcatenation<_CharT>(lhs, rhs); \ - } - - #define NS_DEF_DERIVED_STRING_OPERATOR_PLUS(_StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_StringT, _StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseSubstring<_CharT>, _StringT, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_StringT, nsPromiseSubstring<_CharT>, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(nsPromiseConcatenation<_CharT>, _StringT, _CharT) - - #define NS_DEF_2_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) \ - NS_DEF_DERIVED_STRING_STRING_OPERATOR_PLUS(_String2T, _String1T, _CharT) - -#else - #define NS_DEF_DERIVED_STRING_OPERATOR_PLUS(_StringT, _CharT) - #define NS_DEF_2_STRING_STRING_OPERATOR_PLUS(_String1T, _String2T, _CharT) -#endif - - -#define kDefaultFlatStringSize 64 - -template -class basic_nsPromiseFlatString - : public basic_nsAReadableString - { - public: - explicit basic_nsPromiseFlatString( const basic_nsAReadableString& ); - - virtual - ~basic_nsPromiseFlatString( ) - { - if (mOwnsBuffer) - nsMemory::Free((void*)mBuffer); - } - - virtual PRUint32 Length() const { return mLength; } - virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const; - - const CharT* get() const { return mBuffer; } - - // operator const CharT*() const; // use |get()| - - protected: - PRUint32 mLength; - const CharT* mBuffer; - PRBool mOwnsBuffer; - CharT mInlineBuffer[kDefaultFlatStringSize]; - }; - -template -basic_nsPromiseFlatString::basic_nsPromiseFlatString( const basic_nsAReadableString& aString ) - : mLength(aString.Length()), - mOwnsBuffer(PR_FALSE) - { - typedef nsReadingIterator iterator; - - iterator start; - iterator end; - - aString.BeginReading(start); - aString.EndReading(end); - - // First count the number of buffers - PRInt32 buffer_count = 0; - while ( start != end ) - { - buffer_count++; - start += start.size_forward(); - } - - // Now figure out what we want to do with the string - aString.BeginReading(start); - // XXX Not guaranteed null-termination in the first case - // If it's a single buffer, we just use the implementation's buffer - if ( buffer_count == 1 ) - mBuffer = start.get(); - // If it's too big for our inline buffer, we allocate a new one - else if ( mLength > kDefaultFlatStringSize-1 ) - { - CharT* result = NS_STATIC_CAST(CharT*, nsMemory::Alloc((mLength+1) * sizeof(CharT))); - CharT* toBegin = result; - *copy_string(start, end, toBegin) = CharT(0); - - mBuffer = result; - mOwnsBuffer = PR_TRUE; - } - // Otherwise copy into our internal buffer - else - { - mBuffer = mInlineBuffer; - CharT* toBegin = &mInlineBuffer[0]; - copy_string( start, end, toBegin); - mInlineBuffer[mLength] = 0; - } - } - - -template -const CharT* -basic_nsPromiseFlatString::GetReadableFragment( nsReadableFragment& aFragment, - nsFragmentRequest aRequest, - PRUint32 aOffset ) const - { - switch ( aRequest ) - { - case kFirstFragment: - case kLastFragment: - case kFragmentAt: - aFragment.mEnd = (aFragment.mStart = mBuffer) + mLength; - return aFragment.mStart + aOffset; - - case kPrevFragment: - case kNextFragment: - default: - return 0; - } - } - - -typedef basic_nsAReadableString nsAReadableString; -typedef basic_nsAReadableString nsAReadableCString; - -typedef basic_nsLiteralString nsLiteralString; -typedef basic_nsLiteralString nsLiteralCString; - -typedef basic_nsPromiseFlatString nsPromiseFlatString; -typedef basic_nsPromiseFlatString nsPromiseFlatCString; - - -#ifdef HAVE_CPP_2BYTE_WCHAR_T - #define NS_L(s) L##s - #define NS_MULTILINE_LITERAL_STRING(s) nsLiteralString(s, (sizeof(s)/sizeof(wchar_t))-1) - #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) nsLiteralString n(s, (sizeof(s)/sizeof(wchar_t))-1) -#else - #define NS_L(s) s - #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUCS2(s, sizeof(s)-1) - #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) NS_ConvertASCIItoUCS2 n(s, sizeof(s)-1) -#endif - -#define NS_LITERAL_STRING(s) NS_MULTILINE_LITERAL_STRING(NS_L(s)) -#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n,NS_L(s)) - -#define NS_LITERAL_CSTRING(s) nsLiteralCString(s, sizeof(s)-1) -#define NS_NAMED_LITERAL_CSTRING(n,s) nsLiteralCString n(s, sizeof(s)-1) - -typedef basic_nsLiteralChar nsLiteralChar; -typedef basic_nsLiteralChar nsLiteralPRUnichar; - - #endif // !defined(nsAReadableString_h___) diff --git a/xpcom/string/public/nsAString.h b/xpcom/string/public/nsAString.h new file mode 100644 index 000000000000..a6fb0361ef48 --- /dev/null +++ b/xpcom/string/public/nsAString.h @@ -0,0 +1,772 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsAString_h___ +#define nsAString_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nsPrivateSharableString_h___ +#include "nsPrivateSharableString.h" +#endif + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsStringIterator_h___ +#include "nsStringIterator.h" +#endif + + + /** + * + */ + +class NS_COM nsAString + : public nsPrivateSharableString + { + public: + typedef nsAString self_type; + typedef nsAPromiseString promise_type; + typedef PRUnichar char_type; + typedef char incompatible_char_type; + + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + + + + // nsAString(); // auto-generated default constructor OK (we're abstract anyway) + // nsAString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract) + virtual ~nsAString() { } // ...yes, I expect to be sub-classed + + inline const_iterator& BeginReading( const_iterator& ) const; + inline const_iterator& EndReading( const_iterator& ) const; + + inline iterator& BeginWriting( iterator& ); + inline iterator& EndWriting( iterator& ); + + virtual size_type Length() const = 0; + PRBool IsEmpty() const { return Length() == 0; } + + inline PRBool Equals( const self_type& ) const; + PRBool Equals( const char_type* ) const; + + + /** + * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. + * These signatures should be pushed down into interfaces that guarantee flat allocation. + * Clients at _this_ level should always use iterators. + */ + char_type First() const; + char_type Last() const; + + size_type CountChar( char_type ) const; + + + /* + |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + any _other_ way than they are now. Consider these alternatives + + aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + Left(aReadable, 17, aWritable); // ...a global function that does the assignment + + as opposed to the current signature + + aReadable.Left(aWritable, 17); // ...a member function that does the assignment + + or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + + aWritable = Substring(aReadable, 0, 17); + */ + + size_type Left( self_type&, size_type ) const; + size_type Mid( self_type&, PRUint32, PRUint32 ) const; + size_type Right( self_type&, size_type ) const; + + // Find( ... ) const; + PRInt32 FindChar( char_type, index_type aOffset = 0 ) const; + // FindCharInSet( ... ) const; + // RFind( ... ) const; + // RFindChar( ... ) const; + // RFindCharInSet( ... ) const; + + /** + * |SetCapacity| is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * |SetCapacity(0)| is a suggestion to discard all associated storage. + */ + virtual void SetCapacity( size_type ) { } + + /** + * |SetLength| is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| is this latter capacity. + * Should this really be a public operation? + * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you + * override the |do_...| routines to not need this facility. + * + * This distinction makes me think the two different uses should be split into + * two distinct functions. + */ + virtual void SetLength( size_type ) { } + + + void + Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); + + if ( aNewLength < this->Length() ) + SetLength(aNewLength); + } + + + // PRBool SetCharAt( char_type, index_type ) = 0; + + + + // void ToLowerCase(); + // void ToUpperCase(); + + // void StripChars( const char_type* aSet ); + // void StripChar( ... ); + // void StripWhitespace(); + // void ReplaceChar( ... ); + // void ReplaceSubstring( ... ); + // void Trim( ... ); + // void CompressSet( ... ); + // void CompressWhitespace( ... ); + + + + // + // |Assign()|, |operator=()| + // + + void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); } + inline void Assign( const promise_type& aReadable ); + void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } + void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } + void Assign( char_type aChar ) { do_AssignFromElement(aChar); } + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; } + + self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; } + self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; } + self_type& operator=( char_type aChar ) { Assign(aChar); return *this; } + + + + // + // |Append()|, |operator+=()| + // + + void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); } + inline void Append( const promise_type& aReadable ); + void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } + void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } + void Append( char_type aChar ) { do_AppendFromElement(aChar); } + + self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; } + self_type& operator+=( char_type aChar ) { Append(aChar); return *this; } + + + + /** + * The following index based routines need to be recast with iterators. + */ + + // + // |Insert()| + // Note: I would really like to move the |atPosition| parameter to the front of the argument list + // + + void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); } + inline void Insert( const promise_type& aReadable, index_type atPosition ); + void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } + void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } + void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); } + + + + virtual void Cut( index_type cutStart, size_type cutLength ); + + + + void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } +// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } + + private: + // NOT TO BE IMPLEMENTED + index_type CountChar( incompatible_char_type ) const; + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + + + protected: + void AssignFromReadable( const self_type& ); + void AssignFromPromise( const self_type& ); + virtual void do_AssignFromReadable( const self_type& ); + virtual void do_AssignFromElementPtr( const char_type* ); + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ); + virtual void do_AssignFromElement( char_type ); + + void AppendFromReadable( const self_type& ); + void AppendFromPromise( const self_type& ); + virtual void do_AppendFromReadable( const self_type& ); + virtual void do_AppendFromElementPtr( const char_type* ); + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ); + virtual void do_AppendFromElement( char_type ); + + void InsertFromReadable( const self_type&, index_type ); + void InsertFromPromise( const self_type&, index_type ); + virtual void do_InsertFromReadable( const self_type&, index_type ); + virtual void do_InsertFromElementPtr( const char_type*, index_type ); + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ); + virtual void do_InsertFromElement( char_type, index_type ); + + void ReplaceFromReadable( index_type, size_type, const self_type& ); + void ReplaceFromPromise( index_type, size_type, const self_type& ); + virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& ); + + +// protected: + public: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; + virtual PRBool Promises( const self_type& aString ) const { return &aString == this; } + }; + +class NS_COM nsACString + : public nsPrivateSharableCString + { + public: + typedef nsACString self_type; + typedef nsAPromiseCString promise_type; + typedef char char_type; + typedef PRUnichar incompatible_char_type; + + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + + + + // nsACString(); // auto-generated default constructor OK (we're abstract anyway) + // nsACString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract) + virtual ~nsACString() { } // ...yes, I expect to be sub-classed + + inline const_iterator& BeginReading( const_iterator& ) const; + inline const_iterator& EndReading( const_iterator& ) const; + + inline iterator& BeginWriting( iterator& ); + inline iterator& EndWriting( iterator& ); + + virtual size_type Length() const = 0; + PRBool IsEmpty() const { return Length() == 0; } + + inline PRBool Equals( const self_type& ) const; + PRBool Equals( const char_type* ) const; + + + /** + * |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations. + * These signatures should be pushed down into interfaces that guarantee flat allocation. + * Clients at _this_ level should always use iterators. + */ + char_type First() const; + char_type Last() const; + + size_type CountChar( char_type ) const; + + + /* + |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + any _other_ way than they are now. Consider these alternatives + + aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + Left(aReadable, 17, aWritable); // ...a global function that does the assignment + + as opposed to the current signature + + aReadable.Left(aWritable, 17); // ...a member function that does the assignment + + or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + + aWritable = Substring(aReadable, 0, 17); + */ + + size_type Left( self_type&, size_type ) const; + size_type Mid( self_type&, PRUint32, PRUint32 ) const; + size_type Right( self_type&, size_type ) const; + + // Find( ... ) const; + PRInt32 FindChar( char_type, PRUint32 aOffset = 0 ) const; + // FindCharInSet( ... ) const; + // RFind( ... ) const; + // RFindChar( ... ) const; + // RFindCharInSet( ... ) const; + + /** + * |SetCapacity| is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * |SetCapacity(0)| is a suggestion to discard all associated storage. + */ + virtual void SetCapacity( size_type ) { } + + /** + * |SetLength| is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| is this latter capacity. + * Should this really be a public operation? + * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you + * override the |do_...| routines to not need this facility. + * + * This distinction makes me think the two different uses should be split into + * two distinct functions. + */ + virtual void SetLength( size_type ) { } + + + void + Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); + + if ( aNewLength < this->Length() ) + SetLength(aNewLength); + } + + + // PRBool SetCharAt( char_type, index_type ) = 0; + + + + // void ToLowerCase(); + // void ToUpperCase(); + + // void StripChars( const char_type* aSet ); + // void StripChar( ... ); + // void StripWhitespace(); + // void ReplaceChar( ... ); + // void ReplaceSubstring( ... ); + // void Trim( ... ); + // void CompressSet( ... ); + // void CompressWhitespace( ... ); + + + + // + // |Assign()|, |operator=()| + // + + void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); } + inline void Assign( const promise_type& aReadable ); + void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } + void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } + void Assign( char_type aChar ) { do_AssignFromElement(aChar); } + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; } + + self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; } + self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; } + self_type& operator=( char_type aChar ) { Assign(aChar); return *this; } + + + + // + // |Append()|, |operator+=()| + // + + void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); } + inline void Append( const promise_type& aReadable ); + void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } + void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } + void Append( char_type aChar ) { do_AppendFromElement(aChar); } + + self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; } + self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; } + self_type& operator+=( char_type aChar ) { Append(aChar); return *this; } + + + + /** + * The following index based routines need to be recast with iterators. + */ + + // + // |Insert()| + // Note: I would really like to move the |atPosition| parameter to the front of the argument list + // + + void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); } + inline void Insert( const promise_type& aReadable, index_type atPosition ); + void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } + void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } + void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); } + + + + virtual void Cut( index_type cutStart, size_type cutLength ); + + + + void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } +// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } + + private: + // NOT TO BE IMPLEMENTED + index_type CountChar( incompatible_char_type ) const; + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + + + protected: + void AssignFromReadable( const self_type& ); + void AssignFromPromise( const self_type& ); + virtual void do_AssignFromReadable( const self_type& ); + virtual void do_AssignFromElementPtr( const char_type* ); + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ); + virtual void do_AssignFromElement( char_type ); + + void AppendFromReadable( const self_type& ); + void AppendFromPromise( const self_type& ); + virtual void do_AppendFromReadable( const self_type& ); + virtual void do_AppendFromElementPtr( const char_type* ); + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ); + virtual void do_AppendFromElement( char_type ); + + void InsertFromReadable( const self_type&, index_type ); + void InsertFromPromise( const self_type&, index_type ); + virtual void do_InsertFromReadable( const self_type&, index_type ); + virtual void do_InsertFromElementPtr( const char_type*, index_type ); + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ); + virtual void do_InsertFromElement( char_type, index_type ); + + void ReplaceFromReadable( index_type, size_type, const self_type& ); + void ReplaceFromPromise( index_type, size_type, const self_type& ); + virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& ); + + +// protected: + public: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; + virtual PRBool Promises( const self_type& aString ) const { return &aString == this; } + }; + +#include "nsAPromiseString.h" + +inline +void +nsAString::Assign( const nsAPromiseString& aReadable ) + { + AssignFromPromise(aReadable); + } + +inline +void +nsAString::Append( const nsAPromiseString& aReadable ) + { + AppendFromPromise(aReadable); + } + +inline +void +nsAString::Insert( const nsAPromiseString& aReadable, index_type atPosition ) + { + InsertFromPromise(aReadable, atPosition); + } + +inline +void +nsACString::Assign( const nsAPromiseCString& aReadable ) + { + AssignFromPromise(aReadable); + } + +inline +void +nsACString::Append( const nsAPromiseCString& aReadable ) + { + AppendFromPromise(aReadable); + } + +inline +void +nsACString::Insert( const nsAPromiseCString& aReadable, index_type atPosition ) + { + InsertFromPromise(aReadable, atPosition); + } + + + /** + * Note: measure -- should the |Begin...| and |End...| be |inline|? + */ +inline +nsAString::const_iterator& +nsAString::BeginReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + +inline +nsAString::const_iterator& +nsAString::EndReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +inline +nsAString::iterator& +nsAString::BeginWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + + +inline +nsAString::iterator& +nsAString::EndWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +NS_COM int Compare( const nsAString& lhs, const nsAString& rhs ); + +inline +PRBool +nsAString::Equals( const self_type& rhs ) const + { + return Length()==rhs.Length() && Compare(*this, rhs)==0; + } + +inline +PRBool +operator!=( const nsAString& lhs, const nsAString& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool +operator< ( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool +operator<=( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool +operator==( const nsAString& lhs, const nsAString& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool +operator>=( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool +operator> ( const nsAString& lhs, const nsAString& rhs ) + { + return Compare(lhs, rhs)> 0; + } + +inline +nsAString::size_type +nsAString::Left( nsAString& aResult, size_type aLengthToCopy ) const + { + return Mid(aResult, 0, aLengthToCopy); + } + + + /** + * + */ + +inline +nsACString::const_iterator& +nsACString::BeginReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + +inline +nsACString::const_iterator& +nsACString::EndReading( const_iterator& aResult ) const + { + aResult.mOwningString = this; + GetReadableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +inline +nsACString::iterator& +nsACString::BeginWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kFirstFragment); + aResult.mPosition = aResult.mFragment.mStart; + aResult.normalize_forward(); + return aResult; + } + + +inline +nsACString::iterator& +nsACString::EndWriting( iterator& aResult ) + { + aResult.mOwningString = this; + GetWritableFragment(aResult.mFragment, kLastFragment); + aResult.mPosition = aResult.mFragment.mEnd; + // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| + return aResult; + } + +NS_COM int Compare( const nsACString& lhs, const nsACString& rhs ); + +inline +PRBool +nsACString::Equals( const self_type& rhs ) const + { + return Length()==rhs.Length() && Compare(*this, rhs)==0; + } + +inline +PRBool +operator!=( const nsACString& lhs, const nsACString& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool +operator< ( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool +operator<=( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool +operator==( const nsACString& lhs, const nsACString& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool +operator>=( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool +operator> ( const nsACString& lhs, const nsACString& rhs ) + { + return Compare(lhs, rhs)> 0; + } + +inline +nsACString::size_type +nsACString::Left( nsACString& aResult, size_type aLengthToCopy ) const + { + return Mid(aResult, 0, aLengthToCopy); + } + + // Once you've got strings, you shouldn't need to do anything else to have concatenation +#ifndef nsPromiseConcatenation_h___ +#include "nsPromiseConcatenation.h" +#endif + +#endif // !defined(nsAString_h___) diff --git a/xpcom/string/public/nsAWritableString.h b/xpcom/string/public/nsAWritableString.h index 209e4ff8766c..04024d8a0354 100644 --- a/xpcom/string/public/nsAWritableString.h +++ b/xpcom/string/public/nsAWritableString.h @@ -21,866 +21,16 @@ * Scott Collins (original author) */ +/* nsAWritableString.h --- a compatibility header for clients still using the names |nsAWritable[C]String| */ + #ifndef nsAWritableString_h___ #define nsAWritableString_h___ - // See also... #ifndef nsAReadableString_h___ #include "nsAReadableString.h" #endif - -template -struct nsWritableFragment - { - CharT* mStart; - CharT* mEnd; - void* mFragmentIdentifier; - - nsWritableFragment() - : mStart(0), mEnd(0), mFragmentIdentifier(0) - { - // nothing else to do here - } - }; - -template class basic_nsAWritableString; - -template -class nsWritingIterator -// : public bidirectional_iterator_tag - { - public: - typedef ptrdiff_t difference_type; - typedef CharT value_type; - typedef CharT* pointer; - typedef CharT& reference; -// typedef bidirectional_iterator_tag iterator_category; - - private: - friend class basic_nsAWritableString; - - nsWritableFragment mFragment; - CharT* mPosition; - basic_nsAWritableString* mOwningString; - - nsWritingIterator( nsWritableFragment& aFragment, - CharT* aStartingPosition, - basic_nsAWritableString& aOwningString ) - : mFragment(aFragment), - mPosition(aStartingPosition), - mOwningString(&aOwningString) - { - // nothing else to do here - } - - public: - nsWritingIterator() { } - // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK - // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK - - inline void normalize_forward(); - inline void normalize_backward(); - - pointer - get() const - { - return mPosition; - } - - reference - operator*() const - { - return *get(); - } - -#if 0 - // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) - // don't like this when |CharT| is a type without members. - pointer - operator->() const - { - return get(); - } -#endif - - nsWritingIterator& - operator++() - { - ++mPosition; - normalize_forward(); - return *this; - } - - nsWritingIterator - operator++( int ) - { - nsWritingIterator result(*this); - ++mPosition; - normalize_forward(); - return result; - } - - nsWritingIterator& - operator--() - { - normalize_backward(); - --mPosition; - return *this; - } - - nsWritingIterator - operator--( int ) - { - nsWritingIterator result(*this); - normalize_backward(); - --mPosition; - return result; - } - - const nsWritableFragment& - fragment() const - { - return mFragment; - } - - nsWritableFragment& - fragment() - { - return mFragment; - } - - const basic_nsAWritableString& - string() const - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - basic_nsAWritableString& - string() - { - NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); - return *mOwningString; - } - - difference_type - size_forward() const - { - return mFragment.mEnd - mPosition; - } - - difference_type - size_backward() const - { - return mPosition - mFragment.mStart; - } - - nsWritingIterator& - 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 writing 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 writing iterator beyond the end of a string"); - // perhaps I should |break| if |!one_hop|? - - mPosition += one_hop; - n -= one_hop; - } - - return *this; - } - - /** - * Really don't want to call these two operations |+=| and |-=|. - * Would prefer a single function, e.g., |advance|, which doesn't imply a constant time operation. - * - * We'll get rid of these as soon as we can. - */ - nsWritingIterator& - operator+=( difference_type n ) // deprecated - { - return advance(n); - } - - nsWritingIterator& - operator-=( difference_type n ) // deprecated - { - return advance(-n); - } - - PRUint32 - write( const value_type* s, PRUint32 n ) - { - NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); - - n = NS_MIN(n, PRUint32(size_forward())); - nsCharTraits::move(mPosition, s, n); - advance( difference_type(n) ); - return n; - } - }; - -#if 0 -template -nsWritingIterator& -nsWritingIterator::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 writing 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 writing iterator beyond the end of a string"); - // perhaps I should |break| if |!one_hop|? - - mPosition += one_hop; - n -= one_hop; - } - - return *this; - } -#endif - -/* - This file defines the abstract interfaces |nsAWritableString| and - |nsAWritableCString|. - - |nsAWritableString| is a string of |PRUnichar|s. |nsAWritableCString| (note the - 'C') is a string of |char|s. -*/ - -template -class basic_nsAWritableString - : public basic_nsAReadableString - /* - ... - */ - { - // friend class nsWritingIterator; - - public: - typedef CharT char_type; - typedef PRUint32 size_type; - typedef PRUint32 index_type; - - typedef nsWritingIterator iterator; - - // basic_nsAWritableString(); // auto-generated default constructor OK (we're abstract anyway) - // basic_nsAWritableString( const basic_nsAWritableString& ); // auto-generated copy-constructor OK (again, only because we're abstract) - // ~basic_nsAWritableString(); // auto-generated destructor OK - // see below for copy-assignment operator - - virtual CharT* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 = 0 ) = 0; - - /** - * Note: measure -- should the |BeginWriting| and |EndWriting| be |inline|? - */ - nsWritingIterator& - BeginWriting( nsWritingIterator& aResult ) - { - aResult.mOwningString = this; - GetWritableFragment(aResult.mFragment, kFirstFragment); - aResult.mPosition = aResult.mFragment.mStart; - aResult.normalize_forward(); - return aResult; - } - - - nsWritingIterator& - EndWriting( nsWritingIterator& aResult ) - { - aResult.mOwningString = this; - GetWritableFragment(aResult.mFragment, kLastFragment); - aResult.mPosition = aResult.mFragment.mEnd; - // must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )| - return aResult; - } - - - /** - * |SetCapacity| is not required to do anything; however, it can be used - * as a hint to the implementation to reduce allocations. - * |SetCapacity(0)| is a suggestion to discard all associated storage. - */ - virtual void SetCapacity( PRUint32 ) { } - - /** - * |SetLength| is used in two ways: - * 1) to |Cut| a suffix of the string; - * 2) to prepare to |Append| or move characters around. - * - * External callers are not allowed to use |SetLength| is this latter capacity. - * Should this really be a public operation? - * Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you - * override the |do_...| routines to not need this facility. - * - * This distinction makes me think the two different uses should be split into - * two distinct functions. - */ - virtual void SetLength( PRUint32 ) = 0; - - - void - Truncate( PRUint32 aNewLength=0 ) - { - NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer."); - - if ( aNewLength < this->Length() ) - SetLength(aNewLength); - } - - - // PRBool SetCharAt( char_type, index_type ) = 0; - - - - // void ToLowerCase(); - // void ToUpperCase(); - - // void StripChars( const CharT* aSet ); - // void StripChar( ... ); - // void StripWhitespace(); - // void ReplaceChar( ... ); - // void ReplaceSubstring( ... ); - // void Trim( ... ); - // void CompressSet( ... ); - // void CompressWhitespace( ... ); - - - - // - // |Assign()|, |operator=()| - // - - void Assign( const basic_nsAReadableString& aReadable ) { AssignFromReadable(aReadable); } - void Assign( const nsPromiseReadable& aReadable ) { AssignFromPromise(aReadable); } - void Assign( const CharT* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); } - void Assign( const CharT* aPtr, PRUint32 aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); } - void Assign( CharT aChar ) { do_AssignFromElement(aChar); } - - // copy-assignment operator. I must define my own if I don't want the compiler to make me one - basic_nsAWritableString& operator=( const basic_nsAWritableString& aWritable ) { Assign(aWritable); return *this; } - - basic_nsAWritableString& operator=( const basic_nsAReadableString& aReadable ) { Assign(aReadable); return *this; } - basic_nsAWritableString& operator=( const nsPromiseReadable& aReadable ) { Assign(aReadable); return *this; } - basic_nsAWritableString& operator=( const CharT* aPtr ) { Assign(aPtr); return *this; } - basic_nsAWritableString& operator=( CharT aChar ) { Assign(aChar); return *this; } - - - - // - // |Append()|, |operator+=()| - // - - void Append( const basic_nsAReadableString& aReadable ) { AppendFromReadable(aReadable); } - void Append( const nsPromiseReadable& aReadable ) { AppendFromPromise(aReadable); } - void Append( const CharT* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); } - void Append( const CharT* aPtr, PRUint32 aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); } - void Append( CharT aChar ) { do_AppendFromElement(aChar); } - - basic_nsAWritableString& operator+=( const basic_nsAReadableString& aReadable ) { Append(aReadable); return *this; } - basic_nsAWritableString& operator+=( const nsPromiseReadable& aReadable ) { Append(aReadable); return *this; } - basic_nsAWritableString& operator+=( const CharT* aPtr ) { Append(aPtr); return *this; } - basic_nsAWritableString& operator+=( CharT aChar ) { Append(aChar); return *this; } - - - - /** - * The following index based routines need to be recast with iterators. - */ - - // - // |Insert()| - // Note: I would really like to move the |atPosition| parameter to the front of the argument list - // - - void Insert( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) { InsertFromReadable(aReadable, atPosition); } - void Insert( const nsPromiseReadable& aReadable, PRUint32 atPosition ) { InsertFromPromise(aReadable, atPosition); } - void Insert( const CharT* aPtr, PRUint32 atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); } - void Insert( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); } - void Insert( CharT aChar, PRUint32 atPosition ) { do_InsertFromElement(aChar, atPosition); } - - - - virtual void Cut( PRUint32 cutStart, PRUint32 cutLength ); - - - - void Replace( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); } - void Replace( PRUint32 cutStart, PRUint32 cutLength, const nsPromiseReadable& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); } - - private: - typedef typename nsCharTraits::incompatible_char_type incompatible_char_type; - - // NOT TO BE IMPLEMENTED - void operator= ( incompatible_char_type ); - void Assign ( incompatible_char_type ); - void operator+= ( incompatible_char_type ); - void Append ( incompatible_char_type ); - void Insert ( incompatible_char_type, PRUint32 ); - - - protected: - void AssignFromReadable( const basic_nsAReadableString& ); - void AssignFromPromise( const basic_nsAReadableString& ); - virtual void do_AssignFromReadable( const basic_nsAReadableString& ); - virtual void do_AssignFromElementPtr( const CharT* ); - virtual void do_AssignFromElementPtrLength( const CharT*, PRUint32 ); - virtual void do_AssignFromElement( CharT ); - - void AppendFromReadable( const basic_nsAReadableString& ); - void AppendFromPromise( const basic_nsAReadableString& ); - virtual void do_AppendFromReadable( const basic_nsAReadableString& ); - virtual void do_AppendFromElementPtr( const CharT* ); - virtual void do_AppendFromElementPtrLength( const CharT*, PRUint32 ); - virtual void do_AppendFromElement( CharT ); - - void InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - void InsertFromPromise( const basic_nsAReadableString&, PRUint32 ); - virtual void do_InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - virtual void do_InsertFromElementPtr( const CharT*, PRUint32 ); - virtual void do_InsertFromElementPtrLength( const CharT*, PRUint32, PRUint32 ); - virtual void do_InsertFromElement( CharT, PRUint32 ); - - void ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); - void ReplaceFromPromise( PRUint32, PRUint32, const basic_nsAReadableString& ); - virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); - }; - - - - // - // |nsWritingIterator|s - // - -template -inline -void -nsWritingIterator::normalize_forward() - { - while ( mPosition == mFragment.mEnd - && mOwningString->GetWritableFragment(mFragment, kNextFragment) ) - mPosition = mFragment.mStart; - } - -template -inline -void -nsWritingIterator::normalize_backward() - { - while ( mPosition == mFragment.mStart - && mOwningString->GetWritableFragment(mFragment, kPrevFragment) ) - mPosition = mFragment.mEnd; - } - -template -inline -PRBool -operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) - { - return lhs.get() == rhs.get(); - } - -template -inline -PRBool -operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) - { - return lhs.get() != rhs.get(); - } - - - - // - // |Assign()| - // - -template -void -basic_nsAWritableString::AssignFromReadable( const basic_nsAReadableString& rhs ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &rhs ) - do_AssignFromReadable(rhs); - // else, self-assign is a no-op - } - -template -void -basic_nsAWritableString::AssignFromPromise( const basic_nsAReadableString& aReadable ) - /* - ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. - E.g., - - ... writable& w ... - ... readable& r ... - - w = r + w; - - In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before - anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents - of |r| before being retrieved to be appended. - - We could have a really tricky solution where we tell the promise to resolve _just_ the data promised - by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., - in the case above, |Insert| could have special behavior with significantly better performance. Since - it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the - entire promise. If we measure and this turns out to show up on performance radar, we then have the - option to fix either the callers or this mechanism. - */ - { - if ( !aReadable.Promises(*this) ) - do_AssignFromReadable(aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - // Note: not exception safe. We need something to manage temporary buffers like this - - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_AssignFromElementPtrLength(buffer, length); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_AssignFromReadable( const basic_nsAReadableString& aReadable ) - { - SetLength(0); - SetLength(aReadable.Length()); - // first setting the length to |0| avoids copying characters only to be overwritten later - // in the case where the implementation decides to re-allocate - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); - } - -template -void -basic_nsAWritableString::do_AssignFromElementPtr( const CharT* aPtr ) - { - do_AssignFromReadable(basic_nsLiteralString(aPtr)); - } - -template -void -basic_nsAWritableString::do_AssignFromElementPtrLength( const CharT* aPtr, PRUint32 aLength ) - { - do_AssignFromReadable(basic_nsLiteralString(aPtr, aLength)); - } - -template -void -basic_nsAWritableString::do_AssignFromElement( CharT aChar ) - { - do_AssignFromReadable(basic_nsLiteralChar(aChar)); - } - - - - // - // |Append()| - // - -template -void -basic_nsAWritableString::AppendFromReadable( const basic_nsAReadableString& aReadable ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReadable ) - do_AppendFromReadable(aReadable); - else - AppendFromPromise(aReadable); - } - -template -void -basic_nsAWritableString::AppendFromPromise( const basic_nsAReadableString& aReadable ) - { - if ( !aReadable.Promises(*this) ) - do_AppendFromReadable(aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_AppendFromElementPtrLength(buffer, length); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_AppendFromReadable( const basic_nsAReadableString& aReadable ) - { - PRUint32 oldLength = this->Length(); - SetLength(oldLength + aReadable.Length()); - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); - } - -template -void -basic_nsAWritableString::do_AppendFromElementPtr( const CharT* aChar ) - { - do_AppendFromReadable(basic_nsLiteralString(aChar)); - } - -template -void -basic_nsAWritableString::do_AppendFromElementPtrLength( const CharT* aChar, PRUint32 aLength ) - { - do_AppendFromReadable(basic_nsLiteralString(aChar, aLength)); - } - -template -void -basic_nsAWritableString::do_AppendFromElement( CharT aChar ) - { - do_AppendFromReadable(basic_nsLiteralChar(aChar)); - } - - - - // - // |Insert()| - // - -template -void -basic_nsAWritableString::InsertFromReadable( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReadable ) - do_InsertFromReadable(aReadable, atPosition); - else - InsertFromPromise(aReadable, atPosition); - } - -template -void -basic_nsAWritableString::InsertFromPromise( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - if ( !aReadable.Promises(*this) ) - do_InsertFromReadable(aReadable, atPosition); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_InsertFromElementPtrLength(buffer, atPosition, length); - delete buffer; - } - // else assert - } - } - -template -void -basic_nsAWritableString::do_InsertFromReadable( const basic_nsAReadableString& aReadable, PRUint32 atPosition ) - { - PRUint32 oldLength = this->Length(); - SetLength(oldLength + aReadable.Length()); - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( atPosition < oldLength ) - copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); - else - atPosition = oldLength; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); - } - -template -void -basic_nsAWritableString::do_InsertFromElementPtr( const CharT* aPtr, PRUint32 atPosition ) - { - do_InsertFromReadable(basic_nsLiteralString(aPtr), atPosition); - } - -template -void -basic_nsAWritableString::do_InsertFromElementPtrLength( const CharT* aPtr, PRUint32 atPosition, PRUint32 aLength ) - { - do_InsertFromReadable(basic_nsLiteralString(aPtr, aLength), atPosition); - } - -template -void -basic_nsAWritableString::do_InsertFromElement( CharT aChar, PRUint32 atPosition ) - { - do_InsertFromReadable(basic_nsLiteralChar(aChar), atPosition); - } - - - - // - // |Cut()| - // - -template -void -basic_nsAWritableString::Cut( PRUint32 cutStart, PRUint32 cutLength ) - { - PRUint32 myLength = this->Length(); - cutLength = NS_MIN(cutLength, myLength-cutStart); - PRUint32 cutEnd = cutStart + cutLength; - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( cutEnd < myLength ) - copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); - SetLength(myLength-cutLength); - } - - - - // - // |Replace()| - // - -template -void -basic_nsAWritableString::ReplaceFromReadable( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReplacement ) - { - if ( NS_STATIC_CAST(const basic_nsAReadableString*, this) != &aReplacement ) - do_ReplaceFromReadable(cutStart, cutLength, aReplacement); - else - ReplaceFromPromise(cutStart, cutLength, aReplacement); - } - -template -void -basic_nsAWritableString::ReplaceFromPromise( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReadable ) - { - if ( !aReadable.Promises(*this) ) - do_ReplaceFromReadable(cutStart, cutLength, aReadable); - else - { - PRUint32 length = aReadable.Length(); - CharT* buffer = new CharT[length]; - if ( buffer ) - { - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = buffer; - copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); - do_ReplaceFromReadable(cutStart, cutLength, basic_nsLiteralString(buffer, length)); - delete buffer; - } - // else assert? - } - } - -template -void -basic_nsAWritableString::do_ReplaceFromReadable( PRUint32 cutStart, PRUint32 cutLength, const basic_nsAReadableString& aReplacement ) - { - PRUint32 oldLength = this->Length(); - - cutStart = NS_MIN(cutStart, oldLength); - cutLength = NS_MIN(cutLength, oldLength-cutStart); - PRUint32 cutEnd = cutStart + cutLength; - - PRUint32 replacementLength = aReplacement.Length(); - PRUint32 replacementEnd = cutStart + replacementLength; - - PRUint32 newLength = oldLength - cutLength + replacementLength; - - nsReadingIterator fromBegin, fromEnd; - nsWritingIterator toBegin; - if ( cutLength > replacementLength ) - copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); - SetLength(newLength); - if ( cutLength < replacementLength ) - copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); - - copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); - } - - -template -PRUint32 -basic_nsAReadableString::Mid( basic_nsAWritableString& aResult, PRUint32 aStartPos, PRUint32 aLengthToCopy ) const - { - // If we're just assigning our entire self, give |aResult| the opportunity to share - if ( aStartPos == 0 && aLengthToCopy >= Length() ) - aResult = *this; - else - aResult = Substring(*this, aStartPos, aLengthToCopy); - - return aResult.Length(); - } - -template -inline -PRUint32 -basic_nsAReadableString::Left( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - return Mid(aResult, 0, aLengthToCopy); - } - -template -PRUint32 -basic_nsAReadableString::Right( basic_nsAWritableString& aResult, PRUint32 aLengthToCopy ) const - { - PRUint32 myLength = Length(); - aLengthToCopy = NS_MIN(myLength, aLengthToCopy); - return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); - } - - - - - // - // Types - // - -typedef basic_nsAWritableString nsAWritableString; -typedef basic_nsAWritableString nsAWritableCString; +typedef nsAString nsAWritableString; +typedef nsACString nsAWritableCString; #endif // !defined(nsAWritableString_h___) diff --git a/xpcom/string/public/nsBufferHandle.h b/xpcom/string/public/nsBufferHandle.h index a2b290334fc8..0cd7e1d547e7 100755 --- a/xpcom/string/public/nsBufferHandle.h +++ b/xpcom/string/public/nsBufferHandle.h @@ -163,13 +163,14 @@ class nsSharedBufferHandle protected: enum { - kIsShared = 1<<31, - kIsSingleAllocationWithBuffer = 1<<30, // handle and buffer are one piece, no separate deallocation is possible for the buffer - kIsStorageDefinedSeparately = 1<<29, // i.e., we're using the ``flex'' structure defined below - kIsUserAllocator = 1<<28, // can't |delete|, call a hook instead + kIsShared = 0x8000000, + kIsSingleAllocationWithBuffer = 0x4000000, // handle and buffer are one piece, no separate deallocation is possible for the buffer + kIsStorageDefinedSeparately = 0x2000000, // i.e., we're using the ``flex'' structure defined below + kIsUserAllocator = 0x1000000, // can't |delete|, call a hook instead - kFlagsMask = kIsShared | kIsSingleAllocationWithBuffer | kIsStorageDefinedSeparately | kIsUserAllocator, - kRefCountMask = ~kFlagsMask + kImplementationFlagsMask = 0x0F00000, + kFlagsMask = 0xFF00000, + kRefCountMask = 0x00FFFFF }; public: @@ -179,6 +180,14 @@ class nsSharedBufferHandle mFlags = kIsShared; } + nsSharedBufferHandle( CharT* aDataStart, CharT* aDataEnd, CharT*, CharT*, PRBool isSingleAllocation ) + : nsBufferHandle(aDataStart, aDataEnd) + { + mFlags = kIsShared; + if ( isSingleAllocation ) + mFlags |= kIsSingleAllocationWithBuffer; + } + ~nsSharedBufferHandle(); void @@ -203,6 +212,18 @@ class nsSharedBufferHandle return get_refcount() != 0; } + PRUint32 + GetImplementationFlags() const + { + return mFlags & kImplementationFlagsMask; + } + + void + SetImplementationFlags( PRUint32 aNewFlags ) + { + mFlags = (mFlags & ~kImplementationFlagsMask) | (aNewFlags & kImplementationFlagsMask); + } + protected: PRUint32 mFlags; diff --git a/xpcom/string/public/nsBufferHandleUtils.h b/xpcom/string/public/nsBufferHandleUtils.h index 6f05fabe22ab..565ac3b64f07 100644 --- a/xpcom/string/public/nsBufferHandleUtils.h +++ b/xpcom/string/public/nsBufferHandleUtils.h @@ -25,15 +25,83 @@ #ifndef nsBufferHandleUtils_h___ #define nsBufferHandleUtils_h___ -#ifndef nsAReadableString_h___ -#include "nsAReadableString.h" - // for |basic_nsAReadableString|... +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" #endif #include // for placement |new| +template +class nsAutoBufferHandle + { + public: + nsAutoBufferHandle() : mHandle(0) { } + + nsAutoBufferHandle( const nsAutoBufferHandle& aOther ) + : mHandle(aOther.get()) + { + if ( mHandle) + mHandle->AcquireReference(); + } + + explicit + nsAutoBufferHandle( const nsSharedBufferHandle* aHandle ) + : mHandle(aHandle) + { + if ( mHandle) + mHandle->AcquireReference(); + } + + ~nsAutoBufferHandle() + { + if ( mHandle ) + mHandle->ReleaseReference(); + } + + nsAutoBufferHandle& + operator=( const nsSharedBufferHandle* rhs ) + { + nsSharedBufferHandle* old_handle = mHandle; + if ( (mHandle = NS_CONST_CAST(nsSharedBufferHandle*, rhs)) ) + mHandle->AcquireReference(); + if ( old_handle ) + old_handle->ReleaseReference(); + return *this; + } + + nsAutoBufferHandle& + operator=( const nsAutoBufferHandle& rhs ) + { + return operator=(rhs.get()); + } + + nsSharedBufferHandle* + get() const + { + return mHandle; + } + + operator nsSharedBufferHandle*() const + { + return get(); + } + + nsSharedBufferHandle* + operator->() const + { + return get(); + } + + private: + nsSharedBufferHandle* mHandle; + }; + template inline @@ -62,21 +130,22 @@ NS_DataAfterHandle( HandleT* aHandlePtr, const CharT* aDummyCharTPtr ) return CharT_ptr(NS_STATIC_CAST(unsigned char*, aHandlePtr) + NS_AlignedHandleSize(aHandlePtr, aDummyCharTPtr)); } -template +template HandleT* -NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const basic_nsAReadableString& aDataSource, PRUint32 aAdditionalCapacity ) +NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const StringT& aDataSource, PRUint32 aAdditionalCapacity ) { - typedef CharT* CharT_ptr; + typedef typename StringT::char_type char_type; + typedef char_type* char_ptr; // figure out the number of bytes needed the |HandleT| part, including padding to correctly align the data part - size_t handle_size = NS_AlignedHandleSize(aDummyHandlePtr, CharT_ptr(0)); + size_t handle_size = NS_AlignedHandleSize(aDummyHandlePtr, char_ptr(0)); - // figure out how many |CharT|s wee need to fit in the data part + // figure out how many |char_type|s wee need to fit in the data part size_t data_length = aDataSource.Length(); size_t buffer_length = data_length + aAdditionalCapacity; // how many bytes is that (including a zero-terminator so we can claim to be flat)? - size_t buffer_size = buffer_length * sizeof(CharT); + size_t buffer_size = buffer_length * sizeof(char_type); HandleT* result = 0; @@ -84,17 +153,17 @@ NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const basic if ( handle_ptr ) { - CharT* data_start_ptr = CharT_ptr(NS_STATIC_CAST(unsigned char*, handle_ptr) + handle_size); - CharT* data_end_ptr = data_start_ptr + data_length; - CharT* buffer_end_ptr = data_start_ptr + buffer_length; + char_ptr data_start_ptr = char_ptr(NS_STATIC_CAST(unsigned char*, handle_ptr) + handle_size); + char_ptr data_end_ptr = data_start_ptr + data_length; + char_ptr buffer_end_ptr = data_start_ptr + buffer_length; - nsReadingIterator fromBegin, fromEnd; - CharT* toBegin = data_start_ptr; + typename StringT::const_iterator fromBegin, fromEnd; + char_ptr toBegin = data_start_ptr; copy_string(aDataSource.BeginReading(fromBegin), aDataSource.EndReading(fromEnd), toBegin); // and if the caller bothered asking for a buffer bigger than their string, we'll zero-terminate if ( aAdditionalCapacity > 0 ) - *toBegin = CharT(0); + *toBegin = char_type(0); result = new (handle_ptr) HandleT(data_start_ptr, data_end_ptr, data_start_ptr, buffer_end_ptr, PR_TRUE); } diff --git a/xpcom/string/public/nsCharTraits.h b/xpcom/string/public/nsCharTraits.h index dc4b681a1f5e..32f0fb58c4ec 100644 --- a/xpcom/string/public/nsCharTraits.h +++ b/xpcom/string/public/nsCharTraits.h @@ -35,6 +35,9 @@ // for |PRUnichar| #endif +#ifndef nsStringIteratorUtils_h___ +#include "nsStringIteratorUtils.h" +#endif #ifdef HAVE_CPP_BOOL typedef bool nsCharTraits_bool; @@ -45,8 +48,8 @@ template struct nsCharTraits { - typedef CharT char_type; - typedef char incompatible_char_type; + typedef CharT char_type; + typedef char incompatible_char_type; static void @@ -210,8 +213,8 @@ struct nsCharTraits NS_SPECIALIZE_TEMPLATE struct nsCharTraits { - typedef char char_type; - typedef PRUnichar incompatible_char_type; + typedef char char_type; + typedef PRUnichar incompatible_char_type; static void @@ -337,7 +340,7 @@ struct nsCharTraits NS_SPECIALIZE_TEMPLATE struct nsCharTraits { - typedef wchar_t char_type; + typedef wchar_t char_type; static void @@ -460,7 +463,6 @@ struct nsCharTraits }; #endif - template struct nsCharSourceTraits { diff --git a/xpcom/string/public/nsCommonString.h b/xpcom/string/public/nsCommonString.h new file mode 100644 index 000000000000..64a5f9e438da --- /dev/null +++ b/xpcom/string/public/nsCommonString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsCommonString.h --- a string implementation that shares its underlying storage */ + + +#ifndef nsCommonString_h___ +#define nsCommonString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + +#ifndef nsBufferHandleUtils_h___ +#include "nsBufferHandleUtils.h" +#endif + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + /** + * Not yet ready for non-|const| access + */ + +class NS_COM nsCommonString + : public nsAFlatString + { + public: + typedef nsCommonString self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + + public: + nsCommonString() { } + nsCommonString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +class NS_COM nsCommonCString + : public nsAFlatCString + { + public: + typedef nsCommonCString self_type; + typedef char char_type; + typedef nsACString string_type; + + public: + nsCommonCString() { } + nsCommonCString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonCString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +#endif /* !defined(nsCommonString_h___) */ diff --git a/xpcom/string/public/nsDependentConcatenation.h b/xpcom/string/public/nsDependentConcatenation.h new file mode 100644 index 000000000000..3339087112f8 --- /dev/null +++ b/xpcom/string/public/nsDependentConcatenation.h @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsPromiseConcatenation.h --- string concatenation machinery lives here, but don't include this file + directly, always get it by including either "nsAString.h" or one of the compatibility headers */ + +#ifndef nsPromiseConcatenation_h___ +#define nsPromiseConcatenation_h___ + + /** + NOT FOR USE BY HUMANS + + Instances of this class only exist as anonymous temporary results from |operator+()|. + This is the machinery that makes string concatenation efficient. No allocations or + character copies are required unless and until a final assignment is made. It works + its magic by overriding and forwarding calls to |GetReadableFragment()|. + + Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. + - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| + - left to right evaluation is required ... do not use parentheses to override this + + In practice, neither of these is onerous. Parentheses do not change the semantics of the + concatenation, only the order in which the result is assembled ... so there's no reason + for a user to need to control it. Too many strings summed together can easily be worked + around with an intermediate assignment. I wouldn't have the parentheses limitation if I + assigned the identifier mask starting at the top, the first time anybody called + |GetReadableFragment()|. + */ + +class NS_COM nsPromiseConcatenation + : public nsAPromiseString + { + public: + typedef nsPromiseConcatenation self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + +class NS_COM nsPromiseCConcatenation + : public nsAPromiseCString + { + public: + typedef nsPromiseCConcatenation self_type; + typedef char char_type; + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseCConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + + /* + How shall we provide |operator+()|? + + What would it return? It has to return a stack based object, because the client will + not be given an opportunity to handle memory management in an expression like + + myWritableString = stringA + stringB + stringC; + + ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could + return an |nsString|, if that name were in scope here, though there's no telling what the client + will really want to do with the result. What might be better, though, + is to return a `promise' to concatenate some strings... + + By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle + assignment and other interesting uses within writable strings, plus we drastically reduce + the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings + in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work + to implement the virtual functions of readables. + */ + +inline +const nsPromiseConcatenation +operator+( const nsPromiseConcatenation& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseCConcatenation +operator+( const nsPromiseCConcatenation& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseConcatenation +operator+( const nsAString& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs); + } + +inline +const nsPromiseCConcatenation +operator+( const nsACString& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs); + } + +#if 0 +inline +const nsPromiseConcatenation +nsPromiseConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } + +inline +const nsPromiseCConcatenation +nsPromiseCConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseCConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } +#endif + + +#endif /* !defined(nsPromiseConcatenation_h___) */ diff --git a/xpcom/string/public/nsDependentString.h b/xpcom/string/public/nsDependentString.h new file mode 100644 index 000000000000..59bc4a94b3b5 --- /dev/null +++ b/xpcom/string/public/nsDependentString.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLocalString_h___ +#define nsLocalString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + + /* + ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. + + Use it like this: + + SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); + + With some tweaking, I think I can make this work as well... + + SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); + + This class just holds a pointer. If you don't supply the length, it must calculate it. + No copying or allocations are performed. + + |const nsLocalString&| appears frequently in interfaces because it + allows the automatic conversion of a |PRUnichar*|. + */ + +class NS_COM nsLocalString + : public nsAFlatString + { + public: + + explicit + nsLocalString( const PRUnichar* aLiteral ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)) + { + // nothing else to do here + } + + nsLocalString( const PRUnichar* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), NS_CONST_CAST(PRUnichar*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)); + } + } + + // nsLocalString( const nsLocalString& ); // auto-generated copy-constructor OK + // ~nsLocalString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalString& ); // we're immutable + }; + + + +class NS_COM nsLocalCString + : public nsAFlatCString + { + public: + + explicit + nsLocalCString( const char* aLiteral ) + : mHandle(NS_CONST_CAST(char*, aLiteral), aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)) + { + // nothing else to do here + } + + nsLocalCString( const char* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(char*, aLiteral), NS_CONST_CAST(char*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)); + } + } + + // nsLocalCString( const nsLocalCString& ); // auto-generated copy-constructor OK + // ~nsLocalCString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalCString& ); // we're immutable + }; + +#endif /* !defined(nsLocalString_h___) */ diff --git a/xpcom/string/public/nsDependentSubstring.h b/xpcom/string/public/nsDependentSubstring.h new file mode 100644 index 000000000000..afbe0890f598 --- /dev/null +++ b/xpcom/string/public/nsDependentSubstring.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseSubstring_h___ +#define nsPromiseSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + + + + // + // nsPromiseSubstring + // + +class NS_COM nsPromiseSubstring + : public nsAPromiseString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + +class NS_COM nsPromiseCSubstring + : public nsAPromiseCString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseCSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseCSubstring( const nsPromiseCSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseCSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + + + + + + + +inline +const nsPromiseCSubstring +Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseCSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseSubstring +Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseCSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseCSubstring(aStart, aEnd); + } + +inline +const nsPromiseSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseSubstring(aStart, aEnd); + } + + +#endif /* !defined(nsPromiseSubstring_h___) */ diff --git a/xpcom/string/public/nsFragmentedString.h b/xpcom/string/public/nsFragmentedString.h index e5348b42f48a..3201a699d63f 100644 --- a/xpcom/string/public/nsFragmentedString.h +++ b/xpcom/string/public/nsFragmentedString.h @@ -27,8 +27,8 @@ // WORK IN PROGRESS -#ifndef nsAWritableString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" #endif #ifndef nsSharedBufferList_h___ @@ -37,7 +37,7 @@ class nsFragmentedString - : public basic_nsAWritableString + : public nsAString /* ... */ @@ -57,10 +57,10 @@ class nsFragmentedString // virtual void Cut( PRUint32 cutStart, PRUint32 cutLength ); protected: - // virtual void do_AssignFromReadable( const basic_nsAReadableString& ); - // virtual void do_AppendFromReadable( const basic_nsAReadableString& ); - // virtual void do_InsertFromReadable( const basic_nsAReadableString&, PRUint32 ); - // virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const basic_nsAReadableString& ); + // virtual void do_AssignFromReadable( const nsAString& ); + // virtual void do_AppendFromReadable( const nsAString& ); + // virtual void do_InsertFromReadable( const nsAString&, PRUint32 ); + // virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const nsAString& ); private: nsSharedBufferList mBufferList; diff --git a/xpcom/string/public/nsLiteralString.h b/xpcom/string/public/nsLiteralString.h new file mode 100644 index 000000000000..b5d30e01baa2 --- /dev/null +++ b/xpcom/string/public/nsLiteralString.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLiteralString_h___ +#define nsLiteralString_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsLocalString_h___ +#include "nsLocalString.h" +#endif + +typedef const nsLocalString nsLiteralString; +typedef const nsLocalCString nsLiteralCString; + +#if 0 +inline +const nsLocalString +literal_string( const PRUnichar* aPtr ) + { + return nsLocalString(aPtr); + } + +inline +const nsLocalString +literal_string( const PRUnichar* aPtr, PRUint32 aLength ) + { + return nsLocalString(aPtr, aLength); + } + +inline +const nsLocalCString +literal_string( const char* aPtr ) + { + return nsLocalCString(aPtr); + } + +inline +const nsLocalCString +literal_string( const char* aPtr, PRUint32 aLength ) + { + return nsLocalCString(aPtr, aLength); + } +#endif + +#ifdef HAVE_CPP_2BYTE_WCHAR_T + #define NS_L(s) L##s + #define NS_MULTILINE_LITERAL_STRING(s) nsLiteralString(s, (sizeof(s)/sizeof(wchar_t))-1) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) nsLiteralString n(s, (sizeof(s)/sizeof(wchar_t))-1) +#else + #define NS_L(s) s + #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUCS2(s, sizeof(s)-1) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) NS_ConvertASCIItoUCS2 n(s, sizeof(s)-1) +#endif + +#define NS_LITERAL_STRING(s) NS_MULTILINE_LITERAL_STRING(NS_L(s)) +#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n,NS_L(s)) + +#define NS_LITERAL_CSTRING(s) nsLiteralCString(s, sizeof(s)-1) +#define NS_NAMED_LITERAL_CSTRING(n,s) nsLiteralCString n(s, sizeof(s)-1) + +#endif /* !defined(nsLiteralString_h___) */ diff --git a/xpcom/string/public/nsLocalString.h b/xpcom/string/public/nsLocalString.h new file mode 100644 index 000000000000..59bc4a94b3b5 --- /dev/null +++ b/xpcom/string/public/nsLocalString.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsLocalString_h___ +#define nsLocalString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + + /* + ...this class wraps a constant literal string and lets it act like an |nsAReadable...|. + + Use it like this: + + SomeFunctionTakingACString( nsLiteralCString("Hello, World!") ); + + With some tweaking, I think I can make this work as well... + + SomeStringFunc( nsLiteralString( L"Hello, World!" ) ); + + This class just holds a pointer. If you don't supply the length, it must calculate it. + No copying or allocations are performed. + + |const nsLocalString&| appears frequently in interfaces because it + allows the automatic conversion of a |PRUnichar*|. + */ + +class NS_COM nsLocalString + : public nsAFlatString + { + public: + + explicit + nsLocalString( const PRUnichar* aLiteral ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)) + { + // nothing else to do here + } + + nsLocalString( const PRUnichar* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), NS_CONST_CAST(PRUnichar*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral)); + } + } + + // nsLocalString( const nsLocalString& ); // auto-generated copy-constructor OK + // ~nsLocalString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalString& ); // we're immutable + }; + + + +class NS_COM nsLocalCString + : public nsAFlatCString + { + public: + + explicit + nsLocalCString( const char* aLiteral ) + : mHandle(NS_CONST_CAST(char*, aLiteral), aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)) + { + // nothing else to do here + } + + nsLocalCString( const char* aLiteral, PRUint32 aLength ) + : mHandle(NS_CONST_CAST(char*, aLiteral), NS_CONST_CAST(char*, aLiteral)+aLength) + { + // This is an annoying hack. Callers should be fixed to use the other + // constructor if they don't really know the length. + if ( aLength == PRUint32(-1) ) + { +// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor."); + mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral)); + } + } + + // nsLocalCString( const nsLocalCString& ); // auto-generated copy-constructor OK + // ~nsLocalCString(); // auto-generated destructor OK + + virtual const nsBufferHandle* GetFlatBufferHandle() const { return &mHandle; } + virtual const nsBufferHandle* GetBufferHandle() const { return &mHandle; } + + private: + nsBufferHandle mHandle; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsLocalCString& ); // we're immutable + }; + +#endif /* !defined(nsLocalString_h___) */ diff --git a/xpcom/string/public/nsPrintfCString.h b/xpcom/string/public/nsPrintfCString.h index e434c8c8230f..9f3a3d1b4316 100755 --- a/xpcom/string/public/nsPrintfCString.h +++ b/xpcom/string/public/nsPrintfCString.h @@ -38,7 +38,9 @@ #ifndef nsPrintfCString_h___ #define nsPrintfCString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" +#endif /** @@ -66,7 +68,7 @@ */ class nsPrintfCString - : public nsAReadableCString + : public nsACString { enum { kLocalBufferSize=15 }; // ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask) @@ -81,7 +83,8 @@ class nsPrintfCString virtual PRUint32 Length() const; protected: - virtual const char* GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const; + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } // virtual PRBool GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest ) const; private: diff --git a/xpcom/string/public/nsPrivateSharableString.h b/xpcom/string/public/nsPrivateSharableString.h index 0c34d60d3f4c..6bf03dc0872a 100755 --- a/xpcom/string/public/nsPrivateSharableString.h +++ b/xpcom/string/public/nsPrivateSharableString.h @@ -30,39 +30,53 @@ #endif /** - * This class is (will be) part of the machinery that makes + * This class is part of the machinery that makes * most string implementations in this family share their underlying buffers * when convenient. It is _not_ part of the abstract string interface, * though other machinery interested in sharing buffers will know about it. + * + * Normal string clients must _never_ call routines from this interface. */ -template -class nsPrivateSharableString +class NS_COM nsPrivateSharableString { public: - virtual const nsBufferHandle* GetBufferHandle() const; - virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + typedef PRUnichar char_type; + + public: + virtual ~nsPrivateSharableString() {} + + virtual PRUint32 GetImplementationFlags() const; + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; /** - * |GetBufferHandle()| will return either |0|, |1|, or a reasonable pointer. + * |GetBufferHandle()| will return either |0|, or a reasonable pointer. * The meaning of |0| is that the string points to a non-contiguous or else empty representation. - * The meaning of |1| is implementation dependant. - * Otherwise |GetBufferHandle()| returns a pointer to the single contiguous hunk of characters - * that makes up this string. + * Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters + * that make up this string. */ }; -template -const nsSharedBufferHandle* -nsPrivateSharableString::GetSharedBufferHandle() const +class NS_COM nsPrivateSharableCString { - return 0; - } + public: + typedef char char_type; -template -const nsBufferHandle* -nsPrivateSharableString::GetBufferHandle() const - { - return GetSharedBufferHandle(); - } + public: + virtual ~nsPrivateSharableCString() {} + + virtual PRUint32 GetImplementationFlags() const; + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + /** + * |GetBufferHandle()| will return either |0|, or a reasonable pointer. + * The meaning of |0| is that the string points to a non-contiguous or else empty representation. + * Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters + * that make up this string. + */ + }; #endif // !defined(nsPrivateSharableString_h___) diff --git a/xpcom/string/public/nsPromiseConcatenation.h b/xpcom/string/public/nsPromiseConcatenation.h new file mode 100644 index 000000000000..3339087112f8 --- /dev/null +++ b/xpcom/string/public/nsPromiseConcatenation.h @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsPromiseConcatenation.h --- string concatenation machinery lives here, but don't include this file + directly, always get it by including either "nsAString.h" or one of the compatibility headers */ + +#ifndef nsPromiseConcatenation_h___ +#define nsPromiseConcatenation_h___ + + /** + NOT FOR USE BY HUMANS + + Instances of this class only exist as anonymous temporary results from |operator+()|. + This is the machinery that makes string concatenation efficient. No allocations or + character copies are required unless and until a final assignment is made. It works + its magic by overriding and forwarding calls to |GetReadableFragment()|. + + Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|. + - no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33| + - left to right evaluation is required ... do not use parentheses to override this + + In practice, neither of these is onerous. Parentheses do not change the semantics of the + concatenation, only the order in which the result is assembled ... so there's no reason + for a user to need to control it. Too many strings summed together can easily be worked + around with an intermediate assignment. I wouldn't have the parentheses limitation if I + assigned the identifier mask starting at the top, the first time anybody called + |GetReadableFragment()|. + */ + +class NS_COM nsPromiseConcatenation + : public nsAPromiseString + { + public: + typedef nsPromiseConcatenation self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + +class NS_COM nsPromiseCConcatenation + : public nsAPromiseCString + { + public: + typedef nsPromiseCConcatenation self_type; + typedef char char_type; + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char_type* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char_type* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + enum { kLeftString, kRightString }; + + int + GetCurrentStringFromFragment( const nsReadableFragment& aFragment ) const + { + return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString; + } + + int + SetLeftStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask); + return kLeftString; + } + + int + SetRightStringInFragment( nsReadableFragment& aFragment ) const + { + aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask); + return kRightString; + } + + public: + nsPromiseCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 ) + : mFragmentIdentifierMask(aMask) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + nsPromiseCConcatenation( const self_type& aLeftString, const string_type& aRightString ) + : mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1) + { + mStrings[kLeftString] = &aLeftString; + mStrings[kRightString] = &aRightString; + } + + // nsPromiseCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCConcatenation(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation + + public: + + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& ) const; +// virtual PRBool PromisesExactly( const string_type& ) const; + +// const self_type operator+( const string_type& rhs ) const; + + PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; } + + private: + void operator+( const self_type& ); // NOT TO BE IMPLEMENTED + // making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)| + // which would break the algorithm for distributing bits in the fragment identifier + + private: + const string_type* mStrings[2]; + PRUint32 mFragmentIdentifierMask; + }; + + /* + How shall we provide |operator+()|? + + What would it return? It has to return a stack based object, because the client will + not be given an opportunity to handle memory management in an expression like + + myWritableString = stringA + stringB + stringC; + + ...so the `obvious' answer of returning a new |nsSharedString| is no good. We could + return an |nsString|, if that name were in scope here, though there's no telling what the client + will really want to do with the result. What might be better, though, + is to return a `promise' to concatenate some strings... + + By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle + assignment and other interesting uses within writable strings, plus we drastically reduce + the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings + in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work + to implement the virtual functions of readables. + */ + +inline +const nsPromiseConcatenation +operator+( const nsPromiseConcatenation& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseCConcatenation +operator+( const nsPromiseCConcatenation& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1); + } + +inline +const nsPromiseConcatenation +operator+( const nsAString& lhs, const nsAString& rhs ) + { + return nsPromiseConcatenation(lhs, rhs); + } + +inline +const nsPromiseCConcatenation +operator+( const nsACString& lhs, const nsACString& rhs ) + { + return nsPromiseCConcatenation(lhs, rhs); + } + +#if 0 +inline +const nsPromiseConcatenation +nsPromiseConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } + +inline +const nsPromiseCConcatenation +nsPromiseCConcatenation::operator+( const string_type& rhs ) const + { + return nsPromiseCConcatenation(*this, rhs, mFragmentIdentifierMask<<1); + } +#endif + + +#endif /* !defined(nsPromiseConcatenation_h___) */ diff --git a/xpcom/string/public/nsPromiseFlatString.h b/xpcom/string/public/nsPromiseFlatString.h new file mode 100644 index 000000000000..1c23bd05945b --- /dev/null +++ b/xpcom/string/public/nsPromiseFlatString.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseFlatString_h___ +#define nsPromiseFlatString_h___ + +#ifndef nsCommonString_h___ +#include "nsCommonString.h" +#endif + + /** + * WARNING: + * + * Try to avoid flat strings. |PromiseFlat[C]String| will help you as a last resort, + * and this may be necessary when dealing with legacy or OS calls, but in general, + * requiring a zero-terminated contiguous hunk of characters kills many of the performance + * wins the string classes offer. Write your own code to use |nsA[C]String&|s for parameters. + * Write your string proccessing algorithms to exploit iterators. If you do this, you + * will benefit from being able to chain operations without copying or allocating and your + * code will be significantly more efficient. Remember, a function that takes an + * |const nsA[C]String&| can always be passed a raw character pointer by wrapping it (for free) + * in a |nsLocal[C]String|. But a function that takes a character pointer always has the + * potential to force allocation and copying. + * + * + * How to use it: + * + * Like all `promises', a |nsPromiseFlat[C]String| doesn't own the characters it promises. + * You must never use it to promise characters out of a string with a shorter lifespan. + * The typical use will be something like this + * + * SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD + * + * Here's a BAD use: + * + * const char* buffer = PromiseFlatCString(aCString).get(); + * SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer + * + * A |nsPromiseFlat[C]String| doesn't support non-|const| access (you can't use it to make + * changes back into the original string). To help you avoid that, the only way to make + * one is with the function |PromiseFlat[C]String|, which produce a |const| instance. + * ``What if I need to keep a promise around for a little while?'' you might ask. + * In that case, you can keep a reference, like so + * + * const nsPromiseFlatString& flat = PromiseFlatString(aString); + * // this reference holds the anonymous temporary alive, but remember, it must _still_ + * // have a lifetime shorter than that of |aString| + * + * SomeOSFunction(flat.get()); + * SomeOtherOSFunction(flat.get()); + * + * + * How does it work? + * + * A |nsPromiseFlat[C]String| is just a wrapper for another string. If you apply it to + * a string that happens to be flat, your promise is just a reference to that other string + * and all calls are forwarded through to it. If you apply it to a non-flat string, + * then a temporary flat string is created for you, by allocating and copying. In the unlikely + * event that you end up assigning the result into a sharing string (e.g., |nsCommon[C]String|), + * the right thing happens. + */ + +class NS_COM nsPromiseFlatString + : public nsAFlatString /* , public nsAPromiseString */ + { + friend const nsPromiseFlatString PromiseFlatString( const nsAString& ); + + public: + nsPromiseFlatString( const nsPromiseFlatString& ); + virtual const PRUnichar* get() const; // this will be gone after we fix obsolete/nsString + + protected: + nsPromiseFlatString() : mPromisedString(&mFlattenedString) { } + explicit nsPromiseFlatString( const nsAString& aString ); + + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseFlatString& ); + + private: + nsCommonString mFlattenedString; + const nsAFlatString* mPromisedString; + }; + +class NS_COM nsPromiseFlatCString + : public nsAFlatCString /* , public nsAPromiseCString */ + { + friend const nsPromiseFlatCString PromiseFlatCString( const nsACString& ); + + public: + nsPromiseFlatCString( const nsPromiseFlatCString& ); + virtual const char* get() const; // this will be gone after we fix obsolete/nsString + + protected: + nsPromiseFlatCString() : mPromisedString(&mFlattenedString) { } + explicit nsPromiseFlatCString( const nsACString& aString ); + + virtual const nsBufferHandle* GetFlatBufferHandle() const; + virtual const nsBufferHandle* GetBufferHandle() const; + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseFlatCString& ); + + private: + nsCommonCString mFlattenedString; + const nsAFlatCString* mPromisedString; + }; + + +inline +const nsPromiseFlatString +PromiseFlatString( const nsAString& aString ) + { + return nsPromiseFlatString(aString); + } + +inline +const nsPromiseFlatCString +PromiseFlatCString( const nsACString& aString ) + { + return nsPromiseFlatCString(aString); + } + +#endif /* !defined(nsPromiseFlatString_h___) */ diff --git a/xpcom/string/public/nsPromiseSubstring.h b/xpcom/string/public/nsPromiseSubstring.h new file mode 100644 index 000000000000..afbe0890f598 --- /dev/null +++ b/xpcom/string/public/nsPromiseSubstring.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsPromiseSubstring_h___ +#define nsPromiseSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + + + + // + // nsPromiseSubstring + // + +class NS_COM nsPromiseSubstring + : public nsAPromiseString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsAString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + +class NS_COM nsPromiseCSubstring + : public nsAPromiseCString + /* + NOT FOR USE BY HUMANS (mostly) + + ...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous + temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only + holds a pointer, no string data of its own. It does its magic by overriding and forwarding + calls to |GetReadableFragment()|. + */ + { + typedef nsACString string_type; + typedef string_type::const_iterator const_iterator; + + protected: + virtual const char* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual char* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } + + public: + nsPromiseCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength ) + : mString(aString), + mStartPos( NS_MIN(aStartPos, aString.Length()) ), + mLength( NS_MIN(aLength, aString.Length()-mStartPos) ) + { + // nothing else to do here + } + + nsPromiseCSubstring( const const_iterator& aStart, const const_iterator& aEnd ) + : mString(aStart.string()) + { + const_iterator zeroPoint; + mString.BeginReading(zeroPoint); + mStartPos = Distance(zeroPoint, aStart); + mLength = Distance(aStart, aEnd); + } + + // nsPromiseCSubstring( const nsPromiseCSubstring& ); // auto-generated copy-constructor should be OK + // ~nsPromiseCSubstring(); // auto-generated destructor OK + + private: + // NOT TO BE IMPLEMENTED + void operator=( const nsPromiseCSubstring& ); // we're immutable, you can't assign into a substring + + public: + virtual PRUint32 Length() const; + virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); } + + private: + const string_type& mString; + PRUint32 mStartPos; + PRUint32 mLength; + }; + + + + + + + +inline +const nsPromiseCSubstring +Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseCSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseSubstring +Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength ) + { + return nsPromiseSubstring(aString, aStartPos, aSubstringLength); + } + +inline +const nsPromiseCSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseCSubstring(aStart, aEnd); + } + +inline +const nsPromiseSubstring +Substring( const nsReadingIterator& aStart, const nsReadingIterator& aEnd ) + { + return nsPromiseSubstring(aStart, aEnd); + } + + +#endif /* !defined(nsPromiseSubstring_h___) */ diff --git a/xpcom/string/public/nsReadableUtils.h b/xpcom/string/public/nsReadableUtils.h index 1e64cd951f7e..1057153ce72d 100755 --- a/xpcom/string/public/nsReadableUtils.h +++ b/xpcom/string/public/nsReadableUtils.h @@ -31,16 +31,16 @@ * According to our conventions, they should be |NS_xxx|. */ -#ifndef nsAWritableString_h___ -#include "nsAWritableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" #endif NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); -NS_COM void CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ); -NS_COM void CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ); +NS_COM void CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ); /** * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. @@ -53,7 +53,7 @@ NS_COM void CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableStrin * @param aSource a 16-bit wide string * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewCString( const nsAReadableString& aSource ); +NS_COM char* ToNewCString( const nsAString& aSource ); /** @@ -65,7 +65,7 @@ NS_COM char* ToNewCString( const nsAReadableString& aSource ); * @param aSource an 8-bit wide string * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewCString( const nsAReadableCString& aSource ); +NS_COM char* ToNewCString( const nsACString& aSource ); /** * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. @@ -78,7 +78,7 @@ NS_COM char* ToNewCString( const nsAReadableCString& aSource ); * @return a new |char| buffer you must free with |nsMemory::Free|. */ -NS_COM char* ToNewUTF8String( const nsAReadableString& aSource ); +NS_COM char* ToNewUTF8String( const nsAString& aSource ); /** @@ -90,7 +90,7 @@ NS_COM char* ToNewUTF8String( const nsAReadableString& aSource ); * @param aSource a 16-bit wide string * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. */ -NS_COM PRUnichar* ToNewUnicode( const nsAReadableString& aSource ); +NS_COM PRUnichar* ToNewUnicode( const nsAString& aSource ); /** @@ -104,7 +104,7 @@ NS_COM PRUnichar* ToNewUnicode( const nsAReadableString& aSource ); * @param aSource an 8-bit wide string * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. */ -NS_COM PRUnichar* ToNewUnicode( const nsAReadableCString& aSource ); +NS_COM PRUnichar* ToNewUnicode( const nsACString& aSource ); /** * Copies |aLength| 16-bit characters from the start of |aSource| to the @@ -118,7 +118,7 @@ NS_COM PRUnichar* ToNewUnicode( const nsAReadableCString& aSource ); * @param aLength the number of 16-bit characters to copy * @return pointer to destination buffer - identical to |aDest| */ -NS_COM PRUnichar* CopyUnicodeTo( const nsAReadableString& aSource, +NS_COM PRUnichar* CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ); @@ -137,7 +137,7 @@ NS_COM PRUnichar* CopyUnicodeTo( const nsAReadableString& aSource, */ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ); + nsAString& aDest ); /** * Appends 16-bit characters between iterators |aSrcStart| and @@ -151,25 +151,25 @@ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, */ NS_COM void AppendUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ); + nsAString& aDest ); /** * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). * * @param aString a 16-bit wide string to scan */ -NS_COM PRBool IsASCII( const nsAReadableString& aString ); +NS_COM PRBool IsASCII( const nsAString& aString ); /** * Converts case in place in the argument string. */ -NS_COM void ToUpperCase( nsAWritableString& ); -NS_COM void ToUpperCase( nsAWritableCString& ); +NS_COM void ToUpperCase( nsAString& ); +NS_COM void ToUpperCase( nsACString& ); -NS_COM void ToLowerCase( nsAWritableString& ); -NS_COM void ToLowerCase( nsAWritableCString& ); +NS_COM void ToLowerCase( nsAString& ); +NS_COM void ToLowerCase( nsACString& ); /** * Finds the leftmost occurance of |aPattern|, if any in the range |aSearchStart|..|aSearchEnd|. @@ -180,8 +180,8 @@ NS_COM void ToLowerCase( nsAWritableCString& ); * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. * If we need something faster; we can implement that later. */ -NS_COM PRBool FindInReadable( const nsAReadableString& aPattern, nsReadingIterator&, nsReadingIterator& ); -NS_COM PRBool FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool FindInReadable( const nsAString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool FindInReadable( const nsACString& aPattern, nsReadingIterator&, nsReadingIterator& ); /** @@ -192,8 +192,8 @@ NS_COM PRBool FindInReadable( const nsAReadableCString& aPattern, nsReadingItera * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. * If we need something faster; we can implement that later. */ -NS_COM PRBool RFindInReadable( const nsAReadableString& aPattern, nsReadingIterator&, nsReadingIterator& ); -NS_COM PRBool RFindInReadable( const nsAReadableCString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool RFindInReadable( const nsAString& aPattern, nsReadingIterator&, nsReadingIterator& ); +NS_COM PRBool RFindInReadable( const nsACString& aPattern, nsReadingIterator&, nsReadingIterator& ); /** * Finds the leftmost occurance of |aChar|, if any in the range @@ -209,9 +209,9 @@ NS_COM PRBool FindCharInReadable( char aChar, nsReadingIterator& aSearchSt /** * Finds the number of occurences of |aChar| in the string |aStr| */ -NS_COM PRUint32 CountCharInReadable( const nsAReadableString& aStr, +NS_COM PRUint32 CountCharInReadable( const nsAString& aStr, PRUnichar aChar ); -NS_COM PRUint32 CountCharInReadable( const nsAReadableCString& aStr, +NS_COM PRUint32 CountCharInReadable( const nsACString& aStr, char aChar ); #endif // !defined(nsReadableUtils_h___) diff --git a/xpcom/string/public/nsSharableString.h b/xpcom/string/public/nsSharableString.h new file mode 100644 index 000000000000..64a5f9e438da --- /dev/null +++ b/xpcom/string/public/nsSharableString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsCommonString.h --- a string implementation that shares its underlying storage */ + + +#ifndef nsCommonString_h___ +#define nsCommonString_h___ + +#ifndef nsAFlatString_h___ +#include "nsAFlatString.h" +#endif + +#ifndef nsBufferHandleUtils_h___ +#include "nsBufferHandleUtils.h" +#endif + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + /** + * Not yet ready for non-|const| access + */ + +class NS_COM nsCommonString + : public nsAFlatString + { + public: + typedef nsCommonString self_type; + typedef PRUnichar char_type; + typedef nsAString string_type; + + public: + nsCommonString() { } + nsCommonString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +class NS_COM nsCommonCString + : public nsAFlatCString + { + public: + typedef nsCommonCString self_type; + typedef char char_type; + typedef nsACString string_type; + + public: + nsCommonCString() { } + nsCommonCString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { } + nsCommonCString( const string_type& aReadable ) { assign(aReadable); } + + self_type& + operator=( const string_type& aReadable ) + { + assign(aReadable); + return *this; + } + + protected: + void assign( const string_type& ); + virtual const nsSharedBufferHandle* GetSharedBufferHandle() const; + + private: + nsAutoBufferHandle mBuffer; + }; + + +#endif /* !defined(nsCommonString_h___) */ diff --git a/xpcom/string/public/nsSharedBufferList.h b/xpcom/string/public/nsSharedBufferList.h index a97c2af1ec60..4fda3118cb82 100755 --- a/xpcom/string/public/nsSharedBufferList.h +++ b/xpcom/string/public/nsSharedBufferList.h @@ -35,9 +35,12 @@ // for |PRUnichar| #endif -#ifndef nsAReadableString_h___ -#include "nsAReadableString.h" - // for |nsReadingIterator| +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsLocalString_h___ +#include "nsLocalString.h" #endif #ifndef nsBufferHandleUtils_h___ @@ -180,12 +183,12 @@ class NS_COM nsSharedBufferList NewSingleAllocationBuffer( const PRUnichar* aData, PRUint32 aDataLength, PRUint32 aAdditionalCapacity = 1 ) { typedef Buffer* Buffer_ptr; - return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), NS_READABLE_CAST(PRUnichar, nsLiteralString(aData, aDataLength)), aAdditionalCapacity); + return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), nsLocalString(aData, aDataLength), aAdditionalCapacity); } static Buffer* - NewSingleAllocationBuffer( const nsAReadableString& aReadable, PRUint32 aAdditionalCapacity = 1 ) + NewSingleAllocationBuffer( const nsAString& aReadable, PRUint32 aAdditionalCapacity = 1 ) { typedef Buffer* Buffer_ptr; return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), aReadable, aAdditionalCapacity); diff --git a/xpcom/string/public/nsSlidingString.h b/xpcom/string/public/nsSlidingString.h index 079e7e2f1eb3..abe764b04135 100755 --- a/xpcom/string/public/nsSlidingString.h +++ b/xpcom/string/public/nsSlidingString.h @@ -25,8 +25,13 @@ #ifndef nsSlidingString_h___ #define nsSlidingString_h___ -#include "nsAReadableString.h" +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#ifndef nsSharedBufferList_h___ #include "nsSharedBufferList.h" +#endif /** @@ -69,7 +74,7 @@ class nsSlidingString; * a substring over a buffer list, this */ class NS_COM nsSlidingSubstring - : virtual public nsPromiseReadable + : virtual public nsAPromiseString { friend class nsSlidingString; @@ -90,14 +95,14 @@ class NS_COM nsSlidingSubstring nsSlidingSubstring( const nsSlidingSubstring& aString, const nsReadingIterator& aStart, const nsReadingIterator& aEnd ); nsSlidingSubstring( const nsSlidingString& ); nsSlidingSubstring( const nsSlidingString& aString, const nsReadingIterator& aStart, const nsReadingIterator& aEnd ); - explicit nsSlidingSubstring( const nsAReadableString& ); + explicit nsSlidingSubstring( const nsAString& ); // copy the supplied string into a new buffer ... there will be no modifying instance over this buffer list void Rebind( const nsSlidingSubstring& ); void Rebind( const nsSlidingSubstring&, const nsReadingIterator&, const nsReadingIterator& ); void Rebind( const nsSlidingString& ); void Rebind( const nsSlidingString&, const nsReadingIterator&, const nsReadingIterator& ); - void Rebind( const nsAReadableString& ); + void Rebind( const nsAString& ); ~nsSlidingSubstring(); @@ -106,6 +111,7 @@ class NS_COM nsSlidingSubstring protected: nsSlidingSubstring( nsSlidingSharedBufferList* aBufferList ); virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } private: // can't assign into me, I'm a read-only reference @@ -154,7 +160,7 @@ class NS_COM nsSlidingSubstring * */ class NS_COM nsSlidingString - : virtual public nsPromiseReadable, + : virtual public nsAPromiseString, private nsSlidingSubstring { friend class nsSlidingSubstring; @@ -176,8 +182,9 @@ class NS_COM nsSlidingString protected: virtual const PRUnichar* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual PRUnichar* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ) { return 0; } - void InsertReadable( const nsAReadableString&, const nsReadingIterator& ); // ...to implement |nsScannerString::UngetReadable| + void InsertReadable( const nsAString&, const nsReadingIterator& ); // ...to implement |nsScannerString::UngetReadable| private: diff --git a/xpcom/string/public/nsStringFragment.h b/xpcom/string/public/nsStringFragment.h new file mode 100644 index 000000000000..0a8238023e91 --- /dev/null +++ b/xpcom/string/public/nsStringFragment.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringFragment.h --- machinery that makes string iterators work */ + +#ifndef nsStringFragment_h___ +#define nsStringFragment_h___ + + + + /** + * An |nsFragmentRequest| is used to tell |GetReadableFragment| and + * |GetWritableFragment| what to do. + * + * @see GetReadableFragment + */ + +enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; + + + /** + * A |nsReadableFragment| provides |const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsReadableFragment| is the underlying machinery that lets + * |nsReadingIterator|s work. + * + * @see nsReadingIterator + */ + +template +struct nsReadableFragment + { + const CharT* mStart; + const CharT* mEnd; + const void* mFragmentIdentifier; + + nsReadableFragment() + : mStart(0), mEnd(0), mFragmentIdentifier(0) + { + // nothing else to do here + } + }; + + + /** + * A |nsWritableFragment| provides non-|const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsWritableFragment| is the underlying machinery that lets + * |nsWritingIterator|s work. + * + * @see nsWritingIterator + */ + +template +struct nsWritableFragment + { + CharT* mStart; + CharT* mEnd; + void* mFragmentIdentifier; + + nsWritableFragment() + : mStart(0), mEnd(0), mFragmentIdentifier(0) + { + // nothing else to do here + } + }; + +#endif /* !defined(nsStringFragment_h___) */ diff --git a/xpcom/string/public/nsStringFwd.h b/xpcom/string/public/nsStringFwd.h new file mode 100644 index 000000000000..b1caa033c51a --- /dev/null +++ b/xpcom/string/public/nsStringFwd.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringFwd.h --- forward declarations for string classes */ + +#ifndef nsStringFwd_h___ +#define nsStringFwd_h___ + + + /** + * @see nsAString.h + */ + +class nsAString; +class nsACString; + + + /** + * @see nsAPromiseString.h + */ + +class nsAPromiseString; +class nsAPromiseCString; + + + /** + * @see nsAFlatString.h + */ + +class nsAFlatString; +class nsAFlatCString; + + + /** + * @see nsLocalString.h + */ + +class nsLocalString; +class nsLocalCString; + +#endif /* !defined(nsStringFwd_h___) */ diff --git a/xpcom/string/public/nsStringIterator.h b/xpcom/string/public/nsStringIterator.h new file mode 100644 index 000000000000..2305e232dc4b --- /dev/null +++ b/xpcom/string/public/nsStringIterator.h @@ -0,0 +1,436 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsStringIterator_h___ +#define nsStringIterator_h___ + +#ifndef nsStringFragment_h___ +#include "nsStringFragment.h" +#endif + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif + +#ifndef nsAlgorithm_h___ +#include "nsAlgorithm.h" + // for |NS_MIN|, |NS_MAX|, and |NS_COUNT|... +#endif + + + + + + + /** + * + * @see nsReadableFragment + * @see nsAString + */ + +template +class nsReadingIterator +// : public bidirectional_iterator_tag + { + public: + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef const CharT* pointer; + typedef const CharT& reference; +// typedef bidirectional_iterator_tag iterator_category; + + private: + friend class nsAString; + friend class nsACString; + typedef typename nsStringTraits::abstract_string_type string_type; + + nsReadableFragment mFragment; + const CharT* mPosition; + const string_type* mOwningString; + + public: + nsReadingIterator() { } + // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK + // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward(); + inline void normalize_backward(); + + pointer + get() const + { + return mPosition; + } + + CharT + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + nsReadingIterator& + operator++() + { + ++mPosition; + normalize_forward(); + return *this; + } + + nsReadingIterator + operator++( int ) + { + nsReadingIterator result(*this); + ++mPosition; + normalize_forward(); + return result; + } + + nsReadingIterator& + operator--() + { + normalize_backward(); + --mPosition; + return *this; + } + + nsReadingIterator + operator--( int ) + { + nsReadingIterator result(*this); + normalize_backward(); + --mPosition; + return result; + } + + const nsReadableFragment& + fragment() const + { + return mFragment; + } + + const string_type& + string() const + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + difference_type + size_forward() const + { + return mFragment.mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mFragment.mStart; + } + + nsReadingIterator& + 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; + } + }; + +template +class nsWritingIterator +// : public nsReadingIterator + { + public: + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef CharT* pointer; + typedef CharT& reference; +// typedef bidirectional_iterator_tag iterator_category; + + private: + friend class nsAString; + friend class nsACString; + typedef typename nsStringTraits::abstract_string_type string_type; + + nsWritableFragment mFragment; + CharT* mPosition; + string_type* mOwningString; + + public: + nsWritingIterator() { } + // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK + // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward(); + inline void normalize_backward(); + + pointer + get() const + { + return mPosition; + } + + reference + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + nsWritingIterator& + operator++() + { + ++mPosition; + normalize_forward(); + return *this; + } + + nsWritingIterator + operator++( int ) + { + nsWritingIterator result(*this); + ++mPosition; + normalize_forward(); + return result; + } + + nsWritingIterator& + operator--() + { + normalize_backward(); + --mPosition; + return *this; + } + + nsWritingIterator + operator--( int ) + { + nsWritingIterator result(*this); + normalize_backward(); + --mPosition; + return result; + } + + const nsWritableFragment& + fragment() const + { + return mFragment; + } + + nsWritableFragment& + fragment() + { + return mFragment; + } + + const string_type& + string() const + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + string_type& + string() + { + NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)"); + return *mOwningString; + } + + difference_type + size_forward() const + { + return mFragment.mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mFragment.mStart; + } + + nsWritingIterator& + 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 writing 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 writing iterator beyond the end of a string"); + // perhaps I should |break| if |!one_hop|? + + mPosition += one_hop; + n -= one_hop; + } + + return *this; + } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); + + n = NS_MIN(n, PRUint32(size_forward())); + nsCharTraits::move(mPosition, s, n); + advance( difference_type(n) ); + return n; + } + }; + +template +inline +void +nsReadingIterator::normalize_forward() + { + while ( mPosition == mFragment.mEnd + && mOwningString->GetReadableFragment(mFragment, kNextFragment) ) + mPosition = mFragment.mStart; + } + +template +inline +void +nsReadingIterator::normalize_backward() + { + while ( mPosition == mFragment.mStart + && mOwningString->GetReadableFragment(mFragment, kPrevFragment) ) + mPosition = mFragment.mEnd; + } + +template +inline +PRBool +operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + + + // + // |nsWritingIterator|s + // + +template +inline +void +nsWritingIterator::normalize_forward() + { + while ( mPosition == mFragment.mEnd + && mOwningString->GetWritableFragment(mFragment, kNextFragment) ) + mPosition = mFragment.mStart; + } + +template +inline +void +nsWritingIterator::normalize_backward() + { + while ( mPosition == mFragment.mStart + && mOwningString->GetWritableFragment(mFragment, kPrevFragment) ) + mPosition = mFragment.mEnd; + } + +template +inline +PRBool +operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + +#endif /* !defined(nsStringIterator_h___) */ diff --git a/xpcom/string/public/nsStringIteratorUtils.h b/xpcom/string/public/nsStringIteratorUtils.h new file mode 100644 index 000000000000..0d74365c1eb0 --- /dev/null +++ b/xpcom/string/public/nsStringIteratorUtils.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#ifndef nsStringIteratorUtils_h___ +#define nsStringIteratorUtils_h___ + +template +inline +PRBool +SameFragment( const Iterator& lhs, const Iterator& rhs ) + { + return lhs.fragment().mStart == rhs.fragment().mStart; + } + +template class nsReadingIterator; + + // NOTE: need to break iterators out into their own file (as with many classes here), need + // these routines, but can't currently |#include "nsReadableUtils.h"|, this hack is bad + // but we need it to get OS2 building again. Fix by splitting things into different files. +NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); +NS_COM size_t Distance( const nsReadingIterator&, const nsReadingIterator& ); + + +#endif /* !defined(nsStringIteratorUtils_h___) */ diff --git a/xpcom/string/public/nsStringTraits.h b/xpcom/string/public/nsStringTraits.h new file mode 100644 index 000000000000..1f41b5b596b5 --- /dev/null +++ b/xpcom/string/public/nsStringTraits.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +/* nsStringTraits.h --- declares specialized ``traits'' classes which allow templatized functions and classes to select appropriate non-template types */ + +#ifndef nsStringTraits_h___ +#define nsStringTraits_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + + + + /** + * + */ + +template +struct nsStringTraits + { + typedef nsAString abstract_string_type; + typedef nsAPromiseString abstract_promise_type; + typedef nsAFlatString abstract_flat_type; + typedef const nsLocalString literal_string_type; + }; + +#if 0 + // for lame compilers, put these declarations into the general case + // so we only need to specialize for |char| +NS_SPECIALIZE_TEMPLATE +struct nsStringTraits + { + typedef nsAString abstract_string_type; + typedef nsAPromiseString abstract_promise_type; + typedef nsAFlatString abstract_flat_type; + typedef const nsLocalString literal_string_type; + }; +#endif + +NS_SPECIALIZE_TEMPLATE +struct nsStringTraits + { + typedef nsACString abstract_string_type; + typedef nsAPromiseCString abstract_promise_type; + typedef nsAFlatCString abstract_flat_type; + typedef const nsLocalCString literal_string_type; + }; + + +#endif /* !defined(nsStringTraits_h___) */ diff --git a/xpcom/string/src/Makefile.in b/xpcom/string/src/Makefile.in index fdec9c555597..8ca522cde25e 100644 --- a/xpcom/string/src/Makefile.in +++ b/xpcom/string/src/Makefile.in @@ -18,6 +18,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH = ../.. @@ -33,8 +34,16 @@ LIBRARY_NAME = string_s REQUIRES = xpcom CPPSRCS = \ + nsAFlatString.cpp \ + nsAString.cpp \ + nsCommonString.cpp \ nsFragmentedString.cpp \ + nsLocalString.cpp \ nsPrintfCString.cpp \ + nsPrivateSharableString.cpp \ + nsPromiseConcatenation.cpp \ + nsPromiseFlatString.cpp \ + nsPromiseSubstring.cpp \ nsReadableUtils.cpp \ nsSharedBufferList.cpp \ nsSlidingString.cpp \ diff --git a/xpcom/string/src/makefile.win b/xpcom/string/src/makefile.win index 4442c23ef74a..608ec516b6a5 100644 --- a/xpcom/string/src/makefile.win +++ b/xpcom/string/src/makefile.win @@ -19,6 +19,7 @@ # # Contributor(s): # Johnny Stenback (original author) +# Scott Collins # DEPTH=..\.. @@ -28,8 +29,16 @@ LIBRARY_NAME=string_s LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN CPP_OBJS = \ + .\$(OBJDIR)\nsAFlatString.obj \ + .\$(OBJDIR)\nsAString.obj \ + .\$(OBJDIR)\nsCommonString.obj \ .\$(OBJDIR)\nsFragmentedString.obj \ + .\$(OBJDIR)\nsLocalString.obj \ .\$(OBJDIR)\nsPrintfCString.obj \ + .\$(OBJDIR)\nsPrivateSharableString.obj \ + .\$(OBJDIR)\nsPromiseConcatenation.obj \ + .\$(OBJDIR)\nsPromiseFlatString.obj \ + .\$(OBJDIR)\nsPromiseSubstring.obj \ .\$(OBJDIR)\nsReadableUtils.obj \ .\$(OBJDIR)\nsSharedBufferList.obj \ .\$(OBJDIR)\nsSlidingString.obj \ diff --git a/xpcom/string/src/nsAFlatString.cpp b/xpcom/string/src/nsAFlatString.cpp new file mode 100644 index 000000000000..143f2c419f58 --- /dev/null +++ b/xpcom/string/src/nsAFlatString.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsAFlatString.h" + +const PRUnichar* +nsAFlatString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + const nsBufferHandle* buffer = GetBufferHandle(); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +PRUnichar* +nsAFlatString::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + nsBufferHandle* buffer = NS_CONST_CAST(nsBufferHandle*, GetBufferHandle()); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +const char* +nsAFlatCString::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + const nsBufferHandle* buffer = GetBufferHandle(); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +char* +nsAFlatCString::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + { + nsBufferHandle* buffer = NS_CONST_CAST(nsBufferHandle*, GetBufferHandle()); + NS_ASSERTION(buffer, "trouble: no buffer!"); + + aFragment.mEnd = buffer->DataEnd(); + return (aFragment.mStart = buffer->DataStart()) + aOffset; + } + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } diff --git a/xpcom/string/src/nsAString.cpp b/xpcom/string/src/nsAString.cpp new file mode 100644 index 000000000000..d08cc12796a7 --- /dev/null +++ b/xpcom/string/src/nsAString.cpp @@ -0,0 +1,921 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsAString.h" +#include "nsPromiseSubstring.h" +#include "nsLocalString.h" + + +NS_COM +int +Compare( const nsAString& lhs, const nsAString& rhs ) + { + typedef nsAString::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + size_type lLength = lhs.Length(); + size_type rLength = rhs.Length(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + nsAString::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + int result; + + for (;;) + { + size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); + + if ( lengthAvailable > lengthToCompare ) + lengthAvailable = lengthToCompare; + + // Note: |result| should be declared in this |if| expression, but some compilers don't like that + if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) + return result; + + if ( !(lengthToCompare -= lengthAvailable) ) + break; + + leftIter.advance( PRInt32(lengthAvailable) ); + rightIter.advance( PRInt32(lengthAvailable) ); + } + + if ( lLength < rLength ) + return -1; + else if ( rLength < lLength ) + return 1; + else + return 0; + } + +PRBool +nsAString::Equals( const char_type* rhs ) const + { + return Equals(nsLocalString(rhs)); + } + + + +nsAString::char_type +nsAString::First() const + { + NS_ASSERTION(Length()>0, "|First()| on an empty string"); + + const_iterator iter; + return *BeginReading(iter); + } + +nsAString::char_type +nsAString::Last() const + { + NS_ASSERTION(Length()>0, "|Last()| on an empty string"); + + const_iterator iter; + + if ( !IsEmpty() ) + { + EndReading(iter); + iter.advance(-1); + } + + return *iter; // Note: this has undefined results if |IsEmpty()| + } + +nsAString::size_type +nsAString::CountChar( char_type c ) const + { + /* + re-write this to use a counting sink + */ + + size_type result = 0; + size_type lengthToExamine = Length(); + + const_iterator iter; + for ( BeginReading(iter); ; ) + { + PRInt32 lengthToExamineInThisFragment = iter.size_forward(); + const char_type* fromBegin = iter.get(); + result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); + if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) + return result; + iter.advance(lengthToExamineInThisFragment); + } + // never reached; quiets warnings + return 0; + } + +nsAString::size_type +nsAString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + // If we're just assigning our entire self, give |aResult| the opportunity to share + if ( aStartPos == 0 && aLengthToCopy >= Length() ) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.Length(); + } + +nsAString::size_type +nsAString::Right( self_type& aResult, size_type aLengthToCopy ) const + { + size_type myLength = Length(); + aLengthToCopy = NS_MIN(myLength, aLengthToCopy); + return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); + } + +PRInt32 +nsAString::FindChar( char_type aChar, PRUint32 aOffset ) const + { + const_iterator iter, done_searching; + BeginReading(iter).advance( PRInt32(aOffset) ); + EndReading(done_searching); + + size_type lengthSearched = 0; + while ( iter != done_searching ) + { + PRInt32 fragmentLength = iter.size_forward(); + const char_type* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); + if ( charFoundAt ) + return lengthSearched + (charFoundAt-iter.get()) + aOffset; + + lengthSearched += fragmentLength; + iter.advance(fragmentLength); + } + + return -1; + } + + + // + // |Assign()| + // + +void +nsAString::AssignFromReadable( const self_type& rhs ) + { + if ( this != &rhs ) + do_AssignFromReadable(rhs); + // else, self-assign is a no-op + } + +void +nsAString::AssignFromPromise( const self_type& aReadable ) + /* + ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. + E.g., + + ... writable& w ... + ... readable& r ... + + w = r + w; + + In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before + anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents + of |r| before being retrieved to be appended. + + We could have a really tricky solution where we tell the promise to resolve _just_ the data promised + by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., + in the case above, |Insert| could have special behavior with significantly better performance. Since + it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the + entire promise. If we measure and this turns out to show up on performance radar, we then have the + option to fix either the callers or this mechanism. + */ + { + if ( !aReadable.Promises(*this) ) + do_AssignFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + // Note: not exception safe. We need something to manage temporary buffers like this + + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AssignFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_AssignFromReadable( const self_type& aReadable ) + { + SetLength(0); + SetLength(aReadable.Length()); + // first setting the length to |0| avoids copying characters only to be overwritten later + // in the case where the implementation decides to re-allocate + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); + } + +void +nsAString::do_AssignFromElementPtr( const char_type* aPtr ) + { + do_AssignFromReadable(nsLocalString(aPtr)); + } + +void +nsAString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength ) + { + do_AssignFromReadable(nsLocalString(aPtr, aLength)); + } + +void +nsAString::do_AssignFromElement( char_type aChar ) + { + do_AssignFromReadable(nsLocalString(&aChar, 1)); + } + + + + // + // |Append()| + // + +void +nsAString::AppendFromReadable( const self_type& aReadable ) + { + if ( this != &aReadable ) + do_AppendFromReadable(aReadable); + else + AppendFromPromise(aReadable); + } + +void +nsAString::AppendFromPromise( const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_AppendFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AppendFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_AppendFromReadable( const self_type& aReadable ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); + } + +void +nsAString::do_AppendFromElementPtr( const char_type* aChar ) + { + do_AppendFromReadable(nsLocalString(aChar)); + } + +void +nsAString::do_AppendFromElementPtrLength( const char_type* aChar, size_type aLength ) + { + do_AppendFromReadable(nsLocalString(aChar, aLength)); + } + +void +nsAString::do_AppendFromElement( char_type aChar ) + { + do_AppendFromReadable(nsLocalString(&aChar, 1)); + } + + + + // + // |Insert()| + // + +void +nsAString::InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + if ( this != &aReadable ) + do_InsertFromReadable(aReadable, atPosition); + else + InsertFromPromise(aReadable, atPosition); + } + +void +nsAString::InsertFromPromise( const self_type& aReadable, index_type atPosition ) + { + if ( !aReadable.Promises(*this) ) + do_InsertFromReadable(aReadable, atPosition); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_InsertFromElementPtrLength(buffer, atPosition, length); + delete buffer; + } + // else assert + } + } + +void +nsAString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( atPosition < oldLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); + else + atPosition = oldLength; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); + } + +void +nsAString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition ) + { + do_InsertFromReadable(nsLocalString(aPtr), atPosition); + } + +void +nsAString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength ) + { + do_InsertFromReadable(nsLocalString(aPtr, aLength), atPosition); + } + +void +nsAString::do_InsertFromElement( char_type aChar, index_type atPosition ) + { + do_InsertFromReadable(nsLocalString(&aChar, 1), atPosition); + } + + + + // + // |Cut()| + // + +void +nsAString::Cut( index_type cutStart, size_type cutLength ) + { + size_type myLength = this->Length(); + cutLength = NS_MIN(cutLength, myLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutEnd < myLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + SetLength(myLength-cutLength); + } + + + + // + // |Replace()| + // + +void +nsAString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + if ( this != &aReplacement ) + do_ReplaceFromReadable(cutStart, cutLength, aReplacement); + else + ReplaceFromPromise(cutStart, cutLength, aReplacement); + } + +void +nsAString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_ReplaceFromReadable(cutStart, cutLength, aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_ReplaceFromReadable(cutStart, cutLength, nsLocalString(buffer, length)); + delete buffer; + } + // else assert? + } + } + +void +nsAString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + size_type oldLength = this->Length(); + + cutStart = NS_MIN(cutStart, oldLength); + cutLength = NS_MIN(cutLength, oldLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + size_type replacementLength = aReplacement.Length(); + index_type replacementEnd = cutStart + replacementLength; + + size_type newLength = oldLength - cutLength + replacementLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutLength > replacementLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + SetLength(newLength); + if ( cutLength < replacementLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + + copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + } + + + + +NS_COM +int +Compare( const nsACString& lhs, const nsACString& rhs ) + { + typedef nsACString::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + size_type lLength = lhs.Length(); + size_type rLength = rhs.Length(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + nsACString::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + int result; + + for (;;) + { + size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) ); + + if ( lengthAvailable > lengthToCompare ) + lengthAvailable = lengthToCompare; + + // Note: |result| should be declared in this |if| expression, but some compilers don't like that + if ( (result = nsCharTraits::compare(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 ) + return result; + + if ( !(lengthToCompare -= lengthAvailable) ) + break; + + leftIter.advance( PRInt32(lengthAvailable) ); + rightIter.advance( PRInt32(lengthAvailable) ); + } + + if ( lLength < rLength ) + return -1; + else if ( rLength < lLength ) + return 1; + else + return 0; + } + +PRBool +nsACString::Equals( const char_type* rhs ) const + { + return Equals(nsLocalCString(rhs)); + } + +nsACString::char_type +nsACString::First() const + { + NS_ASSERTION(Length()>0, "|First()| on an empty string"); + + const_iterator iter; + return *BeginReading(iter); + } + +nsACString::char_type +nsACString::Last() const + { + NS_ASSERTION(Length()>0, "|Last()| on an empty string"); + + const_iterator iter; + + if ( !IsEmpty() ) + { + EndReading(iter); + iter.advance(-1); + } + + return *iter; // Note: this has undefined results if |IsEmpty()| + } + +nsACString::size_type +nsACString::CountChar( char_type c ) const + { + /* + re-write this to use a counting sink + */ + + size_type result = 0; + size_type lengthToExamine = Length(); + + const_iterator iter; + for ( BeginReading(iter); ; ) + { + PRInt32 lengthToExamineInThisFragment = iter.size_forward(); + const char_type* fromBegin = iter.get(); + result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c)); + if ( !(lengthToExamine -= lengthToExamineInThisFragment) ) + return result; + iter.advance(lengthToExamineInThisFragment); + } + // never reached; quiets warnings + return 0; + } + +nsACString::size_type +nsACString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + // If we're just assigning our entire self, give |aResult| the opportunity to share + if ( aStartPos == 0 && aLengthToCopy >= Length() ) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.Length(); + } + +nsACString::size_type +nsACString::Right( self_type& aResult, size_type aLengthToCopy ) const + { + size_type myLength = Length(); + aLengthToCopy = NS_MIN(myLength, aLengthToCopy); + return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy); + } + +PRInt32 +nsACString::FindChar( char_type aChar, PRUint32 aOffset ) const + { + const_iterator iter, done_searching; + BeginReading(iter).advance( PRInt32(aOffset) ); + EndReading(done_searching); + + size_type lengthSearched = 0; + while ( iter != done_searching ) + { + PRInt32 fragmentLength = iter.size_forward(); + const char_type* charFoundAt = nsCharTraits::find(iter.get(), fragmentLength, aChar); + if ( charFoundAt ) + return lengthSearched + (charFoundAt-iter.get()) + aOffset; + + lengthSearched += fragmentLength; + iter.advance(fragmentLength); + } + + return -1; + } + + + // + // |Assign()| + // + +void +nsACString::AssignFromReadable( const self_type& rhs ) + { + if ( this != &rhs ) + do_AssignFromReadable(rhs); + // else, self-assign is a no-op + } + +void +nsACString::AssignFromPromise( const self_type& aReadable ) + /* + ...this function is only called when a promise that somehow references |this| is assigned _into_ |this|. + E.g., + + ... writable& w ... + ... readable& r ... + + w = r + w; + + In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before + anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents + of |r| before being retrieved to be appended. + + We could have a really tricky solution where we tell the promise to resolve _just_ the data promised + by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g., + in the case above, |Insert| could have special behavior with significantly better performance. Since + it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the + entire promise. If we measure and this turns out to show up on performance radar, we then have the + option to fix either the callers or this mechanism. + */ + { + if ( !aReadable.Promises(*this) ) + do_AssignFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + // Note: not exception safe. We need something to manage temporary buffers like this + + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AssignFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_AssignFromReadable( const self_type& aReadable ) + { + SetLength(0); + SetLength(aReadable.Length()); + // first setting the length to |0| avoids copying characters only to be overwritten later + // in the case where the implementation decides to re-allocate + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin)); + } + +void +nsACString::do_AssignFromElementPtr( const char_type* aPtr ) + { + do_AssignFromReadable(nsLocalCString(aPtr)); + } + +void +nsACString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength ) + { + do_AssignFromReadable(nsLocalCString(aPtr, aLength)); + } + +void +nsACString::do_AssignFromElement( char_type aChar ) + { + do_AssignFromReadable(nsLocalCString(&aChar, 1)); + } + + + + // + // |Append()| + // + +void +nsACString::AppendFromReadable( const self_type& aReadable ) + { + if ( this != &aReadable ) + do_AppendFromReadable(aReadable); + else + AppendFromPromise(aReadable); + } + +void +nsACString::AppendFromPromise( const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_AppendFromReadable(aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_AppendFromElementPtrLength(buffer, length); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_AppendFromReadable( const self_type& aReadable ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) ); + } + +void +nsACString::do_AppendFromElementPtr( const char_type* aChar ) + { + do_AppendFromReadable(nsLocalCString(aChar)); + } + +void +nsACString::do_AppendFromElementPtrLength( const char_type* aChar, size_type aLength ) + { + do_AppendFromReadable(nsLocalCString(aChar, aLength)); + } + +void +nsACString::do_AppendFromElement( char_type aChar ) + { + do_AppendFromReadable(nsLocalCString(&aChar, 1)); + } + + + + // + // |Insert()| + // + +void +nsACString::InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + if ( this != &aReadable ) + do_InsertFromReadable(aReadable, atPosition); + else + InsertFromPromise(aReadable, atPosition); + } + +void +nsACString::InsertFromPromise( const self_type& aReadable, index_type atPosition ) + { + if ( !aReadable.Promises(*this) ) + do_InsertFromReadable(aReadable, atPosition); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_InsertFromElementPtrLength(buffer, atPosition, length); + delete buffer; + } + // else assert + } + } + +void +nsACString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition ) + { + size_type oldLength = this->Length(); + SetLength(oldLength + aReadable.Length()); + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( atPosition < oldLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin)); + else + atPosition = oldLength; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition))); + } + +void +nsACString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition ) + { + do_InsertFromReadable(nsLocalCString(aPtr), atPosition); + } + +void +nsACString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength ) + { + do_InsertFromReadable(nsLocalCString(aPtr, aLength), atPosition); + } + +void +nsACString::do_InsertFromElement( char_type aChar, index_type atPosition ) + { + do_InsertFromReadable(nsLocalCString(&aChar, 1), atPosition); + } + + + + // + // |Cut()| + // + +void +nsACString::Cut( index_type cutStart, size_type cutLength ) + { + size_type myLength = this->Length(); + cutLength = NS_MIN(cutLength, myLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutEnd < myLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + SetLength(myLength-cutLength); + } + + + + // + // |Replace()| + // + +void +nsACString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + if ( this != &aReplacement ) + do_ReplaceFromReadable(cutStart, cutLength, aReplacement); + else + ReplaceFromPromise(cutStart, cutLength, aReplacement); + } + +void +nsACString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable ) + { + if ( !aReadable.Promises(*this) ) + do_ReplaceFromReadable(cutStart, cutLength, aReadable); + else + { + size_type length = aReadable.Length(); + char_type* buffer = new char_type[length]; + if ( buffer ) + { + const_iterator fromBegin, fromEnd; + char_type* toBegin = buffer; + copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin); + do_ReplaceFromReadable(cutStart, cutLength, nsLocalCString(buffer, length)); + delete buffer; + } + // else assert? + } + } + +void +nsACString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement ) + { + size_type oldLength = this->Length(); + + cutStart = NS_MIN(cutStart, oldLength); + cutLength = NS_MIN(cutLength, oldLength-cutStart); + index_type cutEnd = cutStart + cutLength; + + size_type replacementLength = aReplacement.Length(); + index_type replacementEnd = cutStart + replacementLength; + + size_type newLength = oldLength - cutLength + replacementLength; + + const_iterator fromBegin, fromEnd; + iterator toBegin; + if ( cutLength > replacementLength ) + copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + SetLength(newLength); + if ( cutLength < replacementLength ) + copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd))); + + copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart))); + } + diff --git a/xpcom/string/src/nsCommonString.cpp b/xpcom/string/src/nsCommonString.cpp new file mode 100644 index 000000000000..fefbba159171 --- /dev/null +++ b/xpcom/string/src/nsCommonString.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsCommonString.h" +// #include "nsBufferHandleUtils.h" + +void +nsCommonString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + +void +nsCommonCString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonCString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + diff --git a/xpcom/string/src/nsDependentConcatenation.cpp b/xpcom/string/src/nsDependentConcatenation.cpp new file mode 100644 index 000000000000..ed1bd50b6c7a --- /dev/null +++ b/xpcom/string/src/nsDependentConcatenation.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsAString.h" + // remember, no one should include "nsPromiseConcatenation.h" themselves + // one always gets it through "nsAString.h" + +PRUint32 +nsPromiseConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const PRUnichar* +nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } + + +PRUint32 +nsPromiseCConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseCConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseCConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const char* +nsPromiseCConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } diff --git a/xpcom/string/src/nsDependentString.cpp b/xpcom/string/src/nsDependentString.cpp new file mode 100644 index 000000000000..5c046c264ffa --- /dev/null +++ b/xpcom/string/src/nsDependentString.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsLocalString.h" + diff --git a/xpcom/string/src/nsDependentSubstring.cpp b/xpcom/string/src/nsDependentSubstring.cpp new file mode 100644 index 000000000000..563cd3b48d4a --- /dev/null +++ b/xpcom/string/src/nsDependentSubstring.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseSubstring.h" + +PRUint32 +nsPromiseSubstring::Length() const + { + return mLength; + } + +const PRUnichar* +nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const PRUnichar* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } + + + + +PRUint32 +nsPromiseCSubstring::Length() const + { + return mLength; + } + +const char* +nsPromiseCSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const char* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } diff --git a/xpcom/string/src/nsLocalString.cpp b/xpcom/string/src/nsLocalString.cpp new file mode 100644 index 000000000000..5c046c264ffa --- /dev/null +++ b/xpcom/string/src/nsLocalString.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsLocalString.h" + diff --git a/xpcom/string/src/nsPrivateSharableString.cpp b/xpcom/string/src/nsPrivateSharableString.cpp new file mode 100644 index 000000000000..70fcbaa4e93e --- /dev/null +++ b/xpcom/string/src/nsPrivateSharableString.cpp @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPrivateSharableString.h" + +//-------1---------2---------3---------4---------5---------6---------7---------8 + + +const nsSharedBufferHandle* +nsPrivateSharableString::GetSharedBufferHandle() const + { + return 0; + } + +const nsBufferHandle* +nsPrivateSharableString::GetFlatBufferHandle() const + { + return GetSharedBufferHandle(); + } + +const nsBufferHandle* +nsPrivateSharableString::GetBufferHandle() const + { + return GetSharedBufferHandle(); + } + +PRUint32 +nsPrivateSharableString::GetImplementationFlags() const + { + PRUint32 flags = 0; + const nsSharedBufferHandle* handle = GetSharedBufferHandle(); + if ( handle ) + flags = handle->GetImplementationFlags(); + return flags; + } + + + +const nsSharedBufferHandle* +nsPrivateSharableCString::GetSharedBufferHandle() const + { + return 0; + } + +const nsBufferHandle* +nsPrivateSharableCString::GetFlatBufferHandle() const + { + return GetSharedBufferHandle(); + } + +const nsBufferHandle* +nsPrivateSharableCString::GetBufferHandle() const + { + return GetSharedBufferHandle(); + } + +PRUint32 +nsPrivateSharableCString::GetImplementationFlags() const + { + PRUint32 flags = 0; + const nsSharedBufferHandle* handle = GetSharedBufferHandle(); + if ( handle ) + flags = handle->GetImplementationFlags(); + return flags; + } diff --git a/xpcom/string/src/nsPromiseConcatenation.cpp b/xpcom/string/src/nsPromiseConcatenation.cpp new file mode 100644 index 000000000000..ed1bd50b6c7a --- /dev/null +++ b/xpcom/string/src/nsPromiseConcatenation.cpp @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsAString.h" + // remember, no one should include "nsPromiseConcatenation.h" themselves + // one always gets it through "nsAString.h" + +PRUint32 +nsPromiseConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const PRUnichar* +nsPromiseConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } + + +PRUint32 +nsPromiseCConcatenation::Length() const + { + return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length(); + } + +PRBool +nsPromiseCConcatenation::Promises( const string_type& aString ) const + { + return mStrings[0]->Promises(aString) || mStrings[1]->Promises(aString); + } + +#if 0 +PRBool +nsPromiseCConcatenation::PromisesExactly( const string_type& aString ) const + { + // Not really like this, test for the empty string, etc + return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString; + } +#endif + +const char* +nsPromiseCConcatenation::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + int whichString; + + // based on the request, pick which string we will forward the |GetReadableFragment()| call into + + switch ( aRequest ) + { + case kPrevFragment: + case kNextFragment: + whichString = GetCurrentStringFromFragment(aFragment); + break; + + case kFirstFragment: + whichString = SetLeftStringInFragment(aFragment); + break; + + case kLastFragment: + whichString = SetRightStringInFragment(aFragment); + break; + + case kFragmentAt: + PRUint32 leftLength = mStrings[kLeftString]->Length(); + if ( aPosition < leftLength ) + whichString = SetLeftStringInFragment(aFragment); + else + { + whichString = SetRightStringInFragment(aFragment); + aPosition -= leftLength; + } + break; + + } + + const char_type* result; + PRBool done; + do + { + done = PR_TRUE; + result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition); + + if ( !result ) + { + done = PR_FALSE; + if ( aRequest == kNextFragment && whichString == kLeftString ) + { + aRequest = kFirstFragment; + whichString = SetRightStringInFragment(aFragment); + } + else if ( aRequest == kPrevFragment && whichString == kRightString ) + { + aRequest = kLastFragment; + whichString = SetLeftStringInFragment(aFragment); + } + else + done = PR_TRUE; + } + } + while ( !done ); + return result; + } diff --git a/xpcom/string/src/nsPromiseFlatString.cpp b/xpcom/string/src/nsPromiseFlatString.cpp new file mode 100644 index 000000000000..4dbc38862a0c --- /dev/null +++ b/xpcom/string/src/nsPromiseFlatString.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseFlatString.h" + + +nsPromiseFlatString::nsPromiseFlatString( const nsPromiseFlatString& aOther ) + : mFlattenedString(aOther.mFlattenedString) + { + if ( aOther.mPromisedString == &aOther.mFlattenedString ) + mPromisedString = &mFlattenedString; + else + mPromisedString = aOther.mPromisedString; + } + +nsPromiseFlatString::nsPromiseFlatString( const nsAString& aString ) + { + if ( aString.GetFlatBufferHandle() ) + mPromisedString = NS_STATIC_CAST(const nsAFlatString*, &aString); + else + { + mFlattenedString = aString; // flatten |aString| + mPromisedString = &mFlattenedString; + } + } + +const PRUnichar* +nsPromiseFlatString::get() const + { + return mPromisedString->get(); + } + +const nsBufferHandle* +nsPromiseFlatString::GetFlatBufferHandle() const + { + return mPromisedString->GetFlatBufferHandle(); + } + +const nsBufferHandle* +nsPromiseFlatString::GetBufferHandle() const + { + return mPromisedString->GetBufferHandle(); + } + +const nsSharedBufferHandle* +nsPromiseFlatString::GetSharedBufferHandle() const + { + return mPromisedString->GetSharedBufferHandle(); + } + + + + +nsPromiseFlatCString::nsPromiseFlatCString( const nsPromiseFlatCString& aOther ) + : mFlattenedString(aOther.mFlattenedString) + { + if ( aOther.mPromisedString == &aOther.mFlattenedString ) + mPromisedString = &mFlattenedString; + else + mPromisedString = aOther.mPromisedString; + } + +nsPromiseFlatCString::nsPromiseFlatCString( const nsACString& aString ) + { + if ( aString.GetFlatBufferHandle() ) + mPromisedString = NS_STATIC_CAST(const nsAFlatCString*, &aString); + else + { + mFlattenedString = aString; // flatten |aString| + mPromisedString = &mFlattenedString; + } + } + +const char* +nsPromiseFlatCString::get() const + { + return mPromisedString->get(); + } + +const nsBufferHandle* +nsPromiseFlatCString::GetFlatBufferHandle() const + { + return mPromisedString->GetFlatBufferHandle(); + } + +const nsBufferHandle* +nsPromiseFlatCString::GetBufferHandle() const + { + return mPromisedString->GetBufferHandle(); + } + +const nsSharedBufferHandle* +nsPromiseFlatCString::GetSharedBufferHandle() const + { + return mPromisedString->GetSharedBufferHandle(); + } diff --git a/xpcom/string/src/nsPromiseSubstring.cpp b/xpcom/string/src/nsPromiseSubstring.cpp new file mode 100644 index 000000000000..563cd3b48d4a --- /dev/null +++ b/xpcom/string/src/nsPromiseSubstring.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +#include "nsPromiseSubstring.h" + +PRUint32 +nsPromiseSubstring::Length() const + { + return mLength; + } + +const PRUnichar* +nsPromiseSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const PRUnichar* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } + + + + +PRUint32 +nsPromiseCSubstring::Length() const + { + return mLength; + } + +const char* +nsPromiseCSubstring::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const + { + // Offset any request for a specific position (First, Last, At) by our + // substrings startpos within the owning string + + if ( aRequest == kFirstFragment ) + { + aPosition = mStartPos; + aRequest = kFragmentAt; + } + else if ( aRequest == kLastFragment ) + { + aPosition = mStartPos + mLength; + aRequest = kFragmentAt; + } + else if ( aRequest == kFragmentAt ) + aPosition += mStartPos; + + // requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing + + const char* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition); + + // If |GetReadableFragment| returns |0|, then we are off the string, the contents of the + // fragment are garbage. + + // Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null + if ( position_ptr ) + { + // if there's more physical data in the returned fragment than I logically have left... + size_t logical_size_backward = aPosition - mStartPos; + if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward ) + aFragment.mStart = position_ptr - logical_size_backward; + + size_t logical_size_forward = mLength - logical_size_backward; + if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward ) + aFragment.mEnd = position_ptr + logical_size_forward; + } + + return position_ptr; + } diff --git a/xpcom/string/src/nsReadableUtils.cpp b/xpcom/string/src/nsReadableUtils.cpp index 19f12776d4a4..94823b2ad8e1 100755 --- a/xpcom/string/src/nsReadableUtils.cpp +++ b/xpcom/string/src/nsReadableUtils.cpp @@ -26,6 +26,9 @@ #include "nsString.h" #include "nsCRT.h" +#ifndef nsStringTraits_h___ +#include "nsStringTraits.h" +#endif /** * this allocator definition, and the global functions to access it need to move @@ -142,7 +145,7 @@ class LossyConvertEncoding NS_COM void -CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ) +CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ) { // right now, this won't work on multi-fragment destinations aDest.SetLength(aSource.Length()); @@ -157,7 +160,7 @@ CopyUCS2toASCII( const nsAReadableString& aSource, nsAWritableCString& aDest ) NS_COM void -CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ) +CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ) { // right now, this won't work on multi-fragment destinations aDest.SetLength(aSource.Length()); @@ -178,10 +181,10 @@ CopyASCIItoUCS2( const nsAReadableCString& aSource, nsAWritableString& aDest ) * @return a new buffer (of the type specified by the second parameter) which you must free with |nsMemory::Free|. * */ -template +template inline ToCharT* -AllocateStringCopy( const basic_nsAReadableString& aSource, ToCharT* ) +AllocateStringCopy( const FromStringT& aSource, ToCharT* ) { return NS_STATIC_CAST(ToCharT*, nsMemory::Alloc((aSource.Length()+1) * sizeof(ToCharT))); } @@ -189,7 +192,7 @@ AllocateStringCopy( const basic_nsAReadableString& aSource, ToCharT* NS_COM char* -ToNewCString( const nsAReadableString& aSource ) +ToNewCString( const nsAString& aSource ) { char* result = AllocateStringCopy(aSource, (char*)0); @@ -201,7 +204,7 @@ ToNewCString( const nsAReadableString& aSource ) NS_COM char* -ToNewUTF8String( const nsAReadableString& aSource ) +ToNewUTF8String( const nsAString& aSource ) { NS_ConvertUCS2toUTF8 temp(aSource); @@ -225,7 +228,7 @@ ToNewUTF8String( const nsAReadableString& aSource ) NS_COM char* -ToNewCString( const nsAReadableCString& aSource ) +ToNewCString( const nsACString& aSource ) { // no conversion needed, just allocate a buffer of the correct length and copy into it @@ -239,7 +242,7 @@ ToNewCString( const nsAReadableCString& aSource ) NS_COM PRUnichar* -ToNewUnicode( const nsAReadableString& aSource ) +ToNewUnicode( const nsAString& aSource ) { // no conversion needed, just allocate a buffer of the correct length and copy into it @@ -253,7 +256,7 @@ ToNewUnicode( const nsAReadableString& aSource ) NS_COM PRUnichar* -ToNewUnicode( const nsAReadableCString& aSource ) +ToNewUnicode( const nsACString& aSource ) { PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); @@ -265,7 +268,7 @@ ToNewUnicode( const nsAReadableCString& aSource ) NS_COM PRUnichar* -CopyUnicodeTo( const nsAReadableString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) +CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) { nsReadingIterator fromBegin, fromEnd; PRUnichar* toBegin = aDest; @@ -277,7 +280,7 @@ NS_COM void CopyUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ) + nsAString& aDest ) { nsWritingIterator writer; aDest.SetLength(Distance(aSrcStart, aSrcEnd)); @@ -291,7 +294,7 @@ NS_COM void AppendUnicodeTo( const nsReadingIterator& aSrcStart, const nsReadingIterator& aSrcEnd, - nsAWritableString& aDest ) + nsAString& aDest ) { nsWritingIterator writer; PRUint32 oldLength = aDest.Length(); @@ -304,7 +307,7 @@ AppendUnicodeTo( const nsReadingIterator& aSrcStart, NS_COM PRBool -IsASCII( const nsAReadableString& aString ) +IsASCII( const nsAString& aString ) { static const PRUnichar NOT_ASCII = PRUnichar(~0x007F); @@ -354,18 +357,18 @@ class ConvertToUpperCase NS_COM void -ToUpperCase( nsAWritableString& aString ) +ToUpperCase( nsAString& aString ) { - nsAWritableString::iterator fromBegin, fromEnd; + nsAString::iterator fromBegin, fromEnd; ConvertToUpperCase converter; copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); } NS_COM void -ToUpperCase( nsAWritableCString& aCString ) +ToUpperCase( nsACString& aCString ) { - nsAWritableCString::iterator fromBegin, fromEnd; + nsACString::iterator fromBegin, fromEnd; ConvertToUpperCase converter; copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); } @@ -391,18 +394,18 @@ class ConvertToLowerCase NS_COM void -ToLowerCase( nsAWritableString& aString ) +ToLowerCase( nsAString& aString ) { - nsAWritableString::iterator fromBegin, fromEnd; + nsAString::iterator fromBegin, fromEnd; ConvertToLowerCase converter; copy_string(aString.BeginWriting(fromBegin), aString.EndWriting(fromEnd), converter); } NS_COM void -ToLowerCase( nsAWritableCString& aCString ) +ToLowerCase( nsACString& aCString ) { - nsAWritableCString::iterator fromBegin, fromEnd; + nsACString::iterator fromBegin, fromEnd; ConvertToLowerCase converter; copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); } @@ -411,7 +414,7 @@ ToLowerCase( nsAWritableCString& aCString ) template inline // probably wishful thinking PRBool -FindInReadable_Impl( const basic_nsAReadableString& aPattern, +FindInReadable_Impl( const typename nsStringTraits::abstract_string_type& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { @@ -479,14 +482,14 @@ FindInReadable_Impl( const basic_nsAReadableString& aPattern, NS_COM PRBool -FindInReadable( const nsAReadableString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +FindInReadable( const nsAString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } NS_COM PRBool -FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +FindInReadable( const nsACString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } @@ -499,7 +502,7 @@ FindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSe template inline // probably wishful thinking PRBool -RFindInReadable_Impl( const basic_nsAReadableString& aPattern, +RFindInReadable_Impl( const typename nsStringTraits::abstract_string_type& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { @@ -535,14 +538,14 @@ RFindInReadable_Impl( const basic_nsAReadableString& aPattern, NS_COM PRBool -RFindInReadable( const nsAReadableString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +RFindInReadable( const nsAString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } NS_COM PRBool -RFindInReadable( const nsAReadableCString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) +RFindInReadable( const nsACString& aPattern, nsReadingIterator& aSearchStart, nsReadingIterator& aSearchEnd ) { return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd); } @@ -593,7 +596,7 @@ FindCharInReadable( char aChar, nsReadingIterator& aSearchStart, const nsR template PRUint32 -CountCharInReadable_Impl( const basic_nsAReadableString& aStr, +CountCharInReadable_Impl( const typename nsStringTraits::abstract_string_type& aStr, CharT aChar ) { PRUint32 count = 0; @@ -614,7 +617,7 @@ CountCharInReadable_Impl( const basic_nsAReadableString& aStr, NS_COM PRUint32 -CountCharInReadable( const nsAReadableString& aStr, +CountCharInReadable( const nsAString& aStr, PRUnichar aChar ) { return CountCharInReadable_Impl(aStr, aChar); @@ -622,7 +625,7 @@ CountCharInReadable( const nsAReadableString& aStr, NS_COM PRUint32 -CountCharInReadable( const nsAReadableCString& aStr, +CountCharInReadable( const nsACString& aStr, char aChar ) { return CountCharInReadable_Impl(aStr, aChar); diff --git a/xpcom/string/src/nsSharableString.cpp b/xpcom/string/src/nsSharableString.cpp new file mode 100644 index 000000000000..fefbba159171 --- /dev/null +++ b/xpcom/string/src/nsSharableString.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is Netscape + * Communications. Portions created by Netscape Communications are + * Copyright (C) 2001 by Netscape Communications. All + * Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + */ + +//-------1---------2---------3---------4---------5---------6---------7---------8 + +#include "nsCommonString.h" +// #include "nsBufferHandleUtils.h" + +void +nsCommonString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + +void +nsCommonCString::assign( const string_type& aReadable ) + { + const nsSharedBufferHandle* handle = aReadable.GetSharedBufferHandle(); + if ( !handle ) + handle = NS_AllocateContiguousHandleWithData(handle, aReadable, 1); + mBuffer = handle; + } + +const nsSharedBufferHandle* +nsCommonCString::GetSharedBufferHandle() const + { + return mBuffer.get(); + } + diff --git a/xpcom/string/src/nsSlidingString.cpp b/xpcom/string/src/nsSlidingString.cpp index f574779c281b..51a5842581d7 100755 --- a/xpcom/string/src/nsSlidingString.cpp +++ b/xpcom/string/src/nsSlidingString.cpp @@ -99,7 +99,7 @@ nsSlidingSubstring::nsSlidingSubstring( nsSlidingSharedBufferList* aBufferList ) typedef const nsSharedBufferList::Buffer* Buffer_ptr; static nsSharedBufferList::Buffer* -AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAReadableString& aDataSource ) +AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAString& aDataSource ) { typedef const PRUnichar* PRUnichar_ptr; @@ -131,7 +131,7 @@ AllocateContiguousHandleWithData( Buffer_ptr aDummyHandlePtr, const nsAReadableS return result; } -nsSlidingSubstring::nsSlidingSubstring( const nsAReadableString& aSourceString ) +nsSlidingSubstring::nsSlidingSubstring( const nsAString& aSourceString ) : mBufferList(new nsSlidingSharedBufferList(AllocateContiguousHandleWithData(Buffer_ptr(0), aSourceString))) { init_range_from_buffer_list(); @@ -189,7 +189,7 @@ nsSlidingSubstring::Rebind( const nsSlidingString& aString, const nsReadingItera } void -nsSlidingSubstring::Rebind( const nsAReadableString& aSourceString ) +nsSlidingSubstring::Rebind( const nsAString& aSourceString ) { release_ownership_of_buffer_list(); mBufferList = new nsSlidingSharedBufferList(AllocateContiguousHandleWithData(Buffer_ptr(0), aSourceString)); @@ -291,7 +291,7 @@ nsSlidingString::AppendBuffer( PRUnichar* aStorageStart, PRUnichar* aDataEnd, PR } void -nsSlidingString::InsertReadable( const nsAReadableString& aReadable, const nsReadingIterator& aInsertPoint ) +nsSlidingString::InsertReadable( const nsAString& aReadable, const nsReadingIterator& aInsertPoint ) /* * Warning: this routine manipulates the shared buffer list in an unexpected way. * The original design did not really allow for insertions, but this call promises