VirtualBox

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

Last change on this file since 77809 was 77236, checked in by vboxsync, 6 years ago

IPRT: Implemented RTFileSgWriteAt and RTfileSgReadAt for linux and freebsd. Clearified RTFileWriteAt and RTFileSgWriteAt specs wrt RTFILE_O_APPEND. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/** @file
2 * IPRT - S/G buffer handling.
3 */
4
5/*
6 * Copyright (C) 2010-2019 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/**
42 * A S/G entry.
43 */
44typedef struct RTSGSEG
45{
46 /** Pointer to the segment buffer. */
47 void *pvSeg;
48 /** Size of the segment buffer. */
49 size_t cbSeg;
50} RTSGSEG;
51/** Pointer to a S/G entry. */
52typedef RTSGSEG *PRTSGSEG;
53/** Pointer to a const S/G entry. */
54typedef const RTSGSEG *PCRTSGSEG;
55/** Pointer to a S/G entry pointer. */
56typedef PRTSGSEG *PPRTSGSEG;
57
58/**
59 * A S/G buffer.
60 *
61 * The members should be treated as private.
62 *
63 * @warning There is a lot of code, especially in the VFS area of IPRT, that
64 * totally ignores the idxSeg, pvSegCur and cbSegLeft members! So,
65 * it is not recommended to pass buffers that aren't fully reset or
66 * where cbSegLeft is shorter than what paSegs describes.
67 */
68typedef struct RTSGBUF
69{
70 /** Pointer to the scatter/gather array. */
71 PCRTSGSEG paSegs;
72 /** Number of segments. */
73 unsigned cSegs;
74
75 /** Current segment we are in. */
76 unsigned idxSeg;
77 /** Pointer to the current segment start. */
78 void *pvSegCur;
79 /** Number of bytes left in the current buffer. */
80 size_t cbSegLeft;
81} RTSGBUF;
82/** Pointer to a S/G entry. */
83typedef RTSGBUF *PRTSGBUF;
84/** Pointer to a const S/G entry. */
85typedef const RTSGBUF *PCRTSGBUF;
86/** Pointer to a S/G entry pointer. */
87typedef PRTSGBUF *PPRTSGBUF;
88
89
90/**
91 * Sums up the length of all the segments.
92 *
93 * @returns The complete segment length.
94 * @param pSgBuf The S/G buffer to check out.
95 */
96DECLINLINE(size_t) RTSgBufCalcTotalLength(PCRTSGBUF pSgBuf)
97{
98 size_t cb = 0;
99 unsigned i = pSgBuf->cSegs;
100 while (i-- > 0)
101 cb += pSgBuf->paSegs[i].cbSeg;
102 return cb;
103}
104
105/**
106 * Sums up the number of bytes left from the current position.
107 *
108 * @returns Number of bytes left.
109 * @param pSgBuf The S/G buffer to check out.
110 */
111DECLINLINE(size_t) RTSgBufCalcLengthLeft(PCRTSGBUF pSgBuf)
112{
113 size_t cb = pSgBuf->cbSegLeft;
114 unsigned i = pSgBuf->cSegs;
115 while (i-- > pSgBuf->idxSeg + 1)
116 cb += pSgBuf->paSegs[i].cbSeg;
117 return cb;
118}
119
120/**
121 * Checks if the current buffer position is at the start of the first segment.
122 *
123 * @returns true / false.
124 * @param pSgBuf The S/G buffer to check out.
125 */
126DECLINLINE(bool) RTSgBufIsAtStart(PCRTSGBUF pSgBuf)
127{
128 return pSgBuf->idxSeg == 0
129 && ( pSgBuf->cSegs == 0
130 || pSgBuf->pvSegCur == pSgBuf->paSegs[0].pvSeg);
131}
132
133/**
134 * Checks if the current buffer position is at the end of all the segments.
135 *
136 * @returns true / false.
137 * @param pSgBuf The S/G buffer to check out.
138 */
139DECLINLINE(bool) RTSgBufIsAtEnd(PCRTSGBUF pSgBuf)
140{
141 return pSgBuf->idxSeg > pSgBuf->cSegs
142 || ( pSgBuf->idxSeg == pSgBuf->cSegs
143 && pSgBuf->cbSegLeft == 0);
144}
145
146/**
147 * Checks if the current buffer position is at the start of the current segment.
148 *
149 * @returns true / false.
150 * @param pSgBuf The S/G buffer to check out.
151 */
152DECLINLINE(bool) RTSgBufIsAtStartOfSegment(PCRTSGBUF pSgBuf)
153{
154 return pSgBuf->idxSeg < pSgBuf->cSegs
155 && pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg == pSgBuf->pvSegCur;
156}
157
158/**
159 * Initialize a S/G buffer structure.
160 *
161 * @returns nothing.
162 * @param pSgBuf Pointer to the S/G buffer to initialize.
163 * @param paSegs Pointer to the start of the segment array.
164 * @param cSegs Number of segments in the array.
165 *
166 * @note paSegs and cSegs can be NULL and 0 respectively to indicate an empty
167 * S/G buffer. Operations on the S/G buffer will not do anything in this
168 * case.
169 */
170RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs);
171
172/**
173 * Resets the internal buffer position of the S/G buffer to the beginning.
174 *
175 * @returns nothing.
176 * @param pSgBuf The S/G buffer to reset.
177 */
178RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf);
179
180/**
181 * Clones a given S/G buffer.
182 *
183 * @returns nothing.
184 * @param pSgBufNew The new S/G buffer to clone to.
185 * @param pSgBufOld The source S/G buffer to clone from.
186 *
187 * @note This is only a shallow copy. Both S/G buffers will point to the
188 * same segment array.
189 */
190RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufNew, PCRTSGBUF pSgBufOld);
191
192/**
193 * Returns the next segment in the S/G buffer or NULL if no segments left.
194 *
195 * @returns Pointer to the next segment in the S/G buffer.
196 * @param pSgBuf The S/G buffer.
197 * @param cbDesired The max number of bytes to get.
198 * @param pcbSeg Where to store the size of the returned segment, this is
199 * equal or smaller than @a cbDesired.
200 *
201 * @note Use RTSgBufAdvance() to advance after read/writing into the buffer.
202 */
203DECLINLINE(void *) RTSgBufGetCurrentSegment(PRTSGBUF pSgBuf, size_t cbDesired, size_t *pcbSeg)
204{
205 if (!RTSgBufIsAtEnd(pSgBuf))
206 {
207 *pcbSeg = RT_MIN(cbDesired, pSgBuf->cbSegLeft);
208 return pSgBuf->pvSegCur;
209 }
210 *pcbSeg = 0;
211 return NULL;
212}
213
214/**
215 * Returns the next segment in the S/G buffer or NULL if no segment is left.
216 *
217 * @returns Pointer to the next segment in the S/G buffer.
218 * @param pSgBuf The S/G buffer.
219 * @param pcbSeg Where to store the size of the returned segment.
220 * Holds the number of bytes requested initially or 0 to
221 * indicate that the size doesn't matter.
222 * This may contain fewer bytes on success if the current segment
223 * is smaller than the amount of bytes requested.
224 *
225 * @note This operation advances the internal buffer pointer of both S/G buffers.
226 */
227RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg);
228
229/**
230 * Copy data between two S/G buffers.
231 *
232 * @returns The number of bytes copied.
233 * @param pSgBufDst The destination S/G buffer.
234 * @param pSgBufSrc The source S/G buffer.
235 * @param cbCopy Number of bytes to copy.
236 *
237 * @note This operation advances the internal buffer pointer of both S/G buffers.
238 */
239RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy);
240
241/**
242 * Compares the content of two S/G buffers.
243 *
244 * @returns Whatever memcmp returns.
245 * @param pSgBuf1 First S/G buffer.
246 * @param pSgBuf2 Second S/G buffer.
247 * @param cbCmp How many bytes to compare.
248 *
249 * @note This operation doesn't change the internal position of the S/G buffers.
250 */
251RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp);
252
253/**
254 * Compares the content of two S/G buffers - advanced version.
255 *
256 * @returns Whatever memcmp returns.
257 * @param pSgBuf1 First S/G buffer.
258 * @param pSgBuf2 Second S/G buffer.
259 * @param cbCmp How many bytes to compare.
260 * @param poffDiff Where to store the offset of the first different byte
261 * in the buffer starting from the position of the S/G
262 * buffer before this call.
263 * @param fAdvance Flag whether the internal buffer position should be advanced.
264 *
265 */
266RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance);
267
268/**
269 * Fills an S/G buf with a constant byte.
270 *
271 * @returns The number of actually filled bytes.
272 * Can be less than than cbSet if the end of the S/G buffer was reached.
273 * @param pSgBuf The S/G buffer.
274 * @param ubFill The byte to fill the buffer with.
275 * @param cbSet How many bytes to set.
276 *
277 * @note This operation advances the internal buffer pointer of the S/G buffer.
278 */
279RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t ubFill, size_t cbSet);
280
281/**
282 * Copies data from an S/G buffer into a given non scattered buffer.
283 *
284 * @returns Number of bytes copied.
285 * @param pSgBuf The S/G buffer to copy from.
286 * @param pvBuf Buffer to copy the data into.
287 * @param cbCopy How many bytes to copy.
288 *
289 * @note This operation advances the internal buffer pointer of the S/G buffer.
290 */
291RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy);
292
293/**
294 * Copies data from a non scattered buffer into an S/G buffer.
295 *
296 * @returns Number of bytes copied.
297 * @param pSgBuf The S/G buffer to copy to.
298 * @param pvBuf Buffer to copy the data from.
299 * @param cbCopy How many bytes to copy.
300 *
301 * @note This operation advances the internal buffer pointer of the S/G buffer.
302 */
303RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy);
304
305/**
306 * Advances the internal buffer pointer.
307 *
308 * @returns Number of bytes the pointer was moved forward.
309 * @param pSgBuf The S/G buffer.
310 * @param cbAdvance Number of bytes to move forward.
311 */
312RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance);
313
314/**
315 * Constructs a new segment array starting from the current position
316 * and describing the given number of bytes.
317 *
318 * @returns Number of bytes the array describes.
319 * @param pSgBuf The S/G buffer.
320 * @param paSeg The uninitialized segment array.
321 * If NULL pcSeg will contain the number of segments needed
322 * to describe the requested amount of data.
323 * @param pcSeg The number of segments the given array has.
324 * This will hold the actual number of entries needed upon return.
325 * @param cbData Number of bytes the new array should describe.
326 *
327 * @note This operation advances the internal buffer pointer of the S/G buffer if paSeg is not NULL.
328 */
329RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSeg, size_t cbData);
330
331/**
332 * Returns whether the given S/G buffer is zeroed out from the current position
333 * upto the number of bytes to check.
334 *
335 * @returns true if the buffer has only zeros
336 * false otherwise.
337 * @param pSgBuf The S/G buffer.
338 * @param cbCheck Number of bytes to check.
339 */
340RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck);
341
342/**
343 * Maps the given S/G buffer to a segment array of another type (for example to
344 * iovec on POSIX or WSABUF on Windows).
345 *
346 * @param paMapped Where to store the pointer to the start of the native
347 * array or NULL. The memory needs to be freed with
348 * RTMemTmpFree().
349 * @param pSgBuf The S/G buffer to map.
350 * @param Struct Struct used as the destination.
351 * @param pvBufField Name of the field holding the pointer to a buffer.
352 * @param TypeBufPtr Type of the buffer pointer.
353 * @param cbBufField Name of the field holding the size of the buffer.
354 * @param TypeBufSize Type of the field for the buffer size.
355 * @param cSegsMapped Where to store the number of segments the native array
356 * has.
357 *
358 * @note This operation maps the whole S/G buffer starting at the current
359 * internal position. The internal buffer position is unchanged by
360 * this operation.
361 *
362 * @remark Usage is a bit ugly but saves a few lines of duplicated code
363 * somewhere else and makes it possible to keep the S/G buffer members
364 * private without going through RTSgBufSegArrayCreate() first.
365 */
366#define RTSgBufMapToNative(paMapped, pSgBuf, Struct, pvBufField, TypeBufPtr, cbBufField, TypeBufSize, cSegsMapped) \
367 do \
368 { \
369 AssertCompileMemberSize(Struct, pvBufField, RT_SIZEOFMEMB(RTSGSEG, pvSeg)); \
370 /*AssertCompile(RT_SIZEOFMEMB(Struct, cbBufField) >= RT_SIZEOFMEMB(RTSGSEG, cbSeg));*/ \
371 (cSegsMapped) = (pSgBuf)->cSegs - (pSgBuf)->idxSeg; \
372 \
373 /* We need room for at least one segment. */ \
374 if ((pSgBuf)->cSegs == (pSgBuf)->idxSeg) \
375 (cSegsMapped)++; \
376 \
377 (paMapped) = (Struct *)RTMemTmpAllocZ((cSegsMapped) * sizeof(Struct)); \
378 if ((paMapped)) \
379 { \
380 /* The first buffer is special because we could be in the middle of a segment. */ \
381 (paMapped)[0].pvBufField = (TypeBufPtr)(pSgBuf)->pvSegCur; \
382 (paMapped)[0].cbBufField = (TypeBufSize)(pSgBuf)->cbSegLeft; \
383 \
384 for (unsigned i = 1; i < (cSegsMapped); i++) \
385 { \
386 (paMapped)[i].pvBufField = (TypeBufPtr)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].pvSeg; \
387 (paMapped)[i].cbBufField = (TypeBufSize)(pSgBuf)->paSegs[(pSgBuf)->idxSeg + i].cbSeg; \
388 } \
389 } \
390 } while (0)
391
392RT_C_DECLS_END
393
394/** @} */
395
396#endif /* !IPRT_INCLUDED_sg_h */
397
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