VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/sg.cpp@ 59745

Last change on this file since 59745 was 59745, checked in by vboxsync, 9 years ago

sg.cpp/h: Some cleanups/optimizations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1/* $Id: sg.cpp 59745 2016-02-19 21:54:11Z vboxsync $ */
2/** @file
3 * IPRT - S/G buffer handling.
4 */
5
6/*
7 * Copyright (C) 2010-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/sg.h>
32#include <iprt/string.h>
33#include <iprt/assert.h>
34#include <iprt/asm.h>
35
36
37static void *rtSgBufGet(PRTSGBUF pSgBuf, size_t *pcbData)
38{
39 size_t cbData;
40 void *pvBuf;
41
42 /* Check that the S/G buffer has memory left. */
43 if (RT_UNLIKELY( pSgBuf->idxSeg == pSgBuf->cSegs
44 && !pSgBuf->cbSegLeft))
45 {
46 *pcbData = 0;
47 return NULL;
48 }
49
50#ifndef RDESKTOP
51 AssertMsg( pSgBuf->cbSegLeft <= 128 * _1M
52 && (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg
53 && (uintptr_t)pSgBuf->pvSegCur + pSgBuf->cbSegLeft <= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg + pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg,
54 ("pSgBuf->idxSeg=%d pSgBuf->cSegs=%d pSgBuf->pvSegCur=%p pSgBuf->cbSegLeft=%zd pSgBuf->paSegs[%d].pvSeg=%p pSgBuf->paSegs[%d].cbSeg=%zd\n",
55 pSgBuf->idxSeg, pSgBuf->cSegs, pSgBuf->pvSegCur, pSgBuf->cbSegLeft, pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg,
56 pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg));
57#endif
58
59 cbData = RT_MIN(*pcbData, pSgBuf->cbSegLeft);
60 pvBuf = pSgBuf->pvSegCur;
61 pSgBuf->cbSegLeft -= cbData;
62
63 /* Advance to the next segment if required. */
64 if (!pSgBuf->cbSegLeft)
65 {
66 pSgBuf->idxSeg++;
67
68 if (pSgBuf->idxSeg < pSgBuf->cSegs)
69 {
70 pSgBuf->pvSegCur = pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg;
71 pSgBuf->cbSegLeft = pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg;
72 }
73
74 *pcbData = cbData;
75 }
76 else
77 pSgBuf->pvSegCur = (uint8_t *)pSgBuf->pvSegCur + cbData;
78
79 return pvBuf;
80}
81
82
83RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs)
84{
85 AssertPtr(pSgBuf);
86 AssertPtr(paSegs);
87 Assert(cSegs > 0);
88 Assert(cSegs < (~(unsigned)0 >> 1));
89
90 pSgBuf->paSegs = paSegs;
91 pSgBuf->cSegs = (unsigned)cSegs;
92 pSgBuf->idxSeg = 0;
93 pSgBuf->pvSegCur = paSegs[0].pvSeg;
94 pSgBuf->cbSegLeft = paSegs[0].cbSeg;
95}
96
97
98RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf)
99{
100 AssertPtrReturnVoid(pSgBuf);
101
102 pSgBuf->idxSeg = 0;
103 pSgBuf->pvSegCur = pSgBuf->paSegs[0].pvSeg;
104 pSgBuf->cbSegLeft = pSgBuf->paSegs[0].cbSeg;
105}
106
107
108RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufTo, PCRTSGBUF pSgBufFrom)
109{
110 AssertPtr(pSgBufTo);
111 AssertPtr(pSgBufFrom);
112
113 pSgBufTo->paSegs = pSgBufFrom->paSegs;
114 pSgBufTo->cSegs = pSgBufFrom->cSegs;
115 pSgBufTo->idxSeg = pSgBufFrom->idxSeg;
116 pSgBufTo->pvSegCur = pSgBufFrom->pvSegCur;
117 pSgBufTo->cbSegLeft = pSgBufFrom->cbSegLeft;
118}
119
120
121RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg)
122{
123 AssertPtrReturn(pSgBuf, NULL);
124 AssertPtrReturn(pcbSeg, NULL);
125
126 if (!*pcbSeg)
127 *pcbSeg = pSgBuf->cbSegLeft;
128
129 return rtSgBufGet(pSgBuf, pcbSeg);
130}
131
132
133RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy)
134{
135 AssertPtrReturn(pSgBufDst, 0);
136 AssertPtrReturn(pSgBufSrc, 0);
137
138 size_t cbLeft = cbCopy;
139 while (cbLeft)
140 {
141 size_t cbThisCopy = RT_MIN(RT_MIN(pSgBufDst->cbSegLeft, cbLeft), pSgBufSrc->cbSegLeft);
142 if (!cbThisCopy)
143 break;
144
145 size_t cbTmp = cbThisCopy;
146 void *pvBufDst = rtSgBufGet(pSgBufDst, &cbTmp);
147 Assert(cbTmp == cbThisCopy);
148 void *pvBufSrc = rtSgBufGet(pSgBufSrc, &cbTmp);
149 Assert(cbTmp == cbThisCopy);
150
151 memcpy(pvBufDst, pvBufSrc, cbThisCopy);
152
153 cbLeft -= cbThisCopy;
154 }
155
156 return cbCopy - cbLeft;
157}
158
159
160RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp)
161{
162 AssertPtrReturn(pSgBuf1, 0);
163 AssertPtrReturn(pSgBuf2, 0);
164
165 /* Set up the temporary buffers */
166 RTSGBUF SgBuf1;
167 RTSgBufClone(&SgBuf1, pSgBuf1);
168 RTSGBUF SgBuf2;
169 RTSgBufClone(&SgBuf2, pSgBuf2);
170
171 size_t cbLeft = cbCmp;
172 while (cbLeft)
173 {
174 size_t cbThisCmp = RT_MIN(RT_MIN(SgBuf1.cbSegLeft, cbLeft), SgBuf2.cbSegLeft);
175 if (!cbThisCmp)
176 break;
177
178 size_t cbTmp = cbThisCmp;
179 void *pvBuf1 = rtSgBufGet(&SgBuf1, &cbTmp);
180 Assert(cbTmp == cbThisCmp);
181 void *pvBuf2 = rtSgBufGet(&SgBuf2, &cbTmp);
182 Assert(cbTmp == cbThisCmp);
183
184 int rc = memcmp(pvBuf1, pvBuf2, cbThisCmp);
185 if (rc)
186 return rc;
187
188 cbLeft -= cbThisCmp;
189 }
190
191 return 0;
192}
193
194
195RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance)
196{
197 AssertPtrReturn(pSgBuf1, 0);
198 AssertPtrReturn(pSgBuf2, 0);
199
200 RTSGBUF SgBuf1Tmp;
201 RTSGBUF SgBuf2Tmp;
202 PRTSGBUF pSgBuf1Tmp;
203 PRTSGBUF pSgBuf2Tmp;
204
205 if (!fAdvance)
206 {
207 /* Set up the temporary buffers */
208 RTSgBufClone(&SgBuf1Tmp, pSgBuf1);
209 RTSgBufClone(&SgBuf2Tmp, pSgBuf2);
210 pSgBuf1Tmp = &SgBuf1Tmp;
211 pSgBuf2Tmp = &SgBuf2Tmp;
212 }
213 else
214 {
215 pSgBuf1Tmp = pSgBuf1;
216 pSgBuf2Tmp = pSgBuf2;
217 }
218
219 size_t cbLeft = cbCmp;
220 size_t off = 0;
221 while (cbLeft)
222 {
223 size_t cbThisCmp = RT_MIN(RT_MIN(pSgBuf1Tmp->cbSegLeft, cbLeft), pSgBuf2Tmp->cbSegLeft);
224 if (!cbThisCmp)
225 break;
226
227 size_t cbTmp = cbThisCmp;
228 uint8_t *pbBuf1 = (uint8_t *)rtSgBufGet(pSgBuf1Tmp, &cbTmp);
229 Assert(cbTmp == cbThisCmp);
230 uint8_t *pbBuf2 = (uint8_t *)rtSgBufGet(pSgBuf2Tmp, &cbTmp);
231 Assert(cbTmp == cbThisCmp);
232
233 int iDiff = memcmp(pbBuf1, pbBuf2, cbThisCmp);
234 if (iDiff)
235 {
236 /* Locate the first byte that differs if the caller requested this. */
237 if (poffDiff)
238 {
239 while ( cbThisCmp-- > 0
240 && *pbBuf1 == *pbBuf2)
241 {
242 pbBuf1++;
243 pbBuf2++;
244 off++;
245 }
246
247 *poffDiff = off;
248 }
249 return iDiff;
250 }
251
252 cbLeft -= cbThisCmp;
253 off += cbThisCmp;
254 }
255
256 return 0;
257}
258
259
260RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet)
261{
262 AssertPtrReturn(pSgBuf, 0);
263
264 size_t cbLeft = cbSet;
265
266 while (cbLeft)
267 {
268 size_t cbThisSet = cbLeft;
269 void *pvBuf = rtSgBufGet(pSgBuf, &cbThisSet);
270
271 if (!cbThisSet)
272 break;
273
274 memset(pvBuf, ubFill, cbThisSet);
275
276 cbLeft -= cbThisSet;
277 }
278
279 return cbSet - cbLeft;
280}
281
282
283RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
284{
285 AssertPtrReturn(pSgBuf, 0);
286 AssertPtrReturn(pvBuf, 0);
287
288 size_t cbLeft = cbCopy;
289
290 while (cbLeft)
291 {
292 size_t cbThisCopy = cbLeft;
293 void *pvSrc = rtSgBufGet(pSgBuf, &cbThisCopy);
294
295 if (!cbThisCopy)
296 break;
297
298 memcpy(pvBuf, pvSrc, cbThisCopy);
299
300 cbLeft -= cbThisCopy;
301 pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy);
302 }
303
304 return cbCopy - cbLeft;
305}
306
307
308RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy)
309{
310 AssertPtrReturn(pSgBuf, 0);
311 AssertPtrReturn(pvBuf, 0);
312
313 size_t cbLeft = cbCopy;
314
315 while (cbLeft)
316 {
317 size_t cbThisCopy = cbLeft;
318 void *pvDst = rtSgBufGet(pSgBuf, &cbThisCopy);
319
320 if (!cbThisCopy)
321 break;
322
323 memcpy(pvDst, pvBuf, cbThisCopy);
324
325 cbLeft -= cbThisCopy;
326 pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy);
327 }
328
329 return cbCopy - cbLeft;
330}
331
332
333RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance)
334{
335 AssertPtrReturn(pSgBuf, 0);
336
337 size_t cbLeft = cbAdvance;
338 while (cbLeft)
339 {
340 size_t cbThisAdvance = cbLeft;
341 rtSgBufGet(pSgBuf, &cbThisAdvance);
342 if (!cbThisAdvance)
343 break;
344
345 cbLeft -= cbThisAdvance;
346 }
347
348 return cbAdvance - cbLeft;
349}
350
351
352RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData)
353{
354 AssertPtrReturn(pSgBuf, 0);
355 AssertPtrReturn(pcSeg, 0);
356
357 unsigned cSeg = 0;
358 size_t cb = 0;
359
360 if (!paSeg)
361 {
362 if (pSgBuf->cbSegLeft > 0)
363 {
364 size_t idx = pSgBuf->idxSeg;
365 cSeg = 1;
366
367 cb += RT_MIN(pSgBuf->cbSegLeft, cbData);
368 cbData -= RT_MIN(pSgBuf->cbSegLeft, cbData);
369
370 while ( cbData
371 && idx < pSgBuf->cSegs - 1)
372 {
373 idx++;
374 cSeg++;
375 cb += RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
376 cbData -= RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
377 }
378 }
379 }
380 else
381 {
382 while ( cbData
383 && cSeg < *pcSeg)
384 {
385 size_t cbThisSeg = cbData;
386 void *pvSeg = rtSgBufGet(pSgBuf, &cbThisSeg);
387
388 if (!cbThisSeg)
389 {
390 Assert(!pvSeg);
391 break;
392 }
393
394 AssertMsg(cbThisSeg <= cbData, ("Impossible!\n"));
395
396 paSeg[cSeg].cbSeg = cbThisSeg;
397 paSeg[cSeg].pvSeg = pvSeg;
398 cSeg++;
399 cbData -= cbThisSeg;
400 cb += cbThisSeg;
401 }
402 }
403
404 *pcSeg = cSeg;
405
406 return cb;
407}
408
409RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck)
410{
411 RTSGBUF SgBufTmp;
412 RTSgBufClone(&SgBufTmp, pSgBuf);
413
414 bool fIsZero = true;
415 size_t cbLeft = cbCheck;
416 while (cbLeft)
417 {
418 size_t cbThisCheck = cbLeft;
419 void *pvBuf = rtSgBufGet(&SgBufTmp, &cbThisCheck);
420 if (!cbThisCheck)
421 break;
422
423/** @todo fix this after asm.h gets updated. */
424 /* Use optimized inline assembler if possible. */
425 if ( !(cbThisCheck % 4)
426 && cbThisCheck * 8 <= UINT32_MAX)
427 {
428 if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbThisCheck * 8) != -1)
429 {
430 fIsZero = false;
431 break;
432 }
433 }
434 else
435 {
436 for (size_t i = 0; i < cbThisCheck; i++)
437 {
438 char *pbBuf = (char *)pvBuf;
439 if (*pbBuf)
440 {
441 fIsZero = false;
442 break;
443 }
444 pvBuf = pbBuf + 1;
445 }
446
447 if (!fIsZero)
448 break;
449 }
450
451 cbLeft -= cbThisCheck;
452 }
453
454 return fIsZero;
455}
456
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette