VirtualBox

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

Last change on this file since 51770 was 51770, checked in by vboxsync, 10 years ago

Merged in iprt++ dev branch.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Id: sg.cpp 51770 2014-07-01 18:14:02Z vboxsync $ */
2/** @file
3 * IPRT - S/G buffer handling.
4 */
5
6/*
7 * Copyright (C) 2010-2013 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 *sgBufGet(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 AssertReleaseMsg( pSgBuf->cbSegLeft <= 32 * _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,
56 pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg, 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 sgBufGet(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
140 while (cbLeft)
141 {
142 size_t cbThisCopy = RT_MIN(RT_MIN(pSgBufDst->cbSegLeft, cbLeft), pSgBufSrc->cbSegLeft);
143 size_t cbTmp = cbThisCopy;
144 void *pvBufDst;
145 void *pvBufSrc;
146
147 if (!cbThisCopy)
148 break;
149
150 pvBufDst = sgBufGet(pSgBufDst, &cbTmp);
151 Assert(cbTmp == cbThisCopy);
152 pvBufSrc = sgBufGet(pSgBufSrc, &cbTmp);
153 Assert(cbTmp == cbThisCopy);
154
155 memcpy(pvBufDst, pvBufSrc, cbThisCopy);
156
157 cbLeft -= cbThisCopy;
158 }
159
160 return cbCopy - cbLeft;
161}
162
163
164RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp)
165{
166 AssertPtrReturn(pSgBuf1, 0);
167 AssertPtrReturn(pSgBuf2, 0);
168
169 size_t cbLeft = cbCmp;
170 RTSGBUF SgBuf1;
171 RTSGBUF SgBuf2;
172
173 /* Set up the temporary buffers */
174 RTSgBufClone(&SgBuf1, pSgBuf1);
175 RTSgBufClone(&SgBuf2, pSgBuf2);
176
177 while (cbLeft)
178 {
179 size_t cbThisCmp = RT_MIN(RT_MIN(SgBuf1.cbSegLeft, cbLeft), SgBuf2.cbSegLeft);
180 size_t cbTmp = cbThisCmp;
181 void *pvBuf1;
182 void *pvBuf2;
183
184 if (!cbCmp)
185 break;
186
187 pvBuf1 = sgBufGet(&SgBuf1, &cbTmp);
188 Assert(cbTmp == cbThisCmp);
189 pvBuf2 = sgBufGet(&SgBuf2, &cbTmp);
190 Assert(cbTmp == cbThisCmp);
191
192 int rc = memcmp(pvBuf1, pvBuf2, cbThisCmp);
193 if (rc)
194 return rc;
195
196 cbLeft -= cbThisCmp;
197 }
198
199 return 0;
200}
201
202
203RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp,
204 size_t *pcbOff, bool fAdvance)
205{
206 AssertPtrReturn(pSgBuf1, 0);
207 AssertPtrReturn(pSgBuf2, 0);
208
209 size_t cbLeft = cbCmp;
210 size_t cbOff = 0;
211 RTSGBUF SgBuf1Tmp;
212 RTSGBUF SgBuf2Tmp;
213 PRTSGBUF pSgBuf1Tmp;
214 PRTSGBUF pSgBuf2Tmp;
215
216 if (!fAdvance)
217 {
218 /* Set up the temporary buffers */
219 RTSgBufClone(&SgBuf1Tmp, pSgBuf1);
220 RTSgBufClone(&SgBuf2Tmp, pSgBuf2);
221 pSgBuf1Tmp = &SgBuf1Tmp;
222 pSgBuf2Tmp = &SgBuf2Tmp;
223 }
224 else
225 {
226 pSgBuf1Tmp = pSgBuf1;
227 pSgBuf2Tmp = pSgBuf2;
228 }
229
230 while (cbLeft)
231 {
232 size_t cbThisCmp = RT_MIN(RT_MIN(pSgBuf1Tmp->cbSegLeft, cbLeft), pSgBuf2Tmp->cbSegLeft);
233 size_t cbTmp = cbThisCmp;
234 uint8_t *pbBuf1;
235 uint8_t *pbBuf2;
236
237 if (!cbCmp)
238 break;
239
240 pbBuf1 = (uint8_t *)sgBufGet(pSgBuf1Tmp, &cbTmp);
241 Assert(cbTmp == cbThisCmp);
242 pbBuf2 = (uint8_t *)sgBufGet(pSgBuf2Tmp, &cbTmp);
243 Assert(cbTmp == cbThisCmp);
244
245 int rc = memcmp(pbBuf1, pbBuf2, cbThisCmp);
246 if (rc)
247 {
248 if (pcbOff)
249 {
250 /* Search for the correct offset */
251 while ( cbThisCmp-- > 0
252 && (*pbBuf1 == *pbBuf2))
253 {
254 pbBuf1++;
255 pbBuf2++;
256 cbOff++;
257 }
258
259 *pcbOff = cbOff;
260 }
261 return rc;
262 }
263
264 cbLeft -= cbThisCmp;
265 cbOff += cbThisCmp;
266 }
267
268 return 0;
269}
270
271
272RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet)
273{
274 AssertPtrReturn(pSgBuf, 0);
275
276 size_t cbLeft = cbSet;
277
278 while (cbLeft)
279 {
280 size_t cbThisSet = cbLeft;
281 void *pvBuf = sgBufGet(pSgBuf, &cbThisSet);
282
283 if (!cbThisSet)
284 break;
285
286 memset(pvBuf, ubFill, cbThisSet);
287
288 cbLeft -= cbThisSet;
289 }
290
291 return cbSet - cbLeft;
292}
293
294
295RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
296{
297 AssertPtrReturn(pSgBuf, 0);
298 AssertPtrReturn(pvBuf, 0);
299
300 size_t cbLeft = cbCopy;
301
302 while (cbLeft)
303 {
304 size_t cbThisCopy = cbLeft;
305 void *pvSrc = sgBufGet(pSgBuf, &cbThisCopy);
306
307 if (!cbThisCopy)
308 break;
309
310 memcpy(pvBuf, pvSrc, cbThisCopy);
311
312 cbLeft -= cbThisCopy;
313 pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy);
314 }
315
316 return cbCopy - cbLeft;
317}
318
319
320RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy)
321{
322 AssertPtrReturn(pSgBuf, 0);
323 AssertPtrReturn(pvBuf, 0);
324
325 size_t cbLeft = cbCopy;
326
327 while (cbLeft)
328 {
329 size_t cbThisCopy = cbLeft;
330 void *pvDst = sgBufGet(pSgBuf, &cbThisCopy);
331
332 if (!cbThisCopy)
333 break;
334
335 memcpy(pvDst, pvBuf, cbThisCopy);
336
337 cbLeft -= cbThisCopy;
338 pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy);
339 }
340
341 return cbCopy - cbLeft;
342}
343
344
345RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance)
346{
347 AssertPtrReturn(pSgBuf, 0);
348
349 size_t cbLeft = cbAdvance;
350
351 while (cbLeft)
352 {
353 size_t cbThisAdvance = cbLeft;
354 void *pv = sgBufGet(pSgBuf, &cbThisAdvance);
355
356 NOREF(pv);
357
358 if (!cbThisAdvance)
359 break;
360
361 cbLeft -= cbThisAdvance;
362 }
363
364 return cbAdvance - cbLeft;
365}
366
367
368RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData)
369{
370 AssertPtrReturn(pSgBuf, 0);
371 AssertPtrReturn(pcSeg, 0);
372
373 unsigned cSeg = 0;
374 size_t cb = 0;
375
376 if (!paSeg)
377 {
378 if (pSgBuf->cbSegLeft > 0)
379 {
380 size_t idx = pSgBuf->idxSeg;
381 cSeg = 1;
382
383 cb += RT_MIN(pSgBuf->cbSegLeft, cbData);
384 cbData -= RT_MIN(pSgBuf->cbSegLeft, cbData);
385
386 while ( cbData
387 && idx < pSgBuf->cSegs - 1)
388 {
389 idx++;
390 cSeg++;
391 cb += RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
392 cbData -= RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
393 }
394 }
395 }
396 else
397 {
398 while ( cbData
399 && cSeg < *pcSeg)
400 {
401 size_t cbThisSeg = cbData;
402 void *pvSeg = NULL;
403
404 pvSeg = sgBufGet(pSgBuf, &cbThisSeg);
405
406 if (!cbThisSeg)
407 {
408 Assert(!pvSeg);
409 break;
410 }
411
412 AssertMsg(cbThisSeg <= cbData, ("Impossible!\n"));
413
414 paSeg[cSeg].cbSeg = cbThisSeg;
415 paSeg[cSeg].pvSeg = pvSeg;
416 cSeg++;
417 cbData -= cbThisSeg;
418 cb += cbThisSeg;
419 }
420 }
421
422 *pcSeg = cSeg;
423
424 return cb;
425}
426
427RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck)
428{
429 bool fIsZero = true;
430 size_t cbLeft = cbCheck;
431 RTSGBUF SgBufTmp;
432
433 RTSgBufClone(&SgBufTmp, pSgBuf);
434
435 while (cbLeft)
436 {
437 size_t cbThisCheck = cbLeft;
438 void *pvBuf = sgBufGet(&SgBufTmp, &cbThisCheck);
439
440 if (!cbThisCheck)
441 break;
442
443 /* Use optimized inline assembler if possible. */
444 if ( !(cbThisCheck % 4)
445 && (cbThisCheck * 8 <= UINT32_MAX))
446 {
447 if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbThisCheck * 8) != -1)
448 {
449 fIsZero = false;
450 break;
451 }
452 }
453 else
454 {
455 for (unsigned i = 0; i < cbThisCheck; i++)
456 {
457 char *pbBuf = (char *)pvBuf;
458 if (*pbBuf)
459 {
460 fIsZero = false;
461 break;
462 }
463 pvBuf = pbBuf + 1;
464 }
465
466 if (!fIsZero)
467 break;
468 }
469
470 cbLeft -= cbThisCheck;
471 }
472
473 return fIsZero;
474}
475
Note: See TracBrowser for help on using the repository browser.

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