Example #1
0
nsTAdoptingString_CharT&
nsTAdoptingString_CharT::operator=(const self_type& str)
{
  // This'll violate the constness of this argument, that's just
  // the nature of this class...
  self_type* mutable_str = const_cast<self_type*>(&str);

  if (str.mFlags & F_OWNED) {
    // We want to do what Adopt() does, but without actually incrementing
    // the Adopt count.  Note that we can be a little more straightforward
    // about this than Adopt() is, because we know that str.mData is
    // non-null.  Should we be able to assert that str is not void here?
    NS_ASSERTION(str.mData, "String with null mData?");
    Finalize();
    mData = str.mData;
    mLength = str.mLength;
    SetDataFlags(F_TERMINATED | F_OWNED);

    // Make str forget the buffer we just took ownership of.
    new(mutable_str) self_type();
  } else {
    Assign(str);

    mutable_str->Truncate();
  }

  return *this;
}
Example #2
0
void
nsTSubstring_CharT::Adopt( char_type* data, size_type length )
  {
    if (data)
      {
        ::ReleaseData(mData, mFlags);

        if (length == size_type(-1))
          length = char_traits::length(data);

        mData = data;
        mLength = length;
        SetDataFlags(F_TERMINATED | F_OWNED);

        STRING_STAT_INCREMENT(Adopt);
#ifdef NS_BUILD_REFCNT_LOGGING
        // Treat this as construction of a "StringAdopt" object for leak
        // tracking purposes.        
        NS_LogCtor(mData, "StringAdopt", 1);
#endif // NS_BUILD_REFCNT_LOGGING
      }
    else
      {
        SetIsVoid(true);
      }
  }
void
nsTDependentString_CharT::Rebind( const char_type* data, size_type length )
  {
    // If we currently own a buffer, release it.
    Finalize();

    mData = const_cast<char_type*>(data);
    mLength = length;
    SetDataFlags(F_TERMINATED);
    AssertValid();
  }
Example #4
0
void
nsTDependentSubstring_CharT::Rebind( const char_type* data, size_type length )
{
  NS_ASSERTION(data, "nsTDependentSubstring must wrap a non-NULL buffer");

  // If we currently own a buffer, release it.
  Finalize();

  mData = const_cast<char_type*>(static_cast<const char_type*>(data));
  mLength = length;
  SetDataFlags(F_NONE);
}
void
nsTDependentSubstring_CharT::Rebind( const char_type* start, const char_type* end )
  {
    NS_ASSERTION(start && end, "nsTDependentSubstring must wrap a non-NULL buffer");

    // If we currently own a buffer, release it.
    Finalize();

    mData = NS_CONST_CAST(char_type*, start);
    mLength = end - start;
    SetDataFlags(F_NONE);
  }
void
nsTDependentString_CharT::Rebind( const string_type& str, PRUint32 startPos )
  {
    // If we currently own a buffer, release it.
    Finalize();

    size_type strLength = str.Length();

    if (startPos > strLength)
      startPos = strLength;

    mData = const_cast<char_type*>(str.Data()) + startPos;
    mLength = strLength - startPos;

    SetDataFlags(F_TERMINATED);
  }
Example #7
0
void
nsTDependentSubstring_CharT::Rebind( const substring_type& str, uint32_t startPos, uint32_t length )
{
  // If we currently own a buffer, release it.
  Finalize();

  size_type strLength = str.Length();

  if (startPos > strLength)
    startPos = strLength;

  mData = const_cast<char_type*>(static_cast<const char_type*>(str.Data())) + startPos;
  mLength = XPCOM_MIN(length, strLength - startPos);

  SetDataFlags(F_NONE);
}
void
nsTDependentSubstring_CharT::Rebind( const substring_type& str, PRUint32 startPos, PRUint32 length )
  {
    // If we currently own a buffer, release it.
    Finalize();

    size_type strLength = str.Length();

    if (startPos > strLength)
      startPos = strLength;

    mData = NS_CONST_CAST(char_type*, str.Data()) + startPos;
    mLength = NS_MIN(length, strLength - startPos);

    SetDataFlags(F_NONE);
  }
