Back to index

lightning-sunbird  0.9+nobinonly
nsSubstring.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla.
00017  *
00018  * The Initial Developer of the Original Code is IBM Corporation.
00019  * Portions created by IBM Corporation are Copyright (C) 2003
00020  * IBM Corporation. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifdef DEBUG
00040 #define ENABLE_STRING_STATS
00041 #endif
00042 
00043 #ifdef ENABLE_STRING_STATS
00044 #include <stdio.h>
00045 #endif
00046 
00047 #include <stdlib.h>
00048 #include "nsSubstring.h"
00049 #include "nsString.h"
00050 #include "nsStringBuffer.h"
00051 #include "nsDependentString.h"
00052 #include "nsMemory.h"
00053 #include "pratom.h"
00054 
00055 // ---------------------------------------------------------------------------
00056 
00057 static const PRUnichar gNullChar = 0;
00058 
00059 const char*      nsCharTraits<char>     ::sEmptyBuffer = (const char*) &gNullChar;
00060 const PRUnichar* nsCharTraits<PRUnichar>::sEmptyBuffer =               &gNullChar;
00061 
00062 // ---------------------------------------------------------------------------
00063 
00064 #ifdef ENABLE_STRING_STATS
00065 class nsStringStats
00066   {
00067     public:
00068       nsStringStats()
00069         : mAllocCount(0), mReallocCount(0), mFreeCount(0), mShareCount(0) {}
00070 
00071       ~nsStringStats()
00072         {
00073           // this is a hack to suppress duplicate string stats printing
00074           // in seamonkey as a result of the string code being linked
00075           // into seamonkey and libxpcom! :-(
00076           if (!mAllocCount && !mAdoptCount)
00077             return;
00078 
00079           printf("nsStringStats\n");
00080           printf(" => mAllocCount:     % 10d\n", mAllocCount);
00081           printf(" => mReallocCount:   % 10d\n", mReallocCount);
00082           printf(" => mFreeCount:      % 10d", mFreeCount);
00083           if (mAllocCount > mFreeCount)
00084             printf("  --  LEAKED %d !!!\n", mAllocCount - mFreeCount);
00085           else
00086             printf("\n");
00087           printf(" => mShareCount:     % 10d\n", mShareCount);
00088           printf(" => mAdoptCount:     % 10d\n", mAdoptCount);
00089           printf(" => mAdoptFreeCount: % 10d", mAdoptFreeCount);
00090           if (mAdoptCount > mAdoptFreeCount)
00091             printf("  --  LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount);
00092           else
00093             printf("\n");
00094         }
00095 
00096       PRInt32 mAllocCount;
00097       PRInt32 mReallocCount;
00098       PRInt32 mFreeCount;
00099       PRInt32 mShareCount;
00100       PRInt32 mAdoptCount;
00101       PRInt32 mAdoptFreeCount;
00102   };
00103 static nsStringStats gStringStats;
00104 #define STRING_STAT_INCREMENT(_s) PR_AtomicIncrement(&gStringStats.m ## _s ## Count)
00105 #else
00106 #define STRING_STAT_INCREMENT(_s)
00107 #endif
00108 
00109 // ---------------------------------------------------------------------------
00110 
00111 inline void
00112 ReleaseData( void* data, PRUint32 flags )
00113   {
00114     if (flags & nsSubstring::F_SHARED)
00115       {
00116         nsStringBuffer::FromData(data)->Release();
00117       }
00118     else if (flags & nsSubstring::F_OWNED)
00119       {
00120         nsMemory::Free(data);
00121         STRING_STAT_INCREMENT(AdoptFree);
00122       }
00123     // otherwise, nothing to do.
00124   }
00125 
00126 // ---------------------------------------------------------------------------
00127 
00128 // XXX or we could make nsStringBuffer be a friend of nsTAString
00129 
00130 class nsAStringAccessor : public nsAString
00131   {
00132     private:
00133       nsAStringAccessor(); // NOT IMPLEMENTED
00134 
00135     public:
00136 #ifdef MOZ_V1_STRING_ABI
00137       const void *vtable() const { return mVTable; }
00138 #endif
00139       char_type  *data() const   { return mData; }
00140       size_type   length() const { return mLength; }
00141       PRUint32    flags() const  { return mFlags; }
00142 
00143       void set(char_type *data, size_type len, PRUint32 flags)
00144         {
00145           ReleaseData(mData, mFlags);
00146           mData = data;
00147           mLength = len;
00148           mFlags = flags;
00149         }
00150   };
00151 
00152 class nsACStringAccessor : public nsACString
00153   {
00154     private:
00155       nsACStringAccessor(); // NOT IMPLEMENTED
00156 
00157     public:
00158 #ifdef MOZ_V1_STRING_ABI
00159       const void *vtable() const { return mVTable; }
00160 #endif
00161       char_type  *data() const   { return mData; }
00162       size_type   length() const { return mLength; }
00163       PRUint32    flags() const  { return mFlags; }
00164 
00165       void set(char_type *data, size_type len, PRUint32 flags)
00166         {
00167           ReleaseData(mData, mFlags);
00168           mData = data;
00169           mLength = len;
00170           mFlags = flags;
00171         }
00172   };
00173 
00174 // ---------------------------------------------------------------------------
00175 
00176 void
00177 nsStringBuffer::AddRef()
00178   {
00179     PR_AtomicIncrement(&mRefCount);
00180     STRING_STAT_INCREMENT(Share);
00181   }
00182 
00183 void
00184 nsStringBuffer::Release()
00185   {
00186     if (PR_AtomicDecrement(&mRefCount) == 0)
00187       {
00188         STRING_STAT_INCREMENT(Free);
00189         free(this); // we were allocated with |malloc|
00190       }
00191   }
00192 
00196 nsStringBuffer*
00197 nsStringBuffer::Alloc(size_t size)
00198   {
00199     STRING_STAT_INCREMENT(Alloc);
00200 
00201     NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
00202 
00203     nsStringBuffer *hdr =
00204         (nsStringBuffer *) malloc(sizeof(nsStringBuffer) + size);
00205     if (hdr)
00206       {
00207         hdr->mRefCount = 1;
00208         hdr->mStorageSize = size;
00209       }
00210     return hdr;
00211   }
00212 
00213 nsStringBuffer*
00214 nsStringBuffer::Realloc(nsStringBuffer* hdr, size_t size)
00215   {
00216     STRING_STAT_INCREMENT(Realloc);
00217 
00218     NS_ASSERTION(size != 0, "zero capacity allocation not allowed");
00219 
00220     // no point in trying to save ourselves if we hit this assertion
00221     NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string");
00222 
00223     hdr = (nsStringBuffer*) realloc(hdr, sizeof(nsStringBuffer) + size);
00224     if (hdr)
00225       hdr->mStorageSize = size;
00226 
00227     return hdr;
00228   }
00229 
00230 nsStringBuffer*
00231 nsStringBuffer::FromString(const nsAString& str)
00232   {
00233     const nsAStringAccessor* accessor =
00234         NS_STATIC_CAST(const nsAStringAccessor*, &str);
00235 
00236 #ifdef MOZ_V1_STRING_ABI
00237     if (accessor->vtable() != nsObsoleteAString::sCanonicalVTable)
00238       return nsnull;
00239 #endif
00240     if (!(accessor->flags() & nsSubstring::F_SHARED))
00241       return nsnull;
00242 
00243     return FromData(accessor->data());
00244   }
00245 
00246 nsStringBuffer*
00247 nsStringBuffer::FromString(const nsACString& str)
00248   {
00249     const nsACStringAccessor* accessor =
00250         NS_STATIC_CAST(const nsACStringAccessor*, &str);
00251 
00252 #ifdef MOZ_V1_STRING_ABI
00253     if (accessor->vtable() != nsObsoleteACString::sCanonicalVTable)
00254       return nsnull;
00255 #endif
00256     if (!(accessor->flags() & nsCSubstring::F_SHARED))
00257       return nsnull;
00258 
00259     return FromData(accessor->data());
00260   }
00261 
00262 void
00263 nsStringBuffer::ToString(PRUint32 len, nsAString &str)
00264   {
00265     PRUnichar* data = NS_STATIC_CAST(PRUnichar*, Data());
00266 
00267     nsAStringAccessor* accessor = NS_STATIC_CAST(nsAStringAccessor*, &str);
00268 #ifdef MOZ_V1_STRING_ABI
00269     if (accessor->vtable() != nsObsoleteAString::sCanonicalVTable)
00270       {
00271         str.Assign(data, len);
00272         return;
00273       }
00274 #endif
00275     NS_ASSERTION(data[len] == PRUnichar(0), "data should be null terminated");
00276 
00277     // preserve class flags
00278     PRUint32 flags = accessor->flags();
00279     flags = (flags & 0xFFFF0000) | nsSubstring::F_SHARED | nsSubstring::F_TERMINATED;
00280 
00281     AddRef();
00282     accessor->set(data, len, flags);
00283   }
00284 
00285 void
00286 nsStringBuffer::ToString(PRUint32 len, nsACString &str)
00287   {
00288     char* data = NS_STATIC_CAST(char*, Data());
00289 
00290     nsACStringAccessor* accessor = NS_STATIC_CAST(nsACStringAccessor*, &str);
00291 #ifdef MOZ_V1_STRING_ABI
00292     if (accessor->vtable() != nsObsoleteACString::sCanonicalVTable)
00293       {
00294         str.Assign(data, len);
00295         return;
00296       }
00297 #endif
00298     NS_ASSERTION(data[len] == char(0), "data should be null terminated");
00299 
00300     // preserve class flags
00301     PRUint32 flags = accessor->flags();
00302     flags = (flags & 0xFFFF0000) | nsCSubstring::F_SHARED | nsCSubstring::F_TERMINATED;
00303 
00304     AddRef();
00305     accessor->set(data, len, flags);
00306   }
00307 
00308 // ---------------------------------------------------------------------------
00309 
00310 
00311   // define nsSubstring
00312 #include "string-template-def-unichar.h"
00313 #include "nsTSubstring.cpp"
00314 #include "string-template-undef.h"
00315 
00316   // define nsCSubstring
00317 #include "string-template-def-char.h"
00318 #include "nsTSubstring.cpp"
00319 #include "string-template-undef.h"