1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsSegmentedBuffer.h"
39 : #include "nsCRT.h"
40 :
41 : nsresult
42 26451 : nsSegmentedBuffer::Init(PRUint32 segmentSize, PRUint32 maxSize,
43 : nsIMemory* allocator)
44 : {
45 26451 : if (mSegmentArrayCount != 0)
46 0 : return NS_ERROR_FAILURE; // initialized more than once
47 26451 : mSegmentSize = segmentSize;
48 26451 : mMaxSize = maxSize;
49 26451 : mSegAllocator = allocator;
50 26451 : if (mSegAllocator == nsnull) {
51 26450 : mSegAllocator = nsMemory::GetGlobalMemoryService();
52 : }
53 : else {
54 1 : NS_ADDREF(mSegAllocator);
55 : }
56 : #if 0 // testing...
57 : mSegmentArrayCount = 2;
58 : #else
59 26451 : mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
60 : #endif
61 26451 : return NS_OK;
62 : }
63 :
64 : char*
65 3683029 : nsSegmentedBuffer::AppendNewSegment()
66 : {
67 3683029 : if (GetSize() >= mMaxSize)
68 31 : return nsnull;
69 :
70 3682998 : if (mSegmentArray == nsnull) {
71 23713 : PRUint32 bytes = mSegmentArrayCount * sizeof(char*);
72 23713 : mSegmentArray = (char**)nsMemory::Alloc(bytes);
73 23713 : if (mSegmentArray == nsnull)
74 0 : return nsnull;
75 23713 : memset(mSegmentArray, 0, bytes);
76 : }
77 :
78 3682998 : if (IsFull()) {
79 23851 : PRUint32 newArraySize = mSegmentArrayCount * 2;
80 23851 : PRUint32 bytes = newArraySize * sizeof(char*);
81 23851 : char** newSegArray = (char**)nsMemory::Realloc(mSegmentArray, bytes);
82 23851 : if (newSegArray == nsnull)
83 0 : return nsnull;
84 23851 : mSegmentArray = newSegArray;
85 : // copy wrapped content to new extension
86 23851 : if (mFirstSegmentIndex > mLastSegmentIndex) {
87 : // deal with wrap around case
88 2 : memcpy(&mSegmentArray[mSegmentArrayCount],
89 : mSegmentArray,
90 4 : mLastSegmentIndex * sizeof(char*));
91 2 : memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*));
92 2 : mLastSegmentIndex += mSegmentArrayCount;
93 2 : memset(&mSegmentArray[mLastSegmentIndex], 0,
94 4 : (newArraySize - mLastSegmentIndex) * sizeof(char*));
95 : }
96 : else {
97 23849 : memset(&mSegmentArray[mLastSegmentIndex], 0,
98 47698 : (newArraySize - mLastSegmentIndex) * sizeof(char*));
99 : }
100 23851 : mSegmentArrayCount = newArraySize;
101 : }
102 :
103 3682998 : char* seg = (char*)mSegAllocator->Alloc(mSegmentSize);
104 3682998 : if (seg == nsnull) {
105 0 : return nsnull;
106 : }
107 3682998 : mSegmentArray[mLastSegmentIndex] = seg;
108 3682998 : mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1);
109 3682998 : return seg;
110 : }
111 :
112 : bool
113 1112 : nsSegmentedBuffer::DeleteFirstSegment()
114 : {
115 1112 : NS_ASSERTION(mSegmentArray[mFirstSegmentIndex] != nsnull, "deleting bad segment");
116 1112 : (void)mSegAllocator->Free(mSegmentArray[mFirstSegmentIndex]);
117 1112 : mSegmentArray[mFirstSegmentIndex] = nsnull;
118 1112 : PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
119 1112 : if (mFirstSegmentIndex == last) {
120 132 : mLastSegmentIndex = last;
121 132 : return true;
122 : }
123 : else {
124 980 : mFirstSegmentIndex = ModSegArraySize(mFirstSegmentIndex + 1);
125 980 : return false;
126 : }
127 : }
128 :
129 : bool
130 310 : nsSegmentedBuffer::DeleteLastSegment()
131 : {
132 310 : PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
133 310 : NS_ASSERTION(mSegmentArray[last] != nsnull, "deleting bad segment");
134 310 : (void)mSegAllocator->Free(mSegmentArray[last]);
135 310 : mSegmentArray[last] = nsnull;
136 310 : mLastSegmentIndex = last;
137 310 : return (bool)(mLastSegmentIndex == mFirstSegmentIndex);
138 : }
139 :
140 : bool
141 8121 : nsSegmentedBuffer::ReallocLastSegment(size_t newSize)
142 : {
143 8121 : PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1);
144 8121 : NS_ASSERTION(mSegmentArray[last] != nsnull, "realloc'ing bad segment");
145 : char *newSegment =
146 8121 : (char*)mSegAllocator->Realloc(mSegmentArray[last], newSize);
147 8121 : if (newSegment) {
148 8121 : mSegmentArray[last] = newSegment;
149 8121 : return true;
150 : } else {
151 0 : return false;
152 : }
153 : }
154 :
155 : void
156 26437 : nsSegmentedBuffer::Empty()
157 : {
158 26437 : if (mSegmentArray) {
159 5897695 : for (PRUint32 i = 0; i < mSegmentArrayCount; i++) {
160 5873984 : if (mSegmentArray[i])
161 3681574 : mSegAllocator->Free(mSegmentArray[i]);
162 : }
163 23711 : nsMemory::Free(mSegmentArray);
164 23711 : mSegmentArray = nsnull;
165 : }
166 26437 : mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
167 26437 : mFirstSegmentIndex = mLastSegmentIndex = 0;
168 26437 : }
169 :
170 : #if 0
171 : void
172 : TestSegmentedBuffer()
173 : {
174 : nsSegmentedBuffer* buf = new nsSegmentedBuffer();
175 : NS_ASSERTION(buf, "out of memory");
176 : buf->Init(4, 16);
177 : char* seg;
178 : bool empty;
179 : seg = buf->AppendNewSegment();
180 : NS_ASSERTION(seg, "AppendNewSegment failed");
181 : seg = buf->AppendNewSegment();
182 : NS_ASSERTION(seg, "AppendNewSegment failed");
183 : seg = buf->AppendNewSegment();
184 : NS_ASSERTION(seg, "AppendNewSegment failed");
185 : empty = buf->DeleteFirstSegment();
186 : NS_ASSERTION(!empty, "DeleteFirstSegment failed");
187 : empty = buf->DeleteFirstSegment();
188 : NS_ASSERTION(!empty, "DeleteFirstSegment failed");
189 : seg = buf->AppendNewSegment();
190 : NS_ASSERTION(seg, "AppendNewSegment failed");
191 : seg = buf->AppendNewSegment();
192 : NS_ASSERTION(seg, "AppendNewSegment failed");
193 : seg = buf->AppendNewSegment();
194 : NS_ASSERTION(seg, "AppendNewSegment failed");
195 : empty = buf->DeleteFirstSegment();
196 : NS_ASSERTION(!empty, "DeleteFirstSegment failed");
197 : empty = buf->DeleteFirstSegment();
198 : NS_ASSERTION(!empty, "DeleteFirstSegment failed");
199 : empty = buf->DeleteFirstSegment();
200 : NS_ASSERTION(!empty, "DeleteFirstSegment failed");
201 : empty = buf->DeleteFirstSegment();
202 : NS_ASSERTION(empty, "DeleteFirstSegment failed");
203 : delete buf;
204 : }
205 : #endif
206 :
207 : ////////////////////////////////////////////////////////////////////////////////
|