void
nsTDependentSubstring_CharT::Rebind( const abstract_string_type& readable, PRUint32 startPos, PRUint32 length )
  {
    // If we currently own a buffer, release it.
    Finalize();

    size_type strLength = readable.GetReadableBuffer((const char_type**) &mData);

    if (startPos > strLength)
      startPos = strLength;

    mData += startPos;
    mLength = NS_MIN(length, strLength - startPos);

    SetDataFlags(F_NONE);
  }
Example #10
0
PRBool
nsTSubstring_CharT::SetCapacity( size_type capacity )
  {
    // capacity does not include room for the terminating null char

    // if our capacity is reduced to zero, then free our buffer.
    if (capacity == 0)
      {
        ::ReleaseData(mData, mFlags);
        mData = char_traits::sEmptyBuffer;
        mLength = 0;
        SetDataFlags(F_TERMINATED);
      }
    else
      {
        char_type* oldData;
        PRUint32 oldFlags;
        if (!MutatePrep(capacity, &oldData, &oldFlags))
          return PR_FALSE; // out-of-memory

        // compute new string length
        size_type newLen = NS_MIN(mLength, capacity);

        if (oldData)
          {
            // preserve old data
            if (mLength > 0)
              char_traits::copy(mData, oldData, newLen);

            ::ReleaseData(oldData, oldFlags);
          }

        // adjust mLength if our buffer shrunk down in size
        if (newLen < mLength)
          mLength = newLen;

        // always null-terminate here, even if the buffer got longer.  this is
        // for backwards compat with the old string implementation.
        mData[capacity] = char_type(0);
      }

    return PR_TRUE;
  }
void
nsTDependentString_CharT::Rebind(const string_type& str, uint32_t startPos)
{
  NS_ABORT_IF_FALSE(str.Flags() & F_TERMINATED, "Unterminated flat string");

  // If we currently own a buffer, release it.
  Finalize();

  size_type strLength = str.Length();

  if (startPos > strLength) {
    startPos = strLength;
  }

  mData = const_cast<char_type*>(static_cast<const char_type*>(str.Data())) + startPos;
  mLength = strLength - startPos;

  SetDataFlags(str.Flags() & (F_TERMINATED | F_LITERAL));
}
bool
nsTSubstring_CharT::Assign( const self_type& str, const fallible_t& )
  {
    // |str| could be sharable.  we need to check its flags to know how to
    // deal with it.

    if (&str == this)
      return true;

    if (!str.mLength)
      {
        Truncate();
        mFlags |= str.mFlags & F_VOIDED;
        return true;
      }

    if (str.mFlags & F_SHARED)
      {
        // nice! we can avoid a string copy :-)

        // |str| should be null-terminated
        NS_ASSERTION(str.mFlags & F_TERMINATED, "shared, but not terminated");

        ::ReleaseData(mData, mFlags);

        mData = str.mData;
        mLength = str.mLength;
        SetDataFlags(F_TERMINATED | F_SHARED);

        // get an owning reference to the mData
        nsStringBuffer::FromData(mData)->AddRef();
        return true;
      }

    // else, treat this like an ordinary assignment.
    return Assign(str.Data(), str.Length(), fallible_t());
  }
  /**
   * this function is called to prepare mData for writing.  the given capacity
   * indicates the required minimum storage size for mData, in sizeof(char_type)
   * increments.  this function returns true if the operation succeeds.  it also
   * returns the old data and old flags members if mData is newly allocated.
   * the old data must be released by the caller.
   */
