VirtualBox

source: vbox/trunk/include/iprt/sg.h@ 91991

Last change on this file since 91991 was 89264, checked in by vboxsync, 4 years ago

Runtime/sg.h: Add copy variants which take a callback instead of a buffer to do the actual copying for single segments, bugref:4841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/** @file
2 * IPRT - S/G buffer handling.
3 */
4
5/*
6 * Copyright (C) 2010-2020 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef IPRT_INCLUDED_sg_h
27#define IPRT_INCLUDED_sg_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <iprt/types.h>
33
34RT_C_DECLS_BEGIN
35
36/** @defgroup grp_rt_sgbuf RTSgBuf - Scatter / Gather Buffers
37 * @ingroup grp_rt
38 * @{
39 */
40
41/** Pointer to a const S/G entry. */
42typedef const struct RTSGBUF *PCRTSGBUF;
43
44/**
45 * Callback for RTSgBufCopyToFn() called on every segment of the given S/G buffer.
46 *
47 * @returns Number of bytes copied for this segment, a value smaller than cbSrc will stop the copy operation.
48 * @param pSgBuf The S/G buffer for reference.
49 * @param pvSrc Where to copy from.
50 * @param cbSrc The number of bytes in the source buffer.
51 * @param pvUser Opaque user data passed in RTSgBufCopyToFn().
52 */
53typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYTO, (PCRTSGBUF pSgBuf, const void *pvSrc, size_t cbSrc, void *pvUser));
54/** Pointer to a FNRTSGBUFCOPYTO. */
55typedef FNRTSGBUFCOPYTO *PFNRTSGBUFCOPYTO;
56
57/**
58 * Callback for RTSgBufCopyFromFn() called on every segment of the given S/G buffer.
59 *
60 * @returns Number of bytes copied for this segment, a value smaller than cbDst will stop the copy operation.
61 * @param pSgBuf The S/G buffer for reference.
62 * @param pvDst Where to copy to.
63 * @param cbDst The number of bytes in the destination buffer.
64 * @param pvUser Opaque user data passed in RTSgBufCopyFromFn().
65 */
66typedef DECLCALLBACKTYPE(size_t, FNRTSGBUFCOPYFROM, (PCRTSGBUF pSgBuf, void *pvDst, size_t cbDst, void *pvUser));
67/** Pointer to a FNRTSGBUFCOPYFROM. */
68typedef FNRTSGBUFCOPYFROM *PFNRTSGBUFCOPYFROM;
69
70/**
71 * A S/G entry.
72 */
73typedef struct RTSGSEG
74{
75 /** Pointer to the segment buffer. */
76 void *pvSeg;
77 /** Size of the segment buffer. */
78 size_t cbSeg;
79} RTSGSEG;
80/** Pointer to a S/G entry. */
81typedef RTSGSEG *PRTSGSEG;
82/** Pointer to a const S/G entry. */
83typedef const RTSGSEG *PCRTSGSEG;
84/** Pointer to a S/G entry pointer. */
85typedef PRTSGSEG *PPRTSGSEG;
86
87/**
88 * A S/G buffer.
89 *
90 * The members should be treated as private.
91 *
92 * @warning There is a lot of code, especially in the VFS area of IPRT, that
93 * totally ignores the idxSeg, pvSegCur and cbSegLeft members! So,
94 * it is not recommended to pass buffers that aren't fully reset or
95 * where cbSegLeft is shorter than what paSegs describes.
96 */
97typedef struct RTSGBUF
98{
99 /** Pointer to the scatter/gather array. */
100 PCRTSGSEG paSegs;
101 /** Number of segments. */
102 unsigned cSegs;
103
104 /** Current segment we are in. */
105 unsigned idxSeg;
106 /** Pointer to current byte within the current segment. */
107 void *pvSegCur;
108 /** Number of bytes left in the current segment. */
109 size_t cbSegLeft;
110} RTSGBUF;
111/** Pointer to a S/G entry. */
112typedef RTSGBUF *PRTSGBUF;
113/** Pointer to a S/G entry pointer. */
114typedef PRTSGBUF *PPRTSGBUF;
115
116
117/**
118 * Sums up the length of all the segments.
119 *
120 * @returns The complete segment length.
121 * @param pSgBuf The S/G buffer to check out.
122 */
123DECLINLINE(size_t) RTSgBufCalcTotalLength(PCRTSGBUF pSgBuf)
124{
125 size_t cb = 0;
126 unsigned i = pSgBuf->cSegs;
127 while (i-- > 0)
128 cb += pSgBuf->paSegs[i].cbSeg;
129 return cb;
130}
131
132/**
133 * Sums up the number of bytes left from the current position.
134 *
135 * @returns Number of bytes left.
136 * @param pSgBuf The S/G buffer to check out.
137 */
138DECLINLINE(size_t) RTSgBufCalcLengthLeft(PCRTSGBUF pSgBuf)
139{
140 size_t cb = pSgBuf->cbSegLeft;
141 unsigned i = pSgBuf->cSegs;
142 while (i-- > pSgBuf->idxSeg + 1)
143 cb += pSgBuf->paSegs[i].cbSeg;
144 return cb;
145}
146
147/**
148 * Checks if the current buffer position is at the start of the first segment.
149 *
150 * @returns true / false.
151 * @param pSgBuf The S/G buffer to check out.
152 */
153DECLINLINE(bool) RTSgBufIsAtStart(PCRTSGBUF pSgBuf)
154{
155 return pSgBuf->idxSeg == 0
156 && ( pSgBuf->cSegs == 0
157 || pSgBuf->pvSegCur == pSgBuf->paSegs[0].pvSeg);
158}
159
160/**
161 * Checks if the current buffer position is at the end of all the segments.
162 *
163 * @returns true / false.
164 * @param pSgBuf The S/G buffer to check out.
165 */
166DECLINLINE(bool) RTSgBufIsAtEnd(PCRTSGBUF pSgBuf)
167{
168 return pSgBuf->idxSeg > pSgBuf->cSegs
169 || ( pSgBuf->idxSeg == pSgBuf->cSegs
170 && pSgBuf->cbSegLeft == 0);
171}
172
173/**
174 * Checks if the current buffer position is at the start of the current segment.
175 *
176 * @returns true / false.
177 * @param pSgBuf The S/G buffer to check out.
178 */
179DECLINLINE(bool) RTSgBufIsAtStartOfSegment(PCRTSGBUF pSgBuf)
180{
181 return pSgBuf->idxSeg < pSgBuf->cSegs
182 && pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg == pSgBuf->pvSegCur;
183}
184
185/**
186 * Initialize a S/G buffer structure.
187 *
188 * @returns nothing.
189 * @param pSgBuf Pointer to the S/G buffer to initialize.
190 * @param paSegs Pointer to the start of the segment array.
191 * @param cSegs Number of segments in the array.
192 *
193 * @note paSegs and cSegs can be NULL and 0 respectively to indicate an empty
194 * S/G buffer. Operations on the S/G buffer will not do anything in this
195 * case.
196 */
197RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs);
198
199/**
200 * Resets the internal buffer position of the S/G buffer to the beginning.
201 *
202 * @returns nothing.
203 * @param pSgBuf The S/G buffer to reset.
204 */
205RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf);
206
207/**
208 * Clones a given S/G buffer.
209 *
210 * @returns nothing.
211 * @param pSgBufNew The new S/G buffer to clone to.
212 * @param pSgBufOld The source S/G buffer to clone from.
213 *
214 * @note This is only a shallow copy. Both S/G buffers will point to the
215 * same segment array.
216 */
217RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufNew, PCRTSGBUF pSgBufOld);
218
219/**
220 * Returns the next segment in the S/G buffer or NULL if no segments left.
221 *
222 * @returns Pointer to the next segment in the S/G buffer.
223 * @param pSgBuf The S/G buffer.
224 * @param cbDesired The max number of bytes to get.
225 * @param pcbSeg Where to store the size of the returned segment, this is
226 * equal or smaller than @a cbDesired.
227 *
228 * @note Use RTSgBufAdvance() to advance after read/writing into the buffer.
229 */
230DECLINLINE(void *) RTSgBufGetCurrentSegment(PRTSGBUF pSgBuf, size_t cbDesired, size_t *pcbSeg)
231{
232 if (!RTSgBufIsAtEnd(pSgBuf))
233 {
234 *pcbSeg = RT_MIN(cbDesired, pSgBuf->cbSegLeft);
235 return pSgBuf->pvSegCur;
236 }
237 *pcbSeg = 0;
238 return NULL;
239}
240
241/**
242 * Returns the next segment in the S/G buffer or NULL if no segment is left.
243 *
244 * @returns Pointer to the next segment in the S/G buffer.
245 * @param pSgBuf The S/G buffer.
246 * @param pcbSeg Where to store the size of the returned segment.
247 * Holds the number of bytes requested initially or 0 to
248 * indicate that the size doesn't matter.
249 * This may contain fewer bytes on success if the current segment
250 * is smaller than the amount of bytes requested.
251 *
252 * @note This operation advances the internal buffer pointer of both S/G buffers.
253 */
254RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg);
255
256/**
257 * Copy data between two S/G buffers.
258 *
259 * @returns The number of bytes copied.
260 * @param pSgBufDst The destination S/G buffer.
261 * @param pSgBufSrc The source S/G buffer.
262 * @param cbCopy Number of bytes to copy.
263 *
264 * @note This operation advances the internal buffer pointer of both S/G buffers.
265 */
266RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy);
267
268/**
269 * Compares the content of two S/G buffers.
270 *
271 * @returns Whatever memcmp returns.
272 * @param pSgBuf1 First S/G buffer.
273 * @param pSgBuf2 Second S/G buffer.
274 * @param cbCmp How many bytes to compare.
275 *
276 * @note This operation doesn't change the internal position of the S/G buffers.
277 */
278RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp);
279
280/**
281 * Compares the content of two S/G buffers - advanced version.
282 *
283 * @returns Whatever memcmp returns.
284 * @param pSgBuf1 First S/G buffer.
285 * @param pSgBuf2 Second S/G buffer.
286 * @param cbCmp How many bytes to compare.
287 * @param poffDiff Where to store the offset of the first different byte
288 * in the buffer starting from the position of the S/G
289 * buffer before this call.
290 * @param fAdvance Flag whether the internal buffer position should be advanced.
291 *
292 */
293RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance);
294
295/**
296 * Fills an S/G buf with a constant byte.
297 *
298 * @returns The number of actually filled bytes.
299 * Can be less than than cbSet if the end of the S/G buffer was reached.
300 * @param pSgBuf The S/G buffer.
301 * @param ubFill The byte to fill the buffer with.
302 * @param cbSet How many bytes to set.
303 *
304 * @note This operation advances the internal buffer pointer of the S/G buffer.
305 */
306RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet);
307
308/**
309 * Copies data from an S/G buffer into a given non scattered buffer.
310 *
311 * @returns Number of bytes copied.
312 * @param pSgBuf The S/G buffer to copy from.
313 * @param pvBuf Buffer to copy the data into.
314 * @param cbCopy How many bytes to copy.
315 *
316 * @note This operation advances the internal buffer pointer of the S/G buffer.
317 */
318RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy);
319
320/**
321 * Copies data from a non scattered buffer into an S/G buffer.
322 *
323 * @returns Number of bytes copied.
324 * @param pSgBuf The S/G buffer to copy to.
325 * @param pvBuf Buffer to copy the data from.
326 * @param cbCopy How many bytes to copy.
327 *
328 * @note This operation advances the internal buffer pointer of the S/G buffer.
329 */
330RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy);
331
332/**
333 * Copies data from the given S/G buffer to a destination handled by the given callback.
334 *
335 * @returns Number of bytes copied.
336 * @param pSgBuf The S/G buffer to copy from.
337 * @param cbCopy How many bytes to copy.
338 * @param pfnCopyTo The callback to call on every S/G buffer segment until the operation finished.
339 * @param pvUser Opaque user data to pass in the given callback.
340 *
341 * @note This operation advances the internal buffer pointer of the S/G buffer.
342 */
343RTDECL(size_t) RTSgBufCopyToFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYTO pfnCopyTo, void *pvUser);
344
345/**
346 * Copies data to the given S/G buffer from a destination handled by the given callback.
347 *
348 * @returns Number of bytes copied.
349 * @param pSgBuf The S/G buffer to copy to.
350 * @param cbCopy How many bytes to copy.
351 * @param pfnCopyFrom The callback to call on every S/G buffer segment until the operation finished.
352 * @param pvUser Opaque user data to pass in the given callback.
353 *
354 * @note This operation advances the internal buffer pointer of the S/G buffer.
355 */
356RTDECL(size_t) RTSgBufCopyFromFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYFROM pfnCopyFrom, void *pvUser);
357
358/**
359 * Advances the internal buffer pointer.
360 *
361 * @returns Number of bytes the pointer was moved forward.
362 * @param pSgBuf The S/G buffer.
363 * @param cbAdvance Number of bytes to move forward.
364 */
365RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance);
366
367/**
368 * Constructs a new segment array starting from the current position
369 * and describing the given number of bytes.
370 *
371 * @returns Number of bytes the array describes.
372 * @param pSgBuf The S/G buffer.
373 * @param paSeg The uninitialized segment array.
374 * If NULL pcSeg will contain the number of segments needed
375 * to describe the requested amount of data.
376 * @param pcSeg The number of segments the given array has.
377 * This will hold the actual number of entries needed upon return.
378 * @param cbData Number of bytes the new array should describe.
379 *
380 * @note This operation advances the internal buffer pointer of the S/G buffer if paSeg is not NULL.
381 */
382RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData);
383
384/**
385 * Returns whether the given S/G buffer is zeroed out from the current position
386 * upto the number of bytes to check.
387 *
388 * @returns true if the buffer has only zeros
389 * false otherwise.
390 * @param pSgBuf The S/G buffer.
391 * @param cbCheck Number of bytes to check.
392 */
393RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck);
394
395/**
396 * Maps the given S/G buffer to a segment array of another type (for example to
397 * iovec on POSIX or WSABUF on Windows).
398 *
399 * @param paMapped Where to store the pointer to the start of the native
400 * array or NULL. The memory needs to be freed with
401 * RTMemTmpFree().
402 * @param pSgBuf The S/G buffer to map.
403 * @param Struct Struct used as the destination.
404 * @param pvBufField Name of the field holding the pointer to a buffer.
405 * @param TypeBufPtr Type of the buffer pointer.
406 * @param cbBufField Name of the field holding the size of the buffer.
407 * @param TypeBufSize Type of the field for the buffer size.
408 * @param cSegsMapped Where to store the number of segments the native array
409 * has.
410 *
411 * @note This operation maps the whole S/G buffer starting at the current
412 * internal position. The internal buffer position is unchanged by
413 * this operation.
414 *
415 * @remark Usage is a bit ugly but saves a few lines of duplicated code
416 * somewhere else and makes it possible to keep the S/G buffer members
417 * private without going through RTSgBufSegArrayCreate() first.
418 */
419#define RTSgBufMapToNative(paMapped, pSgBuf, Struct, pvBufField, TypeBufPtr, cbBufField, TypeBufSize, cSegsMapped) \
420 do \
421 { \
422 AssertCompileMemberSize(Struct, pvBufField, RT_SIZEOFMEMB(RTSGSEG, pvSeg)); \
423 /*AssertCompile(RT_SIZEOFMEMB(Struct, cbBufField) >= RT_SIZEOFMEMB(RTSGSEG, cbSeg));*/ \
424 (cSegsMapped) = (pSgBuf)->cSegs - (pSgBuf)->idxSeg; \
425 \
426 /* We need room for at least one segment. */ \
427 if ((pSgBuf)->cSegs == (pSgBuf)->idxSeg) \
428 (cSegsMapped)++; \
429 \
430 (paMapped) = (Struct *)RTMemTmpAllocZ((cSegsMapped) * sizeof(Struct)); \
431 if ((paMapped)) \
432 { \
433 /* The first buffer is special because we could be in the middle of a segment. */ \
434 (paMapped)[0].pvBufField = (TypeBufPtr)(pSgBuf)->pvSegCur; \
435 (paMapped)[0].cbBufField = (TypeBufSize)(pSgBuf)->cbSegLeft; \
436 \
437 for (unsigned i = 1; i < (cSegsMapped); i++) \
438 { \
439 (paMapped)[i].pvBufField = (TypeBufPtr)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].pvSeg; \
440 (paMapped)[i].cbBufField = (TypeBufSize)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].cbSeg; \
441 } \
442 } \
443 } while (0)
444
445RT_C_DECLS_END
446
447/** @} */
448
449#endif /* !IPRT_INCLUDED_sg_h */
450
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