LCOV - code coverage report
Current view: directory - xpcom/string/src - nsTSubstring.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 356 244 68.5 %
Date: 2012-06-02 Functions: 81 63 77.8 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is IBM Corporation.
      19                 :  * Portions created by IBM Corporation are Copyright (C) 2003
      20                 :  * IBM Corporation. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Darin Fisher <darin@meer.net>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : #include "prdtoa.h"
      39                 : 
      40                 : #ifdef XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE
      41        46173401 : nsTSubstring_CharT::nsTSubstring_CharT( char_type *data, size_type length,
      42                 :                                         PRUint32 flags)
      43                 :   : mData(data),
      44                 :     mLength(length),
      45        46173401 :     mFlags(flags)
      46                 :   {
      47        46173401 :     if (flags & F_OWNED) {
      48              42 :       STRING_STAT_INCREMENT(Adopt);
      49                 : #ifdef NS_BUILD_REFCNT_LOGGING
      50              42 :       NS_LogCtor(mData, "StringAdopt", 1);
      51                 : #endif
      52                 :     }
      53        46173401 :   }
      54                 : #endif /* XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE */
      55                 : 
      56                 :   /**
      57                 :    * helper function for down-casting a nsTSubstring to a nsTFixedString.
      58                 :    */
      59                 : inline const nsTFixedString_CharT*
      60        16467516 : AsFixedString( const nsTSubstring_CharT* s )
      61                 :   {
      62        16467516 :     return static_cast<const nsTFixedString_CharT*>(s);
      63                 :   }
      64                 : 
      65                 : 
      66                 :   /**
      67                 :    * this function is called to prepare mData for writing.  the given capacity
      68                 :    * indicates the required minimum storage size for mData, in sizeof(char_type)
      69                 :    * increments.  this function returns true if the operation succeeds.  it also
      70                 :    * returns the old data and old flags members if mData is newly allocated.
      71                 :    * the old data must be released by the caller.
      72                 :    */
      73                 : bool
      74        12118904 : nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint32* oldFlags )
      75                 :   {
      76                 :     // initialize to no old data
      77        12118904 :     *oldData = nsnull;
      78        12118904 :     *oldFlags = 0;
      79                 : 
      80        12118904 :     size_type curCapacity = Capacity();
      81                 : 
      82                 :     // If |capacity > kMaxCapacity|, then our doubling algorithm may not be
      83                 :     // able to allocate it.  Just bail out in cases like that.  We don't want
      84                 :     // to be allocating 2GB+ strings anyway.
      85                 :     PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
      86                 :     const size_type kMaxCapacity =
      87        12118802 :       (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
      88        12118802 :     if (capacity > kMaxCapacity) {
      89                 :       // Also assert for |capacity| equal to |size_type(-1)|, since we used to
      90                 :       // use that value to flag immutability.
      91               0 :       NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
      92               0 :       return false;
      93                 :     }
      94                 : 
      95                 :     // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we
      96                 :     // need to allocate a new buffer. We cannot use the existing buffer even
      97                 :     // though it might be large enough.
      98                 : 
      99        12118802 :     if (curCapacity != 0)
     100                 :       {
     101         3765759 :         if (capacity <= curCapacity) {
     102         2832574 :           mFlags &= ~F_VOIDED;  // mutation clears voided flag
     103         2832574 :           return true;
     104                 :         }
     105                 : 
     106                 :         // Use doubling algorithm when forced to increase available capacity.
     107          933185 :         size_type temp = curCapacity;
     108         2895040 :         while (temp < capacity)
     109         1028670 :           temp <<= 1;
     110          933185 :         NS_ASSERTION(NS_MIN(temp, kMaxCapacity) >= capacity,
     111                 :                      "should have hit the early return at the top");
     112          933185 :         capacity = NS_MIN(temp, kMaxCapacity);
     113                 :       }
     114                 : 
     115                 :     //
     116                 :     // several cases:
     117                 :     //
     118                 :     //  (1) we have a shared buffer (mFlags & F_SHARED)
     119                 :     //  (2) we have an owned buffer (mFlags & F_OWNED)
     120                 :     //  (3) we have a fixed buffer (mFlags & F_FIXED)
     121                 :     //  (4) we have a readonly buffer
     122                 :     //
     123                 :     // requiring that we in some cases preserve the data before creating
     124                 :     // a new buffer complicates things just a bit ;-)
     125                 :     //
     126                 : 
     127         9286228 :     size_type storageSize = (capacity + 1) * sizeof(char_type);
     128                 : 
     129                 :     // case #1
     130         9286228 :     if (mFlags & F_SHARED)
     131                 :       {
     132          748661 :         nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
     133          748661 :         if (!hdr->IsReadonly())
     134                 :           {
     135          557702 :             nsStringBuffer *newHdr = nsStringBuffer::Realloc(hdr, storageSize);
     136          557702 :             if (!newHdr)
     137               0 :               return false; // out-of-memory (original header left intact)
     138                 : 
     139          557702 :             hdr = newHdr;
     140          557702 :             mData = (char_type*) hdr->Data();
     141          557702 :             mFlags &= ~F_VOIDED;  // mutation clears voided flag
     142          557702 :             return true;
     143                 :           }
     144                 :       }
     145                 : 
     146                 :     char_type* newData;
     147                 :     PRUint32 newDataFlags;
     148                 : 
     149                 :       // if we have a fixed buffer of sufficient size, then use it.  this helps
     150                 :       // avoid heap allocations.
     151         8728526 :     if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity))
     152                 :       {
     153         1234227 :         newData = AsFixedString(this)->mFixedBuf;
     154         1234227 :         newDataFlags = F_TERMINATED | F_FIXED;
     155                 :       }
     156                 :     else
     157                 :       {
     158                 :         // if we reach here then, we must allocate a new buffer.  we cannot
     159                 :         // make use of our F_OWNED or F_FIXED buffers because they are not
     160                 :         // large enough.
     161                 : 
     162         7494299 :         nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize);
     163         7494489 :         if (!newHdr)
     164               0 :           return false; // we are still in a consistent state
     165                 : 
     166         7494489 :         newData = (char_type*) newHdr->Data();
     167         7494487 :         newDataFlags = F_TERMINATED | F_SHARED;
     168                 :       }
     169                 : 
     170                 :     // save old data and flags
     171         8728714 :     *oldData = mData;
     172         8728714 :     *oldFlags = mFlags;
     173                 : 
     174         8728714 :     mData = newData;
     175         8728714 :     SetDataFlags(newDataFlags);
     176                 : 
     177                 :     // mLength does not change
     178                 : 
     179                 :     // though we are not necessarily terminated at the moment, now is probably
     180                 :     // still the best time to set F_TERMINATED.
     181                 : 
     182         8728714 :     return true;
     183                 :   }
     184                 : 
     185                 : void
     186        71864413 : nsTSubstring_CharT::Finalize()
     187                 :   {
     188        71864413 :     ::ReleaseData(mData, mFlags);
     189                 :     // mData, mLength, and mFlags are purposefully left dangling
     190        71864267 :   }
     191                 : 
     192                 : bool
     193         7036240 : nsTSubstring_CharT::ReplacePrepInternal(index_type cutStart, size_type cutLen,
     194                 :                                         size_type fragLen, size_type newLen)
     195                 :   {
     196                 :     char_type* oldData;
     197                 :     PRUint32 oldFlags;
     198         7036240 :     if (!MutatePrep(newLen, &oldData, &oldFlags))
     199               0 :       return false; // out-of-memory
     200                 : 
     201         7036282 :     if (oldData)
     202                 :       {
     203                 :         // determine whether or not we need to copy part of the old string
     204                 :         // over to the new string.
     205                 : 
     206         6267743 :         if (cutStart > 0)
     207                 :           {
     208                 :             // copy prefix from old string
     209           76070 :             char_traits::copy(mData, oldData, cutStart);
     210                 :           }
     211                 : 
     212         6267741 :         if (cutStart + cutLen < mLength)
     213                 :           {
     214                 :             // copy suffix from old string to new offset
     215            3097 :             size_type from = cutStart + cutLen;
     216            3097 :             size_type fromLen = mLength - from;
     217            3097 :             PRUint32 to = cutStart + fragLen;
     218            3097 :             char_traits::copy(mData + to, oldData + from, fromLen);
     219                 :           }
     220                 : 
     221         6267741 :         ::ReleaseData(oldData, oldFlags);
     222                 :       }
     223                 :     else
     224                 :       {
     225                 :         // original data remains intact
     226                 : 
     227                 :         // determine whether or not we need to move part of the existing string
     228                 :         // to make room for the requested hole.
     229          768539 :         if (fragLen != cutLen && cutStart + cutLen < mLength)
     230                 :           {
     231           31783 :             PRUint32 from = cutStart + cutLen;
     232           31783 :             PRUint32 fromLen = mLength - from;
     233           31783 :             PRUint32 to = cutStart + fragLen;
     234           31783 :             char_traits::move(mData + to, mData + from, fromLen);
     235                 :           }
     236                 :       }
     237                 : 
     238                 :     // add null terminator (mutable mData always has room for the null-
     239                 :     // terminator).
     240         7036272 :     mData[newLen] = char_type(0);
     241         7036272 :     mLength = newLen;
     242                 : 
     243         7036272 :     return true;
     244                 :   }
     245                 : 
     246                 : nsTSubstring_CharT::size_type
     247        30653458 : nsTSubstring_CharT::Capacity() const
     248                 :   {
     249                 :     // return 0 to indicate an immutable or 0-sized buffer
     250                 : 
     251                 :     size_type capacity;
     252        30653458 :     if (mFlags & F_SHARED)
     253                 :       {
     254                 :         // if the string is readonly, then we pretend that it has no capacity.
     255         3411249 :         nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
     256         3411249 :         if (hdr->IsReadonly())
     257          249051 :           capacity = 0;
     258                 :         else {
     259         3162198 :           capacity = (hdr->StorageSize() / sizeof(char_type)) - 1;
     260                 :         }
     261                 :       }
     262        27242209 :     else if (mFlags & F_FIXED)
     263                 :       {
     264        12996939 :         capacity = AsFixedString(this)->mFixedCapacity;
     265                 :       }
     266        14245270 :     else if (mFlags & F_OWNED)
     267                 :       {
     268                 :         // we don't store the capacity of an adopted buffer because that would
     269                 :         // require an additional member field.  the best we can do is base the
     270                 :         // capacity on our length.  remains to be seen if this is the right
     271                 :         // trade-off.
     272            1654 :         capacity = mLength;
     273                 :       }
     274                 :     else
     275                 :       {
     276        14243616 :         capacity = 0;
     277                 :       }
     278                 : 
     279        30653457 :     return capacity;
     280                 :   }
     281                 : 
     282                 : bool
     283        10571804 : nsTSubstring_CharT::EnsureMutable( size_type newLen )
     284                 :   {
     285        10571804 :     if (newLen == size_type(-1) || newLen == mLength)
     286                 :       {
     287         8632047 :         if (mFlags & (F_FIXED | F_OWNED))
     288         6159579 :           return true;
     289         2472468 :         if ((mFlags & F_SHARED) && !nsStringBuffer::FromData(mData)->IsReadonly())
     290         2440475 :           return true;
     291                 : 
     292           31993 :         newLen = mLength;
     293                 :       }
     294         1971750 :     return SetLength(newLen);
     295                 :   }
     296                 : 
     297                 : // ---------------------------------------------------------------------------
     298                 : 
     299                 :   // This version of Assign is optimized for single-character assignment.
     300                 : void
     301             600 : nsTSubstring_CharT::Assign( char_type c )
     302                 :   {
     303             600 :     if (ReplacePrep(0, mLength, 1))
     304             600 :       *mData = c;
     305             600 :   }
     306                 : 
     307                 : 
     308                 : void
     309        13930463 : nsTSubstring_CharT::Assign( const char_type* data, size_type length )
     310                 :   {
     311                 :       // unfortunately, some callers pass null :-(
     312        13930463 :     if (!data)
     313                 :       {
     314            6079 :         Truncate();
     315            6079 :         return;
     316                 :       }
     317                 : 
     318        13924384 :     if (length == size_type(-1))
     319         6886134 :       length = char_traits::length(data);
     320                 : 
     321        13924384 :     if (IsDependentOn(data, data + length))
     322                 :       {
     323                 :         // take advantage of sharing here...
     324             252 :         Assign(string_type(data, length));
     325             252 :         return;
     326                 :       }
     327                 : 
     328        13924098 :     if (ReplacePrep(0, mLength, length))
     329        13924136 :       char_traits::copy(mData, data, length);
     330                 :   }
     331                 : 
     332                 : void
     333          436784 : nsTSubstring_CharT::AssignASCII( const char* data, size_type length )
     334                 :   {
     335                 :     // A Unicode string can't depend on an ASCII string buffer,
     336                 :     // so this dependence check only applies to CStrings.
     337                 : #ifdef CharT_is_char
     338          232241 :     if (IsDependentOn(data, data + length))
     339                 :       {
     340                 :         // take advantage of sharing here...
     341               0 :         Assign(string_type(data, length));
     342               0 :         return;
     343                 :       }
     344                 : #endif
     345                 : 
     346          436784 :     if (ReplacePrep(0, mLength, length))
     347          436784 :       char_traits::copyASCII(mData, data, length);
     348          204543 :   }
     349                 : 
     350                 : void
     351           12409 : nsTSubstring_CharT::AssignASCII( const char* data )
     352                 :   {
     353           12409 :     AssignASCII(data, strlen(data));
     354           12409 :   }
     355                 : 
     356                 : void
     357        11759329 : nsTSubstring_CharT::Assign( const self_type& str )
     358                 :   {
     359                 :     // |str| could be sharable.  we need to check its flags to know how to
     360                 :     // deal with it.
     361                 : 
     362        11759329 :     if (&str == this)
     363               2 :       return;
     364                 : 
     365        11759327 :     if (!str.mLength)
     366                 :       {
     367         1824783 :         Truncate();
     368         1824783 :         mFlags |= str.mFlags & F_VOIDED;
     369                 :       }
     370         9934544 :     else if (str.mFlags & F_SHARED)
     371                 :       {
     372                 :         // nice! we can avoid a string copy :-)
     373                 : 
     374                 :         // |str| should be null-terminated
     375         4995236 :         NS_ASSERTION(str.mFlags & F_TERMINATED, "shared, but not terminated");
     376                 : 
     377         4995236 :         ::ReleaseData(mData, mFlags);
     378                 : 
     379         4995236 :         mData = str.mData;
     380         4995236 :         mLength = str.mLength;
     381         4995236 :         SetDataFlags(F_TERMINATED | F_SHARED);
     382                 : 
     383                 :         // get an owning reference to the mData
     384         4995237 :         nsStringBuffer::FromData(mData)->AddRef();
     385                 :       }
     386                 :     else
     387                 :       {
     388                 :         // else, treat this like an ordinary assignment.
     389         4939308 :         Assign(str.Data(), str.Length());
     390                 :       }
     391                 :   }
     392                 : 
     393                 : void
     394          276268 : nsTSubstring_CharT::Assign( const substring_tuple_type& tuple )
     395                 :   {
     396          276268 :     if (tuple.IsDependentOn(mData, mData + mLength))
     397                 :       {
     398                 :         // take advantage of sharing here...
     399               0 :         Assign(string_type(tuple));
     400               0 :         return;
     401                 :       }
     402                 : 
     403          276268 :     size_type length = tuple.Length();
     404                 : 
     405                 :     // don't use ReplacePrep here because it changes the length
     406                 :     char_type* oldData;
     407                 :     PRUint32 oldFlags;
     408          276268 :     if (MutatePrep(length, &oldData, &oldFlags)) {
     409          276268 :       if (oldData)
     410          222487 :         ::ReleaseData(oldData, oldFlags);
     411                 : 
     412          276268 :       tuple.WriteTo(mData, length);
     413          276268 :       mData[length] = 0;
     414          276268 :       mLength = length;
     415                 :     }
     416                 :   }
     417                 : 
     418                 : void
     419          269562 : nsTSubstring_CharT::Adopt( char_type* data, size_type length )
     420                 :   {
     421          269562 :     if (data)
     422                 :       {
     423          237967 :         ::ReleaseData(mData, mFlags);
     424                 : 
     425          237967 :         if (length == size_type(-1))
     426          233514 :           length = char_traits::length(data);
     427                 : 
     428          237967 :         mData = data;
     429          237967 :         mLength = length;
     430          237967 :         SetDataFlags(F_TERMINATED | F_OWNED);
     431                 : 
     432          237967 :         STRING_STAT_INCREMENT(Adopt);
     433                 : #ifdef NS_BUILD_REFCNT_LOGGING
     434                 :         // Treat this as construction of a "StringAdopt" object for leak
     435                 :         // tracking purposes.        
     436          237967 :         NS_LogCtor(mData, "StringAdopt", 1);
     437                 : #endif // NS_BUILD_REFCNT_LOGGING
     438                 :       }
     439                 :     else
     440                 :       {
     441           31595 :         SetIsVoid(true);
     442                 :       }
     443          269562 :   }
     444                 : 
     445                 : 
     446                 :   // This version of Replace is optimized for single-character replacement.
     447                 : void
     448          760675 : nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, char_type c )
     449                 :   {
     450          760675 :     cutStart = NS_MIN(cutStart, Length());
     451                 : 
     452          760675 :     if (ReplacePrep(cutStart, cutLength, 1))
     453          760675 :       mData[cutStart] = c;
     454          760675 :   }
     455                 : 
     456                 : 
     457                 : void
     458         2731365 : nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length )
     459                 :   {
     460                 :       // unfortunately, some callers pass null :-(
     461         2731365 :     if (!data)
     462                 :       {
     463               0 :         length = 0;
     464                 :       }
     465                 :     else
     466                 :       {
     467         2731365 :         if (length == size_type(-1))
     468          708487 :           length = char_traits::length(data);
     469                 : 
     470         2731365 :         if (IsDependentOn(data, data + length))
     471                 :           {
     472               0 :             nsTAutoString_CharT temp(data, length);
     473               0 :             Replace(cutStart, cutLength, temp);
     474                 :             return;
     475                 :           }
     476                 :       }
     477                 : 
     478         2731365 :     cutStart = NS_MIN(cutStart, Length());
     479                 : 
     480         2731365 :     if (ReplacePrep(cutStart, cutLength, length) && length > 0)
     481         2625122 :       char_traits::copy(mData + cutStart, data, length);
     482                 :   }
     483                 : 
     484                 : void
     485          333848 : nsTSubstring_CharT::ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length )
     486                 :   {
     487          333848 :     if (length == size_type(-1))
     488             713 :       length = strlen(data);
     489                 :     
     490                 :     // A Unicode string can't depend on an ASCII string buffer,
     491                 :     // so this dependence check only applies to CStrings.
     492                 : #ifdef CharT_is_char
     493          327808 :     if (IsDependentOn(data, data + length))
     494                 :       {
     495               0 :         nsTAutoString_CharT temp(data, length);
     496               0 :         Replace(cutStart, cutLength, temp);
     497                 :         return;
     498                 :       }
     499                 : #endif
     500                 : 
     501          333848 :     cutStart = NS_MIN(cutStart, Length());
     502                 : 
     503          333848 :     if (ReplacePrep(cutStart, cutLength, length) && length > 0)
     504          333848 :       char_traits::copyASCII(mData + cutStart, data, length);
     505            6040 :   }
     506                 : 
     507                 : void
     508          562785 : nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple )
     509                 :   {
     510          562785 :     if (tuple.IsDependentOn(mData, mData + mLength))
     511                 :       {
     512               0 :         nsTAutoString_CharT temp(tuple);
     513               0 :         Replace(cutStart, cutLength, temp);
     514                 :         return;
     515                 :       }
     516                 : 
     517          562785 :     size_type length = tuple.Length();
     518                 : 
     519          562785 :     cutStart = NS_MIN(cutStart, Length());
     520                 : 
     521          562785 :     if (ReplacePrep(cutStart, cutLength, length) && length > 0)
     522          562785 :       tuple.WriteTo(mData + cutStart, length);
     523                 :   }
     524                 : 
     525                 : bool
     526        11784205 : nsTSubstring_CharT::SetCapacity( size_type capacity )
     527                 :   {
     528                 :     // capacity does not include room for the terminating null char
     529                 : 
     530                 :     // if our capacity is reduced to zero, then free our buffer.
     531        11784205 :     if (capacity == 0)
     532                 :       {
     533         6977763 :         ::ReleaseData(mData, mFlags);
     534         6977762 :         mData = char_traits::sEmptyBuffer;
     535         6977762 :         mLength = 0;
     536         6977762 :         SetDataFlags(F_TERMINATED);
     537                 :       }
     538                 :     else
     539                 :       {
     540                 :         char_type* oldData;
     541                 :         PRUint32 oldFlags;
     542         4806442 :         if (!MutatePrep(capacity, &oldData, &oldFlags))
     543               0 :           return false; // out-of-memory
     544                 : 
     545                 :         // compute new string length
     546         4806442 :         size_type newLen = NS_MIN(mLength, capacity);
     547                 : 
     548         4806442 :         if (oldData)
     549                 :           {
     550                 :             // preserve old data
     551         2218856 :             if (mLength > 0)
     552          132861 :               char_traits::copy(mData, oldData, newLen);
     553                 : 
     554         2218856 :             ::ReleaseData(oldData, oldFlags);
     555                 :           }
     556                 : 
     557                 :         // adjust mLength if our buffer shrunk down in size
     558         4806442 :         if (newLen < mLength)
     559          427217 :           mLength = newLen;
     560                 : 
     561                 :         // always null-terminate here, even if the buffer got longer.  this is
     562                 :         // for backwards compat with the old string implementation.
     563         4806442 :         mData[capacity] = char_type(0);
     564                 :       }
     565                 : 
     566        11784203 :     return true;
     567                 :   }
     568                 : 
     569                 : bool
     570        11711014 : nsTSubstring_CharT::SetLength( size_type length )
     571                 :   {
     572        11711014 :     if (!SetCapacity(length))
     573               0 :       return false;
     574                 : 
     575        11711013 :     mLength = length;
     576        11711013 :     return true;
     577                 :   }
     578                 : 
     579                 : void
     580          386662 : nsTSubstring_CharT::SetIsVoid( bool val )
     581                 :   {
     582          386662 :     if (val)
     583                 :       {
     584          386646 :         Truncate();
     585          386646 :         mFlags |= F_VOIDED;
     586                 :       }
     587                 :     else
     588                 :       {
     589              16 :         mFlags &= ~F_VOIDED;
     590                 :       }
     591          386662 :   }
     592                 : 
     593                 : bool
     594        20985320 : nsTSubstring_CharT::Equals( const self_type& str ) const
     595                 :   {
     596        20985320 :     return mLength == str.mLength && char_traits::compare(mData, str.mData, mLength) == 0;
     597                 :   }
     598                 : 
     599                 : bool
     600          175121 : nsTSubstring_CharT::Equals( const self_type& str, const comparator_type& comp ) const
     601                 :   {
     602          175121 :     return mLength == str.mLength && comp(mData, str.mData, mLength, str.mLength) == 0;
     603                 :   }
     604                 : 
     605                 : bool
     606          470841 : nsTSubstring_CharT::Equals( const char_type* data ) const
     607                 :   {
     608                 :     // unfortunately, some callers pass null :-(
     609          470841 :     if (!data)
     610                 :       {
     611               0 :         NS_NOTREACHED("null data pointer");
     612               0 :         return mLength == 0;
     613                 :       }
     614                 : 
     615                 :     // XXX avoid length calculation?
     616          470841 :     size_type length = char_traits::length(data);
     617          470841 :     return mLength == length && char_traits::compare(mData, data, mLength) == 0;
     618                 :   }
     619                 : 
     620                 : bool
     621              34 : nsTSubstring_CharT::Equals( const char_type* data, const comparator_type& comp ) const
     622                 :   {
     623                 :     // unfortunately, some callers pass null :-(
     624              34 :     if (!data)
     625                 :       {
     626               0 :         NS_NOTREACHED("null data pointer");
     627               0 :         return mLength == 0;
     628                 :       }
     629                 : 
     630                 :     // XXX avoid length calculation?
     631              34 :     size_type length = char_traits::length(data);
     632              34 :     return mLength == length && comp(mData, data, mLength, length) == 0;
     633                 :   }
     634                 : 
     635                 : bool
     636         1564158 : nsTSubstring_CharT::EqualsASCII( const char* data, size_type len ) const
     637                 :   {
     638         1564158 :     return mLength == len && char_traits::compareASCII(mData, data, len) == 0;
     639                 :   }
     640                 : 
     641                 : bool
     642            7246 : nsTSubstring_CharT::EqualsASCII( const char* data ) const
     643                 :   {
     644            7246 :     return char_traits::compareASCIINullTerminated(mData, mLength, data) == 0;
     645                 :   }
     646                 : 
     647                 : bool
     648          331597 : nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data, size_type len ) const
     649                 :   {
     650          331597 :     return mLength == len && char_traits::compareLowerCaseToASCII(mData, data, len) == 0;
     651                 :   }
     652                 : 
     653                 : bool
     654            4061 : nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data ) const
     655                 :   {
     656            4061 :     return char_traits::compareLowerCaseToASCIINullTerminated(mData, mLength, data) == 0;
     657                 :   }
     658                 : 
     659                 : nsTSubstring_CharT::size_type
     660              25 : nsTSubstring_CharT::CountChar( char_type c ) const
     661                 :   {
     662              25 :     const char_type *start = mData;
     663              25 :     const char_type *end   = mData + mLength;
     664                 : 
     665              25 :     return NS_COUNT(start, end, c);
     666                 :   }
     667                 : 
     668                 : PRInt32
     669         1709023 : nsTSubstring_CharT::FindChar( char_type c, index_type offset ) const
     670                 :   {
     671         1709023 :     if (offset < mLength)
     672                 :       {
     673         1698002 :         const char_type* result = char_traits::find(mData + offset, mLength - offset, c);
     674         1698002 :         if (result)
     675           71750 :           return result - mData;
     676                 :       }
     677         1637273 :     return -1;
     678                 :   }
     679                 : 
     680                 : void
     681               0 : nsTSubstring_CharT::StripChar( char_type aChar, PRInt32 aOffset )
     682                 :   {
     683               0 :     if (mLength == 0 || aOffset >= PRInt32(mLength))
     684               0 :       return;
     685                 : 
     686               0 :     EnsureMutable(); // XXX do this lazily?
     687                 : 
     688                 :     // XXX(darin): this code should defer writing until necessary.
     689                 : 
     690               0 :     char_type* to   = mData + aOffset;
     691               0 :     char_type* from = mData + aOffset;
     692               0 :     char_type* end  = mData + mLength;
     693                 : 
     694               0 :     while (from < end)
     695                 :       {
     696               0 :         char_type theChar = *from++;
     697               0 :         if (aChar != theChar)
     698               0 :           *to++ = theChar;
     699                 :       }
     700               0 :     *to = char_type(0); // add the null
     701               0 :     mLength = to - mData;
     702                 :   }
     703                 : 
     704                 : void
     705               2 : nsTSubstring_CharT::StripChars( const char_type* aChars, PRUint32 aOffset )
     706                 :   {
     707               2 :     if (aOffset >= PRUint32(mLength))
     708               2 :       return;
     709                 : 
     710               0 :     EnsureMutable(); // XXX do this lazily?
     711                 : 
     712                 :     // XXX(darin): this code should defer writing until necessary.
     713                 : 
     714               0 :     char_type* to   = mData + aOffset;
     715               0 :     char_type* from = mData + aOffset;
     716               0 :     char_type* end  = mData + mLength;
     717                 : 
     718               0 :     while (from < end)
     719                 :       {
     720               0 :         char_type theChar = *from++;
     721               0 :         const char_type* test = aChars;
     722                 : 
     723               0 :         for (; *test && *test != theChar; ++test);
     724                 : 
     725               0 :         if (!*test) {
     726                 :           // Not stripped, copy this char.
     727               0 :           *to++ = theChar;
     728                 :         }
     729                 :       }
     730               0 :     *to = char_type(0); // add the null
     731               0 :     mLength = to - mData;
     732                 :   }
     733                 : 
     734           39118 : void nsTSubstring_CharT::AppendPrintf31( const char* format, ...)
     735                 :   {
     736                 :     char buf[32];
     737                 :     va_list ap;
     738           39118 :     va_start(ap, format);
     739           39118 :     PRUint32 len = PR_vsnprintf(buf, sizeof(buf), format, ap);
     740           39118 :     AppendASCII(buf, len);
     741           39118 :     va_end(ap);
     742           39118 :   }
     743                 : 
     744             709 : void nsTSubstring_CharT::AppendPrintf( const char* format, ...)
     745                 :   {
     746                 :     char *buf;
     747                 :     va_list ap;
     748             709 :     va_start(ap, format);
     749             709 :     buf = PR_vsmprintf(format, ap);
     750             709 :     AppendASCII(buf);
     751             709 :     PR_smprintf_free(buf);
     752             709 :     va_end(ap);
     753             709 :   }
     754                 : 
     755                 : 
     756                 : /* hack to make sure we define Modified_cnvtf only once */
     757                 : #ifdef CharT_is_PRUnichar
     758                 : /**
     759                 :  * This is a copy of |PR_cnvtf| with a bug fixed.  (The second argument
     760                 :  * of PR_dtoa is 2 rather than 1.)
     761                 :  *
     762                 :  * XXX(darin): if this is the right thing, then why wasn't it fixed in NSPR?!?
     763                 :  */
     764                 : static void 
     765               0 : Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval)
     766                 : {
     767                 :   PRIntn decpt, sign, numdigits;
     768                 :   char *num, *nump;
     769               0 :   char *bufp = buf;
     770                 :   char *endnum;
     771                 : 
     772                 :   /* If anything fails, we store an empty string in 'buf' */
     773               0 :   num = (char*)malloc(bufsz);
     774               0 :   if (num == NULL) {
     775               0 :     buf[0] = '\0';
     776               0 :     return;
     777                 :   }
     778               0 :   if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz)
     779                 :       == PR_FAILURE) {
     780               0 :     buf[0] = '\0';
     781               0 :     goto done;
     782                 :   }
     783               0 :   numdigits = endnum - num;
     784               0 :   nump = num;
     785                 : 
     786                 :   /*
     787                 :    * The NSPR code had a fancy way of checking that we weren't dealing
     788                 :    * with -0.0 or -NaN, but I'll just use < instead.
     789                 :    * XXX Should we check !isnan(fval) as well?  Is it portable?  We
     790                 :    * probably don't need to bother since NAN isn't portable.
     791                 :    */
     792               0 :   if (sign && fval < 0.0f) {
     793               0 :     *bufp++ = '-';
     794                 :   }
     795                 : 
     796               0 :   if (decpt == 9999) {
     797               0 :     while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
     798               0 :     goto done;
     799                 :   }
     800                 : 
     801               0 :   if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
     802               0 :     *bufp++ = *nump++;
     803               0 :     if (numdigits != 1) {
     804               0 :       *bufp++ = '.';
     805                 :     }
     806                 : 
     807               0 :     while (*nump != '\0') {
     808               0 :       *bufp++ = *nump++;
     809                 :     }
     810               0 :     *bufp++ = 'e';
     811               0 :     PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
     812                 :   }
     813               0 :   else if (decpt >= 0) {
     814               0 :     if (decpt == 0) {
     815               0 :       *bufp++ = '0';
     816                 :     }
     817                 :     else {
     818               0 :       while (decpt--) {
     819               0 :         if (*nump != '\0') {
     820               0 :           *bufp++ = *nump++;
     821                 :         }
     822                 :         else {
     823               0 :           *bufp++ = '0';
     824                 :         }
     825                 :       }
     826                 :     }
     827               0 :     if (*nump != '\0') {
     828               0 :       *bufp++ = '.';
     829               0 :       while (*nump != '\0') {
     830               0 :         *bufp++ = *nump++;
     831                 :       }
     832                 :     }
     833               0 :     *bufp++ = '\0';
     834                 :   }
     835               0 :   else if (decpt < 0) {
     836               0 :     *bufp++ = '0';
     837               0 :     *bufp++ = '.';
     838               0 :     while (decpt++) {
     839               0 :       *bufp++ = '0';
     840                 :     }
     841                 : 
     842               0 :     while (*nump != '\0') {
     843               0 :       *bufp++ = *nump++;
     844                 :     }
     845               0 :     *bufp++ = '\0';
     846                 :   }
     847                 : done:
     848               0 :   free(num);
     849                 : }
     850                 : #endif /* CharT_is_PRUnichar */
     851                 : 
     852                 : void
     853               0 : nsTSubstring_CharT::DoAppendFloat( double aFloat, int digits )
     854                 : {
     855                 :   char buf[40];
     856                 :   // Use Modified_cnvtf, which is locale-insensitive, instead of the
     857                 :   // locale-sensitive PR_snprintf or sprintf(3)
     858               0 :   Modified_cnvtf(buf, sizeof(buf), digits, aFloat);
     859               0 :   AppendASCII(buf);
     860               0 : }
     861                 : 
     862                 : size_t
     863               0 : nsTSubstring_CharT::SizeOfExcludingThisMustBeUnshared(
     864                 :     nsMallocSizeOfFun mallocSizeOf) const
     865                 : {
     866               0 :   if (mFlags & F_SHARED) {
     867                 :     return nsStringBuffer::FromData(mData)->
     868               0 :              SizeOfIncludingThisMustBeUnshared(mallocSizeOf);
     869                 :   } 
     870               0 :   if (mFlags & F_OWNED) {
     871               0 :     return mallocSizeOf(mData);
     872                 :   }
     873                 : 
     874                 :   // If we reach here, exactly one of the following must be true:
     875                 :   // - F_VOIDED is set, and mData points to sEmptyBuffer;
     876                 :   // - F_FIXED is set, and mData points to a buffer within a string
     877                 :   //   object (e.g. nsAutoString);
     878                 :   // - None of F_SHARED, F_OWNED, F_FIXED is set, and mData points to a buffer
     879                 :   //   owned by something else.
     880                 :   //
     881                 :   // In all three cases, we don't measure it.
     882               0 :   return 0;
     883                 : }
     884                 : 
     885                 : size_t
     886               0 : nsTSubstring_CharT::SizeOfExcludingThisIfUnshared(
     887                 :     nsMallocSizeOfFun mallocSizeOf) const
     888                 : {
     889                 :   // This is identical to SizeOfExcludingThisMustBeUnshared except for the
     890                 :   // F_SHARED case.
     891               0 :   if (mFlags & F_SHARED) {
     892                 :     return nsStringBuffer::FromData(mData)->
     893               0 :              SizeOfIncludingThisIfUnshared(mallocSizeOf);
     894                 :   }
     895               0 :   if (mFlags & F_OWNED) {
     896               0 :     return mallocSizeOf(mData);
     897                 :   }
     898               0 :   return 0;
     899                 : }
     900                 : 
     901                 : size_t
     902               0 : nsTSubstring_CharT::SizeOfIncludingThisMustBeUnshared(
     903                 :     nsMallocSizeOfFun mallocSizeOf) const
     904                 : {
     905               0 :   return mallocSizeOf(this) + SizeOfExcludingThisMustBeUnshared(mallocSizeOf);
     906                 : }
     907                 : 
     908                 : size_t
     909               0 : nsTSubstring_CharT::SizeOfIncludingThisIfUnshared(
     910                 :     nsMallocSizeOfFun mallocSizeOf) const
     911                 : {
     912               0 :   return mallocSizeOf(this) + SizeOfExcludingThisIfUnshared(mallocSizeOf);
     913                 : }
     914                 : 

Generated by: LCOV version 1.7