Back to index

lightning-sunbird  0.9+nobinonly
nsSegmentedBuffer.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsSegmentedBuffer.h"
00039 #include "nsCRT.h"
00040 
00041 nsresult
00042 nsSegmentedBuffer::Init(PRUint32 segmentSize, PRUint32 maxSize,
00043                         nsIMemory* allocator)
00044 {
00045     if (mSegmentArrayCount != 0)
00046         return NS_ERROR_FAILURE;        // initialized more than once
00047     mSegmentSize = segmentSize;
00048     mMaxSize = maxSize;
00049     mSegAllocator = allocator;
00050     if (mSegAllocator == nsnull) {
00051         mSegAllocator = nsMemory::GetGlobalMemoryService();
00052     }
00053     else {
00054         NS_ADDREF(mSegAllocator);
00055     }
00056 #if 0 // testing...
00057     mSegmentArrayCount = 2;
00058 #else
00059     mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
00060 #endif
00061     return NS_OK;
00062 }
00063 
00064 char*
00065 nsSegmentedBuffer::AppendNewSegment()
00066 {
00067     if (GetSize() >= mMaxSize)
00068         return nsnull;
00069 
00070     if (mSegmentArray == nsnull) {
00071         PRUint32 bytes = mSegmentArrayCount * sizeof(char*);
00072         mSegmentArray = (char**)nsMemory::Alloc(bytes);
00073         if (mSegmentArray == nsnull)
00074             return nsnull;
00075         memset(mSegmentArray, 0, bytes);
00076     }
00077     
00078     if (IsFull()) {
00079         PRUint32 newArraySize = mSegmentArrayCount * 2;
00080         PRUint32 bytes = newArraySize * sizeof(char*);
00081         char** newSegArray = (char**)nsMemory::Realloc(mSegmentArray, bytes);
00082         if (newSegArray == nsnull)
00083             return nsnull;
00084         mSegmentArray = newSegArray;
00085         // copy wrapped content to new extension
00086         if (mFirstSegmentIndex > mLastSegmentIndex) {
00087             // deal with wrap around case
00088             memcpy(&mSegmentArray[mSegmentArrayCount],
00089                    mSegmentArray,
00090                    mLastSegmentIndex * sizeof(char*));
00091             memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*));
00092             mLastSegmentIndex += mSegmentArrayCount;
00093             memset(&mSegmentArray[mLastSegmentIndex], 0,
00094                    (newArraySize - mLastSegmentIndex) * sizeof(char*));
00095         }
00096         else {
00097             memset(&mSegmentArray[mLastSegmentIndex], 0,
00098                    (newArraySize - mLastSegmentIndex) * sizeof(char*));
00099         }
00100         mSegmentArrayCount = newArraySize;
00101     }
00102 
00103     char* seg = (char*)mSegAllocator->Alloc(mSegmentSize);
00104     if (seg == nsnull) {
00105         return nsnull;
00106     }
00107     mSegmentArray[mLastSegmentIndex] = seg;
00108     mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1);
00109     return seg;
00110 }
00111 
00112 PRBool
00113 nsSegmentedBuffer::DeleteFirstSegment()
00114 {
00115     NS_ASSERTION(mSegmentArray[mFirstSegmentIndex] != nsnull, "deleting bad segment");
00116     (void)mSegAllocator->Free(mSegmentArray[mFirstSegmentIndex]);
00117     mSegmentArray[mFirstSegmentIndex] = nsnull;
00118     PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
00119     if (mFirstSegmentIndex == last) {
00120         mLastSegmentIndex = last;
00121         return PR_TRUE;
00122     }
00123     else {
00124         mFirstSegmentIndex = ModSegArraySize(mFirstSegmentIndex + 1);
00125         return PR_FALSE;
00126     }
00127 }
00128 
00129 PRBool
00130 nsSegmentedBuffer::DeleteLastSegment()
00131 {
00132     PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
00133     NS_ASSERTION(mSegmentArray[last] != nsnull, "deleting bad segment");
00134     (void)mSegAllocator->Free(mSegmentArray[last]);
00135     mSegmentArray[last] = nsnull;
00136     mLastSegmentIndex = last;
00137     return (PRBool)(mLastSegmentIndex == mFirstSegmentIndex);
00138 }
00139 
00140 PRBool
00141 nsSegmentedBuffer::ReallocLastSegment(size_t newSize)
00142 {
00143     PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
00144     NS_ASSERTION(mSegmentArray[last] != nsnull, "realloc'ing bad segment");
00145     char *newSegment =
00146         (char*)mSegAllocator->Realloc(mSegmentArray[last], newSize);
00147     if (newSegment) {
00148         mSegmentArray[last] = newSegment;
00149         return PR_TRUE;
00150     } else {
00151         return PR_FALSE;
00152     }
00153 }
00154 
00155 void
00156 nsSegmentedBuffer::Empty()
00157 {
00158     if (mSegmentArray) {
00159         for (PRUint32 i = 0; i < mSegmentArrayCount; i++) {
00160             if (mSegmentArray[i])
00161                 mSegAllocator->Free(mSegmentArray[i]);
00162         }
00163         nsMemory::Free(mSegmentArray);
00164         mSegmentArray = nsnull;
00165     }
00166     mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
00167     mFirstSegmentIndex = mLastSegmentIndex = 0;
00168 }
00169 
00170 #ifdef DEBUG
00171 NS_COM void
00172 TestSegmentedBuffer()
00173 {
00174     nsSegmentedBuffer* buf = new nsSegmentedBuffer();
00175     NS_ASSERTION(buf, "out of memory");
00176     buf->Init(4, 16);
00177     char* seg;
00178     PRBool empty;
00179     seg = buf->AppendNewSegment();
00180     NS_ASSERTION(seg, "AppendNewSegment failed");
00181     seg = buf->AppendNewSegment();
00182     NS_ASSERTION(seg, "AppendNewSegment failed");
00183     seg = buf->AppendNewSegment();
00184     NS_ASSERTION(seg, "AppendNewSegment failed");
00185     empty = buf->DeleteFirstSegment();
00186     NS_ASSERTION(!empty, "DeleteFirstSegment failed");
00187     empty = buf->DeleteFirstSegment();
00188     NS_ASSERTION(!empty, "DeleteFirstSegment failed");
00189     seg = buf->AppendNewSegment();
00190     NS_ASSERTION(seg, "AppendNewSegment failed");
00191     seg = buf->AppendNewSegment();
00192     NS_ASSERTION(seg, "AppendNewSegment failed");
00193     seg = buf->AppendNewSegment();
00194     NS_ASSERTION(seg, "AppendNewSegment failed");
00195     empty = buf->DeleteFirstSegment();
00196     NS_ASSERTION(!empty, "DeleteFirstSegment failed");
00197     empty = buf->DeleteFirstSegment();
00198     NS_ASSERTION(!empty, "DeleteFirstSegment failed");
00199     empty = buf->DeleteFirstSegment();
00200     NS_ASSERTION(!empty, "DeleteFirstSegment failed");
00201     empty = buf->DeleteFirstSegment();
00202     NS_ASSERTION(empty, "DeleteFirstSegment failed");
00203     delete buf;
00204 }
00205 #endif
00206