bool
nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, uint32_t* oldFlags )
  {
    // initialize to no old data
    *oldData = nullptr;
    *oldFlags = 0;

    size_type curCapacity = Capacity();

    // If |capacity > kMaxCapacity|, then our doubling algorithm may not be
    // able to allocate it.  Just bail out in cases like that.  We don't want
    // to be allocating 2GB+ strings anyway.
    PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
    const size_type kMaxCapacity =
      (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
    if (capacity > kMaxCapacity) {
      // Also assert for |capacity| equal to |size_type(-1)|, since we used to
      // use that value to flag immutability.
      NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
      return false;
    }

    // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we
    // need to allocate a new buffer. We cannot use the existing buffer even
    // though it might be large enough.

    if (curCapacity != 0)
      {
        if (capacity <= curCapacity) {
          mFlags &= ~F_VOIDED;  // mutation clears voided flag
          return true;
        }

        // Use doubling algorithm when forced to increase available capacity.
        size_type temp = curCapacity;
        while (temp < capacity)
          temp <<= 1;
        NS_ASSERTION(XPCOM_MIN(temp, kMaxCapacity) >= capacity,
                     "should have hit the early return at the top");
        capacity = XPCOM_MIN(temp, kMaxCapacity);
      }

    //
    // several cases:
    //
    //  (1) we have a shared buffer (mFlags & F_SHARED)
    //  (2) we have an owned buffer (mFlags & F_OWNED)
    //  (3) we have a fixed buffer (mFlags & F_FIXED)
    //  (4) we have a readonly buffer
    //
    // requiring that we in some cases preserve the data before creating
    // a new buffer complicates things just a bit ;-)
    //

    size_type storageSize = (capacity + 1) * sizeof(char_type);

    // case #1
    if (mFlags & F_SHARED)
      {
        nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
        if (!hdr->IsReadonly())
          {
            nsStringBuffer *newHdr = nsStringBuffer::Realloc(hdr, storageSize);
            if (!newHdr)
              return false; // out-of-memory (original header left intact)

            hdr = newHdr;
            mData = (char_type*) hdr->Data();
            mFlags &= ~F_VOIDED;  // mutation clears voided flag
            return true;
          }
      }

    char_type* newData;
    uint32_t newDataFlags;

      // if we have a fixed buffer of sufficient size, then use it.  this helps
      // avoid heap allocations.
    if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity))
      {
        newData = AsFixedString(this)->mFixedBuf;
        newDataFlags = F_TERMINATED | F_FIXED;
      }
    else
      {
        // if we reach here then, we must allocate a new buffer.  we cannot
        // make use of our F_OWNED or F_FIXED buffers because they are not
        // large enough.

        nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize);
        if (!newHdr)
          return false; // we are still in a consistent state

        newData = (char_type*) newHdr->Data();
        newDataFlags = F_TERMINATED | F_SHARED;
      }

    // save old data and flags
    *oldData = mData;
    *oldFlags = mFlags;

    mData = newData;
    SetDataFlags(newDataFlags);

    // mLength does not change

    // though we are not necessarily terminated at the moment, now is probably
    // still the best time to set F_TERMINATED.

    return true;
  }
Example #14
0
  /**
   * this function is called to prepare mData for writing.  the given capacity
   * indicates the required minimum storage size for mData, in sizeof(char_type)
   * increments.  this function returns true if the operation succeeds.  it also
   * returns the old data and old flags members if mData is newly allocated.
   * the old data must be released by the caller.
   */
PRBool
nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint32* oldFlags )
  {
    // initialize to no old data
    *oldData = nsnull;
    *oldFlags = 0;

    size_type curCapacity = Capacity();

    // |curCapacity == size_type(-1)| means that the buffer is immutable, so we
    // need to allocate a new buffer.  we cannot use the existing buffer even
    // though it might be large enough.

    if (curCapacity != size_type(-1))
      {
        if (capacity <= curCapacity)
          return PR_TRUE;

        if (curCapacity > 0)
          {
            // use doubling algorithm when forced to increase available capacity,
            // but always start out with exactly the requested amount.
            PRUint32 temp = curCapacity;
            while (temp < capacity)
              temp <<= 1;
            capacity = temp;
          }
      }

    //
    // several cases:
    //
    //  (1) we have a shared buffer (mFlags & F_SHARED)
    //  (2) we have an owned buffer (mFlags & F_OWNED)
    //  (3) we have a fixed buffer (mFlags & F_FIXED)
    //  (4) we have a readonly buffer
    //
    // requiring that we in some cases preserve the data before creating
    // a new buffer complicates things just a bit ;-)
    //

    size_type storageSize = (capacity + 1) * sizeof(char_type);

    // case #1
    if (mFlags & F_SHARED)
      {
        nsStringHeader* hdr = nsStringHeader::FromData(mData);
        if (!hdr->IsReadonly())
          {
            nsStringHeader *newHdr = nsStringHeader::Realloc(hdr, storageSize);
            if (newHdr)
              {
                hdr = newHdr;
                mData = (char_type*) hdr->Data();
                return PR_TRUE;
              }
            hdr->Release();
            // out of memory!!  put us in a consistent state at least.
            mData = NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer);
            mLength = 0;
            SetDataFlags(F_TERMINATED);
            return PR_FALSE;
          }